001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Color;
007import java.awt.Dimension;
008import java.awt.GridBagConstraints;
009import java.awt.GridBagLayout;
010import java.awt.Insets;
011import java.awt.event.MouseAdapter;
012import java.awt.event.MouseEvent;
013import java.util.Arrays;
014import java.util.LinkedList;
015
016import javax.swing.JFrame;
017import javax.swing.JLabel;
018import javax.swing.JPanel;
019import javax.swing.JProgressBar;
020import javax.swing.JSeparator;
021import javax.swing.border.Border;
022import javax.swing.border.EmptyBorder;
023import javax.swing.border.EtchedBorder;
024
025import org.openstreetmap.josm.data.Version;
026import org.openstreetmap.josm.gui.progress.ProgressMonitor;
027import org.openstreetmap.josm.gui.progress.ProgressRenderer;
028import org.openstreetmap.josm.gui.progress.SwingRenderingProgressMonitor;
029import org.openstreetmap.josm.gui.util.GuiHelper;
030import org.openstreetmap.josm.tools.ImageProvider;
031import org.openstreetmap.josm.tools.WindowGeometry;
032
033/**
034 * Show a splash screen so the user knows what is happening during startup.
035 *
036 */
037public class SplashScreen extends JFrame {
038
039    private SwingRenderingProgressMonitor progressMonitor;
040
041    /**
042     * Constructs a new {@code SplashScreen}.
043     */
044    public SplashScreen() {
045        super();
046        setUndecorated(true);
047
048        // Add a nice border to the main splash screen
049        JPanel contentPane = (JPanel)this.getContentPane();
050        Border margin = new EtchedBorder(1, Color.white, Color.gray);
051        contentPane.setBorder(margin);
052
053        // Add a margin from the border to the content
054        JPanel innerContentPane = new JPanel();
055        innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
056        contentPane.add(innerContentPane);
057        innerContentPane.setLayout(new GridBagLayout());
058
059        // Add the logo
060        JLabel logo = new JLabel(ImageProvider.get("logo.png"));
061        GridBagConstraints gbc = new GridBagConstraints();
062        gbc.gridheight = 2;
063        gbc.insets = new Insets(0, 0, 0, 70);
064        innerContentPane.add(logo, gbc);
065
066        // Add the name of this application
067        JLabel caption = new JLabel("JOSM - " + tr("Java OpenStreetMap Editor"));
068        caption.setFont(GuiHelper.getTitleFont());
069        gbc.gridheight = 1;
070        gbc.gridx = 1;
071        gbc.insets = new Insets(30, 0, 0, 0);
072        innerContentPane.add(caption, gbc);
073
074        // Add the version number
075        JLabel version = new JLabel(tr("Version {0}", Version.getInstance().getVersionString()));
076        gbc.gridy = 1;
077        gbc.insets = new Insets(0, 0, 0, 0);
078        innerContentPane.add(version, gbc);
079
080        // Add a separator to the status text
081        JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
082        gbc.gridx = 0;
083        gbc.gridy = 2;
084        gbc.gridwidth = 2;
085        gbc.fill = GridBagConstraints.HORIZONTAL;
086        gbc.insets = new Insets(15, 0, 5, 0);
087        innerContentPane.add(separator, gbc);
088
089        // Add a status message
090        SplashScreenProgressRenderer progressRenderer = new SplashScreenProgressRenderer();
091        gbc.gridy = 3;
092        gbc.insets = new Insets(0, 0, 10, 0);
093        innerContentPane.add(progressRenderer, gbc);
094        progressMonitor = new SwingRenderingProgressMonitor(progressRenderer);
095
096        pack();
097
098        WindowGeometry.centerOnScreen(this.getSize(), "gui.geometry").applySafe(this);
099
100        // Add ability to hide splash screen by clicking it
101        addMouseListener(new MouseAdapter() {
102            @Override
103            public void mousePressed(MouseEvent event) {
104                setVisible(false);
105            }
106        });
107    }
108
109    public ProgressMonitor getProgressMonitor() {
110        return progressMonitor;
111    }
112
113    static private class SplashScreenProgressRenderer extends JPanel implements ProgressRenderer {
114        private JLabel lblTaskTitle;
115        private JLabel lblCustomText;
116        private JProgressBar progressBar;
117
118        protected void build() {
119            setLayout(new GridBagLayout());
120            GridBagConstraints gc = new GridBagConstraints();
121            gc.gridx = 0;
122            gc.gridy = 0;
123            gc.fill = GridBagConstraints.HORIZONTAL;
124            gc.weightx = 1.0;
125            gc.weighty = 0.0;
126            gc.insets = new Insets(5,0,0,0);
127            add(lblTaskTitle = new JLabel(" "), gc);
128
129            gc.gridx = 0;
130            gc.gridy = 1;
131            gc.fill = GridBagConstraints.HORIZONTAL;
132            gc.weightx = 1.0;
133            gc.weighty = 0.0;
134            gc.insets = new Insets(5,0,0,0);
135            add(lblCustomText = new JLabel(" ") {
136                @Override
137                public Dimension getPreferredSize() {
138                    Dimension d = super.getPreferredSize();
139                    if(d.width < 600) d.width = 600;
140                    d.height *= MAX_NUMBER_OF_MESSAGES;
141                    return d;
142                }
143            }, gc);
144
145            gc.gridx = 0;
146            gc.gridy = 2;
147            gc.fill = GridBagConstraints.HORIZONTAL;
148            gc.weightx = 1.0;
149            gc.weighty = 0.0;
150            gc.insets = new Insets(5,0,0,0);
151            add(progressBar = new JProgressBar(JProgressBar.HORIZONTAL), gc);
152        }
153
154        public SplashScreenProgressRenderer() {
155            build();
156        }
157
158        @Override
159        public void setCustomText(String message) {
160            if(message.isEmpty())
161                message = " "; // prevent killing of additional line
162            lblCustomText.setText(message);
163            repaint();
164        }
165
166        @Override
167        public void setIndeterminate(boolean indeterminate) {
168            progressBar.setIndeterminate(indeterminate);
169            repaint();
170        }
171
172        @Override
173        public void setMaximum(int maximum) {
174            progressBar.setMaximum(maximum);
175            repaint();
176        }
177
178        private static final int MAX_NUMBER_OF_MESSAGES = 3;
179        private LinkedList<String> messages = new LinkedList<String>(Arrays.asList("", "", "")); //update when changing MAX_NUMBER_OF_MESSAGES
180        private long time = System.currentTimeMillis();
181
182        /**
183         * Stores and displays the {@code MAX_NUMBER_OF_MESSAGES} most recent
184         * task titles together with their execution time.
185         */
186        @Override
187        public void setTaskTitle(String taskTitle) {
188
189            while (messages.size() >= MAX_NUMBER_OF_MESSAGES) {
190                messages.removeFirst();
191            }
192            long now = System.currentTimeMillis();
193            String prevMessageTitle = messages.getLast();
194            if (!prevMessageTitle.isEmpty()) {
195                messages.removeLast();
196                messages.add(tr("{0} ({1} ms)", prevMessageTitle, Long.toString(now - time)));
197            }
198            time = now;
199            if (!taskTitle.isEmpty()) {
200                messages.add(taskTitle);
201            }
202            StringBuilder html = new StringBuilder();
203            int i = 0;
204            for (String m : messages) {
205                html.append("<p class=\"entry").append(++i).append("\">").append(m).append("</p>");
206            }
207
208            lblTaskTitle.setText("<html><style>"
209                    + ".entry1{color:#CCCCCC;}"
210                    + ".entry2{color:#999999;}"
211                    + ".entry3{color:#000000;}</style>" + html + "</html>");  //update when changing MAX_NUMBER_OF_MESSAGES
212            repaint();
213        }
214
215        @Override
216        public void setValue(int value) {
217            progressBar.setValue(value);
218            repaint();
219        }
220    }
221}