EMMA Coverage Report (generated Wed Aug 16 18:51:55 GMT 2006)
[all classes][javax.swing.plaf.metal]

COVERAGE SUMMARY FOR SOURCE FILE [MetalRootPaneUI.java]

nameclass, %method, %block, %line, %
MetalRootPaneUI.java100% (10/10)70%  (39/56)77%  (1205/1569)71%  (254/358)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class MetalRootPaneUI100% (1/1)75%  (6/8)60%  (86/143)60%  (23.4/39)
<static initializer> 100% (1/1)64%  (14/22)63%  (0.6/1)
MetalRootPaneUI (): void 100% (1/1)100% (3/3)100% (2/2)
createUI (JComponent): ComponentUI 100% (1/1)100% (8/8)100% (3/3)
installUI (JComponent): void 100% (1/1)77%  (10/13)80%  (4/5)
installWindowDecorations (JRootPane): void 100% (1/1)85%  (29/34)85%  (6.8/8)
propertyChange (PropertyChangeEvent): void 100% (1/1)88%  (22/25)88%  (7/8)
uninstallUI (JComponent): void 0%   (0/1)0%   (0/13)0%   (0/5)
uninstallWindowDecorations (JRootPane): void 0%   (0/1)0%   (0/25)0%   (0/7)
     
class MetalRootPaneUI$MetalFrameBorder100% (1/1)100% (4/4)93%  (262/282)83%  (30/36)
MetalRootPaneUI$MetalFrameBorder (): void 100% (1/1)100% (3/3)100% (1/1)
getBorderInsets (Component): Insets 100% (1/1)100% (5/5)100% (1/1)
getBorderInsets (Component, Insets): Insets 100% (1/1)52%  (13/25)43%  (3/7)
paintBorder (Component, Graphics, int, int, int, int): void 100% (1/1)97%  (241/249)93%  (25/27)
     
class MetalRootPaneUI$MetalRootLayout100% (1/1)36%  (4/11)77%  (257/335)77%  (58.6/76)
MetalRootPaneUI$MetalRootLayout (MetalRootPaneUI$MetalTitlePane): void 100% (1/1)100% (6/6)100% (3/3)
addLayoutComponent (Component, Object): void 0%   (0/1)0%   (0/1)0%   (0/1)
addLayoutComponent (String, Component): void 0%   (0/1)0%   (0/1)0%   (0/1)
getLayoutAlignmentX (Container): float 0%   (0/1)0%   (0/2)0%   (0/1)
getLayoutAlignmentY (Container): float 0%   (0/1)0%   (0/2)0%   (0/1)
invalidateLayout (Container): void 100% (1/1)90%  (26/29)99%  (7.9/8)
layoutContainer (Container): void 100% (1/1)84%  (154/184)85%  (33.8/40)
maximumLayoutSize (Container): Dimension 0%   (0/1)0%   (0/4)0%   (0/1)
minimumLayoutSize (Container): Dimension 0%   (0/1)0%   (0/4)0%   (0/1)
preferredLayoutSize (Container): Dimension 100% (1/1)70%  (71/101)77%  (13.9/18)
removeLayoutComponent (Component): void 0%   (0/1)0%   (0/1)0%   (0/1)
     
class MetalRootPaneUI$MetalTitlePane100% (1/1)100% (16/16)85%  (406/478)85%  (104/123)
MetalRootPaneUI$MetalTitlePane (JRootPane): void 100% (1/1)100% (29/29)100% (9/9)
addSubComponents (): void 100% (1/1)100% (21/21)100% (5/5)
addSystemMenuItems (JMenu): void 100% (1/1)100% (1/1)100% (1/1)
assembleSystemMenu (): void 100% (1/1)100% (21/21)100% (6/6)
createActions (): void 100% (1/1)100% (19/19)100% (4/4)
createButtons (): void 100% (1/1)100% (61/61)100% (13/13)
createLayout (): LayoutManager 100% (1/1)100% (5/5)100% (1/1)
createSystemMenu (): JMenu 100% (1/1)100% (14/14)100% (4/4)
createSystemMenuBar (): JMenuBar 100% (1/1)100% (14/14)100% (4/4)
enableActions (): void 100% (1/1)100% (1/1)100% (1/1)
installDefaults (): void 100% (1/1)100% (44/44)100% (12/12)
installListeners (): void 100% (1/1)100% (12/12)100% (4/4)
installTitlePane (): void 100% (1/1)100% (17/17)100% (9/9)
paintComponent (Graphics): void 100% (1/1)73%  (105/143)70%  (21/30)
paintTitleBackground (Graphics): void 100% (1/1)19%  (8/42)23%  (3/13)
setButtonIcons (): void 100% (1/1)100% (34/34)100% (7/7)
     
class MetalRootPaneUI$MetalTitlePane$CloseAction100% (1/1)50%  (1/2)12%  (7/60)8%   (2/24)
MetalRootPaneUI$MetalTitlePane$CloseAction (MetalRootPaneUI$MetalTitlePane): ... 100% (1/1)100% (7/7)100% (2/2)
actionPerformed (ActionEvent): void 0%   (0/1)0%   (0/53)0%   (0/22)
     
class MetalRootPaneUI$MetalTitlePane$IconifyAction100% (1/1)50%  (1/2)25%  (6/24)14%  (1/7)
MetalRootPaneUI$MetalTitlePane$IconifyAction (MetalRootPaneUI$MetalTitlePane)... 100% (1/1)100% (6/6)100% (1/1)
actionPerformed (ActionEvent): void 0%   (0/1)0%   (0/18)0%   (0/6)
     
class MetalRootPaneUI$MetalTitlePane$MaximizeAction100% (1/1)50%  (1/2)25%  (6/24)14%  (1/7)
MetalRootPaneUI$MetalTitlePane$MaximizeAction (MetalRootPaneUI$MetalTitlePane... 100% (1/1)100% (6/6)100% (1/1)
actionPerformed (ActionEvent): void 0%   (0/1)0%   (0/18)0%   (0/6)
     
class MetalRootPaneUI$MetalTitlePane$MetalTitlePaneLayout100% (1/1)67%  (4/6)97%  (153/158)94%  (30/32)
MetalRootPaneUI$MetalTitlePane$MetalTitlePaneLayout (MetalRootPaneUI$MetalTit... 100% (1/1)100% (6/6)100% (2/2)
addLayoutComponent (String, Component): void 100% (1/1)100% (1/1)100% (1/1)
layoutContainer (Container): void 100% (1/1)100% (140/140)100% (26/26)
minimumLayoutSize (Container): Dimension 0%   (0/1)0%   (0/4)0%   (0/1)
preferredLayoutSize (Container): Dimension 100% (1/1)100% (6/6)100% (1/1)
removeLayoutComponent (Component): void 0%   (0/1)0%   (0/1)0%   (0/1)
     
class MetalRootPaneUI$MetalTitlePane$MouseHandler100% (1/1)33%  (1/3)13%  (6/47)10%  (1/10)
MetalRootPaneUI$MetalTitlePane$MouseHandler (MetalRootPaneUI$MetalTitlePane):... 100% (1/1)100% (6/6)100% (1/1)
mouseDragged (MouseEvent): void 0%   (0/1)0%   (0/36)0%   (0/7)
mousePressed (MouseEvent): void 0%   (0/1)0%   (0/5)0%   (0/2)
     
class MetalRootPaneUI$MetalTitlePane$PaneButton100% (1/1)50%  (1/2)89%  (16/18)75%  (3/4)
MetalRootPaneUI$MetalTitlePane$PaneButton (MetalRootPaneUI$MetalTitlePane, Ac... 100% (1/1)100% (16/16)100% (3/3)
isFocusable (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)

1/* MetalRootPaneUI.java
2   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3 
4This file is part of GNU Classpath.
5 
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10 
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14General Public License for more details.
15 
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING.  If not, write to the
18Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1902110-1301 USA.
20 
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library.  Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25 
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module.  An independent module is a module which is not derived from
33or based on this library.  If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so.  If you do not wish to do so, delete this
36exception statement from your version. */
37 
38 
39package javax.swing.plaf.metal;
40 
41import java.awt.Color;
42import java.awt.Component;
43import java.awt.Container;
44import java.awt.Dimension;
45import java.awt.Frame;
46import java.awt.Graphics;
47import java.awt.Insets;
48import java.awt.LayoutManager;
49import java.awt.LayoutManager2;
50import java.awt.Point;
51import java.awt.Rectangle;
52import java.awt.Window;
53import java.awt.event.ActionEvent;
54import java.awt.event.MouseEvent;
55import java.beans.PropertyChangeEvent;
56 
57import javax.swing.AbstractAction;
58import javax.swing.Action;
59import javax.swing.Icon;
60import javax.swing.JButton;
61import javax.swing.JComponent;
62import javax.swing.JDialog;
63import javax.swing.JFrame;
64import javax.swing.JLabel;
65import javax.swing.JLayeredPane;
66import javax.swing.JMenu;
67import javax.swing.JMenuBar;
68import javax.swing.JRootPane;
69import javax.swing.SwingConstants;
70import javax.swing.SwingUtilities;
71import javax.swing.UIManager;
72import javax.swing.border.AbstractBorder;
73import javax.swing.event.MouseInputAdapter;
74import javax.swing.plaf.ComponentUI;
75import javax.swing.plaf.basic.BasicRootPaneUI;
76 
77/**
78 * A UI delegate for the {@link JRootPane} component. This implementation
79 * supports the JRootPane <code>windowDecorationStyle</code> property.  
80 * 
81 * @author Roman Kennke (kennke@aicas.com)
82 *
83 * @since 1.4
84 */
85public class MetalRootPaneUI
86  extends BasicRootPaneUI
87{
88 
89  /**
90   * The border that is used on JRootPane when the windowDecorationStyle
91   * property of the JRootPane is set to a different value than NONE.
92   *
93   * @author Roman Kennke (kennke@aicas.com)
94   */
95  private static class MetalFrameBorder
96    extends AbstractBorder
97  {
98    /**
99     * Returns the border insets.
100     *
101     * @param c the component
102     * @param newInsets the insets to be filled with the return value, may be
103     *        <code>null</code> in which case a new object is created
104     *
105     * @return the border insets
106     */
107    public Insets getBorderInsets(Component c, Insets newInsets)
108    {
109      if (newInsets == null)
110        newInsets = new Insets(5, 5, 5, 5);
111      else
112        {
113          newInsets.top = 5;
114          newInsets.left = 5;
115          newInsets.bottom = 5;
116          newInsets.right = 5;
117        }
118      return newInsets;  
119    }
120 
121    /**
122     * Returns the border insets.
123     *
124     * @param c the component
125     *
126     * @return the border insets
127     */
128    public Insets getBorderInsets(Component c)
129    {
130      return getBorderInsets(c, null);
131    }
132 
133    /**
134     * Paints the border for the specified component.
135     * 
136     * @param c  the component
137     * @param g  the graphics device
138     * @param x  the x-coordinate
139     * @param y  the y-coordinate
140     * @param w  the width
141     * @param h  the height
142     */
143    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
144                            int h)
145    {
146      JRootPane f = (JRootPane) c;
147      Window frame = SwingUtilities.getWindowAncestor(f);
148      if (frame.isActive())
149        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
150      else
151        g.setColor(MetalLookAndFeel.getControlDarkShadow());
152      
153      // Fill the border background.
154      g.fillRect(x, y, w, 5);
155      g.fillRect(x, y, 5, h);
156      g.fillRect(x + w - 5, y, 5, h);
157      g.fillRect(x, y + h - 5, w, 5);
158      
159      // Draw a dot in each corner.
160      g.setColor(MetalLookAndFeel.getControl());
161      g.fillRect(x, y, 1, 1);
162      g.fillRect(x + w - 1, y, 1, 1);
163      g.fillRect(x + w - 1, y + h - 1, 1, 1);
164      g.fillRect(x, y + h - 1, 1, 1);
165      
166      // Draw the lines.
167      g.setColor(MetalLookAndFeel.getBlack());
168      g.drawLine(x + 14, y + 2, x + w - 15, y + 2);
169      g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3);
170      g.drawLine(x + 2, y + 14, x + 2, y + h - 15);
171      g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15);
172      
173      // Draw the line highlights.
174      if (frame.isActive())
175        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
176      else 
177        g.setColor(MetalLookAndFeel.getControlShadow());
178      g.drawLine(x + 15, y + 3, x + w - 14, y + 3);
179      g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2);
180      g.drawLine(x + 3, y + 15, x + 3, y + h - 14);
181      g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14);
182    }
183  }
184 
185  /**
186   * The component that renders the title bar for frames. This duplicates
187   * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible
188   * to reuse that class because that is bound to the JInternalFrame and we
189   * need to handle JFrames/JRootPanes here.
190   *
191   * @author Roman Kennke (kennke@aicas.com)
192   */
193  private static class MetalTitlePane extends JComponent
194  {
195 
196    /**
197     * Handles dragging of the title pane and moves the window accordingly.
198     */
199    private class MouseHandler
200      extends MouseInputAdapter
201    {
202      /**
203       * The point where the dragging started.
204       */
205      Point lastDragLocation;
206 
207      /**
208       * Receives notification when the mouse gets pressed on the title pane.
209       * This updates the lastDragLocation.
210       *
211       * @param ev the mouse event
212       */
213      public void mousePressed(MouseEvent ev)
214      {
215        lastDragLocation = ev.getPoint();
216      }
217 
218      /**
219       * Receives notification when the mouse is dragged on the title pane.
220       * This will move the nearest window accordingly.
221       *
222       * @param ev the mouse event
223       */
224      public void mouseDragged(MouseEvent ev)
225      {
226        Point dragLocation = ev.getPoint();
227        int deltaX = dragLocation.x - lastDragLocation.x;
228        int deltaY = dragLocation.y - lastDragLocation.y;
229        Window window = SwingUtilities.getWindowAncestor(rootPane);
230        Point loc = window.getLocation();
231        window.setLocation(loc.x + deltaX, loc.y + deltaY);
232        // Note that we do not update the lastDragLocation. This is because
233        // we move the underlying window while dragging the component, which
234        // results in having the same lastDragLocation under the mouse while
235        // dragging.
236      }
237    }
238 
239    /**
240     * The Action responsible for closing the JInternalFrame.
241     */
242    private class CloseAction extends AbstractAction
243    {
244      /**
245       * Creates a new action.
246       */
247      public CloseAction()
248      {
249        super("Close");
250      }
251      
252      /**
253       * This method is called when something closes the frame.
254       *
255       * @param e the ActionEvent
256       */
257      public void actionPerformed(ActionEvent e)
258      {
259        Window frame = SwingUtilities.getWindowAncestor(rootPane);
260        if (frame instanceof JFrame)
261          {
262            JFrame jframe = (JFrame) frame;
263            switch (jframe.getDefaultCloseOperation())
264            {
265              case JFrame.EXIT_ON_CLOSE:
266                jframe.setVisible(false);
267                jframe.dispose();
268                System.exit(0);
269                break;
270              case JFrame.DISPOSE_ON_CLOSE:
271                jframe.setVisible(false);
272                jframe.dispose();
273                break;
274              case JFrame.HIDE_ON_CLOSE:
275                jframe.setVisible(false);
276                break;
277              case JFrame.DO_NOTHING_ON_CLOSE:
278              default:
279                  break;
280            }
281          }
282        else if (frame instanceof JDialog)
283          {
284            JDialog jdialog = (JDialog) frame;
285            switch (jdialog.getDefaultCloseOperation())
286            {
287              case JFrame.DISPOSE_ON_CLOSE:
288                jdialog.setVisible(false);
289                jdialog.dispose();
290                break;
291              case JFrame.HIDE_ON_CLOSE:
292                jdialog.setVisible(false);
293                break;
294              case JFrame.DO_NOTHING_ON_CLOSE:
295              default:
296                  break;
297            }
298          }
299      }
300    }
301 
302    /**
303     * This action is performed when the iconify button is pressed.
304     */
305    private class IconifyAction
306      extends AbstractAction
307    {
308 
309      public void actionPerformed(ActionEvent event)
310      {
311        Window w = SwingUtilities.getWindowAncestor(rootPane);
312        if (w instanceof Frame)
313          {
314            Frame f = (Frame) w;
315            int state = f.getExtendedState();
316            f.setExtendedState(Frame.ICONIFIED);
317          }
318      }
319        
320    }
321 
322    /**
323     * This action is performed when the maximize button is pressed.
324     */
325    private class MaximizeAction
326      extends AbstractAction
327    {
328 
329      public void actionPerformed(ActionEvent event)
330      {
331        Window w = SwingUtilities.getWindowAncestor(rootPane);
332        if (w instanceof Frame)
333          {
334            Frame f = (Frame) w;
335            int state = f.getExtendedState();
336            f.setExtendedState(Frame.MAXIMIZED_BOTH);
337          }
338      }
339    }
340 
341    /**
342     * This helper class is used to create the minimize, maximize and close
343     * buttons in the top right corner of the Title Pane. These buttons are
344     * special since they cannot be given focus and have no border.
345     */
346    private class PaneButton extends JButton
347    {
348      /**
349       * Creates a new PaneButton object with the given Action.
350       *
351       * @param a The Action that the button uses.
352       */
353      public PaneButton(Action a)
354      {
355        super(a);
356        setMargin(new Insets(0, 0, 0, 0));
357      }
358 
359      /**
360       * This method returns true if the Component can be focused.
361       *
362       * @return false.
363       */
364      public boolean isFocusable()
365      {
366        // These buttons cannot be given focus.
367        return false;
368      }
369 
370    }
371 
372    /**
373     * The layout for the JRootPane when the <code>windowDecorationStyle</code>
374     * property is set. In addition to the usual JRootPane.RootLayout behaviour
375     * this lays out the titlePane.
376     *
377     * @author Roman Kennke (kennke@aicas.com)
378     */
379    private class MetalTitlePaneLayout implements LayoutManager
380    {
381      /**
382       * Creates a new <code>TitlePaneLayout</code> object.
383       */
384      public MetalTitlePaneLayout()
385      {
386        // Do nothing.
387      }
388 
389      /**
390       * Adds a Component to the Container.
391       *
392       * @param name The name to reference the added Component by.
393       * @param c The Component to add.
394       */
395      public void addLayoutComponent(String name, Component c)
396      {
397        // Do nothing.
398      }
399 
400      /**
401       * This method is called to lay out the children of the Title Pane.
402       *
403       * @param c The Container to lay out.
404       */
405      public void layoutContainer(Container c)
406      {
407 
408        Dimension size = c.getSize();
409        Insets insets = c.getInsets();
410        int width = size.width - insets.left - insets.right;
411        int height = size.height - insets.top - insets.bottom;
412 
413        int loc = width - insets.right - 1;
414        int top = insets.top + 2;
415        int buttonHeight = height - 4;
416        if (closeButton.isVisible())
417          {
418            int buttonWidth = closeIcon.getIconWidth();
419            loc -= buttonWidth + 2;
420            closeButton.setBounds(loc, top, buttonWidth, buttonHeight);
421            loc -= 6;
422          }
423 
424        if (maxButton.isVisible())
425          {
426            int buttonWidth = maxIcon.getIconWidth();
427            loc -= buttonWidth + 4;
428            maxButton.setBounds(loc, top, buttonWidth, buttonHeight);
429          }
430 
431        if (iconButton.isVisible())
432          {
433            int buttonWidth = minIcon.getIconWidth();
434            loc -= buttonWidth + 4;
435            iconButton.setBounds(loc, top, buttonWidth, buttonHeight);
436            loc -= 2;
437          }
438 
439        Dimension titlePreferredSize = title.getPreferredSize();
440        title.setBounds(insets.left + 5, insets.top, 
441                Math.min(titlePreferredSize.width, loc - insets.left - 10), 
442                height);
443 
444      }
445 
446      /**
447       * This method returns the minimum size of the given Container given the
448       * children that it has.
449       *
450       * @param c The Container to get a minimum size for.
451       *
452       * @return The minimum size of the Container.
453       */
454      public Dimension minimumLayoutSize(Container c)
455      {
456        return preferredLayoutSize(c);
457      }
458 
459      /**
460       * Returns the preferred size of the given Container taking
461       * into account the children that it has.
462       *
463       * @param c The Container to lay out.
464       *
465       * @return The preferred size of the Container.
466       */
467      public Dimension preferredLayoutSize(Container c)
468      {
469        return new Dimension(22, 22);
470      }
471 
472      /**
473       * Removes a Component from the Container.
474       *
475       * @param c The Component to remove.
476       */
477      public void removeLayoutComponent(Component c)
478      {
479        // Nothing to do here.
480      }
481    }
482 
483    JRootPane rootPane;
484 
485    /** The button that closes the JInternalFrame. */
486    JButton closeButton;
487 
488    /** The button that iconifies the JInternalFrame. */
489    JButton iconButton;
490 
491    /** The button that maximizes the JInternalFrame. */
492    JButton maxButton;
493 
494    Icon minIcon;
495 
496    /** The icon displayed in the maximize button. */
497    Icon maxIcon;
498 
499    /** The icon displayed in the iconify button. */
500    private Icon iconIcon;
501 
502    /** The icon displayed in the close button. */
503    Icon closeIcon;
504    
505    /**
506     * The background color of the TitlePane when the JInternalFrame is not
507     * selected.
508     */
509    private Color notSelectedTitleColor;
510 
511    /**
512     * The background color of the TitlePane when the JInternalFrame is
513     * selected.
514     */
515    private Color selectedTitleColor;
516 
517    /**
518     * The label used to display the title. This label is not added to the
519     * TitlePane.
520     */
521    JLabel title;
522 
523    /** The action associated with closing the JInternalFrame. */
524    private Action closeAction;
525 
526    /** The action associated with iconifying the JInternalFrame. */
527    private Action iconifyAction;
528 
529    /** The action associated with maximizing the JInternalFrame. */
530    private Action maximizeAction;
531 
532    /** The JMenuBar that is located at the top left of the Title Pane. */
533    private JMenuBar menuBar;
534 
535    /** The JMenu inside the menuBar. */
536    protected JMenu windowMenu;
537 
538    MetalTitlePane(JRootPane rp)
539    {
540      rootPane = rp;
541      setLayout(createLayout());
542      title = new JLabel();
543      title.setHorizontalAlignment(SwingConstants.LEFT);
544      title.setHorizontalTextPosition(SwingConstants.LEFT);
545      title.setOpaque(false);
546      installTitlePane();
547    }
548 
549    protected LayoutManager createLayout()
550    {
551      return new MetalTitlePaneLayout();
552    }
553 
554    /**
555     * This method installs the TitlePane onto the JInternalFrameTitlePane. It
556     * also creates any children components that need to be created and adds
557     * listeners to the appropriate components.
558     */
559    protected void installTitlePane()
560    {
561      installDefaults();
562      installListeners();
563      createActions();
564      assembleSystemMenu();
565      createButtons();
566      setButtonIcons();
567      addSubComponents();
568      enableActions();
569    }
570 
571    private void enableActions()
572    {
573      // TODO: Implement this.
574    }
575 
576    private void addSubComponents()
577    {
578      add(menuBar);
579      add(closeButton);
580      add(iconButton);
581      add(maxButton);
582    }
583 
584    private void installListeners()
585    {
586      MouseInputAdapter mouseHandler = new MouseHandler();
587      addMouseListener(mouseHandler);
588      addMouseMotionListener(mouseHandler);
589    }
590 
591    private void createActions()
592    {
593      closeAction = new CloseAction();
594      iconifyAction = new IconifyAction();
595      maximizeAction = new MaximizeAction();
596    }
597 
598    private void assembleSystemMenu()
599    {
600      menuBar = createSystemMenuBar();
601      windowMenu = createSystemMenu();
602      menuBar.add(windowMenu);
603      addSystemMenuItems(windowMenu);
604      enableActions();
605    }
606 
607    protected JMenuBar createSystemMenuBar()
608    {
609      if (menuBar == null)
610        menuBar = new JMenuBar();
611      menuBar.removeAll();
612      return menuBar;
613    }
614 
615    protected JMenu createSystemMenu()
616    {
617      if (windowMenu == null)
618        windowMenu = new JMenu();
619      windowMenu.removeAll();
620      return windowMenu;
621    }
622 
623    private void addSystemMenuItems(JMenu menu)
624    {
625      // TODO: Implement this.
626    }
627 
628    protected void createButtons()
629    {
630      closeButton = new PaneButton(closeAction);
631      closeButton.setText(null);
632      iconButton = new PaneButton(iconifyAction);
633      iconButton.setText(null);
634      maxButton = new PaneButton(maximizeAction);
635      maxButton.setText(null);
636      closeButton.setBorderPainted(false);
637      closeButton.setContentAreaFilled(false);
638      iconButton.setBorderPainted(false);
639      iconButton.setContentAreaFilled(false);
640      maxButton.setBorderPainted(false);
641      maxButton.setContentAreaFilled(false);
642    }
643 
644    protected void setButtonIcons()
645    {
646      if (closeIcon != null && closeButton != null)
647        closeButton.setIcon(closeIcon);
648      if (iconIcon != null && iconButton != null)
649        iconButton.setIcon(iconIcon);
650      if (maxIcon != null && maxButton != null)
651        maxButton.setIcon(maxIcon);
652    }
653 
654    /**
655     * Paints a representation of the current state of the internal frame.
656     * 
657     * @param g  the graphics device.
658     */
659    public void paintComponent(Graphics g)
660    {
661      Window frame = SwingUtilities.getWindowAncestor(rootPane);
662      Color savedColor = g.getColor();
663      paintTitleBackground(g);
664      paintChildren(g);
665      Dimension d = getSize();
666      if (frame.isActive())
667        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
668      else
669        g.setColor(MetalLookAndFeel.getControlDarkShadow());
670          
671      // put a dot in each of the top corners
672      g.drawLine(0, 0, 0, 0);
673      g.drawLine(d.width - 1, 0, d.width - 1, 0);
674          
675      g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
676          
677      // draw the metal pattern
678      if (UIManager.get("InternalFrame.activeTitleGradient") != null
679          && frame.isActive())
680        {
681          MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(),
682                                   SwingConstants.VERTICAL,
683          "InternalFrame.activeTitleGradient");
684        }
685 
686      Rectangle b = title.getBounds();
687      int startX = b.x + b.width + 5;
688      int endX = startX;
689      if (iconButton.isVisible())
690        endX = Math.max(iconButton.getX(), endX);
691      else if (maxButton.isVisible()) 
692        endX = Math.max(maxButton.getX(), endX);
693      else if (closeButton.isVisible())
694        endX = Math.max(closeButton.getX(), endX);
695      endX -= 7;
696      if (endX > startX)
697        MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray);
698      g.setColor(savedColor);
699    }
700 
701    /**
702     * This method paints the TitlePane's background.
703     *
704     * @param g The Graphics object to paint with.
705     */
706    protected void paintTitleBackground(Graphics g)
707    {
708      Window frame = SwingUtilities.getWindowAncestor(rootPane);
709 
710      if (!isOpaque())
711        return;
712      
713      Color saved = g.getColor();
714      Dimension dims = getSize();
715      
716      Color bg = getBackground();
717      if (frame.isActive())
718        bg = selectedTitleColor;
719      else
720        bg = notSelectedTitleColor;
721      g.setColor(bg);
722      g.fillRect(0, 0, dims.width, dims.height);
723      g.setColor(saved);
724    }
725 
726    /**
727     * This method installs the defaults determined by the look and feel.
728     */
729    private void installDefaults()
730    {
731      title.setFont(UIManager.getFont("InternalFrame.titleFont"));
732      selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
733      notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
734      closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
735      iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
736      maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
737      minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16);
738      Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane);
739      title = new JLabel(frame.getTitle(), 
740              MetalIconFactory.getInternalFrameDefaultMenuIcon(), 
741              SwingConstants.LEFT);
742    }
743  }
744 
745  private static class MetalRootLayout
746    implements LayoutManager2
747  {
748 
749    /**
750     * The cached layout info for the glass pane.
751     */
752    private Rectangle glassPaneBounds;
753 
754    /**
755     * The cached layout info for the layered pane.
756     */
757    private Rectangle layeredPaneBounds;
758 
759    /**
760     * The cached layout info for the content pane.
761     */
762    private Rectangle contentPaneBounds;
763 
764    /**
765     * The cached layout info for the menu bar.
766     */
767    private Rectangle menuBarBounds;
768 
769    /**
770     * The cached layout info for the title pane.
771     */
772    private Rectangle titlePaneBounds;
773    
774    /**
775     * The cached preferred size.
776     */
777    private Dimension prefSize;
778 
779    /**
780     * The title pane for l&f decorated frames.
781     */
782    private MetalTitlePane titlePane;
783 
784    /**
785     * Creates a new MetalRootLayout.
786     *
787     * @param tp the title pane
788     */
789    MetalRootLayout(MetalTitlePane tp)
790    {
791      titlePane = tp;
792    }
793 
794    public void addLayoutComponent(Component component, Object constraints)
795    {
796      // Nothing to do here.
797    }
798 
799    public Dimension maximumLayoutSize(Container target)
800    {
801      return preferredLayoutSize(target);
802    }
803 
804    public float getLayoutAlignmentX(Container target)
805    {
806      return 0.0F;
807    }
808 
809    public float getLayoutAlignmentY(Container target)
810    {
811      return 0.0F;
812    }
813 
814    public void invalidateLayout(Container target)
815    {
816      synchronized (this)
817      {
818        glassPaneBounds = null;
819        layeredPaneBounds = null;
820        contentPaneBounds = null;
821        menuBarBounds = null;
822        titlePaneBounds = null;
823        prefSize = null;
824      }
825    }
826 
827    public void addLayoutComponent(String name, Component component)
828    {
829      // Nothing to do here.
830    }
831 
832    public void removeLayoutComponent(Component component)
833    {
834      // TODO Auto-generated method stub
835      
836    }
837 
838    public Dimension preferredLayoutSize(Container parent)
839    {
840      JRootPane rp = (JRootPane) parent;
841      JLayeredPane layeredPane = rp.getLayeredPane();
842      Component contentPane = rp.getContentPane();
843      Component menuBar = rp.getJMenuBar();
844 
845      // We must synchronize here, otherwise we cannot guarantee that the
846      // prefSize is still non-null when returning.
847      synchronized (this)
848        {
849          if (prefSize == null)
850            {
851              Insets i = parent.getInsets();
852              prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
853              Dimension contentPrefSize = contentPane.getPreferredSize();
854              prefSize.width += contentPrefSize.width;
855              prefSize.height += contentPrefSize.height
856                                 + titlePane.getPreferredSize().height;
857              if (menuBar != null)
858                {
859                  Dimension menuBarSize = menuBar.getPreferredSize();
860                  if (menuBarSize.width > contentPrefSize.width)
861                    prefSize.width += menuBarSize.width - contentPrefSize.width;
862                  prefSize.height += menuBarSize.height;
863                }
864            }
865          // Return a copy here so the cached value won't get trashed by some
866          // other component.
867          return new Dimension(prefSize);
868      }
869    }
870 
871    public Dimension minimumLayoutSize(Container parent)
872    {
873      return preferredLayoutSize(parent);
874    }
875 
876    public void layoutContainer(Container parent)
877    {
878      JRootPane rp = (JRootPane) parent;
879      JLayeredPane layeredPane = rp.getLayeredPane();
880      Component contentPane = rp.getContentPane();
881      Component menuBar = rp.getJMenuBar();
882      Component glassPane = rp.getGlassPane();
883 
884      if (glassPaneBounds == null || layeredPaneBounds == null
885          || contentPaneBounds == null || menuBarBounds == null)
886        {
887          Insets i = rp.getInsets();
888          int containerWidth = parent.getBounds().width - i.left - i.right;
889          int containerHeight = parent.getBounds().height - i.top - i.bottom;
890 
891          // 1. The glassPane fills entire viewable region (bounds - insets).
892          // 2. The layeredPane filles entire viewable region.
893          // 3. The titlePane is placed at the upper edge of the layeredPane.
894          // 4. The menuBar is positioned at the upper edge of layeredPane.
895          // 5. The contentPane fills viewable region minus menuBar minus
896          //    titlePane, if present.
897      
898          // +-------------------------------+
899          // |  JLayeredPane                 |
900          // |  +--------------------------+ |
901          // |  | titlePane                + |
902          // |  +--------------------------+ |
903          // |  +--------------------------+ |
904          // |  | menuBar                  | |
905          // |  +--------------------------+ |
906          // |  +--------------------------+ |
907          // |  |contentPane               | |
908          // |  |                          | |
909          // |  |                          | |
910          // |  |                          | |
911          // |  +--------------------------+ |
912          // +-------------------------------+
913 
914          // Setup titlePaneBounds.
915          if (titlePaneBounds == null)
916            titlePaneBounds = new Rectangle();
917          titlePaneBounds.width = containerWidth;
918          titlePaneBounds.height = titlePane.getPreferredSize().height;
919 
920          // Setup menuBarBounds.
921          if (menuBarBounds == null)
922            menuBarBounds = new Rectangle();
923          menuBarBounds.setBounds(0,
924                                  titlePaneBounds.y + titlePaneBounds.height,
925                                  containerWidth, 0);
926          if (menuBar != null)
927            {
928              Dimension menuBarSize = menuBar.getPreferredSize();
929              if (menuBarSize.height > containerHeight)
930                menuBarBounds.height = containerHeight;
931              else
932                menuBarBounds.height = menuBarSize.height;
933            }
934 
935          // Setup contentPaneBounds.
936          if (contentPaneBounds == null)
937            contentPaneBounds = new Rectangle();
938          contentPaneBounds.setBounds(0,
939                                      menuBarBounds.y + menuBarBounds.height,
940                                      containerWidth,
941                                      containerHeight - menuBarBounds.y
942                                      - menuBarBounds.height);
943          glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
944          layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
945        }
946 
947      // Layout components.
948      glassPane.setBounds(glassPaneBounds);
949      layeredPane.setBounds(layeredPaneBounds);
950      if (menuBar != null)
951        menuBar.setBounds(menuBarBounds);
952      contentPane.setBounds(contentPaneBounds);
953      titlePane.setBounds(titlePaneBounds);
954    }
955      
956  }
957 
958  /**
959   * The shared UI instance for MetalRootPaneUIs.
960   */
961  private static MetalRootPaneUI instance;
962 
963  /**
964   * Constructs a shared instance of <code>MetalRootPaneUI</code>.
965   */
966  public MetalRootPaneUI()
967  {
968    super();
969  }
970 
971  /**
972   * Returns a shared instance of <code>MetalRootPaneUI</code>.
973   *
974   * @param component the component for which we return an UI instance
975   *
976   * @return A shared instance of <code>MetalRootPaneUI</code>.
977   */
978  public static ComponentUI createUI(JComponent component)
979  {
980    if (instance == null)
981      instance = new MetalRootPaneUI();
982    return instance;
983  }
984 
985  /**
986   * Installs this UI to the root pane. If the
987   * <code>windowDecorationsStyle</code> property is set on the root pane,
988   * the Metal window decorations are installed on the root pane.
989   *
990   * @param c
991   */
992  public void installUI(JComponent c)
993  {
994    super.installUI(c);
995    JRootPane rp = (JRootPane) c;
996    if (rp.getWindowDecorationStyle() != JRootPane.NONE)
997      installWindowDecorations(rp);
998  }
999 
1000  /**
1001   * Uninstalls the UI from the root pane. This performs the superclass
1002   * behaviour and uninstalls the window decorations that have possibly been
1003   * installed by {@link #installUI}.
1004   *
1005   * @param c the root pane
1006   */
1007  public void uninstallUI(JComponent c)
1008  {
1009    JRootPane rp = (JRootPane) c;
1010    if (rp.getWindowDecorationStyle() != JRootPane.NONE)
1011      uninstallWindowDecorations(rp);
1012    super.uninstallUI(c);
1013  }
1014 
1015  /**
1016   * Receives notification if any of the JRootPane's property changes. In
1017   * particular this catches changes to the <code>windowDecorationStyle</code>
1018   * property and installs the window decorations accordingly.
1019   *
1020   * @param ev the property change event
1021   */
1022  public void propertyChange(PropertyChangeEvent ev)
1023  {
1024    super.propertyChange(ev);
1025    String propertyName = ev.getPropertyName();
1026    if (propertyName.equals("windowDecorationStyle"))
1027      {
1028        JRootPane rp = (JRootPane) ev.getSource();
1029        if (rp.getWindowDecorationStyle() != JRootPane.NONE)
1030          installWindowDecorations(rp);
1031        else
1032          uninstallWindowDecorations(rp);
1033      }
1034  }
1035 
1036  /**
1037   * Installs the window decorations to the root pane. This sets up a border,
1038   * a title pane and a layout manager that can layout the root pane with that
1039   * title pane.
1040   *
1041   * @param rp the root pane.
1042   */
1043  private void installWindowDecorations(JRootPane rp)
1044  {
1045    rp.setBorder(new MetalFrameBorder());
1046    MetalTitlePane titlePane = new MetalTitlePane(rp);
1047    rp.setLayout(new MetalRootLayout(titlePane));
1048    // We should have a contentPane already.
1049    assert rp.getLayeredPane().getComponentCount() > 0
1050           : "We should have a contentPane already";
1051 
1052    rp.getLayeredPane().add(titlePane,
1053                            JLayeredPane.FRAME_CONTENT_LAYER, 1);
1054  }
1055 
1056  /**
1057   * Uninstalls the window decorations from the root pane. This should rarely
1058   * be necessary, but we do it anyway.
1059   *
1060   * @param rp the root pane
1061   */
1062  private void uninstallWindowDecorations(JRootPane rp)
1063  {
1064    rp.setBorder(null);
1065    JLayeredPane lp = rp.getLayeredPane();
1066    for (int i = lp.getComponentCount() - 1; i >= 0; --i)
1067      {
1068        if (lp.getComponent(i) instanceof MetalTitlePane)
1069          {
1070            lp.remove(i);
1071            break;
1072          }
1073      }
1074  }
1075}

[all classes][javax.swing.plaf.metal]
EMMA 2.0.6427 (unsupported private build) (C) Vladimir Roubtsov