001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: SplitWindow.java,v 1.50 2007/01/28 21:25:10 jesper Exp $
023: package net.infonode.docking;
024:
025: import net.infonode.docking.drop.InteriorDropInfo;
026: import net.infonode.docking.drop.SplitDropInfo;
027: import net.infonode.docking.internal.ReadContext;
028: import net.infonode.docking.internal.WindowAncestors;
029: import net.infonode.docking.internal.WriteContext;
030: import net.infonode.docking.internalutil.DropAction;
031: import net.infonode.docking.model.SplitWindowItem;
032: import net.infonode.docking.model.ViewReader;
033: import net.infonode.docking.model.ViewWriter;
034: import net.infonode.docking.properties.SplitWindowProperties;
035: import net.infonode.gui.ComponentUtil;
036: import net.infonode.gui.SimpleSplitPane;
037: import net.infonode.gui.SimpleSplitPaneListener;
038: import net.infonode.gui.panel.BaseContainerUtil;
039: import net.infonode.properties.propertymap.PropertyMap;
040: import net.infonode.util.Direction;
041:
042: import javax.swing.*;
043: import java.awt.*;
044: import java.awt.event.MouseAdapter;
045: import java.awt.event.MouseEvent;
046: import java.io.IOException;
047: import java.io.ObjectInputStream;
048: import java.io.ObjectOutputStream;
049:
050: /**
051: * A window with a split pane that contains two child windows.
052: *
053: * @author $Author: jesper $
054: * @version $Revision: 1.50 $
055: */
056: public class SplitWindow extends DockingWindow {
057: private SimpleSplitPane splitPane;
058: private DockingWindow leftWindow;
059: private DockingWindow rightWindow;
060:
061: /**
062: * Creates a split window.
063: *
064: * @param horizontal true if the split is horizontal
065: */
066: public SplitWindow(boolean horizontal) {
067: this (horizontal, null, null);
068: }
069:
070: /**
071: * Creates a split window with with the given child windows.
072: *
073: * @param horizontal true if the split is horizontal
074: * @param leftWindow the left/upper window
075: * @param rightWindow the right/lower window
076: */
077: public SplitWindow(boolean horizontal, DockingWindow leftWindow,
078: DockingWindow rightWindow) {
079: this (horizontal, 0.5f, leftWindow, rightWindow);
080: }
081:
082: /**
083: * Creates a split window with with the given child windows.
084: *
085: * @param horizontal true if the split is horizontal
086: * @param dividerLocation the divider location, 0 - 1
087: * @param leftWindow the left/upper window
088: * @param rightWindow the right/lower window
089: */
090: public SplitWindow(boolean horizontal, float dividerLocation,
091: DockingWindow leftWindow, DockingWindow rightWindow) {
092: this (horizontal, dividerLocation, leftWindow, rightWindow, null);
093: }
094:
095: protected SplitWindow(boolean horizontal, float dividerLocation,
096: DockingWindow leftWindow, DockingWindow rightWindow,
097: SplitWindowItem windowItem) {
098: super (windowItem == null ? new SplitWindowItem() : windowItem);
099:
100: splitPane = new SimpleSplitPane(horizontal);
101: BaseContainerUtil.setForcedOpaque(splitPane, false);
102: //splitPane.setForcedOpaque(false);
103: splitPane.addListener(new SimpleSplitPaneListener() {
104: public void dividerLocationChanged(
105: SimpleSplitPane simpleSplitPane) {
106: ((SplitWindowItem) getWindowItem())
107: .setDividerLocation(simpleSplitPane
108: .getDividerLocation());
109: }
110: });
111: setComponent(splitPane);
112: setWindows(leftWindow, rightWindow);
113: setHorizontal(horizontal);
114: setDividerLocation(dividerLocation);
115: splitPane.getDividerPanel().addMouseListener(
116: new MouseAdapter() {
117: public void mousePressed(MouseEvent e) {
118: if (e.isPopupTrigger()) {
119: showPopupMenu(e);
120: }
121: }
122:
123: public void mouseReleased(MouseEvent e) {
124: mousePressed(e);
125: }
126: });
127: init();
128: }
129:
130: /**
131: * Returns the property values for this split window.
132: *
133: * @return the property values for this split window
134: */
135: public SplitWindowProperties getSplitWindowProperties() {
136: return ((SplitWindowItem) getWindowItem())
137: .getSplitWindowProperties();
138: }
139:
140: /**
141: * Returns the left/upper child window.
142: *
143: * @return the left/upper child window
144: */
145: public DockingWindow getLeftWindow() {
146: return leftWindow;
147: }
148:
149: /**
150: * Returns the right/lower child window.
151: *
152: * @return the right/lower child window
153: */
154: public DockingWindow getRightWindow() {
155: return rightWindow;
156: }
157:
158: /**
159: * Sets the divider location as a fraction of this split window's size.
160: *
161: * @param dividerLocation the divider location as a fraction of this split window's size
162: */
163: public void setDividerLocation(float dividerLocation) {
164: splitPane.setDividerLocation(dividerLocation);
165: }
166:
167: /**
168: * Returns the divider location as a fraction of this split window's size.
169: *
170: * @return the divider location as a fraction of this split window's size
171: */
172: public float getDividerLocation() {
173: return splitPane.getDividerLocation();
174: }
175:
176: /**
177: * Sets the child windows of this split window.
178: *
179: * @param leftWindow the left/upper child window
180: * @param rightWindow the right/lower child window
181: */
182: public void setWindows(final DockingWindow leftWindow,
183: final DockingWindow rightWindow) {
184: if (leftWindow == getLeftWindow()
185: && rightWindow == getRightWindow())
186: return;
187:
188: optimizeAfter(null, new Runnable() {
189: public void run() {
190: WindowAncestors leftAncestors = leftWindow
191: .storeAncestors();
192: WindowAncestors rightAncestors = rightWindow
193: .storeAncestors();
194:
195: DockingWindow lw = leftWindow
196: .getContentWindow(SplitWindow.this );
197: DockingWindow rw = rightWindow
198: .getContentWindow(SplitWindow.this );
199: lw.detach();
200: rw.detach();
201:
202: if (getLeftWindow() != null)
203: removeWindow(getLeftWindow());
204:
205: if (getRightWindow() != null)
206: removeWindow(getRightWindow());
207:
208: SplitWindow.this .leftWindow = lw;
209: SplitWindow.this .rightWindow = rw;
210: splitPane.setComponents(lw, rw);
211: addWindow(lw);
212: addWindow(rw);
213:
214: if (getUpdateModel()) {
215: addWindowItem(getLeftWindow(), -1);
216: addWindowItem(getRightWindow(), -1);
217: cleanUpModel();
218: }
219:
220: leftWindow.notifyListeners(leftAncestors);
221: rightWindow.notifyListeners(rightAncestors);
222: }
223: });
224: }
225:
226: /**
227: * Returns true if this SplitWindow is a horizontal split, otherwise it's vertical.
228: *
229: * @return true if this SplitWindow is a horizontal split, otherwise it's vertical
230: * @since IDW 1.2.0
231: */
232: public boolean isHorizontal() {
233: return splitPane.isHorizontal();
234: }
235:
236: /**
237: * Sets the split to horizontal or vertical.
238: *
239: * @param horizontal if true the split is set to horizontal, otherwise vertical
240: * @since IDW 1.2.0
241: */
242: public void setHorizontal(boolean horizontal) {
243: splitPane.setHorizontal(horizontal);
244: ((SplitWindowItem) getWindowItem()).setHorizontal(horizontal);
245: }
246:
247: protected void update() {
248: splitPane.setDividerSize(getSplitWindowProperties()
249: .getDividerSize());
250: splitPane.setContinuousLayout(getSplitWindowProperties()
251: .getContinuousLayoutEnabled());
252: splitPane.setDividerDraggable(getSplitWindowProperties()
253: .getDividerLocationDragEnabled());
254: splitPane.setDragIndicatorColor(getSplitWindowProperties()
255: .getDragIndicatorColor());
256: }
257:
258: protected void optimizeWindowLayout() {
259: DockingWindow parent = getWindowParent();
260:
261: if (parent != null
262: && (getRightWindow() == null || getLeftWindow() == null)) {
263: if (getRightWindow() == null && getLeftWindow() == null)
264: parent.removeChildWindow(this );
265: else {
266: DockingWindow w = getRightWindow() == null ? getLeftWindow()
267: : getRightWindow();
268: parent.internalReplaceChildWindow(this , w
269: .getBestFittedWindow(parent));
270: }
271: }
272: }
273:
274: public DockingWindow getChildWindow(int index) {
275: return getWindows()[index];
276: }
277:
278: protected void rootChanged(RootWindow oldRoot, RootWindow newRoot) {
279: super .rootChanged(oldRoot, newRoot);
280: if (newRoot != null)
281: splitPane.setHeavyWeightDragIndicator(newRoot
282: .isHeavyweightSupported());
283: }
284:
285: private DockingWindow[] getWindows() {
286: return getLeftWindow() == null ? (getRightWindow() == null ? new DockingWindow[0]
287: : new DockingWindow[] { getRightWindow() })
288: : getRightWindow() == null ? new DockingWindow[] { getLeftWindow() }
289: : new DockingWindow[] { getLeftWindow(),
290: getRightWindow() };
291: }
292:
293: public int getChildWindowCount() {
294: return getWindows().length;
295: }
296:
297: public Icon getIcon() {
298: return getLeftWindow() == null ? (getRightWindow() == null ? null
299: : getRightWindow().getIcon())
300: : getLeftWindow().getIcon();
301: }
302:
303: protected void doReplace(DockingWindow oldWindow,
304: DockingWindow newWindow) {
305: if (getLeftWindow() == oldWindow) {
306: leftWindow = newWindow;
307: splitPane.setLeftComponent(newWindow);
308: } else {
309: rightWindow = newWindow;
310: splitPane.setRightComponent(newWindow);
311: }
312:
313: ComponentUtil.validate(splitPane);
314: }
315:
316: protected void doRemoveWindow(DockingWindow window) {
317: if (window == getLeftWindow()) {
318: leftWindow = null;
319: splitPane.setLeftComponent(null);
320: } else {
321: rightWindow = null;
322: splitPane.setRightComponent(null);
323: }
324: }
325:
326: protected DockingWindow oldRead(ObjectInputStream in,
327: ReadContext context) throws IOException {
328: splitPane.setHorizontal(in.readBoolean());
329: splitPane.setDividerLocation(in.readFloat());
330: DockingWindow leftWindow = WindowDecoder.decodeWindow(in,
331: context);
332: DockingWindow rightWindow = WindowDecoder.decodeWindow(in,
333: context);
334: super .oldRead(in, context);
335:
336: if (leftWindow != null && rightWindow != null) {
337: setWindows(leftWindow, rightWindow);
338: return this ;
339: } else
340: return leftWindow != null ? leftWindow
341: : rightWindow != null ? rightWindow : null;
342: }
343:
344: protected void updateWindowItem(RootWindow rootWindow) {
345: super .updateWindowItem(rootWindow);
346: ((SplitWindowItem) getWindowItem())
347: .setParentSplitWindowProperties(rootWindow == null ? SplitWindowItem.emptyProperties
348: : rootWindow.getRootWindowProperties()
349: .getSplitWindowProperties());
350: }
351:
352: protected PropertyMap getPropertyObject() {
353: return getSplitWindowProperties().getMap();
354: }
355:
356: protected PropertyMap createPropertyObject() {
357: return new SplitWindowProperties().getMap();
358: }
359:
360: void removeWindowComponent(DockingWindow window) {
361: if (window == getLeftWindow())
362: splitPane.setLeftComponent(null);
363: else
364: splitPane.setRightComponent(null);
365: }
366:
367: void restoreWindowComponent(DockingWindow window) {
368: if (window == getLeftWindow())
369: splitPane.setLeftComponent(leftWindow);
370: else
371: splitPane.setRightComponent(rightWindow);
372: }
373:
374: protected int getChildEdgeDepth(DockingWindow window, Direction dir) {
375: return (window == leftWindow ? dir : dir.getOpposite()) == (isHorizontal() ? Direction.RIGHT
376: : Direction.DOWN) ? 0 : super .getChildEdgeDepth(window,
377: dir);
378: }
379:
380: protected DropAction doAcceptDrop(Point p, DockingWindow window) {
381: DropAction da = acceptChildDrop(p, window);
382:
383: if (da != null)
384: return da;
385:
386: float f = isHorizontal() ? (float) p.y / getHeight()
387: : (float) p.x / getWidth();
388:
389: if (f <= 0.33f) {
390: Direction splitDir = isHorizontal() ? Direction.UP
391: : Direction.LEFT;
392: return getSplitDropFilter().acceptDrop(
393: new SplitDropInfo(window, this , p, splitDir)) ? split(
394: window, splitDir)
395: : null;
396: } else if (f >= 0.66f) {
397: Direction splitDir = isHorizontal() ? Direction.DOWN
398: : Direction.RIGHT;
399: return getSplitDropFilter().acceptDrop(
400: new SplitDropInfo(window, this , p, splitDir)) ? split(
401: window, splitDir)
402: : null;
403: } else {
404: return getInteriorDropFilter().acceptDrop(
405: new InteriorDropInfo(window, this , p)) ? createTabWindow(window)
406: : null;
407: }
408: }
409:
410: protected void write(ObjectOutputStream out, WriteContext context,
411: ViewWriter viewWriter) throws IOException {
412: out.writeInt(WindowIds.SPLIT);
413: viewWriter.writeWindowItem(getWindowItem(), out, context);
414: getLeftWindow().write(out, context, viewWriter);
415: getRightWindow().write(out, context, viewWriter);
416: }
417:
418: protected DockingWindow newRead(ObjectInputStream in,
419: ReadContext context, ViewReader viewReader)
420: throws IOException {
421: DockingWindow leftWindow = WindowDecoder.decodeWindow(in,
422: context, viewReader);
423: DockingWindow rightWindow = WindowDecoder.decodeWindow(in,
424: context, viewReader);
425:
426: if (leftWindow != null && rightWindow != null) {
427: setWindows(leftWindow, rightWindow);
428: return this;
429: } else
430: return leftWindow != null ? leftWindow
431: : rightWindow != null ? rightWindow : null;
432: }
433:
434: }
|