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