OSDN Git Service

2005-04-19 Roman Kennke <roman@kennke.org>
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / DefaultDesktopManager.java
1 /* DefaultDesktopManager.java --
2    Copyright (C) 2002, 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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;
40
41 import java.awt.Component;
42 import java.awt.Container;
43 import java.awt.Dimension;
44 import java.awt.Insets;
45 import java.awt.Rectangle;
46 import java.beans.PropertyVetoException;
47 import java.io.Serializable;
48
49 import javax.swing.JInternalFrame.JDesktopIcon;
50
51 /**
52  * DefaultDesktopManager is the default implementation of DesktopManager for
53  * swing. It implements the basic beaviours for JInternalFrames in arbitrary
54  * parents. The methods provided by the class are not meant to be called by
55  * the user, instead, the JInternalFrame methods will call these methods.
56  */
57 public class DefaultDesktopManager implements DesktopManager, Serializable
58 {
59   /** DOCUMENT ME! */
60   private static final long serialVersionUID = 4657624909838017887L;
61
62   /** The property change event fired when the wasIcon property changes. */
63   static final String WAS_ICON_ONCE_PROPERTY = "wasIconOnce";
64
65   /**
66    * The method of dragging used by the JDesktopPane that parents the
67    * JInternalFrame that is being dragged.
68    */
69   private int currentDragMode = 0;
70
71   /**
72    * The cache of the bounds used to draw the outline rectangle when
73    * OUTLINE_DRAG_MODE is used.
74    */
75   private transient Rectangle dragCache = new Rectangle();
76
77   /**
78    * A cached JDesktopPane that is stored when the JInternalFrame is initially
79    * dragged.
80    */
81   private transient Container pane;
82
83   /**
84    * An array of Rectangles that holds the bounds of the JDesktopIcons in the
85    * JDesktopPane when looking for where to place a new icon.
86    */
87   private transient Rectangle[] iconRects;
88
89   /**
90    * This creates a new DefaultDesktopManager object.
91    */
92   public DefaultDesktopManager()
93   {
94   }
95
96   /**
97    * This method is not normally called since the user will typically add the
98    * JInternalFrame to a Container. If this is called, it will try to
99    * determine the parent of the JInternalFrame and remove any icon that
100    * represents this JInternalFrame and add this JInternalFrame.
101    *
102    * @param frame The JInternalFrame to open.
103    */
104   public void openFrame(JInternalFrame frame)
105   {
106     Container c = frame.getParent();
107     if (c == null)
108       c = frame.getDesktopIcon().getParent();
109     if (c == null)
110       return;
111
112     c.remove(frame.getDesktopIcon());
113     c.add(frame);
114     frame.setVisible(true);
115   }
116
117   /**
118    * This method removes the JInternalFrame and JDesktopIcon (if one is
119    * present) from their parents.
120    *
121    * @param frame The JInternalFrame to close.
122    */
123   public void closeFrame(JInternalFrame frame)
124   {
125     Container c = frame.getParent();
126     frame.doDefaultCloseAction();
127
128     if (c != null)
129       {
130         if (frame.isIcon())
131           c.remove(frame.getDesktopIcon());
132         else
133           c.remove(frame);
134         c.repaint();
135       }
136   }
137
138   /**
139    * This method resizes the JInternalFrame to match its parent's bounds.
140    *
141    * @param frame The JInternalFrame to maximize.
142    */
143   public void maximizeFrame(JInternalFrame frame)
144   {
145     // Can't maximize from iconified state.
146     // It can only return to maximized state, but that would fall under
147     // deiconify.
148     if (frame.isIcon())
149       return;
150     frame.setNormalBounds(frame.getBounds());
151
152     Container p = frame.getParent();
153     if (p != null)
154       {
155         Rectangle pBounds = p.getBounds();
156         Insets insets = p.getInsets();
157         pBounds.width -= insets.left + insets.right;
158         pBounds.height -= insets.top + insets.bottom;
159
160         setBoundsForFrame(frame, 0, 0, pBounds.width, pBounds.height);
161       }
162     if (p instanceof JDesktopPane)
163       ((JDesktopPane) p).setSelectedFrame(frame);
164     else
165       {
166         try
167           {
168             frame.setSelected(true);
169           }
170         catch (PropertyVetoException e)
171           {
172             // Do nothing.
173           }
174       }
175   }
176
177   /**
178    * This method restores the JInternalFrame's bounds to what they were
179    * previous to the setMaximize call.
180    *
181    * @param frame The JInternalFrame to minimize.
182    */
183   public void minimizeFrame(JInternalFrame frame)
184   {
185     Rectangle normalBounds = frame.getNormalBounds();
186
187     JDesktopPane p = frame.getDesktopPane();
188     if (p != null)
189       p.setSelectedFrame(frame);
190     else
191       {
192         try
193           {
194             frame.setSelected(true);
195           }
196         catch (PropertyVetoException e)
197           {
198             // Do nothing.
199           }
200       }
201
202     setBoundsForFrame(frame, normalBounds.x, normalBounds.y,
203                       normalBounds.width, normalBounds.height);
204   }
205
206   /**
207    * This method removes the JInternalFrame from its parent and adds its
208    * JDesktopIcon representation.
209    *
210    * @param frame The JInternalFrame to iconify.
211    */
212   public void iconifyFrame(JInternalFrame frame)
213   {
214     JDesktopPane p = frame.getDesktopPane();
215     JDesktopIcon icon = frame.getDesktopIcon();
216     if (p != null && p.getSelectedFrame() == frame)
217       p.setSelectedFrame(null);
218     else
219       {
220         try
221           {
222             frame.setSelected(false);
223           }
224         catch (PropertyVetoException e)
225           {
226           }
227       }
228
229     Container c = frame.getParent();
230
231     if (! wasIcon(frame))
232       {
233         Rectangle r = getBoundsForIconOf(frame);
234         icon.setBounds(r);
235         setWasIcon(frame, Boolean.TRUE);
236       }
237
238     if (c != null)
239       {
240         if (icon != null)
241           {
242             c.add(icon);
243             icon.setVisible(true);
244           }
245         c.remove(frame);
246       }
247   }
248
249   /**
250    * This method removes the JInternalFrame's JDesktopIcon representation and
251    * adds the JInternalFrame back to its parent.
252    *
253    * @param frame The JInternalFrame to deiconify.
254    */
255   public void deiconifyFrame(JInternalFrame frame)
256   {
257     JDesktopIcon icon = frame.getDesktopIcon();
258     Container c = icon.getParent();
259
260     removeIconFor(frame);
261     c.add(frame);
262     frame.setVisible(true);
263
264     if (! frame.isSelected())
265       {
266         JDesktopPane p = frame.getDesktopPane();
267         if (p != null)
268           p.setSelectedFrame(frame);
269         else
270           {
271             try
272               {
273                 frame.setSelected(true);
274               }
275             catch (PropertyVetoException e)
276               {
277                 // Do nothing.
278               }
279           }
280       }
281
282     c.invalidate();
283   }
284
285   /**
286    * This method activates the JInternalFrame by moving it to the front and
287    * selecting it.
288    *
289    * @param frame The JInternalFrame to activate.
290    */
291   public void activateFrame(JInternalFrame frame)
292   {
293     JDesktopPane p = frame.getDesktopPane();
294
295     if (p != null)
296       p.setSelectedFrame(frame);
297     else
298       {
299         try
300           {
301             frame.setSelected(true);
302           }
303         catch (PropertyVetoException e)
304           {
305           }
306       }
307
308     frame.toFront();
309   }
310
311   /**
312    * This method is called when the JInternalFrame loses focus.
313    *
314    * @param frame The JInternalFram to deactivate.
315    */
316   public void deactivateFrame(JInternalFrame frame)
317   {
318     JDesktopPane p = frame.getDesktopPane();
319     if (p != null)
320       {
321         if (p.getSelectedFrame() == frame)
322           p.setSelectedFrame(null);
323       }
324     else
325       {
326         try
327           {
328             frame.setSelected(false);
329           }
330         catch (PropertyVetoException e)
331           {
332           }
333       }
334   }
335
336   /**
337    * This method is called to indicate that the DesktopManager should prepare
338    * to drag the JInternalFrame. Any state information needed to drag the
339    * frame will be prepared now.
340    *
341    * @param component The JComponent to drag, usually a JInternalFrame.
342    */
343   public void beginDraggingFrame(JComponent component)
344   {
345     if (component instanceof JDesktopIcon)
346       pane = ((JDesktopIcon) component).getInternalFrame().getDesktopPane();
347     else
348       pane = ((JInternalFrame) component).getDesktopPane();
349     if (pane == null)
350       return;
351
352     dragCache = component.getBounds();
353
354     if (! (pane instanceof JDesktopPane))
355       currentDragMode = JDesktopPane.LIVE_DRAG_MODE;
356     else
357       currentDragMode = ((JDesktopPane) pane).getDragMode();
358   }
359
360   /**
361    * This method is called to drag the JInternalFrame to a new location.
362    *
363    * @param component The JComponent to drag, usually a JInternalFrame.
364    * @param newX The new x coordinate.
365    * @param newY The new y coordinate.
366    */
367   public void dragFrame(JComponent component, int newX, int newY)
368   {
369     if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE)
370       {
371         // FIXME: Do outline drag mode painting.
372       }
373     else
374       {
375         Rectangle b = component.getBounds();
376         if (component instanceof JDesktopIcon)
377           component.setBounds(newX, newY, b.width, b.height);
378         else
379           setBoundsForFrame((JInternalFrame) component, newX, newY, b.width,
380                             b.height);
381       }
382   }
383
384   /**
385    * This method indicates that the dragging is done. Any state information
386    * stored by the DesktopManager can be cleared.
387    *
388    * @param component The JComponent that has finished dragging.
389    */
390   public void endDraggingFrame(JComponent component)
391   {
392     if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE)
393       {
394         setBoundsForFrame((JInternalFrame) component, dragCache.x,
395                           dragCache.y, dragCache.width, dragCache.height);
396         pane = null;
397         dragCache = null;
398       }
399     component.repaint();
400   }
401
402   /**
403    * This method is called to indicate that the given JComponent will be
404    * resized. Any state information necessary to resize the JComponent will
405    * be prepared now.
406    *
407    * @param component The JComponent to resize, usually a JInternalFrame.
408    * @param direction The direction to drag in (a SwingConstant).
409    */
410   public void beginResizingFrame(JComponent component, int direction)
411   {
412     pane = ((JInternalFrame) component).getDesktopPane();
413     if (pane == null)
414       return;
415
416     dragCache = component.getBounds();
417     if (! (pane instanceof JDesktopPane))
418       currentDragMode = JDesktopPane.LIVE_DRAG_MODE;
419     else
420       currentDragMode = ((JDesktopPane) pane).getDragMode();
421   }
422
423   /**
424    * This method resizes the give JComponent.
425    *
426    * @param component The JComponent to resize.
427    * @param newX The new x coordinate.
428    * @param newY The new y coordinate.
429    * @param newWidth The new width.
430    * @param newHeight The new height.
431    */
432   public void resizeFrame(JComponent component, int newX, int newY,
433                           int newWidth, int newHeight)
434   {
435     dragCache.setBounds(newX, newY, newWidth, newHeight);
436
437     if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE)
438       {
439         // FIXME: Do outline drag painting.
440       }
441     else
442       setBoundsForFrame(component, dragCache.x, dragCache.y, dragCache.width,
443                         dragCache.height);
444   }
445
446   /**
447    * This method is called to indicate that the given JComponent has finished
448    * dragging. Any state information stored by the DesktopManager can be
449    * cleared.
450    *
451    * @param component The JComponent that finished resizing.
452    */
453   public void endResizingFrame(JComponent component)
454   {
455     if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE)
456       {
457         setBoundsForFrame((JInternalFrame) component, dragCache.x,
458                           dragCache.y, dragCache.width, dragCache.height);
459         pane = null;
460         dragCache = null;
461       }
462     component.repaint();
463   }
464
465   /**
466    * This method calls setBounds with the given parameters and repaints the
467    * JComponent.
468    *
469    * @param component The JComponent to set bounds for.
470    * @param newX The new x coordinate.
471    * @param newY The new y coordinate.
472    * @param newWidth The new width.
473    * @param newHeight The new height.
474    */
475   public void setBoundsForFrame(JComponent component, int newX, int newY,
476                                 int newWidth, int newHeight)
477   {
478     component.setBounds(newX, newY, newWidth, newHeight);
479     component.revalidate();
480
481     // If not null, I'd rather repaint the parent
482     if (component.getParent() != null)
483       component.getParent().repaint();
484     else
485       component.repaint();
486   }
487
488   /**
489    * This is a helper method that removes the JDesktopIcon of the given
490    * JInternalFrame from the parent.
491    *
492    * @param frame The JInternalFrame to remove an icon for.
493    */
494   protected void removeIconFor(JInternalFrame frame)
495   {
496     JDesktopIcon icon = frame.getDesktopIcon();
497     Container c = icon.getParent();
498     if (c != null && icon != null)
499       c.remove(icon);
500   }
501
502   /**
503    * This method is called by iconifyFrame to determine the bounds of the
504    * JDesktopIcon for the given JInternalFrame.
505    *
506    * @param frame The JInternalFrame to find the bounds of its JDesktopIcon
507    *        for.
508    *
509    * @return The bounds of the JDesktopIcon.
510    */
511   protected Rectangle getBoundsForIconOf(JInternalFrame frame)
512   {
513     // IconRects has no order to it.
514     // The icon _must_ be placed in the first free slot (working from 
515     // the bottom left corner)
516     // The icon also must not be placed where another icon is placed 
517     // (regardless whether that frame is an icon currently or not)
518     JDesktopPane desktopPane = frame.getDesktopPane();
519     Rectangle paneBounds = desktopPane.getBounds();
520     Insets insets = desktopPane.getInsets();
521     Dimension pref = frame.getDesktopIcon().getPreferredSize();
522
523     if (desktopPane == null)
524       return frame.getDesktopIcon().getBounds();
525
526     Component[] frames = desktopPane.getComponents();
527
528     int count = 0;
529     for (int i = 0, j = 0; i < frames.length; i++)
530       if (frames[i] instanceof JDesktopIcon
531           || frames[i] instanceof JInternalFrame
532           && ((JInternalFrame) frames[i]).getWasIcon() && frames[i] != frame)
533         count++;
534     iconRects = new Rectangle[count];
535     for (int i = 0, j = 0; i < frames.length; i++)
536       if (frames[i] instanceof JDesktopIcon)
537         iconRects[--count] = frames[i].getBounds();
538       else if (frames[i] instanceof JInternalFrame
539                && ((JInternalFrame) frames[i]).getWasIcon()
540                && frames[i] != frame)
541         iconRects[--count] = ((JInternalFrame) frames[i]).getDesktopIcon()
542                               .getBounds();
543
544     int startingX = insets.left;
545     int startingY = paneBounds.height - insets.bottom - pref.height;
546     Rectangle ideal = new Rectangle(startingX, startingY, pref.width,
547                                     pref.height);
548     boolean clear = true;
549
550     while (iconRects.length > 0)
551       {
552         clear = true;
553         for (int i = 0; i < iconRects.length; i++)
554           {
555             if (iconRects[i] != null && iconRects[i].intersects(ideal))
556               {
557                 clear = false;
558                 break;
559               }
560           }
561         if (clear)
562           return ideal;
563
564         startingX += pref.width;
565         if (startingX + pref.width > paneBounds.width - insets.right)
566           {
567             startingX = insets.left;
568             startingY -= pref.height;
569           }
570         ideal.setBounds(startingX, startingY, pref.width, pref.height);
571       }
572
573     return ideal;
574   }
575
576   /**
577    * This method sets the bounds of the JInternalFrame right before the
578    * maximizeFrame call.
579    *
580    * @param frame The JInternalFrame being maximized.
581    * @param rect The normal bounds.
582    */
583   protected void setPreviousBounds(JInternalFrame frame, Rectangle rect)
584   {
585     frame.setNormalBounds(rect);
586   }
587
588   /**
589    * This method returns the normal bounds of the JInternalFrame from before
590    * the maximize call.
591    *
592    * @param frame The JInternalFrame that is being restored.
593    *
594    * @return The previous bounds of the JInternalFrame.
595    */
596   protected Rectangle getPreviousBounds(JInternalFrame frame)
597   {
598     return frame.getNormalBounds();
599   }
600
601   /**
602    * This method sets the value to true if the given JInternalFrame has been
603    * iconized and the bounds of its DesktopIcon are valid.
604    *
605    * @param frame The JInternalFrame for the JDesktopIcon.
606    * @param value True if the JInternalFrame has been iconized and the bounds
607    *        of the JDesktopIcon are valid.
608    */
609   protected void setWasIcon(JInternalFrame frame, Boolean value)
610   {
611     frame.setWasIcon(value.booleanValue(), WAS_ICON_ONCE_PROPERTY);
612   }
613
614   /**
615    * This method returns true if the given JInternalFrame has been iconized
616    * and the bounds of its DesktopIcon are valid.
617    *
618    * @param frame The JInternalFrame for the JDesktopIcon.
619    *
620    * @return True if the given JInternalFrame has been iconized and the bounds
621    *         of its DesktopIcon are valid.
622    */
623   protected boolean wasIcon(JInternalFrame frame)
624   {
625     return frame.getWasIcon();
626   }
627 }