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 }