001    /* MetalIconFactory.java --
002       Copyright (C) 2005, 2006, Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.plaf.metal;
040    
041    import java.awt.Color;
042    import java.awt.Component;
043    import java.awt.Graphics;
044    import java.io.Serializable;
045    
046    import javax.swing.AbstractButton;
047    import javax.swing.Icon;
048    import javax.swing.JCheckBox;
049    import javax.swing.JCheckBoxMenuItem;
050    import javax.swing.JFileChooser;
051    import javax.swing.JInternalFrame;
052    import javax.swing.JRadioButton;
053    import javax.swing.JRadioButtonMenuItem;
054    import javax.swing.JSlider;
055    import javax.swing.SwingConstants;
056    import javax.swing.UIManager;
057    import javax.swing.plaf.UIResource;
058    
059    
060    /**
061     * Creates icons for the {@link MetalLookAndFeel}.
062     */
063    public 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    }