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