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    }