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