KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > awt > SplittedPanel


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.awt;
20
21 import org.openide.util.NbBundle;
22
23 import java.awt.*;
24 import java.awt.event.ActionEvent JavaDoc;
25 import java.awt.event.ActionListener JavaDoc;
26 import java.awt.event.MouseEvent JavaDoc;
27 import java.awt.event.MouseListener JavaDoc;
28 import java.awt.event.MouseMotionListener JavaDoc;
29
30 import java.text.MessageFormat JavaDoc;
31
32 import java.util.Enumeration JavaDoc;
33 import java.util.ResourceBundle JavaDoc;
34 import java.util.Vector JavaDoc;
35 import java.util.logging.Level JavaDoc;
36 import java.util.logging.Logger JavaDoc;
37
38 import javax.accessibility.Accessible JavaDoc;
39 import javax.accessibility.AccessibleContext JavaDoc;
40 import javax.accessibility.AccessibleRole JavaDoc;
41
42 import javax.swing.*;
43 import javax.swing.JComponent.AccessibleJComponent;
44 import javax.swing.border.*;
45
46
47 /** The SplittedPanel widget is a Panel that can contain one or two components and
48 * place them side-by-side vertically or horizontally with a splitter in the middle.
49 * User can move the split point by dragging the splitter with mouse.
50 * The two components are accessed by add/remove methods with constraints value
51 * ADD_SPLITTER, ADD_FIRST, ADD_SECOND, ....
52 * The split position could be either absolute or proportional (according to the
53 * "Absolute" property setting) - in thwe absolute mode the split point remains same
54 * when resizing (i.e. the left/top component keeps its size and only the
55 * right/bottom component resizes), while in the proportional mode the splitPosition
56 * is a percentage of the width/height assigned to the left/top component.
57
58 * <P><TABLE BORDER COLS=3 WIDTH=100%>
59 * <TR><TH WIDTH=15%>Property<TH WIDTH=15%>Property Type<TH>Description
60 * <TR><TD> SplitType <TD> int <TD> The type of the splitting - HORIZONTAL, VERTICAL or NONE
61 * <TR><TD> SplitPosition <TD> int <TD> The position of the split point - either absolute position or number of percents
62 * according to the "Absolute" property settings, could be one of FIRST_PREFERRED or
63 * SECOND_PREFERRED, which means that the split point should be placed so that
64 * the first(left/top) resp. second (bottom/rignt) is sized according to its preferredSize
65 * (in this case the Absolute property setting is ignored)
66 * <TR><TD> SplitterType <TD> int <TD> The type of the component that renders the splitter - DEFAULT_SPLITTER, RAISED_SPLITTER,
67 * EMPTY_SPLITTER.
68 * <TR><TD> SplitterComponent <TD> Component <TD> The component that renders the splitter. A custom component can be provided in addition to EMPTY_SPLITTER and RAISED-SPLITTER using this method.
69 * <TR><TD> SplitAbsolute <TD> boolean <TD> if true then the meaning of the SplitPosition is absolute points,
70 * otherwise the SplitPosition is a number of percents
71 * <TR><TD> SplitDragable <TD> boolean <TD> if true then the split point can be dragged using a mouse,
72 * otherwise the SplitPosition is fixed
73 * <TR><TD> SplitTypeChangeEnabled <TD> boolean<TD> if true then the split type can be changed via popup menu commands
74 * <TR><TD> SwapPanesEnabled <TD> boolean<TD> if true then the panes can be swapped via popup menu command
75 * </TABLE>
76 *
77 * @author Ian Formanek
78 * @deprecated This class does nothing interesting that cannot be done with a JSplitPane.
79 * Use a JSplitPane instead.
80 */

81 public class SplittedPanel extends JComponent implements Accessible JavaDoc {
82     /** generated Serialized Version UID */
83     static final long serialVersionUID = 5058424218525927233L;
84
85     /** constant for no split - only the first (left/top) component will be shown */
86     public final static int NONE = 0;
87
88     /** constant for vertical split */
89     public final static int VERTICAL = 1;
90
91     /** constant for horizontal split */
92     public final static int HORIZONTAL = 2;
93
94     /** constraints constant for adding a splitter */
95     public static final Object JavaDoc ADD_SPLITTER = new Integer JavaDoc(0);
96
97     /** constraints constant for adding a component to the first (left/top) pane */
98     public static final Object JavaDoc ADD_FIRST = new Integer JavaDoc(1);
99
100     /** constraints constant for adding a component to the second (right/bottom) pane */
101     public static final Object JavaDoc ADD_SECOND = new Integer JavaDoc(2);
102
103     /** constraints constant for adding a component to the left(top) pane (an alias for the ADD_FIRST constant) */
104     public static final Object JavaDoc ADD_LEFT = ADD_FIRST;
105
106     /** constraints constant for adding a component to the top(left) pane (an alias for the ADD_FIRST constant) */
107     public static final Object JavaDoc ADD_TOP = ADD_FIRST;
108
109     /** constraints constant for adding a component to the right(bottom) pane (an alias for the ADD_SECOND constant) */
110     public static final Object JavaDoc ADD_RIGHT = ADD_SECOND;
111
112     /** constraints constant for adding a component to the bottom(right) pane (an alias for the ADD_SECOND constant) */
113     public static final Object JavaDoc ADD_BOTTOM = ADD_SECOND;
114
115     /** constant for moving the split point so that the first (left/top) component is sized according to its preferredSize */
116     public static final int FIRST_PREFERRED = -1;
117
118     /** constant for moving the split point so that the second (right/bottom) component is sized according to its preferredSize */
119     public static final int SECOND_PREFERRED = -2;
120
121     /** constant for splitter component types - raised splitter*/
122     public static final int RAISED_SPLITTER = 0;
123
124     /** constant for splitter component types - empty splitter */
125     public static final int EMPTY_SPLITTER = 1;
126
127     /** constant for splitter component types - default splitter (raised)*/
128     public static final int DEFAULT_SPLITTER = RAISED_SPLITTER;
129     private static MessageFormat JavaDoc nameFormat = null;
130     private static MessageFormat JavaDoc descriptionFormat = null;
131
132     /** The default split type */
133     private final static int DEFAULT_SPLIT_TYPE = HORIZONTAL;
134
135     /** Save the last preferred setting (first or second). Double click reset the splitPosition to this value */
136     private int resetPosition = FIRST_PREFERRED;
137
138     /** Is popup menu enabled?*/
139     private Boolean JavaDoc popupMenuEnabled;
140     private boolean drawBumps;
141
142     ///////////////////////
143
// Private variables //
144
///////////////////////
145

146     /** the first (left/top) component */
147     private Component firstComponent = null;
148
149     /** the second (right/bottom) component */
150     private Component secondComponent = null;
151
152     /** the splitter component */
153     private Component splitter = null;
154
155     /** the splitter component type */
156     private int splitterType = DEFAULT_SPLITTER;
157
158     /** the mouse adapter that does the dragging of the splitter*/
159     private transient MouseListenerAdapter mouseAdapter;
160
161     /** current split type */
162     private int splitType = NONE;
163
164     /** current split position */
165     private int splitPosition = 50;
166     private boolean absolute = false;
167     private boolean dragable = true;
168     private boolean continuousLayout = true;
169
170     /** current enabled/disabled state of change of split type */
171     private boolean splitTypeChangeEnabled = true;
172
173     /** current enabled/disabled state of change of swapping panes */
174     private boolean swapPanesEnabled = true;
175
176     /** current keepSecondSame state - this has bigger priority than keepFirstSame */
177     private boolean keepSecondSame = false;
178
179     /** current keepFirstSame state */
180     private boolean keepFirstSame = false;
181     transient private boolean splitIsChanging = false;
182     private int dragPos = -1;
183
184     /** true if the panes were swapped, false otherwise */
185     private boolean panesSwapped = false;
186
187     /** popup menu for setting vertical/horizontal splitting */
188     transient private JPopupMenu popupMenu;
189
190     /** The popup menu item */
191     transient private JRadioButtonMenuItem verticalCMI;
192
193     /** The popup menu item */
194     transient private JRadioButtonMenuItem horizontalCMI;
195
196     /** The popup menu item */
197     transient private JMenuItem swapCMI;
198
199     /** The popup menu item */
200     transient private JMenuItem splitterCMI;
201
202     /** A Vector of SplitChangeListeners */
203     transient private Vector JavaDoc<SplitChangeListener> listeners;
204
205     /** Accessible context */
206     private AccessibleContext JavaDoc accessibleContext;
207
208     /** Constructs a new empty SplittedPanel with no spliting.
209     */

210     public SplittedPanel() {
211         splitter = new DefaultSplitter(getDefaultSplitterSize());
212         accessibleContext = null;
213         setLayout(new SplitLayout());
214         add(splitter, ADD_SPLITTER);
215         init();
216
217         RuntimeException JavaDoc rte = new RuntimeException JavaDoc("SplittedPanel is deprecated. Please use JSplitPane instead"); //NOI18N
218
Logger.getLogger(SplittedPanel.class.getName()).log(Level.WARNING, null, rte);
219     }
220
221     /** Initializes the SplittedPanel */
222     private void init() {
223         setSplitterCursor();
224         mouseAdapter = new MouseListenerAdapter();
225
226         if (dragable) {
227             splitter.addMouseMotionListener(mouseAdapter);
228             splitter.addMouseListener(mouseAdapter);
229             addSplitChangeListener(mouseAdapter);
230         }
231
232         initAccessible();
233     }
234
235     /** Updates splitting, too. */
236     public void updateUI() {
237         super.updateUI();
238         updateSplitting();
239
240         Object JavaDoc o = UIManager.get("nb.SplittedPanel.drawBumps");
241         drawBumps = Boolean.TRUE.equals(o);
242     }
243
244     /** Updates the visual state and layout when the split state changes. */
245     protected void updateSplitting() {
246         if ((firstComponent != null) && (secondComponent != null)) {
247             invalidate();
248             firstComponent.invalidate();
249             splitter.invalidate();
250             secondComponent.invalidate();
251             validate();
252         }
253     }
254
255     /** Computes component sizes after performing the flip,
256     * it means splitTypeChange */

257     protected void computeSizesAfterFlip() {
258         if ((firstComponent == null) || (secondComponent == null)) {
259             return;
260         }
261
262         Dimension ourSize = getSize();
263         int splitterSize;
264
265         switch (splitType) {
266         case VERTICAL:
267
268             if (ourSize.width == 0) {
269                 break;
270             }
271
272             splitterSize = splitter.getPreferredSize().height;
273
274             int newHeight = ((ourSize.height - splitterSize) * firstComponent.getSize().width) / ourSize.width;
275             firstComponent.setSize(new Dimension(ourSize.width, newHeight));
276             secondComponent.setSize(new Dimension(ourSize.width, ourSize.height - newHeight - splitterSize));
277
278             break;
279
280         case HORIZONTAL:
281
282             if (ourSize.height == 0) {
283                 break;
284             }
285
286             splitterSize = splitter.getPreferredSize().width;
287
288             int newWidth = ((ourSize.width - splitterSize) * firstComponent.getSize().height) / ourSize.height;
289             firstComponent.setSize(new Dimension(newWidth, ourSize.height));
290             secondComponent.setSize(new Dimension(ourSize.width - newWidth - splitterSize, ourSize.height));
291
292             break;
293         }
294     }
295
296     /** Updates the splitter's cursor according to the current SplittedPanel settings. */
297     protected void setSplitterCursor() {
298         if (dragable) {
299             if (splitType == VERTICAL) {
300                 splitter.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
301             } else {
302                 splitter.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
303             }
304         } else {
305             splitter.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
306         }
307     }
308
309     /** Is popup menu on spliter enabled? See issue 25216.*/
310     private boolean isPopupMenuEnabled() {
311         if (popupMenuEnabled == null) {
312             Object JavaDoc o = getClientProperty("popupMenuEnabled");
313
314             if (o instanceof Boolean JavaDoc) {
315                 popupMenuEnabled = (Boolean JavaDoc) o;
316             } else {
317                 popupMenuEnabled = Boolean.TRUE;
318             }
319         }
320
321         return popupMenuEnabled.booleanValue();
322     }
323
324     /** Updates the splitter's popup menu. */
325     protected void updatePopupMenu() {
326         if (popupMenu == null) {
327             popupMenu = new JPopupMenu();
328
329             java.util.ResourceBundle JavaDoc awtBundle = NbBundle.getBundle(SplittedPanel.class);
330
331             popupMenu.add(verticalCMI = new JRadioButtonMenuItem(awtBundle.getString("SplittedPanelVertical")));
332             popupMenu.add(horizontalCMI = new JRadioButtonMenuItem(awtBundle.getString("SplittedPanelHorizontal")));
333             popupMenu.add(new JSeparator());
334             popupMenu.add(swapCMI = new JMenuItem(awtBundle.getString("SplittedPanelSwap")));
335             popupMenu.add(new JSeparator());
336             popupMenu.add(splitterCMI = new JMenuItem(awtBundle.getString("ResetSplitter")));
337
338             ActionListener JavaDoc al = new ActionListener JavaDoc() {
339                     public void actionPerformed(ActionEvent JavaDoc e) {
340                         if (horizontalCMI.equals(e.getSource())) {
341                             setSplitType(HORIZONTAL);
342                         } else {
343                             setSplitType(VERTICAL);
344                         }
345                     }
346                 };
347
348             verticalCMI.addActionListener(al);
349             horizontalCMI.addActionListener(al);
350             swapCMI.addActionListener(
351                 new ActionListener JavaDoc() {
352                     public void actionPerformed(ActionEvent JavaDoc e) {
353                         swapPanes();
354                     }
355                 }
356             );
357             splitterCMI.addActionListener(
358                 new ActionListener JavaDoc() {
359                     public void actionPerformed(ActionEvent JavaDoc e) {
360                         resetSplitter();
361                     }
362                 }
363             );
364         }
365
366         if (splitType == VERTICAL) {
367             verticalCMI.setSelected(true);
368             horizontalCMI.setSelected(false);
369         } else {
370             verticalCMI.setSelected(false);
371             horizontalCMI.setSelected(true);
372         }
373
374         if (splitTypeChangeEnabled) {
375             verticalCMI.setEnabled(true);
376             horizontalCMI.setEnabled(true);
377         } else {
378             verticalCMI.setEnabled(false);
379             horizontalCMI.setEnabled(false);
380         }
381
382         if (swapPanesEnabled) {
383             swapCMI.setEnabled(true);
384         } else {
385             swapCMI.setEnabled(false);
386         }
387
388         splitterCMI.setEnabled((getSplitPosition() != FIRST_PREFERRED) && (getSplitPosition() != SECOND_PREFERRED));
389     }
390
391     /** Reset split line to follow the largest name. */
392     private void resetSplitter() {
393         if ((getSplitPosition() != FIRST_PREFERRED) && (getSplitPosition() != SECOND_PREFERRED)) {
394             setSplitPosition(resetPosition);
395
396             if (splitterCMI != null) {
397                 splitterCMI.setEnabled(false);
398             }
399         }
400     }
401
402     /** Swaps the panes.*/
403     public void swapPanes() {
404         if (!swapPanesEnabled) {
405             return;
406         }
407
408         if ((firstComponent == null) || (secondComponent == null)) {
409             return;
410         }
411
412         splitIsChanging = true;
413         panesSwapped = !panesSwapped;
414
415         if (keepSecondSame) {
416             keepSecondSame = false;
417             keepFirstSame = true;
418         } else if (keepFirstSame) {
419             keepSecondSame = true;
420             keepFirstSame = false;
421         }
422
423         Component aFirstComponent = firstComponent;
424         Component aSecondComponent = secondComponent;
425
426         remove(aFirstComponent);
427         remove(aSecondComponent);
428         add(aSecondComponent, ADD_FIRST);
429         add(aFirstComponent, ADD_SECOND);
430         updateSplitting();
431         splitIsChanging = false;
432     }
433
434     /** @return true if the panes are swapped, false otherwise */
435     public boolean getPanesSwapped() {
436         return panesSwapped;
437     }
438
439     ///////////////////////////////
440
// Property accessor methods //
441
///////////////////////////////
442

443     /** Getter method for the SplitType property.
444     * @return Current SplitType value.
445     */

446     public int getSplitType() {
447         return splitType;
448     }
449
450     /** Setter method for the SplitType property.
451     * @param value New SplitType value.
452     */

453     public void setSplitType(int value) {
454         if (splitType == value) {
455             return;
456         }
457
458         int oldSplitType = splitType;
459         splitType = value;
460
461         if ((oldSplitType != NONE) && (splitType != NONE)) {
462             computeSizesAfterFlip();
463         }
464
465         setSplitterCursor();
466         updateSplitting();
467         updatePopupMenu();
468
469         initAccessible();
470     }
471
472     /** Getter method for the SplitPosition property.
473     * @return Current SplitPosition value.
474     */

475     public int getSplitPosition() {
476         return splitPosition;
477     }
478
479     /** Setter method for the SplitPosition property.
480     * @param value New SplitPosition value.
481     */

482     public void setSplitPosition(int value) {
483         if (splitPosition == value) {
484             return;
485         }
486
487         int oldValue = splitPosition;
488         splitPosition = value;
489         splitIsChanging = true;
490         updateSplitting();
491         fireSplitChange(oldValue, splitPosition);
492         splitIsChanging = false;
493     }
494
495     /** Getter method for the SplitterType property.
496     * @return Current SplitterType value.
497     * @see #EMPTY_SPLITTER
498     * @see #RAISED_SPLITTER
499     * @see #DEFAULT_SPLITTER
500     */

501     public int getSplitterType() {
502         return splitterType;
503     }
504
505     private int getDefaultSplitterSize() {
506         Object JavaDoc o = UIManager.get("nb.SplittedPanel.dividerSize"); //NOI18N
507

508         if (o != null) {
509             return ((Integer JavaDoc) o).intValue();
510         }
511
512         o = UIManager.get("SplitPane.dividerSize"); //NOI18N
513

514         if (o != null) {
515             return ((Integer JavaDoc) o).intValue();
516         }
517
518         return 6;
519     }
520
521     /** Setter method for the SplitterType property.
522     * @param type New SplitterType value.
523     * @see #EMPTY_SPLITTER
524     * @see #RAISED_SPLITTER
525     * @see #DEFAULT_SPLITTER
526     */

527     public void setSplitterType(int type) {
528         if (splitterType == type) {
529             return;
530         }
531
532         splitterType = type;
533
534         switch (splitterType) {
535         case EMPTY_SPLITTER:
536             splitter = new EmptySplitter();
537
538             break;
539
540         default:
541         case RAISED_SPLITTER:
542             splitter = new DefaultSplitter(getDefaultSplitterSize());
543
544             break;
545         }
546
547         add(splitter, ADD_SPLITTER);
548         updateSplitting();
549     }
550
551     /** Getter method for the SplitterComponent property.
552     * @return Current SplitterComponent value.
553     * @see #getSplitterType
554     */

555     public Component getSplitterComponent() {
556         return splitter;
557     }
558
559     /** Setter method for the SplitterComponent property.
560     * @param comp New SplitterComponent value.
561     * @see #setSplitterType
562     */

563     public void setSplitterComponent(Component comp) {
564         if (splitter == comp) {
565             return;
566         }
567
568         if (dragable) {
569             splitter.removeMouseMotionListener(mouseAdapter);
570             splitter.removeMouseListener(mouseAdapter);
571         }
572
573         remove(splitter);
574         splitter = comp;
575         add(splitter, ADD_SPLITTER);
576
577         if (dragable) {
578             splitter.addMouseMotionListener(mouseAdapter);
579             splitter.addMouseListener(mouseAdapter);
580         }
581
582         setSplitterCursor();
583         updateSplitting();
584     }
585
586     /** Getter method for the SplitAbsolute property.
587     * @return Current SplitAbsolute value.
588     */

589     public boolean isSplitAbsolute() {
590         return absolute;
591     }
592
593     /** Setter method for the SplitAbsolute property.
594     * @param value New SplitAbsolute value.
595     */

596     public void setSplitAbsolute(boolean value) {
597         if (absolute == value) {
598             return;
599         }
600
601         absolute = value;
602         updateSplitting();
603     }
604
605     /** Getter method for the SplitDragable property.
606     * @return Current SplitDragable value.
607     */

608     public boolean isSplitDragable() {
609         return dragable;
610     }
611
612     /** Setter method for the Dragable property.
613     * @param value New Dragable value.
614     */

615     public void setSplitDragable(boolean value) {
616         if (dragable == value) {
617             return;
618         }
619
620         dragable = value;
621
622         if (dragable) {
623             splitter.addMouseMotionListener(mouseAdapter);
624             splitter.addMouseListener(mouseAdapter);
625         } else {
626             splitter.removeMouseMotionListener(mouseAdapter);
627             splitter.removeMouseListener(mouseAdapter);
628         }
629
630         setSplitterCursor();
631     }
632
633     /** Getter method for the ContinuousLayout property.
634     * @return Current ContinuousLayout value.
635     */

636     public boolean isContinuousLayout() {
637         return continuousLayout;
638     }
639
640     /** Setter method for the ContinuousLayout property.
641     * @param value New ContinuousLayout value.
642     */

643     public void setContinuousLayout(boolean value) {
644         continuousLayout = value;
645     }
646
647     /** Getter method for the KeepFirstSame property.
648     * @return Current KeepFirstSame value.
649     */

650     public boolean getKeepFirstSame() {
651         return keepFirstSame;
652     }
653
654     /** Setter method for the KeepFirstSame property.
655     * @param value New KeepFirstSame value.
656     */

657     public void setKeepFirstSame(boolean value) {
658         keepFirstSame = value;
659     }
660
661     /** Getter method for the KeepSecondSame property.
662     * @return Current KeepSecondSame value.
663     */

664     public boolean getKeepSecondSame() {
665         return keepSecondSame;
666     }
667
668     /** Setter method for the KeepSecondSame property.
669     * @param value New KeepSecondSame value.
670     */

671     public void setKeepSecondSame(boolean value) {
672         keepSecondSame = value;
673     }
674
675     /** Getter method for the SplitTypeChangeEnabled property.
676     * @return Current SplitTypeChangeEnabled value.
677     */

678     public boolean isSplitTypeChangeEnabled() {
679         return splitTypeChangeEnabled;
680     }
681
682     /** Setter method for the SplitTypeChangeEnabled property.
683     * @param value New SplitTypeChangeEnabled value.
684     */

685     public void setSplitTypeChangeEnabled(boolean value) {
686         if (splitTypeChangeEnabled == value) {
687             return;
688         }
689
690         splitTypeChangeEnabled = value;
691         updatePopupMenu();
692     }
693
694     /** Getter method for the SwapPanesEnabled property.
695     * @return Current SwapPanesEnabled value.
696     */

697     public boolean isSwapPanesEnabled() {
698         return swapPanesEnabled;
699     }
700
701     /** Setter method for the SwapPanesEnabled property.
702     * @param value New SwapPanesEnabled value.
703     */

704     public void setSwapPanesEnabled(boolean value) {
705         if (swapPanesEnabled == value) {
706             return;
707         }
708
709         swapPanesEnabled = value;
710         updatePopupMenu();
711     }
712
713     /////////////////////
714
// Event Listeners //
715
/////////////////////
716

717     /** Adds specified listener to the current set of SplitChangeListeners */
718     public void addSplitChangeListener(SplitChangeListener l) {
719         if (listeners == null) {
720             listeners = new Vector JavaDoc<SplitChangeListener>();
721         }
722
723         listeners.addElement(l);
724     }
725
726     /** Removes specified listener from the current set of SplitChangeListeners */
727     public void removeSplitChangeListener(SplitChangeListener l) {
728         if (listeners == null) {
729             return;
730         }
731
732         listeners.removeElement(l);
733     }
734
735     /** Fires the SplitChange event */
736     protected void fireSplitChange(int oldValue, int newValue) {
737         if (listeners == null) {
738             return;
739         }
740
741         Vector JavaDoc<SplitChangeListener> l;
742
743         synchronized (this) {
744             l = (Vector JavaDoc<SplitChangeListener>) listeners.clone();
745         }
746
747         Enumeration JavaDoc en = l.elements();
748         SplitChangeEvent evt = new SplitChangeEvent(this, oldValue, newValue);
749
750         while (en.hasMoreElements()) {
751             SplitChangeListener scl = (SplitChangeListener) en.nextElement();
752             scl.splitChanged(evt);
753         }
754     }
755
756     /* Read accessible context
757      * @return - accessible context
758      */

759     public AccessibleContext JavaDoc getAccessibleContext() {
760         if (accessibleContext == null) {
761             accessibleContext = new AccessibleJComponent() {
762                         public AccessibleRole JavaDoc getAccessibleRole() {
763                             return AccessibleRole.SPLIT_PANE;
764                         }
765                     };
766             initAccessible();
767         }
768
769         return accessibleContext;
770     }
771
772     private void initAccessible() {
773         if (nameFormat == null) {
774             ResourceBundle JavaDoc bundle = NbBundle.getBundle(SplittedPanel.class);
775             nameFormat = new MessageFormat JavaDoc(bundle.getString("ACS_SplittedPanel_Name"));
776         }
777
778         getAccessibleContext().setAccessibleName(
779             nameFormat.format(
780                 new Object JavaDoc[] {
781                     ((firstComponent == null) || !(firstComponent instanceof Accessible JavaDoc)) ? null
782                                                                                           : firstComponent.getAccessibleContext()
783                                                                                                           .getAccessibleName(),
784                     ((secondComponent == null) || !(secondComponent instanceof Accessible JavaDoc)) ? null
785                                                                                             : secondComponent.getAccessibleContext()
786                                                                                                              .getAccessibleName()
787                 }
788             )
789         );
790
791         if (descriptionFormat == null) {
792             ResourceBundle JavaDoc bundle = NbBundle.getBundle(SplittedPanel.class);
793             descriptionFormat = new MessageFormat JavaDoc(bundle.getString("ACS_SplittedPanel_Description"));
794         }
795
796         getAccessibleContext().setAccessibleDescription(
797             descriptionFormat.format(
798                 new Object JavaDoc[] {
799                     ((firstComponent == null) || !(firstComponent instanceof Accessible JavaDoc)) ? null
800                                                                                           : firstComponent.getAccessibleContext()
801                                                                                                           .getAccessibleDescription(),
802                     ((secondComponent == null) || !(secondComponent instanceof Accessible JavaDoc)) ? null
803                                                                                             : secondComponent.getAccessibleContext()
804                                                                                                              .getAccessibleDescription()
805                 }
806             )
807         );
808     }
809
810     /** Deserializes the component and initializes it. */
811     private void readObject(java.io.ObjectInputStream JavaDoc ois)
812     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
813         ois.defaultReadObject();
814         init();
815     }
816
817     ///////////////////
818
// Inner Classes //
819
///////////////////
820

821     /** A listener interface for tracking split point changes */
822     public static interface SplitChangeListener {
823         /** Called when a split point changes
824         * @param evt The SplitChangeEvent that describes the change
825         */

826         public void splitChanged(SplitChangeEvent evt);
827     }
828
829     /** An event that describes a split point change
830       * @deprecated This class does nothing interesting that cannot be done with a JSplitPane.
831       * Use a JSplitPane instead.
832      */

833     public static class SplitChangeEvent extends java.util.EventObject JavaDoc {
834         /** generated Serialized Version UID */
835         static final long serialVersionUID = 6748966611210836878L;
836         private int oldValue;
837         private int newValue;
838
839         /** Constructs a new SplitChangeEvent for specified source SplittedPanel and
840         * old and new SplitPositions
841         */

842         public SplitChangeEvent(SplittedPanel splittedPanel, int oldValue, int newValue) {
843             super(splittedPanel);
844             this.oldValue = oldValue;
845             this.newValue = newValue;
846         }
847
848         /** @return the old splitterPosition */
849         public int getOldValue() {
850             return oldValue;
851         }
852
853         /** @return the new splitterPosition */
854         public int getNewValue() {
855             return newValue;
856         }
857     }
858
859     /** The EmptySplitter is an empty splitter component with specified width.
860      * It can be used as the splitter via setSplitterComponent.
861      * @deprecated This class does nothing interesting that cannot be done with a JSplitPane.
862      * Use a JSplitPane instead.
863     */

864     public static class EmptySplitter extends JComponent implements Accessible JavaDoc {
865         /** generated Serialized Version UID */
866         static final long serialVersionUID = 929648193440460693L;
867         private int width;
868         private AccessibleContext JavaDoc accessibleContext;
869
870         public EmptySplitter() {
871             this(0);
872         }
873
874         public EmptySplitter(int width) {
875             ResourceBundle JavaDoc bundle = NbBundle.getBundle(SplittedPanel.class);
876
877             accessibleContext = null;
878             this.width = width;
879
880             getAccessibleContext().setAccessibleName(bundle.getString("ACS_SplittedPanel_EmptySplitter"));
881             getAccessibleContext().setAccessibleName(bundle.getString("ACSD_SplittedPanel_EmptySplitter"));
882         }
883
884         public Dimension getPreferredSize() {
885             return new Dimension(width, width);
886         }
887
888         public AccessibleContext JavaDoc getAccessibleContext() {
889             if (accessibleContext == null) {
890                 accessibleContext = new AccessibleJComponent() {
891                             public AccessibleRole JavaDoc getAccessibleRole() {
892                                 return AccessibleRole.SPLIT_PANE;
893                             }
894                         };
895             }
896
897             return accessibleContext;
898         }
899     }
900
901     /** The DefaultSplitter class implements a splitting line that is to be used as a default splitter for the SplittedPanel.
902     * It paints a raised 3D-line with given width.
903     */

904     class DefaultSplitter extends JComponent implements Accessible JavaDoc {
905         static final long serialVersionUID = -4223135481223014719L;
906         private int splitterSize;
907
908         /**
909         * Constructs a new DefaultSplitter with given width.
910         * @param aWidth the desired width of the splitting line, if the value is lower than 2, the width of 2 is used
911         */

912         public DefaultSplitter(int aSplitterSize) {
913             splitterSize = aSplitterSize;
914
915             if (splitterSize < 2) {
916                 splitterSize = 2;
917             }
918         }
919
920         public Dimension getPreferredSize() {
921             return new Dimension(splitterSize, splitterSize);
922         }
923
924         public void paint(Graphics g) {
925             super.paint(g);
926
927             if (splitterSize <= 2) {
928                 return;
929             }
930
931             Dimension size = this.getSize();
932             int height = size.height - 1;
933             g.setColor(this.getBackground());
934
935             Color high = UIManager.getColor("controlLtHighlight");
936
937             //Color bg=UIManager.getColor("control");
938
Color low = UIManager.getColor("controlDkShadow");
939
940             boolean isMetal = UIManager.getLookAndFeel().getClass() == javax.swing.plaf.metal.MetalLookAndFeel JavaDoc.class;
941
942             boolean firstHasBorder = true;
943             boolean secondHasBorder = true;
944
945             if (firstComponent instanceof JComponent) {
946                 Border b1 = ((JComponent) firstComponent).getBorder();
947                 firstHasBorder = (b1 != null) && (!(b1 instanceof EmptyBorder));
948             }
949
950             if (secondComponent instanceof JComponent) {
951                 Border b2 = ((JComponent) secondComponent).getBorder();
952                 secondHasBorder = (b2 != null) && (!(b2 instanceof EmptyBorder));
953             }
954
955             if (panesSwapped) {
956                 boolean b = firstHasBorder;
957                 firstHasBorder = secondHasBorder;
958                 secondHasBorder = b;
959             }
960
961             //draw the bumps
962
if (isMetal && (splitterSize > 3) && drawBumps) {
963                 //looks backwards, but isn't - splitType==vertical gives you a
964
//horizontal splitter
965
int starty = (firstHasBorder && (splitType == VERTICAL)) ? 0 : 2;
966                 int startx = (firstHasBorder && (splitType == HORIZONTAL)) ? 0 : 2;
967
968                 for (int x = startx; (x + 1) < size.width; x += 4) {
969                     for (int y = starty; (y + 1) < height; y += 4) {
970                         g.setColor(this.getBackground().brighter());
971                         g.drawLine(x, y, x, y);
972
973                         if ((x < size.width) && (y < height)) {
974                             g.drawLine(x + 2, y + 2, x + 2, y + 2);
975                         }
976
977                         g.setColor(this.getBackground().darker().darker());
978                         g.drawLine(x + 1, y + 1, x + 1, y + 1);
979
980                         if ((x < size.width) && (y < height)) {
981                             g.drawLine(x + 3, y + 3, x + 3, y + 3);
982                         }
983                     }
984                 }
985             }
986
987             if (splitType == HORIZONTAL) {
988                 int pos = (size.width - splitterSize) / 2;
989
990                 if (!firstHasBorder) {
991                     g.setColor(isMetal ? low : high);
992                     g.drawLine(pos, 0, pos, size.height - 1);
993
994                     if (isMetal) {
995                         g.setColor(high);
996                         g.drawLine(pos + 1, 0, pos + 1, size.height - 1);
997                     }
998                 }
999
1000                if (!secondHasBorder) {
1001                    g.setColor(isMetal ? high : low);
1002                    g.drawLine((pos + splitterSize) - 1, 0, (pos + splitterSize) - 1, size.height - 1);
1003
1004                    if (isMetal) {
1005                        g.setColor(low);
1006                        g.drawLine((pos + splitterSize) - 2, 0, (pos + splitterSize) - 2, size.height - 1);
1007                    }
1008                }
1009            } else if (splitType == VERTICAL) {
1010                int pos = (size.height - splitterSize) / 2;
1011
1012                if (!firstHasBorder) {
1013                    g.setColor(isMetal ? low : high);
1014                    g.drawLine(0, pos, size.width - 1, pos);
1015
1016                    if (isMetal) {
1017                        g.setColor(high);
1018                        g.drawLine(0, pos + 1, size.width - 1, pos + 1);
1019                    }
1020                }
1021
1022                if (!secondHasBorder) {
1023                    g.setColor(isMetal ? high : low);
1024                    g.drawLine(0, (pos + splitterSize) - 1, size.width - 1, (pos + splitterSize) - 1);
1025
1026                    if (isMetal) {
1027                        g.setColor(low);
1028                        g.drawLine(0, (pos + splitterSize) - 2, size.width - 1, (pos + splitterSize) - 2);
1029                    }
1030                }
1031            }
1032        }
1033
1034        public AccessibleContext JavaDoc getAccessibleContext() {
1035            return SplittedPanel.this.getAccessibleContext();
1036        }
1037    }
1038
1039    /**
1040    * The MouseListenerAdapter class implements the dragging behaviour of the splitter.
1041    */

1042    class MouseListenerAdapter extends MouseUtils.PopupMouseAdapter implements MouseListener JavaDoc, MouseMotionListener JavaDoc,
1043        SplitChangeListener {
1044        /** Called when the sequnce of mouse events should lead to actual
1045         * showing of the popup menu.
1046         * Should be redefined to show the menu.
1047         * param evt The mouse release event - should be used to obtain the
1048         * position of the popup menu
1049         */

1050        protected void showPopup(MouseEvent JavaDoc e) {
1051            updatePopupMenu();
1052
1053            if (isPopupMenuEnabled()) {
1054                popupMenu.show(splitter, e.getX(), e.getY());
1055            }
1056        }
1057
1058        /** A method implemented from the MouseListener interface to handle the splitter dragging */
1059        public void mouseReleased(MouseEvent JavaDoc e) {
1060            super.mouseReleased(e);
1061
1062            if (continuousLayout == false) {
1063                if (dragPos == -1) {
1064                    return;
1065                }
1066
1067                if (!absolute) {
1068                    Dimension d = getSize();
1069
1070                    if (splitType == VERTICAL) {
1071                        dragPos = (100 * dragPos) / d.height;
1072                    } else {
1073                        dragPos = (100 * dragPos) / d.width;
1074                    }
1075                }
1076
1077                setSplitPosition(dragPos);
1078                dragPos = -1;
1079            }
1080        }
1081
1082        /** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
1083        public void mouseDragged(MouseEvent JavaDoc e) {
1084            if (continuousLayout == true) {
1085                Dimension d = getSize();
1086                Point splitterPos = splitter.getLocation();
1087                e.translatePoint(splitterPos.x, splitterPos.y);
1088
1089                if (splitType == VERTICAL) {
1090                    dragPos = e.getY();
1091
1092                    if (dragPos > d.height) {
1093                        dragPos = d.height;
1094                    }
1095                } else {
1096                    dragPos = e.getX();
1097
1098                    if (dragPos > d.width) {
1099                        dragPos = d.width;
1100                    }
1101                }
1102
1103                if (dragPos < 0) {
1104                    dragPos = 0;
1105                }
1106
1107                if (continuousLayout) {
1108                    if (dragPos == -1) {
1109                        return;
1110                    }
1111
1112                    int newDragPos = dragPos;
1113
1114                    if (!absolute) {
1115                        if (splitType == VERTICAL) {
1116                            newDragPos = (100 * dragPos) / d.height;
1117                        } else {
1118                            newDragPos = (100 * dragPos) / d.width;
1119                        }
1120                    }
1121
1122                    setSplitPosition(newDragPos);
1123                }
1124            }
1125        }
1126
1127        /** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
1128        public void mouseMoved(MouseEvent JavaDoc e) {
1129        }
1130
1131        /* Double click on the splitter re-sets the splitter to follow one of the fields */
1132        public void mouseClicked(MouseEvent JavaDoc e) {
1133            super.mouseClicked(e);
1134
1135            if ((e.getClickCount() == 2) && isPopupMenuEnabled()) {
1136                resetSplitter();
1137            }
1138        }
1139
1140        public void splitChanged(SplitChangeEvent evt) {
1141            if ((evt.getNewValue() == FIRST_PREFERRED) || (evt.getNewValue() == SECOND_PREFERRED)) {
1142                resetPosition = evt.getNewValue();
1143
1144                if (splitterCMI != null) {
1145                    splitterCMI.setEnabled(true);
1146                }
1147            }
1148        }
1149    }
1150
1151    /**
1152    * The SplitLayout class implements a LayoutManager for the SplittedPanel.
1153    */

1154    class SplitLayout extends Object JavaDoc implements LayoutManager2, java.io.Serializable JavaDoc {
1155        static final long serialVersionUID = 2034500275182524789L;
1156
1157        public void addLayoutComponent(String JavaDoc name, Component comp) {
1158            throw new IllegalArgumentException JavaDoc("You must use the add(Component, Object) method for adding"); // NOI18N
1159
}
1160
1161        public void addLayoutComponent(Component comp, Object JavaDoc constraints) {
1162            if (constraints == ADD_SPLITTER) { // adding a splitter
1163
splitter = comp;
1164            } else if (constraints == ADD_FIRST) { // adding to the left/top
1165

1166                if ((firstComponent != null) && (secondComponent == null)) { // if we altready have ... [PENDING]
1167
secondComponent = firstComponent;
1168                }
1169
1170                firstComponent = comp;
1171
1172                if ((secondComponent != null) && (splitType == NONE)) {
1173                    splitType = DEFAULT_SPLIT_TYPE;
1174                }
1175            } else if (constraints == ADD_SECOND) {
1176                if (firstComponent == null) {
1177                    firstComponent = comp;
1178                } else {
1179                    secondComponent = comp;
1180
1181                    if (splitType == NONE) {
1182                        splitType = DEFAULT_SPLIT_TYPE;
1183                    }
1184                }
1185            } else {
1186                throw new IllegalArgumentException JavaDoc("You must use one of the SplittedPanel.ADD_XXX constraints Objects"); // NOI18N
1187
}
1188
1189            initAccessible();
1190        }
1191
1192        public void removeLayoutComponent(Component comp) {
1193            if (comp.equals(secondComponent)) {
1194                secondComponent = null;
1195            } else if (comp.equals(firstComponent)) {
1196                firstComponent = null;
1197
1198                if (secondComponent != null) {
1199                    firstComponent = secondComponent;
1200                    secondComponent = null;
1201                }
1202            }
1203
1204            initAccessible();
1205        }
1206
1207        public Dimension preferredLayoutSize(Container parent) {
1208            int width = 0;
1209            int height = 0;
1210
1211            if (firstComponent != null) {
1212                Dimension d = firstComponent.getPreferredSize();
1213                width = d.width;
1214                height = d.height;
1215            }
1216
1217            if (secondComponent != null) {
1218                Dimension d = secondComponent.getPreferredSize();
1219
1220                if (splitType == VERTICAL) {
1221                    int splitterSize = splitter.getPreferredSize().height;
1222
1223                    if (width < d.width) {
1224                        width = d.width;
1225                    }
1226
1227                    height += (splitterSize + d.height);
1228                } else {
1229                    int splitterSize = splitter.getPreferredSize().width;
1230
1231                    if (height < d.height) {
1232                        height = d.height;
1233                    }
1234
1235                    width += (splitterSize + d.width);
1236                }
1237            }
1238
1239            return new Dimension(width, height);
1240        }
1241
1242        public Dimension minimumLayoutSize(Container parent) {
1243            int width = 0;
1244            int height = 0;
1245
1246            if (firstComponent != null) {
1247                Dimension d = firstComponent.getMinimumSize();
1248                width = d.width;
1249                height = d.height;
1250            }
1251
1252            if (secondComponent != null) {
1253                Dimension d = secondComponent.getMinimumSize();
1254
1255                if (splitType == VERTICAL) {
1256                    int splitterSize = splitter.getMinimumSize().height;
1257
1258                    if (width < d.width) {
1259                        width = d.width;
1260                    }
1261
1262                    height += (splitterSize + d.height);
1263                } else {
1264                    int splitterSize = splitter.getMinimumSize().width;
1265
1266                    if (height < d.height) {
1267                        height = d.height;
1268                    }
1269
1270                    width += (splitterSize + d.width);
1271                }
1272            }
1273
1274            return new Dimension(width, height);
1275        }
1276
1277        public void layoutContainer(Container parent) {
1278            Dimension d = parent.getSize();
1279            int sPosition = splitPosition;
1280
1281            // 1. first preferred
1282
if (splitPosition == FIRST_PREFERRED) {
1283                if (splitType == VERTICAL) {
1284                    sPosition = firstComponent.getPreferredSize().height;
1285                } else {
1286                    sPosition = firstComponent.getPreferredSize().width;
1287                }
1288
1289                // 2. second preferred
1290
} else if (splitPosition == SECOND_PREFERRED) {
1291                if (splitType == VERTICAL) {
1292                    sPosition = d.height - splitter.getPreferredSize().width -
1293                        secondComponent.getPreferredSize().height;
1294                } else {
1295                    sPosition = d.width - splitter.getPreferredSize().height -
1296                        secondComponent.getPreferredSize().width;
1297                }
1298
1299                // 3. percent position
1300
} else if (!absolute) {
1301                int sp = splitPosition;
1302
1303                if (sp > 100) {
1304                    sp = 100;
1305                }
1306
1307                if (splitType == VERTICAL) {
1308                    sPosition = (d.height * sp) / 100;
1309                } else {
1310                    sPosition = (d.width * sp) / 100;
1311                }
1312            }
1313
1314            if ((splitType != NONE) && (firstComponent != null) && (secondComponent != null)) { // splitted
1315

1316                if (splitType == VERTICAL) {
1317                    int splitterSize = splitter.getPreferredSize().height;
1318
1319                    if ((firstComponent == null) || (secondComponent == null)) {
1320                        splitterSize = 0;
1321                    }
1322
1323                    if (keepSecondSame && !splitIsChanging) {
1324                        Dimension secondSize = secondComponent.getSize();
1325
1326                        if (secondSize.height != 0) {
1327                            sPosition = d.height - secondSize.height - splitterSize;
1328                        }
1329                    }
1330
1331                    if ((sPosition + splitterSize) > d.height) {
1332                        sPosition = d.height - splitterSize;
1333                    }
1334
1335                    if (sPosition < 0) {
1336                        sPosition = 0;
1337                    }
1338
1339                    firstComponent.setBounds(new Rectangle(0, 0, d.width, sPosition));
1340                    splitter.setBounds(new Rectangle(0, sPosition, d.width, splitterSize));
1341                    secondComponent.setBounds(
1342                        new Rectangle(0, sPosition + splitterSize, d.width, d.height - sPosition - splitterSize)
1343                    );
1344                } else {
1345                    int splitterSize = splitter.getPreferredSize().width;
1346
1347                    if ((firstComponent == null) || (secondComponent == null)) {
1348                        splitterSize = 0;
1349                    }
1350
1351                    if (keepSecondSame && !splitIsChanging) {
1352                        Dimension secondSize = secondComponent.getSize();
1353
1354                        if (secondSize.width != 0) {
1355                            sPosition = d.width - secondSize.width - splitterSize;
1356                        }
1357                    }
1358
1359                    if ((sPosition + splitterSize) > d.width) {
1360                        sPosition = d.width - splitterSize;
1361                    }
1362
1363                    if (sPosition < 0) {
1364                        sPosition = 0;
1365                    }
1366
1367                    firstComponent.setBounds(new Rectangle(0, 0, sPosition, d.height));
1368                    splitter.setBounds(new Rectangle(sPosition, 0, splitterSize, d.height));
1369                    secondComponent.setBounds(
1370                        new Rectangle(sPosition + splitterSize, 0, d.width - sPosition - splitterSize, d.height)
1371                    );
1372                }
1373            } else if (firstComponent != null) {
1374                firstComponent.setBounds(new Rectangle(0, 0, d.width - 1, d.height - 1));
1375
1376                if (splitter != null) {
1377                    splitter.setBounds(0, 0, 0, 0);
1378                }
1379            }
1380        }
1381
1382        public Dimension maximumLayoutSize(Container target) {
1383            return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1384        }
1385
1386        public float getLayoutAlignmentX(Container target) {
1387            return 0;
1388        }
1389
1390        public float getLayoutAlignmentY(Container target) {
1391            return 0;
1392        }
1393
1394        public void invalidateLayout(Container target) {
1395        }
1396    }
1397}
1398
Popular Tags