001: package org.wings;
002:
003: import org.wings.plaf.SplitPaneCG;
004:
005: public class SSplitPane extends SContainer implements
006: LowLevelEventListener {
007: /**
008: * Vertical split indicates the <code>SComponent</code>s are
009: * split along the y axis. For example the two
010: * <code>SComponent</code>s will be split one on top of the other.
011: */
012: public final static int VERTICAL_SPLIT = 0;
013:
014: /**
015: * Horizontal split indicates the <code>SComponent</code>s are
016: * split along the x axis. For example the two
017: * <code>SComponent</code>s will be split one to the left of the
018: * other.
019: */
020: public final static int HORIZONTAL_SPLIT = 1;
021:
022: /**
023: * Used to add a <code>SComponent</code> to the left of the other
024: * <code>SComponent</code>.
025: */
026: public final static String LEFT = "left";
027:
028: /**
029: * Used to add a <code>SComponent</code> to the right of the other
030: * <code>SComponent</code>.
031: */
032: public final static String RIGHT = "right";
033:
034: /**
035: * Used to add a <code>SComponent</code> above the other
036: * <code>SComponent</code>.
037: */
038: public final static String TOP = "top";
039:
040: /**
041: * Used to add a <code>SComponent</code> below the other
042: * <code>SComponent</code>.
043: */
044: public final static String BOTTOM = "bottom";
045:
046: /**
047: * Used to add a <code>SComponent</code> that will represent the divider.
048: */
049: public final static String DIVIDER = "divider";
050:
051: /**
052: * How the views are split.
053: */
054: protected int orientation;
055:
056: /**
057: * Whether or not the views are continuously redisplayed while
058: * resizing.
059: */
060: protected boolean continuousLayout;
061:
062: /**
063: * The left or top component.
064: */
065: protected SComponent leftComponent;
066:
067: /**
068: * The right or bottom component.
069: */
070: protected SComponent rightComponent;
071:
072: /**
073: * Size of the divider.
074: */
075: protected int dividerSize = 4;
076:
077: /**
078: * How to distribute extra space.
079: */
080: private double resizeWeight;
081:
082: /**
083: * Location of the divider, at least the value that was set, the UI may
084: * have a different value.
085: */
086: private int dividerLocation;
087: private int newLocation = -1;
088:
089: /**
090: * Creates a new <code>JSplitPane</code> configured to arrange the child
091: * components side-by-side horizontally with no continuous
092: * layout, using two buttons for the components.
093: */
094: public SSplitPane() {
095: this (SSplitPane.HORIZONTAL_SPLIT, false);
096: }
097:
098: /**
099: * Creates a new <code>JSplitPane</code> configured with the
100: * specified orientation and no continuous layout.
101: *
102: * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
103: * <code>JSplitPane.VERTICAL_SPLIT</code>
104: * @exception IllegalArgumentException if <code>orientation</code>
105: * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT.
106: */
107: public SSplitPane(int newOrientation) {
108: this (newOrientation, false);
109: }
110:
111: /**
112: * Creates a new <code>JSplitPane</code> with the specified
113: * orientation and redrawing style.
114: *
115: * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
116: * <code>JSplitPane.VERTICAL_SPLIT</code>
117: * @param newContinuousLayout a boolean, true for the components to
118: * redraw continuously as the divider changes position, false
119: * to wait until the divider position stops changing to redraw
120: * @exception IllegalArgumentException if <code>orientation</code>
121: * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
122: */
123: public SSplitPane(int newOrientation, boolean newContinuousLayout) {
124: this (newOrientation, newContinuousLayout, null, null);
125: }
126:
127: /**
128: * Creates a new <code>JSplitPane</code> with the specified
129: * orientation and
130: * with the specified components that do not do continuous
131: * redrawing.
132: *
133: * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
134: * <code>JSplitPane.VERTICAL_SPLIT</code>
135: * @param newLeftSComponent the <code>SComponent</code> that will
136: * appear on the left
137: * of a horizontally-split pane, or at the top of a
138: * vertically-split pane
139: * @param newRightSComponent the <code>SComponent</code> that will
140: * appear on the right
141: * of a horizontally-split pane, or at the bottom of a
142: * vertically-split pane
143: * @exception IllegalArgumentException if <code>orientation</code>
144: * is not one of: HORIZONTAL_SPLIT or VERTICAL_SPLIT
145: */
146: public SSplitPane(int newOrientation, SComponent newLeftSComponent,
147: SComponent newRightSComponent) {
148: this (newOrientation, false, newLeftSComponent,
149: newRightSComponent);
150: }
151:
152: /**
153: * Creates a new <code>JSplitPane</code> with the specified
154: * orientation and
155: * redrawing style, and with the specified components.
156: *
157: * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
158: * <code>JSplitPane.VERTICAL_SPLIT</code>
159: * @param newContinuousLayout a boolean, true for the components to
160: * redraw continuously as the divider changes position, false
161: * to wait until the divider position stops changing to redraw
162: * @param newLeftSComponent the <code>SComponent</code> that will
163: * appear on the left
164: * of a horizontally-split pane, or at the top of a
165: * vertically-split pane
166: * @param newRightSComponent the <code>SComponent</code> that will
167: * appear on the right
168: * of a horizontally-split pane, or at the bottom of a
169: * vertically-split pane
170: * @exception IllegalArgumentException if <code>orientation</code>
171: * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
172: */
173: public SSplitPane(int newOrientation, boolean newContinuousLayout,
174: SComponent newLeftSComponent, SComponent newRightSComponent) {
175: dividerLocation = -1;
176: setLayout(null);
177:
178: orientation = newOrientation;
179: if (orientation != HORIZONTAL_SPLIT
180: && orientation != VERTICAL_SPLIT)
181: throw new IllegalArgumentException(
182: "cannot create SSplitPane, "
183: + "orientation must be one of "
184: + "JSplitPane.HORIZONTAL_SPLIT "
185: + "or JSplitPane.VERTICAL_SPLIT");
186: continuousLayout = newContinuousLayout;
187: if (newLeftSComponent != null)
188: setLeftComponent(newLeftSComponent);
189: if (newRightSComponent != null)
190: setRightComponent(newRightSComponent);
191:
192: }
193:
194: /**
195: * Sets the size of the divider.
196: *
197: * @param newSize an integer giving the size of the divider in pixels
198: * @beaninfo
199: * bound: true
200: * description: The size of the divider.
201: */
202: public void setDividerSize(int newSize) {
203: int oldSize = dividerSize;
204:
205: if (oldSize != newSize) {
206: dividerSize = newSize;
207: reloadIfChange(oldSize, newSize);
208: }
209: }
210:
211: /**
212: * Returns the size of the divider.
213: *
214: * @return an integer giving the size of the divider in pixels
215: */
216: public int getDividerSize() {
217: return dividerSize;
218: }
219:
220: /**
221: * Sets the component to the left (or above) the divider.
222: *
223: * @param comp the <code>SComponent</code> to display in that position
224: */
225: public void setLeftComponent(SComponent comp) {
226: if (comp == null) {
227: if (leftComponent != null) {
228: remove(leftComponent);
229: leftComponent = null;
230: }
231: } else {
232: add(comp, SSplitPane.LEFT);
233: }
234: }
235:
236: /**
237: * Returns the component to the left (or above) the divider.
238: *
239: * @return the <code>SComponent</code> displayed in that position
240: * @beaninfo
241: * preferred: true
242: * description: The component to the left (or above) the divider.
243: */
244: public SComponent getLeftComponent() {
245: return leftComponent;
246: }
247:
248: /**
249: * Sets the component above, or to the left of the divider.
250: *
251: * @param comp the <code>SComponent</code> to display in that position
252: * @beaninfo
253: * description: The component above, or to the left of the divider.
254: */
255: public void setTopComponent(SComponent comp) {
256: setLeftComponent(comp);
257: }
258:
259: /**
260: * Returns the component above, or to the left of the divider.
261: *
262: * @return the <code>SComponent</code> displayed in that position
263: */
264: public SComponent getTopComponent() {
265: return leftComponent;
266: }
267:
268: /**
269: * Sets the component to the right (or below) the divider.
270: *
271: * @param comp the <code>SComponent</code> to display in that position
272: * @beaninfo
273: * preferred: true
274: * description: The component to the right (or below) the divider.
275: */
276: public void setRightComponent(SComponent comp) {
277: if (comp == null) {
278: if (rightComponent != null) {
279: remove(rightComponent);
280: rightComponent = null;
281: }
282: } else {
283: add(comp, SSplitPane.RIGHT);
284: }
285: }
286:
287: /**
288: * Returns the component to the right (or below) the divider.
289: *
290: * @return the <code>SComponent</code> displayed in that position
291: */
292: public SComponent getRightComponent() {
293: return rightComponent;
294: }
295:
296: /**
297: * Sets the component below, or to the right of the divider.
298: *
299: * @param comp the <code>SComponent</code> to display in that position
300: * @beaninfo
301: * description: The component below, or to the right of the divider.
302: */
303: public void setBottomComponent(SComponent comp) {
304: setRightComponent(comp);
305: }
306:
307: /**
308: * Returns the component below, or to the right of the divider.
309: *
310: * @return the <code>SComponent</code> displayed in that position
311: */
312: public SComponent getBottomComponent() {
313: return rightComponent;
314: }
315:
316: /**
317: * Sets the orientation, or how the splitter is divided. The options
318: * are:<ul>
319: * <li>JSplitPane.VERTICAL_SPLIT (above/below orientation of components)
320: * <li>JSplitPane.HORIZONTAL_SPLIT (left/right orientation of components)
321: * </ul>
322: *
323: * @param orientation an integer specifying the orientation
324: * @exception IllegalArgumentException if orientation is not one of:
325: * HORIZONTAL_SPLIT or VERTICAL_SPLIT.
326: * @beaninfo
327: * bound: true
328: * description: The orientation, or how the splitter is divided.
329: * enum: HORIZONTAL_SPLIT JSplitPane.HORIZONTAL_SPLIT
330: * VERTICAL_SPLIT JSplitPane.VERTICAL_SPLIT
331: */
332: public void setOrientation(int orientation) {
333: if ((orientation != VERTICAL_SPLIT)
334: && (orientation != HORIZONTAL_SPLIT)) {
335: throw new IllegalArgumentException(
336: "SSplitPane: orientation must " + "be one of "
337: + "SSplitPane.VERTICAL_SPLIT or "
338: + "SSplitPane.HORIZONTAL_SPLIT");
339: }
340:
341: int oldOrientation = this .orientation;
342:
343: this .orientation = orientation;
344: reloadIfChange(oldOrientation, orientation);
345: }
346:
347: /**
348: * Returns the orientation.
349: *
350: * @return an integer giving the orientation
351: * @see #setOrientation
352: */
353: public int getOrientation() {
354: return orientation;
355: }
356:
357: /**
358: * Sets the value of the <code>continuousLayout</code> property,
359: * which must be <code>true</code> for the child components
360: * to be continuously
361: * redisplayed and laid out during user intervention.
362: * The default value of this property is <code>false</code>.
363: * Some look and feels might not support continuous layout;
364: * they will ignore this property.
365: *
366: * @param newContinuousLayout <code>true</code> if the components
367: * should continuously be redrawn as the divider changes position
368: * @beaninfo
369: * bound: true
370: * description: Whether the child components are
371: * continuously redisplayed and laid out during
372: * user intervention.
373: * @see #isContinuousLayout
374: */
375: public void setContinuousLayout(boolean newContinuousLayout) {
376: boolean oldCD = continuousLayout;
377:
378: continuousLayout = newContinuousLayout;
379: reloadIfChange(oldCD, newContinuousLayout);
380: }
381:
382: /**
383: * Gets the <code>continuousLayout</code> property.
384: *
385: * @return the value of the <code>continuousLayout</code> property
386: * @see #setContinuousLayout
387: */
388: public boolean isContinuousLayout() {
389: return continuousLayout;
390: }
391:
392: /**
393: * Specifies how to distribute extra space when the size of the split pane
394: * changes. A value of 0, the default,
395: * indicates the right/bottom component gets all the extra space (the
396: * left/top component acts fixed), where as a value of 1 specifies the
397: * left/top component gets all the extra space (the right/bottom component
398: * acts fixed). Specifically, the left/top component gets (weight * diff)
399: * extra space and the right/bottom component gets (1 - weight) * diff
400: * extra space.
401: *
402: * @param value as described above
403: * @exception IllegalArgumentException if <code>value</code> is < 0 or > 1
404: * @since 1.3
405: * @beaninfo
406: * bound: true
407: * description: Specifies how to distribute extra space when the split pane
408: * resizes.
409: */
410: public void setResizeWeight(double value) {
411: if (value < 0 || value > 1) {
412: throw new IllegalArgumentException(
413: "JSplitPane weight must be between 0 and 1");
414: }
415: double oldWeight = resizeWeight;
416:
417: resizeWeight = value;
418: reloadIfChange(oldWeight, value);
419: }
420:
421: /**
422: * Returns the number that determines how extra space is distributed.
423: * @return how extra space is to be distributed on a resize of the
424: * split pane
425: * @since 1.3
426: */
427: public double getResizeWeight() {
428: return resizeWeight;
429: }
430:
431: /**
432: * Lays out the <code>JSplitPane</code> layout based on the preferred size
433: * of the children components. This will likely result in changing
434: * the divider location.
435: */
436: public void resetToPreferredSizes() {
437: // TODO: what shall we do here?
438: }
439:
440: /**
441: * Sets the location of the divider. This is passed off to the
442: * look and feel implementation, and then listeners are notified. A value
443: * less than 0 implies the divider should be reset to a value that
444: * attempts to honor the preferred size of the left/top component.
445: * After notifying the listeners, the last divider location is updated,
446: * via <code>setLastDividerLocation</code>.
447: *
448: * @param location an int specifying a UI-specific value (typically a
449: * pixel count)
450: * @beaninfo
451: * bound: true
452: * description: The location of the divider.
453: */
454: public void setDividerLocation(int location) {
455: int oldValue = dividerLocation;
456: dividerLocation = location;
457: reloadIfChange(oldValue, dividerLocation);
458: }
459:
460: /**
461: * Returns the last value passed to <code>setDividerLocation</code>.
462: * The value returned from this method may differ from the actual
463: * divider location (if <code>setDividerLocation</code> was passed a
464: * value bigger than the curent size).
465: *
466: * @return an integer specifying the location of the divider
467: */
468: public int getDividerLocation() {
469: return dividerLocation;
470: }
471:
472: /**
473: * Removes the child component, <code>component</code> from the
474: * pane. Resets the <code>leftComponent</code> or
475: * <code>rightComponent</code> instance variable, as necessary.
476: *
477: * @param component the <code>SComponent</code> to remove
478: */
479: public void remove(SComponent component) {
480: if (component == leftComponent) {
481: leftComponent = null;
482: } else if (component == rightComponent) {
483: rightComponent = null;
484: }
485: super .remove(component);
486: }
487:
488: /**
489: * Removes the <code>SComponent</code> at the specified index.
490: * Updates the <code>leftComponent</code> and <code>rightComponent</code>
491: * instance variables as necessary, and then messages super.
492: *
493: * @param index an integer specifying the component to remove, where
494: * 1 specifies the left/top component and 2 specifies the
495: * bottom/right component
496: */
497: public void remove(int index) {
498: SComponent comp = getComponent(index);
499:
500: if (comp == leftComponent) {
501: leftComponent = null;
502: } else if (comp == rightComponent) {
503: rightComponent = null;
504: }
505: super .remove(index);
506: }
507:
508: /**
509: * Removes all the child components from the split pane. Resets the
510: * <code>leftComonent</code> and <code>rightComponent</code>
511: * instance variables.
512: */
513: public void removeAll() {
514: leftComponent = rightComponent = null;
515: super .removeAll();
516: }
517:
518: /**
519: * Adds the specified component to this split pane.
520: * If <code>constraints</code> identifies the left/top or
521: * right/bottom child component, and a component with that identifier
522: * was previously added, it will be removed and then <code>comp</code>
523: * will be added in its place. If <code>constraints</code> is not
524: * one of the known identifiers the layout manager may throw an
525: * <code>IllegalArgumentException</code>.
526: * <p>
527: * The possible constraints objects (Strings) are:
528: * <ul>
529: * <li>JSplitPane.TOP
530: * <li>JSplitPane.LEFT
531: * <li>JSplitPane.BOTTOM
532: * <li>JSplitPane.RIGHT
533: * </ul>
534: * If the <code>constraints</code> object is <code>null</code>,
535: * the component is added in the
536: * first available position (left/top if open, else right/bottom).
537: *
538: * @param comp the component to add
539: * @param constraints an <code>Object</code> specifying the
540: * layout constraints
541: * (position) for this component
542: * @param index an integer specifying the index in the container's
543: * list.
544: * @exception IllegalArgumentException if the <code>constraints</code>
545: * object does not match an existing component
546: */
547: public SComponent addComponent(SComponent comp, Object constraints,
548: int index) {
549: SComponent toRemove;
550:
551: if (constraints != null && !(constraints instanceof String)) {
552: throw new IllegalArgumentException("cannot add to layout: "
553: + "constraint must be a string " + "(or null)");
554: }
555:
556: /* If the constraints are null and the left/right component is
557: invalid, add it at the left/right component. */
558: if (constraints == null) {
559: if (getLeftComponent() == null) {
560: constraints = SSplitPane.LEFT;
561: } else if (getRightComponent() == null) {
562: constraints = SSplitPane.RIGHT;
563: }
564: }
565:
566: /* Find the SComponent that already exists and remove it. */
567: if (constraints != null
568: && (constraints.equals(SSplitPane.LEFT) || constraints
569: .equals(SSplitPane.TOP))) {
570: toRemove = getLeftComponent();
571: if (toRemove != null) {
572: remove(toRemove);
573: }
574: leftComponent = comp;
575: index = -1;
576: } else if (constraints != null
577: && (constraints.equals(SSplitPane.RIGHT) || constraints
578: .equals(SSplitPane.BOTTOM))) {
579: toRemove = getRightComponent();
580: if (toRemove != null) {
581: remove(toRemove);
582: }
583: rightComponent = comp;
584: index = -1;
585: } else if (constraints != null
586: && constraints.equals(SSplitPane.DIVIDER)) {
587: index = -1;
588: }
589: /* LayoutManager should raise for else condition here. */
590:
591: super .addComponent(comp, constraints, index);
592:
593: return comp;
594: }
595:
596: /**
597: * Returns a string representation of this <code>SSplitPane</code>.
598: * This method
599: * is intended to be used only for debugging purposes, and the
600: * content and format of the returned string may vary between
601: * implementations. The returned string may be empty but may not
602: * be <code>null</code>.
603: *
604: * @return a string representation of this <code>SSplitPane</code>.
605: */
606: protected String paramString() {
607: String orientationString = (orientation == HORIZONTAL_SPLIT ? "HORIZONTAL_SPLIT"
608: : "VERTICAL_SPLIT");
609: String continuousLayoutString = (continuousLayout ? "true"
610: : "false");
611:
612: return super .paramString() + ",continuousLayout="
613: + continuousLayoutString + ",dividerSize="
614: + dividerSize + ",orientation=" + orientationString;
615: }
616:
617: public void setCG(SplitPaneCG cg) {
618: super .setCG(cg);
619: }
620:
621: public void processLowLevelEvent(String name, String[] values) {
622: this .newLocation = new Integer(values[0]);
623: SForm.addArmedComponent(this );
624: }
625:
626: public void fireIntermediateEvents() {
627: if (newLocation != -1)
628: dividerLocation = newLocation;
629: }
630:
631: public boolean isEpochCheckEnabled() {
632: return false;
633: }
634: }
|