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

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

fix #8143 - Side buttons reappear despite "Always hidden" option

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