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 }