001/* MetalIconFactory.java --
002   Copyright (C) 2005, 2006, Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.metal;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Graphics;
044import java.io.Serializable;
045
046import javax.swing.AbstractButton;
047import javax.swing.Icon;
048import javax.swing.JCheckBox;
049import javax.swing.JCheckBoxMenuItem;
050import javax.swing.JFileChooser;
051import javax.swing.JInternalFrame;
052import javax.swing.JRadioButton;
053import javax.swing.JRadioButtonMenuItem;
054import javax.swing.JSlider;
055import javax.swing.SwingConstants;
056import javax.swing.UIManager;
057import javax.swing.plaf.UIResource;
058
059
060/**
061 * Creates icons for the {@link MetalLookAndFeel}.
062 */
063public class MetalIconFactory implements Serializable 
064{
065
066  /** A constant representing "dark". */
067  public static final boolean DARK = false;
068    
069  /** A constant representing "light". */
070  public static final boolean LIGHT = true;
071  
072  /** A shared instance of the MenuArrowIcon. */
073  private static Icon menuArrow;
074  
075  /** A shared instance of the MenuItemArrowIcon. */
076  private static Icon menuItemArrow;
077    
078  /**
079   * An icon displayed for {@link JCheckBoxMenuItem} components.
080   */
081  private static class CheckBoxMenuItemIcon 
082    implements Icon, UIResource, Serializable 
083  {
084    /**
085     * Creates a new icon instance.
086     */
087    public CheckBoxMenuItemIcon() 
088    {
089      // Nothing to do here.
090    }
091      
092    /**
093     * Returns the width of the icon, in pixels.
094     * 
095     * @return The width of the icon (10 pixels).
096     */
097    public int getIconWidth() 
098    {
099      return 10;
100    }
101    
102    /**
103     * Returns the height of the icon, in pixels.
104     * 
105     * @return The height of the icon (10 pixels).
106     */
107    public int getIconHeight() 
108    {
109      return 10;
110    }
111    
112    /**
113     * Paints the icon.
114     * 
115     * @param c  the component.
116     * @param g  the graphics device.
117     * @param x  the x-coordinate.
118     * @param y  the y-coordinate.
119     */
120    public void paintIcon(Component c, Graphics g, int x, int y) 
121    {
122      JCheckBoxMenuItem item = (JCheckBoxMenuItem) c;
123        
124      if (item.isArmed())
125        g.setColor(MetalLookAndFeel.getBlack());
126      else
127        g.setColor(MetalLookAndFeel.getControlDarkShadow());
128      g.drawLine(x, y, x + 8, y);
129      g.drawLine(x, y + 1, x, y + 8);
130      g.drawLine(x + 2, y + 8, x + 8, y + 8);
131      g.drawLine(x + 8, y + 2, x + 8, y + 7);
132      
133      g.setColor(MetalLookAndFeel.getWhite());
134      g.drawLine(x + 1, y + 1, x + 7, y + 1);
135      g.drawLine(x + 1, y + 2, x + 1, y + 7);
136      g.drawLine(x + 1, y + 9, x + 9, y + 9);
137      g.drawLine(x + 9, y + 1, x + 9, y + 8);
138
139      // if the item is selected, we should draw a tick
140      if (item.isSelected())
141      {
142        g.setColor(MetalLookAndFeel.getBlack());
143        g.fillRect(x + 2, y + 2, 2, 5);
144        for (int i = 0; i < 6; i++)
145          g.drawLine(x + 8 - i, y + i, x + 9 - i, y + i);
146      }
147
148    }        
149  }
150
151  /**
152   * An icon used for the "detail view" button on a {@link JFileChooser} under
153   * the {@link MetalLookAndFeel}.
154   * 
155   * @see MetalIconFactory#getFileChooserDetailViewIcon()
156   */
157  private static class FileChooserDetailViewIcon 
158    implements Icon, UIResource, Serializable
159  {
160
161    /**
162     * Creates a new icon.
163     */
164    public FileChooserDetailViewIcon() 
165    {
166      // Nothing to do here.
167    }
168      
169    /**
170     * Returns the width of the icon, in pixels.
171     * 
172     * @return The width of the icon.
173     */
174    public int getIconWidth() 
175    {
176      return 18;
177    }
178    
179    /**
180     * Returns the height of the icon, in pixels.
181     * 
182     * @return The height of the icon.
183     */
184    public int getIconHeight() 
185    {
186      return 18;
187    }
188    
189    /**
190     * Paints the icon using colors from the {@link MetalLookAndFeel}.
191     * 
192     * @param c  the component (ignored).
193     * @param g  the graphics device.
194     * @param x  the x-coordinate for the top-left of the icon.
195     * @param y  the y-coordinate for the top-left of the icon.
196     */
197    public void paintIcon(Component c, Graphics g, int x, int y) 
198    {
199      Color savedColor = g.getColor();
200      g.setColor(MetalLookAndFeel.getBlack());
201
202      // file 1 outline
203      g.drawLine(x + 2, y + 2, x + 5, y + 2);
204      g.drawLine(x + 6, y + 3, x + 6, y + 7);
205      g.drawLine(x + 2, y + 7, x + 6, y + 7);
206      g.drawLine(x + 2, y + 2, x + 2, y + 7);
207      
208      // file 2 outline
209      g.drawLine(x + 2, y + 10, x + 5, y + 10);
210      g.drawLine(x + 6, y + 11, x + 6, y + 15);
211      g.drawLine(x + 2, y + 15, x + 6, y + 15);
212      g.drawLine(x + 2, y + 10, x + 2, y + 15);
213
214      // detail lines
215      g.drawLine(x + 8, y + 5, x + 15, y + 5);
216      g.drawLine(x + 8, y + 13, x + 15, y + 13);
217      
218      // fill files
219      g.setColor(MetalLookAndFeel.getPrimaryControl());
220      g.fillRect(x + 3, y + 3, 3, 4);
221      g.fillRect(x + 3, y + 11, 3, 4);
222      
223      // highlight files
224      g.setColor(MetalLookAndFeel.getPrimaryControlHighlight());
225      g.drawLine(x + 4, y + 4, x + 4, y + 5);
226      g.drawLine(x + 4, y + 12, x + 4, y + 13);
227      
228      g.setColor(savedColor);
229    }        
230  }
231
232  /**
233   * An icon used for the "home folder" button on a {@link JFileChooser} under
234   * the {@link MetalLookAndFeel}.
235   * 
236   * @see MetalIconFactory#getFileChooserHomeFolderIcon()
237   */
238  private static class FileChooserHomeFolderIcon 
239    implements Icon, UIResource, Serializable
240  {
241
242    /**
243     * Creates a new icon.
244     */
245    public FileChooserHomeFolderIcon() 
246    {
247      // Nothing to do here.
248    }
249
250    /**
251     * Returns the width of the icon, in pixels.
252     * 
253     * @return The width of the icon.
254     */
255    public int getIconWidth() 
256    {
257      return 18;
258    }
259    
260    /**
261     * Returns the height of the icon, in pixels.
262     * 
263     * @return The height of the icon.
264     */
265    public int getIconHeight() 
266    {
267      return 18;
268    }
269    
270    /**
271     * Paints the icon using colors from the {@link MetalLookAndFeel}.
272     * 
273     * @param c  the component (ignored).
274     * @param g  the graphics device.
275     * @param x  the x-coordinate for the top-left of the icon.
276     * @param y  the y-coordinate for the top-left of the icon.
277     */
278    public void paintIcon(Component c, Graphics g, int x, int y) 
279    {   
280      Color savedColor = g.getColor();
281      g.setColor(MetalLookAndFeel.getBlack());
282      
283      // roof
284      g.drawLine(x + 1, y + 8, x + 8, y + 1);
285      g.drawLine(x + 8, y + 1, x + 15, y + 8);
286      
287      // base of house
288      g.drawLine(x + 3, y + 6, x + 3, y + 15);
289      g.drawLine(x + 3, y + 15, x + 13, y + 15);
290      g.drawLine(x + 13, y + 6, x + 13, y + 15);
291      
292      // door frame
293      g.drawLine(x + 6, y + 9, x + 6, y + 15);
294      g.drawLine(x + 6, y + 9, x + 10, y + 9);
295      g.drawLine(x + 10, y + 9, x + 10, y + 15);
296      
297      // chimney
298      g.drawLine(x + 11, y + 2, x + 11, y + 4);
299      g.drawLine(x + 12, y + 2, x + 12, y + 5);
300      
301      g.setColor(MetalLookAndFeel.getControlDarkShadow());
302      
303      // roof paint
304      int xx = x + 8;
305      for (int i = 0; i < 4; i++)
306        g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i);
307      g.fillRect(x + 4, y + 6, 9, 2);
308      
309      // door knob
310      g.drawLine(x + 9, y + 12, x + 9, y + 12);
311      
312      // house paint
313      g.setColor(MetalLookAndFeel.getPrimaryControl());
314      g.drawLine(x + 4, y + 8, x + 12, y + 8);
315      g.fillRect(x + 4, y + 9, 2, 6);
316      g.fillRect(x + 11, y + 9, 2, 6);
317      
318      g.setColor(savedColor);
319    }        
320  }
321    
322  /**
323   * An icon used for the "list view" button on a {@link JFileChooser} under
324   * the {@link MetalLookAndFeel}.
325   * 
326   * @see MetalIconFactory#getFileChooserListViewIcon()
327   */
328  private static class FileChooserListViewIcon 
329    implements Icon, UIResource, Serializable 
330  {
331    /**
332     * Creates a new icon.
333     */
334    public FileChooserListViewIcon() 
335    {
336      // Nothing to do here.
337    }
338    
339    /**
340     * Returns the width of the icon, in pixels.
341     * 
342     * @return The width of the icon.
343     */
344    public int getIconWidth() 
345    {
346      return 18;
347    }
348    
349    /**
350     * Returns the height of the icon, in pixels.
351     * 
352     * @return The height of the icon.
353     */
354    public int getIconHeight() 
355    {
356      return 18;
357    }
358    
359    /**
360     * Paints the icon using colors from the {@link MetalLookAndFeel}.
361     * 
362     * @param c  the component (ignored).
363     * @param g  the graphics device.
364     * @param x  the x-coordinate for the top-left of the icon.
365     * @param y  the y-coordinate for the top-left of the icon.
366     */
367    public void paintIcon(Component c, Graphics g, int x, int y) 
368    {
369      Color savedColor = g.getColor();
370      g.setColor(MetalLookAndFeel.getBlack());
371
372      // file 1 outline
373      g.drawLine(x + 2, y + 2, x + 5, y + 2);
374      g.drawLine(x + 6, y + 3, x + 6, y + 7);
375      g.drawLine(x + 2, y + 7, x + 6, y + 7);
376      g.drawLine(x + 2, y + 2, x + 2, y + 7);
377      
378      // file 2 outline
379      g.drawLine(x + 2, y + 10, x + 5, y + 10);
380      g.drawLine(x + 6, y + 11, x + 6, y + 15);
381      g.drawLine(x + 2, y + 15, x + 6, y + 15);
382      g.drawLine(x + 2, y + 10, x + 2, y + 15);
383      
384      // file 3 outline
385      g.drawLine(x + 10, y + 2, x + 13, y + 2);
386      g.drawLine(x + 14, y + 3, x + 14, y + 7);
387      g.drawLine(x + 10, y + 7, x + 14, y + 7);
388      g.drawLine(x + 10, y + 2, x + 10, y + 7);
389      
390      // file 4 outline
391      g.drawLine(x + 10, y + 10, x + 13, y + 10);
392      g.drawLine(x + 14, y + 11, x + 14, y + 15);
393      g.drawLine(x + 10, y + 15, x + 14, y + 15);
394      g.drawLine(x + 10, y + 10, x + 10, y + 15);
395      
396      g.drawLine(x + 8, y + 5, x + 8, y + 5);
397      g.drawLine(x + 8, y + 13, x + 8, y + 13);
398      g.drawLine(x + 16, y + 5, x + 16, y + 5);
399      g.drawLine(x + 16, y + 13, x + 16, y + 13);
400      
401      // fill files
402      g.setColor(MetalLookAndFeel.getPrimaryControl());
403      g.fillRect(x + 3, y + 3, 3, 4);
404      g.fillRect(x + 3, y + 11, 3, 4);
405      g.fillRect(x + 11, y + 3, 3, 4);
406      g.fillRect(x + 11, y + 11, 3, 4);
407      
408      // highlight files
409      g.setColor(MetalLookAndFeel.getPrimaryControlHighlight());
410      g.drawLine(x + 4, y + 4, x + 4, y + 5);
411      g.drawLine(x + 4, y + 12, x + 4, y + 13);
412      g.drawLine(x + 12, y + 4, x + 12, y + 5);
413      g.drawLine(x + 12, y + 12, x + 12, y + 13);
414
415      g.setColor(savedColor);
416    }        
417  }
418    
419  /**
420   * An icon used for the "new folder" button on a {@link JFileChooser} under
421   * the {@link MetalLookAndFeel}.
422   * 
423   * @see MetalIconFactory#getFileChooserNewFolderIcon()
424   */
425  private static class FileChooserNewFolderIcon 
426    implements Icon, UIResource, Serializable
427  {
428    /** 
429     * Creates a new icon.
430     */
431    public FileChooserNewFolderIcon() 
432    {
433      // Nothing to do here.
434    }
435    
436    /**
437     * Returns the width of the icon, in pixels.
438     * 
439     * @return The width of the icon.
440     */
441    public int getIconWidth() 
442    {
443      return 18;
444    }
445    
446    /**
447     * Returns the height of the icon, in pixels.
448     * 
449     * @return The height of the icon.
450     */
451    public int getIconHeight() 
452    {
453      return 18;
454    }
455    
456    /**
457     * Paints the icon using colors from the {@link MetalLookAndFeel}.
458     * 
459     * @param c  the component (ignored).
460     * @param g  the graphics device.
461     * @param x  the x-coordinate for the top-left of the icon.
462     * @param y  the y-coordinate for the top-left of the icon.
463     */
464    public void paintIcon(Component c, Graphics g, int x, int y) 
465    {      
466      Color savedColor = g.getColor();
467      g.setColor(MetalLookAndFeel.getBlack());
468      
469      g.drawLine(x + 2, y + 5, x + 9, y + 5);
470      g.drawLine(x + 10, y + 6, x + 15, y + 6);
471      g.drawLine(x + 15, y + 5, x + 15, y + 14);
472      g.drawLine(x + 2, y + 14, x + 15, y + 14);
473      g.drawLine(x + 1, y + 6, x + 1, y + 14);
474      
475      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
476      g.drawLine(x + 11, y + 3, x + 15, y + 3);
477      g.drawLine(x + 10, y + 4, x + 15, y + 4);
478      
479      g.setColor(MetalLookAndFeel.getPrimaryControl());
480      g.fillRect(x + 3, y + 7, 7, 7);
481      g.fillRect(x + 10, y + 8, 5, 6);
482      g.drawLine(x + 10, y + 5, x + 14, y + 5);
483      
484      g.setColor(MetalLookAndFeel.getPrimaryControlHighlight());
485      g.drawLine(x + 10, y + 7, x + 14, y + 7);
486      g.drawLine(x + 2, y + 6, x + 9, y + 6);
487      g.drawLine(x + 2, y + 6, x + 2, y + 13);
488      g.setColor(savedColor);
489    }        
490  }
491
492  /**
493   * An icon used for the "up folder" button on a {@link JFileChooser} under
494   * the {@link MetalLookAndFeel}.
495   * 
496   * @see MetalIconFactory#getFileChooserNewFolderIcon()
497   */
498  private static class FileChooserUpFolderIcon extends FileChooserNewFolderIcon 
499  {
500    /**
501     * Creates a new icon.
502     */
503    public FileChooserUpFolderIcon() 
504    {
505      // Nothing to do here.
506    }
507    
508    /**
509     * Paints the icon using colors from the {@link MetalLookAndFeel}.
510     * 
511     * @param c  the component (ignored).
512     * @param g  the graphics device.
513     * @param x  the x-coordinate for the top-left of the icon.
514     * @param y  the y-coordinate for the top-left of the icon.
515     */
516    public void paintIcon(Component c, Graphics g, int x, int y) 
517    {
518      Color savedColor = g.getColor();
519
520      // draw the folder
521      super.paintIcon(c, g, x, y);
522      
523      // now draw the up arrow
524      g.setColor(MetalLookAndFeel.getBlack());
525      g.drawLine(x + 8, y + 9, x + 8, y + 16);
526      int xx = x + 8;
527      for (int i = 0; i < 4; i++)
528        g.drawLine(xx - i, y + 9 + i, xx + i, y + 9 + i);
529      g.setColor(savedColor);
530    }        
531  }
532
533  /**
534   * An icon representing a file (drawn as a piece of paper with the top-right
535   * corner turned down).
536   */
537  public static class FileIcon16 implements Icon, Serializable 
538  {
539    /**
540     * Returns the width of the icon, in pixels.
541     * 
542     * @return The width of the icon.
543     */
544    public int getIconWidth() 
545    {
546      return 16;
547    }
548
549    /**
550     * Returns the height of the icon, in pixels.  The height returned is 
551     * <code>16</code> plus the value returned by 
552     * {@link #getAdditionalHeight()}.
553     * 
554     * @return The height of the icon.
555     */
556    public int getIconHeight() 
557    {
558      return 16 + getAdditionalHeight();
559    }
560    
561    /**
562     * Paints the icon at the location (x, y).
563     * 
564     * @param c  the component.
565     * @param g  the graphics context.
566     * @param x  the x coordinate.
567     * @param y  the y coordinate.
568     */
569    public void paintIcon(Component c, Graphics g, int x, int y) 
570    {
571      y = y + getShift();
572      g.setColor(MetalLookAndFeel.getBlack());
573      g.drawLine(x, y, x + 9, y);            
574      g.drawLine(x, y + 1, x, y + 15);            
575      g.drawLine(x, y + 15, x + 12, y + 15);            
576      g.drawLine(x + 12, y + 15, x + 12, y + 6);            
577      g.drawLine(x + 12, y + 6, x + 9, y);           
578
579      g.drawLine(x + 7, y + 2, x + 11, y + 6);
580      g.drawLine(x + 8, y + 1, x + 9, y + 1);
581
582      g.setColor(MetalLookAndFeel.getPrimaryControl());
583      g.drawLine(x + 1, y + 1, x + 7, y + 1);            
584      g.drawLine(x + 1, y + 1, x + 1, y + 14);            
585      g.drawLine(x + 1, y + 14, x + 11, y + 14);            
586      g.drawLine(x + 11, y + 14, x + 11, y + 7);            
587      g.drawLine(x + 8, y + 2, x + 10, y + 4);
588    }
589    
590    /**
591     * Returns the additional height for the icon.  The 
592     * {@link #getIconHeight()} method adds this value to the icon height it
593     * returns.  Subclasses can override this method to adjust the icon height.
594     * 
595     * @return The additional height (<code>0</code> unless overridden).
596     */
597    public int getAdditionalHeight() 
598    {
599      return 0;
600    }
601        
602    /**
603     * Returns the vertical shift, in pixels, applied when painting the icon.  
604     * The default value is zero, but subclasses may override this (for 
605     * example, see {@link TreeLeafIcon}).
606     * 
607     * @return The shift.
608     */
609    public int getShift() 
610    {
611      return 0;
612    }
613        
614  }
615    
616  /**
617   * An icon representing a folder.
618   */
619  public static class FolderIcon16 implements Icon, Serializable 
620  {
621    /**
622     * Returns the width of the icon, in pixels.
623     * 
624     * @return The width of the icon.
625     */
626    public int getIconWidth() 
627    {
628      return 16;
629    }
630    
631    /**
632     * Returns the height of the icon, in pixels.  The height returned is 
633     * <code>16</code> plus the value returned by 
634     * {@link #getAdditionalHeight()}.
635     * 
636     * @return The height of the icon.
637     */
638    public int getIconHeight() 
639    {
640      return 16 + getAdditionalHeight();
641    }
642
643    /**
644     * Paints the icon at the location (x, y).
645     * 
646     * @param c  the component.
647     * @param g  the graphics device.
648     * @param x  the x coordinate.
649     * @param y  the y coordinate.
650     */
651    public void paintIcon(Component c, Graphics g, int x, int y) 
652    {
653      y = y + getShift();
654      g.setColor(MetalLookAndFeel.getBlack());
655      g.drawLine(x, y + 6, x, y + 15);
656      g.drawLine(x, y + 15, x + 15, y + 15);
657      g.drawLine(x + 15, y + 15, x + 15, y + 5);
658      g.drawLine(x + 14, y + 6, x + 9, y + 6);
659      g.drawLine(x + 8, y + 5, x + 1, y + 5);
660      g.setColor(MetalLookAndFeel.getPrimaryControl());
661      g.fillRect(x + 2, y + 7, 7, 8);
662      g.fillRect(x + 9, y + 8, 6, 7);
663      g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
664      g.drawLine(x + 9, y + 5, x + 14, y + 5);
665      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
666      g.drawLine(x + 9, y + 4, x + 15, y + 4);
667      g.drawLine(x + 10, y + 3, x + 15, y + 3);
668    }
669    
670    /**
671     * Returns the additional height for the icon.  The 
672     * {@link #getIconHeight()} method adds this value to the icon height it
673     * returns.  Subclasses can override this method to adjust the icon height.
674     * 
675     * @return The additional height (<code>0</code> unless overridden).
676     */
677    public int getAdditionalHeight() 
678    {
679      return 0;
680    }
681    
682    /**
683     * Returns the vertical shift, in pixels, applied when painting the icon.  
684     * The default value is zero, but subclasses may override this (for 
685     * example, see {@link TreeFolderIcon}).
686     * 
687     * @return The shift.
688     */
689    public int getShift() 
690    {
691      return 0;
692    }
693        
694  }
695
696  /**
697   * An icon used by the {@link MetalInternalFrameUI} class when the frame
698   * is displayed as a palette.
699   * 
700   * @since 1.3
701   */
702  public static class PaletteCloseIcon
703    implements Icon, Serializable, UIResource
704  {
705    /**
706     * Returns the width of the icon, in pixels.
707     * 
708     * @return The width of the icon.
709     */
710    public int getIconWidth() 
711    {
712      return 7;
713    }
714    
715    /**
716     * Returns the height of the icon, in pixels.
717     * 
718     * @return The height of the icon.
719     */
720    public int getIconHeight() 
721    {
722      return 7;
723    }
724    
725    /**
726     * Paints the icon using colors from the {@link MetalLookAndFeel}.
727     * 
728     * @param c  the component (ignored).
729     * @param g  the graphics device.
730     * @param x  the x-coordinate for the top-left of the icon.
731     * @param y  the y-coordinate for the top-left of the icon.
732     */
733    public void paintIcon(Component c, Graphics g, int x, int y) 
734    {
735      Color savedColor = g.getColor();
736      AbstractButton button = (AbstractButton) c;
737      if (button.getModel().isPressed())
738        g.setColor(MetalLookAndFeel.getBlack());
739      else
740        g.setColor(MetalLookAndFeel.getControlDarkShadow());
741      g.fillRect(x + 2, y + 2, 3, 3);
742      g.drawLine(x + 1, y, x + 1, y + 2);
743      g.drawLine(x, y + 1, x + 2, y + 1);
744      g.drawLine(x + 5, y, x + 5, y + 2);
745      g.drawLine(x + 4, y + 1, x + 6, y + 1);
746      g.drawLine(x + 1, y + 4, x + 1, y + 6);
747      g.drawLine(x, y + 5, x + 2, y + 5);
748      g.drawLine(x + 5, y + 4, x + 5, y + 6);
749      g.drawLine(x + 4, y + 5, x + 6, y + 5);
750      g.setColor(MetalLookAndFeel.getControlHighlight());
751      g.drawLine(x + 2, y + 6, x + 3, y + 5);
752      g.drawLine(x + 5, y + 3, x + 6, y + 2);
753      g.drawLine(x + 6, y + 6, x + 6, y + 6);
754      g.setColor(savedColor);
755    }        
756  }
757  
758  /**
759   * An {@link Icon} implementation for {@link JCheckBox}es in the
760   * Metal Look &amp; Feel.
761   *
762   * @author Roman Kennke (roman@kennke.org)
763   */
764  static class RadioButtonIcon implements Icon, UIResource, Serializable
765  {
766
767    /**
768     * This is used as a mask when painting the gradient. See
769     * {@link MetalUtils#paintGradient(java.awt.Graphics, int, int, int, int,
770     *  float, float, java.awt.Color, java.awt.Color, java.awt.Color, int,
771     *  int[][])} for details.
772     */
773    private static int[][] gradientMask = new int[][] {{3, 7}, {1, 9}, {1, 9},
774                                                       {0, 10}, {0, 10}, {0, 10},
775                                                       {0, 10}, {1, 9}, {1, 9},
776                                                       {3, 7}};
777
778    /**
779     * Returns the width of the icon in pixels.
780     *
781     * @return the width of the icon in pixels
782     */
783    public int getIconWidth()
784    {
785      return 13;
786    }
787
788    /**
789     * Returns the height of the icon in pixels.
790     *
791     * @return the height of the icon in pixels
792     */
793    public int getIconHeight()
794    {
795      return 13;
796    }
797
798    /**
799     * Paints the icon, taking into account whether or not the component is
800     * enabled, selected and/or armed.
801     *
802     * @param c the Component to draw on (must be an instance of 
803     *          {@link JRadioButton})
804     * @param g the Graphics context to draw with
805     * @param x the X position
806     * @param y the Y position
807     */
808    public void paintIcon(Component c, Graphics g, int x, int y) 
809    {
810      if (UIManager.get("RadioButton.gradient") != null)
811        MetalUtils.paintGradient(g, x + 2, y + 2, 8, 8,
812                              SwingConstants.VERTICAL, "RadioButton.gradient",
813                              gradientMask);
814
815      Color savedColor = g.getColor();
816      JRadioButton b = (JRadioButton) c;
817
818      // draw outer circle
819      if (b.isEnabled())
820        g.setColor(MetalLookAndFeel.getControlDarkShadow());
821      else
822        g.setColor(MetalLookAndFeel.getControlDisabled());
823      g.drawLine(x + 2, y + 1, x + 3, y + 1);
824      g.drawLine(x + 4, y, x + 7, y);
825      g.drawLine(x + 8, y + 1, x + 9, y + 1);
826      g.drawLine(x + 10, y + 2, x + 10, y + 3);
827      g.drawLine(x + 11, y + 4, x + 11, y + 7);
828      g.drawLine(x + 10, y + 8, x + 10, y + 9);
829      g.drawLine(x + 8, y + 10, x + 9, y + 10);
830      g.drawLine(x + 4, y + 11, x + 7, y + 11);
831      g.drawLine(x + 2, y + 10, x + 3, y + 10);
832      g.drawLine(x + 1, y + 9, x + 1, y + 8);
833      g.drawLine(x, y + 7, x, y + 4);
834      g.drawLine(x + 1, y + 2, x + 1, y + 3);
835
836      if (b.getModel().isArmed())
837        {
838          g.setColor(MetalLookAndFeel.getControlShadow());
839          g.drawLine(x + 4, y + 1, x + 7, y + 1);
840          g.drawLine(x + 4, y + 10, x + 7, y + 10);
841          g.drawLine(x + 1, y + 4, x + 1, y + 7);
842          g.drawLine(x + 10, y + 4, x + 10, y + 7);
843          g.fillRect(x + 2, y + 2, 8, 8);
844        }
845      else 
846        {
847          // only draw inner highlight if not filled
848          if (b.isEnabled())
849            {
850              g.setColor(MetalLookAndFeel.getWhite());
851          
852              g.drawLine(x + 2, y + 8, x + 2, y + 9);
853              g.drawLine(x + 1, y + 4, x + 1, y + 7);
854              g.drawLine(x + 2, y + 2, x + 2, y + 3);
855              g.drawLine(x + 3, y + 2, x + 3, y + 2);
856              g.drawLine(x + 4, y + 1, x + 7, y + 1);
857              g.drawLine(x + 8, y + 2, x + 9, y + 2);
858            }
859        }
860
861      // draw outer highlight
862      if (b.isEnabled())
863        {
864          g.setColor(MetalLookAndFeel.getWhite());
865          
866          // outer
867          g.drawLine(x + 10, y + 1, x + 10, y + 1);
868          g.drawLine(x + 11, y + 2, x + 11, y + 3);
869          g.drawLine(x + 12, y + 4, x + 12, y + 7);
870          g.drawLine(x + 11, y + 8, x + 11, y + 9);
871          g.drawLine(x + 10, y + 10, x + 10, y + 10);
872          g.drawLine(x + 8, y + 11, x + 9, y + 11);
873          g.drawLine(x + 4, y + 12, x + 7, y + 12);
874          g.drawLine(x + 2, y + 11, x + 3, y + 11);
875        }
876      
877      if (b.isSelected())
878        {
879          if (b.isEnabled())
880            g.setColor(MetalLookAndFeel.getBlack());
881          else
882            g.setColor(MetalLookAndFeel.getControlDisabled());
883          g.drawLine(x + 4, y + 3, x + 7, y + 3);
884          g.fillRect(x + 3, y + 4, 6, 4);
885          g.drawLine(x + 4, y + 8, x + 7, y + 8);
886        }
887      g.setColor(savedColor);
888    }        
889  }
890
891  /**
892   * An icon displayed for {@link JRadioButtonMenuItem} components.
893   */
894  private static class RadioButtonMenuItemIcon 
895    implements Icon, UIResource, Serializable 
896  {
897    /**
898     * Creates a new icon instance.
899     */
900    public RadioButtonMenuItemIcon() 
901    {
902      // Nothing to do here.
903    }
904
905    /**
906     * Returns the width of the icon, in pixels.
907     * 
908     * @return The width of the icon.
909     */
910    public int getIconWidth() 
911    {
912      return 10;
913    }
914
915    /**
916     * Returns the height of the icon, in pixels.
917     * 
918     * @return The height of the icon.
919     */
920    public int getIconHeight()   
921    {
922      return 10;
923    }
924
925    /**
926     * Paints the icon.
927     * 
928     * @param c  the component.
929     * @param g  the graphics device.
930     * @param x  the x-coordinate.
931     * @param y  the y-coordinate.
932     */
933    public void paintIcon(Component c, Graphics g, int x, int y) 
934    {
935      Color savedColor = g.getColor();
936      JRadioButtonMenuItem item = (JRadioButtonMenuItem) c;
937      g.setColor(MetalLookAndFeel.getBlack());
938      g.drawLine(x + 2, y, x + 6, y);
939      g.drawLine(x + 7, y + 1, x + 7, y + 1);
940      g.drawLine(x + 8, y + 2, x + 8, y + 6);
941      g.drawLine(x + 7, y + 7, x + 7, y + 7);
942      g.drawLine(x + 2, y + 8, x + 6, y + 8);
943      g.drawLine(x + 1, y + 7, x + 1, y + 7);
944      g.drawLine(x, y + 2, x, y + 6);
945      g.drawLine(x + 1, y + 1, x + 1, y + 1);
946      
947      if (item.isSelected())
948        {
949          g.drawLine(x + 3, y + 2, x + 5, y + 2);
950          g.fillRect(x + 2, y + 3, 5, 3);
951          g.drawLine(x + 3, y + 6, x + 5, y + 6);
952        }
953
954      // highlight
955      g.setColor(MetalLookAndFeel.getControlHighlight());
956      g.drawLine(x + 3, y + 1, x + 6, y + 1);
957      g.drawLine(x + 8, y + 1, x + 8, y + 1);
958      g.drawLine(x + 9, y + 2, x + 9, y + 7);
959      g.drawLine(x + 8, y + 8, x + 8, y + 8);
960      g.drawLine(x + 2, y + 9, x + 7, y + 9);
961      g.drawLine(x + 1, y + 8, x + 1, y + 8);
962      g.drawLine(x + 1, y + 3, x + 1, y + 6);
963      g.drawLine(x + 2, y + 2, x + 2, y + 2);
964      g.setColor(savedColor);
965    }        
966  }
967
968  /**
969   * The icon used to display the thumb control on a horizontally oriented
970   * {@link JSlider} component.
971   */
972  private static class HorizontalSliderThumbIcon 
973    implements Icon, UIResource, Serializable
974  {
975
976    /**
977     * This mask is used to paint the gradient in the shape of the thumb.
978     */
979    int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12},
980                                         {0, 12}, {0, 12}, {0, 12}, {1, 11},
981                                         {2, 10}, {3, 9}, {4, 8}, {5, 7},
982                                         {6, 6}};
983
984    /**
985     * Creates a new instance.
986     */
987    public HorizontalSliderThumbIcon() 
988    {
989      // Nothing to do here.
990    }
991    
992    /**
993     * Returns the width of the icon, in pixels.
994     * 
995     * @return The width of the icon.
996     */
997    public int getIconWidth() 
998    {
999      return 15;
1000    }
1001    
1002    /**
1003     * Returns the height of the icon, in pixels.
1004     * 
1005     * @return The height of the icon.
1006     */
1007    public int getIconHeight() 
1008    {
1009      return 16;
1010    }
1011    
1012    /**
1013     * Paints the icon, taking into account whether or not the component has 
1014     * the focus.
1015     * 
1016     * @param c  the component.
1017     * @param g  the graphics device.
1018     * @param x  the x-coordinate.
1019     * @param y  the y-coordinate.
1020     */
1021    public void paintIcon(Component c, Graphics g, int x, int y) 
1022    {
1023      boolean enabled = false;
1024      boolean focus = false;
1025      if (c != null)
1026        {
1027          enabled = c.isEnabled();
1028          focus = c.hasFocus();    
1029        }
1030      
1031      // draw the outline
1032      if (enabled) 
1033        g.setColor(MetalLookAndFeel.getBlack());
1034      else
1035        g.setColor(MetalLookAndFeel.getControlDarkShadow());
1036      g.drawLine(x + 1, y, x + 13, y);
1037      g.drawLine(x + 14, y + 1, x + 14, y + 7);
1038      g.drawLine(x + 14, y + 8, x + 7, y + 15);
1039      g.drawLine(x + 6, y + 14, x, y + 8);
1040      g.drawLine(x, y + 7, x, y + 1);
1041      
1042// The following is commented out until the masking for the gradient painting 
1043// is working correctly
1044//      // Fill the icon.
1045//      if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme
1046//          && enabled)
1047//        {
1048//          String gradient;
1049//          if (focus)
1050//            gradient = "Slider.focusGradient";
1051//          else
1052//            gradient = "Slider.gradient";
1053//          MetalUtils.paintGradient(g, x + 1, y + 2, 12, 13,
1054//                                   SwingConstants.VERTICAL, gradient,
1055//                                   gradientMask);
1056//        }
1057//      else
1058        {
1059          if (focus)
1060            g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1061          else
1062            g.setColor(MetalLookAndFeel.getControl());
1063          g.fillRect(x + 1, y + 2, 13, 7);
1064          g.drawLine(x + 2, y + 9, x + 12, y + 9);
1065          g.drawLine(x + 3, y + 10, x + 11, y + 10);
1066          g.drawLine(x + 4, y + 11, x + 10, y + 11);
1067          g.drawLine(x + 5, y + 12, x + 9, y + 12);
1068          g.drawLine(x + 6, y + 13, x + 8, y + 13);
1069          g.drawLine(x + 7, y + 14, x + 7, y + 14);
1070        }
1071
1072      // If the slider is enabled, draw dots and highlights.
1073      if (c.isEnabled()
1074          && !(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme))
1075        {
1076          if (focus)
1077            g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1078          else
1079            g.setColor(MetalLookAndFeel.getBlack());
1080          g.drawLine(x + 3, y + 3, x + 3, y + 3);
1081          g.drawLine(x + 7, y + 3, x + 7, y + 3);
1082          g.drawLine(x + 11, y + 3, x + 11, y + 3);
1083
1084          g.drawLine(x + 5, y + 5, x + 5, y + 5);
1085          g.drawLine(x + 9, y + 5, x + 9, y + 5);
1086
1087          g.drawLine(x + 3, y + 7, x + 3, y + 7);
1088          g.drawLine(x + 7, y + 7, x + 7, y + 7);
1089          g.drawLine(x + 11, y + 7, x + 11, y + 7);
1090
1091          // Draw highlights
1092          if (focus)
1093            g.setColor(MetalLookAndFeel.getPrimaryControl());
1094          else
1095            g.setColor(MetalLookAndFeel.getWhite());
1096          g.drawLine(x + 1, y + 1, x + 13, y + 1);
1097          g.drawLine(x + 1, y + 2, x + 1, y + 8);
1098          g.drawLine(x + 2, y + 2, x + 2, y + 2);
1099          g.drawLine(x + 6, y + 2, x + 6, y + 2);
1100          g.drawLine(x + 10, y + 2, x + 10, y + 2);
1101          
1102          g.drawLine(x + 4, y + 4, x + 4, y + 4);
1103          g.drawLine(x + 8, y + 4, x + 8, y + 4);
1104
1105          g.drawLine(x + 2, y + 6, x + 2, y + 6);
1106          g.drawLine(x + 6, y + 6, x + 6, y + 6);
1107          g.drawLine(x + 10, y + 6, x + 10, y + 6);
1108        }
1109
1110    }        
1111  }
1112  
1113  /**
1114   * An icon used for the 'close' button in the title frame of a 
1115   * {@link JInternalFrame}.
1116   */
1117  private static class InternalFrameCloseIcon 
1118    implements Icon, UIResource, Serializable
1119  {
1120    /** The icon size in pixels. */
1121    private int size;
1122    
1123    /**
1124     * Creates a new icon.
1125     * 
1126     * @param size  the icon size (width and height) in pixels.
1127     */
1128    public InternalFrameCloseIcon(int size) 
1129    {
1130      this.size = size;
1131    }
1132    
1133    /**
1134     * Returns the width of the icon, in pixels.
1135     * 
1136     * @return The width of the icon.
1137     */
1138    public int getIconWidth() 
1139    {
1140      return size;
1141    }
1142    
1143    /**
1144     * Returns the height of the icon, in pixels.
1145     * 
1146     * @return The height of the icon.
1147     */
1148    public int getIconHeight() 
1149    {
1150      return size;
1151    }
1152    
1153    /**
1154     * Paints the icon.
1155     * 
1156     * @param c  the component (an {@link JInternalFrame} is expected).
1157     * @param g  the graphics device.
1158     * @param x  the x-coordinate.
1159     * @param y  the y-coordinate.
1160     */
1161    public void paintIcon(Component c, Graphics g, int x, int y) 
1162    {
1163      Color savedColor = g.getColor();
1164      AbstractButton b = (AbstractButton) c;
1165      
1166      // fill the interior
1167      if (b.getModel().isPressed())
1168        // FIXME: also need to take into account whether the internal frame is
1169        // selected
1170        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1171      else
1172        g.setColor(MetalLookAndFeel.getPrimaryControl());
1173      g.fillRect(x + 2, y + 2, 10, 10);
1174      
1175      // draw the outline box and the cross
1176      if (b.getModel().isPressed())
1177        g.setColor(MetalLookAndFeel.getBlack());
1178      else
1179        {
1180          // FIXME: also need to take into account whether the internal frame is
1181          // selected
1182          boolean selected = true;
1183          if (selected)
1184            g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1185          else
1186            g.setColor(MetalLookAndFeel.getControlDarkShadow());
1187        }
1188      g.drawLine(x + 1, y + 1, x + 13, y + 1);
1189      g.drawLine(x + 1, y + 2, x + 1, y + 12);
1190      g.drawLine(x + 1, y + 13, x + 13, y + 13);
1191      g.drawLine(x + 13, y + 2, x + 13, y + 12);
1192      g.drawLine(x + 2, y + 12, x + 2, y + 12);
1193      g.drawLine(x + 12, y + 2, x + 12, y + 2);
1194      
1195      g.fillRect(x + 4, y + 4, 2, 2);
1196      g.fillRect(x + 5, y + 5, 4, 4);
1197      g.drawLine(x + 9, y + 4, x + 10, y + 4);
1198      g.drawLine(x + 9, y + 4, x + 9, y + 5);
1199      g.drawLine(x + 4, y + 9, x + 4, y + 10);
1200      g.drawLine(x + 4, y + 9, x + 5, y + 9);
1201      g.drawLine(x + 9, y + 8, x + 9, y + 10);
1202      g.drawLine(x + 8, y + 9, x + 10, y + 9);
1203      
1204      g.setColor(MetalLookAndFeel.getBlack());
1205      g.drawLine(x, y, x + 13, y);
1206      g.drawLine(x, y + 1, x, y + 13);
1207      g.drawLine(x + 3, y + 4, x + 4, y + 3);
1208      g.drawLine(x + 3, y + 9, x + 5, y + 7);
1209      g.drawLine(x + 7, y + 5, x + 9, y + 3);
1210      
1211      g.drawLine(x + 12, y + 3, x + 12, y + 11);
1212      g.drawLine(x + 3, y + 12, x + 12, y + 12);
1213      
1214      g.setColor(MetalLookAndFeel.getWhite());
1215      g.drawLine(x + 1, y + 14, x + 14, y + 14);
1216      g.drawLine(x + 14, y + 1, x + 14, y + 14);
1217      
1218      if (!b.getModel().isPressed())
1219        {
1220          g.drawLine(x + 5, y + 10, x + 5, y + 10);
1221          g.drawLine(x + 6, y + 9, x + 7, y + 9);
1222          g.drawLine(x + 10, y + 5, x + 10, y + 5);
1223          g.drawLine(x + 9, y + 6, x + 9, y + 7);
1224          g.drawLine(x + 10, y + 10, x + 11, y + 10);
1225          g.drawLine(x + 10, y + 11, x + 10, y + 11);
1226        }
1227      g.setColor(savedColor);
1228    }        
1229  }
1230
1231  /**
1232   * The icon displayed at the top-left corner of a {@link JInternalFrame}.
1233   */
1234  private static class InternalFrameDefaultMenuIcon
1235    implements Icon, UIResource, Serializable 
1236  {
1237       
1238    /**
1239     * Creates a new instance.
1240     */
1241    public InternalFrameDefaultMenuIcon() 
1242    {
1243      // Nothing to do here.
1244    }
1245    
1246    /**
1247     * Returns the width of the icon, in pixels.
1248     * 
1249     * @return The width of the icon.
1250     */
1251    public int getIconWidth() 
1252    {
1253      return 16;
1254    }
1255    
1256    /**
1257     * Returns the height of the icon, in pixels.
1258     * 
1259     * @return The height of the icon.
1260     */
1261    public int getIconHeight() 
1262    {
1263      return 16;
1264    }
1265    
1266    /**
1267     * Paints the icon at the specified location.
1268     * 
1269     * @param c  the component.
1270     * @param g  the graphics device.
1271     * @param x  the x coordinate.
1272     * @param y  the y coordinate.
1273     */
1274    public void paintIcon(Component c, Graphics g, int x, int y) 
1275    {
1276      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1277      g.fillRect(x + 1, y, 14, 2);
1278      g.fillRect(x, y + 1, 2, 14);
1279      g.fillRect(x + 1, y + 14, 14, 2);
1280      g.fillRect(x + 14, y + 1, 2, 14);
1281      g.drawLine(x + 2, y + 5, x + 14, y + 5);
1282      
1283      g.setColor(MetalLookAndFeel.getPrimaryControl());
1284      g.fillRect(x + 2, y + 2, 12, 3);
1285      
1286      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1287      g.drawLine(x + 3, y + 3, x + 3, y + 3);
1288      g.drawLine(x + 6, y + 3, x + 6, y + 3);
1289      g.drawLine(x + 9, y + 3, x + 9, y + 3);
1290      g.drawLine(x + 12, y + 3, x + 12, y + 3);
1291
1292      g.setColor(MetalLookAndFeel.getWhite());
1293      g.fillRect(x + 2, y + 6, 12, 8);
1294      g.drawLine(x + 2, y + 2, x + 2, y + 2);
1295      g.drawLine(x + 5, y + 2, x + 5, y + 2);
1296      g.drawLine(x + 8, y + 2, x + 8, y + 2);
1297      g.drawLine(x + 11, y + 2, x + 11, y + 2);
1298    }        
1299  }
1300
1301  /**
1302   * An icon used in the title frame of a {@link JInternalFrame}.  When you 
1303   * maximise an internal frame, this icon will replace the 'maximise' icon to
1304   * provide a 'restore' option.
1305   */
1306  private static class InternalFrameAltMaximizeIcon
1307    implements Icon, UIResource, Serializable 
1308  {
1309    /** The icon size in pixels. */
1310    private int size;
1311    
1312    /**
1313     * Creates a new icon.
1314     * 
1315     * @param size  the icon size in pixels.
1316     */
1317    public InternalFrameAltMaximizeIcon(int size) 
1318    {
1319      this.size = size;
1320    }
1321    
1322    /**
1323     * Returns the width of the icon, in pixels.
1324     * 
1325     * @return The width of the icon.
1326     */
1327    public int getIconWidth() 
1328    {
1329      return size;
1330    }
1331    
1332    /**
1333     * Returns the height of the icon, in pixels.
1334     * 
1335     * @return The height of the icon.
1336     */
1337    public int getIconHeight() 
1338    {
1339      return size;
1340    }
1341    
1342    /**
1343     * Paints the icon at the specified location.
1344     * 
1345     * @param c  the component.
1346     * @param g  the graphics device.
1347     * @param x  the x coordinate.
1348     * @param y  the y coordinate.
1349     */
1350    public void paintIcon(Component c, Graphics g, int x, int y) 
1351    {
1352      Color savedColor = g.getColor();
1353
1354      AbstractButton b = (AbstractButton) c;
1355
1356      // fill the small box interior
1357      if (b.getModel().isPressed())
1358        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1359      else
1360        g.setColor(MetalLookAndFeel.getPrimaryControl());
1361      g.fillRect(x + 2, y + 6, 7, 7);
1362      
1363      
1364      if (b.getModel().isPressed())
1365        g.setColor(MetalLookAndFeel.getBlack());
1366      else
1367        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1368        
1369      g.drawLine(x + 12, y + 1, x + 13, y + 1);
1370      g.drawLine(x + 11, y + 2, x + 12, y + 2);
1371      g.drawLine(x + 10, y + 3, x + 11, y + 3);
1372      g.drawLine(x + 8, y + 2, x + 8, y + 3);
1373      g.fillRect(x + 8, y + 4, 3, 3);
1374      g.drawLine(x + 11, y + 6, x + 12, y + 6);
1375      
1376      g.drawLine(x + 1, y + 5, x + 5, y + 5);
1377      g.drawLine(x + 1, y + 6, x + 1, y + 12);
1378      g.drawLine(x + 9, y + 9, x + 9, y + 12);
1379      g.drawLine(x + 1, y + 13, x + 9, y + 13);
1380      
1381      g.drawLine(x + 2, y + 12, x + 2, y + 12);
1382      
1383      g.setColor(MetalLookAndFeel.getBlack());
1384      g.drawLine(x + 12, y, x + 9, y + 3);
1385      g.drawLine(x + 7, y + 1, x + 8, y + 1);
1386      g.drawLine(x + 7, y + 2, x + 7, y + 6);
1387      g.drawLine(x + 11, y + 5, x + 12, y + 5);
1388      g.drawLine(x, y + 4, x + 5, y + 4);
1389      g.drawLine(x, y + 5, x, y + 13);
1390      g.drawLine(x + 3, y + 12, x + 8, y + 12);
1391      g.drawLine(x + 8, y + 8, x + 8, y + 11);
1392      g.drawLine(x + 9, y + 8, x + 9, y + 8);
1393      
1394      g.setColor(MetalLookAndFeel.getWhite());
1395      g.drawLine(x + 9, y + 2, x + 9, y + 2);
1396      g.drawLine(x + 11, y + 4, x + 13, y + 2);
1397      g.drawLine(x + 13, y + 6, x + 13, y + 6);
1398      g.drawLine(x + 8, y + 7, x + 13, y + 7);
1399      g.drawLine(x + 6, y + 5, x + 6, y + 5);
1400      g.drawLine(x + 10, y + 8, x + 10, y + 13);
1401      g.drawLine(x + 1, y + 14, x + 10, y + 14);
1402      
1403      if (!b.getModel().isPressed())
1404        {
1405          g.drawLine(x + 2, y + 6, x + 6, y + 6);
1406          g.drawLine(x + 2, y + 6, x + 2, y + 11);
1407        }
1408      
1409      g.setColor(savedColor);
1410    }        
1411  }
1412  
1413  /**
1414   * An icon used for the 'maximize' button in the title frame of a 
1415   * {@link JInternalFrame}.
1416   */
1417  private static class InternalFrameMaximizeIcon 
1418    implements Icon, UIResource, Serializable
1419  {
1420    
1421    /**
1422     * Creates a new instance.
1423     */
1424    public InternalFrameMaximizeIcon() 
1425    {
1426      // Nothing to do here.
1427    }
1428    
1429    /**
1430     * Returns the width of the icon, in pixels.
1431     * 
1432     * @return The width of the icon.
1433     */
1434    public int getIconWidth() 
1435    {
1436      return 16;
1437    }
1438    
1439    /**
1440     * Returns the height of the icon, in pixels.
1441     * 
1442     * @return The height of the icon.
1443     */
1444    public int getIconHeight() 
1445    {
1446      return 16;
1447    }
1448    
1449    /**
1450     * Paints the icon at the specified location.
1451     * 
1452     * @param c  the component.
1453     * @param g  the graphics device.
1454     * @param x  the x coordinate.
1455     * @param y  the y coordinate.
1456     */
1457    public void paintIcon(Component c, Graphics g, int x, int y) 
1458    {
1459      Color savedColor = g.getColor();
1460      
1461      AbstractButton b = (AbstractButton) c;
1462      
1463      // fill the interior
1464      if (b.getModel().isPressed())
1465        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1466      else
1467        g.setColor(MetalLookAndFeel.getPrimaryControl());
1468      g.fillRect(x + 2, y + 6, 7, 7);
1469
1470      if (b.getModel().isPressed())
1471        g.setColor(MetalLookAndFeel.getBlack());
1472      else
1473        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1474          
1475      g.drawLine(x + 9, y + 1, x + 10, y + 1);
1476      g.fillRect(x + 11, y + 1, 3, 3);
1477      g.fillRect(x + 12, y + 4, 2, 2);
1478      g.drawLine(x + 10, y + 3, x + 10, y + 3);
1479      g.drawLine(x + 9, y + 4, x + 10, y + 4);
1480      g.drawLine(x + 1, y + 5, x + 9, y + 5);
1481      g.drawLine(x + 1, y + 6, x + 1, y + 12);
1482      g.drawLine(x + 9, y + 6, x + 9, y + 12);
1483      g.drawLine(x + 1, y + 13, x + 9, y + 13);
1484      
1485      // fill
1486      g.drawLine(x + 7, y + 6, x + 8, y + 6);
1487      g.drawLine(x + 6, y + 7, x + 8, y + 7);
1488      g.drawLine(x + 5, y + 8, x + 6, y + 8);
1489      g.drawLine(x + 4, y + 9, x + 5, y + 9);
1490      g.drawLine(x + 3, y + 10, x + 4, y + 10);
1491      g.drawLine(x + 2, y + 11, x + 3, y + 11);
1492      g.drawLine(x + 2, y + 12, x + 4, y + 12);
1493      g.drawLine(x + 8, y + 8, x + 8, y + 8);
1494      
1495      // draw black
1496      g.setColor(MetalLookAndFeel.getBlack());
1497      g.drawLine(x + 8, y, x + 13, y);
1498      g.drawLine(x + 8, y + 1, x + 8, y + 1);
1499      g.drawLine(x + 10, y + 2, x + 9, y + 3);
1500      g.drawLine(x, y + 4, x + 8, y + 4);
1501      g.drawLine(x, y + 5, x, y + 13);
1502      
1503      g.drawLine(x + 2, y + 10, x + 6, y + 6);
1504      g.drawLine(x + 8, y + 9, x + 8, y + 11);
1505      g.drawLine(x + 5, y + 12, x + 8, y + 12);
1506      
1507      // draw white
1508      g.setColor(MetalLookAndFeel.getWhite());
1509      if (!b.getModel().isPressed())
1510        {
1511          g.drawLine(x + 2, y + 6, x + 5, y + 6);
1512          g.drawLine(x + 2, y + 7, x + 2, y + 9);
1513          g.drawLine(x + 4, y + 11, x + 7, y + 8);
1514        }
1515      
1516      g.drawLine(x + 1, y + 14, x + 10, y + 14);
1517      g.drawLine(x + 10, y + 5, x + 10, y + 13);
1518      
1519      g.drawLine(x + 9, y + 2, x + 9, y + 2);
1520      g.drawLine(x + 11, y + 4, x + 11, y + 5);
1521      g.drawLine(x + 13, y + 6, x + 14, y + 6);
1522      g.drawLine(x + 14, y + 1, x + 14, y + 5);
1523      g.setColor(savedColor);
1524    }        
1525  }
1526
1527  /**
1528   * An icon used in the title frame of a {@link JInternalFrame}.
1529   */
1530  private static class InternalFrameMinimizeIcon 
1531    implements Icon, UIResource, Serializable
1532  {
1533  
1534    /**
1535     * Creates a new instance.
1536     */
1537    public InternalFrameMinimizeIcon() 
1538    {
1539      // Nothing to do here.
1540    }
1541    
1542    /**
1543     * Returns the width of the icon, in pixels.
1544     * 
1545     * @return The width of the icon.
1546     */
1547    public int getIconWidth() 
1548    {
1549      return 16;
1550    }
1551    
1552    /**
1553     * Returns the height of the icon, in pixels.
1554     * 
1555     * @return The height of the icon.
1556     */
1557    public int getIconHeight() 
1558    {
1559      return 16;
1560    }
1561    
1562    /**
1563     * Paints the icon at the specified location.
1564     * 
1565     * @param c  the component.
1566     * @param g  the graphics device.
1567     * @param x  the x coordinate.
1568     * @param y  the y coordinate.
1569     */
1570    public void paintIcon(Component c, Graphics g, int x, int y) 
1571    {
1572      Color savedColor = g.getColor();
1573      
1574      AbstractButton b = (AbstractButton) c;
1575      
1576      if (b.getModel().isPressed())
1577        g.setColor(MetalLookAndFeel.getBlack());
1578      else
1579        // FIXME: here the color depends on whether or not the internal frame 
1580        // is selected 
1581        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1582      
1583      g.drawLine(x + 12, y + 1, x + 13, y + 1);
1584      g.drawLine(x + 11, y + 2, x + 12, y + 2);
1585      g.drawLine(x + 10, y + 3, x + 11, y + 3);
1586      g.drawLine(x + 8, y + 2, x + 8, y + 3);
1587      g.fillRect(x + 8, y + 4, 3, 3);
1588      g.drawLine(x + 11, y + 6, x + 12, y + 6);
1589      
1590      g.drawLine(x + 1, y + 8, x + 6, y + 8);
1591      g.drawLine(x + 1, y + 9, x + 1, y + 12);
1592      g.drawLine(x + 6, y + 9, x + 6, y + 12);
1593      g.drawLine(x + 1, y + 13, x + 6, y + 13);
1594      
1595      g.drawLine(x + 5, y + 9, x + 5, y + 9);
1596      g.drawLine(x + 2, y + 12, x + 2, y + 12);
1597      
1598      g.setColor(MetalLookAndFeel.getBlack());
1599      g.drawLine(x + 12, y, x + 9, y + 3);
1600      g.drawLine(x + 7, y + 1, x + 8, y + 1);
1601      g.drawLine(x + 7, y + 2, x + 7, y + 6);
1602      g.drawLine(x, y + 7, x + 6, y + 7);
1603      g.drawLine(x, y + 8, x, y + 13);
1604      g.drawLine(x + 3, y + 12, x + 5, y + 12);
1605      g.drawLine(x + 5, y + 10, x + 5, y + 11);
1606      g.drawLine(x + 11, y + 5, x + 12, y + 5);
1607      
1608      g.setColor(MetalLookAndFeel.getWhite());
1609      g.drawLine(x + 9, y + 2, x + 9, y + 2);
1610      g.drawLine(x + 11, y + 4, x + 13, y + 2);
1611      g.drawLine(x + 13, y + 6, x + 13, y + 6);
1612      g.drawLine(x + 8, y + 7, x + 13, y + 7);
1613      g.drawLine(x + 7, y + 9, x + 7, y + 13);
1614      g.drawLine(x + 1, y + 14, x + 7, y + 14);
1615
1616      if (b.getModel().isPressed())
1617        {
1618          g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1619          g.fillRect(x + 2, y + 9, 3, 3);
1620        }
1621      else
1622        {
1623          g.drawLine(x + 2, y + 9, x + 4, y + 9);
1624          g.drawLine(x + 2, y + 10, x + 2, y + 11);
1625        }
1626
1627      g.setColor(savedColor);
1628    }        
1629  }
1630
1631  /**
1632   * The icon used to display the thumb control on a horizontally oriented
1633   * {@link JSlider} component.
1634   */
1635  private static class VerticalSliderThumbIcon 
1636    implements Icon, UIResource, Serializable
1637  {
1638    /**
1639     * This mask is used to paint the gradient in the shape of the thumb.
1640     */
1641    int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12},
1642                                         {0, 12}, {0, 12}, {0, 12}, {1, 11},
1643                                         {2, 10}, {3, 9}, {4, 8}, {5, 7},
1644                                         {6, 6}};
1645
1646    /**
1647     * Creates a new instance.
1648     */
1649    public VerticalSliderThumbIcon() 
1650    {
1651      // Nothing to do here.
1652    }
1653    
1654    /**
1655     * Returns the width of the icon, in pixels.
1656     * 
1657     * @return The width of the icon.
1658     */
1659    public int getIconWidth() 
1660    {
1661      return 16;
1662    }
1663    
1664    /**
1665     * Returns the height of the icon, in pixels.
1666     * 
1667     * @return The height of the icon.
1668     */
1669    public int getIconHeight() 
1670    {
1671      return 15;
1672    }
1673    
1674    /**
1675     * Paints the icon taking into account whether the slider control has the
1676     * focus or not.
1677     * 
1678     * @param c  the slider (must be a non-<code>null</code> instance of
1679     *           {@link JSlider}.
1680     * @param g  the graphics device.
1681     * @param x  the x-coordinate.
1682     * @param y  the y-coordinate.
1683     */
1684    public void paintIcon(Component c, Graphics g, int x, int y) 
1685    {
1686      boolean enabled = false;
1687      boolean focus = false;
1688      if (c != null)
1689        {
1690          enabled = c.isEnabled();
1691          focus = c.hasFocus();    
1692        }
1693      
1694      // draw the outline
1695      if (enabled) 
1696        g.setColor(MetalLookAndFeel.getBlack());
1697      else
1698        g.setColor(MetalLookAndFeel.getControlDarkShadow());
1699      g.drawLine(x + 1, y, x + 7, y);
1700      g.drawLine(x + 8, y, x + 15, y + 7);
1701      g.drawLine(x + 14, y + 8, x + 8, y + 14);
1702      g.drawLine(x + 8, y + 14, x + 1, y + 14);
1703      g.drawLine(x, y + 13, x, y + 1);
1704      
1705//    The following is commented out until the masking for the gradient painting 
1706//    is working correctly
1707//      // Fill the icon.
1708//      if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme
1709//          && enabled)
1710//        {
1711//          String gradient;
1712//          if (focus)
1713//            gradient = "Slider.focusGradient";
1714//          else
1715//            gradient = "Slider.gradient";
1716//          MetalUtils.paintGradient(g, x + 2, y + 1, 13, 12,
1717//                                   SwingConstants.HORIZONTAL, gradient,
1718//                                   gradientMask);
1719//        }
1720//      else
1721        {
1722          if (focus)
1723            g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
1724          else
1725            g.setColor(MetalLookAndFeel.getControl());
1726          g.fillRect(x + 2, y + 1, 7, 13);
1727          g.drawLine(x + 9, y + 2, x + 9, y + 12);
1728          g.drawLine(x + 10, y + 3, x + 10, y + 11);
1729          g.drawLine(x + 11, y + 4, x + 11, y + 10);
1730          g.drawLine(x + 12, y + 5, x + 12, y + 9);
1731          g.drawLine(x + 13, y + 6, x + 13, y + 8);
1732          g.drawLine(x + 14, y + 7, x + 14, y + 7);
1733        }
1734
1735      // if the slider is enabled, draw dots and highlights
1736      if (enabled
1737          && ! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme))
1738        {
1739          if (focus)
1740            g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
1741          else
1742            g.setColor(MetalLookAndFeel.getBlack());
1743          g.drawLine(x + 3, y + 3, x + 3, y + 3);
1744          g.drawLine(x + 3, y + 7, x + 3, y + 7);
1745          g.drawLine(x + 3, y + 11, x + 3, y + 11);
1746
1747          g.drawLine(x + 5, y + 5, x + 5, y + 5);
1748          g.drawLine(x + 5, y + 9, x + 5, y + 9);
1749
1750          g.drawLine(x + 7, y + 3, x + 7, y + 3);
1751          g.drawLine(x + 7, y + 7, x + 7, y + 7);
1752          g.drawLine(x + 7, y + 11, x + 7, y + 11);
1753
1754          // draw highlights
1755          if (focus)
1756            g.setColor(MetalLookAndFeel.getPrimaryControl());
1757          else
1758            g.setColor(MetalLookAndFeel.getWhite());
1759          g.drawLine(x + 1, y + 1, x + 8, y + 1);
1760          g.drawLine(x + 1, y + 2, x + 1, y + 13);
1761          g.drawLine(x + 2, y + 2, x + 2, y + 2);
1762          g.drawLine(x + 2, y + 6, x + 2, y + 6);
1763          g.drawLine(x + 2, y + 10, x + 2, y + 10);
1764
1765          g.drawLine(x + 4, y + 4, x + 4, y + 4);
1766          g.drawLine(x + 4, y + 8, x + 4, y + 8);
1767
1768          g.drawLine(x + 6, y + 2, x + 6, y + 2);
1769          g.drawLine(x + 6, y + 6, x + 6, y + 6);
1770          g.drawLine(x + 6, y + 10, x + 6, y + 10);
1771        
1772        }
1773    }        
1774  }
1775    
1776  /**
1777   * A tree control icon.  This icon can be in one of two states: expanded and
1778   * collapsed.
1779   */
1780  public static class TreeControlIcon implements Icon, Serializable
1781  {
1782    
1783    /** ???. */
1784    protected boolean isLight;
1785    
1786    /** A flag that controls whether or not the icon is collapsed. */
1787    private boolean collapsed;
1788    
1789    /**
1790     * Creates a new icon.
1791     * 
1792     * @param isCollapsed  a flag that controls whether the icon is in the
1793     *                     collapsed state or the expanded state.
1794     */
1795    public TreeControlIcon(boolean isCollapsed) 
1796    {
1797      collapsed = isCollapsed;
1798    }
1799    
1800    /**
1801     * Returns the width of the icon, in pixels.
1802     * 
1803     * @return The width of the icon.
1804     */
1805    public int getIconWidth() 
1806    {
1807      return 18;
1808    }
1809    /**
1810     * Returns the height of the icon, in pixels.
1811     * 
1812     * @return The height of the icon.
1813     */
1814    public int getIconHeight() 
1815    {
1816      return 18;
1817    }
1818    
1819    /**
1820     * Paints the icon at the location (x, y).
1821     * 
1822     * @param c the component.
1823     * @param g the graphics device.
1824     * @param x the x coordinate.
1825     * @param y the y coordinate.
1826     */
1827    public void paintIcon(Component c, Graphics g, int x, int y)
1828    {
1829      // TODO: pick up appropriate UI colors
1830      Color dark = new Color(99, 130, 191);
1831      Color light = new Color(163, 184, 204);
1832      Color white = Color.white;
1833
1834      x += 8;
1835      y += 6;
1836
1837      final int w = 6;
1838      final int wHalf = (w >> 2);
1839      g.setColor(light);
1840      g.drawOval(x, y, w, w);
1841      g.setColor(dark);
1842      g.fillOval(x + 1, y + 1, w - 1, w - 1);
1843      
1844      if (collapsed)
1845        g.fillRect(x + w, y + wHalf + 1, w, 2);
1846      else
1847        g.fillRect(x + wHalf + 1, y + w, 2, w);
1848      
1849      g.setColor(white);
1850      g.fillRect(x + wHalf + 1, y + wHalf + 1, 2, 2);
1851
1852    } 
1853    
1854    /**
1855     * Simply calls {@link #paintIcon(Component, Graphics, int, int)}.
1856     * 
1857     * @param c  the component.
1858     * @param g  the graphics device.
1859     * @param x  the x coordinate.
1860     * @param y  the y coordinate.
1861     */
1862    public void paintMe(Component c, Graphics g, int x, int y) 
1863    {
1864      paintIcon(c, g, x, y);  
1865    }
1866  }
1867    
1868  /**
1869   * A tree folder icon.
1870   */
1871  public static class TreeFolderIcon extends FolderIcon16
1872  {
1873    /**
1874     * Creates a new instance.
1875     */
1876    public TreeFolderIcon() 
1877    {
1878      // Nothing to do here.
1879    }
1880    
1881    /**
1882     * Returns the additional height for this icon, in this case <code>2</code>
1883     * pixels.
1884     * 
1885     * @return <code>2</code>.
1886     */
1887    public int getAdditionalHeight() 
1888    {
1889      return 2;
1890    }
1891    
1892    /**
1893     * Returns the vertical shift, in pixels, applied when painting the icon.  
1894     * This overridden method returns <code>-1</code>.
1895     * 
1896     * @return The shift.
1897     */
1898    public int getShift() 
1899    {
1900      return -1;
1901    }
1902  }
1903    
1904  /**
1905   * A tree leaf icon.
1906   */
1907  public static class TreeLeafIcon extends FileIcon16
1908  {
1909    /**
1910     * Creates a new instance.
1911     */
1912    public TreeLeafIcon() 
1913    {
1914      // Nothing to do here.
1915    }
1916    
1917    /**
1918     * Returns the additional height for this icon, in this case <code>4</code>
1919     * pixels.
1920     * 
1921     * @return <code>4</code>.
1922     */
1923    public int getAdditionalHeight() 
1924    {
1925      return 4;
1926    }
1927    
1928    /**
1929     * Returns the vertical shift, in pixels, applied when painting the icon.  
1930     * This overridden method returns <code>2</code>.
1931     * 
1932     * @return The shift.
1933     */
1934    public int getShift() 
1935    {
1936      return 2;
1937    }
1938  }
1939
1940  /**
1941   * An icon representing a hard disk.
1942   * 
1943   * @see MetalIconFactory#getTreeHardDriveIcon()
1944   */
1945  private static class TreeHardDriveIcon 
1946    implements Icon, UIResource, Serializable
1947  {
1948
1949    /**
1950     * Creates a new icon instance.
1951     */
1952    public TreeHardDriveIcon() 
1953    {
1954      // Nothing to do here.
1955    }
1956
1957    /**
1958     * Returns the width of the icon, in pixels.
1959     * 
1960     * @return <code>16</code>.
1961     */
1962    public int getIconWidth() 
1963    { 
1964      return 16;
1965    }
1966
1967    /**
1968     * Returns the height of the icon, in pixels.
1969     * 
1970     * @return <code>16</code>.
1971     */
1972    public int getIconHeight()   
1973    {
1974      return 16;
1975    }
1976
1977    /**
1978     * Paints the icon at the specified location, using colors from the 
1979     * current theme.
1980     * 
1981     * @param c  the component (ignored).
1982     * @param g  the graphics device.
1983     * @param x  the x-coordinate for the top-left of the icon.
1984     * @param y  the y-coordinate for the top-left of the icon.
1985     */
1986    public void paintIcon(Component c, Graphics g, int x, int y) 
1987    {
1988      Color saved = g.getColor();
1989      g.setColor(MetalLookAndFeel.getBlack());
1990      g.drawLine(x + 1, y + 4, x + 1, y + 5);
1991      g.drawLine(x + 14, y + 4, x + 14, y + 5);
1992      g.drawLine(x + 1, y + 7, x + 1, y + 8);
1993      g.drawLine(x + 14, y + 7, x + 14, y + 8);
1994      g.drawLine(x + 1, y + 10, x + 1, y + 11);
1995      g.drawLine(x + 14, y + 10, x + 14, y + 11);
1996      
1997      g.drawLine(x + 2, y + 3, x + 3, y + 3);
1998      g.drawLine(x + 12, y + 3, x + 13, y + 3);
1999      g.drawLine(x + 2, y + 6, x + 3, y + 6);
2000      g.drawLine(x + 12, y + 6, x + 13, y + 6);
2001      g.drawLine(x + 2, y + 9, x + 3, y + 9);
2002      g.drawLine(x + 12, y + 9, x + 13, y + 9);
2003      g.drawLine(x + 2, y + 12, x + 3, y + 12);
2004      g.drawLine(x + 12, y + 12, x + 13, y + 12);
2005      
2006      g.drawLine(x + 4, y + 2, x + 11, y + 2);
2007      g.drawLine(x + 4, y + 7, x + 11, y + 7);
2008      g.drawLine(x + 4, y + 10, x + 11, y + 10);
2009      g.drawLine(x + 4, y + 13, x + 11, y + 13);
2010      
2011      g.setColor(MetalLookAndFeel.getWhite());
2012      g.fillRect(x + 4, y + 3, 2, 2);
2013      g.drawLine(x + 6, y + 4, x + 6, y + 4);
2014      g.drawLine(x + 7, y + 3, x + 9, y + 3);
2015      g.drawLine(x + 8, y + 4, x + 8, y + 4);
2016      g.drawLine(x + 11, y + 3, x + 11, y + 3);
2017      g.fillRect(x + 2, y + 4, 2, 2); 
2018      g.fillRect(x + 2, y + 7, 2, 2); 
2019      g.fillRect(x + 2, y + 10, 2, 2); 
2020      g.drawLine(x + 4, y + 6, x + 4, y + 6);
2021      g.drawLine(x + 4, y + 9, x + 4, y + 9);
2022      g.drawLine(x + 4, y + 12, x + 4, y + 12);
2023      
2024      g.setColor(MetalLookAndFeel.getControlShadow());
2025      g.drawLine(x + 13, y + 4, x + 13, y + 4);
2026      g.drawLine(x + 12, y + 5, x + 13, y + 5);
2027      g.drawLine(x + 13, y + 7, x + 13, y + 7);
2028      g.drawLine(x + 12, y + 8, x + 13, y + 8);
2029      g.drawLine(x + 13, y + 10, x + 13, y + 10);
2030      g.drawLine(x + 12, y + 11, x + 13, y + 11);
2031      
2032      g.drawLine(x + 10, y + 5, x + 10, y + 5);
2033      g.drawLine(x + 7, y + 6, x + 7, y + 6);
2034      g.drawLine(x + 9, y + 6, x + 9, y + 6);
2035      g.drawLine(x + 11, y + 6, x + 11, y + 6);
2036
2037      g.drawLine(x + 10, y + 8, x + 10, y + 8);
2038      g.drawLine(x + 7, y + 9, x + 7, y + 9);
2039      g.drawLine(x + 9, y + 9, x + 9, y + 9);
2040      g.drawLine(x + 11, y + 9, x + 11, y + 9);
2041
2042      g.drawLine(x + 10, y + 11, x + 10, y + 11);
2043      g.drawLine(x + 7, y + 12, x + 7, y + 12);
2044      g.drawLine(x + 9, y + 12, x + 9, y + 12);
2045      g.drawLine(x + 11, y + 12, x + 11, y + 12);
2046
2047      g.setColor(saved);
2048    }        
2049  }  
2050  
2051  /**
2052   * An icon representing a floppy disk.
2053   * 
2054   * @see MetalIconFactory#getTreeFloppyDriveIcon()
2055   */
2056  private static class TreeFloppyDriveIcon 
2057    implements Icon, UIResource, Serializable
2058  {
2059
2060    /**
2061     * Creates a new icon instance.
2062     */
2063    public TreeFloppyDriveIcon() 
2064    {
2065      // Nothing to do here.
2066    }
2067
2068    /**
2069     * Returns the width of the icon, in pixels.
2070     * 
2071     * @return <code>16</code>.
2072     */
2073    public int getIconWidth() 
2074    { 
2075      return 16;
2076    }
2077
2078    /**
2079     * Returns the height of the icon, in pixels.
2080     * 
2081     * @return <code>16</code>.
2082     */
2083    public int getIconHeight()   
2084    {
2085      return 16;
2086    }
2087
2088    /**
2089     * Paints the icon at the specified location, using colors from the 
2090     * current theme.
2091     * 
2092     * @param c  the component (ignored).
2093     * @param g  the graphics device.
2094     * @param x  the x-coordinate for the top-left of the icon.
2095     * @param y  the y-coordinate for the top-left of the icon.
2096     */
2097    public void paintIcon(Component c, Graphics g, int x, int y) 
2098    {
2099      Color saved = g.getColor();
2100      
2101      g.setColor(MetalLookAndFeel.getBlack());
2102      g.drawLine(x + 1, y + 1, x + 13, y + 1);
2103      g.drawLine(x + 1, y + 1, x + 1, y + 14);
2104      g.drawLine(x + 1, y + 14, x + 14, y + 14);
2105      g.drawLine(x + 14, y + 2, x + 14, y + 14);
2106      
2107      g.setColor(MetalLookAndFeel.getPrimaryControl());
2108      g.fillRect(x + 2, y + 2, 12, 12);
2109      
2110      g.setColor(MetalLookAndFeel.getControlShadow());
2111      g.fillRect(x + 5, y + 2, 6, 5);
2112      g.drawLine(x + 4, y + 8, x + 11, y + 8);
2113      g.drawLine(x + 3, y + 9, x + 3, y + 13);
2114      g.drawLine(x + 12, y + 9, x + 12, y + 13);
2115      
2116      g.setColor(MetalLookAndFeel.getWhite());
2117      g.fillRect(x + 8, y + 3, 2, 3);
2118      g.fillRect(x + 4, y + 9, 8, 5);
2119      
2120      g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
2121      g.drawLine(x + 5, y + 10, x + 9, y + 10);
2122      g.drawLine(x + 5, y + 12, x + 8, y + 12);
2123
2124      g.setColor(saved);
2125    }        
2126  }  
2127
2128  /**
2129   * An icon representing a computer.
2130   * 
2131   * @see MetalIconFactory#getTreeComputerIcon()
2132   */
2133  private static class TreeComputerIcon 
2134    implements Icon, UIResource, Serializable
2135  {
2136
2137    /**
2138     * Creates a new icon instance.
2139     */
2140    public TreeComputerIcon() 
2141    {
2142      // Nothing to do here.
2143    }
2144
2145    /**
2146     * Returns the width of the icon, in pixels.
2147     * 
2148     * @return <code>16</code>.
2149     */
2150    public int getIconWidth() 
2151    { 
2152      return 16;
2153    }
2154
2155    /**
2156     * Returns the height of the icon, in pixels.
2157     * 
2158     * @return <code>16</code>.
2159     */
2160    public int getIconHeight()   
2161    {
2162      return 16;
2163    }
2164
2165    /**
2166     * Paints the icon at the specified location, using colors from the 
2167     * current theme.
2168     * 
2169     * @param c  the component (ignored).
2170     * @param g  the graphics device.
2171     * @param x  the x-coordinate for the top-left of the icon.
2172     * @param y  the y-coordinate for the top-left of the icon.
2173     */
2174    public void paintIcon(Component c, Graphics g, int x, int y) 
2175    {
2176      Color saved = g.getColor();
2177      
2178      g.setColor(MetalLookAndFeel.getBlack());
2179      g.drawLine(x + 3, y + 1, x + 12, y + 1);
2180      g.drawLine(x + 2, y + 2, x + 2, y + 8);
2181      g.drawLine(x + 13, y + 2, x + 13, y + 8);
2182      g.drawLine(x + 3, y + 9, x + 3, y + 9);
2183      g.drawLine(x + 12, y + 9, x + 12, y + 9);
2184      g.drawRect(x + 1, y + 10, 13, 4);
2185      g.drawLine(x + 5, y + 3, x + 10, y + 3);
2186      g.drawLine(x + 5, y + 8, x + 10, y + 8);
2187      g.drawLine(x + 4, y + 4, x + 4, y + 7);
2188      g.drawLine(x + 11, y + 4, x + 11, y + 7);
2189
2190      g.setColor(MetalLookAndFeel.getPrimaryControl());
2191      g.fillRect(x + 5, y + 4, 6, 4);
2192      
2193      g.setColor(MetalLookAndFeel.getControlShadow());
2194      g.drawLine(x + 6, y + 12, x + 8, y + 12);
2195      g.drawLine(x + 10, y + 12, x + 12, y + 12);
2196      g.setColor(saved);
2197    }        
2198  }  
2199    
2200  /** The icon returned by {@link #getCheckBoxIcon()}. */
2201  private static Icon checkBoxIcon;
2202  
2203  /** The icon returned by {@link #getCheckBoxMenuItemIcon()}. */
2204  private static Icon checkBoxMenuItemIcon;
2205  
2206  /** The icon returned by {@link #getFileChooserDetailViewIcon()}. */
2207  private static Icon fileChooserDetailViewIcon;
2208
2209  /** The icon returned by {@link #getFileChooserHomeFolderIcon()}. */
2210  private static Icon fileChooserHomeFolderIcon;
2211
2212  /** The icon returned by {@link #getFileChooserListViewIcon()}. */
2213  private static Icon fileChooserListViewIcon;
2214
2215  /** The icon returned by {@link #getFileChooserNewFolderIcon()}. */
2216  private static Icon fileChooserNewFolderIcon;
2217
2218  /** The icon returned by {@link #getFileChooserUpFolderIcon()}. */
2219  private static Icon fileChooserUpFolderIcon;
2220
2221  /** The cached RadioButtonIcon instance. */
2222  private static RadioButtonIcon radioButtonIcon;
2223
2224  /** The icon returned by {@link #getRadioButtonMenuItemIcon()}. */
2225  private static Icon radioButtonMenuItemIcon;
2226
2227  /** The icon returned by {@link #getInternalFrameDefaultMenuIcon()}. */
2228  private static Icon internalFrameDefaultMenuIcon;
2229
2230  /** The icon returned by {@link #getTreeComputerIcon()}. */
2231  private static Icon treeComputerIcon;
2232  
2233  /** The icon instance returned by {@link #getTreeFloppyDriveIcon()}. */
2234  private static Icon treeFloppyDriveIcon;
2235  
2236  /** The icon instance returned by {@link #getTreeHardDriveIcon()}. */
2237  private static Icon treeHardDriveIcon;
2238  
2239  /** The icon instance returned by {@link #getHorizontalSliderThumbIcon()}. */
2240  private static Icon horizontalSliderThumbIcon;
2241
2242  /** The icon instance returned by {@link #getVerticalSliderThumbIcon()}. */
2243  private static Icon verticalSliderThumbIcon;
2244  
2245  /**
2246   * Creates a new instance.  All the methods are static, so creating an 
2247   * instance isn't necessary.
2248   */
2249  public MetalIconFactory() 
2250  {
2251    // Nothing to do here.
2252  }
2253
2254  /**
2255   * Returns an icon for use when rendering the {@link JCheckBox} component.
2256   * 
2257   * @return A check box icon.
2258   * 
2259   * @since 1.3
2260   */
2261  public static Icon getCheckBoxIcon() 
2262  {
2263    if (checkBoxIcon == null)
2264      checkBoxIcon = new MetalCheckBoxIcon();
2265    return checkBoxIcon;
2266  }
2267  
2268  /**
2269   * Returns an icon for use when rendering the {@link JCheckBoxMenuItem} 
2270   * component.
2271   * 
2272   * @return An icon.
2273   */
2274  public static Icon getCheckBoxMenuItemIcon() 
2275  {
2276    if (checkBoxMenuItemIcon == null)
2277      checkBoxMenuItemIcon = new CheckBoxMenuItemIcon();
2278    return checkBoxMenuItemIcon;
2279  }
2280
2281  /**
2282   * Returns an icon for use by the {@link JFileChooser} component.
2283   * 
2284   * @return An icon.
2285   */
2286  public static Icon getFileChooserDetailViewIcon() 
2287  {
2288    if (fileChooserDetailViewIcon == null)
2289      fileChooserDetailViewIcon = new FileChooserDetailViewIcon();
2290    return fileChooserDetailViewIcon;
2291  }
2292    
2293  /**
2294   * Returns an icon for use by the {@link JFileChooser} component.
2295   * 
2296   * @return An icon.
2297   */
2298  public static Icon getFileChooserHomeFolderIcon() 
2299  {
2300    if (fileChooserHomeFolderIcon == null)
2301      fileChooserHomeFolderIcon = new FileChooserHomeFolderIcon();
2302    return fileChooserHomeFolderIcon;        
2303  }
2304    
2305  /**
2306   * Returns an icon for use by the {@link JFileChooser} component.
2307   * 
2308   * @return An icon.
2309   */
2310  public static Icon getFileChooserListViewIcon() 
2311  {
2312    if (fileChooserListViewIcon == null)
2313      fileChooserListViewIcon = new FileChooserListViewIcon();
2314    return fileChooserListViewIcon;
2315  }
2316    
2317  /**
2318   * Returns an icon for use by the {@link JFileChooser} component.
2319   * 
2320   * @return An icon.
2321   */
2322  public static Icon getFileChooserNewFolderIcon() 
2323  {
2324    if (fileChooserNewFolderIcon == null)
2325      fileChooserNewFolderIcon = new FileChooserNewFolderIcon();
2326    return fileChooserNewFolderIcon;
2327  }
2328    
2329  /**
2330   * Returns an icon for use by the {@link JFileChooser} component.
2331   * 
2332   * @return An icon.
2333   */
2334  public static Icon getFileChooserUpFolderIcon() 
2335  {
2336    if (fileChooserUpFolderIcon == null)
2337      fileChooserUpFolderIcon = new FileChooserUpFolderIcon();
2338    return fileChooserUpFolderIcon;
2339  }
2340
2341  /**
2342   * Returns an icon for RadioButtons in the Metal L&amp;F.
2343   *
2344   * @return an icon for RadioButtons in the Metal L&amp;F
2345   */
2346  public static Icon getRadioButtonIcon()
2347  {
2348    if (radioButtonIcon == null)
2349      radioButtonIcon = new RadioButtonIcon();
2350    return radioButtonIcon;
2351  }
2352
2353  /**
2354   * Creates a new instance of the icon used in a {@link JRadioButtonMenuItem}.
2355   * 
2356   * @return A new icon instance.
2357   */
2358  public static Icon getRadioButtonMenuItemIcon() 
2359  {
2360    if (radioButtonMenuItemIcon == null)
2361      radioButtonMenuItemIcon = new RadioButtonMenuItemIcon();
2362    return radioButtonMenuItemIcon;
2363  }
2364
2365  /**
2366   * Returns the icon used to display the thumb for a horizontally oriented
2367   * {@link JSlider}.
2368   * 
2369   * @return The icon.
2370   */
2371  public static Icon getHorizontalSliderThumbIcon() 
2372  {
2373    if (horizontalSliderThumbIcon == null)
2374      horizontalSliderThumbIcon = new HorizontalSliderThumbIcon();
2375    return horizontalSliderThumbIcon;
2376  }
2377    
2378  /**
2379   * Creates a new icon used to represent the 'close' button in the title
2380   * pane of a {@link JInternalFrame}.
2381   * 
2382   * @param size  the icon size.
2383   * 
2384   * @return A close icon.
2385   */
2386  public static Icon getInternalFrameCloseIcon(int size) 
2387  {
2388    return new InternalFrameCloseIcon(size);
2389  }
2390
2391  /**
2392   * Creates a new icon for the menu in a {@link JInternalFrame}.  This is the
2393   * icon displayed at the top left of the frame.
2394   * 
2395   * @return A menu icon.
2396   */
2397  public static Icon getInternalFrameDefaultMenuIcon() 
2398  {
2399    if (internalFrameDefaultMenuIcon == null)
2400      internalFrameDefaultMenuIcon = new InternalFrameDefaultMenuIcon();
2401    return internalFrameDefaultMenuIcon;
2402  }
2403  
2404  /**
2405   * Creates a new icon for the 'maximize' button in a {@link JInternalFrame}.
2406   * 
2407   * @param size  the icon size in pixels.
2408   * 
2409   * @return The icon.
2410   * 
2411   * @see #getInternalFrameAltMaximizeIcon(int)
2412   */
2413  public static Icon getInternalFrameMaximizeIcon(int size) 
2414  {
2415    return new InternalFrameMaximizeIcon();
2416  }
2417    
2418  /**
2419   * Returns the icon used for the minimize button in the frame title for a
2420   * {@link JInternalFrame}.
2421   * 
2422   * @param size  the icon size in pixels (ignored by this implementation).
2423   * 
2424   * @return The icon.
2425   */
2426  public static Icon getInternalFrameMinimizeIcon(int size) 
2427  {
2428    return new InternalFrameMinimizeIcon();
2429  }
2430
2431  /**
2432   * Creates a new icon for the 'restore' button in a {@link JInternalFrame}
2433   * that has been maximised.
2434   * 
2435   * @param size  the icon size in pixels.
2436   * 
2437   * @return The icon.
2438   * 
2439   * @see #getInternalFrameMaximizeIcon(int)
2440   */
2441  public static Icon getInternalFrameAltMaximizeIcon(int size) 
2442  {
2443    return new InternalFrameAltMaximizeIcon(size);
2444  }
2445  
2446  /**
2447   * Returns the icon used to display the thumb for a vertically oriented
2448   * {@link JSlider}.
2449   * 
2450   * @return The icon.
2451   */
2452  public static Icon getVerticalSliderThumbIcon() 
2453  {
2454    if (verticalSliderThumbIcon == null)
2455      verticalSliderThumbIcon = new VerticalSliderThumbIcon();
2456    return verticalSliderThumbIcon;
2457  }
2458    
2459  /**
2460   * Creates and returns a new tree folder icon.
2461   * 
2462   * @return A new tree folder icon.
2463   */  
2464  public static Icon getTreeFolderIcon() 
2465  {
2466    return new TreeFolderIcon();
2467  }
2468    
2469  /**
2470   * Creates and returns a new tree leaf icon.
2471   * 
2472   * @return A new tree leaf icon.
2473   */
2474  public static Icon getTreeLeafIcon() 
2475  {
2476    return new TreeLeafIcon();
2477  }
2478  
2479  /**
2480   * Creates and returns a tree control icon.
2481   * 
2482   * @param isCollapsed  a flag that controls whether the icon is in the 
2483   *                     collapsed or expanded state.
2484   * 
2485   * @return A tree control icon.
2486   */
2487  public static Icon getTreeControlIcon(boolean isCollapsed) 
2488  {
2489    return new TreeControlIcon(isCollapsed);
2490  }
2491
2492  /**
2493   * Returns a <code>16x16</code> icon representing a computer.
2494   * 
2495   * @return The icon.
2496   */
2497  public static Icon getTreeComputerIcon() 
2498  {
2499    if (treeComputerIcon == null)
2500      treeComputerIcon = new TreeComputerIcon();
2501    return treeComputerIcon;        
2502  }
2503    
2504  /**
2505   * Returns a <code>16x16</code> icon representing a floppy disk.
2506   * 
2507   * @return The icon.
2508   */
2509  public static Icon getTreeFloppyDriveIcon() 
2510  {
2511    if (treeFloppyDriveIcon == null)
2512      treeFloppyDriveIcon = new TreeFloppyDriveIcon();
2513    return treeFloppyDriveIcon;
2514  }
2515    
2516  /**
2517   * Returns a <code>16x16</code> icon representing a hard disk.
2518   * 
2519   * @return The icon.
2520   */
2521  public static Icon getTreeHardDriveIcon() 
2522  {
2523    if (treeHardDriveIcon == null)
2524      treeHardDriveIcon = new TreeHardDriveIcon();
2525    return treeHardDriveIcon;
2526  }
2527
2528  /**
2529   * Returns a new instance of a 4 x 8 icon showing a small black triangle that
2530   * points to the right.  This is displayed in menu items that have a 
2531   * sub menu.
2532   * 
2533   * @return The icon.
2534   */
2535  public static Icon getMenuArrowIcon()
2536  {
2537    if (menuArrow == null)
2538      menuArrow = new Icon()
2539      {
2540        public int getIconHeight()
2541        {
2542          return 8;
2543        }
2544
2545        public int getIconWidth()
2546        {
2547          return 4;
2548        }
2549
2550        public void paintIcon(Component c, Graphics g, int x, int y)
2551        {
2552          Color saved = g.getColor();
2553          g.setColor(Color.BLACK);
2554          for (int i = 0; i < 4; i++)
2555            g.drawLine(x + i, y + i, x + i, y + 7 - i);
2556          g.setColor(saved);
2557        }
2558      };
2559    return menuArrow;
2560  }
2561  
2562  /**
2563   * Returns a new instance of a 4 x 8 icon showing a small black triangle that
2564   * points to the right. This is displayed in menu items that have a sub menu.
2565   * 
2566   * @return The icon.
2567   */
2568  public static Icon getMenuItemArrowIcon()
2569  {
2570    if (menuItemArrow == null)
2571      menuItemArrow = new Icon()
2572      {
2573        public int getIconHeight()
2574        {
2575          return 8;
2576        }
2577
2578        public int getIconWidth()
2579        {
2580          return 4;
2581        }
2582
2583        public void paintIcon(Component c, Graphics g, int x, int y)
2584        {
2585          Color saved = g.getColor();
2586          g.setColor(Color.BLACK);
2587          for (int i = 0; i < 4; i++)
2588            g.drawLine(x + i, y + i, x + i, y + 7 - i);
2589          g.setColor(saved);
2590        }
2591      };
2592    return menuItemArrow;
2593  }
2594  
2595  /**
2596   * Returns a new instance of a 13 x 13 icon showing a small black check mark.
2597   * 
2598   * @return The icon.
2599   */
2600  public static Icon getMenuItemCheckIcon()
2601  {
2602    return new Icon()
2603    {
2604      public int getIconHeight()
2605      {
2606        return 13;
2607      }
2608
2609      public int getIconWidth()
2610      {
2611        return 13;
2612      }
2613
2614      public void paintIcon(Component c, Graphics g, int x, int y)
2615      {
2616        Color saved = g.getColor();
2617        g.setColor(Color.BLACK);
2618        g.drawLine(3 + x, 5 + y, 3 + x, 9 + y);
2619        g.drawLine(4 + x, 5 + y, 4 + x, 9 + y);
2620        g.drawLine(5 + x, 7 + y, 9 + x, 3 + y);
2621        g.drawLine(5 + x, 8 + y, 9 + x, 4 + y);
2622        g.setColor(saved);
2623      }
2624    };
2625  }
2626}