001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: KiwiUtils.java,v $
023   Revision 1.23  2004/05/12 18:03:42  markl
024   javadoc updates
025
026   Revision 1.22  2004/05/05 21:22:45  markl
027   Comment header updates.
028
029   Revision 1.21  2004/05/05 18:33:49  markl
030   added randomInt()
031
032   Revision 1.20  2004/03/16 06:37:29  markl
033   Removed deprecated methods.
034
035   Revision 1.19  2004/03/10 00:51:27  markl
036   added getWindowForCompnent() method
037
038   Revision 1.18  2003/11/07 19:17:59  markl
039   Added setFonts() and set*LookAndFeel() methods.
040
041   Revision 1.17  2003/01/19 09:42:39  markl
042   Javadoc & comment header updates.
043
044   Revision 1.16  2002/03/08 21:36:39  markl
045   Fixed NullPointerException in paintImmediately()
046
047   Revision 1.15  2001/08/28 21:37:33  markl
048   Split out stream methods into their own class.
049
050   Revision 1.14  2001/03/12 05:43:34  markl
051   Javadoc cleanup.
052
053   Revision 1.13  2001/03/12 02:57:40  markl
054   Source code cleanup.
055
056   Revision 1.12  2000/10/15 09:33:08  markl
057   Minor fixes to window positioning code.
058
059   Revision 1.11  1999/11/15 03:43:39  markl
060   Replaced some public members with accessors.
061
062   Revision 1.10  1999/08/05 14:37:45  markl
063   Added printWindow() method.
064
065   Revision 1.9  1999/07/19 03:58:56  markl
066   Added bounds checking in centerWindow().
067
068   Revision 1.8  1999/06/28 08:19:08  markl
069   Added Font constants.
070
071   Revision 1.7  1999/06/14 00:51:41  markl
072   Removed second form of paintImmediately() method; it didn't work reliably.
073
074   Revision 1.6  1999/04/25 03:33:14  markl
075   Added new form of paintImmediately() for JComponents.
076
077   Revision 1.5  1999/04/19 05:31:42  markl
078   Added some useful Insets constants.
079
080   Revision 1.4  1999/03/11 07:51:31  markl
081   Added another form of cascadeWindow().
082
083   Revision 1.3  1999/02/28 00:37:23  markl
084   Added yet another form of centerWindow().
085
086   Revision 1.2  1999/01/10 03:47:05  markl
087   added GPL header & RCS tag
088   ----------------------------------------------------------------------------
089*/
090
091package kiwi.util;
092
093import java.awt.*;
094import java.awt.datatransfer.*;
095import java.io.*;
096import java.util.Random;
097import javax.swing.*;
098import javax.swing.border.EmptyBorder;
099
100import kiwi.ui.AboutFrame;
101
102/** This class consists of several convenience routines and constants,
103 * all of which are static.
104 *
105 * @author Mark Lindner
106 */
107
108public final class KiwiUtils
109  {
110  private static Random _rand = new Random(System.currentTimeMillis());
111  
112  /** The data transfer block size. */
113  public static final int blockSize = 4096;
114
115  /** A phantom Frame. */
116  private static Frame phantomFrame = null;
117
118  /** Empty insets (zero pixels on all sides). */
119  public static final Insets emptyInsets = new Insets(0, 0, 0, 0);
120
121  /** A default Kiwi border (empty, 5 pixels on all sides). */
122  public static final EmptyBorder defaultBorder = new EmptyBorder(5, 5, 5, 5);
123
124  /** A default Kiwi border (empty, 0 pixels on all sides). */
125  public static final EmptyBorder emptyBorder = new EmptyBorder(0, 0, 0, 0);
126
127  /** Predefined insets for first component on first or subsequent lines.
128   * Defines 5 pixels of space to the right and below.
129   */
130  public static final Insets firstInsets = new Insets(0, 0, 5, 5);
131
132  /** Predefined insets for last component on first or subsequent lines.
133   * Defines 5 pixels of space below.
134   */
135  public static final Insets lastInsets = new Insets(0, 0, 5, 0);
136
137  /** Predefined insets for first component on last line.
138   * Defines 5 pixels of space to the right.
139   */
140  public static final Insets firstBottomInsets = new Insets(0, 0, 0, 5);
141
142  /** Predefined insets for last component on last line.
143   * Defines no pixels of space.
144   */
145  public static final Insets lastBottomInsets = emptyInsets;  
146  
147  /** The root of the filesystem. */
148  public static final File filesystemRoot
149    = new File(System.getProperty("file.separator"));
150
151  /** A default bold font. */
152  public static final Font boldFont = new Font("Dialog", Font.BOLD, 12);
153
154  /** A default plain font. */
155  public static final Font plainFont = new Font("Dialog", Font.PLAIN, 12);
156
157  /** A default italic font. */
158  public static final Font italicFont = new Font("Dialog", Font.ITALIC, 12);
159
160  /** An origin point: (0,0) */
161  public static final Point origin = new Point(0, 0);
162  
163  private static Cursor lastCursor
164    = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
165  private static Clipboard clipboard = null;
166  private static ResourceManager resmgr = null;
167  private static AboutFrame aboutFrame = null;
168  
169  private KiwiUtils() { }
170
171  /** Paint a component immediately. Paints a component immediately (as opposed
172    * to queueing a repaint request in the event queue.)
173    *
174    * @param c The component to repaint.
175    */
176
177  public static final void paintImmediately(Component c)
178    {
179    Graphics gc = c.getGraphics();
180    if(gc != null)
181      {
182      c.paint(gc);
183      gc.dispose();
184      }
185    }
186  
187  /** Cascade a window off of a parent window. Moves a window a specified
188    * number of pixels below and to the right of another window.
189    *
190    * @param parent The parent window.
191    * @param w The window to cascade.
192    * @param offset The number of pixels to offset the window by
193    * vertically and horizontally.
194    */
195  
196  public static final void cascadeWindow(Window parent, Window w, int offset)
197    {
198    _cascadeWindow(parent, w, offset, offset);
199    }
200
201  /** Cascade a window off of a parent window. Moves a window a specified
202    * number of pixels below and to the right of another window.
203    *
204    * @param parent The parent window.
205    * @param w The window to cascade.
206    * @param offsetx The number of pixels to offset the window by horizontally.
207    * @param offsety The number of pixels to offset the window by vertically.
208    */
209
210  public static final void cascadeWindow(Window parent, Window w, int offsetx,
211                                         int offsety)
212    {
213    _cascadeWindow(parent, w, offsetx, offsety);
214    }
215
216  /** Cascade a window off of a parent window. Moves a window 40 pixels below
217    * and to the right of another window.
218    *
219    * @param parent The parent window.
220    * @param w The window to cascade.
221    */
222
223  public static final void cascadeWindow(Window parent, Window w)
224    {
225    _cascadeWindow(parent, w, 40, 40);
226    }
227
228  /** Cascade a window off of a component's parent window.
229   *
230   * @param w The window to cascade.
231   * @param c The component off whose parent window this window should be
232   * cascaded. If a window cannot be found in the component hierarchy above
233   * <code>c</code>, the window is centered on the screen.
234   */
235  
236  public static final void cascadeWindow(Component c, Window w)
237    {
238    Window pw = SwingUtilities.windowForComponent(c);
239
240    if(pw == null)
241      KiwiUtils.centerWindow(w);
242    else
243      KiwiUtils.cascadeWindow(pw, w);
244    }
245  
246  /* common window cascading code */
247
248  private static void _cascadeWindow(Window parent, Window w, int offsetx,
249                                     int offsety)
250    {
251    Dimension s_size, w_size;
252    Point loc = parent.getLocation();
253    loc.translate(offsetx, offsety);
254    
255    _positionWindow(w, loc.x, loc.y);
256    }
257
258  /** Center a window on the screen.
259    *
260    * @param w The window to center.
261    */
262  
263  public static final void centerWindow(Window w)
264    {
265    Dimension s_size, w_size;
266    int x, y;
267
268    s_size = w.getToolkit().getScreenSize();
269    w_size = w.getSize();
270
271    x = (s_size.width - w_size.width) / 2;
272    y = (s_size.height - w_size.height) / 2;
273
274    _positionWindow(w, x, y);
275    }
276
277  /*
278   * Make sure no part of the window is off-screen.
279   */
280
281  private static final void _positionWindow(Window w, int x, int y)
282    {
283    Dimension s_size, w_size;
284
285    s_size = w.getToolkit().getScreenSize();
286    w_size = w.getSize();
287
288    int xe = (x + w_size.width) - s_size.width;
289    int ye = (y + w_size.height) - s_size.height;
290    
291    if(xe > 0)
292      x -= xe;
293    if(ye > 0)
294      y -= ye;
295    
296    w.setLocation(x, y);    
297    }
298  
299  /** Center a window within the bounds of another window.
300    *
301    * @param w The window to center.
302    * @param parent The window to center within.
303    */
304
305  public static final void centerWindow(Window parent, Window w)
306    {
307    Dimension p_size, w_size, s_size;
308    int x, y;
309
310    p_size = parent.getSize();
311    w_size = w.getSize();
312    s_size = w.getToolkit().getScreenSize();
313    Point p_loc = parent.getLocationOnScreen();
314
315    x = ((p_size.width - w_size.width) / 2) + p_loc.x;
316    y = ((p_size.height - w_size.height) / 2) + p_loc.y;
317
318    // If placing the window at (x,y) would make part if it off-screen,
319    // then center it in the middle of the screen instead.
320    
321    if(((x + w_size.width) > s_size.width) || (x < 0)
322       || ((y + w_size.height) > s_size.height) || (y < 0))
323       centerWindow(w);
324    else
325      w.setLocation(x, y);
326    }
327
328  /** Center a window within the bounds of a component's parent window.
329   *
330   * @param w The window to center.
331   * @param c The component within whose parent window this window should be
332   * centered. If a window cannot be found in the component hierarchy above
333   * <code>c</code>, the window is centered on the screen.
334   */
335  
336  public static final void centerWindow(Component c, Window w)
337    {
338    Window pw = SwingUtilities.windowForComponent(c);
339
340    if(pw == null)
341      KiwiUtils.centerWindow(w);
342    else
343      KiwiUtils.centerWindow(pw, w);
344    }
345
346  /** Turn on a busy cursor.
347    *
348    * @param c The component whose cursor will be changed.
349    */
350  
351  public static final void busyOn(Component c)
352    {
353    lastCursor = c.getCursor();
354    c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
355    }
356
357  /** Turn off the busy cursor. The last cursor saved will be restored.
358    *
359    * @param c The component whose cursor will be changed.
360    */
361
362  public static final void busyOff(Component c)
363    {
364    c.setCursor(lastCursor);
365    }
366
367  /** Get the Frame parent of a component. This method searches upward in the
368    * component hierarchy, searching for an ancestor that is a Frame.
369    */
370
371  public static final Frame getFrameForComponent(Component c)
372    {
373    while((c = c.getParent()) != null)
374      if(c instanceof Frame)
375        return((Frame)c);
376
377    return(null);
378    }
379
380  /** Get the Window parent of a component. This method searches upward in the
381    * component hierarchy, searching for an ancestor that is a Frame.
382    *
383    * @since Kiwi 2.0
384    */
385
386  public static final Window getWindowForComponent(Component c)
387    {
388    while((c = c.getParent()) != null)
389      if(c instanceof Window)
390        return((Window)c);
391
392    return(null);
393    }
394  
395  /** Print a hardcopy of the contents of a window.
396   *
397   * @param window The window to print.
398   * @param title A title for the print job.
399   *
400   * @return <code>true</code> if the print job was started, or
401   * <code>false</code> if the user cancelled the print dialog.
402   */
403
404  public static final boolean printWindow(Window window, String title)
405    {
406    PrintJob pj = Toolkit.getDefaultToolkit()
407      .getPrintJob(getPhantomFrame(), title, null);
408
409    if(pj == null)
410      return(false);
411
412    int res = Toolkit.getDefaultToolkit().getScreenResolution();
413    Dimension d = pj.getPageDimension(); // buggy in JDK 1.1.x
414    //Dimension d = new Dimension((int)(2 * res * 8.5), (int)(res * 11 * 2));
415    
416    d.width -= (int)(res * 0.75 /*in*/);
417    d.height -= (int)(res * 0.75 /*in*/);
418    
419    Graphics gc = pj.getGraphics();
420    window.paint(gc);
421
422    gc.dispose();
423    pj.end();
424    return(true);
425    }
426
427  /** Get a reference to the system clipboard.
428   *
429   * @return The clipboard.
430   */
431
432  public static final Clipboard getClipboard()
433    {
434    if(clipboard == null)
435      clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
436
437    return(clipboard);
438    }
439  
440  /** Copy text to the system clipboard.
441    *
442    * @param text The text to copy to the clipboard.
443    */
444
445  public static synchronized final void setClipboardText(String text)
446    {
447    StringSelection sel = new StringSelection(text);
448    getClipboard().setContents(sel, sel);
449    }
450
451  /** Copy text from the system clipboard.
452    *
453    * @return The text that is in the clipboard, or <code>null</code> if the
454    * clipboard is empty or does not contain plain text.
455    */
456
457  public static synchronized final String getClipboardText()
458    {
459    try
460      {
461      return((String)(getClipboard().getContents(Void.class)
462                      .getTransferData(DataFlavor.stringFlavor)));
463      }
464    catch(Exception ex)
465      {
466      return(null);
467      }
468    }
469
470  /** Get a reference to the internal resource manager singleton. The Kiwi
471    * Toolkit has a small built-in collection of textures, icons, audio clips,
472    * and HTML files.
473    */
474
475  public static final ResourceManager getResourceManager()
476    {
477    if(resmgr == null)
478      resmgr = new ResourceManager(kiwi.ResourceAnchor.class);
479
480    return(resmgr);
481    }
482
483  /** Suspend the calling thread. Suspends the calling thread, returning
484    * immediately if an exception occurs.
485    *
486    * @param sec The number of seconds to sleep.
487    */
488  
489  public static final void sleep(int sec)
490    {
491    try
492      {
493      Thread.currentThread().sleep(sec * 1000);
494      }
495    catch(InterruptedException ex)
496      {
497      }
498    }
499
500  /** Get a reference to a phantom frame.
501   *
502   * @return The phantom frame.
503   */
504
505  public static final Frame getPhantomFrame()
506    {
507    if(phantomFrame == null)
508      phantomFrame = new Frame();
509
510    return(phantomFrame);
511    }
512  
513  /** Get an instance to a prebuilt about window that describes the Kiwi
514    * Toolkit itself.
515    */
516  
517  public static final AboutFrame getKiwiAboutFrame()
518    {
519    if(aboutFrame == null)
520      aboutFrame = new AboutFrame("About Kiwi",
521                                  getResourceManager().getURL("kiwi.html"));
522
523    return(aboutFrame);
524    }
525
526  /** Recursively delete files in a directory. Deletes all files and
527    * subdirectories in the given directory.
528    *
529    * @param parent The parent (presumed to be a directory) of the files to
530    * be deleted. The parent is not deleted.
531    *
532    * @return The number of files and directories deleted.
533    */
534
535  public static final int deleteTree(File parent)
536    {
537    int ct = 0;
538    
539    if(!parent.isDirectory()) return(0);
540    
541    String files[] = parent.list();
542    for(int i = 0; i < files.length; i++)
543      {
544      File f = new File(parent.getAbsolutePath(), files[i]);
545      
546      if(f.isDirectory())
547        ct += deleteTree(f);
548
549      f.delete();
550      ct++;
551      }
552    
553    return(ct);
554    }
555
556  /**
557   * Recursively set the font on a container and all of its descendant
558   * components.
559   *
560   * @param container The container.
561   * @param font The new font.
562   *
563   * @since Kiwi 1.4.3
564   */
565  
566  public static void setFonts(Container container, Font font)
567    {
568    container.setFont(font);
569
570    Component[] components = container.getComponents();
571
572    for(int i = 0; i < components.length; i++)
573      {
574      if(Container.class.isInstance(components[i]))
575        setFonts((Container)components[i], font);
576      else
577        components[i].setFont(font);
578      }
579    }
580
581  /**
582   * Set the default cross-platform Look and Feel
583   *
584   * @since Kiwi 1.4.3
585   */
586
587  public static void setDefaultLookAndFeel()
588    {
589    try
590      {
591      UIManager.setLookAndFeel(
592        UIManager.getCrossPlatformLookAndFeelClassName());
593      }
594    catch(Exception ex) { }
595    }
596
597  /**
598   * Set the native (system) Look and Feel
599   *
600   * @since Kiwi 1.4.3
601   */
602
603  public static void setNativeLookAndFeel()
604    {
605    try
606      {
607      UIManager.setLookAndFeel(
608        UIManager.getSystemLookAndFeelClassName());
609      }
610    catch(Exception ex) { }
611    }
612
613  /**
614   * @since Kiwi 2.0
615   */
616
617  public static int randomInt(int range)
618    {
619    return(_rand.nextInt(range));
620    }
621  
622  }
623
624/* end of source file */