1 /*
2  * Copyright (c) 2006, 2012, 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 
MaximizableInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable)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 
init()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 
updateFrame()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 
updateUI()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 
getMainFrame()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 
getMainMenuBar()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 
setTitle(String title)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 {
FixedMenuBarLayout(Container target, int axis)193         public FixedMenuBarLayout(Container target, int axis) {
194             super(target, axis);
195         }
196 
layoutContainer(Container target)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";
UIManager.put(key, new MDIButtonIcon(UIManager.getIcon(key)))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 
MDIButtonIcon(Icon icon)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 
paintIcon(Component c, Graphics g, int x, int y)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 
getIconWidth()313         public int getIconWidth(){
314             return windowsIcon.getIconWidth();
315         }
316 
getIconHeight()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 
updateButtonStates()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 }
346