1 package nl.tudelft.simulation.dsol.swing.gui;
2
3 import java.awt.Component;
4 import java.awt.Dimension;
5 import java.awt.Font;
6 import java.awt.Frame;
7 import java.awt.event.MouseAdapter;
8 import java.awt.event.MouseEvent;
9 import java.awt.event.WindowAdapter;
10 import java.awt.event.WindowEvent;
11 import java.io.File;
12 import java.io.FileReader;
13 import java.io.FileWriter;
14 import java.io.IOException;
15 import java.util.Dictionary;
16 import java.util.Enumeration;
17 import java.util.Properties;
18
19 import javax.swing.ButtonGroup;
20 import javax.swing.JCheckBoxMenuItem;
21 import javax.swing.JComponent;
22 import javax.swing.JFrame;
23 import javax.swing.JLabel;
24 import javax.swing.JMenu;
25 import javax.swing.JMenuItem;
26 import javax.swing.JPopupMenu;
27 import javax.swing.JSlider;
28 import javax.swing.MenuElement;
29 import javax.swing.MenuSelectionManager;
30 import javax.swing.WindowConstants;
31 import javax.swing.event.ChangeEvent;
32 import javax.swing.event.ChangeListener;
33
34 import nl.tudelft.simulation.dsol.swing.animation.d2.AnimationPanel;
35 import nl.tudelft.simulation.dsol.swing.gui.appearance.Appearance;
36 import nl.tudelft.simulation.dsol.swing.gui.appearance.AppearanceControl;
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class DsolApplication extends JFrame
51 {
52
53 private static final long serialVersionUID = 20190118L;
54
55
56 private final DsolPanel panel;
57
58
59 @SuppressWarnings("checkstyle:visibilitymodifier")
60 protected boolean closed = false;
61
62
63 @SuppressWarnings("checkstyle:visibilitymodifier")
64 protected Properties frameProperties;
65
66
67 private Appearance appearance = Appearance.BRIGHT;
68
69
70
71
72
73 public DsolApplication(final DsolPanel panel, final String title)
74 {
75 setPreferredSize(new Dimension(1024, 768));
76 this.panel = panel;
77 setTitle(title);
78 setContentPane(panel);
79 pack();
80 setExtendedState(Frame.MAXIMIZED_BOTH);
81 setVisible(true);
82
83 setExitOnClose(true);
84 addWindowListener(new WindowAdapter()
85 {
86 @Override
87 public void windowClosing(final WindowEvent windowEvent)
88 {
89 DsolApplication.this.closed = true;
90 super.windowClosing(windowEvent);
91 }
92 });
93
94
95
96
97
98
99 String sep = System.getProperty("file.separator");
100 String propertiesFile = System.getProperty("user.home") + sep + "dsol" + sep + "properties.ini";
101 addWindowListener(new WindowAdapter()
102 {
103
104 @Override
105 public void windowClosing(final WindowEvent windowEvent)
106 {
107 try
108 {
109 File f = new File(propertiesFile);
110 f.getParentFile().mkdirs();
111 FileWriter writer = new FileWriter(f);
112 DsolApplication.this.frameProperties.store(writer, "DSOL user settings");
113 }
114 catch (IOException exception)
115 {
116 System.err.println("Could not store properties at " + propertiesFile + ".");
117 }
118 }
119 });
120
121
122 Properties defaults = new Properties();
123 defaults.setProperty("Appearance", "BRIGHT");
124 this.frameProperties = new Properties(defaults);
125 try
126 {
127 FileReader reader = new FileReader(propertiesFile);
128 this.frameProperties.load(reader);
129 }
130 catch (IOException ioe)
131 {
132
133 }
134 this.appearance = Appearance.valueOf(this.frameProperties.getProperty("Appearance").toUpperCase());
135
136
137 class AppearanceControlMenu extends JMenu implements AppearanceControl
138 {
139
140 private static final long serialVersionUID = 20180206L;
141
142
143
144
145
146 AppearanceControlMenu(final String string)
147 {
148 super(string);
149 }
150
151
152 @Override
153 public boolean isFont()
154 {
155 return true;
156 }
157
158
159 @Override
160 public String toString()
161 {
162 return "AppearanceControlMenu []";
163 }
164 }
165
166
167 JMenu app = new AppearanceControlMenu("Appearance");
168 app.addMouseListener(new SubMenuShower(app));
169 ButtonGroup appGroup = new ButtonGroup();
170 for (Appearance appearanceValue : Appearance.values())
171 {
172 appGroup.add(addAppearance(app, appearanceValue));
173 }
174
175
176 class AppearanceControlPopupMenu extends JPopupMenu implements AppearanceControl
177 {
178
179 private static final long serialVersionUID = 20180206L;
180
181
182 @Override
183 public boolean isFont()
184 {
185 return true;
186 }
187
188
189 @Override
190 public String toString()
191 {
192 return "AppearanceControlPopupMenu []";
193 }
194 }
195
196
197 JPopupMenu popMenu = new AppearanceControlPopupMenu();
198 popMenu.add(app);
199 panel.setComponentPopupMenu(popMenu);
200
201
202 setAppearance(getAppearance());
203 }
204
205
206
207
208
209 public void setAppearance(final Appearance appearance)
210 {
211 this.appearance = appearance;
212 setAppearance(this.getContentPane(), appearance);
213 this.frameProperties.setProperty("Appearance", appearance.toString());
214 }
215
216
217
218
219
220
221 private void setAppearance(final Component c, final Appearance appear)
222 {
223 if (c instanceof AppearanceControl)
224 {
225 AppearanceControl ac = (AppearanceControl) c;
226 if (ac.isBackground())
227 {
228 c.setBackground(appear.getBackground());
229 }
230 if (ac.isForeground())
231 {
232 c.setForeground(appear.getForeground());
233 }
234 if (ac.isFont())
235 {
236 changeFont(c, appear.getFont());
237 }
238 }
239 else if (c instanceof AnimationPanel)
240 {
241
242 c.setBackground(appear.getBackdrop());
243 c.setForeground(appear.getForeground());
244 changeFont(c, appear.getFont());
245 }
246 else
247 {
248
249 c.setBackground(appear.getBackground());
250 c.setForeground(appear.getForeground());
251 changeFont(c, appear.getFont());
252 }
253 if (c instanceof JSlider)
254 {
255
256 Dictionary<?, ?> dictionary = ((JSlider) c).getLabelTable();
257 Enumeration<?> keys = dictionary.keys();
258 while (keys.hasMoreElements())
259 {
260 JLabel label = (JLabel) dictionary.get(keys.nextElement());
261 label.setForeground(appear.getForeground());
262 label.setBackground(appear.getBackground());
263 }
264 }
265
266 if (c instanceof JComponent)
267 {
268 for (Component child : ((JComponent) c).getComponents())
269 {
270 setAppearance(child, appear);
271 }
272 }
273 }
274
275
276
277
278
279
280 private void changeFont(final Component c, final String font)
281 {
282 Font prev = c.getFont();
283 c.setFont(new Font(font, prev.getStyle(), prev.getSize()));
284 }
285
286
287
288
289
290 public Appearance getAppearance()
291 {
292 return this.appearance;
293 }
294
295
296
297
298
299
300
301 private JMenuItem addAppearance(final JMenu group, final Appearance appear)
302 {
303 JCheckBoxMenuItem check = new StayOpenCheckBoxMenuItem(appear.getName(), appear.equals(getAppearance()));
304 check.addMouseListener(new MouseAdapter()
305 {
306
307 @Override
308 public void mouseClicked(final MouseEvent e)
309 {
310 setAppearance(appear);
311 }
312 });
313 return group.add(check);
314 }
315
316
317
318
319
320 public void setExitOnClose(final boolean exitOnClose)
321 {
322 if (exitOnClose)
323 {
324 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
325 }
326 else
327 {
328 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
329 }
330 }
331
332
333
334
335
336 public DsolPanel getDsolPanel()
337 {
338 return this.panel;
339 }
340
341
342
343
344
345 public boolean isClosed()
346 {
347 return this.closed;
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362 private class SubMenuShower extends MouseAdapter
363 {
364
365 private JMenu menu;
366
367
368
369
370
371 SubMenuShower(final JMenu menu)
372 {
373 this.menu = menu;
374 }
375
376
377 @Override
378 public void mouseEntered(final MouseEvent e)
379 {
380 MenuSelectionManager.defaultManager().setSelectedPath(
381 new MenuElement[] {(MenuElement) this.menu.getParent(), this.menu, this.menu.getPopupMenu()});
382 }
383
384
385 @Override
386 public String toString()
387 {
388 return "SubMenuShower [menu=" + this.menu + "]";
389 }
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404 private static class StayOpenCheckBoxMenuItem extends JCheckBoxMenuItem implements AppearanceControl
405 {
406
407 private static final long serialVersionUID = 20180206L;
408
409
410 private static MenuElement[] path;
411
412 {
413 getModel().addChangeListener(new ChangeListener()
414 {
415
416 @Override
417 public void stateChanged(final ChangeEvent e)
418 {
419 if (getModel().isArmed() && isShowing())
420 {
421 setPath(MenuSelectionManager.defaultManager().getSelectedPath());
422 }
423 }
424 });
425 }
426
427
428
429
430
431 public static void setPath(final MenuElement[] path)
432 {
433 StayOpenCheckBoxMenuItem.path = path;
434 }
435
436
437
438
439
440
441 StayOpenCheckBoxMenuItem(final String text, final boolean selected)
442 {
443 super(text, selected);
444 }
445
446
447 @Override
448 public void doClick(final int pressTime)
449 {
450 super.doClick(pressTime);
451 for (MenuElement element : path)
452 {
453 if (element instanceof JComponent)
454 {
455 ((JComponent) element).setVisible(true);
456 }
457 }
458 JMenu menu = (JMenu) path[path.length - 3];
459 MenuSelectionManager.defaultManager()
460 .setSelectedPath(new MenuElement[] {(MenuElement) menu.getParent(), menu, menu.getPopupMenu()});
461 }
462
463
464 @Override
465 public boolean isFont()
466 {
467 return true;
468 }
469
470
471 @Override
472 public String toString()
473 {
474 return "StayOpenCheckBoxMenuItem []";
475 }
476 }
477 }