1 /*
2  * Copyright (c) 2005, 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.awt.event.*;
30 import java.beans.*;
31 
32 import javax.swing.*;
33 import javax.swing.border.*;
34 import javax.swing.text.*;
35 
36 import static javax.swing.JOptionPane.*;
37 
38 @SuppressWarnings("serial")
39 public final class SheetDialog {
40     // Reusable objects
41     private static Rectangle iconR = new Rectangle();
42     private static Rectangle textR = new Rectangle();
43     private static Rectangle viewR = new Rectangle();
44     private static Insets viewInsets = new Insets(0, 0, 0, 0);
45 
46     /** Don't let anyone instantiate this class */
SheetDialog()47     private SheetDialog() {
48     }
49 
showOptionDialog(final VMPanel vmPanel, Object message, int optionType, int messageType, Icon icon, Object[] options, Object initialValue)50     static JOptionPane showOptionDialog(final VMPanel vmPanel, Object message,
51                                         int optionType, int messageType,
52                                         Icon icon, Object[] options, Object initialValue) {
53 
54         JRootPane rootPane = SwingUtilities.getRootPane(vmPanel);
55         JPanel glassPane = (JPanel)rootPane.getGlassPane();
56 
57         if (!(glassPane instanceof SlideAndFadeGlassPane)) {
58             glassPane = new SlideAndFadeGlassPane();
59             glassPane.setName(rootPane.getName()+".glassPane");
60             rootPane.setGlassPane(glassPane);
61             rootPane.revalidate();
62         }
63 
64         final SlideAndFadeGlassPane safGlassPane = (SlideAndFadeGlassPane)glassPane;
65 
66         // Workaround for the fact that JOptionPane does not handle
67         // limiting the width when using multi-line html messages.
68         // See Swing bug 5074006 and JConsole bug 6426317
69         message = fixWrapping(message, rootPane.getWidth() - 75); // Leave room for icon
70 
71         final SheetOptionPane optionPane = new SheetOptionPane(message, messageType, optionType,
72                                                            icon, options, initialValue);
73 
74         optionPane.setComponentOrientation(vmPanel.getComponentOrientation());
75         optionPane.addPropertyChangeListener(new PropertyChangeListener() {
76             public void propertyChange(PropertyChangeEvent event) {
77                 if (event.getPropertyName().equals(VALUE_PROPERTY) &&
78                     event.getNewValue() != null &&
79                     event.getNewValue() != UNINITIALIZED_VALUE) {
80                     ((SlideAndFadeGlassPane)optionPane.getParent()).hide(optionPane);
81                 }
82             }
83         });
84 
85         // Delay this (even though we're already on the EDT)
86         EventQueue.invokeLater(new Runnable() {
87             public void run() {
88                 safGlassPane.show(optionPane);
89             }
90         });
91 
92         return optionPane;
93     }
94 
fixWrapping(Object message, final int maxWidth)95     private static Object fixWrapping(Object message, final int maxWidth) {
96         if (message instanceof Object[]) {
97             Object[] arr = (Object[])message;
98             for (int i = 0; i < arr.length; i++) {
99                 arr[i] = fixWrapping(arr[i], maxWidth);
100             }
101         } else if (message instanceof String &&
102                    ((String)message).startsWith("<html>")) {
103             message = new JLabel((String)message) {
104                 public Dimension getPreferredSize() {
105                     String text = getText();
106                     Insets insets = getInsets(viewInsets);
107                     FontMetrics fm = getFontMetrics(getFont());
108                     Dimension pref = super.getPreferredSize();
109                     Dimension min = getMinimumSize();
110 
111                     iconR.x = iconR.y = iconR.width = iconR.height = 0;
112                     textR.x = textR.y = textR.width = textR.height = 0;
113                     int dx = insets.left + insets.right;
114                     int dy = insets.top + insets.bottom;
115                     viewR.x = dx;
116                     viewR.y = dy;
117                     viewR.width = viewR.height = Short.MAX_VALUE;
118 
119                     View v = (View)getClientProperty("html");
120                     if (v != null) {
121                         // Use pref width if less than 300, otherwise
122                         // min width up to size of window.
123                         int w = Math.min(maxWidth,
124                                          Math.min(pref.width,
125                                                   Math.max(min.width, 300)));
126                         v.setSize((float)w, 0F);
127 
128                         SwingUtilities.layoutCompoundLabel(this, fm, text, null,
129                                                            getVerticalAlignment(),
130                                                            getHorizontalAlignment(),
131                                                            getVerticalTextPosition(),
132                                                            getHorizontalTextPosition(),
133                                                            viewR, iconR, textR,
134                                                            getIconTextGap());
135                         return new Dimension(textR.width + dx,
136                                              textR.height + dy);
137                     } else {
138                         return pref; //  Should not happen
139                     }
140                 }
141             };
142         }
143         return message;
144     }
145 
146     private static class SlideAndFadeGlassPane extends JPanel {
147         SheetOptionPane optionPane;
148 
149         int fade = 20;
150         boolean slideIn = true;
151 
SlideAndFadeGlassPane()152         SlideAndFadeGlassPane() {
153             super(null);
154             setVisible(false);
155             setOpaque(false);
156 
157             // Grab mouse input, making the dialog modal
158             addMouseListener(new MouseAdapter() {});
159         }
160 
show(SheetOptionPane optionPane)161         public void show(SheetOptionPane optionPane) {
162             this.optionPane = optionPane;
163             removeAll();
164             add(optionPane);
165             setVisible(true);
166             slideIn = true;
167             revalidate();
168             repaint();
169             doSlide();
170         }
171 
hide(SheetOptionPane optionPane)172         public void hide(SheetOptionPane optionPane) {
173             if (optionPane != this.optionPane) {
174                 return;
175             }
176 
177             slideIn = false;
178             revalidate();
179             repaint();
180             doSlide();
181         }
182 
doSlide()183         private void doSlide() {
184             if (optionPane.getParent() == null) {
185                 return;
186             }
187 
188             if (optionPane.getWidth() == 0) {
189                 optionPane.setSize(optionPane.getPreferredSize());
190             }
191 
192             int glassPaneWidth = getWidth();
193             if (glassPaneWidth == 0 && getParent() != null) {
194                 glassPaneWidth = getParent().getWidth();
195             }
196 
197             int x = (glassPaneWidth - optionPane.getWidth()) / 2;
198 
199             if (!slideIn) {
200                     remove(optionPane);
201                     setVisible(false);
202                     return;
203             } else {
204                     optionPane.setLocation(x, 0);
205                     setGrayLevel(fade);
206                     return;
207             }
208         }
209 
setGrayLevel(int gray)210         public void setGrayLevel(int gray) {
211             gray = gray * 255 / 100;
212             setBackground(new Color(0, 0, 0, gray));
213         }
214 
paint(Graphics g)215         public void paint(Graphics g) {
216             g.setColor(getBackground());
217             g.fillRect(0, 0, getWidth(), getHeight());
218             super.paint(g);
219         }
220     }
221 
222 
223 
224     static class SheetOptionPane extends JOptionPane {
SheetOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options, Object initialValue)225         SheetOptionPane(Object message, int messageType, int optionType,
226                         Icon icon, Object[] options, Object initialValue) {
227             super(message, messageType, optionType, icon, options, initialValue);
228 
229             setBorder(new CompoundBorder(new LineBorder(new Color(204, 204, 204), 1),
230                                          new EmptyBorder(4, 4, 4, 4)));
231         }
232 
233 
234         private static Composite comp =
235             AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8F);
236 
237         private static Color bgColor = new Color(241, 239, 239);
238 
setVisible(boolean visible)239         public void setVisible(boolean visible) {
240             SlideAndFadeGlassPane glassPane = (SlideAndFadeGlassPane)getParent();
241             if (glassPane != null) {
242                 if (visible) {
243                     glassPane.show(this);
244                 } else {
245                     glassPane.hide(this);
246                 }
247             }
248         }
249 
paint(Graphics g)250         public void paint(Graphics g) {
251             Graphics2D g2d = (Graphics2D)g;
252             Composite oldComp = g2d.getComposite();
253             g2d.setComposite(comp);
254             Color oldColor = g2d.getColor();
255             g2d.setColor(bgColor);
256             g2d.fillRect(0, 0, getWidth(), getHeight());
257             g2d.setColor(oldColor);
258             g2d.setComposite(oldComp);
259             super.paint(g);
260         }
261     }
262 
263 }
264