Source for javax.swing.DefaultDesktopManager

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