1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.kit.editor; 33 34 import com.oracle.javafx.scenebuilder.kit.util.Deprecation; 35 import java.io.File; 36 import java.io.IOException; 37 import java.util.ArrayList; 38 import java.util.List; 39 import java.util.Locale; 40 import javafx.scene.input.MouseEvent; 41 42 /** 43 * This class contains static methods that depends on the platform. 44 * 45 * @treatAsPrivate 46 */ 47 public class EditorPlatform { 48 49 private static final String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); //NOI18N 50 51 /** 52 * True if current platform is running Linux. 53 */ 54 public static final boolean IS_LINUX = osName.contains("linux"); //NOI18N 55 56 /** 57 * True if current platform is running Mac OS X. 58 */ 59 public static final boolean IS_MAC = osName.contains("mac"); //NOI18N 60 61 /** 62 * True if current platform is running Windows. 63 */ 64 public static final boolean IS_WINDOWS = osName.contains("windows"); //NOI18N 65 66 /** 67 * This URL is where you go when the user takes Scene Builder Help action (shortcut F1) 68 */ 69 public static final String DOCUMENTATION_URL = "https://docs.oracle.com/javafx/index.html"; //NOI18N 70 71 /** 72 * Javadoc home (for Inspector and CSS Analyzer properties) 73 */ 74 public final static String JAVADOC_HOME = "https://docs.oracle.com/javase/8/javafx/api/"; //NOI18N 75 76 77 /** 78 * Themes supported by Scene Builder Kit. 79 */ 80 public enum Theme { 81 82 MODENA, 83 MODENA_TOUCH, 84 MODENA_HIGH_CONTRAST_BLACK_ON_WHITE, 85 MODENA_HIGH_CONTRAST_WHITE_ON_BLACK, 86 MODENA_HIGH_CONTRAST_YELLOW_ON_BLACK, 87 MODENA_TOUCH_HIGH_CONTRAST_BLACK_ON_WHITE, 88 MODENA_TOUCH_HIGH_CONTRAST_WHITE_ON_BLACK, 89 MODENA_TOUCH_HIGH_CONTRAST_YELLOW_ON_BLACK, 90 CASPIAN, 91 CASPIAN_HIGH_CONTRAST, 92 CASPIAN_EMBEDDED, 93 CASPIAN_EMBEDDED_HIGH_CONTRAST, 94 CASPIAN_EMBEDDED_QVGA, 95 CASPIAN_EMBEDDED_QVGA_HIGH_CONTRAST 96 } 97 98 /** 99 * Returns the url string for locating the specified stylesheet. 100 * SB uses a set of CSS files aggregating several @import statements (see DTL-6799). 101 * 102 * @param theme theme for which string should be computed 103 * @return string for locating the specified stylesheet. 104 */ 105 public static String getThemeStylesheetURL(Theme theme) { 106 final String result; 107 108 switch (theme) { 109 default: 110 result = null; 111 break; 112 case MODENA: 113 result = Deprecation.MODENA_STYLESHEET; 114 break; 115 case MODENA_TOUCH: 116 result = Deprecation.MODENA_TOUCH_STYLESHEET; 117 break; 118 case MODENA_HIGH_CONTRAST_BLACK_ON_WHITE: 119 result = Deprecation.MODENA_HIGHCONTRAST_BLACKONWHITE_STYLESHEET; 120 break; 121 case MODENA_HIGH_CONTRAST_WHITE_ON_BLACK: 122 result = Deprecation.MODENA_HIGHCONTRAST_WHITEONBLACK_STYLESHEET; 123 break; 124 case MODENA_HIGH_CONTRAST_YELLOW_ON_BLACK: 125 result = Deprecation.MODENA_HIGHCONTRAST_YELLOWONBLACK_STYLESHEET; 126 break; 127 case MODENA_TOUCH_HIGH_CONTRAST_BLACK_ON_WHITE: 128 result = Deprecation.MODENA_TOUCH_HIGHCONTRAST_BLACKONWHITE_STYLESHEET; 129 break; 130 case MODENA_TOUCH_HIGH_CONTRAST_WHITE_ON_BLACK: 131 result = Deprecation.MODENA_TOUCH_HIGHCONTRAST_WHITEONBLACK_STYLESHEET; 132 break; 133 case MODENA_TOUCH_HIGH_CONTRAST_YELLOW_ON_BLACK: 134 result = Deprecation.MODENA_TOUCH_HIGHCONTRAST_YELLOWONBLACK_STYLESHEET; 135 break; 136 case CASPIAN: 137 result = Deprecation.CASPIAN_STYLESHEET; 138 break; 139 case CASPIAN_HIGH_CONTRAST: 140 result = Deprecation.CASPIAN_HIGHCONTRAST_STYLESHEET; 141 break; 142 case CASPIAN_EMBEDDED: 143 result = Deprecation.CASPIAN_EMBEDDED_STYLESHEET; 144 break; 145 case CASPIAN_EMBEDDED_HIGH_CONTRAST: 146 result = Deprecation.CASPIAN_EMBEDDED_HIGHCONTRAST_STYLESHEET; 147 break; 148 case CASPIAN_EMBEDDED_QVGA: 149 result = Deprecation.CASPIAN_EMBEDDED_QVGA_STYLESHEET; 150 break; 151 case CASPIAN_EMBEDDED_QVGA_HIGH_CONTRAST: 152 result = Deprecation.CASPIAN_EMBEDDED_QVGA_HIGHCONTRAST_STYLESHEET; 153 break; 154 } 155 156 if (!theme.equals(Theme.MODENA)) { 157 assert result != null : "Missing logic for " + theme; 158 } 159 160 return result; 161 } 162 163 public static String getPlatformThemeStylesheetURL() { 164 // Return USER_AGENT css, which is Modena for fx 8.0 165 return Deprecation.MODENA_STYLESHEET; 166 } 167 168 public static boolean isModena(Theme theme) { 169 return theme.toString().startsWith("MODENA"); 170 } 171 172 public static boolean isModenaBlackonwhite(Theme theme) { 173 return isModena(theme) 174 && theme.toString().contains("BLACK_ON_WHITE"); 175 } 176 177 public static boolean isModenaWhiteonblack(Theme theme) { 178 return isModena(theme) 179 && theme.toString().contains("WHITE_ON_BLACK"); 180 } 181 182 public static boolean isModenaYellowonblack(Theme theme) { 183 return isModena(theme) 184 && theme.toString().contains("YELLOW_ON_BLACK"); 185 } 186 187 public static boolean isModenaHighContrast(Theme theme) { 188 return isModena(theme) 189 && theme.toString().contains("HIGH_CONTRAST"); 190 } 191 192 public static boolean isModenaTouch(Theme theme) { 193 return isModena(theme) 194 && theme.toString().contains("TOUCH"); 195 } 196 197 public static boolean isModenaTouchHighContrast(Theme theme) { 198 return isModena(theme) 199 && theme.toString().contains("HIGH_CONTRAST") 200 && theme.toString().contains("TOUCH"); 201 } 202 203 public static boolean isCaspian(Theme theme) { 204 return theme.toString().startsWith("CASPIAN"); 205 } 206 207 /** 208 * Requests the underlying platform to open a given file. On Linux, it runs 209 * 'xdg-open'. On Mac, it runs 'open'. On Windows, it runs 'cmd /c start'. 210 * 211 * @param path path for the file to be opened 212 * @throws IOException if an error occurs 213 */ 214 public static void open(String path) throws IOException { 215 List<String> args = new ArrayList<>(); 216 if (EditorPlatform.IS_MAC) { 217 args.add("open"); //NOI18N 218 args.add(path); 219 } else if (EditorPlatform.IS_WINDOWS) { 220 args.add("cmd"); //NOI18N 221 args.add("/c"); //NOI18N 222 args.add("start"); //NOI18N 223 224 if (path.contains(" ")) { //NOI18N 225 args.add("\"html\""); //NOI18N 226 } 227 228 args.add(path); 229 } else if (EditorPlatform.IS_LINUX) { 230 // xdg-open does fine on Ubuntu, which is a Debian. 231 // I've no idea how it does with other Linux flavors. 232 args.add("xdg-open"); //NOI18N 233 args.add(path); 234 } 235 236 if (!args.isEmpty()) { 237 executeDaemon(args, null); 238 } 239 } 240 241 /** 242 * Requests the underlying platform to "reveal" the specified folder. On 243 * Linux, it runs 'nautilus'. On Mac, it runs 'open'. On Windows, it runs 244 * 'explorer /select'. 245 * 246 * @param filePath path for the folder to be revealed 247 * @throws IOException if an error occurs 248 */ 249 public static void revealInFileBrowser(File filePath) throws IOException { 250 List<String> args = new ArrayList<>(); 251 String path = filePath.toURI().toURL().toExternalForm(); 252 if (EditorPlatform.IS_MAC) { 253 args.add("open"); //NOI18N 254 args.add("-R"); //NOI18N 255 args.add(path); 256 } else if (EditorPlatform.IS_WINDOWS) { 257 args.add("explorer"); //NOI18N 258 args.add("/select," + path); //NOI18N 259 } else if (EditorPlatform.IS_LINUX) { 260 // nautilus does fine on Ubuntu, which is a Debian. 261 // I've no idea how it does with other Linux flavors. 262 args.add("nautilus"); //NOI18N 263 // The nautilus that comes with Ubuntu up to 11.04 included doesn't 264 // take a file path as parameter (you get an error popup), you must 265 // provide a dir path. 266 // Starting with Ubuntu 11.10 (the first based on kernel 3.x) a 267 // file path is well managed. 268 int osVersionNumerical = Integer.parseInt(System.getProperty("os.version").substring(0, 1)); //NOI18N 269 if (osVersionNumerical < 3) { 270 // Case Ubuntu 10.04 to 11.04: What you provide to nautilus is 271 // the name of the directory containing the file you want to see 272 // listed. See DTL-5384. 273 path = filePath.getAbsoluteFile().getParent(); 274 if (path == null) { 275 path = "."; //NOI18N 276 } 277 } 278 args.add(path); 279 } else { 280 // Not Supported 281 } 282 283 if (!args.isEmpty()) { 284 executeDaemon(args, null); 285 } 286 } 287 288 /** 289 * Returns true if the modifier key for continuous selection is down. 290 * 291 * @param e mouse event to check (never null) 292 * @return true if the modifier key for continuous selection is down. 293 */ 294 public static boolean isContinuousSelectKeyDown(MouseEvent e) { 295 return e.isShiftDown(); 296 } 297 298 /** 299 * Returns true if the modifier key for non-continuous selection is down. 300 * 301 * @param e mouse event to check (never null). 302 * @return true if the modifier key for non-continuous selection is down. 303 */ 304 public static boolean isNonContinousSelectKeyDown(MouseEvent e) { 305 return IS_MAC ? e.isMetaDown(): e.isControlDown(); 306 } 307 308 /** 309 * Returns true if the jvm is running with assertions enabled. 310 * 311 * @return true if the jvm is running with assertions enabled. 312 */ 313 public static boolean isAssertionEnabled() { 314 return EditorPlatform.class.desiredAssertionStatus(); 315 } 316 317 /* 318 * Private 319 */ 320 private static void executeDaemon(List<String> cmd, File wDir) throws IOException { 321 try { 322 ProcessBuilder builder = new ProcessBuilder(cmd); 323 builder = builder.directory(wDir); 324 builder.start(); 325 } catch (RuntimeException ex) { 326 throw new IOException(ex); 327 } 328 } 329 330 }