1 /* BasicInternalFrameTitlePane.java --
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax
.swing
.plaf
.basic
;
41 import java
.awt
.Color
;
42 import java
.awt
.Component
;
43 import java
.awt
.Container
;
44 import java
.awt
.Dimension
;
46 import java
.awt
.FontMetrics
;
47 import java
.awt
.Graphics
;
48 import java
.awt
.Insets
;
49 import java
.awt
.LayoutManager
;
50 import java
.awt
.Polygon
;
51 import java
.awt
.Rectangle
;
52 import java
.awt
.event
.ActionEvent
;
53 import java
.awt
.event
.KeyEvent
;
54 import java
.beans
.PropertyChangeEvent
;
55 import java
.beans
.PropertyChangeListener
;
56 import java
.beans
.PropertyVetoException
;
58 import javax
.swing
.AbstractAction
;
59 import javax
.swing
.Action
;
60 import javax
.swing
.Icon
;
61 import javax
.swing
.JButton
;
62 import javax
.swing
.JComponent
;
63 import javax
.swing
.JInternalFrame
;
64 import javax
.swing
.JLabel
;
65 import javax
.swing
.JMenu
;
66 import javax
.swing
.JMenuBar
;
67 import javax
.swing
.JMenuItem
;
68 import javax
.swing
.SwingConstants
;
69 import javax
.swing
.SwingUtilities
;
70 import javax
.swing
.UIDefaults
;
71 import javax
.swing
.UIManager
;
74 * This class acts as a titlebar for JInternalFrames.
76 public class BasicInternalFrameTitlePane
extends JComponent
79 * The Action responsible for closing the JInternalFrame.
81 public class CloseAction
extends AbstractAction
84 * This method is called when something closes the JInternalFrame.
86 * @param e The ActionEvent.
88 public void actionPerformed(ActionEvent e
)
90 if (frame
.isClosable())
94 frame
.setClosed(true);
96 catch (PropertyVetoException pve
)
104 * This Action is responsible for iconifying the JInternalFrame.
106 public class IconifyAction
extends AbstractAction
109 * This method is called when the user wants to iconify the
112 * @param e The ActionEvent.
114 public void actionPerformed(ActionEvent e
)
116 if (frame
.isIconifiable() && ! frame
.isIcon())
122 catch (PropertyVetoException pve
)
130 * This Action is responsible for maximizing the JInternalFrame.
132 public class MaximizeAction
extends AbstractAction
135 * This method is called when the user wants to maximize the
138 * @param e The ActionEvent.
140 public void actionPerformed(ActionEvent e
)
144 if (frame
.isMaximizable() && ! frame
.isMaximum())
145 frame
.setMaximum(true);
146 else if (frame
.isMaximum())
147 frame
.setMaximum(false);
149 catch (PropertyVetoException pve
)
156 * This Action is responsible for dragging the JInternalFrame.
158 public class MoveAction
extends AbstractAction
161 * This method is called when the user wants to drag the JInternalFrame.
163 * @param e The ActionEvent.
165 public void actionPerformed(ActionEvent e
)
167 // FIXME: Implement keyboard driven? move actions.
172 * This Action is responsible for restoring the JInternalFrame. Restoring
173 * the JInternalFrame is the same as setting the maximum property to false.
175 public class RestoreAction
extends AbstractAction
178 * This method is called when the user wants to restore the
181 * @param e The ActionEvent.
183 public void actionPerformed(ActionEvent e
)
185 if (frame
.isMaximum())
189 frame
.setMaximum(false);
191 catch (PropertyVetoException pve
)
199 * This action is responsible for sizing the JInternalFrame.
201 public class SizeAction
extends AbstractAction
204 * This method is called when the user wants to resize the JInternalFrame.
206 * @param e The ActionEvent.
208 public void actionPerformed(ActionEvent e
)
210 // FIXME: Not sure how size actions should be handled.
215 * This class is responsible for handling property change events from the
216 * JInternalFrame and adjusting the Title Pane as necessary.
218 protected class PropertyChangeHandler
implements PropertyChangeListener
221 * This method is called when a PropertyChangeEvent is received by the
224 * @param evt The PropertyChangeEvent.
226 public void propertyChange(PropertyChangeEvent evt
)
228 // The title and frameIcon are taken care of during painting time.
229 // The only other thing this will care about are the "is----izable"
230 // properties. So we call enable actions to properly handle the
231 // buttons and menu items for us.
237 * This class acts as the MenuBar for the TitlePane. Clicking on the Frame
238 * Icon in the top left corner will activate it.
240 public class SystemMenuBar
extends JMenuBar
243 * This method returns true if it can receive focus.
245 * @return True if this Component can receive focus.
247 public boolean isFocusTransversable()
253 * This method returns true if this Component is expected to paint all of
256 * @return True if this Component is expect to paint all of itself.
258 public boolean isOpaque()
264 * This method paints this Component.
266 * @param g The Graphics object to paint with.
268 public void paint(Graphics g
)
270 Icon frameIcon
= frame
.getFrameIcon();
271 if (frameIcon
== null)
272 frameIcon
= BasicDesktopIconUI
.defaultIcon
;
273 frameIcon
.paintIcon(this, g
, 0, 0);
277 * This method requests that focus be given to this Component.
279 public void requestFocus()
281 super.requestFocus();
286 * This class acts as the Layout Manager for the TitlePane.
288 protected class TitlePaneLayout
implements LayoutManager
291 * Creates a new <code>TitlePaneLayout</code> object.
293 public TitlePaneLayout()
299 * This method is called when adding a Component to the Container.
301 * @param name The name to reference the added Component by.
302 * @param c The Component to add.
304 public void addLayoutComponent(String name
, Component c
)
310 * This method is called to lay out the children of the Title Pane.
312 * @param c The Container to lay out.
314 public void layoutContainer(Container c
)
318 Insets insets
= c
.getInsets();
319 int width
= c
.getBounds().width
- insets
.left
- insets
.right
;
320 int height
= c
.getBounds().height
- insets
.top
- insets
.bottom
;
322 // MenuBar is always present and located at the top left corner.
323 Dimension menupref
= menuBar
.getPreferredSize();
324 menuBar
.setBounds(insets
.left
, insets
.top
, menupref
.width
, height
);
326 int loc
= width
+ insets
.left
;
328 Insets i
= closeButton
.getInsets();
329 Dimension prefs
= new Dimension(iconSize
+ i
.left
+ i
.right
,
330 iconSize
+ i
.top
+ i
.bottom
);
331 int top
= insets
.top
+ (height
- prefs
.height
) / 2;
332 if (closeAction
.isEnabled())
335 closeButton
.setVisible(true);
336 closeButton
.setBounds(loc
, top
, prefs
.width
, prefs
.height
);
339 closeButton
.setVisible(false);
341 if (maximizeAction
.isEnabled())
344 maxButton
.setVisible(true);
345 maxButton
.setBounds(loc
, top
, prefs
.width
, prefs
.height
);
348 maxButton
.setVisible(false);
350 if (iconifyAction
.isEnabled())
353 iconButton
.setVisible(true);
354 iconButton
.setBounds(loc
, top
, prefs
.width
, prefs
.height
);
357 iconButton
.setVisible(false);
360 title
.setBounds(insets
.left
+ menupref
.width
, insets
.top
,
361 loc
- menupref
.width
- insets
.left
, height
);
365 * This method returns the minimum size of the given Container given the
366 * children that it has.
368 * @param c The Container to get a minimum size for.
370 * @return The minimum size of the Container.
372 public Dimension
minimumLayoutSize(Container c
)
374 return preferredLayoutSize(c
);
378 * This method returns the preferred size of the given Container taking
379 * into account the children that it has.
381 * @param c The Container to lay out.
383 * @return The preferred size of the Container.
385 public Dimension
preferredLayoutSize(Container c
)
387 Insets frameInsets
= frame
.getInsets();
389 // Height is the max of the preferredHeights of all components
395 Component
[] components
= BasicInternalFrameTitlePane
.this.getComponents();
396 for (int i
= 0; i
< components
.length
; i
++)
398 d
= components
[i
].getPreferredSize();
399 height
= Math
.max(height
, d
.height
);
403 Insets insets
= BasicInternalFrameTitlePane
.this.getInsets();
404 height
+= insets
.top
+ insets
.bottom
;
406 return new Dimension(width
, height
);
410 * This method is called when removing a Component from the Container.
412 * @param c The Component to remove.
414 public void removeLayoutComponent(Component c
)
420 * This helper class is used to create the minimize, maximize and close
421 * buttons in the top right corner of the Title Pane. These buttons are
422 * special since they cannot be given focus and have no border.
424 private class PaneButton
extends JButton
427 * Creates a new PaneButton object with the given Action.
429 * @param a The Action that the button uses.
431 public PaneButton(Action a
)
434 setMargin(new Insets(0, 0, 0, 0));
439 * This method returns true if the Component can be focused.
443 public boolean isFocusable()
445 // These buttons cannot be given focus.
450 /** The action command for the Close action. */
451 protected static final String CLOSE_CMD
= "Close";
453 /** The action command for the Minimize action. */
454 protected static final String ICONIFY_CMD
= "Minimize";
456 /** The action command for the Maximize action. */
457 protected static final String MAXIMIZE_CMD
= "Maximize";
459 /** The action command for the Move action. */
460 protected static final String MOVE_CMD
= "Move";
462 /** The action command for the Restore action. */
463 protected static final String RESTORE_CMD
= "Restore";
465 /** The action command for the Size action. */
466 protected static final String SIZE_CMD
= "Size";
468 /** The action associated with closing the JInternalFrame. */
469 protected Action closeAction
;
471 /** The action associated with iconifying the JInternalFrame. */
472 protected Action iconifyAction
;
474 /** The action associated with maximizing the JInternalFrame. */
475 protected Action maximizeAction
;
477 /** The action associated with moving the JInternalFrame. */
478 protected Action moveAction
;
480 /** The action associated with restoring the JInternalFrame. */
481 protected Action restoreAction
;
483 /** The action associated with resizing the JInternalFrame. */
484 protected Action sizeAction
;
486 /** The button that closes the JInternalFrame. */
487 protected JButton closeButton
;
489 /** The button that iconifies the JInternalFrame. */
490 protected JButton iconButton
;
492 /** The button that maximizes the JInternalFrame. */
493 protected JButton maxButton
;
495 /** Active background color. */
496 protected Color activeBGColor
;
498 /** Active foreground color. */
499 protected Color activeFGColor
;
501 /** Inactive background color. */
502 protected Color inactiveBGColor
;
504 /** Inactive foreground color. */
505 protected Color inactiveFGColor
;
507 // FIXME: These icons need to be moved to MetalIconFactory.
509 /** The size of the icons in the buttons. */
510 private static final int iconSize
= 16;
512 /** The icon displayed in the close button. */
513 protected Icon closeIcon
= new Icon()
515 public int getIconHeight()
520 public int getIconWidth()
525 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
528 Color saved
= g
.getColor();
529 g
.setColor(Color
.BLACK
);
531 int four
= iconSize
/ 4;
532 int six
= iconSize
* 6 / 16;
533 int ten
= iconSize
* 10 / 16;
534 int twelve
= iconSize
* 12 / 16;
536 Polygon a
= new Polygon(new int[] { four
, six
, ten
, twelve
},
537 new int[] { six
, four
, twelve
, ten
}, 4);
538 Polygon b
= new Polygon(new int[] { four
, six
, ten
, twelve
},
539 new int[] { ten
, twelve
, four
, six
}, 4);
549 // FIXME: Create new icon.
551 /** The icon displayed in the restore button. */
552 protected Icon minIcon
;
554 /** The icon displayed in the maximize button. */
555 protected Icon maxIcon
= new Icon()
557 public int getIconHeight()
562 public int getIconWidth()
567 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
570 Color saved
= g
.getColor();
571 g
.setColor(Color
.BLACK
);
573 int four
= iconSize
/ 4;
575 int six
= iconSize
* 6 / 16;
576 int eight
= four
* 2;
578 g
.fillRect(four
, four
, eight
, two
);
579 g
.drawRect(four
, six
, eight
, six
);
586 /** The icon displayed in the iconify button. */
587 protected Icon iconIcon
= new Icon()
589 public int getIconHeight()
594 public int getIconWidth()
599 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
602 Color saved
= g
.getColor();
603 g
.setColor(Color
.BLACK
);
605 g
.fillRect(iconSize
/ 4, iconSize
* 10 / 16, iconSize
/ 2, iconSize
/ 8);
612 /** The JInternalFrame that this TitlePane is used in. */
613 protected JInternalFrame frame
;
615 /** The JMenuBar that is located at the top left of the Title Pane. */
616 protected JMenuBar menuBar
;
618 /** The JMenu inside the menuBar. */
619 protected JMenu windowMenu
;
622 * The text color of the TitlePane when the JInternalFrame is not selected.
624 protected Color notSelectedTextColor
;
627 * The background color of the TitlePane when the JInternalFrame is not
630 protected Color notSelectedTitleColor
;
632 /** The text color of the titlePane when the JInternalFrame is selected. */
633 protected Color selectedTextColor
;
636 * The background color of the TitlePane when the JInternalFrame is
639 protected Color selectedTitleColor
;
641 /** The Property Change listener that listens to the JInternalFrame. */
642 protected PropertyChangeListener propertyChangeListener
;
645 * The label used to display the title. This label is not added to the
648 private transient JLabel title
;
651 * Creates a new BasicInternalFrameTitlePane object that is used in the
652 * given JInternalFrame.
654 * @param f The JInternalFrame this BasicInternalFrameTitlePane will be used
657 public BasicInternalFrameTitlePane(JInternalFrame f
)
660 setLayout(createLayout());
661 title
= new JLabel();
662 title
.setHorizontalAlignment(SwingConstants
.LEFT
);
663 title
.setHorizontalTextPosition(SwingConstants
.LEFT
);
664 title
.setOpaque(false);
667 setBackground(Color
.LIGHT_GRAY
);
673 * This method installs the TitlePane onto the JInternalFrameTitlePane. It
674 * also creates any children components that need to be created and adds
675 * listeners to the appropriate components.
677 protected void installTitlePane()
683 assembleSystemMenu();
692 * This method adds the sub components to the TitlePane.
694 protected void addSubComponents()
704 * This method creates the actions that are used to manipulate the
707 protected void createActions()
709 closeAction
= new CloseAction();
710 closeAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, CLOSE_CMD
);
712 iconifyAction
= new IconifyAction();
713 iconifyAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, ICONIFY_CMD
);
715 maximizeAction
= new MaximizeAction();
716 maximizeAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, MAXIMIZE_CMD
);
718 sizeAction
= new SizeAction();
719 sizeAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, SIZE_CMD
);
721 restoreAction
= new RestoreAction();
722 restoreAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, RESTORE_CMD
);
724 moveAction
= new MoveAction();
725 moveAction
.putValue(AbstractAction
.ACTION_COMMAND_KEY
, MOVE_CMD
);
729 * This method is used to install the listeners.
731 protected void installListeners()
733 propertyChangeListener
= new PropertyChangeHandler();
734 frame
.addPropertyChangeListener(propertyChangeListener
);
738 * This method is used to uninstall the listeners.
740 protected void uninstallListeners()
742 frame
.removePropertyChangeListener(propertyChangeListener
);
743 propertyChangeListener
= null;
747 * This method installs the defaults determined by the look and feel.
749 protected void installDefaults()
751 // FIXME: move icons to defaults.
752 UIDefaults defaults
= UIManager
.getLookAndFeelDefaults();
754 setFont(defaults
.getFont("InternalFrame.titleFont"));
755 activeFGColor
= defaults
.getColor("InternalFrame.activeTitleForeground");
756 activeBGColor
= defaults
.getColor("InternalFrame.activeTitleBackground");
757 inactiveFGColor
= defaults
.getColor("InternalFrame.inactiveTitleForeground");
758 inactiveBGColor
= defaults
.getColor("InternalFrame.inactiveTitleBackground");
762 * This method uninstalls the defaults.
764 protected void uninstallDefaults()
767 activeFGColor
= null;
768 activeBGColor
= null;
769 inactiveFGColor
= null;
770 inactiveBGColor
= null;
774 * This method creates the buttons used in the TitlePane.
776 protected void createButtons()
778 closeButton
= new PaneButton(closeAction
);
779 closeButton
.setOpaque(false);
781 iconButton
= new PaneButton(iconifyAction
);
782 iconButton
.setOpaque(false);
784 maxButton
= new PaneButton(maximizeAction
);
785 maxButton
.setOpaque(false);
789 * This method sets the icons in the buttons.
791 protected void setButtonIcons()
793 closeButton
.setIcon(closeIcon
);
794 iconButton
.setIcon(iconIcon
);
795 maxButton
.setIcon(maxIcon
);
799 * This method creates the MenuBar used in the TitlePane.
801 protected void assembleSystemMenu()
803 menuBar
= createSystemMenuBar();
804 windowMenu
= createSystemMenu();
806 menuBar
.add(windowMenu
);
808 addSystemMenuItems(windowMenu
);
813 * This method adds the MenuItems to the given JMenu.
815 * @param systemMenu The JMenu to add MenuItems to.
817 protected void addSystemMenuItems(JMenu systemMenu
)
821 tmp
= new JMenuItem(RESTORE_CMD
);
822 tmp
.addActionListener(restoreAction
);
823 tmp
.setMnemonic(KeyEvent
.VK_R
);
826 tmp
= new JMenuItem(MOVE_CMD
);
827 tmp
.addActionListener(moveAction
);
828 tmp
.setMnemonic(KeyEvent
.VK_M
);
831 tmp
= new JMenuItem(SIZE_CMD
);
832 tmp
.addActionListener(sizeAction
);
833 tmp
.setMnemonic(KeyEvent
.VK_S
);
836 tmp
= new JMenuItem(ICONIFY_CMD
);
837 tmp
.addActionListener(iconifyAction
);
838 tmp
.setMnemonic(KeyEvent
.VK_N
);
841 tmp
= new JMenuItem(MAXIMIZE_CMD
);
842 tmp
.addActionListener(maximizeAction
);
843 tmp
.setMnemonic(KeyEvent
.VK_X
);
846 systemMenu
.addSeparator();
848 tmp
= new JMenuItem(CLOSE_CMD
);
849 tmp
.addActionListener(closeAction
);
850 tmp
.setMnemonic(KeyEvent
.VK_C
);
855 * This method creates a new JMenubar.
857 * @return A new JMenuBar.
859 protected JMenuBar
createSystemMenuBar()
862 menuBar
= new SystemMenuBar();
868 * This method creates a new JMenu.
870 * @return A new JMenu.
872 protected JMenu
createSystemMenu()
874 if (windowMenu
== null)
875 windowMenu
= new JMenu();
876 windowMenu
.removeAll();
881 * This method programmatically shows the JMenu.
883 protected void showSystemMenu()
885 // FIXME: Untested as KeyEvents are not hooked up.
886 menuBar
.getMenu(1).getPopupMenu().show();
890 * This method paints the TitlePane.
892 * @param g The Graphics object to paint with.
894 public void paintComponent(Graphics g
)
896 paintTitleBackground(g
);
897 Font f
= g
.getFont();
898 FontMetrics fm
= g
.getFontMetrics(f
);
899 if (frame
.getTitle() != null && title
!= null)
901 Color saved
= g
.getColor();
902 if (frame
.isSelected())
903 g
.setColor(activeFGColor
);
905 g
.setColor(inactiveFGColor
);
906 title
.setText(getTitle(frame
.getTitle(), fm
, title
.getBounds().width
));
907 SwingUtilities
.paintComponent(g
, title
, null, title
.getBounds());
913 * This method paints the TitlePane's background.
915 * @param g The Graphics object to paint with.
917 protected void paintTitleBackground(Graphics g
)
919 Color saved
= g
.getColor();
920 Dimension dims
= getSize();
922 Color bg
= getBackground();
923 if (frame
.isSelected())
926 bg
= inactiveBGColor
;
928 g
.fillRect(0, 0, dims
.width
, dims
.height
);
933 * This method returns the title string based on the available width and the
936 * @param text The desired title.
937 * @param fm The FontMetrics of the font used.
938 * @param availableWidth The available width.
940 * @return The allowable string.
942 protected String
getTitle(String text
, FontMetrics fm
, int availableWidth
)
944 Rectangle vr
= new Rectangle(0, 0, availableWidth
, fm
.getHeight());
945 Rectangle ir
= new Rectangle();
946 Rectangle tr
= new Rectangle();
947 String value
= SwingUtilities
.layoutCompoundLabel(this, fm
, text
, null,
948 SwingConstants
.CENTER
,
950 SwingConstants
.CENTER
,
951 SwingConstants
.LEFT
, vr
,
957 * This method fires something similar to a WINDOW_CLOSING event.
959 * @param frame The JInternalFrame that is being closed.
961 protected void postClosingEvent(JInternalFrame frame
)
963 // FIXME: Implement postClosingEvent when I figure out what
964 // it's supposed to do.
965 // It says that this fires an WINDOW_CLOSING like event.
966 // So the closest thing is some kind of InternalFrameEvent.
967 // But none is fired.
968 // Can't see it called or anything.
972 * This method enables the actions for the TitlePane given the frame's
975 protected void enableActions()
977 closeAction
.setEnabled(frame
.isClosable());
979 iconifyAction
.setEnabled(frame
.isIconifiable());
980 // The maximize action is responsible for restoring it
981 // as well, if clicked from the button
982 maximizeAction
.setEnabled(frame
.isMaximizable());
984 // The restoring action is only active when selected
986 restoreAction
.setEnabled(frame
.isMaximum());
988 sizeAction
.setEnabled(frame
.isResizable());
990 // FIXME: Tie MoveAction enabled status to a variable.
991 moveAction
.setEnabled(false);
995 * This method creates a new PropertyChangeListener.
997 * @return A new PropertyChangeListener.
999 protected PropertyChangeListener
createPropertyChangeListener()
1001 return new PropertyChangeHandler();
1005 * This method creates a new LayoutManager for the TitlePane.
1007 * @return A new LayoutManager.
1009 protected LayoutManager
createLayout()
1011 return new TitlePaneLayout();