001 /*
002 * $Id: Utilities.java 3100 2008-10-14 22:33:10Z rah003 $
003 *
004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021 package org.jdesktop.swingx.util;
022
023
024 import java.awt.Component;
025 import java.awt.GraphicsConfiguration;
026 import java.awt.GraphicsEnvironment;
027 import java.awt.Insets;
028 import java.awt.KeyboardFocusManager;
029 import java.awt.Rectangle;
030 import java.awt.Toolkit;
031 import java.awt.Window;
032 import java.awt.event.KeyEvent;
033 import java.lang.ref.Reference;
034 import java.lang.ref.SoftReference;
035 import java.lang.reflect.Field;
036 import java.lang.reflect.Modifier;
037 import java.text.BreakIterator;
038 import java.util.ArrayList;
039 import java.util.HashMap;
040 import java.util.Locale;
041 import java.util.NoSuchElementException;
042 import java.util.StringTokenizer;
043 import java.util.logging.Level;
044 import java.util.logging.Logger;
045
046 import javax.swing.KeyStroke;
047 import javax.swing.SwingUtilities;
048
049 /**
050 * Contribution from NetBeans: Issue #319-swingx. <p>
051 *
052 * PENDING: need to reconcile with OS, JVM... added as-is
053 * because needed the shortcut handling to fix #
054 *
055 * @author apple
056 */
057 public class Utilities {
058 private Utilities() {
059 }
060
061 private static final int CTRL_WILDCARD_MASK = 32768;
062 private static final int ALT_WILDCARD_MASK = CTRL_WILDCARD_MASK * 2;
063
064 /** Operating system is Windows NT. */
065 public static final int OS_WINNT = 1 << 0;
066
067 /** Operating system is Windows 95. */
068 public static final int OS_WIN95 = OS_WINNT << 1;
069
070 /** Operating system is Windows 98. */
071 public static final int OS_WIN98 = OS_WIN95 << 1;
072
073 /** Operating system is Solaris. */
074 public static final int OS_SOLARIS = OS_WIN98 << 1;
075
076 /** Operating system is Linux. */
077 public static final int OS_LINUX = OS_SOLARIS << 1;
078
079 /** Operating system is HP-UX. */
080 public static final int OS_HP = OS_LINUX << 1;
081
082 /** Operating system is IBM AIX. */
083 public static final int OS_AIX = OS_HP << 1;
084
085 /** Operating system is SGI IRIX. */
086 public static final int OS_IRIX = OS_AIX << 1;
087
088 /** Operating system is Sun OS. */
089 public static final int OS_SUNOS = OS_IRIX << 1;
090
091 /** Operating system is Compaq TRU64 Unix */
092 public static final int OS_TRU64 = OS_SUNOS << 1;
093
094 /** Operating system is OS/2. */
095 public static final int OS_OS2 = OS_TRU64 << 2;
096
097 /** Operating system is Mac. */
098 public static final int OS_MAC = OS_OS2 << 1;
099
100 /** Operating system is Windows 2000. */
101 public static final int OS_WIN2000 = OS_MAC << 1;
102
103 /** Operating system is Compaq OpenVMS */
104 public static final int OS_VMS = OS_WIN2000 << 1;
105
106 /**
107 *Operating system is one of the Windows variants but we don't know which
108 *one it is
109 */
110 public static final int OS_WIN_OTHER = OS_VMS << 1;
111
112 /** Operating system is unknown. */
113 public static final int OS_OTHER = OS_WIN_OTHER << 1;
114
115 /** Operating system is FreeBSD
116 * @since 4.50
117 */
118 public static final int OS_FREEBSD = OS_OTHER << 1;
119
120 /** A mask for Windows platforms. */
121 public static final int OS_WINDOWS_MASK = OS_WINNT | OS_WIN95 | OS_WIN98 | OS_WIN2000 | OS_WIN_OTHER;
122
123 /** A mask for Unix platforms. */
124 public static final int OS_UNIX_MASK = OS_SOLARIS | OS_LINUX | OS_HP | OS_AIX | OS_IRIX | OS_SUNOS | OS_TRU64 |
125 OS_MAC | OS_FREEBSD;
126
127 /** A height of the windows's taskbar */
128 public static final int TYPICAL_WINDOWS_TASKBAR_HEIGHT = 27;
129
130 /** A height of the Mac OS X's menu */
131 private static final int TYPICAL_MACOSX_MENU_HEIGHT = 24;
132
133 private static int operatingSystem = -1;
134
135 /** reference to map that maps allowed key names to their values (String, Integer)
136 and reference to map for mapping of values to their names */
137 private static Reference<Object> namesAndValues;
138
139 /** Get the operating system on which NetBeans is running.
140 * @return one of the <code>OS_*</code> constants (such as {@link #OS_WINNT})
141 */
142 public static int getOperatingSystem() {
143 if (operatingSystem == -1) {
144 String osName = System.getProperty("os.name");
145
146 if ("Windows NT".equals(osName)) { // NOI18N
147 operatingSystem = OS_WINNT;
148 } else if ("Windows 95".equals(osName)) { // NOI18N
149 operatingSystem = OS_WIN95;
150 } else if ("Windows 98".equals(osName)) { // NOI18N
151 operatingSystem = OS_WIN98;
152 } else if ("Windows 2000".equals(osName)) { // NOI18N
153 operatingSystem = OS_WIN2000;
154 } else if (osName.startsWith("Windows ")) { // NOI18N
155 operatingSystem = OS_WIN_OTHER;
156 } else if ("Solaris".equals(osName)) { // NOI18N
157 operatingSystem = OS_SOLARIS;
158 } else if (osName.startsWith("SunOS")) { // NOI18N
159 operatingSystem = OS_SOLARIS;
160 }
161 // JDK 1.4 b2 defines os.name for me as "Redhat Linux" -jglick
162 else if (osName.endsWith("Linux")) { // NOI18N
163 operatingSystem = OS_LINUX;
164 } else if ("HP-UX".equals(osName)) { // NOI18N
165 operatingSystem = OS_HP;
166 } else if ("AIX".equals(osName)) { // NOI18N
167 operatingSystem = OS_AIX;
168 } else if ("Irix".equals(osName)) { // NOI18N
169 operatingSystem = OS_IRIX;
170 } else if ("SunOS".equals(osName)) { // NOI18N
171 operatingSystem = OS_SUNOS;
172 } else if ("Digital UNIX".equals(osName)) { // NOI18N
173 operatingSystem = OS_TRU64;
174 } else if ("OS/2".equals(osName)) { // NOI18N
175 operatingSystem = OS_OS2;
176 } else if ("OpenVMS".equals(osName)) { // NOI18N
177 operatingSystem = OS_VMS;
178 } else if (osName.equals("Mac OS X")) { // NOI18N
179 operatingSystem = OS_MAC;
180 } else if (osName.startsWith("Darwin")) { // NOI18N
181 operatingSystem = OS_MAC;
182 } else if (osName.toLowerCase(Locale.US).startsWith("freebsd")) { // NOI18N
183 operatingSystem = OS_FREEBSD;
184 } else {
185 operatingSystem = OS_OTHER;
186 }
187 }
188 return operatingSystem;
189 }
190
191 /** Test whether NetBeans is running on some variant of Windows.
192 * @return <code>true</code> if Windows, <code>false</code> if some other manner of operating system
193 */
194 public static boolean isWindows() {
195 return (getOperatingSystem() & OS_WINDOWS_MASK) != 0;
196 }
197
198 /** Test whether NetBeans is running on some variant of Unix.
199 * Linux is included as well as the commercial vendors, and Mac OS X.
200 * @return <code>true</code> some sort of Unix, <code>false</code> if some other manner of operating system
201 */
202 public static boolean isUnix() {
203 return (getOperatingSystem() & OS_UNIX_MASK) != 0;
204 }
205
206 /** Test whether the operating system supports icons on frames (windows).
207 * @return <code>true</code> if it does <em>not</em>
208 *
209 */
210 public static boolean isLargeFrameIcons() {
211 return (getOperatingSystem() == OS_SOLARIS) || (getOperatingSystem() == OS_HP);
212 }
213
214 /**
215 * Finds out the monitor where the user currently has the input focus.
216 * This method is usually used to help the client code to figure out on
217 * which monitor it should place newly created windows/frames/dialogs.
218 *
219 * @return the GraphicsConfiguration of the monitor which currently has the
220 * input focus
221 */
222 private static GraphicsConfiguration getCurrentGraphicsConfiguration() {
223 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
224 if (focusOwner != null) {
225 Window w = SwingUtilities.getWindowAncestor(focusOwner);
226 if (w != null) {
227 return w.getGraphicsConfiguration();
228 }
229 }
230
231 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
232 }
233
234 /**
235 * Returns the usable area of the screen where applications can place its
236 * windows. The method subtracts from the screen the area of taskbars,
237 * system menus and the like. The screen this method applies to is the one
238 * which is considered current, ussually the one where the current input
239 * focus is.
240 *
241 * @return the rectangle of the screen where one can place windows
242 *
243 * @since 2.5
244 */
245 public static Rectangle getUsableScreenBounds() {
246 return getUsableScreenBounds(getCurrentGraphicsConfiguration());
247 }
248
249 /**
250 * Returns the usable area of the screen where applications can place its
251 * windows. The method subtracts from the screen the area of taskbars,
252 * system menus and the like.
253 *
254 * @param gconf the GraphicsConfiguration of the monitor
255 * @return the rectangle of the screen where one can place windows
256 *
257 * @since 2.5
258 */
259 public static Rectangle getUsableScreenBounds(GraphicsConfiguration gconf) {
260 if (gconf == null) {
261 gconf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
262 }
263
264 Rectangle bounds = new Rectangle(gconf.getBounds());
265
266 String str;
267
268 str = System.getProperty("netbeans.screen.insets"); // NOI18N
269
270 if (str != null) {
271 StringTokenizer st = new StringTokenizer(str, ", "); // NOI18N
272
273 if (st.countTokens() == 4) {
274 try {
275 bounds.y = Integer.parseInt(st.nextToken());
276 bounds.x = Integer.parseInt(st.nextToken());
277 bounds.height -= (bounds.y + Integer.parseInt(st.nextToken()));
278 bounds.width -= (bounds.x + Integer.parseInt(st.nextToken()));
279 } catch (NumberFormatException ex) {
280 Logger.getAnonymousLogger().log(Level.WARNING, null, ex);
281 }
282 }
283
284 return bounds;
285 }
286
287 str = System.getProperty("netbeans.taskbar.height"); // NOI18N
288
289 if (str != null) {
290 bounds.height -= Integer.getInteger(str, 0).intValue();
291
292 return bounds;
293 }
294
295 try {
296 Toolkit toolkit = Toolkit.getDefaultToolkit();
297 Insets insets = toolkit.getScreenInsets(gconf);
298 bounds.y += insets.top;
299 bounds.x += insets.left;
300 bounds.height -= (insets.top + insets.bottom);
301 bounds.width -= (insets.left + insets.right);
302 } catch (Exception ex) {
303 Logger.getAnonymousLogger().log(Level.WARNING, null, ex);
304 }
305
306 return bounds;
307 }
308
309
310 /** Initialization of the names and values
311 * @return array of two hashmaps first maps
312 * allowed key names to their values (String, Integer)
313 * and second
314 * hashtable for mapping of values to their names (Integer, String)
315 */
316 private static synchronized HashMap[] initNameAndValues() {
317 if (namesAndValues != null) {
318 HashMap[] arr = (HashMap[]) namesAndValues.get();
319
320 if (arr != null) {
321 return arr;
322 }
323 }
324
325 Field[] fields;
326 // JW - fix Issue #353-swingx: play nicer inside sandbox.
327 try {
328 fields = KeyEvent.class.getDeclaredFields();
329 // fields = KeyEvent.class.getFields();
330 } catch (SecurityException e) {
331 // JW: need to do better? What are the use-cases where we don't have
332 // any access to the fields?
333 fields = new Field[0];
334 }
335
336 HashMap<String,Integer> names = new HashMap<String,Integer>(((fields.length * 4) / 3) + 5, 0.75f);
337 HashMap<Integer,String> values = new HashMap<Integer,String>(((fields.length * 4) / 3) + 5, 0.75f);
338
339 for (int i = 0; i < fields.length; i++) {
340 if (Modifier.isStatic(fields[i].getModifiers())) {
341 String name = fields[i].getName();
342
343 if (name.startsWith("VK_")) { // NOI18N
344
345 // exclude VK
346 name = name.substring(3);
347
348 try {
349 int numb = fields[i].getInt(null);
350 Integer value = new Integer(numb);
351 names.put(name, value);
352 values.put(value, name);
353 } catch (IllegalArgumentException ex) {
354 } catch (IllegalAccessException ex) {
355 }
356 }
357 }
358 }
359
360 if (names.get("CONTEXT_MENU") == null) { // NOI18N
361
362 Integer n = new Integer(0x20C);
363 names.put("CONTEXT_MENU", n); // NOI18N
364 values.put(n, "CONTEXT_MENU"); // NOI18N
365
366 n = new Integer(0x20D);
367 names.put("WINDOWS", n); // NOI18N
368 values.put(n, "WINDOWS"); // NOI18N
369 }
370
371 HashMap[] arr = { names, values };
372
373 namesAndValues = new SoftReference<Object>(arr);
374
375 return arr;
376 }
377
378 /** Converts a Swing key stroke descriptor to a familiar Emacs-like name.
379 * @param stroke key description
380 * @return name of the key (e.g. <code>CS-F1</code> for control-shift-function key one)
381 * @see #stringToKey
382 */
383 public static String keyToString(KeyStroke stroke) {
384 StringBuffer sb = new StringBuffer();
385
386 // add modifiers that must be pressed
387 if (addModifiers(sb, stroke.getModifiers())) {
388 sb.append('-');
389 }
390
391 HashMap[] namesAndValues = initNameAndValues();
392
393 String c = (String) namesAndValues[1].get(new Integer(stroke.getKeyCode()));
394
395 if (c == null) {
396 sb.append(stroke.getKeyChar());
397 } else {
398 sb.append(c);
399 }
400
401 return sb.toString();
402 }
403
404 /** Construct a new key description from a given universal string
405 * description.
406 * Provides mapping between Emacs-like textual key descriptions and the
407 * <code>KeyStroke</code> object used in Swing.
408 * <P>
409 * This format has following form:
410 * <P><code>[C][A][S][M]-<em>identifier</em></code>
411 * <p>Where:
412 * <UL>
413 * <LI> <code>C</code> stands for the Control key
414 * <LI> <code>A</code> stands for the Alt key
415 * <LI> <code>S</code> stands for the Shift key
416 * <LI> <code>M</code> stands for the Meta key
417 * </UL>
418 * The format also supports two wildcard codes, to support differences in
419 * platforms. These are the preferred choices for registering keystrokes,
420 * since platform conflicts will automatically be handled:
421 * <UL>
422 * <LI> <code>D</code> stands for the default menu accelerator - the Control
423 * key on most platforms, the Command (meta) key on Macintosh</LI>
424 * <LI> <code>O</code> stands for the alternate accelerator - the Alt key on
425 * most platforms, the Ctrl key on Macintosh (Macintosh uses Alt as a
426 * secondary shift key for composing international characters - if you bind
427 * Alt-8 to an action, a mac user with a French keyboard will not be able
428 * to type the <code>[</code> character, which is a significant handicap</LI>
429 * </UL>
430 * If you use the wildcard characters, and specify a key which will conflict
431 * with keys the operating system consumes, it will be mapped to whichever
432 * choice can work - for example, on Macintosh, Command-Q is always consumed
433 * by the operating system, so <code>D-Q</code> will always map to Control-Q.
434 * <p>
435 * Every modifier before the hyphen must be pressed.
436 * <em>identifier</EM> can be any text constant from {@link KeyEvent} but
437 * without the leading <code>VK_</code> characters. So {@link KeyEvent#VK_ENTER} is described as
438 * <code>ENTER</code>.
439 *
440 * @param s the string with the description of the key
441 * @return key description object, or <code>null</code> if the string does not represent any valid key
442 */
443 public static KeyStroke stringToKey(String s) {
444 StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), "-", true); // NOI18N
445
446 int needed = 0;
447
448 HashMap names = initNameAndValues()[0];
449
450 int lastModif = -1;
451
452 try {
453 for (;;) {
454 String el = st.nextToken();
455
456 // required key
457 if (el.equals("-")) { // NOI18N
458
459 if (lastModif != -1) {
460 needed |= lastModif;
461 lastModif = -1;
462 }
463
464 continue;
465 }
466
467 // if there is more elements
468 if (st.hasMoreElements()) {
469 // the text should describe modifiers
470 lastModif = readModifiers(el);
471 } else {
472 // last text must be the key code
473 Integer i = (Integer) names.get(el);
474 boolean wildcard = (needed & CTRL_WILDCARD_MASK) != 0;
475
476 //Strip out the explicit mask - KeyStroke won't know
477 //what to do with it
478 needed = needed & ~CTRL_WILDCARD_MASK;
479
480 boolean macAlt = (needed & ALT_WILDCARD_MASK) != 0;
481 needed = needed & ~ALT_WILDCARD_MASK;
482
483 if (i != null) {
484 //#26854 - Default accelerator should be Command on mac
485 if (wildcard) {
486 needed |= getMenuShortCutKeyMask();
487
488 if ((getOperatingSystem() & OS_MAC) != 0) {
489 if (!usableKeyOnMac(i.intValue(), needed)) {
490 needed &= ~getMenuShortCutKeyMask();
491 needed |= KeyEvent.CTRL_MASK;
492 }
493 }
494 }
495
496 if (macAlt) {
497 if (getOperatingSystem() == OS_MAC) {
498 needed |= KeyEvent.CTRL_MASK;
499 } else {
500 needed |= KeyEvent.ALT_MASK;
501 }
502 }
503
504 return KeyStroke.getKeyStroke(i.intValue(), needed);
505 } else {
506 return null;
507 }
508 }
509 }
510 } catch (NoSuchElementException ex) {
511 return null;
512 }
513 }
514 /**
515 * need to guard against headlessExceptions when testing.
516 * @return the acceletor mask for shortcuts.
517 */
518 private static int getMenuShortCutKeyMask() {
519 if (GraphicsEnvironment.isHeadless()) {
520 return ((getOperatingSystem() & OS_MAC) != 0) ?
521 KeyEvent.META_MASK : KeyEvent.CTRL_MASK;
522 }
523
524 return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
525 }
526
527 private static boolean usableKeyOnMac(int key, int mask) {
528 //All permutations fail for Q except ctrl
529 if (key == KeyEvent.VK_Q) {
530 return false;
531 }
532
533 boolean isMeta = ((mask & KeyEvent.META_MASK) != 0) || ((mask & KeyEvent.CTRL_DOWN_MASK) != 0);
534
535 boolean isAlt = ((mask & KeyEvent.ALT_MASK) != 0) || ((mask & KeyEvent.ALT_DOWN_MASK) != 0);
536
537 boolean isOnlyMeta = isMeta && ((mask & ~(KeyEvent.META_DOWN_MASK | KeyEvent.META_MASK)) == 0);
538
539 //Mac OS consumes keys Command+ these keys - the app will never see
540 //them, so CTRL should not be remapped for these
541 if (isOnlyMeta) {
542 return (key != KeyEvent.VK_H) && (key != KeyEvent.VK_SPACE) && (key != KeyEvent.VK_TAB);
543 } else return !((key == KeyEvent.VK_D) && isMeta && isAlt);
544 }
545
546 /** Convert a space-separated list of Emacs-like key binding names to a list of Swing key strokes.
547 * @param s the string with keys
548 * @return array of key strokes, or <code>null</code> if the string description is not valid
549 * @see #stringToKey
550 */
551 public static KeyStroke[] stringToKeys(String s) {
552 StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), " "); // NOI18N
553 ArrayList<KeyStroke> arr = new ArrayList<KeyStroke>();
554
555 while (st.hasMoreElements()) {
556 s = st.nextToken();
557
558 KeyStroke k = stringToKey(s);
559
560 if (k == null) {
561 return null;
562 }
563
564 arr.add(k);
565 }
566
567 return arr.toArray(new KeyStroke[arr.size()]);
568 }
569
570 /** Adds characters for modifiers to the buffer.
571 * @param buf buffer to add to
572 * @param modif modifiers to add (KeyEvent.XXX_MASK)
573 * @return true if something has been added
574 */
575 private static boolean addModifiers(StringBuffer buf, int modif) {
576 boolean b = false;
577
578 if ((modif & KeyEvent.CTRL_MASK) != 0) {
579 buf.append("C"); // NOI18N
580 b = true;
581 }
582
583 if ((modif & KeyEvent.ALT_MASK) != 0) {
584 buf.append("A"); // NOI18N
585 b = true;
586 }
587
588 if ((modif & KeyEvent.SHIFT_MASK) != 0) {
589 buf.append("S"); // NOI18N
590 b = true;
591 }
592
593 if ((modif & KeyEvent.META_MASK) != 0) {
594 buf.append("M"); // NOI18N
595 b = true;
596 }
597
598 if ((modif & CTRL_WILDCARD_MASK) != 0) {
599 buf.append("D");
600 b = true;
601 }
602
603 if ((modif & ALT_WILDCARD_MASK) != 0) {
604 buf.append("O");
605 b = true;
606 }
607
608 return b;
609 }
610
611 /** Reads for modifiers and creates integer with required mask.
612 * @param s string with modifiers
613 * @return integer with mask
614 * @exception NoSuchElementException if some letter is not modifier
615 */
616 private static int readModifiers(String s) throws NoSuchElementException {
617 int m = 0;
618
619 for (int i = 0; i < s.length(); i++) {
620 switch (s.charAt(i)) {
621 case 'C':
622 m |= KeyEvent.CTRL_MASK;
623 break;
624
625 case 'A':
626 m |= KeyEvent.ALT_MASK;
627 break;
628
629 case 'M':
630 m |= KeyEvent.META_MASK;
631 break;
632
633 case 'S':
634 m |= KeyEvent.SHIFT_MASK;
635 break;
636
637 case 'D':
638 m |= CTRL_WILDCARD_MASK;
639 break;
640
641 case 'O':
642 m |= ALT_WILDCARD_MASK;
643 break;
644
645 default:
646 throw new NoSuchElementException(s);
647 }
648 }
649
650 return m;
651 }
652
653 /**
654 * Convert an array of objects to an array of primitive types.
655 * E.g. an <code>Integer[]</code> would be changed to an <code>int[]</code>.
656 * @param array the wrapper array
657 * @return a primitive array
658 * @throws IllegalArgumentException if the array element type is not a primitive wrapper
659 */
660 public static Object toPrimitiveArray(Object[] array) {
661 if (array instanceof Integer[]) {
662 int[] r = new int[array.length];
663 int i;
664 int k = array.length;
665
666 for (i = 0; i < k; i++)
667 r[i] = (array[i] == null) ? 0 : ((Integer) array[i]).intValue();
668
669 return r;
670 }
671
672 if (array instanceof Boolean[]) {
673 boolean[] r = new boolean[array.length];
674 int i;
675 int k = array.length;
676
677 for (i = 0; i < k; i++)
678 r[i] = (array[i] != null) && ((Boolean) array[i]).booleanValue();
679
680 return r;
681 }
682
683 if (array instanceof Byte[]) {
684 byte[] r = new byte[array.length];
685 int i;
686 int k = array.length;
687
688 for (i = 0; i < k; i++)
689 r[i] = (array[i] == null) ? 0 : ((Byte) array[i]).byteValue();
690
691 return r;
692 }
693
694 if (array instanceof Character[]) {
695 char[] r = new char[array.length];
696 int i;
697 int k = array.length;
698
699 for (i = 0; i < k; i++)
700 r[i] = (array[i] == null) ? 0 : ((Character) array[i]).charValue();
701
702 return r;
703 }
704
705 if (array instanceof Double[]) {
706 double[] r = new double[array.length];
707 int i;
708 int k = array.length;
709
710 for (i = 0; i < k; i++)
711 r[i] = (array[i] == null) ? 0 : ((Double) array[i]).doubleValue();
712
713 return r;
714 }
715
716 if (array instanceof Float[]) {
717 float[] r = new float[array.length];
718 int i;
719 int k = array.length;
720
721 for (i = 0; i < k; i++)
722 r[i] = (array[i] == null) ? 0 : ((Float) array[i]).floatValue();
723
724 return r;
725 }
726
727 if (array instanceof Long[]) {
728 long[] r = new long[array.length];
729 int i;
730 int k = array.length;
731
732 for (i = 0; i < k; i++)
733 r[i] = (array[i] == null) ? 0 : ((Long) array[i]).longValue();
734
735 return r;
736 }
737
738 if (array instanceof Short[]) {
739 short[] r = new short[array.length];
740 int i;
741 int k = array.length;
742
743 for (i = 0; i < k; i++)
744 r[i] = (array[i] == null) ? 0 : ((Short) array[i]).shortValue();
745
746 return r;
747 }
748
749 throw new IllegalArgumentException();
750 }
751
752 /**
753 * Convert an array of primitive types to an array of objects.
754 * E.g. an <code>int[]</code> would be turned into an <code>Integer[]</code>.
755 * @param array the primitive array
756 * @return a wrapper array
757 * @throws IllegalArgumentException if the array element type is not primitive
758 */
759 public static Object[] toObjectArray(Object array) {
760 if (array instanceof Object[]) {
761 return (Object[]) array;
762 }
763
764 if (array instanceof int[]) {
765 int i;
766 int k = ((int[]) array).length;
767 Integer[] r = new Integer[k];
768
769 for (i = 0; i < k; i++)
770 r[i] = new Integer(((int[]) array)[i]);
771
772 return r;
773 }
774
775 if (array instanceof boolean[]) {
776 int i;
777 int k = ((boolean[]) array).length;
778 Boolean[] r = new Boolean[k];
779
780 for (i = 0; i < k; i++)
781 r[i] = ((boolean[]) array)[i] ? Boolean.TRUE : Boolean.FALSE;
782
783 return r;
784 }
785
786 if (array instanceof byte[]) {
787 int i;
788 int k = ((byte[]) array).length;
789 Byte[] r = new Byte[k];
790
791 for (i = 0; i < k; i++)
792 r[i] = new Byte(((byte[]) array)[i]);
793
794 return r;
795 }
796
797 if (array instanceof char[]) {
798 int i;
799 int k = ((char[]) array).length;
800 Character[] r = new Character[k];
801
802 for (i = 0; i < k; i++)
803 r[i] = new Character(((char[]) array)[i]);
804
805 return r;
806 }
807
808 if (array instanceof double[]) {
809 int i;
810 int k = ((double[]) array).length;
811 Double[] r = new Double[k];
812
813 for (i = 0; i < k; i++)
814 r[i] = new Double(((double[]) array)[i]);
815
816 return r;
817 }
818
819 if (array instanceof float[]) {
820 int i;
821 int k = ((float[]) array).length;
822 Float[] r = new Float[k];
823
824 for (i = 0; i < k; i++)
825 r[i] = new Float(((float[]) array)[i]);
826
827 return r;
828 }
829
830 if (array instanceof long[]) {
831 int i;
832 int k = ((long[]) array).length;
833 Long[] r = new Long[k];
834
835 for (i = 0; i < k; i++)
836 r[i] = new Long(((long[]) array)[i]);
837
838 return r;
839 }
840
841 if (array instanceof short[]) {
842 int i;
843 int k = ((short[]) array).length;
844 Short[] r = new Short[k];
845
846 for (i = 0; i < k; i++)
847 r[i] = new Short(((short[]) array)[i]);
848
849 return r;
850 }
851
852 throw new IllegalArgumentException();
853 }
854
855 /** Wrap multi-line strings (and get the individual lines).
856 * @param original the original string to wrap
857 * @param width the maximum width of lines
858 * @param breakIterator breaks original to chars, words, sentences, depending on what instance you provide.
859 * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
860 * @return the lines after wrapping
861 */
862 public static String[] wrapStringToArray(
863 String original, int width, BreakIterator breakIterator, boolean removeNewLines
864 ) {
865 if (original.length() == 0) {
866 return new String[] { original };
867 }
868
869 String[] workingSet;
870
871 // substitute original newlines with spaces,
872 // remove newlines from head and tail
873 if (removeNewLines) {
874 original = trimString(original);
875 original = original.replace('\n', ' ');
876 workingSet = new String[] { original };
877 } else {
878 StringTokenizer tokens = new StringTokenizer(original, "\n"); // NOI18N
879 int len = tokens.countTokens();
880 workingSet = new String[len];
881
882 for (int i = 0; i < len; i++) {
883 workingSet[i] = tokens.nextToken();
884 }
885 }
886
887 if (width < 1) {
888 width = 1;
889 }
890
891 if (original.length() <= width) {
892 return workingSet;
893 }
894
895 widthcheck: {
896 boolean ok = true;
897
898 for (int i = 0; i < workingSet.length; i++) {
899 ok = ok && (workingSet[i].length() < width);
900
901 if (!ok) {
902 break widthcheck;
903 }
904 }
905
906 return workingSet;
907 }
908
909 java.util.ArrayList<String> lines = new java.util.ArrayList<String>();
910
911 int lineStart = 0; // the position of start of currently processed line in the original string
912
913 for (int i = 0; i < workingSet.length; i++) {
914 if (workingSet[i].length() < width) {
915 lines.add(workingSet[i]);
916 } else {
917 breakIterator.setText(workingSet[i]);
918
919 int nextStart = breakIterator.next();
920 int prevStart = 0;
921
922 do {
923 while (((nextStart - lineStart) < width) && (nextStart != BreakIterator.DONE)) {
924 prevStart = nextStart;
925 nextStart = breakIterator.next();
926 }
927
928 if (nextStart == BreakIterator.DONE) {
929 nextStart = prevStart = workingSet[i].length();
930 }
931
932 if (prevStart == 0) {
933 prevStart = nextStart;
934 }
935
936 lines.add(workingSet[i].substring(lineStart, prevStart));
937
938 lineStart = prevStart;
939 prevStart = 0;
940 } while (lineStart < workingSet[i].length());
941
942 lineStart = 0;
943 }
944 }
945
946 String[] s = new String[lines.size()];
947
948 return (String[]) lines.toArray(s);
949 }
950
951 private static String trimString(String s) {
952 int idx = 0;
953 char c;
954 final int slen = s.length();
955
956 if (slen == 0) {
957 return s;
958 }
959
960 do {
961 c = s.charAt(idx++);
962 } while (((c == '\n') || (c == '\r')) && (idx < slen));
963
964 s = s.substring(--idx);
965 idx = s.length() - 1;
966
967 if (idx < 0) {
968 return s;
969 }
970
971 do {
972 c = s.charAt(idx--);
973 } while (((c == '\n') || (c == '\r')) && (idx >= 0));
974
975 return s.substring(0, idx + 2);
976 }
977 }