History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicSplitPaneDivider.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicSplitPaneDivider.java+1090−0
@@ -0,0 +1,1090 @@
1+/*
2+ * Copyright (c) 1997, 2006, 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+
27+
28+package javax.swing.plaf.basic;
29+
30+
31+
32+import java.awt.*;
33+import java.awt.event.*;
34+import javax.swing.*;
35+import javax.swing.event.*;
36+import javax.swing.plaf.*;
37+import javax.swing.border.Border;
38+import java.beans.*;
39+import sun.swing.DefaultLookup;
40+
41+
42+
43+/**
44+ * Divider used by BasicSplitPaneUI. Subclassers may wish to override
45+ * paint to do something more interesting.
46+ * The border effect is drawn in BasicSplitPaneUI, so if you don't like
47+ * that border, reset it there.
48+ * To conditionally drag from certain areas subclass mousePressed and
49+ * call super when you wish the dragging to begin.
50+ * <p>
51+ * <strong>Warning:</strong>
52+ * Serialized objects of this class will not be compatible with
53+ * future Swing releases. The current serialization support is
54+ * appropriate for short term storage or RMI between applications running
55+ * the same version of Swing. As of 1.4, support for long term storage
56+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
57+ * has been added to the <code>java.beans</code> package.
58+ * Please see {@link java.beans.XMLEncoder}.
59+ *
60+ * @author Scott Violet
61+ */
62+public class BasicSplitPaneDivider extends Container
63+ implements PropertyChangeListener
64+{
65+ /**
66+ * Width or height of the divider based on orientation
67+ * BasicSplitPaneUI adds two to this.
68+ */
69+ protected static final int ONE_TOUCH_SIZE = 6;
70+ protected static final int ONE_TOUCH_OFFSET = 2;
71+
72+ /**
73+ * Handles mouse dragging message to do the actual dragging.
74+ */
75+ protected DragController dragger;
76+
77+ /**
78+ * UI this instance was created from.
79+ */
80+ protected BasicSplitPaneUI splitPaneUI;
81+
82+ /**
83+ * Size of the divider.
84+ */
85+ protected int dividerSize = 0; // default - SET TO 0???
86+
87+ /**
88+ * Divider that is used for noncontinuous layout mode.
89+ */
90+ protected Component hiddenDivider;
91+
92+ /**
93+ * JSplitPane the receiver is contained in.
94+ */
95+ protected JSplitPane splitPane;
96+
97+ /**
98+ * Handles mouse events from both this class, and the split pane.
99+ * Mouse events are handled for the splitpane since you want to be able
100+ * to drag when clicking on the border of the divider, which is not
101+ * drawn by the divider.
102+ */
103+ protected MouseHandler mouseHandler;
104+
105+ /**
106+ * Orientation of the JSplitPane.
107+ */
108+ protected int orientation;
109+
110+ /**
111+ * Button for quickly toggling the left component.
112+ */
113+ protected JButton leftButton;
114+
115+ /**
116+ * Button for quickly toggling the right component.
117+ */
118+ protected JButton rightButton;
119+
120+ /** Border. */
121+ private Border border;
122+
123+ /**
124+ * Is the mouse over the divider?
125+ */
126+ private boolean mouseOver;
127+
128+ private int oneTouchSize;
129+ private int oneTouchOffset;
130+
131+ /**
132+ * If true the one touch buttons are centered on the divider.
133+ */
134+ private boolean centerOneTouchButtons;
135+
136+
137+ /**
138+ * Creates an instance of BasicSplitPaneDivider. Registers this
139+ * instance for mouse events and mouse dragged events.
140+ */
141+ public BasicSplitPaneDivider(BasicSplitPaneUI ui) {
142+ oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui,
143+ "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
144+ oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui,
145+ "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
146+ centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(),
147+ ui, "SplitPane.centerOneTouchButtons", true);
148+ setLayout(new DividerLayout());
149+ setBasicSplitPaneUI(ui);
150+ orientation = splitPane.getOrientation();
151+ setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
152+ Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
153+ Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
154+ setBackground(UIManager.getColor("SplitPane.background"));
155+ }
156+
157+ private void revalidateSplitPane() {
158+ invalidate();
159+ if (splitPane != null) {
160+ splitPane.revalidate();
161+ }
162+ }
163+
164+ /**
165+ * Sets the SplitPaneUI that is using the receiver.
166+ */
167+ public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) {
168+ if (splitPane != null) {
169+ splitPane.removePropertyChangeListener(this);
170+ if (mouseHandler != null) {
171+ splitPane.removeMouseListener(mouseHandler);
172+ splitPane.removeMouseMotionListener(mouseHandler);
173+ removeMouseListener(mouseHandler);
174+ removeMouseMotionListener(mouseHandler);
175+ mouseHandler = null;
176+ }
177+ }
178+ splitPaneUI = newUI;
179+ if (newUI != null) {
180+ splitPane = newUI.getSplitPane();
181+ if (splitPane != null) {
182+ if (mouseHandler == null) mouseHandler = new MouseHandler();
183+ splitPane.addMouseListener(mouseHandler);
184+ splitPane.addMouseMotionListener(mouseHandler);
185+ addMouseListener(mouseHandler);
186+ addMouseMotionListener(mouseHandler);
187+ splitPane.addPropertyChangeListener(this);
188+ if (splitPane.isOneTouchExpandable()) {
189+ oneTouchExpandableChanged();
190+ }
191+ }
192+ }
193+ else {
194+ splitPane = null;
195+ }
196+ }
197+
198+
199+ /**
200+ * Returns the <code>SplitPaneUI</code> the receiver is currently
201+ * in.
202+ */
203+ public BasicSplitPaneUI getBasicSplitPaneUI() {
204+ return splitPaneUI;
205+ }
206+
207+
208+ /**
209+ * Sets the size of the divider to <code>newSize</code>. That is
210+ * the width if the splitpane is <code>HORIZONTAL_SPLIT</code>, or
211+ * the height of <code>VERTICAL_SPLIT</code>.
212+ */
213+ public void setDividerSize(int newSize) {
214+ dividerSize = newSize;
215+ }
216+
217+
218+ /**
219+ * Returns the size of the divider, that is the width if the splitpane
220+ * is HORIZONTAL_SPLIT, or the height of VERTICAL_SPLIT.
221+ */
222+ public int getDividerSize() {
223+ return dividerSize;
224+ }
225+
226+
227+ /**
228+ * Sets the border of this component.
229+ * @since 1.3
230+ */
231+ public void setBorder(Border border) {
232+ Border oldBorder = this.border;
233+
234+ this.border = border;
235+ }
236+
237+ /**
238+ * Returns the border of this component or null if no border is
239+ * currently set.
240+ *
241+ * @return the border object for this component
242+ * @see #setBorder
243+ * @since 1.3
244+ */
245+ public Border getBorder() {
246+ return border;
247+ }
248+
249+ /**
250+ * If a border has been set on this component, returns the
251+ * border's insets, else calls super.getInsets.
252+ *
253+ * @return the value of the insets property.
254+ * @see #setBorder
255+ */
256+ public Insets getInsets() {
257+ Border border = getBorder();
258+
259+ if (border != null) {
260+ return border.getBorderInsets(this);
261+ }
262+ return super.getInsets();
263+ }
264+
265+ /**
266+ * Sets whether or not the mouse is currently over the divider.
267+ *
268+ * @param mouseOver whether or not the mouse is currently over the divider
269+ * @since 1.5
270+ */
271+ protected void setMouseOver(boolean mouseOver) {
272+ this.mouseOver = mouseOver;
273+ }
274+
275+ /**
276+ * Returns whether or not the mouse is currently over the divider
277+ *
278+ * @return whether or not the mouse is currently over the divider
279+ * @since 1.5
280+ */
281+ public boolean isMouseOver() {
282+ return mouseOver;
283+ }
284+
285+ /**
286+ * Returns dividerSize x dividerSize
287+ */
288+ public Dimension getPreferredSize() {
289+ // Ideally this would return the size from the layout manager,
290+ // but that could result in the layed out size being different from
291+ // the dividerSize, which may break developers as well as
292+ // BasicSplitPaneUI.
293+ if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
294+ return new Dimension(getDividerSize(), 1);
295+ }
296+ return new Dimension(1, getDividerSize());
297+ }
298+
299+ /**
300+ * Returns dividerSize x dividerSize
301+ */
302+ public Dimension getMinimumSize() {
303+ return getPreferredSize();
304+ }
305+
306+
307+ /**
308+ * Property change event, presumably from the JSplitPane, will message
309+ * updateOrientation if necessary.
310+ */
311+ public void propertyChange(PropertyChangeEvent e) {
312+ if (e.getSource() == splitPane) {
313+ if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {
314+ orientation = splitPane.getOrientation();
315+ setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
316+ Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
317+ Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
318+ revalidateSplitPane();
319+ }
320+ else if (e.getPropertyName() == JSplitPane.
321+ ONE_TOUCH_EXPANDABLE_PROPERTY) {
322+ oneTouchExpandableChanged();
323+ }
324+ }
325+ }
326+
327+
328+ /**
329+ * Paints the divider.
330+ */
331+ public void paint(Graphics g) {
332+ super.paint(g);
333+
334+ // Paint the border.
335+ Border border = getBorder();
336+
337+ if (border != null) {
338+ Dimension size = getSize();
339+
340+ border.paintBorder(this, g, 0, 0, size.width, size.height);
341+ }
342+ }
343+
344+
345+ /**
346+ * Messaged when the oneTouchExpandable value of the JSplitPane the
347+ * receiver is contained in changes. Will create the
348+ * <code>leftButton</code> and <code>rightButton</code> if they
349+ * are null. invalidates the receiver as well.
350+ */
351+ protected void oneTouchExpandableChanged() {
352+ if (!DefaultLookup.getBoolean(splitPane, splitPaneUI,
353+ "SplitPane.supportsOneTouchButtons", true)) {
354+ // Look and feel doesn't want to support one touch buttons, bail.
355+ return;
356+ }
357+ if (splitPane.isOneTouchExpandable() &&
358+ leftButton == null &&
359+ rightButton == null) {
360+ /* Create the left button and add an action listener to
361+ expand/collapse it. */
362+ leftButton = createLeftOneTouchButton();
363+ if (leftButton != null)
364+ leftButton.addActionListener(new OneTouchActionHandler(true));
365+
366+
367+ /* Create the right button and add an action listener to
368+ expand/collapse it. */
369+ rightButton = createRightOneTouchButton();
370+ if (rightButton != null)
371+ rightButton.addActionListener(new OneTouchActionHandler
372+ (false));
373+
374+ if (leftButton != null && rightButton != null) {
375+ add(leftButton);
376+ add(rightButton);
377+ }
378+ }
379+ revalidateSplitPane();
380+ }
381+
382+
383+ /**
384+ * Creates and return an instance of JButton that can be used to
385+ * collapse the left component in the split pane.
386+ */
387+ protected JButton createLeftOneTouchButton() {
388+ JButton b = new JButton() {
389+ public void setBorder(Border b) {
390+ }
391+ public void paint(Graphics g) {
392+ if (splitPane != null) {
393+ int[] xs = new int[3];
394+ int[] ys = new int[3];
395+ int blockSize;
396+
397+ // Fill the background first ...
398+ g.setColor(this.getBackground());
399+ g.fillRect(0, 0, this.getWidth(),
400+ this.getHeight());
401+
402+ // ... then draw the arrow.
403+ g.setColor(Color.black);
404+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
405+ blockSize = Math.min(getHeight(), oneTouchSize);
406+ xs[0] = blockSize;
407+ xs[1] = 0;
408+ xs[2] = blockSize << 1;
409+ ys[0] = 0;
410+ ys[1] = ys[2] = blockSize;
411+ g.drawPolygon(xs, ys, 3); // Little trick to make the
412+ // arrows of equal size
413+ }
414+ else {
415+ blockSize = Math.min(getWidth(), oneTouchSize);
416+ xs[0] = xs[2] = blockSize;
417+ xs[1] = 0;
418+ ys[0] = 0;
419+ ys[1] = blockSize;
420+ ys[2] = blockSize << 1;
421+ }
422+ g.fillPolygon(xs, ys, 3);
423+ }
424+ }
425+ // Don't want the button to participate in focus traversable.
426+ public boolean isFocusTraversable() {
427+ return false;
428+ }
429+ };
430+ b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
431+ b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
432+ b.setFocusPainted(false);
433+ b.setBorderPainted(false);
434+ b.setRequestFocusEnabled(false);
435+ return b;
436+ }
437+
438+
439+ /**
440+ * Creates and return an instance of JButton that can be used to
441+ * collapse the right component in the split pane.
442+ */
443+ protected JButton createRightOneTouchButton() {
444+ JButton b = new JButton() {
445+ public void setBorder(Border border) {
446+ }
447+ public void paint(Graphics g) {
448+ if (splitPane != null) {
449+ int[] xs = new int[3];
450+ int[] ys = new int[3];
451+ int blockSize;
452+
453+ // Fill the background first ...
454+ g.setColor(this.getBackground());
455+ g.fillRect(0, 0, this.getWidth(),
456+ this.getHeight());
457+
458+ // ... then draw the arrow.
459+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
460+ blockSize = Math.min(getHeight(), oneTouchSize);
461+ xs[0] = blockSize;
462+ xs[1] = blockSize << 1;
463+ xs[2] = 0;
464+ ys[0] = blockSize;
465+ ys[1] = ys[2] = 0;
466+ }
467+ else {
468+ blockSize = Math.min(getWidth(), oneTouchSize);
469+ xs[0] = xs[2] = 0;
470+ xs[1] = blockSize;
471+ ys[0] = 0;
472+ ys[1] = blockSize;
473+ ys[2] = blockSize << 1;
474+ }
475+ g.setColor(Color.black);
476+ g.fillPolygon(xs, ys, 3);
477+ }
478+ }
479+ // Don't want the button to participate in focus traversable.
480+ public boolean isFocusTraversable() {
481+ return false;
482+ }
483+ };
484+ b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
485+ b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
486+ b.setFocusPainted(false);
487+ b.setBorderPainted(false);
488+ b.setRequestFocusEnabled(false);
489+ return b;
490+ }
491+
492+
493+ /**
494+ * Message to prepare for dragging. This messages the BasicSplitPaneUI
495+ * with startDragging.
496+ */
497+ protected void prepareForDragging() {
498+ splitPaneUI.startDragging();
499+ }
500+
501+
502+ /**
503+ * Messages the BasicSplitPaneUI with dragDividerTo that this instance
504+ * is contained in.
505+ */
506+ protected void dragDividerTo(int location) {
507+ splitPaneUI.dragDividerTo(location);
508+ }
509+
510+
511+ /**
512+ * Messages the BasicSplitPaneUI with finishDraggingTo that this instance
513+ * is contained in.
514+ */
515+ protected void finishDraggingTo(int location) {
516+ splitPaneUI.finishDraggingTo(location);
517+ }
518+
519+
520+ /**
521+ * MouseHandler is responsible for converting mouse events
522+ * (released, dragged...) into the appropriate DragController
523+ * methods.
524+ * <p>
525+ */
526+ protected class MouseHandler extends MouseAdapter
527+ implements MouseMotionListener
528+ {
529+ /**
530+ * Starts the dragging session by creating the appropriate instance
531+ * of DragController.
532+ */
533+ public void mousePressed(MouseEvent e) {
534+ if ((e.getSource() == BasicSplitPaneDivider.this ||
535+ e.getSource() == splitPane) &&
536+ dragger == null &&splitPane.isEnabled()) {
537+ Component newHiddenDivider = splitPaneUI.
538+ getNonContinuousLayoutDivider();
539+
540+ if (hiddenDivider != newHiddenDivider) {
541+ if (hiddenDivider != null) {
542+ hiddenDivider.removeMouseListener(this);
543+ hiddenDivider.removeMouseMotionListener(this);
544+ }
545+ hiddenDivider = newHiddenDivider;
546+ if (hiddenDivider != null) {
547+ hiddenDivider.addMouseMotionListener(this);
548+ hiddenDivider.addMouseListener(this);
549+ }
550+ }
551+ if (splitPane.getLeftComponent() != null &&
552+ splitPane.getRightComponent() != null) {
553+ if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
554+ dragger = new DragController(e);
555+ }
556+ else {
557+ dragger = new VerticalDragController(e);
558+ }
559+ if (!dragger.isValid()) {
560+ dragger = null;
561+ }
562+ else {
563+ prepareForDragging();
564+ dragger.continueDrag(e);
565+ }
566+ }
567+ e.consume();
568+ }
569+ }
570+
571+
572+ /**
573+ * If dragger is not null it is messaged with completeDrag.
574+ */
575+ public void mouseReleased(MouseEvent e) {
576+ if (dragger != null) {
577+ if (e.getSource() == splitPane) {
578+ dragger.completeDrag(e.getX(), e.getY());
579+ }
580+ else if (e.getSource() == BasicSplitPaneDivider.this) {
581+ Point ourLoc = getLocation();
582+
583+ dragger.completeDrag(e.getX() + ourLoc.x,
584+ e.getY() + ourLoc.y);
585+ }
586+ else if (e.getSource() == hiddenDivider) {
587+ Point hDividerLoc = hiddenDivider.getLocation();
588+ int ourX = e.getX() + hDividerLoc.x;
589+ int ourY = e.getY() + hDividerLoc.y;
590+
591+ dragger.completeDrag(ourX, ourY);
592+ }
593+ dragger = null;
594+ e.consume();
595+ }
596+ }
597+
598+
599+ //
600+ // MouseMotionListener
601+ //
602+
603+ /**
604+ * If dragger is not null it is messaged with continueDrag.
605+ */
606+ public void mouseDragged(MouseEvent e) {
607+ if (dragger != null) {
608+ if (e.getSource() == splitPane) {
609+ dragger.continueDrag(e.getX(), e.getY());
610+ }
611+ else if (e.getSource() == BasicSplitPaneDivider.this) {
612+ Point ourLoc = getLocation();
613+
614+ dragger.continueDrag(e.getX() + ourLoc.x,
615+ e.getY() + ourLoc.y);
616+ }
617+ else if (e.getSource() == hiddenDivider) {
618+ Point hDividerLoc = hiddenDivider.getLocation();
619+ int ourX = e.getX() + hDividerLoc.x;
620+ int ourY = e.getY() + hDividerLoc.y;
621+
622+ dragger.continueDrag(ourX, ourY);
623+ }
624+ e.consume();
625+ }
626+ }
627+
628+
629+ /**
630+ * Resets the cursor based on the orientation.
631+ */
632+ public void mouseMoved(MouseEvent e) {
633+ }
634+
635+ /**
636+ * Invoked when the mouse enters a component.
637+ *
638+ * @param e MouseEvent describing the details of the enter event.
639+ * @since 1.5
640+ */
641+ public void mouseEntered(MouseEvent e) {
642+ if (e.getSource() == BasicSplitPaneDivider.this) {
643+ setMouseOver(true);
644+ }
645+ }
646+
647+ /**
648+ * Invoked when the mouse exits a component.
649+ *
650+ * @param e MouseEvent describing the details of the exit event.
651+ * @since 1.5
652+ */
653+ public void mouseExited(MouseEvent e) {
654+ if (e.getSource() == BasicSplitPaneDivider.this) {
655+ setMouseOver(false);
656+ }
657+ }
658+ }
659+
660+
661+ /**
662+ * Handles the events during a dragging session for a
663+ * HORIZONTAL_SPLIT oriented split pane. This continually
664+ * messages <code>dragDividerTo</code> and then when done messages
665+ * <code>finishDraggingTo</code>. When an instance is created it should be
666+ * messaged with <code>isValid</code> to insure that dragging can happen
667+ * (dragging won't be allowed if the two views can not be resized).
668+ * <p>
669+ * <strong>Warning:</strong>
670+ * Serialized objects of this class will not be compatible with
671+ * future Swing releases. The current serialization support is
672+ * appropriate for short term storage or RMI between applications running
673+ * the same version of Swing. As of 1.4, support for long term storage
674+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
675+ * has been added to the <code>java.beans</code> package.
676+ * Please see {@link java.beans.XMLEncoder}.
677+ */
678+ protected class DragController
679+ {
680+ /**
681+ * Initial location of the divider.
682+ */
683+ int initialX;
684+
685+ /**
686+ * Maximum and minimum positions to drag to.
687+ */
688+ int maxX, minX;
689+
690+ /**
691+ * Initial location the mouse down happened at.
692+ */
693+ int offset;
694+
695+
696+ protected DragController(MouseEvent e) {
697+ JSplitPane splitPane = splitPaneUI.getSplitPane();
698+ Component leftC = splitPane.getLeftComponent();
699+ Component rightC = splitPane.getRightComponent();
700+
701+ initialX = getLocation().x;
702+ if (e.getSource() == BasicSplitPaneDivider.this) {
703+ offset = e.getX();
704+ }
705+ else { // splitPane
706+ offset = e.getX() - initialX;
707+ }
708+ if (leftC == null || rightC == null || offset < -1 ||
709+ offset >= getSize().width) {
710+ // Don't allow dragging.
711+ maxX = -1;
712+ }
713+ else {
714+ Insets insets = splitPane.getInsets();
715+
716+ if (leftC.isVisible()) {
717+ minX = leftC.getMinimumSize().width;
718+ if (insets != null) {
719+ minX += insets.left;
720+ }
721+ }
722+ else {
723+ minX = 0;
724+ }
725+ if (rightC.isVisible()) {
726+ int right = (insets != null) ? insets.right : 0;
727+ maxX = Math.max(0, splitPane.getSize().width -
728+ (getSize().width + right) -
729+ rightC.getMinimumSize().width);
730+ }
731+ else {
732+ int right = (insets != null) ? insets.right : 0;
733+ maxX = Math.max(0, splitPane.getSize().width -
734+ (getSize().width + right));
735+ }
736+ if (maxX < minX) minX = maxX = 0;
737+ }
738+ }
739+
740+
741+ /**
742+ * Returns true if the dragging session is valid.
743+ */
744+ protected boolean isValid() {
745+ return (maxX > 0);
746+ }
747+
748+
749+ /**
750+ * Returns the new position to put the divider at based on
751+ * the passed in MouseEvent.
752+ */
753+ protected int positionForMouseEvent(MouseEvent e) {
754+ int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
755+ (e.getX() + getLocation().x) : e.getX();
756+
757+ newX = Math.min(maxX, Math.max(minX, newX - offset));
758+ return newX;
759+ }
760+
761+
762+ /**
763+ * Returns the x argument, since this is used for horizontal
764+ * splits.
765+ */
766+ protected int getNeededLocation(int x, int y) {
767+ int newX;
768+
769+ newX = Math.min(maxX, Math.max(minX, x - offset));
770+ return newX;
771+ }
772+
773+
774+ protected void continueDrag(int newX, int newY) {
775+ dragDividerTo(getNeededLocation(newX, newY));
776+ }
777+
778+
779+ /**
780+ * Messages dragDividerTo with the new location for the mouse
781+ * event.
782+ */
783+ protected void continueDrag(MouseEvent e) {
784+ dragDividerTo(positionForMouseEvent(e));
785+ }
786+
787+
788+ protected void completeDrag(int x, int y) {
789+ finishDraggingTo(getNeededLocation(x, y));
790+ }
791+
792+
793+ /**
794+ * Messages finishDraggingTo with the new location for the mouse
795+ * event.
796+ */
797+ protected void completeDrag(MouseEvent e) {
798+ finishDraggingTo(positionForMouseEvent(e));
799+ }
800+ } // End of BasicSplitPaneDivider.DragController
801+
802+
803+ /**
804+ * Handles the events during a dragging session for a
805+ * VERTICAL_SPLIT oriented split pane. This continually
806+ * messages <code>dragDividerTo</code> and then when done messages
807+ * <code>finishDraggingTo</code>. When an instance is created it should be
808+ * messaged with <code>isValid</code> to insure that dragging can happen
809+ * (dragging won't be allowed if the two views can not be resized).
810+ */
811+ protected class VerticalDragController extends DragController
812+ {
813+ /* DragControllers ivars are now in terms of y, not x. */
814+ protected VerticalDragController(MouseEvent e) {
815+ super(e);
816+ JSplitPane splitPane = splitPaneUI.getSplitPane();
817+ Component leftC = splitPane.getLeftComponent();
818+ Component rightC = splitPane.getRightComponent();
819+
820+ initialX = getLocation().y;
821+ if (e.getSource() == BasicSplitPaneDivider.this) {
822+ offset = e.getY();
823+ }
824+ else {
825+ offset = e.getY() - initialX;
826+ }
827+ if (leftC == null || rightC == null || offset < -1 ||
828+ offset > getSize().height) {
829+ // Don't allow dragging.
830+ maxX = -1;
831+ }
832+ else {
833+ Insets insets = splitPane.getInsets();
834+
835+ if (leftC.isVisible()) {
836+ minX = leftC.getMinimumSize().height;
837+ if (insets != null) {
838+ minX += insets.top;
839+ }
840+ }
841+ else {
842+ minX = 0;
843+ }
844+ if (rightC.isVisible()) {
845+ int bottom = (insets != null) ? insets.bottom : 0;
846+
847+ maxX = Math.max(0, splitPane.getSize().height -
848+ (getSize().height + bottom) -
849+ rightC.getMinimumSize().height);
850+ }
851+ else {
852+ int bottom = (insets != null) ? insets.bottom : 0;
853+
854+ maxX = Math.max(0, splitPane.getSize().height -
855+ (getSize().height + bottom));
856+ }
857+ if (maxX < minX) minX = maxX = 0;
858+ }
859+ }
860+
861+
862+ /**
863+ * Returns the y argument, since this is used for vertical
864+ * splits.
865+ */
866+ protected int getNeededLocation(int x, int y) {
867+ int newY;
868+
869+ newY = Math.min(maxX, Math.max(minX, y - offset));
870+ return newY;
871+ }
872+
873+
874+ /**
875+ * Returns the new position to put the divider at based on
876+ * the passed in MouseEvent.
877+ */
878+ protected int positionForMouseEvent(MouseEvent e) {
879+ int newY = (e.getSource() == BasicSplitPaneDivider.this) ?
880+ (e.getY() + getLocation().y) : e.getY();
881+
882+
883+ newY = Math.min(maxX, Math.max(minX, newY - offset));
884+ return newY;
885+ }
886+ } // End of BasicSplitPaneDividier.VerticalDragController
887+
888+
889+ /**
890+ * Used to layout a <code>BasicSplitPaneDivider</code>.
891+ * Layout for the divider
892+ * involves appropriately moving the left/right buttons around.
893+ * <p>
894+ */
895+ protected class DividerLayout implements LayoutManager
896+ {
897+ public void layoutContainer(Container c) {
898+ if (leftButton != null && rightButton != null &&
899+ c == BasicSplitPaneDivider.this) {
900+ if (splitPane.isOneTouchExpandable()) {
901+ Insets insets = getInsets();
902+
903+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
904+ int extraX = (insets != null) ? insets.left : 0;
905+ int blockSize = getHeight();
906+
907+ if (insets != null) {
908+ blockSize -= (insets.top + insets.bottom);
909+ blockSize = Math.max(blockSize, 0);
910+ }
911+ blockSize = Math.min(blockSize, oneTouchSize);
912+
913+ int y = (c.getSize().height - blockSize) / 2;
914+
915+ if (!centerOneTouchButtons) {
916+ y = (insets != null) ? insets.top : 0;
917+ extraX = 0;
918+ }
919+ leftButton.setBounds(extraX + oneTouchOffset, y,
920+ blockSize * 2, blockSize);
921+ rightButton.setBounds(extraX + oneTouchOffset +
922+ oneTouchSize * 2, y,
923+ blockSize * 2, blockSize);
924+ }
925+ else {
926+ int extraY = (insets != null) ? insets.top : 0;
927+ int blockSize = getWidth();
928+
929+ if (insets != null) {
930+ blockSize -= (insets.left + insets.right);
931+ blockSize = Math.max(blockSize, 0);
932+ }
933+ blockSize = Math.min(blockSize, oneTouchSize);
934+
935+ int x = (c.getSize().width - blockSize) / 2;
936+
937+ if (!centerOneTouchButtons) {
938+ x = (insets != null) ? insets.left : 0;
939+ extraY = 0;
940+ }
941+
942+ leftButton.setBounds(x, extraY + oneTouchOffset,
943+ blockSize, blockSize * 2);
944+ rightButton.setBounds(x, extraY + oneTouchOffset +
945+ oneTouchSize * 2, blockSize,
946+ blockSize * 2);
947+ }
948+ }
949+ else {
950+ leftButton.setBounds(-5, -5, 1, 1);
951+ rightButton.setBounds(-5, -5, 1, 1);
952+ }
953+ }
954+ }
955+
956+
957+ public Dimension minimumLayoutSize(Container c) {
958+ // NOTE: This isn't really used, refer to
959+ // BasicSplitPaneDivider.getPreferredSize for the reason.
960+ // I leave it in hopes of having this used at some point.
961+ if (c != BasicSplitPaneDivider.this || splitPane == null) {
962+ return new Dimension(0,0);
963+ }
964+ Dimension buttonMinSize = null;
965+
966+ if (splitPane.isOneTouchExpandable() && leftButton != null) {
967+ buttonMinSize = leftButton.getMinimumSize();
968+ }
969+
970+ Insets insets = getInsets();
971+ int width = getDividerSize();
972+ int height = width;
973+
974+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
975+ if (buttonMinSize != null) {
976+ int size = buttonMinSize.height;
977+ if (insets != null) {
978+ size += insets.top + insets.bottom;
979+ }
980+ height = Math.max(height, size);
981+ }
982+ width = 1;
983+ }
984+ else {
985+ if (buttonMinSize != null) {
986+ int size = buttonMinSize.width;
987+ if (insets != null) {
988+ size += insets.left + insets.right;
989+ }
990+ width = Math.max(width, size);
991+ }
992+ height = 1;
993+ }
994+ return new Dimension(width, height);
995+ }
996+
997+
998+ public Dimension preferredLayoutSize(Container c) {
999+ return minimumLayoutSize(c);
1000+ }
1001+
1002+
1003+ public void removeLayoutComponent(Component c) {}
1004+
1005+ public void addLayoutComponent(String string, Component c) {}
1006+ } // End of class BasicSplitPaneDivider.DividerLayout
1007+
1008+
1009+ /**
1010+ * Listeners installed on the one touch expandable buttons.
1011+ */
1012+ private class OneTouchActionHandler implements ActionListener {
1013+ /** True indicates the resize should go the minimum (top or left)
1014+ * vs false which indicates the resize should go to the maximum.
1015+ */
1016+ private boolean toMinimum;
1017+
1018+ OneTouchActionHandler(boolean toMinimum) {
1019+ this.toMinimum = toMinimum;
1020+ }
1021+
1022+ public void actionPerformed(ActionEvent e) {
1023+ Insets insets = splitPane.getInsets();
1024+ int lastLoc = splitPane.getLastDividerLocation();
1025+ int currentLoc = splitPaneUI.getDividerLocation(splitPane);
1026+ int newLoc;
1027+
1028+ // We use the location from the UI directly, as the location the
1029+ // JSplitPane itself maintains is not necessarly correct.
1030+ if (toMinimum) {
1031+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
1032+ if (currentLoc >= (splitPane.getHeight() -
1033+ insets.bottom - getHeight())) {
1034+ int maxLoc = splitPane.getMaximumDividerLocation();
1035+ newLoc = Math.min(lastLoc, maxLoc);
1036+ splitPaneUI.setKeepHidden(false);
1037+ }
1038+ else {
1039+ newLoc = insets.top;
1040+ splitPaneUI.setKeepHidden(true);
1041+ }
1042+ }
1043+ else {
1044+ if (currentLoc >= (splitPane.getWidth() -
1045+ insets.right - getWidth())) {
1046+ int maxLoc = splitPane.getMaximumDividerLocation();
1047+ newLoc = Math.min(lastLoc, maxLoc);
1048+ splitPaneUI.setKeepHidden(false);
1049+ }
1050+ else {
1051+ newLoc = insets.left;
1052+ splitPaneUI.setKeepHidden(true);
1053+ }
1054+ }
1055+ }
1056+ else {
1057+ if (orientation == JSplitPane.VERTICAL_SPLIT) {
1058+ if (currentLoc == insets.top) {
1059+ int maxLoc = splitPane.getMaximumDividerLocation();
1060+ newLoc = Math.min(lastLoc, maxLoc);
1061+ splitPaneUI.setKeepHidden(false);
1062+ }
1063+ else {
1064+ newLoc = splitPane.getHeight() - getHeight() -
1065+ insets.top;
1066+ splitPaneUI.setKeepHidden(true);
1067+ }
1068+ }
1069+ else {
1070+ if (currentLoc == insets.left) {
1071+ int maxLoc = splitPane.getMaximumDividerLocation();
1072+ newLoc = Math.min(lastLoc, maxLoc);
1073+ splitPaneUI.setKeepHidden(false);
1074+ }
1075+ else {
1076+ newLoc = splitPane.getWidth() - getWidth() -
1077+ insets.left;
1078+ splitPaneUI.setKeepHidden(true);
1079+ }
1080+ }
1081+ }
1082+ if (currentLoc != newLoc) {
1083+ splitPane.setDividerLocation(newLoc);
1084+ // We do this in case the dividers notion of the location
1085+ // differs from the real location.
1086+ splitPane.setLastDividerLocation(currentLoc);
1087+ }
1088+ }
1089+ } // End of class BasicSplitPaneDivider.LeftActionListener
1090+}