source: josm/trunk/src/org/openstreetmap/josm/gui/SplashScreen.java@ 8499

Last change on this file since 8499 was 8499, checked in by simon04, 10 years ago

see #11355 - Splash screen: attempt to fix dialog height issue

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Graphics;
9import java.awt.GridBagConstraints;
10import java.awt.GridBagLayout;
11import java.awt.Image;
12import java.awt.Insets;
13import java.awt.event.MouseAdapter;
14import java.awt.event.MouseEvent;
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.List;
18import java.util.Objects;
19
20import javax.swing.ImageIcon;
21import javax.swing.JFrame;
22import javax.swing.JLabel;
23import javax.swing.JPanel;
24import javax.swing.JProgressBar;
25import javax.swing.JSeparator;
26import javax.swing.border.Border;
27import javax.swing.border.EmptyBorder;
28import javax.swing.border.EtchedBorder;
29import javax.swing.event.ChangeEvent;
30import javax.swing.event.ChangeListener;
31
32import org.openstreetmap.josm.Main;
33import org.openstreetmap.josm.data.Version;
34import org.openstreetmap.josm.gui.progress.ProgressMonitor;
35import org.openstreetmap.josm.gui.progress.ProgressTaskId;
36import org.openstreetmap.josm.gui.util.GuiHelper;
37import org.openstreetmap.josm.tools.ImageProvider;
38import org.openstreetmap.josm.tools.Predicates;
39import org.openstreetmap.josm.tools.Utils;
40import org.openstreetmap.josm.tools.WindowGeometry;
41
42/**
43 * Show a splash screen so the user knows what is happening during startup.
44 * @since 976
45 */
46public class SplashScreen extends JFrame implements ChangeListener {
47
48 private final SplashProgressMonitor progressMonitor;
49 private final SplashScreenProgressRenderer progressRenderer;
50
51 /**
52 * Constructs a new {@code SplashScreen}.
53 */
54 public SplashScreen() {
55 setUndecorated(true);
56
57 // Add a nice border to the main splash screen
58 JPanel contentPane = (JPanel)this.getContentPane();
59 Border margin = new EtchedBorder(1, Color.white, Color.gray);
60 contentPane.setBorder(margin);
61
62 // Add a margin from the border to the content
63 JPanel innerContentPane = new JPanel();
64 innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
65 contentPane.add(innerContentPane);
66 innerContentPane.setLayout(new GridBagLayout());
67
68 // Add the logo
69 JLabel logo = new JLabel(new ImageIcon(ImageProvider.get("logo.svg").getImage().getScaledInstance(128, 129, Image.SCALE_SMOOTH)));
70 GridBagConstraints gbc = new GridBagConstraints();
71 gbc.gridheight = 2;
72 gbc.insets = new Insets(0, 0, 0, 70);
73 innerContentPane.add(logo, gbc);
74
75 // Add the name of this application
76 JLabel caption = new JLabel("JOSM – " + tr("Java OpenStreetMap Editor"));
77 caption.setFont(GuiHelper.getTitleFont());
78 gbc.gridheight = 1;
79 gbc.gridx = 1;
80 gbc.insets = new Insets(30, 0, 0, 0);
81 innerContentPane.add(caption, gbc);
82
83 // Add the version number
84 JLabel version = new JLabel(tr("Version {0}", Version.getInstance().getVersionString()));
85 gbc.gridy = 1;
86 gbc.insets = new Insets(0, 0, 0, 0);
87 innerContentPane.add(version, gbc);
88
89 // Add a separator to the status text
90 JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
91 gbc.gridx = 0;
92 gbc.gridy = 2;
93 gbc.gridwidth = 2;
94 gbc.fill = GridBagConstraints.HORIZONTAL;
95 gbc.insets = new Insets(15, 0, 5, 0);
96 innerContentPane.add(separator, gbc);
97
98 // Add a status message
99 progressRenderer = new SplashScreenProgressRenderer();
100 gbc.gridy = 3;
101 gbc.insets = new Insets(0, 0, 10, 0);
102 innerContentPane.add(progressRenderer, gbc);
103 progressMonitor = new SplashProgressMonitor(null, this);
104
105 pack();
106
107 WindowGeometry.centerOnScreen(this.getSize(), "gui.geometry").applySafe(this);
108
109 // Add ability to hide splash screen by clicking it
110 addMouseListener(new MouseAdapter() {
111 @Override
112 public void mousePressed(MouseEvent event) {
113 setVisible(false);
114 }
115 });
116 }
117
118 @Override
119 public void stateChanged(ChangeEvent ignore) {
120 progressRenderer.setTasks(progressMonitor.toString());
121 pack();
122 }
123
124 /**
125 * A task (of a {@link ProgressMonitor}).
126 */
127 private static abstract class Task {
128
129 /**
130 * Returns a HTML representation for this task.
131 */
132 public abstract String toHtml();
133
134 @Override
135 public final String toString() {
136 return toHtml();
137 }
138 }
139
140 /**
141 * A single task (of a {@link ProgressMonitor}) which keeps track of its execution duration
142 * (requires a call to {@link #finish()}).
143 */
144 private static class MeasurableTask extends Task {
145 private final String name;
146 private final long start;
147 private String duration = "";
148
149 public MeasurableTask(String name) {
150 this.name = name;
151 this.start = System.currentTimeMillis();
152 }
153
154 public void finish() {
155 if (!"".equals(duration)) {
156 throw new IllegalStateException("This tasks has already been finished");
157 }
158 duration = tr(" ({0})", Utils.getDurationString(System.currentTimeMillis() - start));
159 }
160
161 @Override
162 public String toHtml() {
163 return name + "<i style='color: #666666;'>" + duration + "</i>";
164 }
165
166 @Override
167 public boolean equals(Object o) {
168 if (this == o) return true;
169 if (o == null || getClass() != o.getClass()) return false;
170 MeasurableTask that = (MeasurableTask) o;
171 return Objects.equals(name, that.name);
172 }
173
174 @Override
175 public int hashCode() {
176 return Objects.hashCode(name);
177 }
178 }
179
180 /**
181 * A {@link ProgressMonitor} which stores the (sub)tasks in a tree.
182 */
183 public static class SplashProgressMonitor extends Task implements ProgressMonitor {
184
185 private final String name;
186 private final ChangeListener listener;
187 private final List<Task> tasks = Collections.synchronizedList(new ArrayList<Task>());
188 private SplashProgressMonitor latestSubtask;
189
190 public SplashProgressMonitor(String name, ChangeListener listener) {
191 this.name = name;
192 this.listener = listener;
193 }
194
195 @Override
196 public String toHtml() {
197 synchronized (tasks) {
198 return Utils.firstNonNull(name, "") + (tasks.isEmpty() ? "" : Utils.joinAsHtmlUnorderedList(tasks));
199 }
200 }
201
202 @Override
203 public void beginTask(String title) {
204 if (title != null) {
205 final MeasurableTask task = new MeasurableTask(title);
206 tasks.add(task);
207 listener.stateChanged(null);
208 }
209 }
210
211 @Override
212 public void beginTask(String title, int ticks) {
213 this.beginTask(title);
214 }
215
216 @Override
217 public void setCustomText(String text) {
218 this.beginTask(text);
219 }
220
221 @Override
222 public void setExtraText(String text) {
223 this.beginTask(text);
224 }
225
226 @Override
227 public void indeterminateSubTask(String title) {
228 this.subTask(title);
229 }
230
231 @Override
232 public void subTask(String title) {
233 latestSubtask = new SplashProgressMonitor(title, listener);
234 tasks.add(latestSubtask);
235 listener.stateChanged(null);
236 }
237
238 @Override
239 public ProgressMonitor createSubTaskMonitor(int ticks, boolean internal) {
240 return latestSubtask;
241 }
242
243 @Override
244 @Deprecated
245 public void finishTask() {
246 }
247
248 public void finishTask(String title) {
249 final Task task = Utils.find(tasks, Predicates.<Task>equalTo(new MeasurableTask(title)));
250 if (task != null && task instanceof MeasurableTask) {
251 ((MeasurableTask) task).finish();
252 Main.debug(tr("{0} completed in {1}", title, ((MeasurableTask) task).duration));
253 listener.stateChanged(null);
254 }
255 }
256
257 @Override
258 public void invalidate() {
259 }
260
261 @Override
262 public void setTicksCount(int ticks) {
263 }
264
265 @Override
266 public int getTicksCount() {
267 return 0;
268 }
269
270 @Override
271 public void setTicks(int ticks) {
272 }
273
274 @Override
275 public int getTicks() {
276 return 0;
277 }
278
279 @Override
280 public void worked(int ticks) {
281 }
282
283 @Override
284 public boolean isCanceled() {
285 return false;
286 }
287
288 @Override
289 public void cancel() {
290 }
291
292 @Override
293 public void addCancelListener(CancelListener listener) {
294 }
295
296 @Override
297 public void removeCancelListener(CancelListener listener) {
298 }
299
300 @Override
301 public void appendLogMessage(String message) {
302 }
303
304 @Override
305 public void setProgressTaskId(ProgressTaskId taskId) {
306 }
307
308 @Override
309 public ProgressTaskId getProgressTaskId() {
310 return null;
311 }
312
313 @Override
314 public Component getWindowParent() {
315 return Main.parent;
316 }
317 }
318
319 /**
320 * Returns the progress monitor.
321 * @return The progress monitor
322 */
323 public SplashProgressMonitor getProgressMonitor() {
324 return progressMonitor;
325 }
326
327 private static class SplashScreenProgressRenderer extends JPanel {
328 private JLabel lblTaskTitle;
329 private JProgressBar progressBar;
330 private static final String labelHtml = "<html>"
331 + "<style>ul {margin-top: 0; margin-bottom: 0; padding: 0;} li {margin: 0; padding: 0;}</style>"
332 + "<body height='320'>";
333
334 protected void build() {
335 setLayout(new GridBagLayout());
336 GridBagConstraints gc = new GridBagConstraints();
337 gc.gridx = 0;
338 gc.gridy = 0;
339 gc.fill = GridBagConstraints.HORIZONTAL;
340 gc.weightx = 1.0;
341 gc.weighty = 0.0;
342 gc.insets = new Insets(5,0,0,0);
343 add(lblTaskTitle = new JLabel(labelHtml), gc);
344
345 gc.gridy = 1;
346 gc.insets = new Insets(15,0,0,0);
347 add(progressBar = new JProgressBar(JProgressBar.HORIZONTAL), gc);
348 progressBar.setIndeterminate(true);
349 }
350
351 public SplashScreenProgressRenderer() {
352 build();
353 }
354
355 @Override
356 public void paint(Graphics g) {
357 try {
358 super.paint(g);
359 } catch (NullPointerException ignore) {
360 // NullPointerException at javax.swing.text.html.StyleSheet$ListPainter.paint
361 }
362 }
363
364 public void setTasks(String tasks) {
365 lblTaskTitle.setText(labelHtml + tasks);
366 repaint();
367 }
368 }
369}
Note: See TracBrowser for help on using the repository browser.