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
26package sun.tools.jconsole;
27
28import java.awt.*;
29import java.awt.event.*;
30import java.beans.*;
31
32import javax.swing.*;
33import javax.swing.border.*;
34import javax.swing.text.*;
35
36import static javax.swing.JOptionPane.*;
37
38@SuppressWarnings("serial")
39public 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 */
47    private SheetDialog() {
48    }
49
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
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
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
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
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
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
210        public void setGrayLevel(int gray) {
211            gray = gray * 255 / 100;
212            setBackground(new Color(0, 0, 0, gray));
213        }
214
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 {
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
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
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