package holeg.ui.controller; import holeg.model.*; import holeg.preferences.ImagePreference; import holeg.ui.model.GuiSettings; import holeg.ui.model.IdCounter; import holeg.ui.view.dialog.CreateTemplatePopUp; import holeg.ui.view.category.Category; import holeg.utility.events.Action; import holeg.utility.events.Event; import holeg.utility.math.vector.Vec2i; import javax.swing.*; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.*; import java.util.logging.Logger; import static holeg.serialize.GsonCollection.Gson; /** * The Class represents the controller. */ public class Control { private static final Logger log = Logger.getLogger(Control.class.getName()); private final CanvasController canvasController; private Model model; private final SimulationManager simulationManager; public Event OnCategoryChanged = new Event(); public Event OnSelectionChanged = new Event(); public Event OnCanvasUpdate = new Event(); public Action OnGuiSetEnabled = new Action<>(); public Control(Model model) { this.model = model; this.canvasController = new CanvasController(this); this.simulationManager = new SimulationManager(this); } /* Operations for Categories and Objects */ /** * init default category and objects. */ public void resetCategories() { clearCategories(); initCategories(); saveCategory(); } /** * Gives all Category as String * * @return a array of strings from all Categorys */ public String[] getCategoriesStrings() { return GuiSettings.getCategories().stream().map(Category::getName).toArray(String[]::new); } /** * Add new Holon Object to a Category. */ public void addObject(Category cat, String obj, List list, String img) { addNewHolonObject(cat, obj, list, img); saveCategory(); } /** * Add new Holon Switch to a Category. * * @param cat Category * @param obj New Object Name */ public void addSwitch(Category cat, String obj) { addNewHolonSwitch(cat, obj); saveCategory(); } public void deleteCategory(Category category) { removeCategory(category); saveCategory(); } /** * removes a selectedObject from selection. */ public void removeObjectsFromSelection(Collection objects) { if (GuiSettings.getSelectedObjects().removeAll(objects)) { OnSelectionChanged.broadcast(); } } /** * removes a selectedObject from selection. * * @param obj Cpsobject */ public void removeObjectFromSelection(AbstractCanvasObject obj) { if (GuiSettings.getSelectedObjects().remove(obj)) { OnSelectionChanged.broadcast(); } } public void addSelectedObject(AbstractCanvasObject obj) { if (GuiSettings.getSelectedObjects().add(obj)) { OnSelectionChanged.broadcast(); } } public void addSelectedObjects(Collection objects) { if (GuiSettings.getSelectedObjects().addAll(objects)) { OnSelectionChanged.broadcast(); } } public void clearSelection() { if (!GuiSettings.getSelectedObjects().isEmpty()) { GuiSettings.getSelectedObjects().clear(); OnSelectionChanged.broadcast(); } } /** * This method is primarily for the multi-selection. It adds unselected objects * to the selection and Removes selected objects from the selection. Like the * normal OS Desktop selection. * * @param objects */ public void toggleSelectedObjects(Collection objects) { Set intersection = new HashSet<>(objects); intersection.retainAll(GuiSettings.getSelectedObjects()); GuiSettings.getSelectedObjects().addAll(objects); GuiSettings.getSelectedObjects().removeAll(intersection); OnSelectionChanged.broadcast(); } /* Operations for Canvas */ /** * Add a new Object. * * @param object the Object */ public void addObjectCanvas(GroupNode node, AbstractCanvasObject object) { canvasController.addObject(node, object); calculateStateAndVisualForTimeStep(model.getCurrentIteration()); } /** * Deletes an CpsObject on the Canvas and its connections. * * @param obj AbstractCpsObject */ public void deleteCanvasObject(AbstractCanvasObject obj) { canvasController.deleteObject(obj); if (obj instanceof GroupNode groupnode) { canvasController.deleteAllObjectsInGroupNode(groupnode); } calculateStateAndVisualForCurrentTimeStep(); } public void deleteCanvasObjects(Collection objects) { canvasController.deleteObjects(objects); calculateStateAndVisualForCurrentTimeStep(); } /** * Replaces {@code toBeReplaced} by {@code by} on the canvas * * @param toBeReplaced the object that will be replaced * @param by the object that will replace it */ public void replaceCanvasObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) { canvasController.replaceObject(toBeReplaced, by); } /** * Add an edge to the Canvas. * * @param edge the edge */ public boolean addEdgeOnCanvas(Edge edge) { boolean connectsItSelf = edge.getA() == edge.getB(); boolean connectionExist = model.getEdgesOnCanvas().stream().anyMatch(e -> (e.getA() == edge.getA() && e.getB() == edge.getB()) || (e.getB() == edge.getA() && e.getA() == edge.getB())); if (connectsItSelf || connectionExist) { return false; } canvasController.addEdgeOnCanvas(edge); return true; } /** * Removes an Edge from the Canvas. * * @param edge the edge to remove */ public void removeEdgesOnCanvas(Edge edge) { canvasController.removeEdgesOnCanvas(edge); } /** * calculates the flow of the edges and the supply for objects for the current * Timestep. */ public void calculateStateAndVisualForCurrentTimeStep() { calculateStateAndVisualForTimeStep(model.getCurrentIteration()); } public void calculateStateOnlyForCurrentTimeStep() { calculateStateForTimeStep(model.getCurrentIteration()); } /** * calculates the flow of the edges and the supply for objects. * * @param x current Iteration */ public void calculateStateAndVisualForTimeStep(int x) { simulationManager.calculateStateForTimeStep(x); log.info("OnCanvasUpdate"); OnCanvasUpdate.broadcast(); } /** * calculates the flow of the edges and the supply for objects. * * @param x current Iteration */ public void calculateStateForTimeStep(int x) { simulationManager.calculateStateForTimeStep(x); } /** * resets the whole State of the simulation including a reset of all Edges to * the default "is working" state */ public void resetSimulation() { model.reset(); } public void saveCategory() { //TODO(Tom2022-01-27): } /** * Getter for Model. * * @return the Model */ public Model getModel() { return model; } public void replaceObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) { canvasController.replaceObject(toBeReplaced, by); } /** * Copy all Selected Objects. */ public void copy(GroupNode upperNode) { //TODO(Tom2022-01-27): } public void paste(GroupNode upperNode, Vec2i point) { //TODO(Tom2022-01-27): OnSelectionChanged.broadcast(); } public void cut(GroupNode upperNode) { //TODO(Tom2022-01-27): OnSelectionChanged.broadcast(); } /** * creates a new Template for the given cps Object * * @param cps Object, which should become a template * @param parentFrame */ public void createTemplate(HolonObject cps, JFrame parentFrame) { CreateTemplatePopUp t = new CreateTemplatePopUp(cps, model, parentFrame, this); t.setVisible(true); } public void guiSetEnabled(boolean state) { log.info("guiDisabled"); OnGuiSetEnabled.broadcast(state); } /** * init default category and objects. */ public void initCategories() { Category energy = createCategoryWithName("Energy"); Category building = createCategoryWithName("Building"); Category component = createCategoryWithName("Component"); HolonObject powerPlant = addNewHolonObject(energy, "Power Plant", new ArrayList<>(), ImagePreference.Canvas.DefaultObject.PowerPlant); HolonObject house = addNewHolonObject(building, "House", new ArrayList<>(), ImagePreference.Canvas.DefaultObject.House); addNewHolonSwitch(component, "Switch"); powerPlant.add(new HolonElement(null, "Power", 10000)); energy.getObjects().add(powerPlant); house.add(new HolonElement(null, "TV", -250)); house.add(new HolonElement(null, "TV", -250)); house.add(new HolonElement(null, "Fridge", -500)); house.add(new HolonElement(null, "Radio", -100)); house.add(new HolonElement(null, "PC", -250)); house.add(new HolonElement(null, "PC", -250)); house.add(new HolonElement(null, "PC", -250)); house.add(new HolonElement(null, "Light", -50)); house.add(new HolonElement(null, "Light", -50)); house.add(new HolonElement(null, "Light", -50)); house.add(new HolonElement(null, "Light", -50)); house.add(new HolonElement(null, "Light", -50)); house.add(new HolonElement(null, "Solar Panel", 300)); building.getObjects().add(house); OnCategoryChanged.broadcast(); } public Category createCategoryWithName(String categoryName) { Optional category = findCategoryWithName(categoryName); if(category.isEmpty()) { Category cat = new Category(categoryName); GuiSettings.getCategories().add(cat); OnCategoryChanged.broadcast(); return cat; }else { return category.get(); } } /** * remove a Category from Model. * * @param c * Category */ public void removeCategory(Category c) { GuiSettings.getCategories().remove(c); OnCategoryChanged.broadcast(); } public void clearCategories() { GuiSettings.getCategories().clear(); } /** * Add Object into a Category. * * @param category * Category * @param object * Object */ public void addObject(Category category, AbstractCanvasObject object) { int i = 0; //TODO(Tom2021-12-1) remove/redo this search while (category.findObjectWithName(object.getName()).isPresent()) { if (object.getName().contains("_")) object.setName(object.getName().substring(0, object.getName().indexOf('_'))); object.setName(object.getName() + "_" + i); i++; } category.getObjects().add(object); } /** * Add new Holon Object to a Category. * * @param category * Category * @param object * New Object Name * @param list * Array of Elements * @param image * the image Path */ public HolonObject addNewHolonObject(Category category, String object, List list, String image) { HolonObject obj = new HolonObject(object); obj.setImagePath(image); obj.clearElements(); obj.add(list); addObject(category, obj); return obj; } public HolonSwitch addNewHolonSwitch(Category cat, String objName) { HolonSwitch holonSwitch = new HolonSwitch(objName); addObject(cat, holonSwitch); return holonSwitch; } /** * Removes an Object from a Category. * @param category Category * @param cps the Object */ public void removeObject(Category category, AbstractCanvasObject cps) { category.getObjects().remove(cps); OnCategoryChanged.broadcast(); } public Optional findCategoryWithName(String categoryName) { return GuiSettings.getCategories().stream().filter(cat -> cat.getName().equals(categoryName)).findAny(); } public void loadFile(File file) { log.info("load" + file); try { FileReader reader = new FileReader(file); Model model = Gson.fromJson(reader, Model.class); reader.close(); this.model = model; calculateStateAndVisualForCurrentTimeStep(); } catch (IOException e) { log.warning(e.getLocalizedMessage()); } clearSelection(); GuiSettings.setActualSaveFile(file); } public void saveFile(File file) { log.info("save" + file); try { FileWriter writer = new FileWriter(file); Gson.toJson(model, writer); writer.close(); } catch (IOException e) { log.warning(e.getLocalizedMessage()); } GuiSettings.setActualSaveFile(file); } public void clearModel() { model.clear(); clearSelection(); model.setCurrentIteration(0); IdCounter.reset(); calculateStateAndVisualForCurrentTimeStep(); GuiSettings.setActualSaveFile(null); } }