1 /******************************************************************************* 2 * Copyright (c) 2000, 2007 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.internal.Compatibility; 14 15 import java.lang.all; 16 import java.io.BufferedInputStream; 17 import java.io.File; 18 import java.io.InputStream; 19 import java.io.FileInputStream; 20 import java.io.FileOutputStream; 21 import java.text.MessageFormat; 22 import java.util.MissingResourceException; 23 import java.util.ResourceBundle; 24 import java.util.zip.InflaterInputStream; 25 import java.util.zip.DeflaterOutputStream; 26 27 import org.eclipse.swt.SWT; 28 29 version(Tango){ 30 import Unicode = tango.text.Unicode; 31 import tango.sys.Process; 32 } else { // Phobos 33 } 34 35 /** 36 * This class is a placeholder for utility methods commonly 37 * used on J2SE platforms but not supported on some J2ME 38 * profiles. 39 * <p> 40 * It is part of our effort to provide support for both J2SE 41 * and J2ME platforms. 42 * </p> 43 * <p> 44 * IMPORTANT: some of the methods have been modified from their 45 * J2SE parents. Refer to the description of each method for 46 * specific changes. 47 * </p> 48 * <ul> 49 * <li>Exceptions thrown may differ since J2ME's set of 50 * exceptions is a subset of J2SE's one. 51 * </li> 52 * <li>The range of the mathematic functions is subject to 53 * change. 54 * </li> 55 * </ul> 56 */ 57 public final class Compatibility { 58 59 /** 60 * Returns the PI constant as a double. 61 */ 62 public static const real PI = Math.PI; 63 64 static const real toRadians = PI / 180; 65 66 /** 67 * Answers the length of the side adjacent to the given angle 68 * of a right triangle. In other words, it returns the integer 69 * conversion of length * cos (angle). 70 * <p> 71 * IMPORTANT: the j2me version has an additional restriction on 72 * the argument. length must be between -32767 and 32767 (inclusive). 73 * </p> 74 * 75 * @param angle the angle in degrees 76 * @param length the length of the triangle's hypotenuse 77 * @return the integer conversion of length * cos (angle) 78 */ 79 public static int cos(int angle, int length) { 80 return cast(int)(Math.cos(angle * toRadians) * length); 81 } 82 83 /** 84 * Answers the length of the side opposite to the given angle 85 * of a right triangle. In other words, it returns the integer 86 * conversion of length * sin (angle). 87 * <p> 88 * IMPORTANT: the j2me version has an additional restriction on 89 * the argument. length must be between -32767 and 32767 (inclusive). 90 * </p> 91 * 92 * @param angle the angle in degrees 93 * @param length the length of the triangle's hypotenuse 94 * @return the integer conversion of length * sin (angle) 95 */ 96 public static int sin(int angle, int length) { 97 return cast(int)(Math.sin(angle * toRadians) * length); 98 } 99 100 /** 101 * Answers the most negative (i.e. closest to negative infinity) 102 * integer value which is greater than the number obtained by dividing 103 * the first argument p by the second argument q. 104 * 105 * @param p numerator 106 * @param q denominator (must be different from zero) 107 * @return the ceiling of the rational number p / q. 108 */ 109 public static int ceil(int p, int q) { 110 return cast(int)Math.ceil(cast(float)p / q); 111 } 112 113 /** 114 * Answers whether the indicated file exists or not. 115 * 116 * @param parent the file's parent directory 117 * @param child the file's name 118 * @return true if the file exists 119 */ 120 public static bool fileExists(String parent, String child) { 121 scope f = new File(parent, child); 122 return f.exists(); 123 } 124 125 /** 126 * Answers the most positive (i.e. closest to positive infinity) 127 * integer value which is less than the number obtained by dividing 128 * the first argument p by the second argument q. 129 * 130 * @param p numerator 131 * @param q denominator (must be different from zero) 132 * @return the floor of the rational number p / q. 133 */ 134 public static int floor(int p, int q) { 135 return cast(int)Math.floor(cast(double)p / q); 136 } 137 138 /** 139 * Answers the result of rounding to the closest integer the number obtained 140 * by dividing the first argument p by the second argument q. 141 * <p> 142 * IMPORTANT: the j2me version has an additional restriction on 143 * the arguments. p must be within the range 0 - 32767 (inclusive). 144 * q must be within the range 1 - 32767 (inclusive). 145 * </p> 146 * 147 * @param p numerator 148 * @param q denominator (must be different from zero) 149 * @return the closest integer to the rational number p / q 150 */ 151 public static int round(int p, int q) { 152 return cast(int)Math.round(cast(float)p / q); 153 } 154 155 /** 156 * Returns 2 raised to the power of the argument. 157 * 158 * @param n an int value between 0 and 30 (inclusive) 159 * @return 2 raised to the power of the argument 160 * 161 * @exception IllegalArgumentException <ul> 162 * <li>ERROR_INVALID_RANGE - if the argument is not between 0 and 30 (inclusive)</li> 163 * </ul> 164 */ 165 public static int pow2(int n) { 166 if (n >= 1 && n <= 30) 167 return 2 << (n - 1); 168 else if (n != 0) { 169 SWT.error(SWT.ERROR_INVALID_RANGE); 170 } 171 return 1; 172 } 173 174 /** 175 * Create an DeflaterOutputStream if such things are supported. 176 * 177 * @param stream the output stream 178 * @return a deflater stream or <code>null</code> 179 * @exception IOException 180 * 181 * @since 3.4 182 */ 183 public static OutputStream newDeflaterOutputStream(OutputStream stream) { 184 return new DeflaterOutputStream(stream); 185 } 186 187 /** 188 * Open a file if such things are supported. 189 * 190 * @param filename the name of the file to open 191 * @return a stream on the file if it could be opened. 192 * @exception IOException 193 */ 194 public static InputStream newFileInputStream(String filename) { 195 return new FileInputStream(filename); 196 } 197 198 /** 199 * Open a file if such things are supported. 200 * 201 * @param filename the name of the file to open 202 * @return a stream on the file if it could be opened. 203 * @exception IOException 204 */ 205 public static OutputStream newFileOutputStream(String filename) { 206 return new FileOutputStream(filename); 207 } 208 209 /** 210 * Create an InflaterInputStream if such things are supported. 211 * 212 * @param stream the input stream 213 * @return a inflater stream or <code>null</code> 214 * @exception IOException 215 * 216 * @since 3.3 217 */ 218 public static InflaterInputStream newInflaterInputStream(InputStream stream) { 219 return new InflaterInputStream(stream); 220 } 221 222 /** 223 * Answers whether the character is a letter. 224 * 225 * @param c the character 226 * @return true when the character is a letter 227 */ 228 public static bool isLetter(dchar c) { 229 return Character.isLetter(c); 230 } 231 232 /** 233 * Answers whether the character is a letter or a digit. 234 * 235 * @param c the character 236 * @return true when the character is a letter or a digit 237 */ 238 public static bool isLetterOrDigit(dchar c) { 239 return Character.isLetterOrDigit(c); 240 } 241 242 /** 243 * Answers whether the character is a Unicode space character. 244 * 245 * @param c the character 246 * @return true when the character is a Unicode space character 247 */ 248 public static bool isSpaceChar(dchar c) { 249 return Character.isSpace(c); 250 } 251 252 /** 253 * Answers whether the character is a whitespace character. 254 * 255 * @param c the character to test 256 * @return true if the character is whitespace 257 */ 258 public static bool isWhitespace(dchar c) { 259 return Character.isWhitespace(c); 260 } 261 262 /** 263 * Execute a program in a separate platform process if the 264 * underlying platform support this. 265 * <p> 266 * The new process inherits the environment of the caller. 267 * </p> 268 * 269 * @param prog the name of the program to execute 270 * 271 * @exception ProcessException 272 * if the program cannot be executed 273 */ 274 public static void exec(String prog) { 275 version(Tango){ 276 auto proc = new Process( prog ); 277 proc.execute; 278 } else { // Phobos 279 implMissingInPhobos(); 280 } 281 } 282 283 /** 284 * Execute progArray[0] in a separate platform process if the 285 * underlying platform support this. 286 * <p> 287 * The new process inherits the environment of the caller. 288 * <p> 289 * 290 * @param progArray array containing the program to execute and its arguments 291 * 292 * @exception ProcessException 293 * if the program cannot be executed 294 */ 295 public static void exec(String[] progArray) { 296 version(Tango){ 297 auto proc = new Process( progArray ); 298 proc.execute; 299 } else { // Phobos 300 implMissingInPhobos(); 301 } 302 } 303 304 static const ImportData[] SWTMessagesBundleData = [ 305 getImportData!( "org.eclipse.swt.internal.SWTMessages.properties" ), 306 getImportData!( "org.eclipse.swt.internal.SWTMessages_ar.properties" ), 307 getImportData!( "org.eclipse.swt.internal.SWTMessages_cs.properties" ), 308 getImportData!( "org.eclipse.swt.internal.SWTMessages_da.properties" ), 309 getImportData!( "org.eclipse.swt.internal.SWTMessages_de.properties" ), 310 getImportData!( "org.eclipse.swt.internal.SWTMessages_el.properties" ), 311 getImportData!( "org.eclipse.swt.internal.SWTMessages_es.properties" ), 312 getImportData!( "org.eclipse.swt.internal.SWTMessages_fi.properties" ), 313 getImportData!( "org.eclipse.swt.internal.SWTMessages_fr.properties" ), 314 getImportData!( "org.eclipse.swt.internal.SWTMessages_hu.properties" ), 315 getImportData!( "org.eclipse.swt.internal.SWTMessages_it.properties" ), 316 getImportData!( "org.eclipse.swt.internal.SWTMessages_iw.properties" ), 317 getImportData!( "org.eclipse.swt.internal.SWTMessages_ja.properties" ), 318 getImportData!( "org.eclipse.swt.internal.SWTMessages_ko.properties" ), 319 getImportData!( "org.eclipse.swt.internal.SWTMessages_nl.properties" ), 320 getImportData!( "org.eclipse.swt.internal.SWTMessages_no.properties" ), 321 getImportData!( "org.eclipse.swt.internal.SWTMessages_pl.properties" ), 322 getImportData!( "org.eclipse.swt.internal.SWTMessages_pt_BR.properties" ), 323 getImportData!( "org.eclipse.swt.internal.SWTMessages_pt.properties" ), 324 getImportData!( "org.eclipse.swt.internal.SWTMessages_ru.properties" ), 325 getImportData!( "org.eclipse.swt.internal.SWTMessages_sv.properties" ), 326 getImportData!( "org.eclipse.swt.internal.SWTMessages_tr.properties" ), 327 getImportData!( "org.eclipse.swt.internal.SWTMessages_zh_HK.properties" ), 328 getImportData!( "org.eclipse.swt.internal.SWTMessages_zh.properties" ), 329 getImportData!( "org.eclipse.swt.internal.SWTMessages_zh_TW.properties" ) 330 ]; 331 332 private static ResourceBundle msgs = null; 333 334 /** 335 * Returns the NLS'ed message for the given argument. This is only being 336 * called from SWT. 337 * 338 * @param key the key to look up 339 * @return the message for the given key 340 * 341 * @see SWT#getMessage(String) 342 */ 343 public static String getMessage(String key) { 344 String answer = key; 345 346 if (key is null) { 347 SWT.error (SWT.ERROR_NULL_ARGUMENT); 348 } 349 if (msgs is null) { 350 try { 351 msgs = ResourceBundle.getBundle(SWTMessagesBundleData); //$NON-NLS-1$ 352 } catch (MissingResourceException ex) { 353 answer = key ~ " (no resource bundle)"; //$NON-NLS-1$ 354 } 355 } 356 if (msgs !is null) { 357 try { 358 answer = msgs.getString(key); 359 } catch (MissingResourceException ex2) {} 360 } 361 return answer; 362 } 363 364 public static String getMessage(String key, Object[] args) { 365 String answer = key; 366 367 if (key is null || args is null) { 368 SWT.error (SWT.ERROR_NULL_ARGUMENT); 369 } 370 if (msgs is null) { 371 try { 372 msgs = ResourceBundle.getBundle(SWTMessagesBundleData); //$NON-NLS-1$ 373 } catch (MissingResourceException ex) { 374 answer = key ~ " (no resource bundle)"; //$NON-NLS-1$ 375 } 376 } 377 if (msgs !is null) { 378 try { 379 String frmt = msgs.getString(key); 380 switch( args.length ){ 381 case 0: answer = Format(frmt); break; 382 case 1: answer = Format(frmt, args[0]); break; 383 case 2: answer = Format(frmt, args[0], args[1]); break; 384 case 3: answer = Format(frmt, args[0], args[1], args[2]); break; 385 case 4: answer = Format(frmt, args[0], args[1], args[2], args[3]); break; 386 case 5: answer = Format(frmt, args[0], args[1], args[2], args[3], args[4]); break; 387 default: 388 implMissing(__FILE__, __LINE__ ); 389 } 390 } catch (MissingResourceException ex2) {} 391 } 392 return answer; 393 } 394 395 396 /** 397 * Interrupt the current thread. 398 * <p> 399 * Note that this is not available on CLDC. 400 * </p> 401 */ 402 public static void interrupt() { 403 //PORTING_FIXME: how to implement?? 404 //Thread.currentThread().interrupt(); 405 } 406 407 /** 408 * Compares two instances of class String ignoring the case of the 409 * characters and answers if they are equal. 410 * 411 * @param s1 string 412 * @param s2 string 413 * @return true if the two instances of class String are equal 414 */ 415 public static bool equalsIgnoreCase(in char[] s1, in char[] s2) { 416 return .equalsIgnoreCase(s1, s2); 417 } 418 419 }