1 /* 2 * Copyright (c) 1998, 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 javax.swing.plaf.metal; 27 28 import java.awt.*; 29 import javax.swing.*; 30 import javax.swing.border.*; 31 import javax.swing.plaf.basic.*; 32 33 34 /** 35 * Metal's split pane divider 36 * <p> 37 * <strong>Warning:</strong> 38 * Serialized objects of this class will not be compatible with 39 * future Swing releases. The current serialization support is 40 * appropriate for short term storage or RMI between applications running 41 * the same version of Swing. As of 1.4, support for long term storage 42 * of all JavaBeans™ 43 * has been added to the <code>java.beans</code> package. 44 * Please see {@link java.beans.XMLEncoder}. 45 * 46 * @author Steve Wilson 47 * @author Ralph kar 48 */ 49 @SuppressWarnings("serial") // Same-version serialization only 50 class MetalSplitPaneDivider extends BasicSplitPaneDivider 51 { 52 private MetalBumps bumps = new MetalBumps(10, 10, 53 MetalLookAndFeel.getControlHighlight(), 54 MetalLookAndFeel.getControlDarkShadow(), 55 MetalLookAndFeel.getControl() ); 56 57 private MetalBumps focusBumps = new MetalBumps(10, 10, 58 MetalLookAndFeel.getPrimaryControlHighlight(), 59 MetalLookAndFeel.getPrimaryControlDarkShadow(), 60 UIManager.getColor("SplitPane.dividerFocusColor")); 61 62 private int inset = 2; 63 64 private Color controlColor = MetalLookAndFeel.getControl(); 65 private Color primaryControlColor = UIManager.getColor( 66 "SplitPane.dividerFocusColor"); 67 68 public MetalSplitPaneDivider(BasicSplitPaneUI ui) { 69 super(ui); 70 } 71 72 public void paint(Graphics g) { 73 MetalBumps usedBumps; 74 if (splitPane.hasFocus()) { 75 usedBumps = focusBumps; 76 g.setColor(primaryControlColor); 77 } 78 else { 79 usedBumps = bumps; 80 g.setColor(controlColor); 81 } 82 Rectangle clip = g.getClipBounds(); 83 Insets insets = getInsets(); 84 g.fillRect(clip.x, clip.y, clip.width, clip.height); 85 Dimension size = getSize(); 86 size.width -= inset * 2; 87 size.height -= inset * 2; 88 int drawX = inset; 89 int drawY = inset; 90 if (insets != null) { 91 size.width -= (insets.left + insets.right); 92 size.height -= (insets.top + insets.bottom); 93 drawX += insets.left; 94 drawY += insets.top; 95 } 96 usedBumps.setBumpArea(size); 97 usedBumps.paintIcon(this, g, drawX, drawY); 98 super.paint(g); 99 } 100 101 /** 102 * Creates and return an instance of JButton that can be used to 103 * collapse the left component in the metal split pane. 104 */ 105 protected JButton createLeftOneTouchButton() { 106 JButton b = new JButton() { 107 // Sprite buffer for the arrow image of the left button 108 int[][] buffer = {{0, 0, 0, 2, 2, 0, 0, 0, 0}, 109 {0, 0, 2, 1, 1, 1, 0, 0, 0}, 110 {0, 2, 1, 1, 1, 1, 1, 0, 0}, 111 {2, 1, 1, 1, 1, 1, 1, 1, 0}, 112 {0, 3, 3, 3, 3, 3, 3, 3, 3}}; 113 114 public void setBorder(Border b) { 115 } 116 117 public void paint(Graphics g) { 118 JSplitPane splitPane = getSplitPaneFromSuper(); 119 if(splitPane != null) { 120 int oneTouchSize = getOneTouchSizeFromSuper(); 121 int orientation = getOrientationFromSuper(); 122 int blockSize = Math.min(getDividerSize(), 123 oneTouchSize); 124 125 // Initialize the color array 126 Color[] colors = { 127 this.getBackground(), 128 MetalLookAndFeel.getPrimaryControlDarkShadow(), 129 MetalLookAndFeel.getPrimaryControlInfo(), 130 MetalLookAndFeel.getPrimaryControlHighlight()}; 131 132 // Fill the background first ... 133 g.setColor(this.getBackground()); 134 if (isOpaque()) { 135 g.fillRect(0, 0, this.getWidth(), 136 this.getHeight()); 137 } 138 139 // ... then draw the arrow. 140 if (getModel().isPressed()) { 141 // Adjust color mapping for pressed button state 142 colors[1] = colors[2]; 143 } 144 if(orientation == JSplitPane.VERTICAL_SPLIT) { 145 // Draw the image for a vertical split 146 for (int i=1; i<=buffer[0].length; i++) { 147 for (int j=1; j<blockSize; j++) { 148 if (buffer[j-1][i-1] == 0) { 149 continue; 150 } 151 else { 152 g.setColor( 153 colors[buffer[j-1][i-1]]); 154 } 155 g.drawLine(i, j, i, j); 156 } 157 } 158 } 159 else { 160 // Draw the image for a horizontal split 161 // by simply swaping the i and j axis. 162 // Except the drawLine() call this code is 163 // identical to the code block above. This was done 164 // in order to remove the additional orientation 165 // check for each pixel. 166 for (int i=1; i<=buffer[0].length; i++) { 167 for (int j=1; j<blockSize; j++) { 168 if (buffer[j-1][i-1] == 0) { 169 // Nothing needs 170 // to be drawn 171 continue; 172 } 173 else { 174 // Set the color from the 175 // color map 176 g.setColor( 177 colors[buffer[j-1][i-1]]); 178 } 179 // Draw a pixel 180 g.drawLine(j, i, j, i); 181 } 182 } 183 } 184 } 185 } 186 187 // Don't want the button to participate in focus traversable. 188 @SuppressWarnings("deprecation") 189 public boolean isFocusTraversable() { 190 return false; 191 } 192 }; 193 b.setRequestFocusEnabled(false); 194 b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 195 b.setFocusPainted(false); 196 b.setBorderPainted(false); 197 maybeMakeButtonOpaque(b); 198 return b; 199 } 200 201 /** 202 * If necessary <code>c</code> is made opaque. 203 */ 204 private void maybeMakeButtonOpaque(JComponent c) { 205 Object opaque = UIManager.get("SplitPane.oneTouchButtonsOpaque"); 206 if (opaque != null) { 207 c.setOpaque(((Boolean)opaque).booleanValue()); 208 } 209 } 210 211 /** 212 * Creates and return an instance of JButton that can be used to 213 * collapse the right component in the metal split pane. 214 */ 215 protected JButton createRightOneTouchButton() { 216 JButton b = new JButton() { 217 // Sprite buffer for the arrow image of the right button 218 int[][] buffer = {{2, 2, 2, 2, 2, 2, 2, 2}, 219 {0, 1, 1, 1, 1, 1, 1, 3}, 220 {0, 0, 1, 1, 1, 1, 3, 0}, 221 {0, 0, 0, 1, 1, 3, 0, 0}, 222 {0, 0, 0, 0, 3, 0, 0, 0}}; 223 224 public void setBorder(Border border) { 225 } 226 227 public void paint(Graphics g) { 228 JSplitPane splitPane = getSplitPaneFromSuper(); 229 if(splitPane != null) { 230 int oneTouchSize = getOneTouchSizeFromSuper(); 231 int orientation = getOrientationFromSuper(); 232 int blockSize = Math.min(getDividerSize(), 233 oneTouchSize); 234 235 // Initialize the color array 236 Color[] colors = { 237 this.getBackground(), 238 MetalLookAndFeel.getPrimaryControlDarkShadow(), 239 MetalLookAndFeel.getPrimaryControlInfo(), 240 MetalLookAndFeel.getPrimaryControlHighlight()}; 241 242 // Fill the background first ... 243 g.setColor(this.getBackground()); 244 if (isOpaque()) { 245 g.fillRect(0, 0, this.getWidth(), 246 this.getHeight()); 247 } 248 249 // ... then draw the arrow. 250 if (getModel().isPressed()) { 251 // Adjust color mapping for pressed button state 252 colors[1] = colors[2]; 253 } 254 if(orientation == JSplitPane.VERTICAL_SPLIT) { 255 // Draw the image for a vertical split 256 for (int i=1; i<=buffer[0].length; i++) { 257 for (int j=1; j<blockSize; j++) { 258 if (buffer[j-1][i-1] == 0) { 259 continue; 260 } 261 else { 262 g.setColor( 263 colors[buffer[j-1][i-1]]); 264 } 265 g.drawLine(i, j, i, j); 266 } 267 } 268 } 269 else { 270 // Draw the image for a horizontal split 271 // by simply swaping the i and j axis. 272 // Except the drawLine() call this code is 273 // identical to the code block above. This was done 274 // in order to remove the additional orientation 275 // check for each pixel. 276 for (int i=1; i<=buffer[0].length; i++) { 277 for (int j=1; j<blockSize; j++) { 278 if (buffer[j-1][i-1] == 0) { 279 // Nothing needs 280 // to be drawn 281 continue; 282 } 283 else { 284 // Set the color from the 285 // color map 286 g.setColor( 287 colors[buffer[j-1][i-1]]); 288 } 289 // Draw a pixel 290 g.drawLine(j, i, j, i); 291 } 292 } 293 } 294 } 295 } 296 297 // Don't want the button to participate in focus traversable. 298 @SuppressWarnings("deprecation") 299 public boolean isFocusTraversable() { 300 return false; 301 } 302 }; 303 b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 304 b.setFocusPainted(false); 305 b.setBorderPainted(false); 306 b.setRequestFocusEnabled(false); 307 maybeMakeButtonOpaque(b); 308 return b; 309 } 310 311 /** 312 * Used to layout a MetalSplitPaneDivider. Layout for the divider 313 * involves appropriately moving the left/right buttons around. 314 * <p> 315 * This class should be treated as a "protected" inner class. 316 * Instantiate it only within subclasses of MetalSplitPaneDivider. 317 */ 318 public class MetalDividerLayout implements LayoutManager { 319 320 // NOTE NOTE NOTE NOTE NOTE 321 // This class is no longer used, the functionality has 322 // been rolled into BasicSplitPaneDivider.DividerLayout as a 323 // defaults property 324 325 public void layoutContainer(Container c) { 326 JButton leftButton = getLeftButtonFromSuper(); 327 JButton rightButton = getRightButtonFromSuper(); 328 JSplitPane splitPane = getSplitPaneFromSuper(); 329 int orientation = getOrientationFromSuper(); 330 int oneTouchSize = getOneTouchSizeFromSuper(); 331 int oneTouchOffset = getOneTouchOffsetFromSuper(); 332 Insets insets = getInsets(); 333 334 // This layout differs from the one used in BasicSplitPaneDivider. 335 // It does not center justify the oneTouchExpadable buttons. 336 // This was necessary in order to meet the spec of the Metal 337 // splitpane divider. 338 if (leftButton != null && rightButton != null && 339 c == MetalSplitPaneDivider.this) { 340 if (splitPane.isOneTouchExpandable()) { 341 if (orientation == JSplitPane.VERTICAL_SPLIT) { 342 int extraY = (insets != null) ? insets.top : 0; 343 int blockSize = getDividerSize(); 344 345 if (insets != null) { 346 blockSize -= (insets.top + insets.bottom); 347 } 348 blockSize = Math.min(blockSize, oneTouchSize); 349 leftButton.setBounds(oneTouchOffset, extraY, 350 blockSize * 2, blockSize); 351 rightButton.setBounds(oneTouchOffset + 352 oneTouchSize * 2, extraY, 353 blockSize * 2, blockSize); 354 } 355 else { 356 int blockSize = getDividerSize(); 357 int extraX = (insets != null) ? insets.left : 0; 358 359 if (insets != null) { 360 blockSize -= (insets.left + insets.right); 361 } 362 blockSize = Math.min(blockSize, oneTouchSize); 363 leftButton.setBounds(extraX, oneTouchOffset, 364 blockSize, blockSize * 2); 365 rightButton.setBounds(extraX, oneTouchOffset + 366 oneTouchSize * 2, blockSize, 367 blockSize * 2); 368 } 369 } 370 else { 371 leftButton.setBounds(-5, -5, 1, 1); 372 rightButton.setBounds(-5, -5, 1, 1); 373 } 374 } 375 } 376 377 public Dimension minimumLayoutSize(Container c) { 378 return new Dimension(0,0); 379 } 380 381 public Dimension preferredLayoutSize(Container c) { 382 return new Dimension(0, 0); 383 } 384 385 public void removeLayoutComponent(Component c) {} 386 387 public void addLayoutComponent(String string, Component c) {} 388 } 389 390 /* 391 * The following methods only exist in order to be able to access protected 392 * members in the superclass, because these are otherwise not available 393 * in any inner class. 394 */ 395 396 int getOneTouchSizeFromSuper() { 397 return BasicSplitPaneDivider.ONE_TOUCH_SIZE; 398 } 399 400 int getOneTouchOffsetFromSuper() { 401 return BasicSplitPaneDivider.ONE_TOUCH_OFFSET; 402 } 403 404 int getOrientationFromSuper() { 405 return super.orientation; 406 } 407 408 JSplitPane getSplitPaneFromSuper() { 409 return super.splitPane; 410 } 411 412 JButton getLeftButtonFromSuper() { 413 return super.leftButton; 414 } 415 416 JButton getRightButtonFromSuper() { 417 return super.rightButton; 418 } 419 }