source: josm/trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java@ 5790

Last change on this file since 5790 was 5790, checked in by akks, 11 years ago

fix #8426: add_tags in remote control: better changed tags detection,
fix EDT violations and NPE when layer is closed while adding tags
added GuiHelper.executeByMainWorkerInEDT to execute GUI-related tasks sequentially from non-EDT threads

  • Property svn:eol-style set to native
File size: 7.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.util;
3
4import java.awt.BasicStroke;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Component;
8import java.awt.Container;
9import java.awt.Dialog;
10import java.awt.Dimension;
11import java.awt.Image;
12import java.awt.Stroke;
13import java.awt.Toolkit;
14import java.awt.Window;
15import java.awt.event.ActionListener;
16import java.awt.event.HierarchyEvent;
17import java.awt.event.HierarchyListener;
18import java.awt.image.FilteredImageSource;
19import java.lang.reflect.InvocationTargetException;
20
21import javax.swing.GrayFilter;
22import javax.swing.Icon;
23import javax.swing.ImageIcon;
24import javax.swing.JOptionPane;
25import javax.swing.SwingUtilities;
26import javax.swing.Timer;
27
28import org.openstreetmap.josm.Main;
29import org.openstreetmap.josm.gui.ExtendedDialog;
30import org.openstreetmap.josm.tools.ImageProvider;
31
32/**
33 * basic gui utils
34 */
35public class GuiHelper {
36 /**
37 * disable / enable a component and all its child components
38 */
39 public static void setEnabledRec(Container root, boolean enabled) {
40 root.setEnabled(enabled);
41 Component[] children = root.getComponents();
42 for (Component child : children) {
43 if(child instanceof Container) {
44 setEnabledRec((Container) child, enabled);
45 } else {
46 child.setEnabled(enabled);
47 }
48 }
49 }
50
51 public static void executeByMainWorkerInEDT(final Runnable task) {
52 Main.worker.submit(new Runnable() {
53 public void run() {
54 runInEDTAndWait(task);
55 }
56 });
57 }
58
59 public static void runInEDT(Runnable task) {
60 if (SwingUtilities.isEventDispatchThread()) {
61 task.run();
62 } else {
63 SwingUtilities.invokeLater(task);
64 }
65 }
66
67 public static void runInEDTAndWait(Runnable task) {
68 if (SwingUtilities.isEventDispatchThread()) {
69 task.run();
70 } else {
71 try {
72 SwingUtilities.invokeAndWait(task);
73 } catch (InterruptedException e) {
74 e.printStackTrace();
75 } catch (InvocationTargetException e) {
76 e.printStackTrace();
77 }
78 }
79 }
80
81 /**
82 * returns true if the user wants to cancel, false if they
83 * want to continue
84 */
85 public static final boolean warnUser(String title, String content, ImageIcon baseActionIcon, String continueToolTip) {
86 ExtendedDialog dlg = new ExtendedDialog(Main.parent,
87 title, new String[] {tr("Cancel"), tr("Continue")});
88 dlg.setContent(content);
89 dlg.setButtonIcons(new Icon[] {
90 ImageProvider.get("cancel"),
91 ImageProvider.overlay(
92 ImageProvider.get("upload"),
93 new ImageIcon(ImageProvider.get("warning-small").getImage().getScaledInstance(10 , 10, Image.SCALE_SMOOTH)),
94 ImageProvider.OverlayPosition.SOUTHEAST)});
95 dlg.setToolTipTexts(new String[] {
96 tr("Cancel"),
97 continueToolTip});
98 dlg.setIcon(JOptionPane.WARNING_MESSAGE);
99 dlg.setCancelButton(1);
100 return dlg.showDialog().getValue() != 2;
101 }
102
103 /**
104 * Replies the disabled (grayed) version of the specified image.
105 * @param image The image to disable
106 * @return The disabled (grayed) version of the specified image, brightened by 20%.
107 * @since 5484
108 */
109 public static final Image getDisabledImage(Image image) {
110 return Toolkit.getDefaultToolkit().createImage(
111 new FilteredImageSource(image.getSource(), new GrayFilter(true, 20)));
112 }
113
114 /**
115 * Replies the disabled (grayed) version of the specified icon.
116 * @param icon The icon to disable
117 * @return The disabled (grayed) version of the specified icon, brightened by 20%.
118 * @since 5484
119 */
120 public static final ImageIcon getDisabledIcon(ImageIcon icon) {
121 return new ImageIcon(getDisabledImage(icon.getImage()));
122 }
123
124 /**
125 * Attaches a {@code HierarchyListener} to the specified {@code Component} that
126 * will set its parent dialog resizeable. Use it before a call to JOptionPane#showXXXXDialog
127 * to make it resizeable.
128 * @param pane The component that will be displayed
129 * @param minDimension The minimum dimension that will be set for the dialog. Ignored if null
130 * @return {@code pane}
131 * @since 5493
132 */
133 public static final Component prepareResizeableOptionPane(final Component pane, final Dimension minDimension) {
134 if (pane != null) {
135 pane.addHierarchyListener(new HierarchyListener() {
136 public void hierarchyChanged(HierarchyEvent e) {
137 Window window = SwingUtilities.getWindowAncestor(pane);
138 if (window instanceof Dialog) {
139 Dialog dialog = (Dialog)window;
140 if (!dialog.isResizable()) {
141 dialog.setResizable(true);
142 if (minDimension != null) {
143 dialog.setMinimumSize(minDimension);
144 }
145 }
146 }
147 }
148 });
149 }
150 return pane;
151 }
152
153 /**
154 * Schedules a new Timer to be run in the future (once or several times).
155 * @param initialDelay milliseconds for the initial and between-event delay if repeatable
156 * @param actionListener an initial listener; can be null
157 * @param repeats specify false to make the timer stop after sending its first action event
158 * @return The (started) timer.
159 * @since 5735
160 */
161 public static final Timer scheduleTimer(int initialDelay, ActionListener actionListener, boolean repeats) {
162 Timer timer = new Timer(initialDelay, actionListener);
163 timer.setRepeats(repeats);
164 timer.start();
165 return timer;
166 }
167
168 /**
169 * Return s new BasicStroke object with given thickness and style
170 * @param code = 3.5 -> thickness=3.5px
171 * @param code = 3.5 10 5 -> thickness=3.5px, dashed: 10px filled + 5px empty
172 */
173 public static Stroke getCustomizedStroke(String code) {
174 String[] s = code.trim().split("[^\\.0-9]+");
175
176 if (s.length==0) return new BasicStroke();
177 float w;
178 try {
179 w = Float.parseFloat(s[0]);
180 } catch (NumberFormatException ex) {
181 w = 1.0f;
182 }
183 if (s.length>1) {
184 float dash[]= new float[s.length-1];
185 boolean error = false;
186 float sumAbs = 0;
187 try {
188 for (int i=0; i<s.length-1; i++) {
189 dash[i] = Float.parseFloat(s[i+1]);
190 sumAbs += Math.abs(dash[i]);
191 }
192 } catch (NumberFormatException ex) {
193 System.err.println("Error in stroke preference format: "+code);
194 dash = new float[]{5.0f};
195 }
196 if (sumAbs < 1e-1) {
197 System.err.println("Error in stroke dash fomat (all zeros): "+code);
198 return new BasicStroke(w);
199 }
200 // dashed stroke
201 return new BasicStroke(w, BasicStroke.CAP_BUTT,
202 BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
203 } else {
204 if (w>1) {
205 // thick stroke
206 return new BasicStroke(w, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
207 } else {
208 // thin stroke
209 return new BasicStroke(w);
210 }
211 }
212 }
213
214}
Note: See TracBrowser for help on using the repository browser.