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

Last change on this file since 2512 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

  • Property svn:eol-style set to native
File size: 16.9 KB
Line 
1package org.openstreetmap.josm.gui.dialogs;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.BorderLayout;
6import java.awt.Component;
7import java.awt.Dimension;
8import java.awt.Graphics;
9import java.awt.GridBagLayout;
10import java.awt.Image;
11import java.awt.Rectangle;
12import java.awt.event.ActionEvent;
13import java.awt.event.ActionListener;
14import java.awt.event.ComponentAdapter;
15import java.awt.event.ComponentEvent;
16import java.awt.event.MouseAdapter;
17import java.awt.event.MouseEvent;
18import java.awt.event.WindowAdapter;
19import java.awt.event.WindowEvent;
20
21import javax.swing.AbstractAction;
22import javax.swing.BorderFactory;
23import javax.swing.ImageIcon;
24import javax.swing.JButton;
25import javax.swing.JComponent;
26import javax.swing.JDialog;
27import javax.swing.JLabel;
28import javax.swing.JOptionPane;
29import javax.swing.JPanel;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.actions.JosmAction;
33import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
34import org.openstreetmap.josm.gui.help.HelpUtil;
35import org.openstreetmap.josm.gui.help.Helpful;
36import org.openstreetmap.josm.tools.GBC;
37import org.openstreetmap.josm.tools.ImageProvider;
38import org.openstreetmap.josm.tools.Shortcut;
39
40/**
41 * This class is a toggle dialog that can be turned on and off.
42 *
43 *
44 */
45public class ToggleDialog extends JPanel implements Helpful {
46 /** The action to toggle this dialog */
47 private ToggleDialogAction toggleAction;
48 private String preferencePrefix;
49
50 /** DialogsPanel that manages all ToggleDialogs */
51 private DialogsPanel dialogsPanel;
52
53 private TitleBar titleBar;
54
55 /**
56 * Indicates whether the dialog is showing or not.
57 */
58 private boolean isShowing;
59 /**
60 * If isShowing is true, indicates whether the dialog is docked or not, e. g.
61 * shown as part of the main window or as a seperate dialog window.
62 */
63 private boolean isDocked;
64 /**
65 * If isShowing and isDocked are true, indicates whether the dialog is
66 * currently minimized or not.
67 */
68 private boolean isCollapsed;
69
70 /** the preferred height if the toggle dialog is expanded */
71 private int preferredHeight;
72
73 /** the label in the title bar which shows whether the toggle dialog is expanded or collapsed */
74 private JLabel lblMinimized;
75
76 /** the JDialog displaying the toggle dialog as undocked dialog */
77 private JDialog detachedDialog;
78
79 /**
80 * Constructor
81 * (see below)
82 */
83 public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
84 this(name, iconName, tooltip, shortcut, preferredHeight, false);
85 }
86 /**
87 * Constructor
88 *
89 * @param name the name of the dialog
90 * @param iconName the name of the icon to be displayed
91 * @param tooltip the tool tip
92 * @param shortcut the shortcut
93 * @param preferredHeight the preferred height for the dialog
94 * @param defShow if the dialog should be shown by default, if there is no preference
95 */
96 public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight, boolean defShow) {
97 super(new BorderLayout());
98 this.preferencePrefix = iconName;
99
100 /** Use the full width of the parent element */
101 setPreferredSize(new Dimension(0, preferredHeight));
102 /** Override any minimum sizes of child elements so the user can resize freely */
103 setMinimumSize(new Dimension(0,0));
104 this.preferredHeight = preferredHeight;
105 toggleAction = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortcut, iconName);
106 String helpId = "Dialog/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
107 toggleAction.putValue("help", helpId.substring(0, helpId.length()-6));
108
109 setLayout(new BorderLayout());
110
111 /** show the minimize button */
112 lblMinimized = new JLabel(ImageProvider.get("misc", "normal"));
113 titleBar = new TitleBar(name, iconName);
114 add(titleBar, BorderLayout.NORTH);
115
116 setBorder(BorderFactory.createEtchedBorder());
117
118 isShowing = Main.pref.getBoolean(preferencePrefix+".visible", defShow);
119 isDocked = Main.pref.getBoolean(preferencePrefix+".docked", true);
120 isCollapsed = Main.pref.getBoolean(preferencePrefix+".minimized", false);
121 }
122
123 /**
124 * The action to toggle the visibility state of this toggle dialog.
125 *
126 * Emits {@see PropertyChangeEvent}s for the property <tt>selected</tt>:
127 * <ul>
128 * <li>true, if the dialog is currently visible</li>
129 * <li>false, if the dialog is currently invisible</li>
130 * </ul>
131 *
132 */
133 public final class ToggleDialogAction extends JosmAction {
134 private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
135 super(name, iconName, tooltip, shortcut, false);
136 }
137
138 public void actionPerformed(ActionEvent e) {
139 if (isShowing) {
140 hideDialog();
141 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
142 } else {
143 showDialog();
144 expand();
145 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
146 }
147 }
148 }
149
150 /**
151 * Shows the dialog
152 */
153 public void showDialog() {
154 setIsShowing(true);
155 if (!isDocked) {
156 detach();
157 } else {
158 dock();
159 this.setVisible(true);
160 }
161 // toggling the selected value in order to enforce PropertyChangeEvents
162 setIsShowing(true);
163 toggleAction.putValue("selected", false);
164 toggleAction.putValue("selected", true);
165 showNotify();
166 }
167
168 /**
169 * Hides the dialog
170 */
171 public void hideDialog() {
172 closeDetachedDialog();
173 this.setVisible(false);
174 setIsShowing(false);
175 toggleAction.putValue("selected", false);
176 hideNotify();
177 }
178
179 /**
180 * Displays the toggle dialog in the toggle dialog view on the right
181 * of the main map window.
182 *
183 */
184 protected void dock() {
185 detachedDialog = null;
186 titleBar.setVisible(true);
187 setIsDocked(true);
188 }
189
190 /**
191 * Display the dialog in a detached window.
192 *
193 */
194 protected void detach() {
195 setContentVisible(true);
196 this.setVisible(true);
197 titleBar.setVisible(false);
198 detachedDialog = new DetachedDialog();
199 detachedDialog.setVisible(true);
200 setIsDocked(false);
201 }
202
203 /**
204 * Collapses the toggle dialog to the title bar only
205 *
206 */
207 public void collapse() {
208 if (isShowing && isDocked && !isCollapsed) {
209 setContentVisible(false);
210 setIsCollapsed(true);
211 setPreferredSize(new Dimension(0,20));
212 setMaximumSize(new Dimension(Integer.MAX_VALUE,20));
213 setMinimumSize(new Dimension(Integer.MAX_VALUE,20));
214 lblMinimized.setIcon(ImageProvider.get("misc", "minimized"));
215 hideNotify();
216 }
217 }
218
219 /**
220 * Expands the toggle dialog
221 */
222 protected void expand() {
223 if (isShowing && isDocked && isCollapsed) {
224 setContentVisible(true);
225 setIsCollapsed(false);
226 setPreferredSize(new Dimension(0,preferredHeight));
227 setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
228 lblMinimized.setIcon(ImageProvider.get("misc", "normal"));
229 showNotify();
230 }
231 }
232
233 /**
234 * Sets the visibility of all components in this toggle dialog, except the title bar
235 *
236 * @param visible true, if the components should be visible; false otherwise
237 */
238 protected void setContentVisible(boolean visible) {
239 Component comps[] = getComponents();
240 for(int i=0; i<comps.length; i++) {
241 if(comps[i] != titleBar) {
242 comps[i].setVisible(visible);
243 }
244 }
245 }
246
247 public void destroy() {
248 closeDetachedDialog();
249 hideNotify();
250 }
251
252 /**
253 * Closes the the detached dialog if this toggle dialog is currently displayed
254 * in a detached dialog.
255 *
256 */
257 public void closeDetachedDialog() {
258 if (detachedDialog != null) {
259 detachedDialog.setVisible(false);
260 detachedDialog.getContentPane().removeAll();
261 detachedDialog.dispose();
262 }
263 }
264
265 /**
266 * Called when toggle dialog is shown (after it was created or expanded). Descendants may overwrite this
267 * method, it's a good place to register listeners needed to keep dialog updated
268 */
269 public void showNotify() {
270
271 }
272
273 /**
274 * Called when toggle dialog is hidden (collapsed, removed, MapFrame is removed, ...). Good place to unregister
275 * listeners
276 */
277 public void hideNotify() {
278
279 }
280
281 /**
282 * The title bar displayed in docked mode
283 *
284 */
285 private class TitleBar extends JPanel {
286 final private JLabel lblTitle;
287 final private JComponent lblTitle_weak;
288
289 public TitleBar(String toggleDialogName, String iconName) {
290 setLayout(new GridBagLayout());
291 lblMinimized = new JLabel(ImageProvider.get("misc", "normal"));
292 add(lblMinimized);
293
294 // scale down the dialog icon
295 ImageIcon inIcon = ImageProvider.get("dialogs", iconName);
296 ImageIcon smallIcon = new ImageIcon(inIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
297 lblTitle = new JLabel("",smallIcon, JLabel.TRAILING);
298 lblTitle.setIconTextGap(8);
299
300 JPanel conceal = new JPanel();
301 conceal.add(lblTitle);
302 conceal.setVisible(false);
303 add(conceal, GBC.std());
304
305 // Cannot add the label directly since it would displace other elements on resize
306 lblTitle_weak = new JComponent() {
307 @Override
308 public void paintComponent(Graphics g) {
309 lblTitle.paint(g);
310 }
311 };
312 lblTitle_weak.setPreferredSize(new Dimension(Integer.MAX_VALUE,20));
313 lblTitle_weak.setMinimumSize(new Dimension(0,20));
314 add(lblTitle_weak, GBC.std().fill(GBC.HORIZONTAL));
315
316 addMouseListener(
317 new MouseAdapter() {
318 @Override
319 public void mouseClicked(MouseEvent e) {
320 // toggleExpandedState();
321 if (isCollapsed) {
322 expand();
323 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
324 } else {
325 collapse();
326 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
327 }
328 }
329 }
330 );
331
332 // show the sticky button
333 JButton sticky = new JButton(ImageProvider.get("misc", "sticky"));
334 sticky.setToolTipText(tr("Undock the panel"));
335 sticky.setBorder(BorderFactory.createEmptyBorder());
336 sticky.addActionListener(
337 new ActionListener(){
338 public void actionPerformed(ActionEvent e) {
339 detach();
340 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
341 }
342 }
343 );
344 add(sticky);
345
346 // show the close button
347 JButton close = new JButton(ImageProvider.get("misc", "close"));
348 close.setToolTipText(tr("Close this panel. You can reopen it with the buttons in the left toolbar."));
349 close.setBorder(BorderFactory.createEmptyBorder());
350 close.addActionListener(
351 new ActionListener(){
352 public void actionPerformed(ActionEvent e) {
353 hideDialog();
354 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
355 }
356 }
357 );
358 add(close);
359 setToolTipText(tr("Click to minimize/maximize the panel content"));
360 setTitle(toggleDialogName);
361 }
362
363 public void setTitle(String title) {
364 lblTitle.setText(title);
365 lblTitle_weak.repaint();
366 }
367
368 public String getTitle() {
369 return lblTitle.getText();
370 }
371 }
372
373 /**
374 * The dialog class used to display toggle dialogs in a detached window.
375 *
376 */
377 private class DetachedDialog extends JDialog{
378 public DetachedDialog() {
379 super(JOptionPane.getFrameForComponent(Main.parent));
380 getContentPane().add(ToggleDialog.this);
381 addWindowListener(new WindowAdapter(){
382 @Override public void windowClosing(WindowEvent e) {
383 rememberGeometry();
384 getContentPane().removeAll();
385 dispose();
386 dock();
387 expand();
388 dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
389 }
390 });
391 addComponentListener(new ComponentAdapter() {
392 @Override public void componentMoved(ComponentEvent e) {
393 rememberGeometry();
394 }
395 @Override public void componentResized(ComponentEvent e) {
396 rememberGeometry();
397 }
398 });
399
400 String bounds = Main.pref.get(preferencePrefix+".bounds",null);
401 if (bounds != null) {
402 String[] b = bounds.split(",");
403 setBounds(getDetachedGeometry(new Rectangle(
404 Integer.parseInt(b[0]),Integer.parseInt(b[1]),Integer.parseInt(b[2]),Integer.parseInt(b[3]))));
405 } else {
406 ToggleDialog.this.setPreferredSize(ToggleDialog.this.getDefaultDetachedSize());
407 pack();
408 setLocationRelativeTo(Main.parent);
409 }
410 setTitle(titleBar.getTitle());
411 HelpUtil.setHelpContext(getRootPane(), helpTopic());
412 }
413
414 protected void rememberGeometry() {
415 Main.pref.put(preferencePrefix+".bounds", detachedDialog.getX()+","+detachedDialog.getY()+","+detachedDialog.getWidth()+","+detachedDialog.getHeight());
416 }
417 }
418
419 /**
420 * Change the Geometry of the detached dialog to better fit the content.
421 * Overrride this to make it useful.
422 */
423 protected Rectangle getDetachedGeometry(Rectangle last) {
424 return last;
425 }
426
427 /**
428 * Default size of the detached dialog.
429 * Override this method to customize the initial dialog size.
430 */
431 protected Dimension getDefaultDetachedSize() {
432 return new Dimension(Main.map.DEF_TOGGLE_DLG_WIDTH, preferredHeight);
433 }
434
435 /**
436 * Replies the action to toggle the visible state of this toggle dialog
437 *
438 * @return the action to toggle the visible state of this toggle dialog
439 */
440 public AbstractAction getToggleAction() {
441 return toggleAction;
442 }
443
444 /**
445 * Replies the prefix for the preference settings of this dialog.
446 *
447 * @return the prefix for the preference settings of this dialog.
448 */
449 public String getPreferencePrefix() {
450 return preferencePrefix;
451 }
452
453 /**
454 * Sets the dialogsPanel managing all toggle dialogs
455 */
456 public void setDialogsPanel(DialogsPanel dialogsPanel) {
457 this.dialogsPanel = dialogsPanel;
458 }
459
460 /**
461 * Replies the name of this toggle dialog
462 */
463 @Override
464 public String getName() {
465 return "toggleDialog." + preferencePrefix;
466 }
467
468 /**
469 * Sets the title
470 */
471 public void setTitle(String title) {
472 titleBar.setTitle(title);
473 }
474
475 private void setIsShowing(boolean val) {
476 isShowing = val;
477 Main.pref.put(preferencePrefix+".visible", val);
478 }
479
480 private void setIsDocked(boolean val) {
481 isDocked = val;
482 Main.pref.put(preferencePrefix+".docked", val);
483 }
484
485 private void setIsCollapsed(boolean val) {
486 isCollapsed = val;
487 Main.pref.put(preferencePrefix+".minimized", val);
488 }
489
490 public int getPreferredHeight() {
491 return preferredHeight;
492 }
493
494 /**
495 * Replies true if this dialog is showing either as docked or as detached dialog
496 */
497 public boolean isDialogShowing() {
498 return isShowing;
499 }
500
501 /**
502 * Replies true if this dialog is docked and expanded
503 */
504 public boolean isDialogInDefaultView() {
505 return isShowing && isDocked && (! isCollapsed);
506 }
507
508 /**
509 * Replies true if this dialog is docked and collapsed
510 */
511 public boolean isDialogInCollapsedView() {
512 return isShowing && isDocked && isCollapsed;
513 }
514
515 public String helpTopic() {
516 String help = getClass().getName();
517 help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
518 return "Dialog/"+help;
519 }
520}
Note: See TracBrowser for help on using the repository browser.