source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java@ 6104

Last change on this file since 6104 was 6104, checked in by Don-vip, 11 years ago

see #8902 - Small performance enhancements / coding style (patch by shinigami):

  • while -> foreach
  • for -> for each

plus:

  • cleanup of FileDrop class to make it more integrated into JOSM core + remove warnings
  • Property svn:eol-style set to native
File size: 31.7 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.AWTEvent;
7import java.awt.BorderLayout;
8import java.awt.Component;
9import java.awt.Container;
10import java.awt.Dimension;
11import java.awt.FlowLayout;
12import java.awt.Graphics;
13import java.awt.GridBagLayout;
14import java.awt.GridLayout;
15import java.awt.Image;
16import java.awt.Rectangle;
17import java.awt.Toolkit;
18import java.awt.event.AWTEventListener;
19import java.awt.event.ActionEvent;
20import java.awt.event.ActionListener;
21import java.awt.event.ComponentAdapter;
22import java.awt.event.ComponentEvent;
23import java.awt.event.MouseEvent;
24import java.awt.event.WindowAdapter;
25import java.awt.event.WindowEvent;
26import java.beans.PropertyChangeEvent;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Collection;
30import java.util.LinkedList;
31import java.util.List;
32
33import javax.swing.AbstractAction;
34import javax.swing.BorderFactory;
35import javax.swing.ImageIcon;
36import javax.swing.JButton;
37import javax.swing.JCheckBoxMenuItem;
38import javax.swing.JComponent;
39import javax.swing.JDialog;
40import javax.swing.JLabel;
41import javax.swing.JMenu;
42import javax.swing.JOptionPane;
43import javax.swing.JPanel;
44import javax.swing.JPopupMenu;
45import javax.swing.JRadioButtonMenuItem;
46import javax.swing.JScrollPane;
47import javax.swing.JToggleButton;
48import javax.swing.SwingUtilities;
49
50import org.openstreetmap.josm.Main;
51import org.openstreetmap.josm.actions.JosmAction;
52import org.openstreetmap.josm.data.preferences.ParametrizedEnumProperty;
53import org.openstreetmap.josm.gui.MainMenu;
54import org.openstreetmap.josm.gui.ShowHideButtonListener;
55import org.openstreetmap.josm.gui.SideButton;
56import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
57import org.openstreetmap.josm.gui.help.HelpUtil;
58import org.openstreetmap.josm.gui.help.Helpful;
59import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
60import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
61import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
62import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
63import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
64import org.openstreetmap.josm.tools.Destroyable;
65import org.openstreetmap.josm.tools.GBC;
66import org.openstreetmap.josm.tools.ImageProvider;
67import org.openstreetmap.josm.tools.Shortcut;
68import org.openstreetmap.josm.tools.WindowGeometry;
69import org.openstreetmap.josm.tools.WindowGeometry.WindowGeometryException;
70
71/**
72 * This class is a toggle dialog that can be turned on and off.
73 *
74 */
75public class ToggleDialog extends JPanel implements ShowHideButtonListener, Helpful, AWTEventListener {
76
77 public enum ButtonHiddingType {
78 ALWAYS_SHOWN, ALWAYS_HIDDEN, DYNAMIC
79 }
80
81 private final ParametrizedEnumProperty<ButtonHiddingType> PROP_BUTTON_HIDING = new ParametrizedEnumProperty<ToggleDialog.ButtonHiddingType>(ButtonHiddingType.class, ButtonHiddingType.DYNAMIC) {
82 @Override
83 protected String getKey(String... params) {
84 return preferencePrefix + ".buttonhiding";
85 }
86 @Override
87 protected ButtonHiddingType parse(String s) {
88 try {
89 return super.parse(s);
90 } catch (IllegalArgumentException e) {
91 // Legacy settings
92 return Boolean.parseBoolean(s)?ButtonHiddingType.DYNAMIC:ButtonHiddingType.ALWAYS_SHOWN;
93 }
94 }
95 };
96
97 /** The action to toggle this dialog */
98 protected final ToggleDialogAction toggleAction;
99 protected String preferencePrefix;
100 final protected String name;
101
102 /** DialogsPanel that manages all ToggleDialogs */
103 protected DialogsPanel dialogsPanel;
104
105 protected TitleBar titleBar;
106
107 /**
108 * Indicates whether the dialog is showing or not.
109 */
110 protected boolean isShowing;
111 /**
112 * If isShowing is true, indicates whether the dialog is docked or not, e. g.
113 * shown as part of the main window or as a separate dialog window.
114 */
115 protected boolean isDocked;
116 /**
117 * If isShowing and isDocked are true, indicates whether the dialog is
118 * currently minimized or not.
119 */
120 protected boolean isCollapsed;
121 /**
122 * Indicates whether dynamic button hiding is active or not.
123 */
124 protected ButtonHiddingType buttonHiding;
125
126 /** the preferred height if the toggle dialog is expanded */
127 private int preferredHeight;
128
129 /** the label in the title bar which shows whether the toggle dialog is expanded or collapsed */
130 private JLabel lblMinimized;
131
132 /** the label in the title bar which shows whether buttons are dynamic or not */
133 private JButton buttonsHide = null;
134
135 /** the JDialog displaying the toggle dialog as undocked dialog */
136 protected JDialog detachedDialog;
137
138 protected JToggleButton button;
139 private JPanel buttonsPanel;
140 private List<javax.swing.Action> buttonActions = new ArrayList<javax.swing.Action>();
141
142 /** holds the menu entry in the windows menu. Required to properly
143 * toggle the checkbox on show/hide
144 */
145 protected JCheckBoxMenuItem windowMenuItem;
146
147 /**
148 * The linked preferences class (optional). If set, accessible from the title bar with a dedicated button
149 */
150 protected Class<? extends PreferenceSetting> preferenceClass;
151
152 /**
153 * Constructor
154 *
155 * @param name the name of the dialog
156 * @param iconName the name of the icon to be displayed
157 * @param tooltip the tool tip
158 * @param shortcut the shortcut
159 * @param preferredHeight the preferred height for the dialog
160 */
161 public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
162 this(name, iconName, tooltip, shortcut, preferredHeight, false);
163 }
164 /**
165 * Constructor
166
167 * @param name the name of the dialog
168 * @param iconName the name of the icon to be displayed
169 * @param tooltip the tool tip
170 * @param shortcut the shortcut
171 * @param preferredHeight the preferred height for the dialog
172 * @param defShow if the dialog should be shown by default, if there is no preference
173 */
174 public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight, boolean defShow) {
175 this(name, iconName, tooltip, shortcut, preferredHeight, defShow, null);
176 }
177 /**
178 * Constructor
179 *
180 * @param name the name of the dialog
181 * @param iconName the name of the icon to be displayed
182 * @param tooltip the tool tip
183 * @param shortcut the shortcut
184 * @param preferredHeight the preferred height for the dialog
185 * @param defShow if the dialog should be shown by default, if there is no preference
186 * @param prefClass the preferences settings class, or null if not applicable
187 */
188 public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight, boolean defShow, Class<? extends PreferenceSetting> prefClass) {
189 super(new BorderLayout());
190 this.preferencePrefix = iconName;
191 this.name = name;
192 this.preferenceClass = prefClass;
193
194 /** Use the full width of the parent element */
195 setPreferredSize(new Dimension(0, preferredHeight));
196 /** Override any minimum sizes of child elements so the user can resize freely */
197 setMinimumSize(new Dimension(0,0));
198 this.preferredHeight = preferredHeight;
199 toggleAction = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortcut, iconName);
200 String helpId = "Dialog/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
201 toggleAction.putValue("help", helpId.substring(0, helpId.length()-6));
202
203 isShowing = Main.pref.getBoolean(preferencePrefix+".visible", defShow);
204 isDocked = Main.pref.getBoolean(preferencePrefix+".docked", true);
205 isCollapsed = Main.pref.getBoolean(preferencePrefix+".minimized", false);
206 buttonHiding = PROP_BUTTON_HIDING.get();
207
208 /** show the minimize button */
209 titleBar = new TitleBar(name, iconName);
210 add(titleBar, BorderLayout.NORTH);
211
212 setBorder(BorderFactory.createEtchedBorder());
213
214 Main.redirectToMainContentPane(this);
215
216 windowMenuItem = MainMenu.addWithCheckbox(Main.main.menu.windowMenu,
217 (JosmAction) getToggleAction(),
218 MainMenu.WINDOW_MENU_GROUP.TOGGLE_DIALOG);
219 }
220
221 /**
222 * The action to toggle the visibility state of this toggle dialog.
223 *
224 * Emits {@link PropertyChangeEvent}s for the property <tt>selected</tt>:
225 * <ul>
226 * <li>true, if the dialog is currently visible</li>
227 * <li>false, if the dialog is currently invisible</li>
228 * </ul>
229 *
230 */
231 public final class ToggleDialogAction extends JosmAction {
232
233 private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
234 super(name, iconName, tooltip, shortcut, false);
235 }
236
237 @Override
238 public void actionPerformed(ActionEvent e) {
239 toggleButtonHook();
240 if(getValue("toolbarbutton") != null && getValue("toolbarbutton") instanceof JButton) {
241 ((JButton) getValue("toolbarbutton")).setSelected(!isShowing);
242 }
243 if (isShowing) {
244 hideDialog();
245 if (dialogsPanel != null) {
246 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
247 }
248 hideNotify();
249 } else {
250 showDialog();
251 if (isDocked && isCollapsed) {
252 expand();
253 }
254 if (isDocked && dialogsPanel != null) {
255 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
256 }
257 showNotify();
258 }
259 }
260
261 @Override
262 public void destroy() {
263 super.destroy();
264 }
265 }
266
267 /**
268 * Shows the dialog
269 */
270 public void showDialog() {
271 setIsShowing(true);
272 if (!isDocked) {
273 detach();
274 } else {
275 dock();
276 this.setVisible(true);
277 }
278 // toggling the selected value in order to enforce PropertyChangeEvents
279 setIsShowing(true);
280 windowMenuItem.setState(true);
281 toggleAction.putValue("selected", false);
282 toggleAction.putValue("selected", true);
283 }
284
285 /**
286 * Changes the state of the dialog such that the user can see the content.
287 * (takes care of the panel reconstruction)
288 */
289 public void unfurlDialog() {
290 if (isDialogInDefaultView())
291 return;
292 if (isDialogInCollapsedView()) {
293 expand();
294 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, this);
295 } else if (!isDialogShowing()) {
296 showDialog();
297 if (isDocked && isCollapsed) {
298 expand();
299 }
300 if (isDocked) {
301 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, this);
302 }
303 showNotify();
304 }
305 }
306
307 @Override
308 public void buttonHidden() {
309 if ((Boolean) toggleAction.getValue("selected")) {
310 toggleAction.actionPerformed(null);
311 }
312 }
313
314 @Override
315 public void buttonShown() {
316 unfurlDialog();
317 }
318
319
320 /**
321 * Hides the dialog
322 */
323 public void hideDialog() {
324 closeDetachedDialog();
325 this.setVisible(false);
326 windowMenuItem.setState(false);
327 setIsShowing(false);
328 toggleAction.putValue("selected", false);
329 }
330
331 /**
332 * Displays the toggle dialog in the toggle dialog view on the right
333 * of the main map window.
334 *
335 */
336 protected void dock() {
337 detachedDialog = null;
338 titleBar.setVisible(true);
339 setIsDocked(true);
340 }
341
342 /**
343 * Display the dialog in a detached window.
344 *
345 */
346 protected void detach() {
347 setContentVisible(true);
348 this.setVisible(true);
349 titleBar.setVisible(false);
350 detachedDialog = new DetachedDialog();
351 detachedDialog.setVisible(true);
352 setIsShowing(true);
353 setIsDocked(false);
354 }
355
356 /**
357 * Collapses the toggle dialog to the title bar only
358 *
359 */
360 public void collapse() {
361 if (isDialogInDefaultView()) {
362 setContentVisible(false);
363 setIsCollapsed(true);
364 setPreferredSize(new Dimension(0,20));
365 setMaximumSize(new Dimension(Integer.MAX_VALUE,20));
366 setMinimumSize(new Dimension(Integer.MAX_VALUE,20));
367 lblMinimized.setIcon(ImageProvider.get("misc", "minimized"));
368 }
369 else throw new IllegalStateException();
370 }
371
372 /**
373 * Expands the toggle dialog
374 */
375 protected void expand() {
376 if (isDialogInCollapsedView()) {
377 setContentVisible(true);
378 setIsCollapsed(false);
379 setPreferredSize(new Dimension(0,preferredHeight));
380 setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
381 lblMinimized.setIcon(ImageProvider.get("misc", "normal"));
382 }
383 else throw new IllegalStateException();
384 }
385
386 /**
387 * Sets the visibility of all components in this toggle dialog, except the title bar
388 *
389 * @param visible true, if the components should be visible; false otherwise
390 */
391 protected void setContentVisible(boolean visible) {
392 Component[] comps = getComponents();
393 for (Component comp : comps) {
394 if (comp != titleBar && (!visible || comp != buttonsPanel || buttonHiding != ButtonHiddingType.ALWAYS_HIDDEN)) {
395 comp.setVisible(visible);
396 }
397 }
398 }
399
400 public void destroy() {
401 closeDetachedDialog();
402 hideNotify();
403 Main.main.menu.windowMenu.remove(windowMenuItem);
404 Toolkit.getDefaultToolkit().removeAWTEventListener(this);
405 destroyComponents(this);
406 }
407
408 private void destroyComponents(Component component) {
409 if (component instanceof Container) {
410 for (Component c: ((Container)component).getComponents()) {
411 destroyComponents(c);
412 }
413 }
414 if (component instanceof Destroyable) {
415 ((Destroyable) component).destroy();
416 }
417 }
418
419 /**
420 * Closes the detached dialog if this toggle dialog is currently displayed
421 * in a detached dialog.
422 *
423 */
424 public void closeDetachedDialog() {
425 if (detachedDialog != null) {
426 detachedDialog.setVisible(false);
427 detachedDialog.getContentPane().removeAll();
428 detachedDialog.dispose();
429 }
430 }
431
432 /**
433 * Called when toggle dialog is shown (after it was created or expanded). Descendants may overwrite this
434 * method, it's a good place to register listeners needed to keep dialog updated
435 */
436 public void showNotify() {
437
438 }
439
440 /**
441 * Called when toggle dialog is hidden (collapsed, removed, MapFrame is removed, ...). Good place to unregister
442 * listeners
443 */
444 public void hideNotify() {
445
446 }
447
448 /**
449 * The title bar displayed in docked mode
450 *
451 */
452 protected class TitleBar extends JPanel {
453 final private JLabel lblTitle;
454 final private JComponent lblTitle_weak;
455
456 public TitleBar(String toggleDialogName, String iconName) {
457 setLayout(new GridBagLayout());
458
459 lblMinimized = new JLabel(ImageProvider.get("misc", "normal"));
460 add(lblMinimized);
461
462 // scale down the dialog icon
463 ImageIcon inIcon = ImageProvider.get("dialogs", iconName);
464 ImageIcon smallIcon = new ImageIcon(inIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
465 lblTitle = new JLabel("",smallIcon, JLabel.TRAILING);
466 lblTitle.setIconTextGap(8);
467
468 JPanel conceal = new JPanel();
469 conceal.add(lblTitle);
470 conceal.setVisible(false);
471 add(conceal, GBC.std());
472
473 // Cannot add the label directly since it would displace other elements on resize
474 lblTitle_weak = new JComponent() {
475 @Override
476 public void paintComponent(Graphics g) {
477 lblTitle.paint(g);
478 }
479 };
480 lblTitle_weak.setPreferredSize(new Dimension(Integer.MAX_VALUE,20));
481 lblTitle_weak.setMinimumSize(new Dimension(0,20));
482 add(lblTitle_weak, GBC.std().fill(GBC.HORIZONTAL));
483
484 if(Main.pref.getBoolean("dialog.dynamic.buttons", true)) {
485 buttonsHide = new JButton(ImageProvider.get("misc", buttonHiding != ButtonHiddingType.ALWAYS_SHOWN ? "buttonhide" : "buttonshow"));
486 buttonsHide.setToolTipText(tr("Toggle dynamic buttons"));
487 buttonsHide.setBorder(BorderFactory.createEmptyBorder());
488 buttonsHide.addActionListener(
489 new ActionListener(){
490 @Override
491 public void actionPerformed(ActionEvent e) {
492 setIsButtonHiding(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN?ButtonHiddingType.DYNAMIC:ButtonHiddingType.ALWAYS_SHOWN);
493 }
494 }
495 );
496 add(buttonsHide);
497 }
498
499 // show the pref button if applicable
500 if (preferenceClass != null) {
501 inIcon = ImageProvider.get("preference");
502 smallIcon = new ImageIcon(inIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
503 JButton pref = new JButton(smallIcon);
504 pref.setToolTipText(tr("Open preferences for this panel"));
505 pref.setBorder(BorderFactory.createEmptyBorder());
506 pref.addActionListener(
507 new ActionListener(){
508 @Override
509 @SuppressWarnings("unchecked")
510 public void actionPerformed(ActionEvent e) {
511 final PreferenceDialog p = new PreferenceDialog(Main.parent);
512 if (TabPreferenceSetting.class.isAssignableFrom(preferenceClass)) {
513 p.selectPreferencesTabByClass((Class<? extends TabPreferenceSetting>) preferenceClass);
514 } else if (SubPreferenceSetting.class.isAssignableFrom(preferenceClass)) {
515 p.selectSubPreferencesTabByClass((Class<? extends SubPreferenceSetting>) preferenceClass);
516 }
517 p.setVisible(true);
518 }
519 }
520 );
521 add(pref);
522 }
523
524 // show the sticky button
525 JButton sticky = new JButton(ImageProvider.get("misc", "sticky"));
526 sticky.setToolTipText(tr("Undock the panel"));
527 sticky.setBorder(BorderFactory.createEmptyBorder());
528 sticky.addActionListener(
529 new ActionListener(){
530 @Override
531 public void actionPerformed(ActionEvent e) {
532 detach();
533 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
534 }
535 }
536 );
537 add(sticky);
538
539 // show the close button
540 JButton close = new JButton(ImageProvider.get("misc", "close"));
541 close.setToolTipText(tr("Close this panel. You can reopen it with the buttons in the left toolbar."));
542 close.setBorder(BorderFactory.createEmptyBorder());
543 close.addActionListener(
544 new ActionListener(){
545 @Override
546 public void actionPerformed(ActionEvent e) {
547 hideDialog();
548 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
549 hideNotify();
550 }
551 }
552 );
553 add(close);
554 setToolTipText(tr("Click to minimize/maximize the panel content"));
555 setTitle(toggleDialogName);
556 }
557
558 public void setTitle(String title) {
559 lblTitle.setText(title);
560 lblTitle_weak.repaint();
561 }
562
563 public String getTitle() {
564 return lblTitle.getText();
565 }
566
567 public class DialogPopupMenu extends JPopupMenu {
568 public final JMenu buttonHidingMenu = new JMenu(tr("Side buttons"));
569 public final JRadioButtonMenuItem alwaysShown = new JRadioButtonMenuItem(new AbstractAction(tr("Always shown")) {
570 @Override public void actionPerformed(ActionEvent e) {
571 setIsButtonHiding(ButtonHiddingType.ALWAYS_SHOWN);
572 }
573 });
574 public final JRadioButtonMenuItem dynamic = new JRadioButtonMenuItem(new AbstractAction(tr("Dynamic")) {
575 @Override public void actionPerformed(ActionEvent e) {
576 setIsButtonHiding(ButtonHiddingType.DYNAMIC);
577 }
578 });
579 public final JRadioButtonMenuItem alwaysHidden = new JRadioButtonMenuItem(new AbstractAction(tr("Always hidden")) {
580 @Override public void actionPerformed(ActionEvent e) {
581 setIsButtonHiding(ButtonHiddingType.ALWAYS_HIDDEN);
582 }
583 });
584 public DialogPopupMenu() {
585 alwaysShown.setSelected(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN);
586 dynamic.setSelected(buttonHiding == ButtonHiddingType.DYNAMIC);
587 alwaysHidden.setSelected(buttonHiding == ButtonHiddingType.ALWAYS_HIDDEN);
588 buttonHidingMenu.add(alwaysShown);
589 buttonHidingMenu.add(dynamic);
590 buttonHidingMenu.add(alwaysHidden);
591 add(buttonHidingMenu);
592 for (javax.swing.Action action: buttonActions) {
593 add(action);
594 }
595 }
596 }
597
598 public void registerMouseListener() {
599 addMouseListener(new MouseEventHandler());
600 }
601
602 class MouseEventHandler extends PopupMenuLauncher {
603 public MouseEventHandler() {
604 super(new DialogPopupMenu());
605 }
606 @Override public void mouseClicked(MouseEvent e) {
607 if (SwingUtilities.isLeftMouseButton(e)) {
608 if (isCollapsed) {
609 expand();
610 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
611 } else {
612 collapse();
613 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
614 }
615 }
616 }
617 }
618 }
619
620 /**
621 * The dialog class used to display toggle dialogs in a detached window.
622 *
623 */
624 private class DetachedDialog extends JDialog{
625 public DetachedDialog() {
626 super(JOptionPane.getFrameForComponent(Main.parent));
627 getContentPane().add(ToggleDialog.this);
628 addWindowListener(new WindowAdapter(){
629 @Override public void windowClosing(WindowEvent e) {
630 rememberGeometry();
631 getContentPane().removeAll();
632 dispose();
633 if (dockWhenClosingDetachedDlg()) {
634 dock();
635 if (isDialogInCollapsedView()) {
636 expand();
637 }
638 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
639 } else {
640 hideDialog();
641 hideNotify();
642 }
643 }
644 });
645 addComponentListener(new ComponentAdapter() {
646 @Override public void componentMoved(ComponentEvent e) {
647 rememberGeometry();
648 }
649 @Override public void componentResized(ComponentEvent e) {
650 rememberGeometry();
651 }
652 });
653
654 try {
655 new WindowGeometry(preferencePrefix+".geometry").applySafe(this);
656 } catch (WindowGeometryException e) {
657 ToggleDialog.this.setPreferredSize(ToggleDialog.this.getDefaultDetachedSize());
658 pack();
659 setLocationRelativeTo(Main.parent);
660 }
661 setTitle(titleBar.getTitle());
662 HelpUtil.setHelpContext(getRootPane(), helpTopic());
663 }
664
665 protected void rememberGeometry() {
666 if (detachedDialog != null) {
667 new WindowGeometry(detachedDialog).remember(preferencePrefix+".geometry");
668 }
669 }
670 }
671
672 /**
673 * Replies the action to toggle the visible state of this toggle dialog
674 *
675 * @return the action to toggle the visible state of this toggle dialog
676 */
677 public AbstractAction getToggleAction() {
678 return toggleAction;
679 }
680
681 /**
682 * Replies the prefix for the preference settings of this dialog.
683 *
684 * @return the prefix for the preference settings of this dialog.
685 */
686 public String getPreferencePrefix() {
687 return preferencePrefix;
688 }
689
690 /**
691 * Sets the dialogsPanel managing all toggle dialogs
692 */
693 public void setDialogsPanel(DialogsPanel dialogsPanel) {
694 this.dialogsPanel = dialogsPanel;
695 }
696
697 /**
698 * Replies the name of this toggle dialog
699 */
700 @Override
701 public String getName() {
702 return "toggleDialog." + preferencePrefix;
703 }
704
705 /**
706 * Sets the title
707 */
708 public void setTitle(String title) {
709 titleBar.setTitle(title);
710 if (detachedDialog != null) {
711 detachedDialog.setTitle(title);
712 }
713 }
714
715 protected void setIsShowing(boolean val) {
716 isShowing = val;
717 Main.pref.put(preferencePrefix+".visible", val);
718 stateChanged();
719 }
720
721 protected void setIsDocked(boolean val) {
722 if(buttonsPanel != null && buttonsHide != null) {
723 buttonsPanel.setVisible(val ? buttonHiding == ButtonHiddingType.ALWAYS_SHOWN : true);
724 }
725 isDocked = val;
726 Main.pref.put(preferencePrefix+".docked", val);
727 stateChanged();
728 }
729
730 protected void setIsCollapsed(boolean val) {
731 isCollapsed = val;
732 Main.pref.put(preferencePrefix+".minimized", val);
733 stateChanged();
734 }
735
736 protected void setIsButtonHiding(ButtonHiddingType val) {
737 buttonHiding = val;
738 PROP_BUTTON_HIDING.put(val);
739 if (buttonsHide != null) {
740 buttonsHide.setIcon(ImageProvider.get("misc", val != ButtonHiddingType.ALWAYS_SHOWN ? "buttonhide" : "buttonshow"));
741 }
742 if (buttonsPanel != null) {
743 buttonsPanel.setVisible(val != ButtonHiddingType.ALWAYS_HIDDEN);
744 }
745 stateChanged();
746 }
747
748 public int getPreferredHeight() {
749 return preferredHeight;
750 }
751
752 @Override
753 public String helpTopic() {
754 String help = getClass().getName();
755 help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
756 return "Dialog/"+help;
757 }
758
759 @Override
760 public String toString() {
761 return name;
762 }
763
764 /**
765 * Replies true if this dialog is showing either as docked or as detached dialog
766 */
767 public boolean isDialogShowing() {
768 return isShowing;
769 }
770
771 /**
772 * Replies true if this dialog is docked and expanded
773 */
774 public boolean isDialogInDefaultView() {
775 return isShowing && isDocked && (! isCollapsed);
776 }
777
778 /**
779 * Replies true if this dialog is docked and collapsed
780 */
781 public boolean isDialogInCollapsedView() {
782 return isShowing && isDocked && isCollapsed;
783 }
784
785 public void setButton(JToggleButton button) {
786 this.button = button;
787 }
788
789 public JToggleButton getButton() {
790 return button;
791 }
792
793 /***
794 * The following methods are intended to be overridden, in order to customize
795 * the toggle dialog behavior.
796 **/
797
798 /**
799 * Change the Geometry of the detached dialog to better fit the content.
800 */
801 protected Rectangle getDetachedGeometry(Rectangle last) {
802 return last;
803 }
804
805 /**
806 * Default size of the detached dialog.
807 * Override this method to customize the initial dialog size.
808 */
809 protected Dimension getDefaultDetachedSize() {
810 return new Dimension(dialogsPanel.getWidth(), preferredHeight);
811 }
812
813 /**
814 * Do something when the toggleButton is pressed.
815 */
816 protected void toggleButtonHook() {
817 }
818
819 protected boolean dockWhenClosingDetachedDlg() {
820 return true;
821 }
822
823 /**
824 * primitive stateChangedListener for subclasses
825 */
826 protected void stateChanged() {
827 }
828
829 protected Component createLayout(Component data, boolean scroll, Collection<SideButton> buttons) {
830 return createLayout(data, scroll, buttons, (Collection<SideButton>[]) null);
831 }
832
833 protected Component createLayout(Component data, boolean scroll, Collection<SideButton> firstButtons, Collection<SideButton>... nextButtons) {
834 if (scroll) {
835 data = new JScrollPane(data);
836 }
837 LinkedList<Collection<SideButton>> buttons = new LinkedList<Collection<SideButton>>();
838 buttons.addFirst(firstButtons);
839 if (nextButtons != null) {
840 buttons.addAll(Arrays.asList(nextButtons));
841 }
842 add(data, BorderLayout.CENTER);
843 if (!buttons.isEmpty() && buttons.get(0) != null && !buttons.get(0).isEmpty()) {
844 buttonsPanel = new JPanel(new GridLayout(buttons.size(), 1));
845 for (Collection<SideButton> buttonRow : buttons) {
846 if (buttonRow == null) {
847 continue;
848 }
849 final JPanel buttonRowPanel = new JPanel(Main.pref.getBoolean("dialog.align.left", false)
850 ? new FlowLayout(FlowLayout.LEFT) : new GridLayout(1, buttonRow.size()));
851 buttonsPanel.add(buttonRowPanel);
852 for (SideButton button : buttonRow) {
853 buttonRowPanel.add(button);
854 javax.swing.Action action = button.getAction();
855 if (action != null) {
856 buttonActions.add(action);
857 } else {
858 System.err.println("Button " + button + " doesn't have action defined");
859 new Exception().printStackTrace();
860 }
861 }
862 }
863 add(buttonsPanel, BorderLayout.SOUTH);
864 if (Main.pref.getBoolean("dialog.dynamic.buttons", true)) {
865 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_MOTION_EVENT_MASK);
866 buttonsPanel.setVisible(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN || !isDocked);
867 } else if (buttonHiding == ButtonHiddingType.ALWAYS_HIDDEN) {
868 buttonsPanel.setVisible(false);
869 }
870 } else if (buttonsHide != null) {
871 buttonsHide.setVisible(false);
872 }
873
874 // Register title bar mouse listener only after buttonActions has been initialized to have a complete popup menu
875 titleBar.registerMouseListener();
876
877 return data;
878 }
879
880 @Override
881 public void eventDispatched(AWTEvent event) {
882 if(isShowing() && !isCollapsed && isDocked && buttonHiding == ButtonHiddingType.DYNAMIC) {
883 Rectangle b = this.getBounds();
884 b.setLocation(getLocationOnScreen());
885 if (b.contains(((MouseEvent)event).getLocationOnScreen())) {
886 if(!buttonsPanel.isVisible()) {
887 buttonsPanel.setVisible(true);
888 }
889 } else if (buttonsPanel.isVisible()) {
890 buttonsPanel.setVisible(false);
891 }
892 }
893 }
894}
Note: See TracBrowser for help on using the repository browser.