/* * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.jconsole; import java.awt.*; import java.beans.*; import java.lang.reflect.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; /** * This class is a temporary workaround for bug 4834918: * Win L&F: JInternalFrame should merge with JMenuBar when maximized. * It is not a general solution, but intended for use within the * limited scope of JConsole when running with XP/Vista styles. */ @SuppressWarnings("serial") public class MaximizableInternalFrame extends JInternalFrame { private boolean isXP; private JFrame mainFrame; private JMenuBar mainMenuBar; private String mainTitle; private JComponent titlePane; private Border normalBorder; private PropertyChangeListener pcl; public MaximizableInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) { super(title, resizable, closable, maximizable, iconifiable); init(); } private void init() { normalBorder = getBorder(); isXP = normalBorder.getClass().getName().endsWith("XPBorder"); if (isXP) { setRootPaneCheckingEnabled(false); titlePane = ((BasicInternalFrameUI)getUI()).getNorthPane(); if (pcl == null) { pcl = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { String prop = ev.getPropertyName(); if (prop.equals("icon") || prop.equals("maximum") || prop.equals("closed")) { updateFrame(); } } }; addPropertyChangeListener(pcl); } } else if (pcl != null) { removePropertyChangeListener(pcl); pcl = null; } } private void updateFrame() { JFrame mainFrame; if (!isXP || (mainFrame = getMainFrame()) == null) { return; } JMenuBar menuBar = getMainMenuBar(); BasicInternalFrameUI ui = (BasicInternalFrameUI)getUI(); if (isMaximum() && !isIcon() && !isClosed()) { if (ui.getNorthPane() != null) { // Merge title bar into menu bar mainTitle = mainFrame.getTitle(); mainFrame.setTitle(mainTitle + " - " + getTitle()); if (menuBar != null) { // Move buttons to menu bar updateButtonStates(); menuBar.add(Box.createGlue()); for (Component c : titlePane.getComponents()) { if (c instanceof JButton) { menuBar.add(c); } else if (c instanceof JLabel) { // This is the system menu icon menuBar.add(Box.createHorizontalStrut(3), 0); menuBar.add(c, 1); menuBar.add(Box.createHorizontalStrut(3), 2); } } ui.setNorthPane(null); setBorder(null); } } } else { if (ui.getNorthPane() == null) { // Restore title bar mainFrame.setTitle(mainTitle); if (menuBar != null) { // Move buttons back to title bar for (Component c : menuBar.getComponents()) { if (c instanceof JButton || c instanceof JLabel) { titlePane.add(c); } else if (c instanceof Box.Filler) { menuBar.remove(c); } } menuBar.repaint(); updateButtonStates(); ui.setNorthPane(titlePane); setBorder(normalBorder); } } } } public void updateUI() { boolean isMax = (isXP && getBorder() == null); if (isMax) { try { setMaximum(false); } catch (PropertyVetoException ex) { } } super.updateUI(); init(); if (isMax) { try { setMaximum(true); } catch (PropertyVetoException ex) { } } } private JFrame getMainFrame() { if (mainFrame == null) { JDesktopPane desktop = getDesktopPane(); if (desktop != null) { mainFrame = (JFrame)SwingUtilities.getWindowAncestor(desktop); } } return mainFrame; } private JMenuBar getMainMenuBar() { if (mainMenuBar == null) { JFrame mainFrame = getMainFrame(); if (mainFrame != null) { mainMenuBar = mainFrame.getJMenuBar(); if (mainMenuBar != null && !(mainMenuBar.getLayout() instanceof FixedMenuBarLayout)) { mainMenuBar.setLayout(new FixedMenuBarLayout(mainMenuBar, BoxLayout.X_AXIS)); } } } return mainMenuBar; } public void setTitle(String title) { if (isXP && isMaximum()) { if (getMainFrame() != null) { getMainFrame().setTitle(mainTitle + " - " + title); } } super.setTitle(title); } private class FixedMenuBarLayout extends BoxLayout { public FixedMenuBarLayout(Container target, int axis) { super(target, axis); } public void layoutContainer(Container target) { super.layoutContainer(target); for (Component c : target.getComponents()) { if (c instanceof JButton) { int y = (target.getHeight() - c.getHeight()) / 2; c.setLocation(c.getX(), Math.max(2, y)); } } } } // The rest of this class is messy and should not be relied upon. It // uses reflection to access private, undocumented, and unsupported // classes and fields. // // Install icon wrappers to display MDI icons when the buttons // are in the menubar. // // Please note that this will very likely fail in a future version // of Swing, but at least it should fail silently. // private static Object WP_MINBUTTON, WP_RESTOREBUTTON, WP_CLOSEBUTTON, WP_MDIMINBUTTON, WP_MDIRESTOREBUTTON, WP_MDICLOSEBUTTON; static { if (JConsole.IS_WIN) { try { Class<?> Part = Class.forName("com.sun.java.swing.plaf.windows.TMSchema$Part"); if (Part != null) { WP_MINBUTTON = Part.getField("WP_MINBUTTON").get(null); WP_RESTOREBUTTON = Part.getField("WP_RESTOREBUTTON").get(null); WP_CLOSEBUTTON = Part.getField("WP_CLOSEBUTTON").get(null); WP_MDIMINBUTTON = Part.getField("WP_MDIMINBUTTON").get(null); WP_MDIRESTOREBUTTON = Part.getField("WP_MDIRESTOREBUTTON").get(null); WP_MDICLOSEBUTTON = Part.getField("WP_MDICLOSEBUTTON").get(null); } for (String str : new String[] { "maximize", "minimize", "iconify", "close" }) { String key = "InternalFrame." + str + "Icon"; UIManager.put(key, new MDIButtonIcon(UIManager.getIcon(key))); } } catch (ClassNotFoundException ex) { if (JConsole.debug) { ex.printStackTrace(); } } catch (NoSuchFieldException ex) { if (JConsole.debug) { ex.printStackTrace(); } } catch (IllegalAccessException ex) { if (JConsole.debug) { ex.printStackTrace(); } } } } // A wrapper class for the title pane button icons. // This code should really go in the WindowsIconsFactory class. private static class MDIButtonIcon implements Icon { Icon windowsIcon; Field part; MDIButtonIcon(Icon icon) { windowsIcon = icon; if (WP_MINBUTTON != null) { try { part = windowsIcon.getClass().getDeclaredField("part"); part.setAccessible(true); } catch (NoSuchFieldException ex) { if (JConsole.debug) { ex.printStackTrace(); } } } } public void paintIcon(Component c, Graphics g, int x, int y) { if (part != null) { try { Object v = part.get(windowsIcon); if (c.getParent() instanceof JMenuBar) { // Use MDI icons if (v == WP_MINBUTTON) { part.set(windowsIcon, WP_MDIMINBUTTON); } else if (v == WP_RESTOREBUTTON) { part.set(windowsIcon, WP_MDIRESTOREBUTTON); } else if (v == WP_CLOSEBUTTON) { part.set(windowsIcon, WP_MDICLOSEBUTTON); } } else { // Use regular icons if (v == WP_MDIMINBUTTON) { part.set(windowsIcon, WP_MINBUTTON); } else if (v == WP_MDIRESTOREBUTTON) { part.set(windowsIcon, WP_RESTOREBUTTON); } else if (v == WP_MDICLOSEBUTTON) { part.set(windowsIcon, WP_CLOSEBUTTON); } } } catch (IllegalAccessException ex) { if (JConsole.debug) { ex.printStackTrace(); } } } windowsIcon.paintIcon(c, g, x, y); } public int getIconWidth(){ return windowsIcon.getIconWidth(); } public int getIconHeight() { return windowsIcon.getIconHeight(); } } // Use reflection to invoke protected methods in BasicInternalFrameTitlePane private Method setButtonIcons; private Method enableActions; private void updateButtonStates() { try { if (setButtonIcons == null) { Class<? extends JComponent> cls = titlePane.getClass(); Class<?> superCls = cls.getSuperclass(); setButtonIcons = cls.getDeclaredMethod("setButtonIcons"); enableActions = superCls.getDeclaredMethod("enableActions"); setButtonIcons.setAccessible(true); enableActions.setAccessible(true); } setButtonIcons.invoke(titlePane); enableActions.invoke(titlePane); } catch (Exception ex) { if (JConsole.debug) { ex.printStackTrace(); } } } }