PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/swingx-common/src/main/java/org/jdesktop/swingx/util/Utilities.java

https://github.com/akuhtz/swingx
Java | 977 lines | 576 code | 193 blank | 208 comment | 202 complexity | 2cfd0ad5a7b4690b448c57f476e7f08f MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * $Id$
  3. *
  4. * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
  5. * Santa Clara, California 95054, U.S.A. All rights reserved.
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. package org.jdesktop.swingx.util;
  22. import java.awt.Component;
  23. import java.awt.GraphicsConfiguration;
  24. import java.awt.GraphicsEnvironment;
  25. import java.awt.Insets;
  26. import java.awt.KeyboardFocusManager;
  27. import java.awt.Rectangle;
  28. import java.awt.Toolkit;
  29. import java.awt.Window;
  30. import java.awt.event.KeyEvent;
  31. import java.lang.ref.Reference;
  32. import java.lang.ref.SoftReference;
  33. import java.lang.reflect.Field;
  34. import java.lang.reflect.Modifier;
  35. import java.text.BreakIterator;
  36. import java.util.ArrayList;
  37. import java.util.HashMap;
  38. import java.util.Locale;
  39. import java.util.NoSuchElementException;
  40. import java.util.StringTokenizer;
  41. import java.util.logging.Level;
  42. import java.util.logging.Logger;
  43. import javax.swing.KeyStroke;
  44. import javax.swing.SwingUtilities;
  45. /**
  46. * Contribution from NetBeans: Issue #319-swingx. <p>
  47. *
  48. * PENDING: need to reconcile with OS, JVM... added as-is
  49. * because needed the shortcut handling to fix #
  50. *
  51. * @author apple
  52. */
  53. public class Utilities {
  54. private Utilities() {
  55. }
  56. private static final int CTRL_WILDCARD_MASK = 32768;
  57. private static final int ALT_WILDCARD_MASK = CTRL_WILDCARD_MASK * 2;
  58. /** Operating system is Windows NT. */
  59. public static final int OS_WINNT = 1 << 0;
  60. /** Operating system is Windows 95. */
  61. public static final int OS_WIN95 = OS_WINNT << 1;
  62. /** Operating system is Windows 98. */
  63. public static final int OS_WIN98 = OS_WIN95 << 1;
  64. /** Operating system is Solaris. */
  65. public static final int OS_SOLARIS = OS_WIN98 << 1;
  66. /** Operating system is Linux. */
  67. public static final int OS_LINUX = OS_SOLARIS << 1;
  68. /** Operating system is HP-UX. */
  69. public static final int OS_HP = OS_LINUX << 1;
  70. /** Operating system is IBM AIX. */
  71. public static final int OS_AIX = OS_HP << 1;
  72. /** Operating system is SGI IRIX. */
  73. public static final int OS_IRIX = OS_AIX << 1;
  74. /** Operating system is Sun OS. */
  75. public static final int OS_SUNOS = OS_IRIX << 1;
  76. /** Operating system is Compaq TRU64 Unix */
  77. public static final int OS_TRU64 = OS_SUNOS << 1;
  78. /** Operating system is OS/2. */
  79. public static final int OS_OS2 = OS_TRU64 << 2;
  80. /** Operating system is Mac. */
  81. public static final int OS_MAC = OS_OS2 << 1;
  82. /** Operating system is Windows 2000. */
  83. public static final int OS_WIN2000 = OS_MAC << 1;
  84. /** Operating system is Compaq OpenVMS */
  85. public static final int OS_VMS = OS_WIN2000 << 1;
  86. /**
  87. *Operating system is one of the Windows variants but we don't know which
  88. *one it is
  89. */
  90. public static final int OS_WIN_OTHER = OS_VMS << 1;
  91. /** Operating system is unknown. */
  92. public static final int OS_OTHER = OS_WIN_OTHER << 1;
  93. /** Operating system is FreeBSD
  94. * @since 4.50
  95. */
  96. public static final int OS_FREEBSD = OS_OTHER << 1;
  97. /** A mask for Windows platforms. */
  98. public static final int OS_WINDOWS_MASK = OS_WINNT | OS_WIN95 | OS_WIN98 | OS_WIN2000 | OS_WIN_OTHER;
  99. /** A mask for Unix platforms. */
  100. public static final int OS_UNIX_MASK = OS_SOLARIS | OS_LINUX | OS_HP | OS_AIX | OS_IRIX | OS_SUNOS | OS_TRU64 |
  101. OS_MAC | OS_FREEBSD;
  102. /** A height of the windows's taskbar */
  103. public static final int TYPICAL_WINDOWS_TASKBAR_HEIGHT = 27;
  104. /** A height of the Mac OS X's menu */
  105. private static final int TYPICAL_MACOSX_MENU_HEIGHT = 24;
  106. private static int operatingSystem = -1;
  107. /** reference to map that maps allowed key names to their values (String, Integer)
  108. and reference to map for mapping of values to their names */
  109. private static Reference<Object> namesAndValues;
  110. /** Get the operating system on which NetBeans is running.
  111. * @return one of the <code>OS_*</code> constants (such as {@link #OS_WINNT})
  112. */
  113. public static int getOperatingSystem() {
  114. if (operatingSystem == -1) {
  115. String osName = System.getProperty("os.name");
  116. if ("Windows NT".equals(osName)) { // NOI18N
  117. operatingSystem = OS_WINNT;
  118. } else if ("Windows 95".equals(osName)) { // NOI18N
  119. operatingSystem = OS_WIN95;
  120. } else if ("Windows 98".equals(osName)) { // NOI18N
  121. operatingSystem = OS_WIN98;
  122. } else if ("Windows 2000".equals(osName)) { // NOI18N
  123. operatingSystem = OS_WIN2000;
  124. } else if (osName.startsWith("Windows ")) { // NOI18N
  125. operatingSystem = OS_WIN_OTHER;
  126. } else if ("Solaris".equals(osName)) { // NOI18N
  127. operatingSystem = OS_SOLARIS;
  128. } else if (osName.startsWith("SunOS")) { // NOI18N
  129. operatingSystem = OS_SOLARIS;
  130. }
  131. // JDK 1.4 b2 defines os.name for me as "Redhat Linux" -jglick
  132. else if (osName.endsWith("Linux")) { // NOI18N
  133. operatingSystem = OS_LINUX;
  134. } else if ("HP-UX".equals(osName)) { // NOI18N
  135. operatingSystem = OS_HP;
  136. } else if ("AIX".equals(osName)) { // NOI18N
  137. operatingSystem = OS_AIX;
  138. } else if ("Irix".equals(osName)) { // NOI18N
  139. operatingSystem = OS_IRIX;
  140. } else if ("SunOS".equals(osName)) { // NOI18N
  141. operatingSystem = OS_SUNOS;
  142. } else if ("Digital UNIX".equals(osName)) { // NOI18N
  143. operatingSystem = OS_TRU64;
  144. } else if ("OS/2".equals(osName)) { // NOI18N
  145. operatingSystem = OS_OS2;
  146. } else if ("OpenVMS".equals(osName)) { // NOI18N
  147. operatingSystem = OS_VMS;
  148. } else if (osName.equals("Mac OS X")) { // NOI18N
  149. operatingSystem = OS_MAC;
  150. } else if (osName.startsWith("Darwin")) { // NOI18N
  151. operatingSystem = OS_MAC;
  152. } else if (osName.toLowerCase(Locale.US).startsWith("freebsd")) { // NOI18N
  153. operatingSystem = OS_FREEBSD;
  154. } else {
  155. operatingSystem = OS_OTHER;
  156. }
  157. }
  158. return operatingSystem;
  159. }
  160. /** Test whether NetBeans is running on some variant of Windows.
  161. * @return <code>true</code> if Windows, <code>false</code> if some other manner of operating system
  162. */
  163. public static boolean isWindows() {
  164. return (getOperatingSystem() & OS_WINDOWS_MASK) != 0;
  165. }
  166. /** Test whether NetBeans is running on some variant of Unix.
  167. * Linux is included as well as the commercial vendors, and Mac OS X.
  168. * @return <code>true</code> some sort of Unix, <code>false</code> if some other manner of operating system
  169. */
  170. public static boolean isUnix() {
  171. return (getOperatingSystem() & OS_UNIX_MASK) != 0;
  172. }
  173. /** Test whether the operating system supports icons on frames (windows).
  174. * @return <code>true</code> if it does <em>not</em>
  175. *
  176. */
  177. public static boolean isLargeFrameIcons() {
  178. return (getOperatingSystem() == OS_SOLARIS) || (getOperatingSystem() == OS_HP);
  179. }
  180. /**
  181. * Finds out the monitor where the user currently has the input focus.
  182. * This method is usually used to help the client code to figure out on
  183. * which monitor it should place newly created windows/frames/dialogs.
  184. *
  185. * @return the GraphicsConfiguration of the monitor which currently has the
  186. * input focus
  187. */
  188. private static GraphicsConfiguration getCurrentGraphicsConfiguration() {
  189. Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
  190. if (focusOwner != null) {
  191. Window w = SwingUtilities.getWindowAncestor(focusOwner);
  192. if (w != null) {
  193. return w.getGraphicsConfiguration();
  194. }
  195. }
  196. return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
  197. }
  198. /**
  199. * Returns the usable area of the screen where applications can place its
  200. * windows. The method subtracts from the screen the area of taskbars,
  201. * system menus and the like. The screen this method applies to is the one
  202. * which is considered current, ussually the one where the current input
  203. * focus is.
  204. *
  205. * @return the rectangle of the screen where one can place windows
  206. *
  207. * @since 2.5
  208. */
  209. public static Rectangle getUsableScreenBounds() {
  210. return getUsableScreenBounds(getCurrentGraphicsConfiguration());
  211. }
  212. /**
  213. * Returns the usable area of the screen where applications can place its
  214. * windows. The method subtracts from the screen the area of taskbars,
  215. * system menus and the like.
  216. *
  217. * @param gconf the GraphicsConfiguration of the monitor
  218. * @return the rectangle of the screen where one can place windows
  219. *
  220. * @since 2.5
  221. */
  222. public static Rectangle getUsableScreenBounds(GraphicsConfiguration gconf) {
  223. if (gconf == null) {
  224. gconf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
  225. }
  226. Rectangle bounds = new Rectangle(gconf.getBounds());
  227. String str;
  228. str = System.getProperty("netbeans.screen.insets"); // NOI18N
  229. if (str != null) {
  230. StringTokenizer st = new StringTokenizer(str, ", "); // NOI18N
  231. if (st.countTokens() == 4) {
  232. try {
  233. bounds.y = Integer.parseInt(st.nextToken());
  234. bounds.x = Integer.parseInt(st.nextToken());
  235. bounds.height -= (bounds.y + Integer.parseInt(st.nextToken()));
  236. bounds.width -= (bounds.x + Integer.parseInt(st.nextToken()));
  237. } catch (NumberFormatException ex) {
  238. Logger.getAnonymousLogger().log(Level.WARNING, null, ex);
  239. }
  240. }
  241. return bounds;
  242. }
  243. str = System.getProperty("netbeans.taskbar.height"); // NOI18N
  244. if (str != null) {
  245. bounds.height -= Integer.getInteger(str, 0).intValue();
  246. return bounds;
  247. }
  248. try {
  249. Toolkit toolkit = Toolkit.getDefaultToolkit();
  250. Insets insets = toolkit.getScreenInsets(gconf);
  251. bounds.y += insets.top;
  252. bounds.x += insets.left;
  253. bounds.height -= (insets.top + insets.bottom);
  254. bounds.width -= (insets.left + insets.right);
  255. } catch (Exception ex) {
  256. Logger.getAnonymousLogger().log(Level.WARNING, null, ex);
  257. }
  258. return bounds;
  259. }
  260. /** Initialization of the names and values
  261. * @return array of two hashmaps first maps
  262. * allowed key names to their values (String, Integer)
  263. * and second
  264. * hashtable for mapping of values to their names (Integer, String)
  265. */
  266. private static synchronized HashMap[] initNameAndValues() {
  267. if (namesAndValues != null) {
  268. HashMap[] arr = (HashMap[]) namesAndValues.get();
  269. if (arr != null) {
  270. return arr;
  271. }
  272. }
  273. Field[] fields;
  274. // JW - fix Issue #353-swingx: play nicer inside sandbox.
  275. try {
  276. fields = KeyEvent.class.getDeclaredFields();
  277. // fields = KeyEvent.class.getFields();
  278. } catch (SecurityException e) {
  279. // JW: need to do better? What are the use-cases where we don't have
  280. // any access to the fields?
  281. fields = new Field[0];
  282. }
  283. HashMap<String,Integer> names = new HashMap<String,Integer>(((fields.length * 4) / 3) + 5, 0.75f);
  284. HashMap<Integer,String> values = new HashMap<Integer,String>(((fields.length * 4) / 3) + 5, 0.75f);
  285. for (int i = 0; i < fields.length; i++) {
  286. if (Modifier.isStatic(fields[i].getModifiers())) {
  287. String name = fields[i].getName();
  288. if (name.startsWith("VK_")) { // NOI18N
  289. // exclude VK
  290. name = name.substring(3);
  291. try {
  292. int numb = fields[i].getInt(null);
  293. Integer value = new Integer(numb);
  294. names.put(name, value);
  295. values.put(value, name);
  296. } catch (IllegalArgumentException ex) {
  297. } catch (IllegalAccessException ex) {
  298. }
  299. }
  300. }
  301. }
  302. if (names.get("CONTEXT_MENU") == null) { // NOI18N
  303. Integer n = new Integer(0x20C);
  304. names.put("CONTEXT_MENU", n); // NOI18N
  305. values.put(n, "CONTEXT_MENU"); // NOI18N
  306. n = new Integer(0x20D);
  307. names.put("WINDOWS", n); // NOI18N
  308. values.put(n, "WINDOWS"); // NOI18N
  309. }
  310. HashMap[] arr = { names, values };
  311. namesAndValues = new SoftReference<Object>(arr);
  312. return arr;
  313. }
  314. /** Converts a Swing key stroke descriptor to a familiar Emacs-like name.
  315. * @param stroke key description
  316. * @return name of the key (e.g. <code>CS-F1</code> for control-shift-function key one)
  317. * @see #stringToKey
  318. */
  319. public static String keyToString(KeyStroke stroke) {
  320. StringBuffer sb = new StringBuffer();
  321. // add modifiers that must be pressed
  322. if (addModifiers(sb, stroke.getModifiers())) {
  323. sb.append('-');
  324. }
  325. HashMap[] namesAndValues = initNameAndValues();
  326. String c = (String) namesAndValues[1].get(new Integer(stroke.getKeyCode()));
  327. if (c == null) {
  328. sb.append(stroke.getKeyChar());
  329. } else {
  330. sb.append(c);
  331. }
  332. return sb.toString();
  333. }
  334. /** Construct a new key description from a given universal string
  335. * description.
  336. * Provides mapping between Emacs-like textual key descriptions and the
  337. * <code>KeyStroke</code> object used in Swing.
  338. * <P>
  339. * This format has following form:
  340. * <P><code>[C][A][S][M]-<em>identifier</em></code>
  341. * <p>Where:
  342. * <UL>
  343. * <LI> <code>C</code> stands for the Control key
  344. * <LI> <code>A</code> stands for the Alt key
  345. * <LI> <code>S</code> stands for the Shift key
  346. * <LI> <code>M</code> stands for the Meta key
  347. * </UL>
  348. * The format also supports two wildcard codes, to support differences in
  349. * platforms. These are the preferred choices for registering keystrokes,
  350. * since platform conflicts will automatically be handled:
  351. * <UL>
  352. * <LI> <code>D</code> stands for the default menu accelerator - the Control
  353. * key on most platforms, the Command (meta) key on Macintosh</LI>
  354. * <LI> <code>O</code> stands for the alternate accelerator - the Alt key on
  355. * most platforms, the Ctrl key on Macintosh (Macintosh uses Alt as a
  356. * secondary shift key for composing international characters - if you bind
  357. * Alt-8 to an action, a mac user with a French keyboard will not be able
  358. * to type the <code>[</code> character, which is a significant handicap</LI>
  359. * </UL>
  360. * If you use the wildcard characters, and specify a key which will conflict
  361. * with keys the operating system consumes, it will be mapped to whichever
  362. * choice can work - for example, on Macintosh, Command-Q is always consumed
  363. * by the operating system, so <code>D-Q</code> will always map to Control-Q.
  364. * <p>
  365. * Every modifier before the hyphen must be pressed.
  366. * <em>identifier</EM> can be any text constant from {@link KeyEvent} but
  367. * without the leading <code>VK_</code> characters. So {@link KeyEvent#VK_ENTER} is described as
  368. * <code>ENTER</code>.
  369. *
  370. * @param s the string with the description of the key
  371. * @return key description object, or <code>null</code> if the string does not represent any valid key
  372. */
  373. public static KeyStroke stringToKey(String s) {
  374. StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), "-", true); // NOI18N
  375. int needed = 0;
  376. HashMap names = initNameAndValues()[0];
  377. int lastModif = -1;
  378. try {
  379. for (;;) {
  380. String el = st.nextToken();
  381. // required key
  382. if (el.equals("-")) { // NOI18N
  383. if (lastModif != -1) {
  384. needed |= lastModif;
  385. lastModif = -1;
  386. }
  387. continue;
  388. }
  389. // if there is more elements
  390. if (st.hasMoreElements()) {
  391. // the text should describe modifiers
  392. lastModif = readModifiers(el);
  393. } else {
  394. // last text must be the key code
  395. Integer i = (Integer) names.get(el);
  396. boolean wildcard = (needed & CTRL_WILDCARD_MASK) != 0;
  397. //Strip out the explicit mask - KeyStroke won't know
  398. //what to do with it
  399. needed = needed & ~CTRL_WILDCARD_MASK;
  400. boolean macAlt = (needed & ALT_WILDCARD_MASK) != 0;
  401. needed = needed & ~ALT_WILDCARD_MASK;
  402. if (i != null) {
  403. //#26854 - Default accelerator should be Command on mac
  404. if (wildcard) {
  405. needed |= getMenuShortCutKeyMask();
  406. if ((getOperatingSystem() & OS_MAC) != 0) {
  407. if (!usableKeyOnMac(i.intValue(), needed)) {
  408. needed &= ~getMenuShortCutKeyMask();
  409. needed |= KeyEvent.CTRL_MASK;
  410. }
  411. }
  412. }
  413. if (macAlt) {
  414. if (getOperatingSystem() == OS_MAC) {
  415. needed |= KeyEvent.CTRL_MASK;
  416. } else {
  417. needed |= KeyEvent.ALT_MASK;
  418. }
  419. }
  420. return KeyStroke.getKeyStroke(i.intValue(), needed);
  421. } else {
  422. return null;
  423. }
  424. }
  425. }
  426. } catch (NoSuchElementException ex) {
  427. return null;
  428. }
  429. }
  430. /**
  431. * need to guard against headlessExceptions when testing.
  432. * @return the acceletor mask for shortcuts.
  433. */
  434. private static int getMenuShortCutKeyMask() {
  435. if (GraphicsEnvironment.isHeadless()) {
  436. return ((getOperatingSystem() & OS_MAC) != 0) ?
  437. KeyEvent.META_MASK : KeyEvent.CTRL_MASK;
  438. }
  439. return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  440. }
  441. private static boolean usableKeyOnMac(int key, int mask) {
  442. //All permutations fail for Q except ctrl
  443. if (key == KeyEvent.VK_Q) {
  444. return false;
  445. }
  446. boolean isMeta = ((mask & KeyEvent.META_MASK) != 0) || ((mask & KeyEvent.CTRL_DOWN_MASK) != 0);
  447. boolean isAlt = ((mask & KeyEvent.ALT_MASK) != 0) || ((mask & KeyEvent.ALT_DOWN_MASK) != 0);
  448. boolean isOnlyMeta = isMeta && ((mask & ~(KeyEvent.META_DOWN_MASK | KeyEvent.META_MASK)) == 0);
  449. //Mac OS consumes keys Command+ these keys - the app will never see
  450. //them, so CTRL should not be remapped for these
  451. if (isOnlyMeta) {
  452. return (key != KeyEvent.VK_H) && (key != KeyEvent.VK_SPACE) && (key != KeyEvent.VK_TAB);
  453. } else return !((key == KeyEvent.VK_D) && isMeta && isAlt);
  454. }
  455. /** Convert a space-separated list of Emacs-like key binding names to a list of Swing key strokes.
  456. * @param s the string with keys
  457. * @return array of key strokes, or <code>null</code> if the string description is not valid
  458. * @see #stringToKey
  459. */
  460. public static KeyStroke[] stringToKeys(String s) {
  461. StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), " "); // NOI18N
  462. ArrayList<KeyStroke> arr = new ArrayList<KeyStroke>();
  463. while (st.hasMoreElements()) {
  464. s = st.nextToken();
  465. KeyStroke k = stringToKey(s);
  466. if (k == null) {
  467. return null;
  468. }
  469. arr.add(k);
  470. }
  471. return arr.toArray(new KeyStroke[arr.size()]);
  472. }
  473. /** Adds characters for modifiers to the buffer.
  474. * @param buf buffer to add to
  475. * @param modif modifiers to add (KeyEvent.XXX_MASK)
  476. * @return true if something has been added
  477. */
  478. private static boolean addModifiers(StringBuffer buf, int modif) {
  479. boolean b = false;
  480. if ((modif & KeyEvent.CTRL_MASK) != 0) {
  481. buf.append("C"); // NOI18N
  482. b = true;
  483. }
  484. if ((modif & KeyEvent.ALT_MASK) != 0) {
  485. buf.append("A"); // NOI18N
  486. b = true;
  487. }
  488. if ((modif & KeyEvent.SHIFT_MASK) != 0) {
  489. buf.append("S"); // NOI18N
  490. b = true;
  491. }
  492. if ((modif & KeyEvent.META_MASK) != 0) {
  493. buf.append("M"); // NOI18N
  494. b = true;
  495. }
  496. if ((modif & CTRL_WILDCARD_MASK) != 0) {
  497. buf.append("D");
  498. b = true;
  499. }
  500. if ((modif & ALT_WILDCARD_MASK) != 0) {
  501. buf.append("O");
  502. b = true;
  503. }
  504. return b;
  505. }
  506. /** Reads for modifiers and creates integer with required mask.
  507. * @param s string with modifiers
  508. * @return integer with mask
  509. * @exception NoSuchElementException if some letter is not modifier
  510. */
  511. private static int readModifiers(String s) throws NoSuchElementException {
  512. int m = 0;
  513. for (int i = 0; i < s.length(); i++) {
  514. switch (s.charAt(i)) {
  515. case 'C':
  516. m |= KeyEvent.CTRL_MASK;
  517. break;
  518. case 'A':
  519. m |= KeyEvent.ALT_MASK;
  520. break;
  521. case 'M':
  522. m |= KeyEvent.META_MASK;
  523. break;
  524. case 'S':
  525. m |= KeyEvent.SHIFT_MASK;
  526. break;
  527. case 'D':
  528. m |= CTRL_WILDCARD_MASK;
  529. break;
  530. case 'O':
  531. m |= ALT_WILDCARD_MASK;
  532. break;
  533. default:
  534. throw new NoSuchElementException(s);
  535. }
  536. }
  537. return m;
  538. }
  539. /**
  540. * Convert an array of objects to an array of primitive types.
  541. * E.g. an <code>Integer[]</code> would be changed to an <code>int[]</code>.
  542. * @param array the wrapper array
  543. * @return a primitive array
  544. * @throws IllegalArgumentException if the array element type is not a primitive wrapper
  545. */
  546. public static Object toPrimitiveArray(Object[] array) {
  547. if (array instanceof Integer[]) {
  548. int[] r = new int[array.length];
  549. int i;
  550. int k = array.length;
  551. for (i = 0; i < k; i++)
  552. r[i] = (array[i] == null) ? 0 : ((Integer) array[i]).intValue();
  553. return r;
  554. }
  555. if (array instanceof Boolean[]) {
  556. boolean[] r = new boolean[array.length];
  557. int i;
  558. int k = array.length;
  559. for (i = 0; i < k; i++)
  560. r[i] = (array[i] != null) && ((Boolean) array[i]).booleanValue();
  561. return r;
  562. }
  563. if (array instanceof Byte[]) {
  564. byte[] r = new byte[array.length];
  565. int i;
  566. int k = array.length;
  567. for (i = 0; i < k; i++)
  568. r[i] = (array[i] == null) ? 0 : ((Byte) array[i]).byteValue();
  569. return r;
  570. }
  571. if (array instanceof Character[]) {
  572. char[] r = new char[array.length];
  573. int i;
  574. int k = array.length;
  575. for (i = 0; i < k; i++)
  576. r[i] = (array[i] == null) ? 0 : ((Character) array[i]).charValue();
  577. return r;
  578. }
  579. if (array instanceof Double[]) {
  580. double[] r = new double[array.length];
  581. int i;
  582. int k = array.length;
  583. for (i = 0; i < k; i++)
  584. r[i] = (array[i] == null) ? 0 : ((Double) array[i]).doubleValue();
  585. return r;
  586. }
  587. if (array instanceof Float[]) {
  588. float[] r = new float[array.length];
  589. int i;
  590. int k = array.length;
  591. for (i = 0; i < k; i++)
  592. r[i] = (array[i] == null) ? 0 : ((Float) array[i]).floatValue();
  593. return r;
  594. }
  595. if (array instanceof Long[]) {
  596. long[] r = new long[array.length];
  597. int i;
  598. int k = array.length;
  599. for (i = 0; i < k; i++)
  600. r[i] = (array[i] == null) ? 0 : ((Long) array[i]).longValue();
  601. return r;
  602. }
  603. if (array instanceof Short[]) {
  604. short[] r = new short[array.length];
  605. int i;
  606. int k = array.length;
  607. for (i = 0; i < k; i++)
  608. r[i] = (array[i] == null) ? 0 : ((Short) array[i]).shortValue();
  609. return r;
  610. }
  611. throw new IllegalArgumentException();
  612. }
  613. /**
  614. * Convert an array of primitive types to an array of objects.
  615. * E.g. an <code>int[]</code> would be turned into an <code>Integer[]</code>.
  616. * @param array the primitive array
  617. * @return a wrapper array
  618. * @throws IllegalArgumentException if the array element type is not primitive
  619. */
  620. public static Object[] toObjectArray(Object array) {
  621. if (array instanceof Object[]) {
  622. return (Object[]) array;
  623. }
  624. if (array instanceof int[]) {
  625. int i;
  626. int k = ((int[]) array).length;
  627. Integer[] r = new Integer[k];
  628. for (i = 0; i < k; i++)
  629. r[i] = new Integer(((int[]) array)[i]);
  630. return r;
  631. }
  632. if (array instanceof boolean[]) {
  633. int i;
  634. int k = ((boolean[]) array).length;
  635. Boolean[] r = new Boolean[k];
  636. for (i = 0; i < k; i++)
  637. r[i] = ((boolean[]) array)[i] ? Boolean.TRUE : Boolean.FALSE;
  638. return r;
  639. }
  640. if (array instanceof byte[]) {
  641. int i;
  642. int k = ((byte[]) array).length;
  643. Byte[] r = new Byte[k];
  644. for (i = 0; i < k; i++)
  645. r[i] = new Byte(((byte[]) array)[i]);
  646. return r;
  647. }
  648. if (array instanceof char[]) {
  649. int i;
  650. int k = ((char[]) array).length;
  651. Character[] r = new Character[k];
  652. for (i = 0; i < k; i++)
  653. r[i] = new Character(((char[]) array)[i]);
  654. return r;
  655. }
  656. if (array instanceof double[]) {
  657. int i;
  658. int k = ((double[]) array).length;
  659. Double[] r = new Double[k];
  660. for (i = 0; i < k; i++)
  661. r[i] = new Double(((double[]) array)[i]);
  662. return r;
  663. }
  664. if (array instanceof float[]) {
  665. int i;
  666. int k = ((float[]) array).length;
  667. Float[] r = new Float[k];
  668. for (i = 0; i < k; i++)
  669. r[i] = new Float(((float[]) array)[i]);
  670. return r;
  671. }
  672. if (array instanceof long[]) {
  673. int i;
  674. int k = ((long[]) array).length;
  675. Long[] r = new Long[k];
  676. for (i = 0; i < k; i++)
  677. r[i] = new Long(((long[]) array)[i]);
  678. return r;
  679. }
  680. if (array instanceof short[]) {
  681. int i;
  682. int k = ((short[]) array).length;
  683. Short[] r = new Short[k];
  684. for (i = 0; i < k; i++)
  685. r[i] = new Short(((short[]) array)[i]);
  686. return r;
  687. }
  688. throw new IllegalArgumentException();
  689. }
  690. /** Wrap multi-line strings (and get the individual lines).
  691. * @param original the original string to wrap
  692. * @param width the maximum width of lines
  693. * @param breakIterator breaks original to chars, words, sentences, depending on what instance you provide.
  694. * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
  695. * @return the lines after wrapping
  696. */
  697. public static String[] wrapStringToArray(
  698. String original, int width, BreakIterator breakIterator, boolean removeNewLines
  699. ) {
  700. if (original.length() == 0) {
  701. return new String[] { original };
  702. }
  703. String[] workingSet;
  704. // substitute original newlines with spaces,
  705. // remove newlines from head and tail
  706. if (removeNewLines) {
  707. original = trimString(original);
  708. original = original.replace('\n', ' ');
  709. workingSet = new String[] { original };
  710. } else {
  711. StringTokenizer tokens = new StringTokenizer(original, "\n"); // NOI18N
  712. int len = tokens.countTokens();
  713. workingSet = new String[len];
  714. for (int i = 0; i < len; i++) {
  715. workingSet[i] = tokens.nextToken();
  716. }
  717. }
  718. if (width < 1) {
  719. width = 1;
  720. }
  721. if (original.length() <= width) {
  722. return workingSet;
  723. }
  724. widthcheck: {
  725. boolean ok = true;
  726. for (int i = 0; i < workingSet.length; i++) {
  727. ok = ok && (workingSet[i].length() < width);
  728. if (!ok) {
  729. break widthcheck;
  730. }
  731. }
  732. return workingSet;
  733. }
  734. java.util.ArrayList<String> lines = new java.util.ArrayList<String>();
  735. int lineStart = 0; // the position of start of currently processed line in the original string
  736. for (int i = 0; i < workingSet.length; i++) {
  737. if (workingSet[i].length() < width) {
  738. lines.add(workingSet[i]);
  739. } else {
  740. breakIterator.setText(workingSet[i]);
  741. int nextStart = breakIterator.next();
  742. int prevStart = 0;
  743. do {
  744. while (((nextStart - lineStart) < width) && (nextStart != BreakIterator.DONE)) {
  745. prevStart = nextStart;
  746. nextStart = breakIterator.next();
  747. }
  748. if (nextStart == BreakIterator.DONE) {
  749. nextStart = prevStart = workingSet[i].length();
  750. }
  751. if (prevStart == 0) {
  752. prevStart = nextStart;
  753. }
  754. lines.add(workingSet[i].substring(lineStart, prevStart));
  755. lineStart = prevStart;
  756. prevStart = 0;
  757. } while (lineStart < workingSet[i].length());
  758. lineStart = 0;
  759. }
  760. }
  761. String[] s = new String[lines.size()];
  762. return (String[]) lines.toArray(s);
  763. }
  764. private static String trimString(String s) {
  765. int idx = 0;
  766. char c;
  767. final int slen = s.length();
  768. if (slen == 0) {
  769. return s;
  770. }
  771. do {
  772. c = s.charAt(idx++);
  773. } while (((c == '\n') || (c == '\r')) && (idx < slen));
  774. s = s.substring(--idx);
  775. idx = s.length() - 1;
  776. if (idx < 0) {
  777. return s;
  778. }
  779. do {
  780. c = s.charAt(idx--);
  781. } while (((c == '\n') || (c == '\r')) && (idx >= 0));
  782. return s.substring(0, idx + 2);
  783. }
  784. }