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

Last change on this file since 2319 was 2319, checked in by Gubaer, 14 years ago

fixed #3725: JOSM doesn't provide indication during upload that the server is sending 410 Gone errors
Progress dialog now includes a small log window for use cases like this. Use appendLogMessage() on the progress monitor.

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