Control.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. package holeg.ui.controller;
  2. import holeg.model.*;
  3. import holeg.preferences.ImagePreference;
  4. import holeg.preferences.PreferenceKeys;
  5. import holeg.serialize.CategoryAdapter;
  6. import holeg.ui.model.GuiSettings;
  7. import holeg.ui.model.IdCounter;
  8. import holeg.ui.view.category.Category;
  9. import holeg.ui.view.dialog.CreateTemplatePopUp;
  10. import holeg.utility.events.Action;
  11. import holeg.utility.events.Event;
  12. import holeg.utility.math.vector.Vec2i;
  13. import javax.swing.*;
  14. import java.io.File;
  15. import java.io.FileReader;
  16. import java.io.FileWriter;
  17. import java.io.IOException;
  18. import java.util.*;
  19. import java.util.logging.Logger;
  20. import java.util.prefs.Preferences;
  21. import java.util.stream.Collectors;
  22. import static holeg.serialize.ModelDeserializer.gson;
  23. /**
  24. * The Class represents the controller.
  25. */
  26. public class Control {
  27. private static final Logger log = Logger.getLogger(Control.class.getName());
  28. private static final Preferences prefs = Preferences.userNodeForPackage(Control.class);
  29. private final CanvasController canvasController;
  30. private final SimulationManager simulationManager;
  31. public Event OnCategoryChanged = new Event();
  32. public Event OnSelectionChanged = new Event();
  33. public Event OnCanvasUpdate = new Event();
  34. public Action<Boolean> OnGuiSetEnabled = new Action<>();
  35. public Action<GroupNode> OnShowGroupNode = new Action<>();
  36. public Action<GroupNode> OnRemoveGroupNode = new Action<>();
  37. public Event OnModelChanged = new Event();
  38. private Model model;
  39. public Control(Model model) {
  40. this.model = model;
  41. this.canvasController = new CanvasController(this);
  42. this.simulationManager = new SimulationManager(this);
  43. }
  44. /* Operations for Categories and Objects */
  45. /**
  46. * init default category and objects.
  47. */
  48. public void resetCategories() {
  49. GuiSettings.getCategories().clear();
  50. initCategories();
  51. saveCategories();
  52. }
  53. /**
  54. * Gives all Category as String
  55. *
  56. * @return a array of strings from all Categorys
  57. */
  58. public String[] getCategoriesStrings() {
  59. return GuiSettings.getCategories().stream().map(Category::getName).toArray(String[]::new);
  60. }
  61. /**
  62. * Add new Holon Object to a Category.
  63. */
  64. public void addObject(Category cat, String obj, List<HolonElement> list, String img) {
  65. addNewHolonObject(cat, obj, list, img);
  66. OnCategoryChanged.broadcast();
  67. saveCategories();
  68. }
  69. /**
  70. * Add new Holon Switch to a Category.
  71. *
  72. * @param cat Category
  73. * @param obj New Object Name
  74. */
  75. public void addSwitch(Category cat, String obj) {
  76. addNewHolonSwitch(cat, obj);
  77. OnCategoryChanged.broadcast();
  78. saveCategories();
  79. }
  80. public void deleteCategory(Category category) {
  81. removeCategory(category);
  82. saveCategories();
  83. }
  84. /**
  85. * removes a selectedObject from selection.
  86. */
  87. public void removeObjectsFromSelection(Collection<AbstractCanvasObject> objects) {
  88. if (GuiSettings.getSelectedObjects().removeAll(objects)) {
  89. OnSelectionChanged.broadcast();
  90. }
  91. }
  92. /**
  93. * removes a selectedObject from selection.
  94. *
  95. * @param obj Cpsobject
  96. */
  97. public void removeObjectFromSelection(AbstractCanvasObject obj) {
  98. if (GuiSettings.getSelectedObjects().remove(obj)) {
  99. OnSelectionChanged.broadcast();
  100. }
  101. }
  102. public void addSelectedObject(AbstractCanvasObject obj) {
  103. if (GuiSettings.getSelectedObjects().add(obj)) {
  104. OnSelectionChanged.broadcast();
  105. }
  106. }
  107. public void addSelectedObjects(Collection<AbstractCanvasObject> objects) {
  108. if (GuiSettings.getSelectedObjects().addAll(objects)) {
  109. OnSelectionChanged.broadcast();
  110. }
  111. }
  112. public void setSelection(Collection<AbstractCanvasObject> objects) {
  113. GuiSettings.getSelectedObjects().clear();
  114. addSelectedObjects(objects);
  115. }
  116. public void clearSelection() {
  117. if (!GuiSettings.getSelectedObjects().isEmpty()) {
  118. GuiSettings.getSelectedObjects().clear();
  119. OnSelectionChanged.broadcast();
  120. }
  121. }
  122. public void addObjectOnCanvas(GroupNode node, AbstractCanvasObject object) {
  123. canvasController.addObject(node, object);
  124. calculateStateAndVisualForTimeStep(model.getCurrentIteration());
  125. }
  126. public void addCopyOnCanvas(GroupNode node, AbstractCanvasObject object) {
  127. addObjectOnCanvas(node, object.copy());
  128. }
  129. /**
  130. * Deletes an CpsObject on the Canvas and its connections.
  131. *
  132. * @param obj AbstractCpsObject
  133. */
  134. public void deleteCanvasObject(AbstractCanvasObject obj) {
  135. canvasController.deleteObject(obj);
  136. if (obj instanceof GroupNode groupnode) {
  137. canvasController.deleteAllObjectsInGroupNode(groupnode);
  138. }
  139. calculateStateAndVisualForCurrentTimeStep();
  140. }
  141. public void deleteCanvasObjects(Collection<AbstractCanvasObject> objects) {
  142. canvasController.deleteObjects(objects);
  143. calculateStateAndVisualForCurrentTimeStep();
  144. }
  145. /**
  146. * Replaces {@code toBeReplaced} by {@code by} on the canvas
  147. *
  148. * @param toBeReplaced the object that will be replaced
  149. * @param by the object that will replace it
  150. */
  151. public void replaceCanvasObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
  152. canvasController.replaceObject(toBeReplaced, by);
  153. }
  154. /**
  155. * Add an edge to the Canvas.
  156. *
  157. * @param edge the edge
  158. */
  159. public boolean addEdgeOnCanvas(Edge edge) {
  160. boolean connectsItSelf = edge.getA() == edge.getB();
  161. boolean connectionExist = model.getEdgesOnCanvas().stream().anyMatch(e -> (e.getA() == edge.getA() && e.getB() == edge.getB())
  162. || (e.getB() == edge.getA() && e.getA() == edge.getB()));
  163. if (connectsItSelf || connectionExist) {
  164. return false;
  165. }
  166. canvasController.addEdgeOnCanvas(edge);
  167. return true;
  168. }
  169. /**
  170. * Removes an Edge from the Canvas.
  171. *
  172. * @param edge the edge to remove
  173. */
  174. public void removeEdgesOnCanvas(Edge edge) {
  175. canvasController.removeEdgesOnCanvas(edge);
  176. }
  177. /**
  178. * calculates the flow of the edges and the supply for objects for the current
  179. * Timestep.
  180. */
  181. public void calculateStateAndVisualForCurrentTimeStep() {
  182. calculateStateAndVisualForTimeStep(model.getCurrentIteration());
  183. }
  184. public void calculateStateOnlyForCurrentTimeStep() {
  185. calculateStateForTimeStep(model.getCurrentIteration());
  186. }
  187. /**
  188. * calculates the flow of the edges and the supply for objects.
  189. *
  190. * @param x current Iteration
  191. */
  192. public void calculateStateAndVisualForTimeStep(int x) {
  193. simulationManager.calculateStateForTimeStep(x);
  194. log.info("OnCanvasUpdate");
  195. OnCanvasUpdate.broadcast();
  196. }
  197. /**
  198. * calculates the flow of the edges and the supply for objects.
  199. *
  200. * @param x current Iteration
  201. */
  202. public void calculateStateForTimeStep(int x) {
  203. simulationManager.calculateStateForTimeStep(x);
  204. }
  205. /**
  206. * resets the whole State of the simulation including a reset of all Edges to
  207. * the default "is working" state
  208. */
  209. public void resetSimulation() {
  210. model.reset();
  211. }
  212. /**
  213. * Getter for Model.
  214. *
  215. * @return the Model
  216. */
  217. public Model getModel() {
  218. return model;
  219. }
  220. public void replaceObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
  221. canvasController.replaceObject(toBeReplaced, by);
  222. }
  223. /**
  224. * Copy all Selected Objects.
  225. */
  226. public void copy() {
  227. GuiSettings.getClipboardObjects().clear();
  228. GuiSettings.getClipboardObjects().addAll(GuiSettings.getSelectedObjects());
  229. }
  230. public void paste(GroupNode groupNode, Vec2i offset) {
  231. if (GuiSettings.getClipboardObjects().isEmpty()) {
  232. return;
  233. }
  234. Set<AbstractCanvasObject> copies = GuiSettings.getClipboardObjects().stream().map(AbstractCanvasObject::copy).collect(Collectors.toSet());
  235. copies.forEach(obj -> {
  236. obj.getPosition().addAssign(offset);
  237. obj.getPosition().clampX(0, GuiSettings.canvasSize.getX());
  238. obj.getPosition().clampY(0, GuiSettings.canvasSize.getY());
  239. });
  240. groupNode.addAll(copies);
  241. calculateStateAndVisualForTimeStep(model.getCurrentIteration());
  242. OnSelectionChanged.broadcast();
  243. }
  244. public void cut() {
  245. copy();
  246. deleteCanvasObjects(GuiSettings.getSelectedObjects());
  247. clearSelection();
  248. }
  249. public void createTemplate(HolonObject cps, JFrame parentFrame) {
  250. CreateTemplatePopUp t = new CreateTemplatePopUp(cps, model, parentFrame, this);
  251. t.setVisible(true);
  252. }
  253. public void guiSetEnabled(boolean state) {
  254. OnGuiSetEnabled.broadcast(state);
  255. }
  256. /**
  257. * init default category and objects.
  258. */
  259. private void initCategories() {
  260. Category energy = createCategoryWithName("Energy");
  261. Category building = createCategoryWithName("Building");
  262. Category component = createCategoryWithName("Component");
  263. HolonObject powerPlant = addNewHolonObject(energy, "Power Plant", new ArrayList<>(),
  264. ImagePreference.Canvas.DefaultObject.PowerPlant);
  265. HolonObject house = addNewHolonObject(building, "House", new ArrayList<>(), ImagePreference.Canvas.DefaultObject.House);
  266. addNewHolonSwitch(component, "Switch");
  267. powerPlant.add(new HolonElement(null, "Power", 10000));
  268. energy.getObjects().add(powerPlant);
  269. house.add(new HolonElement(null, "TV", -250));
  270. house.add(new HolonElement(null, "TV", -250));
  271. house.add(new HolonElement(null, "Fridge", -500));
  272. house.add(new HolonElement(null, "Radio", -100));
  273. house.add(new HolonElement(null, "PC", -250));
  274. house.add(new HolonElement(null, "PC", -250));
  275. house.add(new HolonElement(null, "PC", -250));
  276. house.add(new HolonElement(null, "Light", -50));
  277. house.add(new HolonElement(null, "Light", -50));
  278. house.add(new HolonElement(null, "Light", -50));
  279. house.add(new HolonElement(null, "Light", -50));
  280. house.add(new HolonElement(null, "Light", -50));
  281. house.add(new HolonElement(null, "Solar Panel", 300));
  282. building.getObjects().add(house);
  283. OnCategoryChanged.broadcast();
  284. }
  285. public Category createCategoryWithName(String categoryName) {
  286. Optional<Category> category = findCategoryWithName(categoryName);
  287. if (category.isEmpty()) {
  288. Category cat = new Category(categoryName);
  289. GuiSettings.getCategories().add(cat);
  290. OnCategoryChanged.broadcast();
  291. return cat;
  292. } else {
  293. return category.get();
  294. }
  295. }
  296. /**
  297. * remove a Category from Model.
  298. *
  299. * @param c Category
  300. */
  301. public void removeCategory(Category c) {
  302. GuiSettings.getCategories().remove(c);
  303. OnCategoryChanged.broadcast();
  304. }
  305. /**
  306. * Add Object into a Category.
  307. *
  308. * @param category Category
  309. * @param object Object
  310. */
  311. public void addObject(Category category, AbstractCanvasObject object) {
  312. int i = 0;
  313. //TODO(Tom2021-12-1) remove/redo this search
  314. while (category.findObjectWithName(object.getName()).isPresent()) {
  315. if (object.getName().contains("_"))
  316. object.setName(object.getName().substring(0, object.getName().indexOf('_')));
  317. object.setName(object.getName() + "_" + i);
  318. i++;
  319. }
  320. category.getObjects().add(object);
  321. }
  322. /**
  323. * Add new Holon Object to a Category.
  324. *
  325. * @param category Category
  326. * @param object New Object Name
  327. * @param list Array of Elements
  328. * @param image the image Path
  329. */
  330. public HolonObject addNewHolonObject(Category category, String object, List<HolonElement> list, String image) {
  331. HolonObject obj = new HolonObject(object);
  332. obj.setImagePath(image);
  333. obj.clearElements();
  334. obj.add(list);
  335. addObject(category, obj);
  336. return obj;
  337. }
  338. public HolonSwitch addNewHolonSwitch(Category cat, String objName) {
  339. HolonSwitch holonSwitch = new HolonSwitch(objName);
  340. addObject(cat, holonSwitch);
  341. return holonSwitch;
  342. }
  343. /**
  344. * Removes an Object from a Category.
  345. *
  346. * @param category Category
  347. * @param cps the Object
  348. */
  349. public void removeObject(Category category, AbstractCanvasObject cps) {
  350. category.getObjects().remove(cps);
  351. OnCategoryChanged.broadcast();
  352. }
  353. public Optional<Category> findCategoryWithName(String categoryName) {
  354. return GuiSettings.getCategories().stream().filter(cat -> cat.getName().equals(categoryName)).findAny();
  355. }
  356. public void loadFile(File file) {
  357. log.info("load" + file);
  358. try {
  359. FileReader reader = new FileReader(file);
  360. Model model = gson.fromJson(reader, Model.class);
  361. reader.close();
  362. this.model = model;
  363. calculateStateAndVisualForCurrentTimeStep();
  364. OnModelChanged.broadcast();
  365. } catch (IOException e) {
  366. log.warning(e.getLocalizedMessage());
  367. }
  368. clearSelection();
  369. GuiSettings.setActualSaveFile(file);
  370. }
  371. public void toggleSelectedObjects(Collection<AbstractCanvasObject> objects) {
  372. Set<AbstractCanvasObject> intersection = new HashSet<>(objects);
  373. intersection.retainAll(GuiSettings.getSelectedObjects());
  374. GuiSettings.getSelectedObjects().addAll(objects);
  375. GuiSettings.getSelectedObjects().removeAll(intersection);
  376. OnSelectionChanged.broadcast();
  377. }
  378. public void saveFile(File file) {
  379. log.info("save" + file);
  380. try {
  381. FileWriter writer = new FileWriter(file);
  382. gson.toJson(model, writer);
  383. writer.close();
  384. } catch (IOException e) {
  385. log.warning(e.getLocalizedMessage());
  386. }
  387. GuiSettings.setActualSaveFile(file);
  388. }
  389. public void group() {
  390. canvasController.group(GuiSettings.getSelectedObjects());
  391. clearSelection();
  392. OnCanvasUpdate.broadcast();
  393. }
  394. public void ungroup() {
  395. canvasController.ungroup(GuiSettings.getSelectedObjects());
  396. clearSelection();
  397. OnCanvasUpdate.broadcast();
  398. }
  399. public void clearModel() {
  400. model.clear();
  401. clearSelection();
  402. model.setCurrentIteration(0);
  403. IdCounter.reset();
  404. calculateStateAndVisualForCurrentTimeStep();
  405. OnModelChanged.broadcast();
  406. GuiSettings.setActualSaveFile(null);
  407. }
  408. public void showGroupNode(GroupNode groupNode) {
  409. OnShowGroupNode.broadcast(groupNode);
  410. clearSelection();
  411. }
  412. public void loadCategory(){
  413. String json = prefs.get(PreferenceKeys.Category.DefaultCategory, "Init");
  414. if(json.equals("Init")){
  415. initCategories();
  416. return;
  417. }
  418. GuiSettings.getCategories().clear();
  419. GuiSettings.getCategories().addAll(CategoryAdapter.Gson.fromJson(json, CategoryAdapter.CategorySet));
  420. OnCategoryChanged.broadcast();
  421. }
  422. public void saveCategories(){
  423. String json = CategoryAdapter.Gson.toJson(GuiSettings.getCategories());
  424. prefs.put(PreferenceKeys.Category.DefaultCategory, json);
  425. }
  426. }