1. /*
  2. * @(#)BasicInternalFrameTitlePane.java 1.33 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.basic;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import javax.swing.*;
  14. import javax.swing.plaf.*;
  15. import javax.swing.border.*;
  16. import javax.swing.event.InternalFrameEvent;
  17. import java.util.EventListener;
  18. import java.beans.PropertyChangeListener;
  19. import java.beans.PropertyChangeEvent;
  20. import java.beans.VetoableChangeListener;
  21. import java.beans.PropertyVetoException;
  22. /**
  23. * The class that manages a basic title bar
  24. * <p>
  25. * <strong>Warning:</strong>
  26. * Serialized objects of this class will not be compatible with
  27. * future Swing releases. The current serialization support is appropriate
  28. * for short term storage or RMI between applications running the same
  29. * version of Swing. A future release of Swing will provide support for
  30. * long term persistence.
  31. *
  32. * @version 1.33 02/02/00
  33. * @author David Kloba
  34. * @author Steve Wilson
  35. */
  36. public class BasicInternalFrameTitlePane extends JComponent
  37. {
  38. protected JMenuBar menuBar;
  39. protected JButton iconButton;
  40. protected JButton maxButton;
  41. protected JButton closeButton;
  42. protected JMenu windowMenu;
  43. protected JInternalFrame frame;
  44. protected Color selectedTitleColor;
  45. protected Color selectedTextColor;
  46. protected Color notSelectedTitleColor;
  47. protected Color notSelectedTextColor;
  48. protected Icon maxIcon;
  49. protected Icon minIcon;
  50. protected Icon iconIcon;
  51. protected Icon closeIcon;
  52. protected PropertyChangeListener propertyChangeListener;
  53. protected Action closeAction;
  54. protected Action maximizeAction;
  55. protected Action iconifyAction;
  56. protected Action restoreAction;
  57. protected Action moveAction;
  58. protected Action sizeAction;
  59. protected static final String CLOSE_CMD = "Close";
  60. protected static final String ICONIFY_CMD = "Minimize";
  61. protected static final String RESTORE_CMD = "Restore";
  62. protected static final String MAXIMIZE_CMD = "Maximize";
  63. protected static final String MOVE_CMD = "Move";
  64. protected static final String SIZE_CMD = "Size";
  65. public BasicInternalFrameTitlePane(JInternalFrame f) {
  66. frame = f;
  67. installTitlePane();
  68. }
  69. protected void installTitlePane() {
  70. installDefaults();
  71. // Installing listeners must be done in addNotify because they are
  72. // uninstalled in removeNotify. Internal frames (and their title panes)
  73. // get removed and re-added to their parent every time they are
  74. // selected, although this is an implementation detail that may
  75. // eventually change. Installing the defaults should not happen in
  76. // addNotify however because changes in the default LAF would be picked
  77. // up every time a frame was selected.
  78. createActions();
  79. enableActions();
  80. createActionMap();
  81. setLayout(createLayout());
  82. assembleSystemMenu();
  83. createButtons();
  84. addSubComponents();
  85. }
  86. protected void addSubComponents() {
  87. add(menuBar);
  88. add(iconButton);
  89. add(maxButton);
  90. add(closeButton);
  91. }
  92. protected void createActions() {
  93. maximizeAction = new MaximizeAction();
  94. iconifyAction = new IconifyAction();
  95. closeAction = new CloseAction();
  96. restoreAction = new RestoreAction();
  97. moveAction = new MoveAction();
  98. sizeAction = new SizeAction();
  99. }
  100. ActionMap createActionMap() {
  101. ActionMap map = new ActionMapUIResource();
  102. map.put("showSystemMenu", new ShowSystemMenuAction(true));
  103. map.put("hideSystemMenu", new ShowSystemMenuAction(false));
  104. return map;
  105. }
  106. protected void installListeners() {
  107. if( propertyChangeListener == null ) {
  108. propertyChangeListener = createPropertyChangeListener();
  109. }
  110. frame.addPropertyChangeListener(propertyChangeListener);
  111. }
  112. protected void uninstallListeners() {
  113. frame.removePropertyChangeListener(propertyChangeListener);
  114. }
  115. protected void installDefaults() {
  116. maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
  117. minIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
  118. iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
  119. closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
  120. selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
  121. selectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");
  122. notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
  123. notSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
  124. }
  125. protected void uninstallDefaults() {
  126. }
  127. public void addNotify() {
  128. super.addNotify();
  129. installListeners();
  130. addSystemMenuItems(windowMenu);
  131. enableActions();
  132. }
  133. public void removeNotify() {
  134. super.removeNotify();
  135. if (windowMenu!=null) {
  136. windowMenu.removeAll();
  137. }
  138. uninstallDefaults();
  139. uninstallListeners();
  140. }
  141. protected void createButtons() {
  142. iconButton = new NoFocusButton();
  143. iconButton.addActionListener(iconifyAction);
  144. maxButton = new NoFocusButton();
  145. maxButton.addActionListener(maximizeAction);
  146. closeButton = new NoFocusButton();
  147. closeButton.addActionListener(closeAction);
  148. setButtonIcons();
  149. }
  150. protected void setButtonIcons() {
  151. if(frame.isIcon()) {
  152. iconButton.setIcon(minIcon);
  153. maxButton.setIcon(maxIcon);
  154. } else if (frame.isMaximum()) {
  155. iconButton.setIcon(iconIcon);
  156. maxButton.setIcon(minIcon);
  157. } else {
  158. iconButton.setIcon(iconIcon);
  159. maxButton.setIcon(maxIcon);
  160. }
  161. closeButton.setIcon(closeIcon);
  162. }
  163. protected void assembleSystemMenu() {
  164. menuBar = createSystemMenuBar();
  165. windowMenu = createSystemMenu();
  166. menuBar.add(windowMenu);
  167. // moved to addNotify - addSystemMenuItems(windowMenu);
  168. enableActions();
  169. }
  170. protected void addSystemMenuItems(JMenu systemMenu) {
  171. JMenuItem mi = (JMenuItem)systemMenu.add(restoreAction);
  172. mi.setMnemonic('R');
  173. mi = (JMenuItem)systemMenu.add(moveAction);
  174. mi.setMnemonic('M');
  175. mi = (JMenuItem)systemMenu.add(sizeAction);
  176. mi.setMnemonic('S');
  177. mi = (JMenuItem)systemMenu.add(iconifyAction);
  178. mi.setMnemonic('n');
  179. mi = (JMenuItem)systemMenu.add(maximizeAction);
  180. mi.setMnemonic('x');
  181. systemMenu.add(new JSeparator());
  182. mi = (JMenuItem)systemMenu.add(closeAction);
  183. mi.setMnemonic('C');
  184. }
  185. protected JMenu createSystemMenu() {
  186. return new JMenu(" ");
  187. }
  188. protected JMenuBar createSystemMenuBar() {
  189. menuBar = new SystemMenuBar();
  190. menuBar.setBorderPainted(false);
  191. return menuBar;
  192. }
  193. protected void showSystemMenu(){
  194. // windowMenu.setPopupMenuVisible(true);
  195. // windowMenu.setVisible(true);
  196. windowMenu.doClick();
  197. }
  198. public void paintComponent(Graphics g) {
  199. boolean isSelected = frame.isSelected();
  200. if(isSelected)
  201. g.setColor(selectedTitleColor);
  202. else
  203. g.setColor(notSelectedTitleColor);
  204. g.fillRect(0, 0, getWidth(), getHeight());
  205. if(frame.getTitle() != null) {
  206. Font f = g.getFont();
  207. g.setFont(UIManager.getFont("InternalFrame.titleFont"));
  208. if(isSelected)
  209. g.setColor(selectedTextColor);
  210. else
  211. g.setColor(notSelectedTextColor);
  212. // Center text vertically.
  213. FontMetrics fm = g.getFontMetrics();
  214. int fmHeight = fm.getHeight() - fm.getLeading();
  215. int baseline = (18 - fmHeight) / 2 +
  216. fm.getAscent() + fm.getLeading();
  217. int titleX;
  218. String title = frame.getTitle();
  219. if( BasicGraphicsUtils.isLeftToRight(frame) ) {
  220. titleX = menuBar.getX() + menuBar.getWidth() + 2;
  221. } else {
  222. titleX = menuBar.getX() - 2
  223. - SwingUtilities.computeStringWidth(fm,title);
  224. }
  225. g.drawString(title, titleX, baseline);
  226. g.setFont(f);
  227. }
  228. }
  229. /**
  230. * Post a WINDOW_CLOSING-like event to the frame, so that it can
  231. * be treated like a regular Frame.
  232. */
  233. protected void postClosingEvent(JInternalFrame frame) {
  234. InternalFrameEvent e = new InternalFrameEvent(
  235. frame, InternalFrameEvent.INTERNAL_FRAME_CLOSING);
  236. // Try posting event, unless there's a SecurityManager.
  237. if (JInternalFrame.class.getClassLoader() == null) {
  238. try {
  239. Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
  240. return;
  241. } catch (SecurityException se) {
  242. // Use dispatchEvent instead.
  243. }
  244. }
  245. frame.dispatchEvent(e);
  246. }
  247. protected void enableActions() {
  248. restoreAction.setEnabled(frame.isMaximum() || frame.isIcon());
  249. maximizeAction.setEnabled(frame.isMaximizable() && !frame.isMaximum() );
  250. iconifyAction.setEnabled(frame.isIconifiable() && !frame.isIcon());
  251. closeAction.setEnabled(frame.isClosable());
  252. sizeAction.setEnabled(false);
  253. moveAction.setEnabled(false);
  254. }
  255. protected PropertyChangeListener createPropertyChangeListener() {
  256. return new PropertyChangeHandler();
  257. }
  258. protected LayoutManager createLayout() {
  259. return new TitlePaneLayout();
  260. }
  261. /**
  262. * This inner class is marked "public" due to a compiler bug.
  263. * This class should be treated as a "protected" inner class.
  264. * Instantiate it only within subclasses of <Foo>.
  265. */
  266. public class PropertyChangeHandler implements PropertyChangeListener {
  267. public void propertyChange(PropertyChangeEvent evt) {
  268. String prop = (String)evt.getPropertyName();
  269. if(JInternalFrame.IS_SELECTED_PROPERTY.equals(prop)) {
  270. repaint();
  271. return;
  272. }
  273. if(JInternalFrame.IS_ICON_PROPERTY.equals(prop) ||
  274. JInternalFrame.IS_MAXIMUM_PROPERTY.equals(prop)) {
  275. setButtonIcons();
  276. enableActions();
  277. return;
  278. }
  279. if( prop.equals("closable") ) {
  280. if( (Boolean)evt.getNewValue() == Boolean.TRUE )
  281. add(closeButton);
  282. else
  283. remove(closeButton);
  284. } else if( prop.equals("maximizable") ) {
  285. if( (Boolean)evt.getNewValue() == Boolean.TRUE )
  286. add(maxButton);
  287. else
  288. remove(maxButton);
  289. } else if( prop.equals("iconifiable") ) {
  290. if( (Boolean)evt.getNewValue() == Boolean.TRUE )
  291. add(iconButton);
  292. else
  293. remove(iconButton);
  294. }
  295. enableActions();
  296. revalidate();
  297. repaint();
  298. }
  299. } // end PropertyHandler class
  300. /**
  301. * This inner class is marked "public" due to a compiler bug.
  302. * This class should be treated as a "protected" inner class.
  303. * Instantiate it only within subclasses of <Foo>.
  304. */
  305. public class TitlePaneLayout implements LayoutManager {
  306. public void addLayoutComponent(String name, Component c) {}
  307. public void removeLayoutComponent(Component c) {}
  308. public Dimension preferredLayoutSize(Container c) {
  309. return new Dimension(100, 18);
  310. }
  311. public Dimension minimumLayoutSize(Container c) {
  312. return preferredLayoutSize(c);
  313. }
  314. public void layoutContainer(Container c) {
  315. boolean leftToRight = BasicGraphicsUtils.isLeftToRight(frame);
  316. int w = getWidth();
  317. int x;
  318. x = (leftToRight) ? 2 : w - 16 - 2;
  319. menuBar.setBounds(x, 1, 16, 16);
  320. x = (leftToRight) ? w - 16 - 2 : 2;
  321. if(frame.isClosable()) {
  322. closeButton.setBounds(x, 2, 16, 14);
  323. x += (leftToRight) ? -(16 + 2) : 16 + 2;
  324. }
  325. if(frame.isMaximizable()) {
  326. maxButton.setBounds(x, 2, 16, 14);
  327. x += (leftToRight) ? -(16 + 2) : 16 + 2;
  328. }
  329. if(frame.isIconifiable()) {
  330. iconButton.setBounds(x, 2, 16, 14);
  331. }
  332. }
  333. } // end TitlePaneLayout
  334. /**
  335. * This inner class is marked "public" due to a compiler bug.
  336. * This class should be treated as a "protected" inner class.
  337. * Instantiate it only within subclasses of <Foo>.
  338. */
  339. public class CloseAction extends AbstractAction {
  340. public CloseAction() {
  341. super(CLOSE_CMD);
  342. }
  343. public void actionPerformed(ActionEvent e) {
  344. if(frame.isClosable()) {
  345. frame.doDefaultCloseAction();
  346. }
  347. }
  348. } // end CloseAction
  349. /**
  350. * This inner class is marked "public" due to a compiler bug.
  351. * This class should be treated as a "protected" inner class.
  352. * Instantiate it only within subclasses of <Foo>.
  353. */
  354. public class MaximizeAction extends AbstractAction {
  355. public MaximizeAction() {
  356. super(MAXIMIZE_CMD);
  357. }
  358. public void actionPerformed(ActionEvent e) {
  359. if(frame.isMaximizable()) {
  360. if(!frame.isMaximum()) {
  361. try { frame.setMaximum(true); } catch (PropertyVetoException e5) { }
  362. } else {
  363. try {
  364. frame.setMaximum(false);
  365. } catch (PropertyVetoException e6) { }
  366. }
  367. }
  368. }
  369. } // MaximizeAction
  370. /**
  371. * This inner class is marked "public" due to a compiler bug.
  372. * This class should be treated as a "protected" inner class.
  373. * Instantiate it only within subclasses of <Foo>.
  374. */
  375. public class IconifyAction extends AbstractAction {
  376. public IconifyAction() {
  377. super(ICONIFY_CMD);
  378. }
  379. public void actionPerformed(ActionEvent e) {
  380. if(frame.isIconifiable()) {
  381. if(!frame.isIcon()) {
  382. try { frame.setIcon(true); } catch (PropertyVetoException e1) { }
  383. } else{
  384. try { frame.setIcon(false); } catch (PropertyVetoException e1) { }
  385. }
  386. }
  387. }
  388. } // end IconifyAction
  389. /**
  390. * This inner class is marked "public" due to a compiler bug.
  391. * This class should be treated as a "protected" inner class.
  392. * Instantiate it only within subclasses of <Foo>.
  393. */
  394. public class RestoreAction extends AbstractAction {
  395. public RestoreAction() {
  396. super(RESTORE_CMD);
  397. }
  398. public void actionPerformed(ActionEvent e) {
  399. if(frame.isMaximizable() && frame.isMaximum()) {
  400. try { frame.setMaximum(false); } catch (PropertyVetoException e4) { }
  401. }
  402. else if ( frame.isIconifiable() && frame.isIcon() ) {
  403. try { frame.setIcon(false); } catch (PropertyVetoException e4) { }
  404. }
  405. }
  406. } // end RestoreAction
  407. /**
  408. * This inner class is marked "public" due to a compiler bug.
  409. * This class should be treated as a "protected" inner class.
  410. * Instantiate it only within subclasses of <Foo>.
  411. */
  412. public class MoveAction extends AbstractAction {
  413. public MoveAction() {
  414. super(MOVE_CMD);
  415. }
  416. public void actionPerformed(ActionEvent e) {
  417. // This action is currently undefined
  418. }
  419. } // end MoveAction
  420. /*
  421. * Handles showing and hiding the system menu.
  422. */
  423. private class ShowSystemMenuAction extends AbstractAction {
  424. private boolean show; // whether to show the menu
  425. public ShowSystemMenuAction(boolean show) {
  426. this.show = show;
  427. }
  428. public void actionPerformed(ActionEvent e) {
  429. if (show) {
  430. windowMenu.doClick();
  431. } else {
  432. windowMenu.setVisible(false);
  433. }
  434. }
  435. }
  436. /**
  437. * This inner class is marked "public" due to a compiler bug.
  438. * This class should be treated as a "protected" inner class.
  439. * Instantiate it only within subclasses of <Foo>.
  440. */
  441. public class SizeAction extends AbstractAction {
  442. public SizeAction() {
  443. super(SIZE_CMD);
  444. }
  445. public void actionPerformed(ActionEvent e) {
  446. // This action is currently undefined
  447. }
  448. } // end SizeAction
  449. /**
  450. * This inner class is marked "public" due to a compiler bug.
  451. * This class should be treated as a "protected" inner class.
  452. * Instantiate it only within subclasses of <Foo>.
  453. */
  454. public class SystemMenuBar extends JMenuBar {
  455. public boolean isFocusTraversable() { return false; }
  456. public void requestFocus() {}
  457. public void paint(Graphics g) {
  458. Icon icon = frame.getFrameIcon();
  459. if (icon == null) {
  460. icon = UIManager.getIcon("InternalFrame.icon");
  461. }
  462. if (icon != null) {
  463. // Resize to 16x16 if necessary.
  464. if (icon instanceof ImageIcon && (icon.getIconWidth() > 16 || icon.getIconHeight() > 16)) {
  465. Image img = ((ImageIcon)icon).getImage();
  466. ((ImageIcon)icon).setImage(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
  467. }
  468. icon.paintIcon(this, g, 0, 0);
  469. }
  470. }
  471. public boolean isOpaque() {
  472. return true;
  473. }
  474. } // end SystemMenuBar
  475. private class NoFocusButton extends JButton {
  476. public NoFocusButton() { setFocusPainted(false); }
  477. public boolean isFocusTraversable() { return false; }
  478. public void requestFocus() {};
  479. public boolean isOpaque() { return true; }
  480. }; // end NoFocusButton
  481. } // End Title Pane Class