Source for javax.swing.plaf.metal.MetalInternalFrameTitlePane

   1: /* MetalInternalFrameTitlePane.java
   2:    Copyright (C) 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.metal;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Container;
  44: import java.awt.Dimension;
  45: import java.awt.Graphics;
  46: import java.awt.Insets;
  47: import java.awt.LayoutManager;
  48: import java.awt.Rectangle;
  49: import java.beans.PropertyChangeEvent;
  50: import java.beans.PropertyChangeListener;
  51: 
  52: import javax.swing.Icon;
  53: import javax.swing.JInternalFrame;
  54: import javax.swing.JLabel;
  55: import javax.swing.JMenu;
  56: import javax.swing.SwingConstants;
  57: import javax.swing.SwingUtilities;
  58: import javax.swing.UIManager;
  59: import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
  60: 
  61: 
  62: /**
  63:  * The title pane for a {@link JInternalFrame} (see
  64:  * {@link MetalInternalFrameUI#createNorthPane(JInternalFrame)}).  This can
  65:  * be displayed in two styles: one for regular internal frames, and the other
  66:  * for "palette" style internal frames.
  67:  */
  68: public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane
  69: {
  70: 
  71:   /**
  72:    * A property change handler that listens for changes to the
  73:    * <code>JInternalFrame.isPalette</code> property and updates the title
  74:    * pane as appropriate.
  75:    */
  76:   class MetalInternalFrameTitlePanePropertyChangeHandler
  77:     extends PropertyChangeHandler
  78:   {
  79:     /**
  80:      * Creates a new handler.
  81:      */
  82:     public MetalInternalFrameTitlePanePropertyChangeHandler()
  83:     {
  84:       super();
  85:     }
  86: 
  87:     /**
  88:      * Handles <code>JInternalFrame.isPalette</code> property changes, with all
  89:      * other property changes being passed to the superclass.
  90:      *
  91:      * @param e  the event.
  92:      */
  93:     public void propertyChange(PropertyChangeEvent e)
  94:     {
  95:       String propName = e.getPropertyName();
  96:       if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY))
  97:         {
  98:           title.setIcon(frame.getFrameIcon());
  99:         }
 100:       else if (propName.equals("JInternalFrame.isPalette"))
 101:         {
 102:           if (e.getNewValue().equals(Boolean.TRUE))
 103:             setPalette(true);
 104:           else
 105:             setPalette(false);
 106:         }
 107:       else
 108:         super.propertyChange(e);
 109:     }
 110:   }
 111: 
 112:   /**
 113:    * A layout manager for the title pane.
 114:    *
 115:    * @see #createLayout()
 116:    */
 117:   private class MetalTitlePaneLayout implements LayoutManager
 118:   {
 119:     /**
 120:      * Creates a new <code>TitlePaneLayout</code> object.
 121:      */
 122:     public MetalTitlePaneLayout()
 123:     {
 124:       // Do nothing.
 125:     }
 126: 
 127:     /**
 128:      * Adds a Component to the Container.
 129:      *
 130:      * @param name The name to reference the added Component by.
 131:      * @param c The Component to add.
 132:      */
 133:     public void addLayoutComponent(String name, Component c)
 134:     {
 135:       // Do nothing.
 136:     }
 137: 
 138:     /**
 139:      * This method is called to lay out the children of the Title Pane.
 140:      *
 141:      * @param c The Container to lay out.
 142:      */
 143:     public void layoutContainer(Container c)
 144:     {
 145: 
 146:       Dimension size = c.getSize();
 147:       Insets insets = c.getInsets();
 148:       int width = size.width - insets.left - insets.right;
 149:       int height = size.height - insets.top - insets.bottom;
 150: 
 151: 
 152:       int loc = width - insets.right - 1;
 153:       int top = insets.top + 2;
 154:       int buttonHeight = height - 4;
 155:       if (closeButton.isVisible())
 156:         {
 157:           int buttonWidth = closeIcon.getIconWidth();
 158:           loc -= buttonWidth + 2;
 159:           closeButton.setBounds(loc, top, buttonWidth, buttonHeight);
 160:           loc -= 6;
 161:         }
 162: 
 163:       if (maxButton.isVisible())
 164:         {
 165:           int buttonWidth = maxIcon.getIconWidth();
 166:           loc -= buttonWidth + 4;
 167:           maxButton.setBounds(loc, top, buttonWidth, buttonHeight);
 168:         }
 169: 
 170:       if (iconButton.isVisible())
 171:         {
 172:           int buttonWidth = minIcon.getIconWidth();
 173:           loc -= buttonWidth + 4;
 174:           iconButton.setBounds(loc, top, buttonWidth, buttonHeight);
 175:           loc -= 2;
 176:         }
 177: 
 178:       Dimension titlePreferredSize = title.getPreferredSize();
 179:       title.setBounds(insets.left + 5, insets.top,
 180:               Math.min(titlePreferredSize.width, loc - insets.left - 10),
 181:               height);
 182: 
 183:     }
 184: 
 185:     /**
 186:      * This method returns the minimum size of the given Container given the
 187:      * children that it has.
 188:      *
 189:      * @param c The Container to get a minimum size for.
 190:      *
 191:      * @return The minimum size of the Container.
 192:      */
 193:     public Dimension minimumLayoutSize(Container c)
 194:     {
 195:       return preferredLayoutSize(c);
 196:     }
 197: 
 198:     /**
 199:      * Returns the preferred size of the given Container taking
 200:      * into account the children that it has.
 201:      *
 202:      * @param c The Container to lay out.
 203:      *
 204:      * @return The preferred size of the Container.
 205:      */
 206:     public Dimension preferredLayoutSize(Container c)
 207:     {
 208:       if (isPalette)
 209:         return new Dimension(paletteTitleHeight, paletteTitleHeight);
 210:       else
 211:         return new Dimension(22, 22);
 212:     }
 213: 
 214:     /**
 215:      * Removes a Component from the Container.
 216:      *
 217:      * @param c The Component to remove.
 218:      */
 219:     public void removeLayoutComponent(Component c)
 220:     {
 221:       // Nothing to do here.
 222:     }
 223:   }
 224: 
 225:   /** A flag indicating whether the title pane uses the palette style. */
 226:   protected boolean isPalette;
 227: 
 228:   /**
 229:    * The icon used for the close button - this is fetched from the look and
 230:    * feel defaults using the key <code>InternalFrame.paletteCloseIcon</code>.
 231:    */
 232:   protected Icon paletteCloseIcon;
 233: 
 234:   /**
 235:    * The height of the title pane when <code>isPalette</code> is
 236:    * <code>true</code>.  This value is fetched from the look and feel defaults
 237:    * using the key <code>InternalFrame.paletteTitleHeight</code>.
 238:    */
 239:   protected int paletteTitleHeight;
 240: 
 241:   /** The label used to display the title for the internal frame. */
 242:   JLabel title;
 243: 
 244:   /**
 245:    * Creates a new title pane for the specified frame.
 246:    *
 247:    * @param f  the internal frame.
 248:    */
 249:   public MetalInternalFrameTitlePane(JInternalFrame f)
 250:   {
 251:     super(f);
 252:     isPalette = false;
 253:   }
 254: 
 255:   /**
 256:    * Fetches the colors used in the title pane.
 257:    */
 258:   protected void installDefaults()
 259:   {
 260:     super.installDefaults();
 261:     selectedTextColor = MetalLookAndFeel.getControlTextColor();
 262:     selectedTitleColor = MetalLookAndFeel.getWindowTitleBackground();
 263:     notSelectedTextColor = MetalLookAndFeel.getInactiveControlTextColor();
 264:     notSelectedTitleColor = MetalLookAndFeel.getWindowTitleInactiveBackground();
 265: 
 266:     paletteTitleHeight = UIManager.getInt("InternalFrame.paletteTitleHeight");
 267:     paletteCloseIcon = UIManager.getIcon("InternalFrame.paletteCloseIcon");
 268:     minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16);
 269: 
 270:     title = new JLabel(frame.getTitle(),
 271:             MetalIconFactory.getInternalFrameDefaultMenuIcon(),
 272:             SwingConstants.LEFT);
 273:   }
 274: 
 275:   /**
 276:    * Clears the colors used for the title pane.
 277:    */
 278:   protected void uninstallDefaults()
 279:   {
 280:     super.uninstallDefaults();
 281:     selectedTextColor = null;
 282:     selectedTitleColor = null;
 283:     notSelectedTextColor = null;
 284:     notSelectedTitleColor = null;
 285:     paletteCloseIcon = null;
 286:     minIcon = null;
 287:     title = null;
 288:   }
 289: 
 290:   /**
 291:    * Calls the super class to create the buttons, then calls
 292:    * <code>setBorderPainted(false)</code> and
 293:    * <code>setContentAreaFilled(false)</code> for each button.
 294:    */
 295:   protected void createButtons()
 296:   {
 297:     super.createButtons();
 298:     closeButton.setBorderPainted(false);
 299:     closeButton.setContentAreaFilled(false);
 300:     iconButton.setBorderPainted(false);
 301:     iconButton.setContentAreaFilled(false);
 302:     maxButton.setBorderPainted(false);
 303:     maxButton.setContentAreaFilled(false);
 304:   }
 305: 
 306:   /**
 307:    * Overridden to do nothing.
 308:    */
 309:   protected void addSystemMenuItems(JMenu systemMenu)
 310:   {
 311:     // do nothing
 312:   }
 313: 
 314:   /**
 315:    * Overridden to do nothing.
 316:    */
 317:   protected void showSystemMenu()
 318:   {
 319:       // do nothing
 320:   }
 321: 
 322:   /**
 323:    * Adds the sub components of the title pane.
 324:    */
 325:   protected void addSubComponents()
 326:   {
 327:     // FIXME:  this method is probably overridden to only add the required
 328:     // buttons
 329:     add(title);
 330:     add(closeButton);
 331:     add(iconButton);
 332:     add(maxButton);
 333:   }
 334: 
 335:   /**
 336:    * Creates a new instance of <code>MetalTitlePaneLayout</code> (not part of
 337:    * the public API).
 338:    *
 339:    * @return A new instance of <code>MetalTitlePaneLayout</code>.
 340:    */
 341:   protected LayoutManager createLayout()
 342:   {
 343:     return new MetalTitlePaneLayout();
 344:   }
 345: 
 346:   /**
 347:    * Draws the title pane in the palette style.
 348:    *
 349:    * @param g  the graphics device.
 350:    *
 351:    * @see #paintComponent(Graphics)
 352:    */
 353:   public void paintPalette(Graphics g)
 354:   {
 355:     Color savedColor = g.getColor();
 356:     Rectangle b = SwingUtilities.getLocalBounds(this);
 357: 
 358:     if (UIManager.get("InternalFrame.activeTitleGradient") != null
 359:         && frame.isSelected())
 360:       {
 361:         MetalUtils.paintGradient(g, b.x, b.y, b.width, b.height,
 362:                                  SwingConstants.VERTICAL,
 363:                                  "InternalFrame.activeTitleGradient");
 364:       }
 365:     MetalUtils.fillMetalPattern(this, g, b.x + 4, b.y + 2, b.width
 366:             - paletteCloseIcon.getIconWidth() - 13, b.height - 5,
 367:             MetalLookAndFeel.getPrimaryControlHighlight(),
 368:             MetalLookAndFeel.getBlack());
 369: 
 370:     // draw a line separating the title pane from the frame content
 371:     Dimension d = getSize();
 372:     g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
 373:     g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
 374: 
 375:     g.setColor(savedColor);
 376:   }
 377: 
 378:   /**
 379:    * Paints a representation of the current state of the internal frame.
 380:    *
 381:    * @param g  the graphics device.
 382:    */
 383:   public void paintComponent(Graphics g)
 384:   {
 385:     Color savedColor = g.getColor();
 386:     if (isPalette)
 387:       paintPalette(g);
 388:     else
 389:       {
 390:         paintTitleBackground(g);
 391:         paintChildren(g);
 392:         Dimension d = getSize();
 393:         if (frame.isSelected())
 394:           g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
 395:         else
 396:           g.setColor(MetalLookAndFeel.getControlDarkShadow());
 397: 
 398:         // put a dot in each of the top corners
 399:         g.drawLine(0, 0, 0, 0);
 400:         g.drawLine(d.width - 1, 0, d.width - 1, 0);
 401: 
 402:         g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
 403: 
 404:         // draw the metal pattern
 405:         if (UIManager.get("InternalFrame.activeTitleGradient") != null
 406:             && frame.isSelected())
 407:           {
 408:             MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(),
 409:                                      SwingConstants.VERTICAL,
 410:                                      "InternalFrame.activeTitleGradient");
 411:           }
 412: 
 413:         Rectangle b = title.getBounds();
 414:         int startX = b.x + b.width + 5;
 415:         int endX = startX;
 416:         if (iconButton.isVisible())
 417:           endX = Math.max(iconButton.getX(), endX);
 418:         else if (maxButton.isVisible())
 419:           endX = Math.max(maxButton.getX(), endX);
 420:         else if (closeButton.isVisible())
 421:           endX = Math.max(closeButton.getX(), endX);
 422:         endX -= 7;
 423:         if (endX > startX)
 424:           MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX,
 425:               getHeight() - 6, Color.white, Color.gray);
 426:       }
 427:     g.setColor(savedColor);
 428:   }
 429: 
 430:   /**
 431:    * Sets the flag that controls whether the title pane is drawn in the
 432:    * palette style or the regular style.
 433:    *
 434:    * @param b  the new value of the flag.
 435:    */
 436:   public void setPalette(boolean b)
 437:   {
 438:     isPalette = b;
 439:     title.setVisible(!isPalette);
 440:     iconButton.setVisible(!isPalette && frame.isIconifiable());
 441:     maxButton.setVisible(!isPalette && frame.isMaximizable());
 442:     if (isPalette)
 443:       closeButton.setIcon(paletteCloseIcon);
 444:     else
 445:       closeButton.setIcon(closeIcon);
 446:   }
 447: 
 448:   /**
 449:    * Creates and returns a property change handler for the title pane.
 450:    *
 451:    * @return The property change handler.
 452:    */
 453:   protected PropertyChangeListener createPropertyChangeListener()
 454:   {
 455:     return new MetalInternalFrameTitlePanePropertyChangeHandler();
 456:   }
 457: }