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