Gui.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. package holeg.ui.view.main;
  2. import holeg.model.AbstractCanvasObject;
  3. import holeg.model.GroupNode;
  4. import holeg.model.Model;
  5. import holeg.preferences.ImagePreference;
  6. import holeg.preferences.PreferenceKeys;
  7. import holeg.ui.controller.Control;
  8. import holeg.ui.model.GuiSettings;
  9. import holeg.ui.view.canvas.Canvas;
  10. import holeg.ui.view.canvas.CanvasCollectionPanel;
  11. import holeg.ui.view.category.CategoryPanel;
  12. import holeg.ui.view.dialog.AboutUsPopUp;
  13. import holeg.ui.view.dialog.CanvasResizePopUp;
  14. import holeg.ui.view.dialog.EditEdgesPopUp;
  15. import holeg.ui.view.image.Import;
  16. import holeg.ui.view.information.HolonInformationPanel;
  17. import holeg.ui.view.inspector.Inspector;
  18. import holeg.ui.view.window.AddOnWindow;
  19. import holeg.ui.view.window.FlexWindow;
  20. import holeg.ui.view.window.Outliner;
  21. import holeg.utility.listener.WindowClosingListener;
  22. import holeg.utility.math.vector.Vec2i;
  23. import javax.swing.*;
  24. import javax.swing.filechooser.FileNameExtensionFilter;
  25. import javax.swing.filechooser.FileSystemView;
  26. import java.awt.*;
  27. import java.awt.event.ActionEvent;
  28. import java.awt.event.InputEvent;
  29. import java.awt.event.KeyEvent;
  30. import java.io.File;
  31. import java.net.URI;
  32. import java.util.Optional;
  33. import java.util.Set;
  34. import java.util.logging.Logger;
  35. import java.util.prefs.Preferences;
  36. import java.util.stream.Collectors;
  37. public class Gui extends JFrame {
  38. private static final Logger log = Logger.getLogger(Model.class.getName());
  39. private static final Preferences prefs = Preferences.userNodeForPackage(Gui.class);
  40. private final Control control;
  41. private final CategoryPanel categoryPanel;
  42. private final CanvasCollectionPanel canvasCollection;
  43. private final Inspector inspector;
  44. private final HolonInformationPanel informationPanel;
  45. private final TimePanel timePanel;
  46. /**
  47. * Create the application.
  48. *
  49. * @param control the Controller
  50. */
  51. public Gui(Control control) {
  52. super("HOLEG Simulator");
  53. this.control = control;
  54. this.informationPanel = new HolonInformationPanel(control);
  55. this.inspector = new Inspector(control);
  56. this.categoryPanel = new CategoryPanel(control, this);
  57. this.canvasCollection = new CanvasCollectionPanel(control);
  58. this.timePanel = new TimePanel(control);
  59. init();
  60. }
  61. private void init() {
  62. initFrame();
  63. initLayout();
  64. }
  65. private void initFrame() {
  66. this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
  67. this.setBounds(new Rectangle(prefs.getInt(PreferenceKeys.Gui.Width, 1200), prefs.getInt(PreferenceKeys.Gui.Height, 800)));
  68. if (prefs.get(PreferenceKeys.Gui.Width, null) != null) {
  69. this.setLocation(prefs.getInt(PreferenceKeys.Gui.XPos, 1200), prefs.getInt(PreferenceKeys.Gui.YPos, 800));
  70. } else {
  71. this.setLocationRelativeTo(null);
  72. }
  73. this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  74. this.addWindowListener((WindowClosingListener) e -> {
  75. Rectangle bounds = this.getBounds();
  76. prefs.putInt(PreferenceKeys.Gui.XPos, bounds.x);
  77. prefs.putInt(PreferenceKeys.Gui.YPos, bounds.y);
  78. prefs.putInt(PreferenceKeys.Gui.Width, bounds.width);
  79. prefs.putInt(PreferenceKeys.Gui.Height, bounds.height);
  80. control.saveCategories();
  81. if (JOptionPane.showConfirmDialog(this, "Are you sure you want to exit?", "HOLEG",
  82. JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
  83. System.exit(0);
  84. }
  85. });
  86. }
  87. private void initLayout() {
  88. this.setJMenuBar(new GuiMenuBar());
  89. final JSplitPane categorySplit = new JSplitPane();
  90. final JSplitPane canvasSplit = new JSplitPane();
  91. final JSplitPane elementSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
  92. final JScrollPane informationPanelScrollPane = new JScrollPane();
  93. Container contentPanel = this.getContentPane();
  94. contentPanel.setLayout(new BorderLayout(0, 0));
  95. contentPanel.add(categorySplit);
  96. categorySplit.setLeftComponent(categoryPanel);
  97. categorySplit.setRightComponent(canvasSplit);
  98. categorySplit.setDividerLocation(200);
  99. categorySplit.setBorder(null);
  100. canvasSplit.setMinimumSize(new Dimension(0, 25));
  101. canvasSplit.setDividerLocation(500);
  102. canvasSplit.setLeftComponent(canvasCollection);
  103. canvasSplit.setRightComponent(elementSplit);
  104. canvasSplit.setResizeWeight(0.9);
  105. canvasSplit.setBorder(null);
  106. elementSplit.setDividerLocation(700);
  107. elementSplit.setTopComponent(inspector);
  108. elementSplit.setBottomComponent(informationPanelScrollPane);
  109. elementSplit.setBorder(null);
  110. informationPanelScrollPane.setViewportView(this.informationPanel);
  111. informationPanelScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  112. informationPanelScrollPane.getVerticalScrollBar().setUnitIncrement(16);
  113. informationPanelScrollPane.setBorder(null);
  114. contentPanel.add(timePanel, BorderLayout.SOUTH);
  115. }
  116. public Canvas getActualCanvas() {
  117. return this.canvasCollection.getActualCanvas();
  118. }
  119. private class GuiMenuBar extends JMenuBar {
  120. //Menus
  121. private final JMenu fileMenu = new JMenu("File");
  122. private final JMenu editMenu = new JMenu("Edit");
  123. private final JMenu viewMenu = new JMenu("View");
  124. private final JMenu windowMenu = new JMenu("Window");
  125. private final JMenu helpMenu = new JMenu("Help");
  126. // FileMenu
  127. private final JMenuItem newMenuButton = new JMenuItem("New");
  128. private final JMenuItem openMenuButton = new JMenuItem("Open..");
  129. private final JMenuItem saveMenuButton = new JMenuItem("Save");
  130. private final JMenuItem saveAsMenuButton = new JMenuItem("Save..");
  131. // EditMenu
  132. private final JMenuItem undoButton = new JMenuItem("Undo");
  133. private final JMenuItem redoButton = new JMenuItem("Redo");
  134. private final JMenuItem copyButton = new JMenuItem("Copy");
  135. private final JMenuItem pasteButton = new JMenuItem("Paste");
  136. private final JMenuItem cutButton = new JMenuItem("Cut");
  137. private final JMenu selectionMenu = new JMenu("Selection");
  138. private final JMenuItem selectAllButton = new JMenuItem("All");
  139. private final JMenuItem clearSelectionButton = new JMenuItem("Clear");
  140. private final JMenuItem invertSelectionButton = new JMenuItem("Invert");
  141. private final JMenuItem groupButton = new JMenuItem("Group");
  142. private final JMenuItem ungroupButton = new JMenuItem("Ungroup");
  143. private final JMenuItem removeButton = new JMenuItem("Remove");
  144. private final JMenuItem edgePropertiesButton = new JMenuItem("Edge Properties");
  145. private final JMenuItem alignAllButton = new JMenuItem("Align All");
  146. private final JMenu resetMenu = new JMenu("Reset");
  147. private final JMenuItem resetCategoryButton = new JMenuItem("Categories");
  148. //HelpMenu
  149. private final JMenuItem introductionButton = new JMenuItem("Introduction");
  150. private final JMenuItem userManualButton = new JMenuItem("User Manual");
  151. private final JMenuItem algorithmHelpButton = new JMenuItem("Algorithm Introduction");
  152. private final JMenuItem codeDocumentationButton = new JMenuItem("Code Documentation");
  153. private final JMenuItem aboutUsButton = new JMenuItem("About Us");
  154. //ViewMenu
  155. private final JMenu appearanceMenu = new JMenu("Appearance");
  156. private final JMenuItem canvasSizeButton = new JMenuItem("Set View Size");
  157. private final JCheckBoxMenuItem showSupplyBarsCheckBox = new JCheckBoxMenuItem("Show supply bars.", true);
  158. private final JFileChooser fileChooser = initFileChooser();
  159. private final static int IconSize = 15;
  160. //WindowMenu
  161. JMenuItem algorithmButton = new JMenuItem("Algorithm Panel", new ImageIcon(Import
  162. .loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
  163. JMenuItem outlinerButton = new JMenuItem("Outliner", new ImageIcon(Import
  164. .loadImage(ImagePreference.Button.Menu.Outliner).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
  165. JMenuItem flexMenuButton = new JMenuItem("Flexibility Panel", new ImageIcon(Import
  166. .loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
  167. private final static Vec2i DefaultOffset = new Vec2i(20,20);
  168. GuiMenuBar() {
  169. initMenuLayout();
  170. initButtonActions();
  171. initButtonShortCuts();
  172. }
  173. private static JFileChooser initFileChooser() {
  174. JFileChooser safeLoadFileChooser = new JFileChooser(prefs.get(PreferenceKeys.Gui.DefaultFolder,
  175. FileSystemView.getFileSystemView().getDefaultDirectory().getPath()));
  176. safeLoadFileChooser.setFileFilter(new FileNameExtensionFilter("Holeg json files", "json"));
  177. safeLoadFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
  178. safeLoadFileChooser.setAcceptAllFileFilterUsed(false);
  179. return safeLoadFileChooser;
  180. }
  181. private void initMenuLayout() {
  182. add(fileMenu);
  183. add(editMenu);
  184. add(viewMenu);
  185. add(windowMenu);
  186. add(helpMenu);
  187. fileMenu.add(newMenuButton);
  188. fileMenu.add(openMenuButton);
  189. fileMenu.addSeparator();
  190. fileMenu.add(saveMenuButton);
  191. fileMenu.add(saveAsMenuButton);
  192. editMenu.add(undoButton);
  193. editMenu.add(redoButton);
  194. editMenu.addSeparator();
  195. editMenu.add(copyButton);
  196. editMenu.add(pasteButton);
  197. editMenu.add(cutButton);
  198. editMenu.addSeparator();
  199. editMenu.add(selectionMenu);
  200. selectionMenu.add(selectAllButton);
  201. selectionMenu.add(clearSelectionButton);
  202. selectionMenu.add(invertSelectionButton);
  203. editMenu.addSeparator();
  204. editMenu.add(groupButton);
  205. editMenu.add(ungroupButton);
  206. editMenu.addSeparator();
  207. editMenu.add(removeButton);
  208. editMenu.addSeparator();
  209. editMenu.add(edgePropertiesButton);
  210. editMenu.add(alignAllButton);
  211. editMenu.add(resetMenu);
  212. resetMenu.add(resetCategoryButton);
  213. helpMenu.add(introductionButton);
  214. helpMenu.add(userManualButton);
  215. helpMenu.add(algorithmHelpButton);
  216. helpMenu.add(codeDocumentationButton);
  217. helpMenu.add(aboutUsButton);
  218. viewMenu.add(appearanceMenu);
  219. appearanceMenu.add(showSupplyBarsCheckBox);
  220. viewMenu.add(canvasSizeButton);
  221. windowMenu.add(algorithmButton);
  222. windowMenu.add(outlinerButton);
  223. windowMenu.add(flexMenuButton);
  224. }
  225. private void initButtonActions() {
  226. newMenuButton.addActionListener(clicked -> newFile());
  227. openMenuButton.addActionListener(clicked -> openFile());
  228. saveMenuButton.addActionListener(clicked -> saveFile());
  229. saveAsMenuButton.addActionListener(clicked -> saveNewFile());
  230. groupButton.addActionListener(clicked -> control.group());
  231. ungroupButton.addActionListener(clicked -> control.ungroup());
  232. edgePropertiesButton.addActionListener(actionEvent -> new EditEdgesPopUp(Gui.this, control));
  233. alignAllButton.addActionListener(clicked -> {
  234. //TODO(Tom2022-01-14): recreateTryToAlignObjects
  235. log.info("Not implemented yet.");
  236. });
  237. resetCategoryButton.addActionListener(clicked -> control.resetCategories());
  238. showSupplyBarsCheckBox.addActionListener(clicked -> toggleSupplyBarAppearance());
  239. canvasSizeButton.addActionListener(clicked -> new CanvasResizePopUp(control, Gui.this));
  240. algorithmButton.addActionListener(clicked -> new AddOnWindow(Gui.this, control));
  241. outlinerButton.addActionListener(clicked -> new Outliner(Gui.this, control));
  242. flexMenuButton.addActionListener(clicked -> new FlexWindow(Gui.this, control));
  243. selectAllButton.addActionListener(clicked -> selectAll());
  244. clearSelectionButton.addActionListener(clicked -> control.clearSelection());
  245. invertSelectionButton.addActionListener(clicked -> invertSelection());
  246. copyButton.addActionListener(clicked -> control.copy());
  247. cutButton.addActionListener(clicked -> control.cut());
  248. pasteButton.addActionListener(clicked -> paste());
  249. removeButton.addActionListener(clicked -> removeSelectedObjects());
  250. String tkWikiWebpage = "https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/";
  251. introductionButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Introduction+V2.1"));
  252. userManualButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "User+Manual+V2.1"));
  253. algorithmHelpButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Algorithms+V2.1"));
  254. codeDocumentationButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Code+documentation+V2.1"));
  255. aboutUsButton.addActionListener(clicked -> new AboutUsPopUp(Gui.this));
  256. }
  257. private void openWebpage(String URL) {
  258. try {
  259. java.awt.Desktop.getDesktop().browse(new URI(URL));
  260. } catch (Exception e) {
  261. e.printStackTrace();
  262. }
  263. }
  264. private void initButtonShortCuts() {
  265. int defaultModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
  266. int defaultShiftModifier = defaultModifier + InputEvent.SHIFT_DOWN_MASK;
  267. saveMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultModifier));
  268. saveAsMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultShiftModifier));
  269. openMenuButton.setAccelerator(KeyStroke.getKeyStroke('O', defaultModifier));
  270. newMenuButton.setAccelerator(KeyStroke.getKeyStroke('N', defaultModifier));
  271. undoButton.setAccelerator(KeyStroke.getKeyStroke('Z', defaultModifier));
  272. redoButton.setAccelerator(KeyStroke.getKeyStroke('Y', defaultModifier));
  273. copyButton.setAccelerator(KeyStroke.getKeyStroke('C', defaultModifier));
  274. pasteButton.setAccelerator(KeyStroke.getKeyStroke('V', defaultModifier));
  275. cutButton.setAccelerator(KeyStroke.getKeyStroke('X', defaultModifier));
  276. selectAllButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultModifier));
  277. clearSelectionButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultShiftModifier));
  278. invertSelectionButton.setAccelerator(KeyStroke.getKeyStroke('I', defaultModifier));
  279. groupButton.setAccelerator(KeyStroke.getKeyStroke('G', defaultModifier));
  280. ungroupButton.setAccelerator(KeyStroke.getKeyStroke('U', defaultModifier));
  281. removeButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
  282. }
  283. private void toggleSupplyBarAppearance() {
  284. GuiSettings.showSupplyBars = showSupplyBarsCheckBox.isSelected();
  285. }
  286. private void saveFile() {
  287. GuiSettings.getActualSaveFile().ifPresentOrElse(control::saveFile, this::saveNewFile);
  288. }
  289. private void saveNewFile() {
  290. if (fileChooser.showSaveDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
  291. String path = fileChooser.getSelectedFile().getPath();
  292. if (!path.endsWith(".json")) {
  293. path += ".json";
  294. }
  295. prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
  296. control.saveFile(new File(path));
  297. }
  298. }
  299. private void openFile() {
  300. if (fileChooser.showOpenDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
  301. prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
  302. control.loadFile(fileChooser.getSelectedFile());
  303. }
  304. }
  305. private void newFile() {
  306. if (control.getModel().getCanvas().getObjectsInThisLayer().findAny().isPresent()) {
  307. int selectedOption = JOptionPane.showConfirmDialog(Gui.this, "Do you want to save your current model?",
  308. "Warning", JOptionPane.YES_NO_OPTION);
  309. if (selectedOption == JOptionPane.YES_OPTION) {
  310. saveNewFile();
  311. }
  312. }
  313. control.clearModel();
  314. }
  315. private void selectAll(){
  316. control.setSelection(getActualCanvas().getGroupNode()
  317. .getObjectsInThisLayer().collect(Collectors.toSet()));
  318. }
  319. private void invertSelection() {
  320. control.toggleSelectedObjects(getActualCanvas().getGroupNode()
  321. .getObjectsInThisLayer().collect(Collectors.toSet()));
  322. }
  323. private void removeSelectedObjects() {
  324. control.deleteCanvasObjects(GuiSettings.getSelectedObjects());
  325. control.clearSelection();
  326. }
  327. private void paste() {
  328. Vec2i middlePosition = GroupNode.calculateMiddlePosition(GuiSettings.getClipboardObjects());
  329. Optional<Vec2i> offset = Optional.ofNullable(getActualCanvas().getMousePosition())
  330. .map(point -> new Vec2i(point).subtract(middlePosition));
  331. control.paste(getActualCanvas().getGroupNode(), offset.orElse(DefaultOffset));
  332. }
  333. }
  334. }