source: josm/trunk/src/org/openstreetmap/josm/gui/GettingStarted.java@ 18959

Last change on this file since 18959 was 18601, checked in by taylor.smock, 19 months ago

Fix #20528: Copy does not work from the welcome screen

This was caused by setting the TransferHandler to null in order to get
drag and drop working. Instead of setting the TransferHandler to null, we
just set the DropTarget to null, which is what prevents the parent
DropTarget from being triggered.

The DropTarget could also have it's setActive method called with false,
but this will hopefully be less surprising.

  • Property svn:eol-style set to native
File size: 9.3 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.BorderLayout;
7import java.awt.EventQueue;
8import java.awt.Graphics;
9import java.io.IOException;
10import java.nio.charset.StandardCharsets;
11import java.util.regex.Matcher;
12import java.util.regex.Pattern;
13
14import javax.swing.JComponent;
15import javax.swing.JPanel;
16import javax.swing.JScrollPane;
17import javax.swing.Timer;
18import javax.swing.border.EmptyBorder;
19import javax.swing.event.HyperlinkEvent;
20import javax.swing.event.HyperlinkListener;
21
22import org.openstreetmap.josm.actions.DownloadAction;
23import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
24import org.openstreetmap.josm.actions.HistoryInfoAction;
25import org.openstreetmap.josm.data.Version;
26import org.openstreetmap.josm.gui.animation.AnimationExtensionManager;
27import org.openstreetmap.josm.gui.datatransfer.OpenTransferHandler;
28import org.openstreetmap.josm.gui.dialogs.MenuItemSearchDialog;
29import org.openstreetmap.josm.gui.preferences.server.ProxyPreference;
30import org.openstreetmap.josm.gui.preferences.server.ProxyPreferenceListener;
31import org.openstreetmap.josm.gui.widgets.JosmEditorPane;
32import org.openstreetmap.josm.io.CacheCustomContent;
33import org.openstreetmap.josm.io.NetworkManager;
34import org.openstreetmap.josm.io.OnlineResource;
35import org.openstreetmap.josm.spi.preferences.Config;
36import org.openstreetmap.josm.tools.ImageProvider;
37import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
38import org.openstreetmap.josm.tools.LanguageInfo;
39import org.openstreetmap.josm.tools.Logging;
40import org.openstreetmap.josm.tools.OpenBrowser;
41import org.openstreetmap.josm.tools.Utils;
42import org.openstreetmap.josm.tools.WikiReader;
43
44/**
45 * Panel that fills the main part of the program window when JOSM has just started.
46 *
47 * It downloads and displays the so called <em>message of the day</em>, which
48 * contains news about recent major changes, warning in case of outdated versions, etc.
49 */
50public final class GettingStarted extends JPanel implements ProxyPreferenceListener {
51
52 private final LinkGeneral lg;
53 private String content = "";
54 private boolean contentInitialized;
55 private final Timer timer = new Timer(50, e -> repaint());
56
57 private static final String STYLE = "<style type=\"text/css\">\n"
58 + "body {font-family: sans-serif; font-weight: bold; }\n"
59 + "h1 {text-align: center; }\n"
60 + "a {color: " + JosmEditorPane.getLinkColor() + "; }\n"
61 + ".icon {font-size: 0; }\n"
62 + "</style>\n";
63
64 /**
65 * A subclass of {@link JosmEditorPane} which replaces links with something clickable (uses {@link OpenBrowser})
66 * @since 623
67 */
68 public static class LinkGeneral extends JosmEditorPane implements HyperlinkListener {
69
70 /**
71 * Constructs a new {@code LinkGeneral} with the given HTML text
72 * @param text The text to display
73 */
74 public LinkGeneral(String text) {
75 setContentType("text/html");
76 setText(text);
77 setEditable(false);
78 setOpaque(false);
79 addHyperlinkListener(this);
80 adaptForNimbus(this);
81 }
82
83 @Override
84 public void hyperlinkUpdate(HyperlinkEvent e) {
85 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
86 OpenBrowser.displayUrl(e.getDescription());
87 }
88 }
89 }
90
91 /**
92 * Grabs current MOTD from cache or webpage and parses it.
93 */
94 static class MotdContent extends CacheCustomContent<IOException> {
95 MotdContent() {
96 super("motd.html", CacheCustomContent.INTERVAL_DAILY);
97 }
98
99 private final int myVersion = Version.getInstance().getVersion();
100 private final String myJava = Utils.getSystemProperty("java.version");
101 private final String myLang = LanguageInfo.getWikiLanguagePrefix();
102
103 /**
104 * This function gets executed whenever the cached files need updating
105 * @see org.openstreetmap.josm.io.CacheCustomContent#updateData()
106 */
107 @Override
108 protected byte[] updateData() throws IOException {
109 String motd = new WikiReader().readLang("StartupPage");
110 // Save this to prefs in case JOSM is updated so MOTD can be refreshed
111 Config.getPref().putInt("cache.motd.html.version", myVersion);
112 Config.getPref().put("cache.motd.html.java", myJava);
113 Config.getPref().put("cache.motd.html.lang", myLang);
114 return motd.getBytes(StandardCharsets.UTF_8);
115 }
116
117 @Override
118 protected boolean isOffline() {
119 return NetworkManager.isOffline(OnlineResource.JOSM_WEBSITE);
120 }
121
122 /**
123 * Additionally check if JOSM has been updated and refresh MOTD
124 */
125 @Override
126 protected boolean isCacheValid() {
127 // We assume a default of myVersion because it only kicks in in two cases:
128 // 1. Not yet written - but so isn't the interval variable, so it gets updated anyway
129 // 2. Cannot be written (e.g. while developing). Obviously we don't want to update
130 // every time because of something we can't read.
131 return (Config.getPref().getInt("cache.motd.html.version", -999) == myVersion)
132 && Config.getPref().get("cache.motd.html.java").equals(myJava)
133 && Config.getPref().get("cache.motd.html.lang").equals(myLang);
134 }
135 }
136
137 /**
138 * Initializes getting the MOTD as well as enabling the FileDrop Listener. Displays a message
139 * while the MOTD is downloading.
140 */
141 public GettingStarted() {
142 super(new BorderLayout());
143 lg = new LinkGeneral("<html>" + STYLE + "<h1>" + "JOSM - " + tr("Java OpenStreetMap Editor")
144 + "</h1><h2 align=\"center\">" + tr("Downloading \"Message of the day\"") + "</h2></html>");
145 // clear the build-in command ctrl+shift+O, ctrl+space, ctrl+H because it is used as shortcut in JOSM
146 lg.getInputMap(JComponent.WHEN_FOCUSED).put(DownloadAction.SHORTCUT.getKeyStroke(), "none");
147 lg.getInputMap(JComponent.WHEN_FOCUSED).put(DownloadPrimitiveAction.SHORTCUT.getKeyStroke(), "none");
148 lg.getInputMap(JComponent.WHEN_FOCUSED).put(MenuItemSearchDialog.Action.SHORTCUT.getKeyStroke(), "none");
149 lg.getInputMap(JComponent.WHEN_FOCUSED).put(HistoryInfoAction.SHORTCUT.getKeyStroke(), "none");
150 // Don't use the text handler drag and drop behavior. See #13196/#20528.
151 lg.setDropTarget(null);
152
153 JScrollPane scroller = new JScrollPane(lg);
154 scroller.setViewportBorder(new EmptyBorder(10, 100, 10, 100));
155 add(scroller, BorderLayout.CENTER);
156
157 getMOTD();
158
159 setTransferHandler(new OpenTransferHandler());
160 }
161
162 @Override
163 public void addNotify() {
164 if (AnimationExtensionManager.isExtensionEnabled()) {
165 timer.start();
166 }
167 super.addNotify();
168 }
169
170 @Override
171 public void removeNotify() {
172 if (timer.isRunning()) {
173 timer.stop();
174 }
175 super.removeNotify();
176 }
177
178 @Override
179 public void paint(Graphics g) {
180 super.paint(g);
181 if (isShowing()) {
182 AnimationExtensionManager.getExtension().adjustForSize(getWidth(), getHeight());
183 AnimationExtensionManager.getExtension().animate();
184 AnimationExtensionManager.getExtension().paint(g);
185 }
186 }
187
188 private void getMOTD() {
189 // Asynchronously get MOTD to speed-up JOSM startup
190 Thread t = new Thread((Runnable) () -> {
191 if (!contentInitialized && Config.getPref().getBoolean("help.displaymotd", true)) {
192 try {
193 content = new MotdContent().updateIfRequiredString();
194 contentInitialized = true;
195 ProxyPreference.removeProxyPreferenceListener(this);
196 } catch (IOException ex) {
197 Logging.log(Logging.LEVEL_WARN, tr("Failed to read MOTD. Exception was: {0}", ex.toString()), ex);
198 content = "<html>" + STYLE + "<h1>" + "JOSM - " + tr("Java OpenStreetMap Editor")
199 + "</h1>\n<h2 align=\"center\">(" + tr("Message of the day not available") + ")</h2></html>";
200 // In case of MOTD not loaded because of proxy error, listen to preference changes to retry after update
201 ProxyPreference.addProxyPreferenceListener(this);
202 }
203 }
204
205 if (content != null) {
206 EventQueue.invokeLater(() -> lg.setText(fixImageLinks(content)));
207 }
208 }, "MOTD-Loader");
209 t.setDaemon(true);
210 t.start();
211 }
212
213 static String fixImageLinks(String s) {
214 Matcher m = Pattern.compile("src=\"/browser/trunk/resources/images/(.*?)\\.(png|svg)\\?format=raw\"").matcher(s);
215 StringBuffer sb = new StringBuffer();
216 while (m.find()) {
217 String im = m.group(1);
218 String u = new ImageProvider(im).setMaxSize(ImageSizes.HTMLINLINE).getDataURL();
219 if (u != null) {
220 m.appendReplacement(sb, Matcher.quoteReplacement("src=\"" + u + '\"'));
221 }
222 }
223 m.appendTail(sb);
224 return sb.toString();
225 }
226
227 @Override
228 public void proxyPreferenceChanged() {
229 getMOTD();
230 }
231}
Note: See TracBrowser for help on using the repository browser.