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

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

fix #16243 - load files via Windows shortcut files (*.lnk)

  • Property svn:eol-style set to native
File size: 13.3 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
361 /**
362 * Resolves a file link to its destination file.
363 * @param file file (link or regular file)
364 * @return destination file in case of a file link, file if regular
365 * @since 13691
366 */
367 default File resolveFileLink(File file) {
368 // Override if needed
369 return file;
370 }
371}
Note: See TracBrowser for help on using the repository browser.