1/*
2 * Copyright (c) 1997, 2014, 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 javax.swing.plaf.basic;
27
28import java.awt.*;
29import java.awt.event.*;
30import javax.swing.*;
31import javax.swing.event.*;
32import javax.swing.border.*;
33import javax.swing.plaf.*;
34import java.beans.*;
35
36/**
37 * Basic L&F for a minimized window on a desktop.
38 *
39 * @author David Kloba
40 * @author Steve Wilson
41 * @author Rich Schiavi
42 */
43public class BasicDesktopIconUI extends DesktopIconUI {
44
45    /**
46     * The instance of {@code JInternalFrame.JDesktopIcon}.
47     */
48    protected JInternalFrame.JDesktopIcon desktopIcon;
49
50    /**
51     * The instance of {@code JInternalFrame}.
52     */
53    protected JInternalFrame frame;
54
55    /**
56     * The title pane component used in the desktop icon.
57     *
58     * @since 1.5
59     */
60    protected JComponent iconPane;
61    MouseInputListener mouseInputListener;
62
63    /**
64     * Constructs a new instance of {@code BasicDesktopIconUI}.
65     *
66     * @param c a component
67     * @return a new instance of {@code BasicDesktopIconUI}
68     */
69    public static ComponentUI createUI(JComponent c)    {
70        return new BasicDesktopIconUI();
71    }
72
73    /**
74     * Constructs a new instance of {@code BasicDesktopIconUI}.
75     */
76    public BasicDesktopIconUI() {
77    }
78
79    public void installUI(JComponent c)   {
80        desktopIcon = (JInternalFrame.JDesktopIcon)c;
81        frame = desktopIcon.getInternalFrame();
82        installDefaults();
83        installComponents();
84
85        // Update icon layout if frame is already iconified
86        JInternalFrame f = desktopIcon.getInternalFrame();
87        if (f.isIcon() && f.getParent() == null) {
88            JDesktopPane desktop = desktopIcon.getDesktopPane();
89            if (desktop != null) {
90                DesktopManager desktopManager = desktop.getDesktopManager();
91                if (desktopManager instanceof DefaultDesktopManager) {
92                    desktopManager.iconifyFrame(f);
93                }
94            }
95        }
96
97        installListeners();
98        JLayeredPane.putLayer(desktopIcon, JLayeredPane.getLayer(frame));
99    }
100
101    public void uninstallUI(JComponent c) {
102        uninstallDefaults();
103        uninstallComponents();
104
105        // Force future UI to relayout icon
106        JInternalFrame f = desktopIcon.getInternalFrame();
107        if (f.isIcon()) {
108            JDesktopPane desktop = desktopIcon.getDesktopPane();
109            if (desktop != null) {
110                DesktopManager desktopManager = desktop.getDesktopManager();
111                if (desktopManager instanceof DefaultDesktopManager) {
112                    // This will cause DefaultDesktopManager to layout the icon
113                    f.putClientProperty("wasIconOnce", null);
114                    // Move aside to allow fresh layout of all icons
115                    desktopIcon.setLocation(Integer.MIN_VALUE, 0);
116                }
117            }
118        }
119
120        uninstallListeners();
121        frame = null;
122        desktopIcon = null;
123    }
124
125    /**
126     * Registers components.
127     */
128    protected void installComponents() {
129        iconPane = new BasicInternalFrameTitlePane(frame);
130        desktopIcon.setLayout(new BorderLayout());
131        desktopIcon.add(iconPane, BorderLayout.CENTER);
132    }
133
134    /**
135     * Unregisters components.
136     */
137    protected void uninstallComponents() {
138        desktopIcon.remove(iconPane);
139        desktopIcon.setLayout(null);
140        iconPane = null;
141    }
142
143    /**
144     * Registers listeners.
145     */
146    protected void installListeners() {
147        mouseInputListener = createMouseInputListener();
148        desktopIcon.addMouseMotionListener(mouseInputListener);
149        desktopIcon.addMouseListener(mouseInputListener);
150    }
151
152    /**
153     * Unregisters listeners.
154     */
155    protected void uninstallListeners() {
156        desktopIcon.removeMouseMotionListener(mouseInputListener);
157        desktopIcon.removeMouseListener(mouseInputListener);
158        mouseInputListener = null;
159    }
160
161    /**
162     * Installs default properties.
163     */
164    protected void installDefaults() {
165        LookAndFeel.installBorder(desktopIcon, "DesktopIcon.border");
166        LookAndFeel.installProperty(desktopIcon, "opaque", Boolean.TRUE);
167    }
168
169    /**
170     * Uninstalls default properties.
171     */
172    protected void uninstallDefaults() {
173        LookAndFeel.uninstallBorder(desktopIcon);
174    }
175
176    /**
177     * Returns a new instance of {@code MouseInputListener}.
178     *
179     * @return a new instance of {@code MouseInputListener}
180     */
181    protected MouseInputListener createMouseInputListener() {
182        return new MouseInputHandler();
183    }
184
185    public Dimension getPreferredSize(JComponent c) {
186        return desktopIcon.getLayout().preferredLayoutSize(desktopIcon);
187    }
188
189    public Dimension getMinimumSize(JComponent c) {
190        Dimension dim = new Dimension(iconPane.getMinimumSize());
191        Border border = frame.getBorder();
192
193        if (border != null) {
194            dim.height += border.getBorderInsets(frame).bottom +
195                          border.getBorderInsets(frame).top;
196        }
197        return dim;
198    }
199
200    /**
201     * Desktop icons can not be resized.  Therefore, we should always
202     * return the minimum size of the desktop icon.
203     *
204     * @see #getMinimumSize
205     */
206    public Dimension getMaximumSize(JComponent c){
207        return iconPane.getMaximumSize();
208    }
209
210    /**
211     * Returns the insets.
212     *
213     * @param c a component
214     * @return the insets
215     */
216    public Insets getInsets(JComponent c) {
217        JInternalFrame iframe = desktopIcon.getInternalFrame();
218        Border border = iframe.getBorder();
219        if(border != null)
220            return border.getBorderInsets(iframe);
221
222        return new Insets(0,0,0,0);
223    }
224
225    /**
226     * De-iconifies the internal frame.
227     */
228    public void deiconize() {
229        try { frame.setIcon(false); } catch (PropertyVetoException e2) { }
230    }
231
232    /**
233     * Listens for mouse movements and acts on them.
234     *
235     * This class should be treated as a "protected" inner class.
236     * Instantiate it only within subclasses of {@code BasicDesktopIconUI}.
237     */
238    public class MouseInputHandler extends MouseInputAdapter
239    {
240        // _x & _y are the mousePressed location in absolute coordinate system
241        int _x, _y;
242        // __x & __y are the mousePressed location in source view's coordinate system
243        int __x, __y;
244        Rectangle startingBounds;
245
246        public void mouseReleased(MouseEvent e) {
247            _x = 0;
248            _y = 0;
249            __x = 0;
250            __y = 0;
251            startingBounds = null;
252
253            JDesktopPane d;
254            if((d = desktopIcon.getDesktopPane()) != null) {
255                DesktopManager dm = d.getDesktopManager();
256                dm.endDraggingFrame(desktopIcon);
257            }
258
259        }
260
261        public void mousePressed(MouseEvent e) {
262            Point p = SwingUtilities.convertPoint((Component)e.getSource(),
263                        e.getX(), e.getY(), null);
264            __x = e.getX();
265            __y = e.getY();
266            _x = p.x;
267            _y = p.y;
268            startingBounds = desktopIcon.getBounds();
269
270            JDesktopPane d;
271            if((d = desktopIcon.getDesktopPane()) != null) {
272                DesktopManager dm = d.getDesktopManager();
273                dm.beginDraggingFrame(desktopIcon);
274            }
275
276            try { frame.setSelected(true); } catch (PropertyVetoException e1) { }
277            if(desktopIcon.getParent() instanceof JLayeredPane) {
278                ((JLayeredPane)desktopIcon.getParent()).moveToFront(desktopIcon);
279            }
280
281            if(e.getClickCount() > 1) {
282                if(frame.isIconifiable() && frame.isIcon()) {
283                    deiconize();
284                }
285            }
286
287        }
288
289         public void mouseMoved(MouseEvent e) {}
290
291         public void mouseDragged(MouseEvent e) {
292            Point p;
293            int newX, newY, newW, newH;
294            int deltaX;
295            int deltaY;
296            Dimension min;
297            Dimension max;
298            p = SwingUtilities.convertPoint((Component)e.getSource(),
299                                        e.getX(), e.getY(), null);
300
301                Insets i = desktopIcon.getInsets();
302                int pWidth, pHeight;
303                pWidth = ((JComponent)desktopIcon.getParent()).getWidth();
304                pHeight = ((JComponent)desktopIcon.getParent()).getHeight();
305
306                if (startingBounds == null) {
307                  // (STEVE) Yucky work around for bug ID 4106552
308                    return;
309                }
310                newX = startingBounds.x - (_x - p.x);
311                newY = startingBounds.y - (_y - p.y);
312                // Make sure we stay in-bounds
313                if(newX + i.left <= -__x)
314                    newX = -__x - i.left;
315                if(newY + i.top <= -__y)
316                    newY = -__y - i.top;
317                if(newX + __x + i.right > pWidth)
318                    newX = pWidth - __x - i.right;
319                if(newY + __y + i.bottom > pHeight)
320                    newY =  pHeight - __y - i.bottom;
321
322                JDesktopPane d;
323                if((d = desktopIcon.getDesktopPane()) != null) {
324                    DesktopManager dm = d.getDesktopManager();
325                    dm.dragFrame(desktopIcon, newX, newY);
326                } else {
327                    moveAndRepaint(desktopIcon, newX, newY,
328                                desktopIcon.getWidth(), desktopIcon.getHeight());
329                }
330                return;
331        }
332
333        /**
334         * Moves and repaints a component {@code f}.
335         *
336         * @param f a component
337         * @param newX a new X coordinate
338         * @param newY a new Y coordinate
339         * @param newWidth a new width
340         * @param newHeight a new height
341         */
342        public void moveAndRepaint(JComponent f, int newX, int newY,
343                                        int newWidth, int newHeight) {
344            Rectangle r = f.getBounds();
345            f.setBounds(newX, newY, newWidth, newHeight);
346            SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
347            f.getParent().repaint(r.x, r.y, r.width, r.height);
348        }
349    }; /// End MotionListener
350
351}
352