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 }