001 /* MetalInternalFrameTitlePane.java 002 Copyright (C) 2005 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.swing.plaf.metal; 040 041 import java.awt.Color; 042 import java.awt.Component; 043 import java.awt.Container; 044 import java.awt.Dimension; 045 import java.awt.Graphics; 046 import java.awt.Insets; 047 import java.awt.LayoutManager; 048 import java.awt.Rectangle; 049 import java.beans.PropertyChangeEvent; 050 import java.beans.PropertyChangeListener; 051 052 import javax.swing.Icon; 053 import javax.swing.JInternalFrame; 054 import javax.swing.JLabel; 055 import javax.swing.JMenu; 056 import javax.swing.SwingConstants; 057 import javax.swing.SwingUtilities; 058 import javax.swing.UIManager; 059 import javax.swing.plaf.basic.BasicInternalFrameTitlePane; 060 061 062 /** 063 * The title pane for a {@link JInternalFrame} (see 064 * {@link MetalInternalFrameUI#createNorthPane(JInternalFrame)}). This can 065 * be displayed in two styles: one for regular internal frames, and the other 066 * for "palette" style internal frames. 067 */ 068 public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane 069 { 070 071 /** 072 * A property change handler that listens for changes to the 073 * <code>JInternalFrame.isPalette</code> property and updates the title 074 * pane as appropriate. 075 */ 076 class MetalInternalFrameTitlePanePropertyChangeHandler 077 extends PropertyChangeHandler 078 { 079 /** 080 * Creates a new handler. 081 */ 082 public MetalInternalFrameTitlePanePropertyChangeHandler() 083 { 084 super(); 085 } 086 087 /** 088 * Handles <code>JInternalFrame.isPalette</code> property changes, with all 089 * other property changes being passed to the superclass. 090 * 091 * @param e the event. 092 */ 093 public void propertyChange(PropertyChangeEvent e) 094 { 095 String propName = e.getPropertyName(); 096 if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) 097 { 098 title.setIcon(frame.getFrameIcon()); 099 } 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 }