0001: /*
0002: * Copyright (C) 2004 NNL Technology AB
0003: * Visit www.infonode.net for information about InfoNode(R)
0004: * products and how to contact NNL Technology AB.
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License
0008: * as published by the Free Software Foundation; either version 2
0009: * of the License, or (at your option) any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: * GNU General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with this program; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
0019: * MA 02111-1307, USA.
0020: */
0021:
0022: // $Id: RootWindow.java,v 1.127 2007/01/28 21:25:10 jesper Exp $
0023: package net.infonode.docking;
0024:
0025: import net.infonode.docking.action.*;
0026: import net.infonode.docking.drop.ChildDropInfo;
0027: import net.infonode.docking.drop.InteriorDropInfo;
0028: import net.infonode.docking.internal.HeavyWeightContainer;
0029: import net.infonode.docking.internal.HeavyWeightDragRectangle;
0030: import net.infonode.docking.internal.ReadContext;
0031: import net.infonode.docking.internal.WriteContext;
0032: import net.infonode.docking.internalutil.DropAction;
0033: import net.infonode.docking.model.*;
0034: import net.infonode.docking.properties.RootWindowProperties;
0035: import net.infonode.docking.util.DockingUtil;
0036: import net.infonode.gui.CursorManager;
0037: import net.infonode.gui.DragLabelWindow;
0038: import net.infonode.gui.componentpainter.ComponentPainter;
0039: import net.infonode.gui.componentpainter.RectangleComponentPainter;
0040: import net.infonode.gui.layout.BorderLayout2;
0041: import net.infonode.gui.layout.LayoutUtil;
0042: import net.infonode.gui.layout.StretchLayout;
0043: import net.infonode.gui.mouse.MouseButtonListener;
0044: import net.infonode.gui.panel.SimplePanel;
0045: import net.infonode.gui.shaped.panel.ShapedPanel;
0046: import net.infonode.properties.gui.InternalPropertiesUtil;
0047: import net.infonode.properties.propertymap.PropertyMap;
0048: import net.infonode.properties.propertymap.PropertyMapManager;
0049: import net.infonode.util.ArrayUtil;
0050: import net.infonode.util.Direction;
0051: import net.infonode.util.ReadWritable;
0052:
0053: import javax.swing.*;
0054: import java.awt.*;
0055: import java.awt.event.MouseEvent;
0056: import java.beans.PropertyChangeEvent;
0057: import java.beans.PropertyChangeListener;
0058: import java.io.IOException;
0059: import java.io.ObjectInputStream;
0060: import java.io.ObjectOutputStream;
0061: import java.lang.ref.WeakReference;
0062: import java.util.ArrayList;
0063:
0064: /**
0065: * The root window is a top level container for docking windows. Docking windows can't be dragged outside of their root
0066: * window. The property values of a root window is inherited to the docking windows inside it.
0067: *
0068: * @author $Author: jesper $
0069: * @version $Revision: 1.127 $
0070: */
0071: public class RootWindow extends DockingWindow implements ReadWritable {
0072: private static final int SERIALIZE_VERSION = 4;
0073:
0074: private static final int FLOATING_WINDOW_MIN_WIDTH = 400;
0075: private static final int FLOATING_WINDOW_MIN_HEIGHT = 300;
0076:
0077: private boolean heavyweightSupport = false;
0078:
0079: private class SingleComponentLayout implements LayoutManager {
0080: public void addLayoutComponent(String name, Component comp) {
0081: }
0082:
0083: public void layoutContainer(Container parent) {
0084: Dimension size = LayoutUtil.getInteriorSize(parent);
0085: Insets insets = parent.getInsets();
0086: mainPanel.setBounds(insets.left, insets.top, size.width,
0087: size.height);
0088:
0089: int w1 = windowBars[Direction.LEFT.getValue()]
0090: .getPreferredSize().width;
0091: int w2 = windowBars[Direction.RIGHT.getValue()]
0092: .getPreferredSize().width;
0093: int h1 = windowBars[Direction.UP.getValue()]
0094: .getPreferredSize().height;
0095: int h2 = windowBars[Direction.DOWN.getValue()]
0096: .getPreferredSize().height;
0097:
0098: final Direction[] directions = Direction.getDirections();
0099:
0100: for (int i = 0; i < windowBars.length; i++) {
0101: Component panel = windowBars[i].getEdgePanel();
0102:
0103: if (panel.isVisible()) {
0104: Direction dir = directions[i];
0105: int maxWidth = size.width - w1 - w2;
0106: int maxHeight = size.height - h1 - h2;
0107:
0108: if (dir == Direction.RIGHT) {
0109: int rightX = parent.getWidth()
0110: - insets.right
0111: - w2
0112: + windowBars[dir.getValue()]
0113: .getInsets().left;
0114: int width = Math.min(
0115: panel.getPreferredSize().width,
0116: maxWidth
0117: + windowBars[dir.getValue()]
0118: .getInsets().left);
0119: panel.setBounds(rightX - width,
0120: insets.top + h1, width, maxHeight);
0121: } else if (dir == Direction.LEFT) {
0122: int x = insets.left
0123: + w1
0124: - windowBars[dir.getValue()]
0125: .getInsets().right;
0126: int width = Math.min(
0127: panel.getPreferredSize().width,
0128: maxWidth
0129: + windowBars[dir.getValue()]
0130: .getInsets().right);
0131: panel.setBounds(x, insets.top + h1, width,
0132: maxHeight);
0133: } else if (dir == Direction.DOWN) {
0134: int bottomY = parent.getHeight()
0135: - insets.bottom
0136: - h2
0137: + windowBars[dir.getValue()]
0138: .getInsets().top;
0139: int height = Math.min(
0140: panel.getPreferredSize().height,
0141: maxHeight
0142: + windowBars[dir.getValue()]
0143: .getInsets().top);
0144: panel.setBounds(insets.left + w1, bottomY
0145: - height, maxWidth, height);
0146: } else {
0147: int y = insets.top
0148: + h1
0149: - windowBars[dir.getValue()]
0150: .getInsets().bottom;
0151: int height = Math.min(
0152: panel.getPreferredSize().height,
0153: maxHeight
0154: + windowBars[dir.getValue()]
0155: .getInsets().bottom);
0156: panel.setBounds(insets.left + w1, y, maxWidth,
0157: height);
0158: }
0159: }
0160: }
0161: }
0162:
0163: public Dimension minimumLayoutSize(Container parent) {
0164: return LayoutUtil.add(mainPanel.getMinimumSize(), parent
0165: .getInsets());
0166: }
0167:
0168: public Dimension preferredLayoutSize(Container parent) {
0169: return LayoutUtil.add(mainPanel.getPreferredSize(), parent
0170: .getInsets());
0171: }
0172:
0173: public void removeLayoutComponent(Component comp) {
0174: }
0175:
0176: }
0177:
0178: private ShapedPanel layeredPane = new ShapedPanel() {
0179: public boolean isOptimizedDrawingEnabled() {
0180: return false;
0181: }
0182: };
0183:
0184: private ShapedPanel windowPanel = new ShapedPanel(
0185: new StretchLayout(true, true));
0186:
0187: private SimplePanel mainPanel = new SimplePanel();
0188:
0189: private JFrame dummyFrame;
0190:
0191: private ViewSerializer viewSerializer;
0192: private DockingWindow window;
0193: // private View lastFocusedView;
0194: private WindowBar[] windowBars = new WindowBar[Direction
0195: .getDirections().length];
0196: private ArrayList floatingWindows = new ArrayList();
0197: private DockingWindow maximizedWindow;
0198: private View focusedView;
0199: private ArrayList lastFocusedWindows = new ArrayList(4);
0200: private ArrayList focusedWindows = new ArrayList(4);
0201: private ArrayList views = new ArrayList();
0202: private boolean cleanUpModel;
0203: private Runnable modelCleanUpEvent = new Runnable() {
0204: public void run() {
0205: if (cleanUpModel) {
0206: cleanUpModel = false;
0207: getWindowItem().cleanUp();
0208: }
0209: }
0210: };
0211:
0212: private JLabel dragTextLabel = new JLabel();
0213: private Container dragTextContainer;
0214:
0215: private DragLabelWindow dragTextWindow;
0216:
0217: private Component dragRectangle;
0218: private JRootPane currentDragRootPane;
0219:
0220: /**
0221: * Creates an empty root window.
0222: *
0223: * @param viewSerializer used when reading and writing views
0224: * @since IDW 1.1.0
0225: */
0226: public RootWindow(ViewSerializer viewSerializer) {
0227: this (false, viewSerializer);
0228: }
0229:
0230: /**
0231: * Creates an empty root window with support for heavyweight components inside the
0232: * views.
0233: *
0234: * @param heavyweightSupport true for heavy weight component support, otherwise false
0235: * @param viewSerializer used when reading and writing views
0236: * @since IDW 1.4.0
0237: */
0238: public RootWindow(boolean heavyweightSupport,
0239: ViewSerializer viewSerializer) {
0240: super (new RootWindowItem());
0241: this .heavyweightSupport = heavyweightSupport;
0242:
0243: dragRectangle = heavyweightSupport ? new HeavyWeightDragRectangle()
0244: : (Component) new ShapedPanel();
0245:
0246: getWindowProperties().addSuperObject(
0247: getRootWindowProperties().getDockingWindowProperties());
0248:
0249: mainPanel.setLayout(new BorderLayout2());
0250: mainPanel.add(windowPanel, new Point(1, 1));
0251:
0252: createWindowBars();
0253:
0254: layeredPane.add(mainPanel);
0255: layeredPane.setLayout(new SingleComponentLayout());
0256: setComponent(layeredPane);
0257:
0258: this .viewSerializer = viewSerializer;
0259:
0260: dragTextLabel.setOpaque(true);
0261:
0262: if (heavyweightSupport) {
0263: dragTextContainer = new HeavyWeightContainer(dragTextLabel,
0264: true);
0265: dragTextContainer.validate();
0266: } else
0267: dragTextContainer = dragTextLabel;
0268:
0269: init();
0270: FocusManager.getInstance();
0271:
0272: addTabMouseButtonListener(new MouseButtonListener() {
0273: public void mouseButtonEvent(MouseEvent event) {
0274: if (event.isConsumed())
0275: return;
0276:
0277: DockingWindow window = (DockingWindow) event
0278: .getSource();
0279:
0280: if (event.getID() == MouseEvent.MOUSE_PRESSED
0281: && event.getButton() == MouseEvent.BUTTON1
0282: && !event.isShiftDown() && window.isShowing()) {
0283: RestoreFocusWindowAction.INSTANCE.perform(window);
0284: } else if (event.getID() == MouseEvent.MOUSE_CLICKED
0285: && event.getButton() == MouseEvent.BUTTON1) {
0286: if (event.getClickCount() == 2) {
0287: if ((window.getWindowParent() instanceof WindowBar)
0288: && getRootWindowProperties()
0289: .getDoubleClickRestoresWindow())
0290: RestoreWithAbortWindowAction.INSTANCE
0291: .perform(window);
0292: else {
0293: new StateDependentWindowAction(
0294: MaximizeWithAbortWindowAction.INSTANCE,
0295: NullWindowAction.INSTANCE,
0296: RestoreParentWithAbortWindowAction.INSTANCE)
0297: .perform(window);
0298: }
0299: }
0300: }
0301: }
0302: });
0303: }
0304:
0305: /**
0306: * Creates a root window with the given window as window inside this root window.
0307: *
0308: * @param viewSerializer used when reading and writing views
0309: * @param window the window that is placed inside the root window
0310: */
0311: public RootWindow(ViewSerializer viewSerializer,
0312: DockingWindow window) {
0313: this (false, viewSerializer, window);
0314: }
0315:
0316: /**
0317: * Creates a root window with support for heavyweight components inside the views and the
0318: * given window inside as window inside this root window.
0319: *
0320: * @param heavyweightSupport true for heavy weight component support, otherwise false
0321: * @param viewSerializer used when reading and writing views
0322: * @param window the window that is placed inside the root window
0323: * @since IDW 1.4.0
0324: */
0325: public RootWindow(boolean heavyweightSupport,
0326: ViewSerializer viewSerializer, DockingWindow window) {
0327: this (heavyweightSupport, viewSerializer);
0328: setWindow(window);
0329: }
0330:
0331: /**
0332: * Returns the view that currently contains the focus.
0333: *
0334: * @return The currently focused view, null if no view has focus
0335: */
0336: public View getFocusedView() {
0337: return focusedView;
0338: }
0339:
0340: void addFocusedWindow(DockingWindow window) {
0341: for (int i = 0; i < lastFocusedWindows.size(); i++) {
0342: if (((WeakReference) lastFocusedWindows.get(i)).get() == window)
0343: return;
0344: }
0345:
0346: lastFocusedWindows.add(new WeakReference(window));
0347: }
0348:
0349: void setFocusedView(View view) {
0350: if (view == focusedView)
0351: return;
0352:
0353: // System.out.println(focusedView + " -> " + view);
0354:
0355: View previouslyFocusedView = focusedView;
0356: focusedView = view;
0357:
0358: for (DockingWindow w = view; w != null; w = w.getWindowParent()) {
0359: focusedWindows.add(new WeakReference(w));
0360:
0361: for (int i = 0; i < lastFocusedWindows.size(); i++) {
0362: if (((WeakReference) lastFocusedWindows.get(i)).get() == w) {
0363: lastFocusedWindows.remove(i);
0364: break;
0365: }
0366: }
0367: }
0368:
0369: for (int i = 0; i < lastFocusedWindows.size(); i++) {
0370: DockingWindow w = (DockingWindow) ((WeakReference) lastFocusedWindows
0371: .get(i)).get();
0372:
0373: if (w != null) {
0374: w.setFocused(false);
0375: }
0376: }
0377:
0378: ArrayList temp = lastFocusedWindows;
0379: lastFocusedWindows = focusedWindows;
0380: focusedWindows = temp;
0381:
0382: for (int i = 0; i < lastFocusedWindows.size(); i++) {
0383: DockingWindow w = (DockingWindow) ((WeakReference) lastFocusedWindows
0384: .get(i)).get();
0385:
0386: if (w != null)
0387: w.setFocused(true);
0388: }
0389:
0390: if (view != null) {
0391: view.childGainedFocus(null, view);
0392: } else {
0393: clearFocus(null);
0394: }
0395:
0396: // Notify windows that are not ancestors of the new focused view
0397: for (int i = 0; i < focusedWindows.size(); i++) {
0398: DockingWindow w = (DockingWindow) ((WeakReference) focusedWindows
0399: .get(i)).get();
0400:
0401: if (w != null) {
0402: w.fireViewFocusChanged(previouslyFocusedView,
0403: focusedView);
0404: }
0405: }
0406:
0407: // Notify windows that are ancestors of the new focused view
0408: for (int i = 0; i < lastFocusedWindows.size(); i++) {
0409: DockingWindow w = (DockingWindow) ((WeakReference) lastFocusedWindows
0410: .get(i)).get();
0411:
0412: if (w != null) {
0413: w.fireViewFocusChanged(previouslyFocusedView,
0414: focusedView);
0415: }
0416: }
0417:
0418: focusedWindows.clear();
0419: }
0420:
0421: /**
0422: * Returns the property values for this root window. The property values will be inherited to docking windows inside
0423: * this root window.
0424: *
0425: * @return the property values for this root window
0426: */
0427: public RootWindowProperties getRootWindowProperties() {
0428: return ((RootWindowItem) getWindowItem())
0429: .getRootWindowProperties();
0430: }
0431:
0432: /**
0433: * Returns the direction of the closest enabled window bar to a docking window. The distance is measured from the
0434: * window edge that is furthest away from the bar.
0435: *
0436: * @param window the docking window
0437: * @return the direction of the closest enabled window bar to a docking window
0438: */
0439: public Direction getClosestWindowBar(DockingWindow window) {
0440: Point pos = SwingUtilities.convertPoint(window.getParent(),
0441: window.getLocation(), this );
0442:
0443: int[] distances = new int[] {
0444: getWindowBar(Direction.UP).isEnabled() ? pos.y
0445: + window.getHeight() : Integer.MAX_VALUE,
0446: getWindowBar(Direction.DOWN).isEnabled() ? getHeight()
0447: - pos.y : Integer.MAX_VALUE,
0448: getWindowBar(Direction.LEFT).isEnabled() ? pos.x
0449: + window.getWidth() : Integer.MAX_VALUE,
0450: getWindowBar(Direction.RIGHT).isEnabled() ? getWidth()
0451: - pos.x : Integer.MAX_VALUE };
0452:
0453: Direction dir = new Direction[] { Direction.UP, Direction.DOWN,
0454: Direction.LEFT, Direction.RIGHT }[ArrayUtil
0455: .findSmallest(distances)];
0456: return getWindowBar(dir).isEnabled() ? dir : null;
0457: }
0458:
0459: /**
0460: * Returns the window bar in the direction.
0461: *
0462: * @param direction the direction
0463: * @return the window bar in the direction
0464: */
0465: public WindowBar getWindowBar(Direction direction) {
0466: return windowBars[direction.getValue()];
0467: }
0468:
0469: /**
0470: * Sets the top level docking window inside this root window.
0471: *
0472: * @param newWindow the top level docking window
0473: */
0474: public void setWindow(DockingWindow newWindow) {
0475: if (window == newWindow)
0476: return;
0477:
0478: if (window == null) {
0479: DockingWindow actualWindow = addWindow(newWindow);
0480: doReplace(null, actualWindow);
0481:
0482: if (getUpdateModel()
0483: && actualWindow.getWindowItem().getRootItem() != getWindowItem()) {
0484: getWindowItem().removeAll();
0485: addWindowItem(actualWindow, -1);
0486: }
0487: } else if (newWindow == null) {
0488: removeChildWindow(window);
0489: window = null;
0490: } else
0491: replaceChildWindow(window, newWindow);
0492: }
0493:
0494: /**
0495: * Returns the top level docking window inside this root window.
0496: *
0497: * @return the top level docking window inside this root window
0498: */
0499: public DockingWindow getWindow() {
0500: return window;
0501: }
0502:
0503: /**
0504: * <p>
0505: * Creates and shows a floating window with the given window as top-level window in the floating window or without
0506: * any top-level window i.e. empty floating window.
0507: * </p>
0508: *
0509: * <p>
0510: * <strong>Note 1:</strong> The created floating window is not visible per default. To make it visible, call
0511: * {@link FloatingWindow}.getTopLevelAncestor().setVisible(true);
0512: * </p>
0513: *
0514: * <p>
0515: * <strong>Note 2:</strong> Floating windows are dynamically created when a window is undocked and closed/removed
0516: * when all windows inside the floating window has been removed (i.e. cloased/docked/undocked to another floating
0517: * window) from the floating window. The root window has a refernce to the floating window as long as the floating
0518: * window has windows inside it i.e. it is not necessary to keep references to the floating window because the root
0519: * window will handle this.
0520: * </p>
0521: *
0522: * @param location the floating window's location on the screen
0523: * @param innerSize the inner dimension of the floating window's top level container i.e.the size of the root pane
0524: * @param window the docking window that is the top level window in this floating window or null for no top-level
0525: * window i.e. empty floating window
0526: * @return the floating window
0527: * @since IDW 1.4.0
0528: */
0529: public FloatingWindow createFloatingWindow(Point location,
0530: Dimension innerSize, DockingWindow window) {
0531: FloatingWindow fw = new FloatingWindow(this , window, location,
0532: innerSize);
0533: floatingWindows.add(fw);
0534: addWindow(fw);
0535: return fw;
0536: }
0537:
0538: FloatingWindow createFloatingWindow() {
0539: FloatingWindow fw = new FloatingWindow(this );
0540: floatingWindows.add(fw);
0541: addWindow(fw);
0542: return fw;
0543: }
0544:
0545: FloatingWindow createFloatingWindow(DockingWindow window, Point p) {
0546: Dimension size = window.getSize();
0547: if (size.width <= 0 || size.height <= 0) {
0548: Dimension preferred = window.getPreferredSize();
0549: size = new Dimension(Math.max(FLOATING_WINDOW_MIN_WIDTH,
0550: preferred.width), Math.max(
0551: FLOATING_WINDOW_MIN_HEIGHT, preferred.height));
0552: }
0553:
0554: FloatingWindow fw = createFloatingWindow(p, size, window);
0555: fw.getTopLevelAncestor().setVisible(true);
0556:
0557: return fw;
0558: }
0559:
0560: void removeFloatingWindow(FloatingWindow fw) {
0561: floatingWindows.remove(fw);
0562: removeWindow(fw);
0563: }
0564:
0565: /**
0566: * Returns the view serializer object for the views inside this root window.
0567: *
0568: * @return the view serializer object for the views inside this root window
0569: */
0570: public ViewSerializer getViewSerializer() {
0571: return viewSerializer;
0572: }
0573:
0574: public DockingWindow getChildWindow(int index) {
0575: return index < 4 ? windowBars[index]
0576: : window != null ? (index == 4 ? window
0577: : (DockingWindow) floatingWindows
0578: .get(index - 5))
0579: : (DockingWindow) floatingWindows
0580: .get(index - 4);
0581: }
0582:
0583: public int getChildWindowCount() {
0584: return 4 + (window == null ? 0 : 1) + floatingWindows.size();
0585: }
0586:
0587: public Icon getIcon() {
0588: return null;
0589: }
0590:
0591: /**
0592: * Writes the state of this root window and all child windows.
0593: *
0594: * @param out the stream on which to write the state
0595: * @throws IOException if there is a stream error
0596: */
0597: public void write(ObjectOutputStream out) throws IOException {
0598: write(out, true);
0599: }
0600:
0601: /**
0602: * Writes the state of this root window and all child windows.
0603: *
0604: * @param out the stream on which to write the state
0605: * @param writeProperties true if the property values for all docking windows should be written to the stream
0606: * @throws IOException if there is a stream error
0607: */
0608: public void write(ObjectOutputStream out, boolean writeProperties)
0609: throws IOException {
0610: cleanUpModel();
0611: out.writeInt(SERIALIZE_VERSION);
0612: out.writeBoolean(writeProperties);
0613: WriteContext context = new WriteContext(writeProperties,
0614: getViewSerializer());
0615:
0616: final ArrayList v = new ArrayList();
0617:
0618: for (int i = 0; i < views.size(); i++) {
0619: View view = (View) ((WeakReference) views.get(i)).get();
0620:
0621: if (view != null)
0622: v.add(view);
0623: }
0624:
0625: writeViews(v, out, context);
0626: ViewWriter viewWriter = new ViewWriter() {
0627: public void writeWindowItem(WindowItem windowItem,
0628: ObjectOutputStream out, WriteContext context)
0629: throws IOException {
0630: if (windowItem.getRootItem() == getWindowItem()) {
0631: out.writeBoolean(true);
0632: writeWindowItemIndex(windowItem, out);
0633: out.writeInt(-1);
0634: } else {
0635: out.writeBoolean(false);
0636: windowItem.writeSettings(out, context);
0637: }
0638: }
0639:
0640: public void writeView(View view, ObjectOutputStream out,
0641: WriteContext context) throws IOException {
0642: for (int i = 0; i < v.size(); i++) {
0643: if (v.get(i) == view) {
0644: out.writeInt(i);
0645: return;
0646: }
0647: }
0648:
0649: out.writeInt(-1);
0650: }
0651: };
0652: getWindowItem().write(out, context, viewWriter);
0653:
0654: for (int i = 0; i < 4; i++)
0655: windowBars[i].write(out, context, viewWriter);
0656:
0657: out.writeInt(floatingWindows.size());
0658:
0659: for (int i = 0; i < floatingWindows.size(); i++)
0660: ((FloatingWindow) floatingWindows.get(i)).write(out,
0661: context, viewWriter);
0662:
0663: writeLocations(out);
0664:
0665: if (maximizedWindow != null)
0666: writeMaximized(maximizedWindow, out);
0667:
0668: out.writeInt(-1);
0669: }
0670:
0671: private void writeWindowItemIndex(WindowItem item,
0672: ObjectOutputStream out) throws IOException {
0673: if (item.getParent() == null)
0674: return;
0675:
0676: writeWindowItemIndex(item.getParent(), out);
0677: int index = item.getParent().getWindowIndex(item);
0678: out.writeInt(index);
0679: }
0680:
0681: private void writeMaximized(DockingWindow window,
0682: ObjectOutputStream out) throws IOException {
0683: DockingWindow parent = window.getWindowParent();
0684:
0685: if (parent != null) {
0686: writeMaximized(parent, out);
0687: out.writeInt(parent.getChildWindowIndex(window));
0688: }
0689: }
0690:
0691: private static void writeViews(ArrayList views,
0692: ObjectOutputStream out, WriteContext context)
0693: throws IOException {
0694: out.writeInt(views.size());
0695:
0696: for (int i = 0; i < views.size(); i++)
0697: ((View) views.get(i)).write(out, context);
0698: }
0699:
0700: /**
0701: * Reads a previously written window state. This will create child windows and read their state.
0702: *
0703: * @param in the stream from which to read the state
0704: * @throws IOException if there is a stream error
0705: */
0706: public void read(ObjectInputStream in) throws IOException {
0707: read(in, true);
0708: }
0709:
0710: private void oldInternalRead(ObjectInputStream in,
0711: ReadContext context) throws IOException {
0712: setWindow(in.readBoolean() ? WindowDecoder.decodeWindow(in,
0713: context) : null);
0714:
0715: for (int i = 0; i < 4; i++) {
0716: in.readInt(); // DockingWindow bar ID
0717: windowBars[i].oldRead(in, context);
0718: }
0719:
0720: super .oldRead(in, context);
0721: readLocations(in, this , context.getVersion());
0722:
0723: if (context.getVersion() > 1) {
0724: int viewCount = in.readInt();
0725:
0726: for (int i = 0; i < viewCount; i++) {
0727: View view = (View) WindowDecoder.decodeWindow(in,
0728: context);
0729: view.setRootWindow(this );
0730: view.readLocations(in, this , context.getVersion());
0731: }
0732: }
0733: }
0734:
0735: private void newInternalRead(ObjectInputStream in,
0736: ReadContext context) throws IOException {
0737: beginUpdateModel();
0738:
0739: try {
0740: int viewCount = in.readInt();
0741: final View[] views = new View[viewCount];
0742:
0743: for (int i = 0; i < viewCount; i++) {
0744: views[i] = View.read(in, context);
0745:
0746: if (views[i] != null)
0747: views[i].setRootWindow(this );
0748: }
0749:
0750: ViewReader viewReader = new ViewReader() {
0751: public ViewItem readViewItem(ObjectInputStream in,
0752: ReadContext context) throws IOException {
0753: View view = readView(in, context);
0754: return view == null ? new ViewItem()
0755: : (ViewItem) view.getWindowItem();
0756: }
0757:
0758: public WindowItem readWindowItem(ObjectInputStream in,
0759: ReadContext context) throws IOException {
0760: if (in.readBoolean()) {
0761: int index;
0762: WindowItem item = getWindowItem();
0763:
0764: while ((index = in.readInt()) != -1) {
0765: item = item.getWindow(index);
0766: }
0767:
0768: return item;
0769: } else
0770: return null;
0771: }
0772:
0773: public TabWindow createTabWindow(
0774: DockingWindow[] childWindows,
0775: TabWindowItem windowItem) {
0776: TabWindow tabWindow = new TabWindow(childWindows,
0777: windowItem);
0778: tabWindow.updateSelectedTab();
0779: return tabWindow;
0780: }
0781:
0782: public SplitWindow createSplitWindow(
0783: DockingWindow leftWindow,
0784: DockingWindow rightWindow,
0785: SplitWindowItem windowItem) {
0786: return new SplitWindow(windowItem.isHorizontal(),
0787: windowItem.getDividerLocation(),
0788: leftWindow, rightWindow, windowItem);
0789: }
0790:
0791: public View readView(ObjectInputStream in,
0792: ReadContext context) throws IOException {
0793: int id = in.readInt();
0794: return id == -1 ? null : (View) views[id];
0795: }
0796: };
0797: setWindow(getWindowItem().read(in, context, viewReader));
0798:
0799: for (int i = 0; i < 4; i++)
0800: windowBars[i].newRead(in, context, viewReader);
0801:
0802: if (context.getVersion() >= 4) {
0803: int count = in.readInt();
0804:
0805: for (int i = 0; i < count; i++) {
0806: FloatingWindow w = createFloatingWindow();
0807: w.read(in, context, viewReader);
0808: }
0809:
0810: }
0811:
0812: readLocations(in, this , context.getVersion());
0813: } finally {
0814: endUpdateModel();
0815: }
0816: }
0817:
0818: /**
0819: * Reads a previously written window state. This will create child windows and read their state.
0820: *
0821: * @param in the stream from which to read the state
0822: * @param readProperties true if the property values for all child windows should be read. This parameter can be set
0823: * to true or false regardless of if the property values was included when the state was
0824: * written, though obviously no property values are read if there aren't any in the stream.
0825: * @throws IOException if there is a stream error
0826: */
0827: public void read(ObjectInputStream in, boolean readProperties)
0828: throws IOException {
0829: FocusManager.getInstance().startIgnoreFocusChanges();
0830: PropertyMapManager.getInstance().beginBatch();
0831:
0832: try {
0833: setWindow(null);
0834:
0835: while (floatingWindows.size() > 0) {
0836: ((FloatingWindow) floatingWindows.get(0)).close();
0837: }
0838:
0839: int serializeVersion = in.readInt();
0840:
0841: if (serializeVersion > SERIALIZE_VERSION)
0842: throw new IOException(
0843: "Can't read serialized data because it was written by a later version of InfoNode Docking Windows!");
0844:
0845: ReadContext context = new ReadContext(this ,
0846: serializeVersion, in.readBoolean(), readProperties);
0847:
0848: if (context.getVersion() < 3)
0849: oldInternalRead(in, context);
0850: else
0851: newInternalRead(in, context);
0852:
0853: if (serializeVersion > 1)
0854: readMaximized(in);
0855:
0856: FocusManager.focusWindow(this );
0857: } finally {
0858: PropertyMapManager.getInstance().endBatch();
0859: SwingUtilities.invokeLater(new Runnable() {
0860: public void run() {
0861: FocusManager.getInstance().stopIgnoreFocusChanges();
0862: }
0863: });
0864: }
0865: }
0866:
0867: private void readMaximized(ObjectInputStream in) throws IOException {
0868: int index;
0869: DockingWindow w = this ;
0870:
0871: while ((index = in.readInt()) != -1) {
0872: if (index >= w.getChildWindowCount()) {
0873: while (in.readInt() != -1)
0874: ;
0875: return;
0876: }
0877:
0878: w = w.getChildWindow(index);
0879: }
0880:
0881: if (w != this )
0882: setMaximizedWindow(w);
0883: }
0884:
0885: /**
0886: * Returns the maximized window in this root window, or null if there no maximized window.
0887: *
0888: * @return the maximized window in this root window, or null if there no maximized window
0889: * @since IDW 1.1.0
0890: */
0891: public DockingWindow getMaximizedWindow() {
0892: return maximizedWindow;
0893: }
0894:
0895: /**
0896: * Sets the maximized window in this root window.
0897: * This method takes the window component and displays it at the top in the root window. It does NOT modify the
0898: * window tree structure, ie the window parent remains the unchanged.
0899: *
0900: * @param window the maximized window in this root window, null means no maximized window
0901: * @since IDW 1.1.0
0902: */
0903: public void setMaximizedWindow(DockingWindow window) {
0904: /*if (window == maximizedWindow)
0905: return;*/
0906:
0907: if (window != null
0908: && (window.isMinimized() || window.isUndocked()))
0909: return;
0910:
0911: internalSetMaximizedWindow(window);
0912: }
0913:
0914: void addView(View view) {
0915: int freeIndex = views.size();
0916:
0917: for (int i = 0; i < views.size(); i++) {
0918: View v = (View) ((WeakReference) views.get(i)).get();
0919:
0920: if (v == view)
0921: return;
0922:
0923: if (v == null)
0924: freeIndex = i;
0925: }
0926:
0927: views.add(freeIndex, new WeakReference(view));
0928: }
0929:
0930: /**
0931: * Removes all internal references to a view. It's not possible to restore the view to the previous location
0932: * after this method has been called.
0933: *
0934: * If the view is located in the window tree where this is the root nothing happens.
0935: *
0936: * @param view all internal references to this view are removed
0937: * @since IDW 1.4.0
0938: */
0939: public void removeView(View view) {
0940: if (view.getRootWindow() == this )
0941: return;
0942:
0943: for (int i = 0; i < views.size(); i++) {
0944: View v = (View) ((WeakReference) views.get(i)).get();
0945:
0946: if (v == view) {
0947: views.remove(i);
0948: break;
0949: }
0950: }
0951:
0952: getWindowItem().removeWindowRefs(view);
0953: }
0954:
0955: private void internalSetMaximizedWindow(DockingWindow window) {
0956: if (window == maximizedWindow)
0957: return;
0958:
0959: DockingWindow focusWindow = null;
0960:
0961: if (maximizedWindow != null) {
0962: DockingWindow oldMaximized = maximizedWindow;
0963: maximizedWindow = null;
0964:
0965: if (oldMaximized.getWindowParent() != null)
0966: oldMaximized.getWindowParent().restoreWindowComponent(
0967: oldMaximized);
0968:
0969: if (oldMaximized != this .window)
0970: windowPanel.remove(oldMaximized);
0971:
0972: focusWindow = oldMaximized;
0973: fireWindowRestored(oldMaximized);
0974: }
0975:
0976: maximizedWindow = window;
0977:
0978: if (maximizedWindow != null) {
0979: if (maximizedWindow.getWindowParent() != null)
0980: maximizedWindow.getWindowParent()
0981: .removeWindowComponent(maximizedWindow);
0982:
0983: if (maximizedWindow != this .window) {
0984: windowPanel.add(maximizedWindow);
0985:
0986: if (this .window != null)
0987: this .window.setVisible(false);
0988: }
0989:
0990: maximizedWindow.setVisible(true);
0991:
0992: focusWindow = maximizedWindow;
0993: fireWindowMaximized(maximizedWindow);
0994: } else if (this .window != null) {
0995: this .window.setVisible(true);
0996: }
0997:
0998: if (focusWindow != null)
0999: FocusManager.focusWindow(focusWindow);
1000: }
1001:
1002: private void createWindowBars() {
1003: final Direction[] directions = Direction.getDirections();
1004:
1005: for (int i = 0; i < directions.length; i++) {
1006: windowBars[i] = new WindowBar(this , directions[i]);
1007: windowBars[i].setEnabled(false);
1008: addWindow(windowBars[i]);
1009: layeredPane.add(windowBars[i].getEdgePanel());
1010:
1011: mainPanel.add(windowBars[i], new Point(
1012: directions[i] == Direction.LEFT ? 0
1013: : directions[i] == Direction.RIGHT ? 2 : 1,
1014: directions[i] == Direction.UP ? 0
1015: : directions[i] == Direction.DOWN ? 2 : 1));
1016:
1017: windowBars[i].addPropertyChangeListener("enabled",
1018: new PropertyChangeListener() {
1019: public void propertyChange(
1020: PropertyChangeEvent evt) {
1021: updateButtonVisibility();
1022: }
1023: });
1024: }
1025: }
1026:
1027: JComponent getLayeredPane() {
1028: return layeredPane;
1029: }
1030:
1031: JComponent getWindowPanel() {
1032: return windowPanel;
1033: }
1034:
1035: protected void showChildWindow(DockingWindow window) {
1036: if (maximizedWindow != null && window == this .window)
1037: setMaximizedWindow(null);
1038:
1039: super .showChildWindow(window);
1040: }
1041:
1042: protected void update() {
1043: RootWindowProperties properties = getRootWindowProperties();
1044: properties.getComponentProperties().applyTo(layeredPane);
1045: InternalPropertiesUtil.applyTo(properties
1046: .getShapedPanelProperties(), layeredPane);
1047:
1048: properties.getWindowAreaProperties().applyTo(windowPanel);
1049: InternalPropertiesUtil.applyTo(properties
1050: .getWindowAreaShapedPanelProperties(), windowPanel);
1051:
1052: properties.getDragLabelProperties().applyTo(dragTextLabel);
1053:
1054: if (!heavyweightSupport) {
1055: ShapedPanel dragRectangle = (ShapedPanel) this .dragRectangle;
1056: InternalPropertiesUtil.applyTo(properties
1057: .getDragRectangleShapedPanelProperties(),
1058: dragRectangle);
1059:
1060: if (dragRectangle.getComponentPainter() == null)
1061: dragRectangle
1062: .setComponentPainter(new RectangleComponentPainter(
1063: Color.BLACK, Color.WHITE, properties
1064: .getDragRectangleBorderWidth()));
1065: } else {
1066: HeavyWeightDragRectangle rectangle = (HeavyWeightDragRectangle) dragRectangle;
1067: ComponentPainter painter = properties
1068: .getDragRectangleShapedPanelProperties()
1069: .getComponentPainter();
1070: Color color = painter != null ? painter.getColor(this )
1071: : null;
1072: rectangle.setColor(color != null ? color : Color.BLACK);
1073: rectangle.setBorderWidth(properties
1074: .getDragRectangleBorderWidth());
1075: }
1076: }
1077:
1078: void internalStartDrag(JComponent component) {
1079: currentDragRootPane = getRootPane();
1080:
1081: FloatingWindow fwStartedDrag = DockingUtil
1082: .getFloatingWindowFor((DockingWindow) component);
1083:
1084: for (int i = 0; i < floatingWindows.size(); i++) {
1085: FloatingWindow fw = (FloatingWindow) floatingWindows.get(i);
1086: fw.startDrag();
1087: if (dummyFrame != null && fw != fwStartedDrag)
1088: ((JDialog) (fw.getTopLevelAncestor())).toFront();
1089: }
1090:
1091: if (dummyFrame != null && fwStartedDrag != null)
1092: ((JDialog) (fwStartedDrag.getTopLevelAncestor())).toFront();
1093: }
1094:
1095: void stopDrag() {
1096: if (dragTextContainer.getParent() != null) {
1097: if (!heavyweightSupport)
1098: dragTextContainer.getParent().repaint(
1099: dragTextContainer.getX(),
1100: dragTextContainer.getY(),
1101: dragTextContainer.getWidth(),
1102: dragTextContainer.getHeight());
1103: dragTextContainer.getParent().remove(dragTextContainer);
1104: //dragTextContainer.setVisible(false);
1105: }
1106:
1107: if (dragTextWindow != null) {
1108: dragTextWindow.setVisible(false);
1109: dragTextWindow.dispose();
1110: dragTextWindow = null;
1111: }
1112:
1113: if (dragRectangle.getParent() != null) {
1114: if (!heavyweightSupport)
1115: dragRectangle.getParent().repaint(dragRectangle.getX(),
1116: dragRectangle.getY(), dragRectangle.getWidth(),
1117: dragRectangle.getHeight());
1118: dragRectangle.getParent().remove(dragRectangle);
1119: }
1120:
1121: CursorManager.resetGlobalCursor(getCurrentDragRootPane());
1122: currentDragRootPane = null;
1123:
1124: for (int i = 0; i < floatingWindows.size(); i++) {
1125: ((FloatingWindow) floatingWindows.get(i)).stopDrag();
1126: }
1127: }
1128:
1129: boolean floatingWindowsContainPoint(Point p) {
1130: for (int i = 0; i < floatingWindows.size(); i++) {
1131: FloatingWindow c = ((FloatingWindow) floatingWindows.get(i));
1132:
1133: if (c.isShowing()
1134: && c.windowContainsPoint(SwingUtilities
1135: .convertPoint(getRootPane(), p, c)))
1136: return true;
1137: }
1138:
1139: return false;
1140: }
1141:
1142: void setCurrentDragRootPane(JRootPane rootPane) {
1143: //if (rootPane != currentDragRootPane) {
1144: CursorManager.resetGlobalCursor(getCurrentDragRootPane());
1145: currentDragRootPane = rootPane;
1146: //}
1147: }
1148:
1149: JRootPane getCurrentDragRootPane() {
1150: return currentDragRootPane == null ? getRootPane()
1151: : currentDragRootPane;
1152: }
1153:
1154: Component getTopLevelComponent() {
1155: Component c = getTopLevelAncestor();
1156:
1157: if (c instanceof JFrame || c instanceof JDialog)
1158: return c;
1159:
1160: if (dummyFrame == null) {
1161: dummyFrame = new JFrame("");
1162: dummyFrame
1163: .setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
1164: }
1165:
1166: return dummyFrame;
1167: }
1168:
1169: boolean isHeavyweightSupported() {
1170: return heavyweightSupport;
1171: }
1172:
1173: private static boolean reparent(Container parent, Component c) {
1174: if (c.getParent() != parent) {
1175: if (c.getParent() != null)
1176: c.getParent().remove(c);
1177:
1178: parent.add(c);
1179: return true;
1180: }
1181:
1182: return false;
1183: }
1184:
1185: void setDragCursor(Cursor cursor) {
1186: CursorManager.setGlobalCursor(getCurrentDragRootPane(), cursor);
1187:
1188: if (dragTextWindow != null)
1189: dragTextWindow.setCursor(cursor);
1190: }
1191:
1192: void setDragText(Point textPoint, String text) {
1193: if (textPoint != null) {
1194: JRootPane currentDragRootPane = getCurrentDragRootPane();
1195:
1196: if (reparent(currentDragRootPane.getLayeredPane(),
1197: dragTextContainer))
1198: currentDragRootPane.getLayeredPane().setLayer(
1199: dragTextContainer,
1200: JLayeredPane.DRAG_LAYER.intValue()
1201: + (heavyweightSupport ? -1 : 1));
1202:
1203: dragTextLabel.setText(text);
1204: dragTextContainer.setSize(dragTextContainer
1205: .getPreferredSize());
1206: Point p2 = SwingUtilities.convertPoint(currentDragRootPane,
1207: textPoint, dragTextContainer.getParent());
1208: int yLocationOffs = dragTextLabel.getInsets().bottom;
1209: dragTextContainer
1210: .setLocation(
1211: (int) (p2.getX() - dragTextContainer
1212: .getWidth() / 2),
1213: (int) (p2.getY()
1214: - dragTextContainer.getHeight() + yLocationOffs));
1215:
1216: // Drag text window
1217: Point rp = SwingUtilities.convertPoint(currentDragRootPane,
1218: textPoint, getRootPane());
1219:
1220: if (!getRootPane().contains(rp)
1221: && !floatingWindowsContainPoint(rp)) {
1222: dragTextContainer.setVisible(false);
1223:
1224: if (dragTextWindow == null) {
1225: Component c = getTopLevelComponent();
1226: if (c instanceof Frame)
1227: dragTextWindow = new DragLabelWindow((Frame) c);
1228: else if (c instanceof Dialog)
1229: dragTextWindow = new DragLabelWindow((Dialog) c);
1230:
1231: if (dragTextWindow != null) {
1232: dragTextWindow.setFocusableWindowState(false);
1233: dragTextWindow.setFocusable(false);
1234: getRootWindowProperties()
1235: .getDragLabelProperties().applyTo(
1236: dragTextWindow.getLabel());
1237: //dragTextWindow.setSize(dragText.getSize());
1238: }
1239: }
1240:
1241: if (dragTextWindow != null) {
1242: dragTextWindow.getLabel().setText(text);
1243: SwingUtilities.convertPointToScreen(textPoint,
1244: currentDragRootPane);
1245: dragTextWindow
1246: .setLocation(
1247: textPoint.x
1248: - dragTextContainer
1249: .getWidth() / 2,
1250: (int) (textPoint.y
1251: - dragTextContainer
1252: .getHeight() + yLocationOffs));
1253: dragTextWindow.setVisible(true);
1254: }
1255: } else {
1256: dragTextContainer.setVisible(true);
1257: if (heavyweightSupport)
1258: dragTextContainer.repaint();
1259:
1260: if (dragTextWindow != null)
1261: dragTextWindow.setVisible(false);
1262: }
1263: } else if (dragTextContainer.getParent() != null) {
1264: dragTextContainer.setVisible(false);
1265:
1266: if (dragTextWindow != null)
1267: dragTextWindow.setVisible(false);
1268: }
1269: }
1270:
1271: void setDragRectangle(Rectangle rect) {
1272: if (rect != null) {
1273: if (reparent(getCurrentDragRootPane().getLayeredPane(),
1274: dragRectangle))
1275: getCurrentDragRootPane().getLayeredPane().setLayer(
1276: dragRectangle,
1277: JLayeredPane.DRAG_LAYER.intValue()
1278: + (heavyweightSupport ? -1 : 0));
1279:
1280: dragRectangle.setBounds(SwingUtilities.convertRectangle(
1281: this , rect, dragRectangle.getParent()));
1282: dragRectangle.setVisible(true);
1283: } else if (dragRectangle.getParent() != null)
1284: dragRectangle.setVisible(false);
1285: }
1286:
1287: protected void doReplace(DockingWindow oldWindow,
1288: DockingWindow newWindow) {
1289: if (oldWindow == window) {
1290: if (window != null) {
1291: windowPanel.remove(window);
1292: window.setVisible(true);
1293: }
1294:
1295: window = newWindow;
1296:
1297: if (window != null) {
1298: if (maximizedWindow != null)
1299: window.setVisible(false);
1300:
1301: windowPanel.add(window);
1302: windowPanel.revalidate();
1303: //revalidate();
1304: }
1305: }
1306: }
1307:
1308: protected void doRemoveWindow(DockingWindow window) {
1309: if (window == this .window) {
1310: windowPanel.remove(window);
1311: this .window.setVisible(true);
1312: this .window = null;
1313: }
1314:
1315: repaint();
1316: }
1317:
1318: public RootWindow getRootWindow() {
1319: return this ;
1320: }
1321:
1322: protected boolean acceptsSplitWith(DockingWindow window) {
1323: return false;
1324: }
1325:
1326: protected DropAction doAcceptDrop(Point p, DockingWindow window) {
1327: if (maximizedWindow != null) {
1328: Point p2 = SwingUtilities.convertPoint(this , p,
1329: maximizedWindow);
1330:
1331: if (maximizedWindow.contains(p2)
1332: && getChildDropFilter().acceptDrop(
1333: new ChildDropInfo(window, this , p,
1334: maximizedWindow))) {
1335: DropAction da = maximizedWindow.acceptDrop(p2, window);
1336:
1337: if (da != null)
1338: return da;
1339: }
1340: }
1341:
1342: return super .doAcceptDrop(p, window);
1343: }
1344:
1345: protected DropAction acceptInteriorDrop(Point p,
1346: DockingWindow window) {
1347: if (this .window != null)
1348: return null;
1349:
1350: if (getInteriorDropFilter().acceptDrop(
1351: new InteriorDropInfo(window, this , p)))
1352: return new DropAction() {
1353: public void execute(DockingWindow window,
1354: MouseEvent mouseEvent) {
1355: setWindow(window);
1356: }
1357: };
1358:
1359: return null;
1360: }
1361:
1362: protected PropertyMap getPropertyObject() {
1363: return getRootWindowProperties().getMap();
1364: }
1365:
1366: protected PropertyMap createPropertyObject() {
1367: return new RootWindowProperties().getMap();
1368: }
1369:
1370: boolean windowBarEnabled() {
1371: for (int i = 0; i < windowBars.length; i++)
1372: if (windowBars[i].isEnabled())
1373: return true;
1374:
1375: return false;
1376: }
1377:
1378: void removeWindowComponent(DockingWindow window) {
1379: }
1380:
1381: void restoreWindowComponent(DockingWindow window) {
1382: }
1383:
1384: protected void cleanUpModel() {
1385: if (!cleanUpModel) {
1386: cleanUpModel = true;
1387: SwingUtilities.invokeLater(modelCleanUpEvent);
1388: }
1389: }
1390:
1391: protected boolean isShowingInRootWindow() {
1392: return true;
1393: }
1394:
1395: public void updateUI() {
1396: super .updateUI();
1397:
1398: if (floatingWindows != null) {
1399: for (int i = 0; i < floatingWindows.size(); i++)
1400: SwingUtilities
1401: .updateComponentTreeUI(((JComponent) floatingWindows
1402: .get(i)).getTopLevelAncestor());
1403:
1404: for (int i = 0; i < views.size(); i++) {
1405: View v = (View) ((WeakReference) views.get(i)).get();
1406: if (v != null && v.getWindowParent() == null)
1407: SwingUtilities.updateComponentTreeUI(v);
1408: }
1409: }
1410: }
1411:
1412: protected void paintComponent(final Graphics g) {
1413: //((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
1414: super.paintComponent(g);
1415: }
1416: }
|