001/* MetalInternalFrameTitlePane.java
002   Copyright (C) 2005 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.metal;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Container;
044import java.awt.Dimension;
045import java.awt.Graphics;
046import java.awt.Insets;
047import java.awt.LayoutManager;
048import java.awt.Rectangle;
049import java.beans.PropertyChangeEvent;
050import java.beans.PropertyChangeListener;
051
052import javax.swing.Icon;
053import javax.swing.JInternalFrame;
054import javax.swing.JLabel;
055import javax.swing.JMenu;
056import javax.swing.SwingConstants;
057import javax.swing.SwingUtilities;
058import javax.swing.UIManager;
059import 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 */
068public 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}