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 */ 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 */ 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. 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 */ 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 */ 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 */ 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 259 private DragController getDragger() { 260 return dragger; 261 } 262 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 { 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 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 }