source: josm/trunk/src/org/openstreetmap/josm/tools/PlatformHook.java@ 13652

Last change on this file since 13652 was 13647, checked in by Don-vip, 6 years ago

see #16204 - Allow to start and close JOSM in WebStart sandbox mode (where every external access is denied). This was very useful to reproduce some very tricky bugs that occured in real life but were almost impossible to diagnose.

  • Property svn:eol-style set to native
File size: 13.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.awt.GraphicsEnvironment;
5import java.awt.Toolkit;
6import java.awt.event.KeyEvent;
7import java.io.BufferedReader;
8import java.io.File;
9import java.io.IOException;
10import java.io.InputStreamReader;
11import java.nio.charset.StandardCharsets;
12import java.security.KeyStore;
13import java.security.KeyStoreException;
14import java.security.NoSuchAlgorithmException;
15import java.security.cert.CertificateException;
16import java.security.cert.X509Certificate;
17import java.text.DateFormat;
18import java.util.Date;
19import java.util.List;
20
21import org.openstreetmap.josm.data.projection.datum.NTV2Proj4DirGridShiftFileSource;
22import org.openstreetmap.josm.io.CertificateAmendment.NativeCertAmend;
23import org.openstreetmap.josm.spi.preferences.Config;
24import org.openstreetmap.josm.tools.date.DateUtils;
25
26/**
27 * This interface allows platform (operating system) dependent code
28 * to be bundled into self-contained classes.
29 * @since 1023
30 */
31public interface PlatformHook {
32
33 /**
34 * Visitor to construct a PlatformHook from a given {@link Platform} object.
35 */
36 PlatformVisitor<PlatformHook> CONSTRUCT_FROM_PLATFORM = new PlatformVisitor<PlatformHook>() {
37 @Override
38 public PlatformHook visitUnixoid() {
39 return new PlatformHookUnixoid();
40 }
41
42 @Override
43 public PlatformHook visitWindows() {
44 return new PlatformHookWindows();
45 }
46
47 @Override
48 public PlatformHook visitOsx() {
49 return new PlatformHookOsx();
50 }
51 };
52
53 /**
54 * Get the platform corresponding to this platform hook.
55 * @return the platform corresponding to this platform hook
56 */
57 Platform getPlatform();
58
59 /**
60 * The preStartupHook will be called extremly early. It is
61 * guaranteed to be called before the GUI setup has started.
62 *
63 * Reason: On OSX we need to inform the Swing libraries
64 * that we want to be integrated with the OS before we setup our GUI.
65 */
66 default void preStartupHook() {
67 // Do nothing
68 }
69
70 /**
71 * The afterPrefStartupHook will be called early, but after
72 * the preferences have been loaded and basic processing of
73 * command line arguments is finished.
74 * It is guaranteed to be called before the GUI setup has started.
75 */
76 default void afterPrefStartupHook() {
77 // Do nothing
78 }
79
80 /**
81 * The startupHook will be called early, but after the GUI
82 * setup has started.
83 *
84 * Reason: On OSX we need to register some callbacks with the
85 * OS, so we'll receive events from the system menu.
86 * @param callback Java expiration callback, providing GUI feedback
87 * @since 12270 (signature)
88 */
89 default void startupHook(JavaExpirationCallback callback) {
90 // Do nothing
91 }
92
93 /**
94 * The openURL hook will be used to open an URL in the
95 * default web browser.
96 * @param url The URL to open
97 * @throws IOException if any I/O error occurs
98 */
99 void openUrl(String url) throws IOException;
100
101 /**
102 * The initSystemShortcuts hook will be called by the
103 * Shortcut class after the modifier groups have been read
104 * from the config, but before any shortcuts are read from
105 * it or registered from within the application.
106 *
107 * Please note that you are not allowed to register any
108 * shortuts from this hook, but only "systemCuts"!
109 *
110 * BTW: SystemCuts should be named "system:&lt;whatever&gt;",
111 * and it'd be best if sou'd recycle the names already used
112 * by the Windows and OSX hooks. Especially the later has
113 * really many of them.
114 *
115 * You should also register any and all shortcuts that the
116 * operation system handles itself to block JOSM from trying
117 * to use them---as that would just not work. Call setAutomatic
118 * on them to prevent the keyboard preferences from allowing the
119 * user to change them.
120 */
121 void initSystemShortcuts();
122
123 /**
124 * The makeTooltip hook will be called whenever a tooltip for
125 * a menu or button is created.
126 *
127 * Tooltips are usually not system dependent, unless the
128 * JVM is too dumb to provide correct names for all the keys.
129 *
130 * Some LAFs don't understand HTML, such as the OSX LAFs.
131 *
132 * @param name Tooltip text to display
133 * @param sc Shortcut associated (to display accelerator between parenthesis)
134 * @return Full tooltip text (name + accelerator)
135 */
136 default String makeTooltip(String name, Shortcut sc) {
137 StringBuilder result = new StringBuilder();
138 result.append("<html>").append(name);
139 if (sc != null && !sc.getKeyText().isEmpty()) {
140 result.append(" <font size='-2'>(")
141 .append(sc.getKeyText())
142 .append(")</font>");
143 }
144 return result.append("&nbsp;</html>").toString();
145 }
146
147 /**
148 * Returns the default LAF to be used on this platform to look almost as a native application.
149 * @return The default native LAF for this platform
150 */
151 String getDefaultStyle();
152
153 /**
154 * Determines if the platform allows full-screen.
155 * @return {@code true} if full screen is allowed, {@code false} otherwise
156 */
157 default boolean canFullscreen() {
158 return !GraphicsEnvironment.isHeadless() &&
159 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported();
160 }
161
162 /**
163 * Renames a file.
164 * @param from Source file
165 * @param to Target file
166 * @return {@code true} if the file has been renamed, {@code false} otherwise
167 */
168 default boolean rename(File from, File to) {
169 return from.renameTo(to);
170 }
171
172 /**
173 * Returns a detailed OS description (at least family + version).
174 * @return A detailed OS description.
175 * @since 5850
176 */
177 String getOSDescription();
178
179 /**
180 * Returns OS build number.
181 * @return OS build number.
182 * @since 12217
183 */
184 default String getOSBuildNumber() {
185 return "";
186 }
187
188 /**
189 * Setup system keystore to add JOSM HTTPS certificate (for remote control).
190 * @param entryAlias The entry alias to use
191 * @param trustedCert the JOSM certificate for localhost
192 * @return {@code true} if something has changed as a result of the call (certificate installation, etc.)
193 * @throws KeyStoreException in case of error
194 * @throws IOException in case of error
195 * @throws CertificateException in case of error
196 * @throws NoSuchAlgorithmException in case of error
197 * @since 7343
198 */
199 default boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
200 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
201 // TODO setup HTTPS certificate on Unix and OS X systems
202 return false;
203 }
204
205 /**
206 * Returns the {@code X509Certificate} matching the given certificate amendment information.
207 * @param certAmend certificate amendment
208 * @return the {@code X509Certificate} matching the given certificate amendment information, or {@code null}
209 * @throws KeyStoreException in case of error
210 * @throws IOException in case of error
211 * @throws CertificateException in case of error
212 * @throws NoSuchAlgorithmException in case of error
213 * @since 13450
214 */
215 default X509Certificate getX509Certificate(NativeCertAmend certAmend)
216 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
217 return null;
218 }
219
220 /**
221 * Executes a native command and returns the first line of standard output.
222 * @param command array containing the command to call and its arguments.
223 * @return first stripped line of standard output
224 * @throws IOException if an I/O error occurs
225 * @since 12217
226 */
227 default String exec(String... command) throws IOException {
228 Process p = Runtime.getRuntime().exec(command);
229 try (BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) {
230 return Utils.strip(input.readLine());
231 }
232 }
233
234 /**
235 * Returns the platform-dependent default cache directory.
236 * @return the platform-dependent default cache directory
237 * @since 7829
238 */
239 File getDefaultCacheDirectory();
240
241 /**
242 * Returns the platform-dependent default preferences directory.
243 * @return the platform-dependent default preferences directory
244 * @since 7831
245 */
246 File getDefaultPrefDirectory();
247
248 /**
249 * Returns the platform-dependent default user data directory.
250 * @return the platform-dependent default user data directory
251 * @since 7834
252 */
253 File getDefaultUserDataDirectory();
254
255 /**
256 * Returns the list of platform-dependent default datum shifting directories for the PROJ.4 library.
257 * @return the list of platform-dependent default datum shifting directories for the PROJ.4 library
258 * @since 11642
259 */
260 default List<File> getDefaultProj4NadshiftDirectories() {
261 return getPlatform().accept(NTV2Proj4DirGridShiftFileSource.getInstance());
262 }
263
264 /**
265 * Determines if the JVM is OpenJDK-based.
266 * @return {@code true} if {@code java.home} contains "openjdk", {@code false} otherwise
267 * @since 12219
268 */
269 default boolean isOpenJDK() {
270 String javaHome = Utils.getSystemProperty("java.home");
271 return javaHome != null && javaHome.contains("openjdk");
272 }
273
274 /**
275 * Returns extended modifier key used as the appropriate accelerator key for menu shortcuts.
276 * It is advised everywhere to use {@link Toolkit#getMenuShortcutKeyMask()} to get the cross-platform modifier, but:
277 * <ul>
278 * <li>it returns KeyEvent.CTRL_MASK instead of KeyEvent.CTRL_DOWN_MASK. We used the extended
279 * modifier for years, and Oracle recommends to use it instead, so it's best to keep it</li>
280 * <li>the method throws a HeadlessException ! So we would need to handle it for unit tests anyway</li>
281 * </ul>
282 * @return extended modifier key used as the appropriate accelerator key for menu shortcuts
283 * @since 12748 (as a replacement to {@code GuiHelper.getMenuShortcutKeyMaskEx()})
284 */
285 default int getMenuShortcutKeyMaskEx() {
286 // To remove when switching to Java 10+, and use Toolkit.getMenuShortcutKeyMaskEx instead
287 return KeyEvent.CTRL_DOWN_MASK;
288 }
289
290 /**
291 * Called when an outdated version of Java is detected at startup.
292 * @since 12270
293 */
294 @FunctionalInterface
295 interface JavaExpirationCallback {
296 /**
297 * Asks user to update its version of Java.
298 * @param updVersion target update version
299 * @param url download URL
300 * @param major true for a migration towards a major version of Java (8:9), false otherwise
301 * @param eolDate the EOL/expiration date
302 */
303 void askUpdateJava(String updVersion, String url, String eolDate, boolean major);
304 }
305
306 /**
307 * Checks if the running version of Java has expired, proposes to user to update it if needed.
308 * @param callback Java expiration callback
309 * @since 12270 (signature)
310 * @since 12219
311 */
312 default void checkExpiredJava(JavaExpirationCallback callback) {
313 Date expiration = Utils.getJavaExpirationDate();
314 if (expiration != null && expiration.before(new Date())) {
315 String version = Utils.getJavaLatestVersion();
316 callback.askUpdateJava(version != null ? version : "latest",
317 Config.getPref().get("java.update.url", "https://www.java.com/download"),
318 DateUtils.getDateFormat(DateFormat.MEDIUM).format(expiration), false);
319 }
320 }
321
322 /**
323 * Called when interfacing with native OS functions. Currently only used with macOS.
324 * The callback must perform all GUI-related tasks associated to an OS request.
325 * The non-GUI, platform-specific tasks, are usually performed by the {@code PlatformHook}.
326 * @since 12695
327 */
328 interface NativeOsCallback {
329 /**
330 * macOS: Called when JOSM is asked to open a list of files.
331 * @param files list of files to open
332 */
333 void openFiles(List<File> files);
334
335 /**
336 * macOS: Invoked when JOSM is asked to quit.
337 * @return {@code true} if JOSM has been closed, {@code false} if the user has cancelled the operation.
338 */
339 boolean handleQuitRequest();
340
341 /**
342 * macOS: Called when JOSM is asked to show it's about dialog.
343 */
344 void handleAbout();
345
346 /**
347 * macOS: Called when JOSM is asked to show it's preferences UI.
348 */
349 void handlePreferences();
350 }
351
352 /**
353 * Registers the native OS callback. Currently only needed for macOS.
354 * @param callback the native OS callback
355 * @since 12695
356 */
357 default void setNativeOsCallback(NativeOsCallback callback) {
358 // To be implemented if needed
359 }
360}
Note: See TracBrowser for help on using the repository browser.