blob: 6cabcc4a09b488b6a5a89118d012a50618476aef [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.jconsole;
27
28import java.awt.*;
29import java.beans.*;
30import java.lang.reflect.*;
31
32import javax.swing.*;
33import javax.swing.border.*;
34import 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")
44public 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}