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

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

Sonar/FindBugs - various bugfixes / violation fixes

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