1 /* BasicDesktopIconUI.java --
2    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing.plaf.basic;
40 
41 import java.awt.BorderLayout;
42 import java.awt.Color;
43 import java.awt.Component;
44 import java.awt.Dimension;
45 import java.awt.Graphics;
46 import java.awt.Insets;
47 import java.awt.Rectangle;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.MouseEvent;
51 import java.beans.PropertyChangeEvent;
52 import java.beans.PropertyChangeListener;
53 import java.beans.PropertyVetoException;
54 
55 import javax.swing.Icon;
56 import javax.swing.JButton;
57 import javax.swing.JComponent;
58 import javax.swing.JDesktopPane;
59 import javax.swing.JInternalFrame;
60 import javax.swing.JInternalFrame.JDesktopIcon;
61 import javax.swing.SwingConstants;
62 import javax.swing.border.Border;
63 import javax.swing.event.MouseInputAdapter;
64 import javax.swing.event.MouseInputListener;
65 import javax.swing.plaf.ComponentUI;
66 import javax.swing.plaf.DesktopIconUI;
67 
68 /**
69  * This class acts as the UI delegate for JDesktopIcons for the Basic look and feel.
70  */
71 public class BasicDesktopIconUI extends DesktopIconUI
72 {
73   /**
74    * This helper class handles mouse events that occur on the JDesktopIcon.
75    */
76   public class MouseInputHandler extends MouseInputAdapter
77   {
78     /** The x offset from the MouseEvent coordinates to the top left corner. */
79     private transient int xOffset;
80 
81     /** The y offset fromt he MouseEvent coordinates to the top left corner. */
82     private transient int yOffset;
83 
84     /** A cached value of the JDesktopPane that parents this JDesktopIcon. */
85     private transient JDesktopPane pane;
86 
87     /**
88      * This method is called when the mouse is dragged in the JDesktopIcon.
89      *
90      * @param e The MouseEvent.
91      */
mouseDragged(MouseEvent e)92     public void mouseDragged(MouseEvent e)
93     {
94       Rectangle b = desktopIcon.getBounds();
95 
96       moveAndRepaint(desktopIcon, b.x + e.getX() - xOffset,
97                      b.y + e.getY() - yOffset, b.width, b.height);
98     }
99 
100     /**
101      * This method is called when the mouse is moved in the JDesktopIcon.
102      *
103      * @param e The MouseEvent.
104      */
mouseMoved(MouseEvent e)105     public void mouseMoved(MouseEvent e)
106     {
107       // Nothing to do.
108     }
109 
110     /**
111      * This method is called when the mouse is pressed in the JDesktopIcon.
112      *
113      * @param e The MouseEvent.
114      */
mousePressed(MouseEvent e)115     public void mousePressed(MouseEvent e)
116     {
117       xOffset = e.getX();
118       yOffset = e.getY();
119       pane = frame.getDesktopPane();
120       if (pane != null)
121         pane.getDesktopManager().beginDraggingFrame(desktopIcon);
122     }
123 
124     /**
125      * This method is called when the mouse is released in the JDesktopIcon.
126      *
127      * @param e The MouseEvent.
128      */
mouseReleased(MouseEvent e)129     public void mouseReleased(MouseEvent e)
130     {
131       if (pane != null)
132         pane.getDesktopManager().endDraggingFrame(desktopIcon);
133       xOffset = 0;
134       yOffset = 0;
135     }
136 
137     /**
138      * This method moves and repaints the JDesktopIcon to the given bounds.
139      *
140      * @param f The JComponent to move and repaint.
141      * @param newX The new x coordinate.
142      * @param newY The new y coordinate.
143      * @param newWidth The new width.
144      * @param newHeight The new height.
145      */
moveAndRepaint(JComponent f, int newX, int newY, int newWidth, int newHeight)146     public void moveAndRepaint(JComponent f, int newX, int newY, int newWidth,
147                                int newHeight)
148     {
149       if (pane != null)
150         pane.getDesktopManager().dragFrame(f, newX, newY);
151       else
152         desktopIcon.setBounds(newX, newY, newWidth, newHeight);
153     }
154   }
155 
156   /**
157    * This class acts as the border for the JDesktopIcon.
158    */
159   private class DesktopIconBorder implements Border
160   {
161     /** The left inset value. */
162     int left = 10;
163 
164     /** The top inset value. */
165     int top = 4;
166 
167     /** The right inset value. */
168     int right = top;
169 
170     /** The bottom inset value. */
171     int bottom = top;
172 
173     /**
174      * This method returns the insets of the border.
175      *
176      * @param c The Component to find border insets for.
177      *
178      * @return The border insets.
179      */
getBorderInsets(Component c)180     public Insets getBorderInsets(Component c)
181     {
182       return new Insets(top, left, bottom, right);
183     }
184 
185     /**
186      * This method returns whether the border is opaque.
187      *
188      * @return Whether the border is opaque.
189      */
isBorderOpaque()190     public boolean isBorderOpaque()
191     {
192       return true;
193     }
194 
195     /**
196      * This method paints the border.
197      *
198      * @param c The Component the border is in.
199      * @param g The Graphics object to paint with.
200      * @param x The x coordinate of the Component.
201      * @param y The y coordinate of the Component.
202      * @param width The width of the Component.
203      * @param height The height of the Component.
204      */
paintBorder(Component c, Graphics g, int x, int y, int width, int height)205     public void paintBorder(Component c, Graphics g, int x, int y, int width,
206                             int height)
207     {
208       g.translate(x, y);
209       Color saved = g.getColor();
210 
211       g.setColor(Color.LIGHT_GRAY);
212 
213       g.fillRect(0, 0, left, height);
214       g.fillRect(0, 0, width, top);
215       g.fillRect(0, height - bottom, width, bottom);
216       g.fillRect(width - right, 0, right, height);
217 
218       g.setColor(Color.BLACK);
219       g.drawRect(0, 0, width - 1, height - 1);
220 
221       int fHeight = height / 4;
222       int hLeft = left / 2;
223 
224       g.setColor(Color.BLACK);
225       g.fillRect(hLeft, fHeight, 2, 2);
226       g.fillRect(hLeft, fHeight * 2, 2, 2);
227       g.fillRect(hLeft, fHeight * 3, 2, 2);
228 
229       g.setColor(saved);
230       g.translate(-x, -y);
231     }
232   }
233 
234   /** The static width and height of the iconSize. */
235   private static final int iconSize = 16;
236 
237   /**
238    * This class represents the default frame icon when none
239    * is supplied by the JInternalFrame.
240    */
241   static class InternalFrameDefaultMenuIcon implements Icon
242   {
243     /**
244      * This returns the icon height.
245      *
246      * @return The icon height.
247      */
getIconHeight()248     public int getIconHeight()
249     {
250       return iconSize;
251     }
252 
253     /**
254      * This returns the icon width.
255      *
256      * @return The icon width.
257      */
getIconWidth()258     public int getIconWidth()
259     {
260       return iconSize;
261     }
262 
263     /**
264      * This method paints the icon.
265      *
266      * @param c The Component this icon belongs to.
267      * @param g The Graphics object to paint with.
268      * @param x The x coordinate to paint at.
269      * @param y The y coordinate to paint at.
270      */
paintIcon(Component c, Graphics g, int x, int y)271     public void paintIcon(Component c, Graphics g, int x, int y)
272     {
273       g.translate(x, y);
274       Color saved = g.getColor();
275 
276       g.setColor(Color.BLUE);
277       g.fillRect(0, 0, iconSize, (int) ((double) iconSize / 3) + 1);
278 
279       g.setColor(Color.WHITE);
280       g.fillRect(0, (int) ((double) iconSize / 3), iconSize, iconSize * 5 / 6);
281 
282       g.setColor(Color.GRAY);
283       g.drawRect(0, 0, iconSize, iconSize);
284 
285       g.setColor(saved);
286       g.translate(-x, -y);
287     }
288   }
289 
290   /** The default JDesktopIcon width. */
291   private static final int iconWidth = 160;
292 
293   /** The default JDesktopIcon height */
294   private static final int iconHeight = 35;
295 
296   /** The JDesktopIcon this UI delegate represents. */
297   protected JDesktopIcon desktopIcon;
298 
299   /** The JInternalFrame associated with the JDesktopIcon. */
300   protected JInternalFrame frame;
301 
302   /** The MouseListener responsible for reacting to MouseEvents on the JDesktopIcon. */
303   private transient MouseInputListener mouseHandler;
304 
305   /** The Button in the JDesktopIcon responsible for deiconifying it.
306    * This is package-private to avoid an accessor method. */
307   transient BoundButton button;
308 
309   /** The PropertyChangeListener listening to the JDesktopIcon. */
310   private transient PropertyChangeListener propertyHandler;
311 
312   /** The default icon used when no frame icon is given by the JInternalFrame. */
313   static Icon defaultIcon = new InternalFrameDefaultMenuIcon();
314 
315   /**
316    * This is a helper class that is used in JDesktopIcon and gives the Button a predetermined size.
317    */
318   private class BoundButton extends JButton
319   {
320     /**
321      * Creates a new BoundButton object.
322      *
323      * @param title The title of the button.
324      */
BoundButton(String title)325     public BoundButton(String title)
326     {
327       super(title);
328     }
329 
330     /**
331      * This method returns a standard size (based on the defaults of the JDesktopIcon) and the insets.
332      *
333      * @return The preferred size of the JDesktopIcon.
334      */
getPreferredSize()335     public Dimension getPreferredSize()
336     {
337       Insets insets = desktopIcon.getInsets();
338       return new Dimension(iconWidth - insets.left - insets.right,
339                            iconHeight - insets.top - insets.bottom);
340     }
341 
342     /**
343      * This method returns the minimum size of the button.
344      *
345      * @return The minimum size of the button.
346      */
getMinimumSize()347     public Dimension getMinimumSize()
348     {
349       return getPreferredSize();
350     }
351 
352     /**
353      * This method returns the maximum size of the button.
354      *
355      * @return The maximum size of the button.
356      */
getMaximumSize()357     public Dimension getMaximumSize()
358     {
359       return getPreferredSize();
360     }
361   }
362 
363   /**
364    * Creates a new BasicDesktopIconUI object.
365    */
BasicDesktopIconUI()366   public BasicDesktopIconUI()
367   {
368     // Nothing to do here.
369   }
370 
371   /**
372    * This method creates a new BasicDesktopIconUI for the given JComponent.
373    *
374    * @param c The JComponent to create a UI for.
375    *
376    * @return A new BasicDesktopIconUI.
377    */
createUI(JComponent c)378   public static ComponentUI createUI(JComponent c)
379   {
380     return new BasicDesktopIconUI();
381   }
382 
383   /**
384    * This method installs the UI for the given JComponent.
385    *
386    * @param c The JComponent to install this UI for.
387    */
installUI(JComponent c)388   public void installUI(JComponent c)
389   {
390     if (c instanceof JDesktopIcon)
391       {
392         desktopIcon = (JDesktopIcon) c;
393         desktopIcon.setLayout(new BorderLayout());
394         frame = desktopIcon.getInternalFrame();
395 
396         installDefaults();
397         installComponents();
398         installListeners();
399 
400         desktopIcon.setOpaque(true);
401       }
402   }
403 
404   /**
405    * This method uninstalls the UI for the given JComponent.
406    *
407    * @param c The JComponent to uninstall this UI for.
408    */
uninstallUI(JComponent c)409   public void uninstallUI(JComponent c)
410   {
411     desktopIcon.setOpaque(false);
412 
413     uninstallListeners();
414     uninstallComponents();
415     uninstallDefaults();
416 
417     frame = null;
418     desktopIcon.setLayout(null);
419     desktopIcon = null;
420   }
421 
422   /**
423    * This method installs the necessary sub components for the JDesktopIcon.
424    */
installComponents()425   protected void installComponents()
426   {
427     // Try to create a button based on what the frame's
428     // state is currently
429     button = new BoundButton(frame.getTitle());
430     button.setHorizontalAlignment(SwingConstants.LEFT);
431     button.setHorizontalTextPosition(SwingConstants.TRAILING);
432 
433     Icon use = frame.getFrameIcon();
434     if (use == null)
435       use = defaultIcon;
436     button.setIcon(use);
437 
438     desktopIcon.add(button, SwingConstants.CENTER);
439   }
440 
441   /**
442    * This method uninstalls the sub components for the JDesktopIcon.
443    */
uninstallComponents()444   protected void uninstallComponents()
445   {
446     desktopIcon.remove(button);
447 
448     button = null;
449   }
450 
451   /**
452    * This method installs the listeners needed by this UI.
453    */
installListeners()454   protected void installListeners()
455   {
456     mouseHandler = createMouseInputListener();
457 
458     desktopIcon.addMouseMotionListener(mouseHandler);
459     desktopIcon.addMouseListener(mouseHandler);
460 
461     propertyHandler = new PropertyChangeListener()
462         {
463           public void propertyChange(PropertyChangeEvent e)
464           {
465             if (e.getPropertyName().equals(JInternalFrame.TITLE_PROPERTY))
466               button.setText(desktopIcon.getInternalFrame().getTitle());
467             else if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY))
468               {
469                 Icon use = desktopIcon.getInternalFrame().getFrameIcon();
470                 if (use == null)
471                   use = defaultIcon;
472                 button.setIcon(use);
473               }
474             desktopIcon.revalidate();
475             desktopIcon.repaint();
476           }
477         };
478     frame.addPropertyChangeListener(propertyHandler);
479 
480     button.addActionListener(new ActionListener()
481         {
482           public void actionPerformed(ActionEvent e)
483           {
484             deiconize();
485           }
486         });
487   }
488 
489   /**
490    * This method uninstalls the listeners needed by the UI.
491    */
uninstallListeners()492   protected void uninstallListeners()
493   {
494     // button is nulled so no need to remove it.
495 
496     frame.removePropertyChangeListener(propertyHandler);
497     propertyHandler = null;
498 
499     desktopIcon.removeMouseMotionListener(mouseHandler);
500     desktopIcon.removeMouseListener(mouseHandler);
501   }
502 
503   /**
504    * This method installs the defaults for the JDesktopIcon.
505    */
installDefaults()506   protected void installDefaults()
507   {
508     // FIXME: Move border to defaults.
509     desktopIcon.setBorder(new DesktopIconBorder());
510   }
511 
512   /**
513    * This method uninstalls the defaults for the JDesktopIcon.
514    */
uninstallDefaults()515   protected void uninstallDefaults()
516   {
517     desktopIcon.setBorder(null);
518   }
519 
520   /**
521    * This method creates a new MouseInputListener for the JDesktopIcon.
522    *
523    * @return A new MouseInputListener.
524    */
createMouseInputListener()525   protected MouseInputListener createMouseInputListener()
526   {
527     return new MouseInputHandler();
528   }
529 
530   /**
531    * This method returns the preferred size for the given JComponent.
532    *
533    * @param c The JComponent to find a preferred size for.
534    *
535    * @return The preferred size.
536    */
getPreferredSize(JComponent c)537   public Dimension getPreferredSize(JComponent c)
538   {
539     return new Dimension(iconWidth, iconHeight);
540   }
541 
542   /**
543    * This method returns the minimum size for the given JComponent.
544    *
545    * @param c The JComponent to find a minimum size for.
546    *
547    * @return The minimum size.
548    */
getMinimumSize(JComponent c)549   public Dimension getMinimumSize(JComponent c)
550   {
551     return getPreferredSize(c);
552   }
553 
554   /**
555    * This method returns the maximum size for the given JComponent.
556    *
557    * @param c The JComponent to find a maximum size for.
558    *
559    * @return The maximum size.
560    */
getMaximumSize(JComponent c)561   public Dimension getMaximumSize(JComponent c)
562   {
563     return getPreferredSize(c);
564   }
565 
566   /**
567    * This method returns the insets of the given JComponent.
568    *
569    * @param c The JComponent to find insets for.
570    *
571    * @return The insets of the given JComponent.
572    */
getInsets(JComponent c)573   public Insets getInsets(JComponent c)
574   {
575     return c.getInsets();
576   }
577 
578   /**
579    * This method deiconizes the JInternalFrame associated with the JDesktopIcon.
580    */
deiconize()581   public void deiconize()
582   {
583     try
584     {
585       frame.setIcon(false);
586     }
587     catch (PropertyVetoException pve)
588     {
589       // We do nothing if the attempt has been vetoed.
590     }
591   }
592 }
593