1 /*
2  * Copyright (c) 1997, 1999, 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 com.sun.java.swing.plaf.motif;
27 
28 import java.awt.*;
29 import java.awt.event.*;
30 import javax.swing.JSplitPane;
31 import javax.swing.UIManager;
32 import javax.swing.plaf.basic.BasicSplitPaneUI;
33 import javax.swing.plaf.basic.BasicSplitPaneDivider;
34 
35 
36 /**
37  * Divider used for Motif split pane.
38  * <p>
39  * <strong>Warning:</strong>
40  * Serialized objects of this class will not be compatible with
41  * future Swing releases.  The current serialization support is appropriate
42  * for short term storage or RMI between applications running the same
43  * version of Swing.  A future release of Swing will provide support for
44  * long term persistence.
45  *
46  * @author Jeff Dinkins
47  */
48 public class MotifSplitPaneDivider extends BasicSplitPaneDivider
49 {
50     /**
51      * Default cursor, supers is package private, so we have to have one
52      * too.
53      */
54     private static final Cursor defaultCursor =
55                             Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
56 
57 
58     public static final int minimumThumbSize = 6;
59     public static final int defaultDividerSize = 18;
60 
61     protected  static final int pad = 6;
62 
63     private int hThumbOffset = 30;
64     private int vThumbOffset = 40;
65     protected int hThumbWidth = 12;
66     protected int hThumbHeight = 18;
67     protected int vThumbWidth = 18;
68     protected int vThumbHeight = 12;
69 
70     protected Color highlightColor;
71     protected Color shadowColor;
72     protected Color focusedColor;
73 
74     /**
75      * Creates a new Motif SplitPaneDivider
76      */
MotifSplitPaneDivider(BasicSplitPaneUI ui)77     public MotifSplitPaneDivider(BasicSplitPaneUI ui) {
78         super(ui);
79         highlightColor = UIManager.getColor("SplitPane.highlight");
80         shadowColor = UIManager.getColor("SplitPane.shadow");
81         focusedColor = UIManager.getColor("SplitPane.activeThumb");
82         setDividerSize(hThumbWidth + pad);
83     }
84 
85     /**
86      * overrides to hardcode the size of the divider
87      * PENDING(jeff) - rewrite JSplitPane so that this ins't needed
88      */
setDividerSize(int newSize)89     public void setDividerSize(int newSize) {
90         Insets          insets = getInsets();
91         int             borderSize = 0;
92         if (getBasicSplitPaneUI().getOrientation() ==
93             JSplitPane.HORIZONTAL_SPLIT) {
94             if (insets != null) {
95                 borderSize = insets.left + insets.right;
96             }
97         }
98         else if (insets != null) {
99             borderSize = insets.top + insets.bottom;
100         }
101         if (newSize < pad + minimumThumbSize + borderSize) {
102             setDividerSize(pad + minimumThumbSize + borderSize);
103         } else {
104             vThumbHeight = hThumbWidth = newSize - pad - borderSize;
105             super.setDividerSize(newSize);
106         }
107     }
108 
109     /**
110       * Paints the divider.
111       */
112     // PENDING(jeff) - the thumb's location and size is currently hard coded.
113     // It should be dynamic.
paint(Graphics g)114     public void paint(Graphics g) {
115         Color               bgColor = getBackground();
116         Dimension           size = getSize();
117 
118         // fill
119         g.setColor(getBackground());
120         g.fillRect(0, 0, size.width, size.height);
121 
122         if(getBasicSplitPaneUI().getOrientation() ==
123            JSplitPane.HORIZONTAL_SPLIT) {
124             int center = size.width/2;
125             int x = center - hThumbWidth/2;
126             int y = hThumbOffset;
127 
128             // split line
129             g.setColor(shadowColor);
130             g.drawLine(center-1, 0, center-1, size.height);
131 
132             g.setColor(highlightColor);
133             g.drawLine(center, 0, center, size.height);
134 
135             // draw thumb
136             g.setColor((splitPane.hasFocus()) ? focusedColor :
137                                                 getBackground());
138             g.fillRect(x+1, y+1, hThumbWidth-2, hThumbHeight-1);
139 
140             g.setColor(highlightColor);
141             g.drawLine(x, y, x+hThumbWidth-1, y);       // top
142             g.drawLine(x, y+1, x, y+hThumbHeight-1);    // left
143 
144             g.setColor(shadowColor);
145             g.drawLine(x+1, y+hThumbHeight-1,
146                        x+hThumbWidth-1, y+hThumbHeight-1);      // bottom
147             g.drawLine(x+hThumbWidth-1, y+1,
148                        x+hThumbWidth-1, y+hThumbHeight-2);      // right
149 
150         } else {
151             int center = size.height/2;
152             int x = size.width - vThumbOffset;
153             int y = size.height/2 - vThumbHeight/2;
154 
155             // split line
156             g.setColor(shadowColor);
157             g.drawLine(0, center-1, size.width, center-1);
158 
159             g.setColor(highlightColor);
160             g.drawLine(0, center, size.width, center);
161 
162             // draw thumb
163             g.setColor((splitPane.hasFocus()) ? focusedColor :
164                                                 getBackground());
165             g.fillRect(x+1, y+1, vThumbWidth-1, vThumbHeight-1);
166 
167             g.setColor(highlightColor);
168             g.drawLine(x, y, x+vThumbWidth, y);    // top
169             g.drawLine(x, y+1, x, y+vThumbHeight); // left
170 
171             g.setColor(shadowColor);
172             g.drawLine(x+1, y+vThumbHeight,
173                        x+vThumbWidth, y+vThumbHeight);          // bottom
174             g.drawLine(x+vThumbWidth, y+1,
175                        x+vThumbWidth, y+vThumbHeight-1);        // right
176         }
177         super.paint(g);
178 
179     }
180 
181     /**
182       * The minimums size is the same as the preferredSize
183       */
getMinimumSize()184     public Dimension getMinimumSize() {
185         return getPreferredSize();
186     }
187 
188     /**
189      * Sets the SplitPaneUI that is using the receiver. This is completely
190      * overriden from super to create a different MouseHandler.
191      */
setBasicSplitPaneUI(BasicSplitPaneUI newUI)192     public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) {
193         if (splitPane != null) {
194             splitPane.removePropertyChangeListener(this);
195            if (mouseHandler != null) {
196                splitPane.removeMouseListener(mouseHandler);
197                splitPane.removeMouseMotionListener(mouseHandler);
198                removeMouseListener(mouseHandler);
199                removeMouseMotionListener(mouseHandler);
200                mouseHandler = null;
201            }
202         }
203         splitPaneUI = newUI;
204         if (newUI != null) {
205             splitPane = newUI.getSplitPane();
206             if (splitPane != null) {
207                 if (mouseHandler == null) mouseHandler=new MotifMouseHandler();
208                 splitPane.addMouseListener(mouseHandler);
209                 splitPane.addMouseMotionListener(mouseHandler);
210                 addMouseListener(mouseHandler);
211                 addMouseMotionListener(mouseHandler);
212                 splitPane.addPropertyChangeListener(this);
213                 if (splitPane.isOneTouchExpandable()) {
214                     oneTouchExpandableChanged();
215                 }
216             }
217         }
218         else {
219             splitPane = null;
220         }
221     }
222 
223     /**
224      * Returns true if the point at <code>x</code>, <code>y</code>
225      * is inside the thumb.
226      */
isInThumb(int x, int y)227     private boolean isInThumb(int x, int y) {
228         Dimension           size = getSize();
229         int                 thumbX;
230         int                 thumbY;
231         int                 thumbWidth;
232         int                 thumbHeight;
233 
234         if (getBasicSplitPaneUI().getOrientation() ==
235             JSplitPane.HORIZONTAL_SPLIT) {
236             int center = size.width/2;
237             thumbX = center - hThumbWidth/2;
238             thumbY = hThumbOffset;
239             thumbWidth = hThumbWidth;
240             thumbHeight = hThumbHeight;
241         }
242         else {
243             int center = size.height/2;
244             thumbX = size.width - vThumbOffset;
245             thumbY = size.height/2 - vThumbHeight/2;
246             thumbWidth = vThumbWidth;
247             thumbHeight = vThumbHeight;
248         }
249         return (x >= thumbX && x < (thumbX + thumbWidth) &&
250                 y >= thumbY && y < (thumbY + thumbHeight));
251     }
252 
253     //
254     // Two methods are exposed so that MotifMouseHandler can see the
255     // superclass protected ivars
256     //
257 
getDragger()258     private DragController getDragger() {
259         return dragger;
260     }
261 
getSplitPane()262     private JSplitPane getSplitPane() {
263         return splitPane;
264     }
265 
266 
267     /**
268      * MouseHandler is subclassed to only pass off to super if the mouse
269      * is in the thumb. Motif only allows dragging when the thumb is clicked
270      * in.
271      */
272     private class MotifMouseHandler extends MouseHandler {
mousePressed(MouseEvent e)273         public void mousePressed(MouseEvent e) {
274             // Constrain the mouse pressed to the thumb.
275             if (e.getSource() == MotifSplitPaneDivider.this &&
276                 getDragger() == null && getSplitPane().isEnabled() &&
277                 isInThumb(e.getX(), e.getY())) {
278                 super.mousePressed(e);
279             }
280         }
281 
mouseMoved(MouseEvent e)282         public void mouseMoved(MouseEvent e) {
283             if (getDragger() != null) {
284                 return;
285             }
286             if (!isInThumb(e.getX(), e.getY())) {
287                 if (getCursor() != defaultCursor) {
288                     setCursor(defaultCursor);
289                 }
290                 return;
291             }
292             super.mouseMoved(e);
293         }
294     }
295 }
296