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

Last change on this file since 6070 was 6070, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 31.5 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 public void actionPerformed(ActionEvent e) {
238 toggleButtonHook();
239 if(getValue("toolbarbutton") != null && getValue("toolbarbutton") instanceof JButton) {
240 ((JButton) getValue("toolbarbutton")).setSelected(!isShowing);
241 }
242 if (isShowing) {
243 hideDialog();
244 if (dialogsPanel != null) {
245 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
246 }
247 hideNotify();
248 } else {
249 showDialog();
250 if (isDocked && isCollapsed) {
251 expand();
252 }
253 if (isDocked && dialogsPanel != null) {
254 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
255 }
256 showNotify();
257 }
258 }
259
260 @Override
261 public void destroy() {
262 super.destroy();
263 }
264 }
265
266 /**
267 * Shows the dialog
268 */
269 public void showDialog() {
270 setIsShowing(true);
271 if (!isDocked) {
272 detach();
273 } else {
274 dock();
275 this.setVisible(true);
276 }
277 // toggling the selected value in order to enforce PropertyChangeEvents
278 setIsShowing(true);
279 windowMenuItem.setState(true);
280 toggleAction.putValue("selected", false);
281 toggleAction.putValue("selected", true);
282 }
283
284 /**
285 * Changes the state of the dialog such that the user can see the content.
286 * (takes care of the panel reconstruction)
287 */
288 public void unfurlDialog() {
289 if (isDialogInDefaultView())
290 return;
291 if (isDialogInCollapsedView()) {
292 expand();
293 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, this);
294 } else if (!isDialogShowing()) {
295 showDialog();
296 if (isDocked && isCollapsed) {
297 expand();
298 }
299 if (isDocked) {
300 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, this);
301 }
302 showNotify();
303 }
304 }
305
306 @Override
307 public void buttonHidden() {
308 if ((Boolean) toggleAction.getValue("selected")) {
309 toggleAction.actionPerformed(null);
310 }
311 }
312
313 public void buttonShown() {
314 unfurlDialog();
315 }
316
317
318 /**
319 * Hides the dialog
320 */
321 public void hideDialog() {
322 closeDetachedDialog();
323 this.setVisible(false);
324 windowMenuItem.setState(false);
325 setIsShowing(false);
326 toggleAction.putValue("selected", false);
327 }
328
329 /**
330 * Displays the toggle dialog in the toggle dialog view on the right
331 * of the main map window.
332 *
333 */
334 protected void dock() {
335 detachedDialog = null;
336 titleBar.setVisible(true);
337 setIsDocked(true);
338 }
339
340 /**
341 * Display the dialog in a detached window.
342 *
343 */
344 protected void detach() {
345 setContentVisible(true);
346 this.setVisible(true);
347 titleBar.setVisible(false);
348 detachedDialog = new DetachedDialog();
349 detachedDialog.setVisible(true);
350 setIsShowing(true);
351 setIsDocked(false);
352 }
353
354 /**
355 * Collapses the toggle dialog to the title bar only
356 *
357 */
358 public void collapse() {
359 if (isDialogInDefaultView()) {
360 setContentVisible(false);
361 setIsCollapsed(true);
362 setPreferredSize(new Dimension(0,20));
363 setMaximumSize(new Dimension(Integer.MAX_VALUE,20));
364 setMinimumSize(new Dimension(Integer.MAX_VALUE,20));
365 lblMinimized.setIcon(ImageProvider.get("misc", "minimized"));
366 }
367 else throw new IllegalStateException();
368 }
369
370 /**
371 * Expands the toggle dialog
372 */
373 protected void expand() {
374 if (isDialogInCollapsedView()) {
375 setContentVisible(true);
376 setIsCollapsed(false);
377 setPreferredSize(new Dimension(0,preferredHeight));
378 setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
379 lblMinimized.setIcon(ImageProvider.get("misc", "normal"));
380 }
381 else throw new IllegalStateException();
382 }
383
384 /**
385 * Sets the visibility of all components in this toggle dialog, except the title bar
386 *
387 * @param visible true, if the components should be visible; false otherwise
388 */
389 protected void setContentVisible(boolean visible) {
390 Component comps[] = getComponents();
391 for(int i=0; i<comps.length; i++) {
392 if (comps[i] != titleBar && (!visible || comps[i] != buttonsPanel || buttonHiding != ButtonHiddingType.ALWAYS_HIDDEN)) {
393 comps[i].setVisible(visible);
394 }
395 }
396 }
397
398 public void destroy() {
399 closeDetachedDialog();
400 hideNotify();
401 Main.main.menu.windowMenu.remove(windowMenuItem);
402 Toolkit.getDefaultToolkit().removeAWTEventListener(this);
403 destroyComponents(this);
404 }
405
406 private void destroyComponents(Component component) {
407 if (component instanceof Container) {
408 for (Component c: ((Container)component).getComponents()) {
409 destroyComponents(c);
410 }
411 }
412 if (component instanceof Destroyable) {
413 ((Destroyable) component).destroy();
414 }
415 }
416
417 /**
418 * Closes the detached dialog if this toggle dialog is currently displayed
419 * in a detached dialog.
420 *
421 */
422 public void closeDetachedDialog() {
423 if (detachedDialog != null) {
424 detachedDialog.setVisible(false);
425 detachedDialog.getContentPane().removeAll();
426 detachedDialog.dispose();
427 }
428 }
429
430 /**
431 * Called when toggle dialog is shown (after it was created or expanded). Descendants may overwrite this
432 * method, it's a good place to register listeners needed to keep dialog updated
433 */
434 public void showNotify() {
435
436 }
437
438 /**
439 * Called when toggle dialog is hidden (collapsed, removed, MapFrame is removed, ...). Good place to unregister
440 * listeners
441 */
442 public void hideNotify() {
443
444 }
445
446 /**
447 * The title bar displayed in docked mode
448 *
449 */
450 protected class TitleBar extends JPanel {
451 final private JLabel lblTitle;
452 final private JComponent lblTitle_weak;
453
454 public TitleBar(String toggleDialogName, String iconName) {
455 setLayout(new GridBagLayout());
456
457 lblMinimized = new JLabel(ImageProvider.get("misc", "normal"));
458 add(lblMinimized);
459
460 // scale down the dialog icon
461 ImageIcon inIcon = ImageProvider.get("dialogs", iconName);
462 ImageIcon smallIcon = new ImageIcon(inIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
463 lblTitle = new JLabel("",smallIcon, JLabel.TRAILING);
464 lblTitle.setIconTextGap(8);
465
466 JPanel conceal = new JPanel();
467 conceal.add(lblTitle);
468 conceal.setVisible(false);
469 add(conceal, GBC.std());
470
471 // Cannot add the label directly since it would displace other elements on resize
472 lblTitle_weak = new JComponent() {
473 @Override
474 public void paintComponent(Graphics g) {
475 lblTitle.paint(g);
476 }
477 };
478 lblTitle_weak.setPreferredSize(new Dimension(Integer.MAX_VALUE,20));
479 lblTitle_weak.setMinimumSize(new Dimension(0,20));
480 add(lblTitle_weak, GBC.std().fill(GBC.HORIZONTAL));
481
482 if(Main.pref.getBoolean("dialog.dynamic.buttons", true)) {
483 buttonsHide = new JButton(ImageProvider.get("misc", buttonHiding != ButtonHiddingType.ALWAYS_SHOWN ? "buttonhide" : "buttonshow"));
484 buttonsHide.setToolTipText(tr("Toggle dynamic buttons"));
485 buttonsHide.setBorder(BorderFactory.createEmptyBorder());
486 buttonsHide.addActionListener(
487 new ActionListener(){
488 public void actionPerformed(ActionEvent e) {
489 setIsButtonHiding(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN?ButtonHiddingType.DYNAMIC:ButtonHiddingType.ALWAYS_SHOWN);
490 }
491 }
492 );
493 add(buttonsHide);
494 }
495
496 // show the pref button if applicable
497 if (preferenceClass != null) {
498 inIcon = ImageProvider.get("preference");
499 smallIcon = new ImageIcon(inIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
500 JButton pref = new JButton(smallIcon);
501 pref.setToolTipText(tr("Open preferences for this panel"));
502 pref.setBorder(BorderFactory.createEmptyBorder());
503 pref.addActionListener(
504 new ActionListener(){
505 @SuppressWarnings("unchecked")
506 public void actionPerformed(ActionEvent e) {
507 final PreferenceDialog p = new PreferenceDialog(Main.parent);
508 if (TabPreferenceSetting.class.isAssignableFrom(preferenceClass)) {
509 p.selectPreferencesTabByClass((Class<? extends TabPreferenceSetting>) preferenceClass);
510 } else if (SubPreferenceSetting.class.isAssignableFrom(preferenceClass)) {
511 p.selectSubPreferencesTabByClass((Class<? extends SubPreferenceSetting>) preferenceClass);
512 }
513 p.setVisible(true);
514 }
515 }
516 );
517 add(pref);
518 }
519
520 // show the sticky button
521 JButton sticky = new JButton(ImageProvider.get("misc", "sticky"));
522 sticky.setToolTipText(tr("Undock the panel"));
523 sticky.setBorder(BorderFactory.createEmptyBorder());
524 sticky.addActionListener(
525 new ActionListener(){
526 public void actionPerformed(ActionEvent e) {
527 detach();
528 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
529 }
530 }
531 );
532 add(sticky);
533
534 // show the close button
535 JButton close = new JButton(ImageProvider.get("misc", "close"));
536 close.setToolTipText(tr("Close this panel. You can reopen it with the buttons in the left toolbar."));
537 close.setBorder(BorderFactory.createEmptyBorder());
538 close.addActionListener(
539 new ActionListener(){
540 public void actionPerformed(ActionEvent e) {
541 hideDialog();
542 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
543 hideNotify();
544 }
545 }
546 );
547 add(close);
548 setToolTipText(tr("Click to minimize/maximize the panel content"));
549 setTitle(toggleDialogName);
550 }
551
552 public void setTitle(String title) {
553 lblTitle.setText(title);
554 lblTitle_weak.repaint();
555 }
556
557 public String getTitle() {
558 return lblTitle.getText();
559 }
560
561 public class DialogPopupMenu extends JPopupMenu {
562 public final JMenu buttonHidingMenu = new JMenu(tr("Side buttons"));
563 public final JRadioButtonMenuItem alwaysShown = new JRadioButtonMenuItem(new AbstractAction(tr("Always shown")) {
564 @Override public void actionPerformed(ActionEvent e) {
565 setIsButtonHiding(ButtonHiddingType.ALWAYS_SHOWN);
566 }
567 });
568 public final JRadioButtonMenuItem dynamic = new JRadioButtonMenuItem(new AbstractAction(tr("Dynamic")) {
569 @Override public void actionPerformed(ActionEvent e) {
570 setIsButtonHiding(ButtonHiddingType.DYNAMIC);
571 }
572 });
573 public final JRadioButtonMenuItem alwaysHidden = new JRadioButtonMenuItem(new AbstractAction(tr("Always hidden")) {
574 @Override public void actionPerformed(ActionEvent e) {
575 setIsButtonHiding(ButtonHiddingType.ALWAYS_HIDDEN);
576 }
577 });
578 public DialogPopupMenu() {
579 alwaysShown.setSelected(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN);
580 dynamic.setSelected(buttonHiding == ButtonHiddingType.DYNAMIC);
581 alwaysHidden.setSelected(buttonHiding == ButtonHiddingType.ALWAYS_HIDDEN);
582 buttonHidingMenu.add(alwaysShown);
583 buttonHidingMenu.add(dynamic);
584 buttonHidingMenu.add(alwaysHidden);
585 add(buttonHidingMenu);
586 for (javax.swing.Action action: buttonActions) {
587 add(action);
588 }
589 }
590 }
591
592 public void registerMouseListener() {
593 addMouseListener(new MouseEventHandler());
594 }
595
596 class MouseEventHandler extends PopupMenuLauncher {
597 public MouseEventHandler() {
598 super(new DialogPopupMenu());
599 }
600 @Override public void mouseClicked(MouseEvent e) {
601 if (SwingUtilities.isLeftMouseButton(e)) {
602 if (isCollapsed) {
603 expand();
604 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
605 } else {
606 collapse();
607 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
608 }
609 }
610 }
611 }
612 }
613
614 /**
615 * The dialog class used to display toggle dialogs in a detached window.
616 *
617 */
618 private class DetachedDialog extends JDialog{
619 public DetachedDialog() {
620 super(JOptionPane.getFrameForComponent(Main.parent));
621 getContentPane().add(ToggleDialog.this);
622 addWindowListener(new WindowAdapter(){
623 @Override public void windowClosing(WindowEvent e) {
624 rememberGeometry();
625 getContentPane().removeAll();
626 dispose();
627 if (dockWhenClosingDetachedDlg()) {
628 dock();
629 if (isDialogInCollapsedView()) {
630 expand();
631 }
632 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
633 } else {
634 hideDialog();
635 hideNotify();
636 }
637 }
638 });
639 addComponentListener(new ComponentAdapter() {
640 @Override public void componentMoved(ComponentEvent e) {
641 rememberGeometry();
642 }
643 @Override public void componentResized(ComponentEvent e) {
644 rememberGeometry();
645 }
646 });
647
648 try {
649 new WindowGeometry(preferencePrefix+".geometry").applySafe(this);
650 } catch (WindowGeometryException e) {
651 ToggleDialog.this.setPreferredSize(ToggleDialog.this.getDefaultDetachedSize());
652 pack();
653 setLocationRelativeTo(Main.parent);
654 }
655 setTitle(titleBar.getTitle());
656 HelpUtil.setHelpContext(getRootPane(), helpTopic());
657 }
658
659 protected void rememberGeometry() {
660 if (detachedDialog != null) {
661 new WindowGeometry(detachedDialog).remember(preferencePrefix+".geometry");
662 }
663 }
664 }
665
666 /**
667 * Replies the action to toggle the visible state of this toggle dialog
668 *
669 * @return the action to toggle the visible state of this toggle dialog
670 */
671 public AbstractAction getToggleAction() {
672 return toggleAction;
673 }
674
675 /**
676 * Replies the prefix for the preference settings of this dialog.
677 *
678 * @return the prefix for the preference settings of this dialog.
679 */
680 public String getPreferencePrefix() {
681 return preferencePrefix;
682 }
683
684 /**
685 * Sets the dialogsPanel managing all toggle dialogs
686 */
687 public void setDialogsPanel(DialogsPanel dialogsPanel) {
688 this.dialogsPanel = dialogsPanel;
689 }
690
691 /**
692 * Replies the name of this toggle dialog
693 */
694 @Override
695 public String getName() {
696 return "toggleDialog." + preferencePrefix;
697 }
698
699 /**
700 * Sets the title
701 */
702 public void setTitle(String title) {
703 titleBar.setTitle(title);
704 if (detachedDialog != null) {
705 detachedDialog.setTitle(title);
706 }
707 }
708
709 protected void setIsShowing(boolean val) {
710 isShowing = val;
711 Main.pref.put(preferencePrefix+".visible", val);
712 stateChanged();
713 }
714
715 protected void setIsDocked(boolean val) {
716 if(buttonsPanel != null && buttonsHide != null) {
717 buttonsPanel.setVisible(val ? buttonHiding == ButtonHiddingType.ALWAYS_SHOWN : true);
718 }
719 isDocked = val;
720 Main.pref.put(preferencePrefix+".docked", val);
721 stateChanged();
722 }
723
724 protected void setIsCollapsed(boolean val) {
725 isCollapsed = val;
726 Main.pref.put(preferencePrefix+".minimized", val);
727 stateChanged();
728 }
729
730 protected void setIsButtonHiding(ButtonHiddingType val) {
731 buttonHiding = val;
732 PROP_BUTTON_HIDING.put(val);
733 if (buttonsHide != null) {
734 buttonsHide.setIcon(ImageProvider.get("misc", val != ButtonHiddingType.ALWAYS_SHOWN ? "buttonhide" : "buttonshow"));
735 }
736 if (buttonsPanel != null) {
737 buttonsPanel.setVisible(val != ButtonHiddingType.ALWAYS_HIDDEN);
738 }
739 stateChanged();
740 }
741
742 public int getPreferredHeight() {
743 return preferredHeight;
744 }
745
746 public String helpTopic() {
747 String help = getClass().getName();
748 help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
749 return "Dialog/"+help;
750 }
751
752 @Override
753 public String toString() {
754 return name;
755 }
756
757 /**
758 * Replies true if this dialog is showing either as docked or as detached dialog
759 */
760 public boolean isDialogShowing() {
761 return isShowing;
762 }
763
764 /**
765 * Replies true if this dialog is docked and expanded
766 */
767 public boolean isDialogInDefaultView() {
768 return isShowing && isDocked && (! isCollapsed);
769 }
770
771 /**
772 * Replies true if this dialog is docked and collapsed
773 */
774 public boolean isDialogInCollapsedView() {
775 return isShowing && isDocked && isCollapsed;
776 }
777
778 public void setButton(JToggleButton button) {
779 this.button = button;
780 }
781
782 public JToggleButton getButton() {
783 return button;
784 }
785
786 /***
787 * The following methods are intended to be overridden, in order to customize
788 * the toggle dialog behavior.
789 **/
790
791 /**
792 * Change the Geometry of the detached dialog to better fit the content.
793 */
794 protected Rectangle getDetachedGeometry(Rectangle last) {
795 return last;
796 }
797
798 /**
799 * Default size of the detached dialog.
800 * Override this method to customize the initial dialog size.
801 */
802 protected Dimension getDefaultDetachedSize() {
803 return new Dimension(dialogsPanel.getWidth(), preferredHeight);
804 }
805
806 /**
807 * Do something when the toggleButton is pressed.
808 */
809 protected void toggleButtonHook() {
810 }
811
812 protected boolean dockWhenClosingDetachedDlg() {
813 return true;
814 }
815
816 /**
817 * primitive stateChangedListener for subclasses
818 */
819 protected void stateChanged() {
820 }
821
822 protected Component createLayout(Component data, boolean scroll, Collection<SideButton> buttons) {
823 return createLayout(data, scroll, buttons, (Collection<SideButton>[]) null);
824 }
825
826 protected Component createLayout(Component data, boolean scroll, Collection<SideButton> firstButtons, Collection<SideButton>... nextButtons) {
827 if (scroll) {
828 data = new JScrollPane(data);
829 }
830 LinkedList<Collection<SideButton>> buttons = new LinkedList<Collection<SideButton>>();
831 buttons.addFirst(firstButtons);
832 if (nextButtons != null) {
833 buttons.addAll(Arrays.asList(nextButtons));
834 }
835 add(data, BorderLayout.CENTER);
836 if (buttons.size() > 0 && buttons.get(0) != null && !buttons.get(0).isEmpty()) {
837 buttonsPanel = new JPanel(new GridLayout(buttons.size(), 1));
838 for (Collection<SideButton> buttonRow : buttons) {
839 if (buttonRow == null) {
840 continue;
841 }
842 final JPanel buttonRowPanel = new JPanel(Main.pref.getBoolean("dialog.align.left", false)
843 ? new FlowLayout(FlowLayout.LEFT) : new GridLayout(1, buttonRow.size()));
844 buttonsPanel.add(buttonRowPanel);
845 for (SideButton button : buttonRow) {
846 buttonRowPanel.add(button);
847 javax.swing.Action action = button.getAction();
848 if (action != null) {
849 buttonActions.add(action);
850 } else {
851 System.err.println("Button " + button + " doesn't have action defined");
852 new Exception().printStackTrace();
853 }
854 }
855 }
856 add(buttonsPanel, BorderLayout.SOUTH);
857 if (Main.pref.getBoolean("dialog.dynamic.buttons", true)) {
858 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_MOTION_EVENT_MASK);
859 buttonsPanel.setVisible(buttonHiding == ButtonHiddingType.ALWAYS_SHOWN || !isDocked);
860 } else if (buttonHiding == ButtonHiddingType.ALWAYS_HIDDEN) {
861 buttonsPanel.setVisible(false);
862 }
863 } else if (buttonsHide != null) {
864 buttonsHide.setVisible(false);
865 }
866
867 // Register title bar mouse listener only after buttonActions has been initialized to have a complete popup menu
868 titleBar.registerMouseListener();
869
870 return data;
871 }
872
873 @Override
874 public void eventDispatched(AWTEvent event) {
875 if(isShowing() && !isCollapsed && isDocked && buttonHiding == ButtonHiddingType.DYNAMIC) {
876 Rectangle b = this.getBounds();
877 b.setLocation(getLocationOnScreen());
878 if (b.contains(((MouseEvent)event).getLocationOnScreen())) {
879 if(!buttonsPanel.isVisible()) {
880 buttonsPanel.setVisible(true);
881 }
882 } else if (buttonsPanel.isVisible()) {
883 buttonsPanel.setVisible(false);
884 }
885 }
886 }
887}
Note: See TracBrowser for help on using the repository browser.