source: josm/trunk/src/org/openstreetmap/josm/actions/AboutAction.java @ 14693

Last change on this file since 14693 was 14693, checked in by GerdP, 2 months ago

fix #17192 Add tab with installation details in "About" popup

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.Utils.getSystemEnv;
6import static org.openstreetmap.josm.tools.Utils.getSystemProperty;
7
8import java.awt.Color;
9import java.awt.Dimension;
10import java.awt.FlowLayout;
11import java.awt.Font;
12import java.awt.GridBagLayout;
13import java.awt.event.ActionEvent;
14import java.awt.event.KeyEvent;
15import java.awt.event.MouseAdapter;
16import java.awt.event.MouseEvent;
17import java.io.BufferedReader;
18import java.io.File;
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.InputStreamReader;
22
23import javax.swing.AbstractAction;
24import javax.swing.Action;
25import javax.swing.BorderFactory;
26import javax.swing.JButton;
27import javax.swing.JLabel;
28import javax.swing.JPanel;
29import javax.swing.JScrollPane;
30import javax.swing.JTabbedPane;
31import javax.swing.JTextArea;
32
33import org.openstreetmap.josm.data.Version;
34import org.openstreetmap.josm.gui.ExtendedDialog;
35import org.openstreetmap.josm.gui.MainApplication;
36import org.openstreetmap.josm.gui.util.GuiHelper;
37import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
38import org.openstreetmap.josm.gui.widgets.JosmTextArea;
39import org.openstreetmap.josm.gui.widgets.UrlLabel;
40import org.openstreetmap.josm.plugins.PluginHandler;
41import org.openstreetmap.josm.spi.preferences.Config;
42import org.openstreetmap.josm.tools.GBC;
43import org.openstreetmap.josm.tools.ImageProvider;
44import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
45import org.openstreetmap.josm.tools.Logging;
46import org.openstreetmap.josm.tools.OpenBrowser;
47import org.openstreetmap.josm.tools.PlatformManager;
48import org.openstreetmap.josm.tools.Shortcut;
49import org.openstreetmap.josm.tools.Utils;
50
51/**
52 * Nice about screen.
53 *
54 * The REVISION resource is read and if present, it shows the revision information of the jar-file.
55 *
56 * @author imi
57 */
58public final class AboutAction extends JosmAction {
59
60    /**
61     * Constructs a new {@code AboutAction}.
62     */
63    public AboutAction() {
64        super(tr("About"), "logo", tr("Display the about screen."),
65            Shortcut.registerShortcut("system:about", tr("About"),
66            KeyEvent.VK_F1, Shortcut.SHIFT), true);
67    }
68
69    @Override
70    public void actionPerformed(ActionEvent e) {
71        final JTabbedPane about = new JTabbedPane();
72
73        Version version = Version.getInstance();
74
75        JosmTextArea readme = new JosmTextArea();
76        readme.setFont(GuiHelper.getMonospacedFont(readme));
77        readme.setEditable(false);
78        setTextFromResourceFile(readme, "/README");
79        readme.setCaretPosition(0);
80
81        JosmTextArea revision = new JosmTextArea();
82        revision.setFont(GuiHelper.getMonospacedFont(revision));
83        revision.setEditable(false);
84        revision.setText(version.getReleaseAttributes());
85        revision.setCaretPosition(0);
86
87        JosmTextArea contribution = new JosmTextArea();
88        contribution.setEditable(false);
89        setTextFromResourceFile(contribution, "/CONTRIBUTION");
90        contribution.setCaretPosition(0);
91
92        JosmTextArea license = new JosmTextArea();
93        license.setEditable(false);
94        setTextFromResourceFile(license, "/LICENSE");
95        license.setCaretPosition(0);
96
97        JPanel info = new JPanel(new GridBagLayout());
98        final JMultilineLabel label = new JMultilineLabel("<html>" +
99                "<h1>" + "JOSM – " + tr("Java OpenStreetMap Editor") + "</h1>" +
100                "<p style='font-size:75%'></p>" +
101                "<p>" + tr("Version {0}", version.getVersionString()) + "</p>" +
102                "<p style='font-size:50%'></p>" +
103                "<p>" + tr("Last change at {0}", version.getTime()) + "</p>" +
104                "<p style='font-size:50%'></p>" +
105                "<p>" + tr("Java Version {0}", Utils.getSystemProperty("java.version")) + "</p>" +
106                "<p style='font-size:50%'></p>" +
107                "</html>");
108        info.add(label, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 10));
109        info.add(new JLabel(tr("Homepage")), GBC.std().insets(10, 0, 10, 0));
110        info.add(new UrlLabel(Config.getUrls().getJOSMWebsite(), 2), GBC.eol());
111        info.add(new JLabel(tr("Translations")), GBC.std().insets(10, 0, 10, 0));
112        info.add(new UrlLabel("https://translations.launchpad.net/josm", 2), GBC.eol());
113        info.add(new JLabel(tr("Follow us on")), GBC.std().insets(10, 10, 10, 0));
114        JPanel logos = new JPanel(new FlowLayout());
115        logos.add(createImageLink("OpenStreetMap", /* ICON(dialogs/about/) */ "openstreetmap",
116                "https://www.openstreetmap.org/user/josmeditor/diary"));
117        logos.add(createImageLink("Twitter", /* ICON(dialogs/about/) */ "twitter", "https://twitter.com/josmeditor"));
118        logos.add(createImageLink("Facebook", /* ICON(dialogs/about/) */ "facebook", "https://www.facebook.com/josmeditor"));
119        logos.add(createImageLink("GitHub", /* ICON(dialogs/about/) */ "github", "https://github.com/JOSM"));
120        info.add(logos, GBC.eol().insets(0, 10, 0, 0));
121        info.add(GBC.glue(0, 5), GBC.eol());
122
123        JPanel inst = new JPanel(new GridBagLayout());
124        addInstallationLine(inst, getSystemEnv("JAVA_HOME"), PlatformManager.isPlatformWindows() ? "%JAVA_HOME%" : "${JAVA_HOME}");
125        addInstallationLine(inst, getSystemProperty("java.home"), "java.home");
126        addInstallationLine(inst, Config.getDirs().getPreferencesDirectory(false).toString(), null);
127        addInstallationLine(inst, Config.getDirs().getUserDataDirectory(false).toString(), null);
128        addInstallationLine(inst, Config.getDirs().getCacheDirectory(false).toString(), null);
129
130        about.addTab(tr("Info"), info);
131        about.addTab(tr("Readme"), createScrollPane(readme));
132        about.addTab(tr("Revision"), createScrollPane(revision));
133        about.addTab(tr("Contribution"), createScrollPane(contribution));
134        about.addTab(tr("License"), createScrollPane(license));
135        about.addTab(tr("Plugins"), new JScrollPane(PluginHandler.getInfoPanel()));
136        about.addTab(tr("Installation Details"), inst);
137
138        // Get the list of Launchpad contributors using customary msgid “translator-credits”
139        String translators = tr("translator-credits");
140        if (translators != null && !translators.isEmpty() && !"translator-credits".equals(translators)) {
141            about.addTab(tr("Translators"), createScrollPane(new JosmTextArea(translators)));
142        }
143
144        // Intermediate panel to allow proper optionPane resizing
145        JPanel panel = new JPanel(new GridBagLayout());
146        panel.setPreferredSize(new Dimension(890, 300));
147        panel.add(new JLabel("", ImageProvider.get("logo.svg", ImageProvider.ImageSizes.ABOUT_LOGO),
148                JLabel.CENTER), GBC.std().insets(0, 5, 0, 0));
149        panel.add(about, GBC.std().fill());
150
151        GuiHelper.prepareResizeableOptionPane(panel, panel.getPreferredSize());
152        ExtendedDialog dlg = new ExtendedDialog(MainApplication.getMainFrame(), tr("About JOSM..."), tr("OK"), tr("Report bug"));
153        int ret = dlg.setButtonIcons("ok", "bug")
154                .setContent(panel, false)
155                .showDialog().getValue();
156        if (2 == ret) {
157            MainApplication.getMenu().reportbug.actionPerformed(null);
158        }
159        GuiHelper.destroyComponents(panel, false);
160        dlg.dispose();
161    }
162
163    private static class OpenDirAction extends AbstractAction {
164        final String dir;
165
166        OpenDirAction(String dir) {
167            super();
168            putValue(Action.NAME, "...");
169            this.dir = dir;
170            setEnabled(dir != null && new File(dir).isDirectory());
171        }
172
173        @Override
174        public void actionPerformed(ActionEvent e) {
175            OpenBrowser.displayUrl(new File(dir).toURI());
176        }
177    }
178
179    /**
180     * Add line to installation details showing symbolic name used in status report and actual directory.
181     * @param inst the panel
182     * @param dir the actual path represented by a symbol
183     * @param source source for symbol
184     */
185    private void addInstallationLine(JPanel inst, String dir, String source) {
186        if (dir == null && source == null)
187            return;
188        JLabel symbol = new JLabel();
189        JosmTextArea dirLabel = new JosmTextArea();
190        if (dir != null && !dir.isEmpty()) {
191            symbol.setText(ShowStatusReportAction.paramCleanup(dir));
192            dirLabel.setText(dir);
193            dirLabel.setEditable(false);
194        } else {
195            symbol.setText(source);
196            dirLabel.setText(tr("(unset)"));
197            dirLabel.setFont(dirLabel.getFont().deriveFont(Font.ITALIC));
198        }
199        symbol.setFont(GuiHelper.getMonospacedFont(symbol));
200        inst.add(symbol, GBC.std().insets(5, 0, 0, 0));
201        inst.add(GBC.glue(10, 0), GBC.std());
202        dirLabel.setFont(GuiHelper.getMonospacedFont(dirLabel));
203        dirLabel.setOpaque(false);
204        inst.add(dirLabel, GBC.std().fill(GBC.HORIZONTAL));
205        JButton btn = new JButton(new OpenDirAction(dir));
206        btn.setToolTipText(tr("Open directory"));
207        inst.add(btn, GBC.eol().insets(0, 0, 5, 0));
208    }
209
210    private static JLabel createImageLink(String tooltip, String icon, final String link) {
211        JLabel label = new JLabel(ImageProvider.get("dialogs/about", icon, ImageSizes.LARGEICON));
212        label.setToolTipText(tooltip);
213        label.addMouseListener(new MouseAdapter() {
214            @Override
215            public void mouseClicked(MouseEvent e) {
216                OpenBrowser.displayUrl(link);
217            }
218        });
219        return label;
220    }
221
222    /**
223     * Reads the contents of the resource file that is described by the {@code filePath}-attribute and puts that text
224     * into the {@link JTextArea} given by the {@code ta}-attribute.
225     * @param ta the {@link JTextArea} to put the files contents into
226     * @param filePath the path where the resource file to read resides
227     */
228    private void setTextFromResourceFile(JTextArea ta, String filePath) {
229        InputStream is = Utils.getResourceAsStream(getClass(), filePath);
230        if (is == null) {
231            displayErrorMessage(ta, tr("Failed to locate resource ''{0}''.", filePath));
232        } else {
233            try (InputStreamReader reader = new InputStreamReader(is, "UTF-8");
234                 BufferedReader br = new BufferedReader(reader)) {
235                String line;
236                while ((line = br.readLine()) != null) {
237                    ta.append(line+'\n');
238                }
239            } catch (IOException e) {
240                Logging.warn(e);
241                displayErrorMessage(ta, tr("Failed to load resource ''{0}'', error is {1}.", filePath, e.toString()));
242            }
243        }
244    }
245
246    private static void displayErrorMessage(JTextArea ta, String msg) {
247        Logging.warn(msg);
248        ta.setForeground(new Color(200, 0, 0));
249        ta.setText(msg);
250    }
251
252    private static JScrollPane createScrollPane(JosmTextArea area) {
253        area.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
254        area.setOpaque(false);
255        JScrollPane sp = new JScrollPane(area);
256        sp.setBorder(null);
257        sp.setOpaque(false);
258        return sp;
259    }
260}
Note: See TracBrowser for help on using the repository browser.