1 /* 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.jconsole; 27 28 import java.awt.*; 29 import java.beans.*; 30 import java.lang.reflect.*; 31 32 import javax.swing.*; 33 import javax.swing.border.*; 34 import javax.swing.plaf.basic.*; 35 36 37 /** 38 * This class is a temporary workaround for bug 4834918: 39 * Win L&F: JInternalFrame should merge with JMenuBar when maximized. 40 * It is not a general solution, but intended for use within the 41 * limited scope of JConsole when running with XP/Vista styles. 42 */ 43 @SuppressWarnings("serial") 44 public class MaximizableInternalFrame extends JInternalFrame { 45 private boolean isXP; 46 private JFrame mainFrame; 47 private JMenuBar mainMenuBar; 48 private String mainTitle; 49 private JComponent titlePane; 50 private Border normalBorder; 51 private PropertyChangeListener pcl; 52 53 public MaximizableInternalFrame(String title, boolean resizable, 54 boolean closable, boolean maximizable, 55 boolean iconifiable) { 56 super(title, resizable, closable, maximizable, iconifiable); 57 58 init(); 59 } 60 61 private void init() { 62 normalBorder = getBorder(); 63 isXP = normalBorder.getClass().getName().endsWith("XPBorder"); 64 if (isXP) { 65 setRootPaneCheckingEnabled(false); 66 titlePane = ((BasicInternalFrameUI)getUI()).getNorthPane(); 67 68 if (pcl == null) { 69 pcl = new PropertyChangeListener() { 70 public void propertyChange(PropertyChangeEvent ev) { 71 String prop = ev.getPropertyName(); 72 if (prop.equals("icon") || 73 prop.equals("maximum") || 74 prop.equals("closed")) { 75 76 updateFrame(); 77 } 78 } 79 }; 80 addPropertyChangeListener(pcl); 81 } 82 } else if (pcl != null) { 83 removePropertyChangeListener(pcl); 84 pcl = null; 85 } 86 } 87 88 private void updateFrame() { 89 JFrame mainFrame; 90 if (!isXP || (mainFrame = getMainFrame()) == null) { 91 return; 92 } 93 JMenuBar menuBar = getMainMenuBar(); 94 BasicInternalFrameUI ui = (BasicInternalFrameUI)getUI(); 95 if (isMaximum() && !isIcon() && !isClosed()) { 96 if (ui.getNorthPane() != null) { 97 // Merge title bar into menu bar 98 mainTitle = mainFrame.getTitle(); 99 mainFrame.setTitle(mainTitle + " - " + getTitle()); 100 if (menuBar != null) { 101 // Move buttons to menu bar 102 updateButtonStates(); 103 menuBar.add(Box.createGlue()); 104 for (Component c : titlePane.getComponents()) { 105 if (c instanceof JButton) { 106 menuBar.add(c); 107 } else if (c instanceof JLabel) { 108 // This is the system menu icon 109 menuBar.add(Box.createHorizontalStrut(3), 0); 110 menuBar.add(c, 1); 111 menuBar.add(Box.createHorizontalStrut(3), 2); 112 } 113 } 114 ui.setNorthPane(null); 115 setBorder(null); 116 } 117 } 118 } else { 119 if (ui.getNorthPane() == null) { 120 // Restore title bar 121 mainFrame.setTitle(mainTitle); 122 if (menuBar != null) { 123 // Move buttons back to title bar 124 for (Component c : menuBar.getComponents()) { 125 if (c instanceof JButton || c instanceof JLabel) { 126 titlePane.add(c); 127 } else if (c instanceof Box.Filler) { 128 menuBar.remove(c); 129 } 130 } 131 menuBar.repaint(); 132 updateButtonStates(); 133 ui.setNorthPane(titlePane); 134 setBorder(normalBorder); 135 } 136 } 137 } 138 } 139 140 public void updateUI() { 141 boolean isMax = (isXP && getBorder() == null); 142 if (isMax) { 143 try { 144 setMaximum(false); 145 } catch (PropertyVetoException ex) { } 146 } 147 super.updateUI(); 148 init(); 149 if (isMax) { 150 try { 151 setMaximum(true); 152 } catch (PropertyVetoException ex) { } 153 } 154 } 155 156 private JFrame getMainFrame() { 157 if (mainFrame == null) { 158 JDesktopPane desktop = getDesktopPane(); 159 if (desktop != null) { 160 mainFrame = (JFrame)SwingUtilities.getWindowAncestor(desktop); 161 } 162 } 163 return mainFrame; 164 } 165 166 private JMenuBar getMainMenuBar() { 167 if (mainMenuBar == null) { 168 JFrame mainFrame = getMainFrame(); 169 if (mainFrame != null) { 170 mainMenuBar = mainFrame.getJMenuBar(); 171 if (mainMenuBar != null && 172 !(mainMenuBar.getLayout() instanceof FixedMenuBarLayout)) { 173 174 mainMenuBar.setLayout(new FixedMenuBarLayout(mainMenuBar, 175 BoxLayout.X_AXIS)); 176 } 177 } 178 } 179 return mainMenuBar; 180 } 181 182 public void setTitle(String title) { 183 if (isXP && isMaximum()) { 184 if (getMainFrame() != null) { 185 getMainFrame().setTitle(mainTitle + " - " + title); 186 } 187 } 188 super.setTitle(title); 189 } 190 191 192 private class FixedMenuBarLayout extends BoxLayout { 193 public FixedMenuBarLayout(Container target, int axis) { 194 super(target, axis); 195 } 196 197 public void layoutContainer(Container target) { 198 super.layoutContainer(target); 199 200 for (Component c : target.getComponents()) { 201 if (c instanceof JButton) { 202 int y = (target.getHeight() - c.getHeight()) / 2; 203 c.setLocation(c.getX(), Math.max(2, y)); 204 } 205 } 206 } 207 } 208 209 210 // The rest of this class is messy and should not be relied upon. It 211 // uses reflection to access private, undocumented, and unsupported 212 // classes and fields. 213 // 214 // Install icon wrappers to display MDI icons when the buttons 215 // are in the menubar. 216 // 217 // Please note that this will very likely fail in a future version 218 // of Swing, but at least it should fail silently. 219 // 220 private static Object WP_MINBUTTON, WP_RESTOREBUTTON, WP_CLOSEBUTTON, 221 WP_MDIMINBUTTON, WP_MDIRESTOREBUTTON, WP_MDICLOSEBUTTON; 222 static { 223 if (JConsole.IS_WIN) { 224 try { 225 Class Part = 226 Class.forName("com.sun.java.swing.plaf.windows.TMSchema$Part"); 227 if (Part != null) { 228 WP_MINBUTTON = Part.getField("WP_MINBUTTON").get(null); 229 WP_RESTOREBUTTON = Part.getField("WP_RESTOREBUTTON").get(null); 230 WP_CLOSEBUTTON = Part.getField("WP_CLOSEBUTTON").get(null); 231 WP_MDIMINBUTTON = Part.getField("WP_MDIMINBUTTON").get(null); 232 WP_MDIRESTOREBUTTON = Part.getField("WP_MDIRESTOREBUTTON").get(null); 233 WP_MDICLOSEBUTTON = Part.getField("WP_MDICLOSEBUTTON").get(null); 234 } 235 236 for (String str : new String[] { "maximize", "minimize", 237 "iconify", "close" }) { 238 String key = "InternalFrame." + str + "Icon"; 239 UIManager.put(key, 240 new MDIButtonIcon(UIManager.getIcon(key))); 241 } 242 } catch (ClassNotFoundException ex) { 243 if (JConsole.debug) { 244 ex.printStackTrace(); 245 } 246 } catch (NoSuchFieldException ex) { 247 if (JConsole.debug) { 248 ex.printStackTrace(); 249 } 250 } catch (IllegalAccessException ex) { 251 if (JConsole.debug) { 252 ex.printStackTrace(); 253 } 254 } 255 } 256 } 257 258 259 // A wrapper class for the title pane button icons. 260 // This code should really go in the WindowsIconsFactory class. 261 private static class MDIButtonIcon implements Icon { 262 Icon windowsIcon; 263 Field part; 264 265 MDIButtonIcon(Icon icon) { 266 windowsIcon = icon; 267 268 if (WP_MINBUTTON != null) { 269 try { 270 part = windowsIcon.getClass().getDeclaredField("part"); 271 part.setAccessible(true); 272 } catch (NoSuchFieldException ex) { 273 if (JConsole.debug) { 274 ex.printStackTrace(); 275 } 276 } 277 } 278 } 279 280 public void paintIcon(Component c, Graphics g, int x, int y) { 281 if (part != null) { 282 try { 283 Object v = part.get(windowsIcon); 284 285 if (c.getParent() instanceof JMenuBar) { 286 // Use MDI icons 287 if (v == WP_MINBUTTON) { 288 part.set(windowsIcon, WP_MDIMINBUTTON); 289 } else if (v == WP_RESTOREBUTTON) { 290 part.set(windowsIcon, WP_MDIRESTOREBUTTON); 291 } else if (v == WP_CLOSEBUTTON) { 292 part.set(windowsIcon, WP_MDICLOSEBUTTON); 293 } 294 } else { 295 // Use regular icons 296 if (v == WP_MDIMINBUTTON) { 297 part.set(windowsIcon, WP_MINBUTTON); 298 } else if (v == WP_MDIRESTOREBUTTON) { 299 part.set(windowsIcon, WP_RESTOREBUTTON); 300 } else if (v == WP_MDICLOSEBUTTON) { 301 part.set(windowsIcon, WP_CLOSEBUTTON); 302 } 303 } 304 } catch (IllegalAccessException ex) { 305 if (JConsole.debug) { 306 ex.printStackTrace(); 307 } 308 } 309 } 310 windowsIcon.paintIcon(c, g, x, y); 311 } 312 313 public int getIconWidth(){ 314 return windowsIcon.getIconWidth(); 315 } 316 317 public int getIconHeight() { 318 return windowsIcon.getIconHeight(); 319 } 320 } 321 322 323 // Use reflection to invoke protected methods in BasicInternalFrameTitlePane 324 private Method setButtonIcons; 325 private Method enableActions; 326 327 private void updateButtonStates() { 328 try { 329 if (setButtonIcons == null) { 330 Class<? extends JComponent> cls = titlePane.getClass(); 331 Class<?> superCls = cls.getSuperclass(); 332 setButtonIcons = cls.getDeclaredMethod("setButtonIcons"); 333 enableActions = superCls.getDeclaredMethod("enableActions"); 334 setButtonIcons.setAccessible(true); 335 enableActions.setAccessible(true); 336 } 337 setButtonIcons.invoke(titlePane); 338 enableActions.invoke(titlePane); 339 } catch (Exception ex) { 340 if (JConsole.debug) { 341 ex.printStackTrace(); 342 } 343 } 344 } 345 }