001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Anton Avtamonov
020: * @version $Revision$
021: */package javax.swing.plaf.basic;
022:
023: import java.awt.Color;
024: import java.awt.Component;
025: import java.awt.Container;
026: import java.awt.Cursor;
027: import java.awt.Dimension;
028: import java.awt.Graphics;
029: import java.awt.Insets;
030: import java.awt.LayoutManager;
031: import java.awt.event.ActionEvent;
032: import java.awt.event.ActionListener;
033: import java.awt.event.MouseAdapter;
034: import java.awt.event.MouseEvent;
035: import java.awt.event.MouseMotionListener;
036: import java.beans.PropertyChangeEvent;
037: import java.beans.PropertyChangeListener;
038:
039: import javax.swing.JButton;
040: import javax.swing.JSplitPane;
041: import javax.swing.SwingConstants;
042: import javax.swing.UIManager;
043: import javax.swing.border.Border;
044:
045: import org.apache.harmony.x.swing.StringConstants;
046: import org.apache.harmony.x.swing.Utilities;
047:
048: public class BasicSplitPaneDivider extends Container implements
049: PropertyChangeListener {
050: protected class DividerLayout implements LayoutManager {
051: public void layoutContainer(final Container c) {
052: if (splitPane.isOneTouchExpandable()) {
053: Insets insets = getInsets();
054: int buttonSize = ONE_TOUCH_SIZE;
055: int startPos = ONE_TOUCH_OFFSET;
056: if (ONE_TOUCH_SIZE + ONE_TOUCH_OFFSET > dividerSize) {
057: if (ONE_TOUCH_SIZE < dividerSize) {
058: buttonSize = dividerSize;
059: startPos = 0;
060: }
061: }
062:
063: if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
064: leftButton.setBounds(startPos + insets.left,
065: ONE_TOUCH_OFFSET + insets.top, buttonSize,
066: buttonSize);
067: rightButton.setBounds(startPos + insets.left,
068: buttonSize + 2 * ONE_TOUCH_OFFSET
069: + insets.top, buttonSize,
070: buttonSize);
071: } else {
072: leftButton.setBounds(
073: ONE_TOUCH_OFFSET + insets.left, startPos
074: + insets.top, buttonSize,
075: buttonSize);
076: rightButton.setBounds(buttonSize + 2
077: * ONE_TOUCH_OFFSET + insets.left, startPos
078: + insets.top, buttonSize, buttonSize);
079: }
080: }
081: }
082:
083: public Dimension minimumLayoutSize(final Container c) {
084: return null;
085: }
086:
087: public Dimension preferredLayoutSize(final Container c) {
088: return null;
089: }
090:
091: public void removeLayoutComponent(final Component c) {
092:
093: }
094:
095: public void addLayoutComponent(final String constraint,
096: final Component c) {
097:
098: }
099: }
100:
101: protected class DragController {
102: private final int initialMousePosition;
103:
104: protected DragController(final MouseEvent e) {
105: initialMousePosition = positionForMouseEvent(e);
106: if (!splitPane.isContinuousLayout()) {
107: prepareForDragging();
108: }
109: }
110:
111: protected boolean isValid() {
112: return true;
113: }
114:
115: protected int positionForMouseEvent(final MouseEvent e) {
116: return e.getX();
117: }
118:
119: protected int getNeededLocation(final int x, final int y) {
120: return x;
121: }
122:
123: protected void continueDrag(final int x, final int y) {
124: int location = calculateDividerLocation(x, y);
125: if (splitPane.isContinuousLayout()) {
126: splitPane.setDividerLocation(location);
127: } else {
128: dragDividerTo(location);
129: }
130: }
131:
132: protected void continueDrag(final MouseEvent e) {
133: continueDrag(e.getX(), e.getY());
134: }
135:
136: protected void completeDrag(final int x, final int y) {
137: if (!splitPane.isContinuousLayout()) {
138: int location = calculateDividerLocation(x, y);
139: finishDraggingTo(location);
140: }
141: }
142:
143: protected void completeDrag(final MouseEvent e) {
144: completeDrag(e.getX(), e.getY());
145: }
146:
147: private int calculateDividerLocation(final int x, final int y) {
148: int mousePosition = getNeededLocation(x, y);
149: int delta = mousePosition - initialMousePosition;
150: int dividerLocation = splitPane.getDividerLocation()
151: + delta;
152:
153: if (splitPane.getMaximumDividerLocation() < splitPane
154: .getMinimumDividerLocation()) {
155: return splitPane.getDividerLocation();
156: }
157:
158: if (dividerLocation >= splitPane
159: .getMinimumDividerLocation()
160: && dividerLocation <= splitPane
161: .getMaximumDividerLocation()) {
162:
163: return dividerLocation;
164: } else if (dividerLocation >= splitPane
165: .getMaximumDividerLocation()) {
166: return splitPane.getMaximumDividerLocation();
167: } else {
168: return splitPane.getMinimumDividerLocation();
169: }
170: }
171: }
172:
173: protected class VerticalDragController extends DragController {
174: protected VerticalDragController(final MouseEvent e) {
175: super (e);
176: }
177:
178: protected int getNeededLocation(final int x, final int y) {
179: return y;
180: }
181:
182: protected int positionForMouseEvent(final MouseEvent e) {
183: return e.getY();
184: }
185: }
186:
187: protected class MouseHandler extends MouseAdapter implements
188: MouseMotionListener {
189: public void mousePressed(final MouseEvent e) {
190: if (dragger == null) {
191: dragger = orientation == JSplitPane.HORIZONTAL_SPLIT ? new DragController(
192: e)
193: : new VerticalDragController(e);
194: }
195: }
196:
197: public void mouseReleased(final MouseEvent e) {
198: if (dragger != null) {
199: dragger.completeDrag(e);
200: }
201: dragger = null;
202: }
203:
204: public void mouseDragged(final MouseEvent e) {
205: if (dragger != null) {
206: dragger.continueDrag(e);
207: }
208: }
209:
210: public void mouseMoved(final MouseEvent e) {
211: }
212:
213: public void mouseEntered(final MouseEvent e) {
214: setMouseOver(true);
215: }
216:
217: public void mouseExited(final MouseEvent e) {
218: setMouseOver(false);
219: }
220: }
221:
222: private class ArrowButton extends JButton {
223: private final int direction;
224:
225: public ArrowButton(final int direction) {
226: this .direction = direction;
227: setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
228: setOpaque(false);
229: setFocusable(false);
230: }
231:
232: public void paint(final Graphics g) {
233: paint3DArrow(g, direction, getWidth(), Color.DARK_GRAY,
234: Color.WHITE, getModel().isArmed());
235: }
236:
237: private void paint3DArrow(final Graphics g,
238: final int direction, final int size,
239: final Color shadow, final Color highlight,
240: final boolean armed) {
241:
242: final int halfHeight = (size + 1) / 2;
243: final int height = halfHeight * 2;
244: final int width = halfHeight;
245:
246: final int[] heights = new int[] { 0, halfHeight - 1,
247: height - 2 };
248: final int[] lWidths = new int[] { width - 1, 0, width - 1 };
249: final int[] rWidths = new int[] { 0, width - 1, 0 };
250: int[] px = null;
251: int[] py = null;
252: int[] pxHighlight = null;
253: int[] pyHighlight = null;
254: switch (direction) {
255: case SwingConstants.NORTH:
256: px = heights;
257: py = lWidths;
258: break;
259: case SwingConstants.SOUTH:
260: px = heights;
261: py = rWidths;
262: break;
263: case SwingConstants.WEST:
264: case SwingConstants.LEFT:
265: px = lWidths;
266: py = heights;
267: break;
268: case SwingConstants.EAST:
269: case SwingConstants.RIGHT:
270: px = rWidths;
271: py = heights;
272: break;
273: default:
274: assert false : "incorrect direction";
275: }
276:
277: pxHighlight = new int[] { px[0] + 1, px[1] + 1, px[2] + 1 };
278: pyHighlight = new int[] { py[0] + 1, py[1] + 1, py[2] + 1 };
279: final Color oldColor = g.getColor();
280:
281: g.setColor(getBackground());
282: g.fillPolygon(px, py, 3);
283: g.setColor(highlight);
284: g.drawPolygon(pxHighlight, pyHighlight, 3);
285: g.setColor(shadow);
286: g.drawPolygon(px, py, 3);
287: if (armed) {
288: g.setColor(shadow);
289: g.fillPolygon(px, py, 3);
290: }
291:
292: g.setColor(oldColor);
293: }
294: }
295:
296: protected static final int ONE_TOUCH_OFFSET = 2;
297: protected static final int ONE_TOUCH_SIZE = 6;
298:
299: protected JButton leftButton;
300: protected JButton rightButton;
301: protected DragController dragger;
302: protected BasicSplitPaneUI splitPaneUI;
303: protected int dividerSize;
304: protected Component hiddenDivider;
305: protected JSplitPane splitPane;
306: protected MouseHandler mouseHandler;
307: protected int orientation;
308:
309: private Border border;
310: private boolean mouseIsOver;
311:
312: public BasicSplitPaneDivider(final BasicSplitPaneUI ui) {
313: splitPaneUI = ui;
314: splitPane = ui.splitPane;
315: orientation = splitPane.getOrientation();
316: mouseHandler = new MouseHandler();
317:
318: setLayout(new DividerLayout());
319: splitPane.addPropertyChangeListener(this );
320: addMouseListener(mouseHandler);
321: addMouseMotionListener(mouseHandler);
322: updateCursor();
323:
324: if (Utilities.isUIResource(getBorder())) {
325: setBorder(UIManager.getBorder("SplitPaneDivider.border"));
326: }
327: }
328:
329: public void setBasicSplitPaneUI(final BasicSplitPaneUI ui) {
330: splitPaneUI = ui;
331: if (ui != null) {
332: splitPane = ui.splitPane;
333: orientation = splitPane.getOrientation();
334: } else {
335: splitPane = null;
336: }
337: }
338:
339: public BasicSplitPaneUI getBasicSplitPaneUI() {
340: return splitPaneUI;
341: }
342:
343: public void setDividerSize(final int size) {
344: dividerSize = size;
345: }
346:
347: public int getDividerSize() {
348: return dividerSize;
349: }
350:
351: public void setBorder(final Border border) {
352: this .border = border;
353: }
354:
355: public Border getBorder() {
356: return border;
357: }
358:
359: public Insets getInsets() {
360: return border != null ? border.getBorderInsets(this ) : super
361: .getInsets();
362: }
363:
364: public boolean isMouseOver() {
365: return mouseIsOver;
366: }
367:
368: public Dimension getPreferredSize() {
369: if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
370: return new Dimension(dividerSize, 1);
371: } else {
372: return new Dimension(1, dividerSize);
373: }
374:
375: }
376:
377: public Dimension getMinimumSize() {
378: return getPreferredSize();
379: }
380:
381: public void propertyChange(final PropertyChangeEvent e) {
382: ;
383: if (JSplitPane.ORIENTATION_PROPERTY.equals(e.getPropertyName())) {
384: orientation = splitPane.getOrientation();
385: updateCursor();
386: updateButtons();
387: } else if (JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY.equals(e
388: .getPropertyName())) {
389: oneTouchExpandableChanged();
390: } else if (StringConstants.ENABLED_PROPERTY_CHANGED.equals(e
391: .getPropertyName())) {
392: boolean isEnabled = ((Boolean) e.getNewValue())
393: .booleanValue();
394: if (isEnabled) {
395: addMouseListener(mouseHandler);
396: addMouseMotionListener(mouseHandler);
397: } else {
398: removeMouseListener(mouseHandler);
399: removeMouseMotionListener(mouseHandler);
400: }
401: enableButtons(isEnabled);
402: }
403: invalidate();
404: validate();
405: }
406:
407: public void paint(final Graphics g) {
408: super .paint(g);
409: if (splitPane.isFocusOwner()) {
410: g.setColor(UIManager.getColor("SplitPane.darkShadow"));
411: g.drawRect(0, 0, getWidth() - 2, getHeight() - 2);
412: }
413: if (getBorder() != null) {
414: getBorder().paintBorder(this , g, 0, 0, getWidth(),
415: getHeight());
416: }
417: }
418:
419: protected JButton createLeftOneTouchButton() {
420: JButton result = new ArrowButton(
421: orientation == JSplitPane.HORIZONTAL_SPLIT ? SwingConstants.WEST
422: : SwingConstants.NORTH);
423: result.addActionListener(new ActionListener() {
424: public void actionPerformed(final ActionEvent e) {
425: Insets insets = splitPane.getInsets();
426: int oldLocation = splitPaneUI
427: .getDividerLocation(splitPane);
428: int newLocation;
429: if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
430: if (oldLocation == insets.left) {
431: return;
432: } else if (oldLocation == splitPane.getWidth()
433: - insets.right - splitPane.getDividerSize()) {
434: newLocation = splitPane
435: .getLastDividerLocation();
436: } else {
437: newLocation = insets.left;
438: }
439: } else {
440: if (oldLocation == insets.top) {
441: return;
442: } else if (oldLocation == splitPane.getHeight()
443: - insets.bottom
444: - splitPane.getDividerSize()) {
445: newLocation = splitPane
446: .getLastDividerLocation();
447: } else {
448: newLocation = insets.top;
449: }
450: }
451:
452: splitPane.setDividerLocation(newLocation);
453: }
454: });
455:
456: return result;
457: }
458:
459: protected JButton createRightOneTouchButton() {
460: JButton result = new ArrowButton(
461: orientation == JSplitPane.HORIZONTAL_SPLIT ? SwingConstants.EAST
462: : SwingConstants.SOUTH);
463: result.addActionListener(new ActionListener() {
464: public void actionPerformed(final ActionEvent e) {
465: Insets insets = splitPane.getInsets();
466: int oldLocation = splitPaneUI
467: .getDividerLocation(splitPane);
468: int newLocation;
469: if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
470: if (oldLocation == splitPane.getWidth()
471: - insets.right - splitPane.getDividerSize()) {
472: return;
473: } else if (oldLocation == insets.left) {
474: newLocation = splitPane
475: .getLastDividerLocation();
476: } else {
477: newLocation = splitPane.getWidth()
478: - insets.right
479: - splitPane.getDividerSize();
480: }
481: } else {
482: if (oldLocation == splitPane.getHeight()
483: - insets.bottom
484: - splitPane.getDividerSize()) {
485: return;
486: } else if (oldLocation == insets.top) {
487: newLocation = splitPane
488: .getLastDividerLocation();
489: } else {
490: newLocation = splitPane.getHeight()
491: - insets.bottom
492: - splitPane.getDividerSize();
493: }
494: }
495:
496: splitPane.setDividerLocation(newLocation);
497: }
498: });
499:
500: return result;
501: }
502:
503: protected void oneTouchExpandableChanged() {
504: if (leftButton != null) {
505: remove(leftButton);
506: }
507: if (rightButton != null) {
508: remove(rightButton);
509: }
510: if (splitPane.isOneTouchExpandable()) {
511: leftButton = createLeftOneTouchButton();
512: rightButton = createRightOneTouchButton();
513: add(leftButton);
514: add(rightButton);
515: }
516: }
517:
518: protected void prepareForDragging() {
519: splitPaneUI.startDragging();
520: }
521:
522: protected void dragDividerTo(final int location) {
523: splitPaneUI.dragDividerTo(location);
524: }
525:
526: protected void finishDraggingTo(final int location) {
527: splitPaneUI.finishDraggingTo(location);
528: }
529:
530: protected void setMouseOver(final boolean mouseOver) {
531: mouseIsOver = mouseOver;
532: }
533:
534: private void updateCursor() {
535: if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
536: setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
537: } else {
538: setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
539: }
540: }
541:
542: private void updateButtons() {
543: if (leftButton != null) {
544: remove(leftButton);
545: leftButton = createLeftOneTouchButton();
546: add(leftButton);
547: }
548: if (rightButton != null) {
549: remove(rightButton);
550: rightButton = createRightOneTouchButton();
551: add(rightButton);
552: }
553: }
554:
555: private void enableButtons(final boolean enable) {
556: if (leftButton != null) {
557: leftButton.setEnabled(enable);
558: }
559: if (rightButton != null) {
560: rightButton.setEnabled(enable);
561: }
562: }
563: }
|