0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.core.windows.view.dnd;
0043:
0044: import java.awt.*;
0045: import java.awt.datatransfer.*;
0046: import java.awt.dnd.*;
0047: import java.io.IOException;
0048: import java.lang.ref.*;
0049: import java.util.*;
0050: import java.util.logging.Level;
0051: import java.util.logging.Logger;
0052: import javax.swing.*;
0053: import org.netbeans.core.windows.*;
0054: import org.netbeans.core.windows.view.*;
0055: import org.netbeans.core.windows.view.ui.*;
0056: import org.openide.util.WeakSet;
0057: import org.openide.windows.TopComponent;
0058:
0059: /**
0060: * Manager for window DnD. Manages notifying all opened
0061: * <code>ModeContainer</code>'s to be notified about starting
0062: * and finishe window drag operation.
0063: *
0064: *
0065: * @author Peter Zavadsky
0066: *
0067: * @see TopComponentDragSupport
0068: * @see DropTargetGlassPane
0069: */
0070: public final class WindowDnDManager implements
0071: DropTargetGlassPane.Observer, DropTargetGlassPane.Informer {
0072:
0073: private final TopComponentDragSupport topComponentDragSupport = new TopComponentDragSupport(
0074: this );
0075:
0076: /** Only instance of drag source used for window system DnD. */
0077: private DragSource windowDragSource;
0078:
0079: /** Flag indicating the drag operation is in progress. */
0080: private boolean dragging;
0081:
0082: // XXX #21917. The flag is not correct in jdk dnd framework,
0083: // this field is used to workaround the problem. Be aware is
0084: // valisd only for DnD of window component.
0085: /** Flag keeping info about last drop operation. */
0086: private boolean dropSuccess;
0087:
0088: /** Maps root panes to original glass panes. */
0089: private final Map<JRootPane, Component> root2glass = new HashMap<JRootPane, Component>();
0090:
0091: /** Set of floating frame types, i.e. separate windows. */
0092: private final Set<Component> floatingFrames = new WeakSet<Component>(
0093: 4);
0094:
0095: /** Used to hack the last Drop target to clear its indication. */
0096: private Reference<DropTargetGlassPane> lastTargetWRef = new WeakReference<DropTargetGlassPane>(
0097: null);
0098:
0099: /** Accesses view. */
0100: private final ViewAccessor viewAccessor;
0101:
0102: // Helpers
0103: private TopComponentDroppable startingDroppable;
0104: private Point startingPoint;
0105: // XXX Normal way it should be possible to retrieve from DnD events.
0106: private TopComponent startingTransfer;
0107: /** kind of mode into which belonged last dragged TopComponent at that time */
0108: private int draggedKind;
0109:
0110: /** drag feedback handler, listen to the mouse pointer motion during the drag */
0111: private MotionListener motionListener;
0112:
0113: /** Keeps ref to fake center panel droppable. */
0114: private static Reference<CenterPanelDroppable> centerDropWRef = new WeakReference<CenterPanelDroppable>(
0115: null);
0116:
0117: /** Keeps ref to fake editor area droppable. */
0118: private static Reference<EditorAreaDroppable> editorDropWRef = new WeakReference<EditorAreaDroppable>(
0119: null);
0120:
0121: /** Debugging flag. */
0122: private static final boolean DEBUG = Debug
0123: .isLoggable(WindowDnDManager.class);
0124:
0125: /** Creates a new instance of <code>WindowsDnDManager</code>. */
0126: public WindowDnDManager(ViewAccessor viewAccessor) {
0127: this .viewAccessor = viewAccessor;
0128:
0129: // PENDING Be aware it is added only once.
0130: Toolkit.getDefaultToolkit().addAWTEventListener(
0131: topComponentDragSupport,
0132: AWTEvent.MOUSE_EVENT_MASK
0133: | AWTEvent.MOUSE_MOTION_EVENT_MASK);
0134: }
0135:
0136: /** Indicates whether the window drag and drop is enabled. */
0137: public static boolean isDnDEnabled() {
0138: return !Constants.SWITCH_DND_DISABLE;
0139: }
0140:
0141: /** Gets the only current instance of <code>DragSource</code> used in
0142: * window system DnD. */
0143: public synchronized DragSource getWindowDragSource() {
0144: if (windowDragSource == null) {
0145: windowDragSource = new DragSource();
0146: windowDragSource
0147: .addDragSourceMotionListener(getMotionListener());
0148: }
0149: return windowDragSource;
0150: }
0151:
0152: /** Accessor for mouse motion listener */
0153: MotionListener getMotionListener() {
0154: if (motionListener == null) {
0155: motionListener = new MotionListener(this ,
0156: topComponentDragSupport);
0157: }
0158: return motionListener;
0159: }
0160:
0161: /** Indicates whether the drag is in progress or not. */
0162: public boolean isDragging() {
0163: return dragging;
0164: }
0165:
0166: /** Sets the <code>dropSuccess</code> flag. */
0167: public void setDropSuccess(boolean dropSuccess) {
0168: this .dropSuccess = dropSuccess;
0169: }
0170:
0171: /** Indicates whether the last drop operation was successful. */
0172: public boolean isDropSuccess() {
0173: return dropSuccess;
0174: }
0175:
0176: /**Sets the last drop target compoent over which hovered the mouse.
0177: * Hacking purpose only. */
0178: public void setLastDropTarget(DropTargetGlassPane target) {
0179: if (target != lastTargetWRef.get()) {
0180: lastTargetWRef = new WeakReference<DropTargetGlassPane>(
0181: target);
0182: }
0183: }
0184:
0185: // XXX try out to recover the DnD,
0186: // currently impossible no API see #21791, no such API.
0187: /** Tries to reset window DnD system in case some DnD problem occured. */
0188: public void resetDragSource() {
0189: dragFinished();
0190: }
0191:
0192: public TopComponentDroppable getStartingDroppable() {
0193: return startingDroppable;
0194: }
0195:
0196: public Point getStartingPoint() {
0197: return startingPoint;
0198: }
0199:
0200: public TopComponent getStartingTransfer() {
0201: return startingTransfer;
0202: }
0203:
0204: /** Called when there is pending drag operation to be started.
0205: * Informs all currently opened <code>ModeContainer</code>'s implementing
0206: * <code>ModeContainer.DropInidicator</code> interface about
0207: * starting drag operation. */
0208: public void dragStarting(TopComponentDroppable startingDroppable,
0209: Point startingPoint, TopComponent startingTransfer) {
0210: if (DEBUG) {
0211: debugLog(""); // NOI18N
0212: debugLog("dragStarting"); // NOI18N
0213: }
0214:
0215: this .startingDroppable = startingDroppable;
0216: this .startingPoint = startingPoint;
0217: this .startingTransfer = startingTransfer;
0218: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
0219: .findMode(startingTransfer);
0220: this .draggedKind = mode != null ? mode.getKind()
0221: : Constants.MODE_KIND_EDITOR;
0222:
0223: // exclude dragged separate view
0224: /*Window rpc = SwingUtilities.getWindowAncestor(startingTransfer);
0225: if (rpc != null && !WindowManagerImpl.getInstance().getMainWindow().equals(rpc)) {
0226: ZOrderManager.getInstance().setExcludeFromOrder((RootPaneContainer)rpc, true);
0227: }*/
0228:
0229: Map<JRootPane, Component> addedRoots = new HashMap<JRootPane, Component>();
0230: Set<Component> addedFrames = new HashSet<Component>();
0231:
0232: for (Component comp : viewAccessor.getModeComponents()) {
0233: if (comp instanceof TopComponentDroppable) {
0234: // Find root pane.
0235: JRootPane root = null;
0236: if (comp instanceof RootPaneContainer) {
0237: root = ((RootPaneContainer) comp).getRootPane();
0238: } else {
0239: RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
0240: .getAncestorOfClass(
0241: RootPaneContainer.class, comp);
0242: if (rootContainer != null) {
0243: root = rootContainer.getRootPane();
0244: }
0245: }
0246:
0247: if (root != null) {
0248: Component originalGlass = setDropTargetGlassPane(
0249: root, this );
0250: if (originalGlass != null) {
0251: addedRoots.put(root, originalGlass);
0252: }
0253: }
0254: }
0255: }
0256: for (Component w : viewAccessor.getSeparateModeFrames()) {
0257: if (w != null) {
0258: addedFrames.add(w);
0259: }
0260: }
0261:
0262: if (!addedRoots.isEmpty()) {
0263: synchronized (root2glass) {
0264: root2glass.putAll(addedRoots);
0265: }
0266: }
0267:
0268: if (!addedFrames.isEmpty()) {
0269: synchronized (floatingFrames) {
0270: floatingFrames.addAll(addedFrames);
0271: }
0272: }
0273:
0274: dragging = true;
0275: dropSuccess = false;
0276: }
0277:
0278: /** Sets <code>DropTargetGlassPane<code> for specified JRootPane.
0279: * @return original glass pane or null if there was already set drop target
0280: * glass pane */
0281: private static Component setDropTargetGlassPane(JRootPane rootPane,
0282: WindowDnDManager windowDnDManager) {
0283: Component glassPane = rootPane.getGlassPane();
0284: if (glassPane instanceof DropTargetGlassPane) {
0285: // There is already our glass pane.
0286: return null;
0287: }
0288:
0289: DropTargetGlassPane dropGlass = new DropTargetGlassPane(
0290: windowDnDManager);
0291: // Associate with new drop target, and initialize.
0292: new DropTarget(dropGlass, DnDConstants.ACTION_COPY_OR_MOVE,
0293: dropGlass);
0294:
0295: rootPane.setGlassPane(dropGlass);
0296: // !!! Necessary to initialize it after setGlassPane(..),
0297: // i.e. the visibility state.
0298: dropGlass.initialize();
0299:
0300: return glassPane;
0301: }
0302:
0303: /** Called when there finished drag operation.
0304: * Informs all turned on <code>TopComponentDroppable</code>'s
0305: * about fininshed drag and drop. */
0306: public void dragFinished() {
0307: if (DEBUG) {
0308: debugLog(""); // NOI18N
0309: debugLog("dragFinished"); // NOI18N
0310: }
0311:
0312: // include dragged separate view back
0313: /*Window w = SwingUtilities.getWindowAncestor(startingTransfer);
0314: if (w != null && !WindowManagerImpl.getInstance().getMainWindow().equals(w)) {
0315: ZOrderManager.getInstance().setExcludeFromOrder((RootPaneContainer)w, false);
0316: }*/
0317:
0318: // notify motion handler
0319: getMotionListener().dragFinished();
0320:
0321: // PENDING
0322: startingDroppable = null;
0323: startingPoint = null;
0324: startingTransfer = null;
0325:
0326: // Inform the drag support instance about finishing of the DnD.
0327: topComponentDragSupport.dragFinished();
0328:
0329: dragging = false;
0330:
0331: Map<JRootPane, Component> removedRoots;
0332: synchronized (root2glass) {
0333: removedRoots = new HashMap<JRootPane, Component>(root2glass);
0334: root2glass.clear();
0335: }
0336:
0337: for (JRootPane root : removedRoots.keySet()) {
0338: setOriginalGlassPane(root, removedRoots.get(root));
0339: }
0340: }
0341:
0342: /** Sets orgiginal glass pane to specified root pane. */
0343: private static void setOriginalGlassPane(JRootPane rootPane,
0344: Component originalGlass) {
0345: Component glass = rootPane.getGlassPane();
0346:
0347: if (glass instanceof DropTargetGlassPane) {
0348: DropTargetGlassPane dropGlass = (DropTargetGlassPane) glass;
0349:
0350: // Release the drop target, and unititialize.
0351: dropGlass.setDropTarget(null);
0352: dropGlass.uninitialize();
0353: }
0354:
0355: if (originalGlass != null) {
0356: rootPane.setGlassPane(originalGlass);
0357: }
0358:
0359: // #22962. Not selected JInternalFrame needs to have its glass pane
0360: // switched on to work properly, ensure it is so.
0361: JInternalFrame internalFrame = (JInternalFrame) SwingUtilities
0362: .getAncestorOfClass(JInternalFrame.class, originalGlass);
0363: if (internalFrame != null && !internalFrame.isSelected()
0364: && !originalGlass.isVisible()) {
0365: originalGlass.setVisible(true);
0366: }
0367: }
0368:
0369: // PENDING Better design of this issue, it needs to be performed
0370: // later than dragFinished.
0371: /** Maked post drag finished cleaning. Clears references to separated
0372: * modes */
0373: public void dragFinishedEx() {
0374: synchronized (floatingFrames) {
0375: floatingFrames.clear();
0376: }
0377: }
0378:
0379: /** Gets set of floating frames. */
0380: public Set<Component> getFloatingFrames() {
0381: synchronized (floatingFrames) {
0382: return new HashSet<Component>(floatingFrames);
0383: }
0384: }
0385:
0386: /** Checks whether the point is inside separated (floating) frame
0387: * droppable area. The point is relative to screen. */
0388: public boolean isInFloatingFrame(Point location) {
0389: for (Component w : getFloatingFrames()) {
0390: if (w.getBounds().contains(location)) {
0391: return true;
0392: }
0393: }
0394:
0395: return false;
0396: }
0397:
0398: // XXX
0399: public boolean isCopyOperationPossible() {
0400: return topComponentDragSupport.isCopyOperationPossible();
0401: }
0402:
0403: public Controller getController() {
0404: return viewAccessor.getController();
0405: }
0406:
0407: private static void debugLog(String message) {
0408: Debug.log(WindowDnDManager.class, message);
0409: }
0410:
0411: // Helpers>>
0412: /** Checks whether the point is inside main window droppable area.
0413: * The point is relative to screen. */
0414: static boolean isInMainWindow(Point location) {
0415: return WindowManagerImpl.getInstance().getMainWindow()
0416: .getBounds().contains(location);
0417: }
0418:
0419: /** Indicates whether there is a droppable in main window, specified
0420: * by screen location. */
0421: private boolean isInMainWindowDroppable(Point location, int kind,
0422: TopComponent transfer) {
0423: return findMainWindowDroppable(location, kind, transfer) != null;
0424: }
0425:
0426: /** Checks whetner the point is inside one of floating window,
0427: * i.e. separated modes, droppable area. The point is relative to screen. */
0428: private static boolean isInFloatingFrameDroppable(
0429: Set<Component> floatingFrames, Point location, int kind,
0430: TopComponent transfer) {
0431: return findFloatingFrameDroppable(floatingFrames, location,
0432: kind, transfer) != null;
0433: }
0434:
0435: /**
0436: * Tests if given location is in free area or not.
0437: * @param location the location to test
0438: * @param exclude Window to exclude from test (used for fake drag-under effect window)
0439: * @return true when location point is on free screen, not contained in any
0440: * frames or windows of the system, false otherwise
0441: */
0442: private static boolean isInFreeArea(Point location, Window exclude) {
0443: // prepare array of all our windows
0444: Window mainWindow = WindowManagerImpl.getInstance()
0445: .getMainWindow();
0446: Window[] owned = mainWindow.getOwnedWindows();
0447: Window[] frames = Frame.getFrames();
0448: Window[] windows = new Window[owned.length + frames.length];
0449: System.arraycopy(frames, 0, windows, 0, frames.length);
0450: System
0451: .arraycopy(owned, 0, windows, frames.length,
0452: owned.length);
0453:
0454: for (int i = 0; i < windows.length; i++) {
0455: // #114064: exclude fake drar under effect window from the test
0456: if (windows[i] == exclude) {
0457: continue;
0458: }
0459: //#40782 fix. don't take the invisible frames into account when deciding what is
0460: // free space.
0461: if (windows[i].isVisible()
0462: && windows[i].getBounds().contains(location.x,
0463: location.y)) {
0464: return false;
0465: }
0466: }
0467:
0468: return true;
0469: }
0470:
0471: /** Finds <code>TopComponentDroppable</code> from specified screen location. */
0472: private TopComponentDroppable findDroppableFromScreen(
0473: Set<Component> floatingFrames, Point location, int kind,
0474: TopComponent transfer) {
0475:
0476: TopComponentDroppable droppable = findMainWindowDroppable(
0477: location, kind, transfer);
0478: if (droppable != null) {
0479: return droppable;
0480: }
0481:
0482: droppable = findFloatingFrameDroppable(floatingFrames,
0483: location, kind, transfer);
0484: if (droppable != null) {
0485: return droppable;
0486: }
0487:
0488: // // PENDING center panel area. Maybe editor empty area -> revise later.
0489: // if(isAroundCenterPanel(location)) {
0490: // return getCenterPanelDroppable();
0491: // }
0492:
0493: if (isInFreeArea(location, motionListener.fakeWindow)) {
0494: return getFreeAreaDroppable(location);
0495: }
0496: return null;
0497: }
0498:
0499: private CenterSlidingDroppable lastSlideDroppable;
0500:
0501: /** Gets droppable from main window, specified by screen location.
0502: * Helper method. */
0503: private TopComponentDroppable findMainWindowDroppable(
0504: Point location, int kind, TopComponent transfer) {
0505:
0506: MainWindow mainWindow = (MainWindow) WindowManagerImpl
0507: .getInstance().getMainWindow();
0508:
0509: if (!ZOrderManager.getInstance().isOnTop(mainWindow, location)) {
0510: return null;
0511: }
0512:
0513: Point p = new Point(location);
0514: SwingUtilities.convertPointFromScreen(p, mainWindow
0515: .getContentPane());
0516: if (lastSlideDroppable != null) {
0517: if (lastSlideDroppable.isWithinSlide(p)) {
0518: return lastSlideDroppable;
0519: }
0520: }
0521: TopComponentDroppable droppable = findSlideDroppable(viewAccessor
0522: .getSlidingModeComponent(Constants.LEFT));
0523: if (droppable != null) {
0524: CenterSlidingDroppable drop = new CenterSlidingDroppable(
0525: viewAccessor, droppable, Constants.LEFT);
0526: if (drop.isWithinSlide(p)) {
0527: lastSlideDroppable = drop;
0528: return drop;
0529: }
0530: }
0531: droppable = findSlideDroppable(viewAccessor
0532: .getSlidingModeComponent(Constants.RIGHT));
0533: if (droppable != null) {
0534: CenterSlidingDroppable drop = new CenterSlidingDroppable(
0535: viewAccessor, droppable, Constants.RIGHT);
0536: if (drop.isWithinSlide(p)) {
0537: lastSlideDroppable = drop;
0538: return drop;
0539: }
0540: }
0541: droppable = findSlideDroppable(viewAccessor
0542: .getSlidingModeComponent(Constants.BOTTOM));
0543: if (droppable != null) {
0544: CenterSlidingDroppable drop = new CenterSlidingDroppable(
0545: viewAccessor, droppable, Constants.BOTTOM);
0546: if (drop.isWithinSlide(p)) {
0547: lastSlideDroppable = drop;
0548: return drop;
0549: }
0550: }
0551: lastSlideDroppable = null;
0552: if (isNearEditorEdge(location, viewAccessor, kind)) {
0553: return getEditorAreaDroppable();
0554: }
0555: if (isNearEdge(location, viewAccessor)) {
0556: return getCenterPanelDroppable();
0557: }
0558: Point mainP = new Point(location);
0559: SwingUtilities.convertPointFromScreen(mainP, mainWindow);
0560: return findDroppable(mainWindow, mainP, kind, transfer);
0561: }
0562:
0563: private static TopComponentDroppable findSlideDroppable(
0564: Component comp) {
0565: TopComponentDroppable droppable = null;
0566: if (comp instanceof TopComponentDroppable) {
0567: droppable = (TopComponentDroppable) comp;
0568: } else {
0569: droppable = (TopComponentDroppable) SwingUtilities
0570: .getAncestorOfClass(TopComponentDroppable.class,
0571: comp);
0572: }
0573: return droppable;
0574: }
0575:
0576: /** Gets droppable from separated (floating) window, specified
0577: * by screen location. Helper method. */
0578: private static TopComponentDroppable findFloatingFrameDroppable(
0579: Set<Component> floatingFrames, Point location, int kind,
0580: TopComponent transfer) {
0581: for (Component comp : floatingFrames) {
0582: Rectangle bounds = comp.getBounds();
0583:
0584: if (bounds.contains(location)
0585: && ZOrderManager.getInstance().isOnTop(
0586: (RootPaneContainer) comp, location)) {
0587: TopComponentDroppable droppable = findDroppable(comp,
0588: new Point(location.x - bounds.x, location.y
0589: - bounds.y), kind, transfer);
0590: if (droppable != null) {
0591: return droppable;
0592: }
0593: }
0594: }
0595:
0596: return null;
0597: }
0598:
0599: /** Finds <code>TopComponentDroppable</code> for the location in component.
0600: * The location has to be relative to the specified component. Then the
0601: * method finds if there is a droppable component in the hierarchy, which
0602: * also contains the specified location.
0603: * Utilitity method. */
0604: private static TopComponentDroppable findDroppable(Component comp,
0605: Point location, int kind, TopComponent transfer) {
0606: RootPaneContainer rpc;
0607: if (comp instanceof RootPaneContainer) {
0608: rpc = (RootPaneContainer) comp;
0609: } else {
0610: Window w = SwingUtilities.getWindowAncestor(comp);
0611: if (w instanceof RootPaneContainer) {
0612: rpc = (RootPaneContainer) w;
0613: } else {
0614: return null;
0615: }
0616: }
0617:
0618: Component contentPane = rpc.getContentPane();
0619: location = SwingUtilities.convertPoint(comp, location,
0620: contentPane);
0621: Component deepest = SwingUtilities.getDeepestComponentAt(
0622: contentPane, location.x, location.y);
0623:
0624: if (deepest instanceof MultiSplitPane) {
0625: MultiSplitPane splitPane = (MultiSplitPane) deepest;
0626: int dx = 0, dy = 0;
0627: if (splitPane.isHorizontalSplit())
0628: dx = splitPane.getDividerSize() + 1;
0629: else
0630: dy = splitPane.getDividerSize() + 1;
0631: Point pt = SwingUtilities.convertPoint(contentPane,
0632: location, deepest);
0633: deepest = SwingUtilities.getDeepestComponentAt(deepest,
0634: pt.x + dx, pt.y + dy);
0635: }
0636:
0637: if (deepest instanceof TopComponentDroppable) {
0638: TopComponentDroppable droppable = (TopComponentDroppable) deepest;
0639: if (droppable.supportsKind(kind, transfer)) {
0640: return droppable;
0641: }
0642: }
0643:
0644: while (deepest != null) {
0645: TopComponentDroppable nextDroppable = (TopComponentDroppable) SwingUtilities
0646: .getAncestorOfClass(TopComponentDroppable.class,
0647: deepest);
0648: if (nextDroppable != null
0649: && nextDroppable.supportsKind(kind, transfer)) {
0650: return nextDroppable;
0651: }
0652: deepest = (Component) nextDroppable;
0653: }
0654: return null;
0655: }
0656:
0657: /** Indicates whether the cursor is around center panel of main window.
0658: * In that case is needed also to provide a drop. */
0659: static boolean isAroundCenterPanel(Point location) {
0660: Component desktop = ((MainWindow) WindowManagerImpl
0661: .getInstance().getMainWindow()).getDesktop();
0662: if (desktop == null) {
0663: return false;
0664: }
0665:
0666: Point p = new Point(location);
0667: SwingUtilities.convertPointFromScreen(p, desktop.getParent());
0668: Rectangle centerBounds = desktop.getBounds();
0669:
0670: if (!centerBounds.contains(p)) {
0671: centerBounds.grow(Constants.DROP_AREA_SIZE,
0672: Constants.DROP_AREA_SIZE);
0673: if (centerBounds.contains(p)) {
0674: return true;
0675: }
0676: }
0677: return false;
0678: }
0679:
0680: /** Indicates whether the cursor is around the editor area of the main window.
0681: * In that case is needed also to provide a drop. */
0682: static boolean isNearEditorEdge(Point location,
0683: ViewAccessor viewAccessor, int kind) {
0684: Component editor = WindowManagerImpl.getInstance()
0685: .getEditorAreaComponent();
0686: if (editor == null) {
0687: return false;
0688: }
0689: Point p = new Point(location);
0690: SwingUtilities.convertPointFromScreen(p, editor.getParent());
0691: Rectangle editorBounds = editor.getBounds();
0692: editorBounds.y -= 10;
0693: editorBounds.height += 10;
0694: Rectangle shrinked = editor.getBounds();
0695: shrinked.grow(-10, 0);
0696: shrinked.height -= 10;
0697: Component dr = viewAccessor
0698: .getSlidingModeComponent(Constants.RIGHT);
0699: if (dr != null) {
0700: shrinked.width = shrinked.width - dr.getBounds().width;
0701: }
0702: dr = viewAccessor.getSlidingModeComponent(Constants.BOTTOM);
0703: if (dr != null) {
0704: shrinked.height = shrinked.height - dr.getBounds().height;
0705: }
0706: return editorBounds.contains(p) && !shrinked.contains(p)
0707: && kind == Constants.MODE_KIND_EDITOR;
0708: }
0709:
0710: /** Indicates whether the cursor is around center panel of main window.
0711: * In that case is needed also to provide a drop. */
0712: static boolean isNearEdge(Point location, ViewAccessor viewAccessor) {
0713: Component desktop = ((MainWindow) WindowManagerImpl
0714: .getInstance().getMainWindow()).getDesktop();
0715: if (desktop == null) {
0716: return false;
0717: }
0718: Point p = new Point(location);
0719: SwingUtilities.convertPointFromScreen(p, desktop);
0720: Rectangle centerBounds = desktop.getBounds();
0721: centerBounds.y -= 20;
0722: centerBounds.height += 20;
0723: Rectangle shrinked = desktop.getBounds();
0724: shrinked.grow(-10, 0);
0725: shrinked.height -= 10;
0726: Component dr = viewAccessor
0727: .getSlidingModeComponent(Constants.LEFT);
0728: if (dr != null) {
0729: shrinked.x = shrinked.x + dr.getBounds().width;
0730: shrinked.width = shrinked.width - dr.getBounds().width;
0731: }
0732: dr = viewAccessor.getSlidingModeComponent(Constants.RIGHT);
0733: if (dr != null) {
0734: shrinked.width = shrinked.width - dr.getBounds().width;
0735: }
0736: dr = viewAccessor.getSlidingModeComponent(Constants.BOTTOM);
0737: if (dr != null) {
0738: shrinked.height = shrinked.height - dr.getBounds().height;
0739: }
0740: boolean cont = centerBounds.contains(p)
0741: && !shrinked.contains(p);
0742:
0743: return cont;
0744: }
0745:
0746: /** Creates fake droppable for center panel. */
0747: private TopComponentDroppable getCenterPanelDroppable() {
0748: CenterPanelDroppable droppable = centerDropWRef.get();
0749:
0750: if (droppable == null) {
0751: droppable = new CenterPanelDroppable();
0752: centerDropWRef = new WeakReference<CenterPanelDroppable>(
0753: droppable);
0754: }
0755:
0756: return droppable;
0757: }
0758:
0759: private static TopComponentDroppable getFreeAreaDroppable(
0760: Point location) {
0761: return new FreeAreaDroppable(location);
0762: }
0763:
0764: /** Creates fake droppable for editor area. */
0765: private TopComponentDroppable getEditorAreaDroppable() {
0766: EditorAreaDroppable droppable = editorDropWRef.get();
0767:
0768: if (droppable == null) {
0769: droppable = new EditorAreaDroppable();
0770: editorDropWRef = new WeakReference<EditorAreaDroppable>(
0771: droppable);
0772: }
0773:
0774: return droppable;
0775: }
0776:
0777: /**
0778: * Tries to perform actual drop.
0779: * @param location screen location */
0780: boolean tryPerformDrop(Controller controller,
0781: Set<Component> floatingFrames, Point location,
0782: int dropAction, Transferable transferable) {
0783: TopComponent[] tcArray = extractTopComponent(
0784: dropAction == DnDConstants.ACTION_COPY, transferable);
0785:
0786: if (tcArray == null || tcArray.length == 0) {
0787: return false;
0788: }
0789:
0790: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
0791: .findMode(tcArray[0]);
0792: int kind = mode != null ? mode.getKind()
0793: : Constants.MODE_KIND_EDITOR;
0794:
0795: TopComponentDroppable droppable = findDroppableFromScreen(
0796: floatingFrames, location, kind, tcArray[0]);
0797: if (droppable == null) {
0798: return false;
0799: }
0800:
0801: Component dropComponent = droppable.getDropComponent();
0802: if (dropComponent != null) {
0803: SwingUtilities.convertPointFromScreen(location,
0804: dropComponent);
0805: }
0806: return performDrop(controller, droppable, dropAction, tcArray,
0807: location, draggedKind);
0808: }
0809:
0810: /** Extracts <code>TopComponent</code> instance from
0811: * <code>Transferable</code> according the <code>dropAction</code>.
0812: * Utility method. */
0813: static TopComponent[] extractTopComponent(boolean clone,
0814: Transferable tr) {
0815: DataFlavor df = getDataFlavorForDropAction(clone);
0816:
0817: if (df == null) {
0818: // No data flavor -> unsupported drop action.
0819: return null;
0820: }
0821:
0822: // Test whether the requested dataflavor is supported by transferable.
0823: if (tr.isDataFlavorSupported(df)) {
0824: try {
0825: TopComponent tc;
0826:
0827: if (clone) {
0828: TopComponent.Cloneable ctc = (TopComponent.Cloneable) tr
0829: .getTransferData(df);
0830:
0831: // "Copy" the top component.
0832: tc = ctc.cloneComponent();
0833: } else {
0834: tc = (TopComponent) tr.getTransferData(df);
0835: }
0836:
0837: return new TopComponent[] { tc };
0838: } catch (UnsupportedFlavorException ufe) {
0839: Logger.getLogger(WindowDnDManager.class.getName()).log(
0840: Level.WARNING, null, ufe);
0841: } catch (IOException ioe) {
0842: Logger.getLogger(WindowDnDManager.class.getName()).log(
0843: Level.WARNING, null, ioe);
0844: }
0845: }
0846:
0847: df = new DataFlavor(
0848: TopComponentDragSupport.MIME_TOP_COMPONENT_ARRAY, null);
0849: if (tr.isDataFlavorSupported(df)) {
0850: try {
0851: return (TopComponent[]) tr.getTransferData(df);
0852: } catch (UnsupportedFlavorException ufe) {
0853: Logger.getLogger(WindowDnDManager.class.getName()).log(
0854: Level.WARNING, null, ufe);
0855: } catch (IOException ioe) {
0856: Logger.getLogger(WindowDnDManager.class.getName()).log(
0857: Level.WARNING, null, ioe);
0858: }
0859: }
0860:
0861: return null;
0862: }
0863:
0864: /** Gets <code>DataFlavor</code> for specific drop action type.
0865: * Helper utility method. */
0866: private static DataFlavor getDataFlavorForDropAction(boolean clone) {
0867: // Create needed dataflavor.
0868: DataFlavor df;
0869: if (clone) {
0870: df = new DataFlavor(
0871: TopComponentDragSupport.MIME_TOP_COMPONENT_CLONEABLE,
0872: null);
0873: } else {
0874: df = new DataFlavor(
0875: TopComponentDragSupport.MIME_TOP_COMPONENT, null);
0876: }
0877:
0878: return df;
0879: }
0880:
0881: /**
0882: * Performs actual drop operation. Called from DropTargetListener.
0883: * @return <code>true</code> if the drop was successful */
0884: private static boolean performDrop(Controller controller,
0885: TopComponentDroppable droppable, int dropAction,
0886: TopComponent[] tcArray, Point location, int draggedKind) {
0887: if (DEBUG) {
0888: debugLog(""); // NOI18N
0889: debugLog("performDrop"); // NOI18N
0890: debugLog("droppable=" + droppable); // NOI18N
0891: }
0892:
0893: if (tcArray == null || tcArray.length == 0) {
0894: return true;
0895: }
0896:
0897: if (!droppable.canDrop(tcArray[0], location)) {
0898: return true;
0899: }
0900:
0901: ViewElement viewElement = droppable.getDropViewElement();
0902: Object constr = droppable.getConstraintForLocation(location);
0903:
0904: if (viewElement instanceof EditorView) {
0905: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
0906: .findMode(tcArray[0]);
0907: int kind = mode != null ? mode.getKind()
0908: : Constants.MODE_KIND_EDITOR;
0909: if (kind == Constants.MODE_KIND_EDITOR) {
0910: controller
0911: .userDroppedTopComponentsIntoEmptyEditor(tcArray);
0912: } else {
0913: if (constr == Constants.TOP || constr == Constants.LEFT
0914: || constr == Constants.RIGHT
0915: || constr == Constants.BOTTOM) {
0916: controller.userDroppedTopComponentsAroundEditor(
0917: tcArray, (String) constr, kind);
0918: } else if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
0919: || WindowManagerImpl.getInstance()
0920: .isTopComponentAllowedToMoveAnywhere(
0921: tcArray[0])) {
0922: controller
0923: .userDroppedTopComponentsIntoEmptyEditor(tcArray);
0924: }
0925: }
0926: } else if (viewElement instanceof ModeView) {
0927: ModeView modeView = (ModeView) viewElement;
0928: if (constr == Constants.TOP || constr == Constants.LEFT
0929: || constr == Constants.RIGHT
0930: || constr == Constants.BOTTOM) {
0931: controller.userDroppedTopComponents(modeView, tcArray,
0932: (String) constr);
0933: } else if (constr instanceof Integer) {
0934: controller.userDroppedTopComponents(modeView, tcArray,
0935: ((Integer) constr).intValue());
0936: } else {
0937: controller.userDroppedTopComponents(modeView, tcArray);
0938: }
0939: } else if (viewElement == null) { // XXX around area or free area
0940: if (constr == Constants.TOP || constr == Constants.LEFT
0941: || constr == Constants.RIGHT
0942: || constr == Constants.BOTTOM) { // XXX around area
0943: if (droppable instanceof EditorAreaDroppable) {
0944: controller.userDroppedTopComponentsAroundEditor(
0945: tcArray, (String) constr,
0946: Constants.MODE_KIND_EDITOR);
0947: } else {
0948: controller.userDroppedTopComponentsAround(tcArray,
0949: (String) constr);
0950: }
0951: } else if (constr instanceof Rectangle) { // XXX free area
0952: Rectangle bounds = (Rectangle) constr;
0953: // #38657 Refine bounds.
0954: Component modeComp = SwingUtilities.getAncestorOfClass(
0955: ModeComponent.class, tcArray[0]);
0956: if (modeComp != null) {
0957: bounds.setSize(modeComp.getWidth(), modeComp
0958: .getHeight());
0959: }
0960:
0961: controller.userDroppedTopComponentsIntoFreeArea(
0962: tcArray, bounds, draggedKind);
0963: }
0964: }
0965:
0966: return true;
0967: }
0968:
0969: // Helpers<<
0970:
0971: /** Handles mouse cursors shapes and drag-under feedback during the drag.
0972: */
0973: private static class MotionListener implements
0974: DragSourceMotionListener {
0975:
0976: private final WindowDnDManager windowDnDManager;
0977: private final TopComponentDragSupport topComponentDragSupport;
0978:
0979: private Point previousDragLoc;
0980:
0981: /** window used to simulate drag under effect when dropping to free screen area */
0982: private Window fakeWindow;
0983:
0984: /** helper; true when size of fake window set and known, false otherwise */
0985: private boolean isSizeSet;
0986:
0987: /** Constrtucts the instance.
0988: * Adds the listener to the window dnd <code>DragSource</code>. */
0989: private MotionListener(WindowDnDManager windowDnDManager,
0990: TopComponentDragSupport topComponentDragSupport) {
0991: this .windowDnDManager = windowDnDManager;
0992: this .topComponentDragSupport = topComponentDragSupport;
0993: }
0994:
0995: /** Implements <code>DragSourceMotionListener</code>. */
0996: public void dragMouseMoved(DragSourceDragEvent evt) {
0997: if (DEBUG) {
0998: debugLog("dragMouseMoved evt=" + evt); // NOI18N
0999: }
1000:
1001: Point location = evt.getLocation();
1002: if (location == null) {
1003: return;
1004: }
1005:
1006: // move separate windows along with the mouse
1007: /*if (Constants.MODE_STATE_SEPARATED == mode.getState()) {
1008: handleWindowMove(mode, windowDnDManager.startingTransfer, evt);
1009: }*/
1010: boolean isInMainDroppable = windowDnDManager
1011: .isInMainWindowDroppable(location,
1012: windowDnDManager.draggedKind,
1013: windowDnDManager.startingTransfer);
1014: boolean isInFrameDroppable = isInFloatingFrameDroppable(
1015: windowDnDManager.getFloatingFrames(), location,
1016: windowDnDManager.draggedKind,
1017: windowDnDManager.startingTransfer);
1018: boolean isAroundCenterPanel = isAroundCenterPanel(location);
1019: boolean shouldPaintFakeWindow = false;
1020:
1021: if (isInMainDroppable || isInFrameDroppable
1022: || isAroundCenterPanel) {
1023: TopComponentDroppable droppable = windowDnDManager
1024: .findDroppableFromScreen(windowDnDManager
1025: .getFloatingFrames(), location,
1026: windowDnDManager.draggedKind,
1027: windowDnDManager.startingTransfer);
1028: //hack - can't get the bounds correctly, sometimes freearedroppable gets here..
1029:
1030: if (droppable instanceof FreeAreaDroppable) {
1031: if (WindowManagerImpl.getInstance()
1032: .getEditorAreaState() == Constants.EDITOR_AREA_SEPARATED
1033: && droppable.canDrop(
1034: windowDnDManager.startingTransfer,
1035: location)) {
1036: topComponentDragSupport.setSuccessCursor(true);
1037: } else {
1038: topComponentDragSupport.setUnsuccessCursor();
1039: }
1040: // for the status bar it's null somehow, workarounding by checking for null.. should go away..
1041: } else if (droppable != null) {
1042:
1043: // was probably forgotten to set the lastdrop target, was causing strange repaint side effects when 2 frames overlapped.
1044: JComponent cp = (JComponent) droppable
1045: .getDropComponent();
1046: Component glass = cp.getRootPane().getGlassPane();
1047: if (glass instanceof DropTargetGlassPane) {
1048: windowDnDManager
1049: .setLastDropTarget((DropTargetGlassPane) glass);
1050: }
1051: Point p = new Point(location);
1052: SwingUtilities.convertPointFromScreen(p, droppable
1053: .getDropComponent());
1054: if (droppable.canDrop(
1055: windowDnDManager.startingTransfer, p)) {
1056: topComponentDragSupport.setSuccessCursor(false);
1057: } else {
1058: topComponentDragSupport.setUnsuccessCursor();
1059: }
1060: dragOverDropTarget(location, droppable);
1061: }
1062: } else if (!isInMainWindow(location)
1063: && windowDnDManager.isInFloatingFrame(location)) {
1064: // Simulates success drop in free area.
1065: topComponentDragSupport.setSuccessCursor(false);
1066: } else if (isInFreeArea(location, fakeWindow)
1067: && getFreeAreaDroppable(location)
1068: .canDrop(windowDnDManager.startingTransfer,
1069: location)) {
1070: topComponentDragSupport.setSuccessCursor(true);
1071: // paint fake window during move over free area
1072: // shouldPaintFakeWindow = true;
1073: } else {
1074: topComponentDragSupport.setUnsuccessCursor();
1075: }
1076: paintFakeWindow(shouldPaintFakeWindow, evt);
1077:
1078: if (!isInMainDroppable && !isInFrameDroppable
1079: && !isAroundCenterPanel) {
1080: clearExitedDropTarget();
1081: }
1082: }
1083:
1084: /** Simulates dropOver event, for glass pane to indicate possible drop
1085: * operation. */
1086: private/*static*/void dragOverDropTarget(Point location,
1087: TopComponentDroppable droppable) {
1088: DropTargetGlassPane lastTarget = windowDnDManager.lastTargetWRef
1089: .get();
1090:
1091: if (lastTarget != null) {
1092: Point p = new Point(location);
1093: SwingUtilities.convertPointFromScreen(p, lastTarget);
1094: lastTarget.dragOver(p, droppable);
1095: }
1096: }
1097:
1098: /** Hacks drag exit from drop target (glass pane).
1099: * Eliminates bug, where remained drop indicator drawed
1100: * even for cases the cursor was away from drop target. Missing
1101: * drag exit event. */
1102: private/*static*/void clearExitedDropTarget() {
1103: DropTargetGlassPane lastTarget = windowDnDManager.lastTargetWRef
1104: .get();
1105:
1106: if (lastTarget != null) {
1107: lastTarget.clearIndications();
1108: windowDnDManager.lastTargetWRef = new WeakReference<DropTargetGlassPane>(
1109: null);
1110: }
1111: }
1112:
1113: /** Gets main drop target glass pane.*/
1114: private static DropTargetGlassPane getMainDropTargetGlassPane() {
1115: Component glass = ((JFrame) WindowManagerImpl.getInstance()
1116: .getMainWindow()).getGlassPane();
1117: if (glass instanceof DropTargetGlassPane) {
1118: return (DropTargetGlassPane) glass;
1119: } else {
1120: return null;
1121: }
1122: }
1123:
1124: void dragFinished() {
1125: previousDragLoc = null;
1126: if (fakeWindow != null) {
1127: fakeWindow.dispose();
1128: fakeWindow = null;
1129: }
1130: }
1131:
1132: /** Shows or hides fake window as drag under effect
1133: */
1134: private void paintFakeWindow(boolean visible,
1135: DragSourceDragEvent evt) {
1136: // Point loc = evt.getLocation();
1137: // // no window if location is unknown
1138: // if (loc == null) {
1139: // return;
1140: // }
1141: // if (fakeWindow == null) {
1142: // fakeWindow = createFakeWindow();
1143: // isSizeSet = false;
1144: // }
1145: // fakeWindow.setLocation(loc);
1146: // fakeWindow.setVisible(visible);
1147: // // calculate space for window with decorations (title, border...)
1148: // if (visible && !isSizeSet) {
1149: // Dimension size = windowDnDManager.startingTransfer.getSize();
1150: // Insets insets = fakeWindow.getInsets();
1151: // size.width += insets.left + insets.right;
1152: // size.height += insets.top + insets.bottom;
1153: // fakeWindow.setSize(size);
1154: // isSizeSet = true;
1155: // }
1156: }
1157:
1158: /** Creates and returns fake window as drag under effect */
1159: private Window createFakeWindow() {
1160: Window result;
1161: if (windowDnDManager.draggedKind == Constants.MODE_KIND_EDITOR) {
1162: result = new JFrame();
1163: } else {
1164: result = new JDialog((JFrame) null);
1165: }
1166: result.setAlwaysOnTop(true);
1167: return result;
1168: }
1169:
1170: } // End of class MotionListener.
1171:
1172: // XXX
1173: /** Interface for accessing */
1174: public interface ViewAccessor {
1175: public Set<Component> getModeComponents();
1176:
1177: public Set<Component> getSeparateModeFrames();
1178:
1179: public Controller getController();
1180:
1181: public Component getSlidingModeComponent(String side);
1182: } // End of ViewState.
1183:
1184: /** Fake helper droppable used when used around */
1185: private class CenterPanelDroppable implements TopComponentDroppable {
1186:
1187: /** Implements <code>TopComponentDroppable</code>. */
1188: public java.awt.Shape getIndicationForLocation(Point p) {
1189: Rectangle bounds = getDropComponent().getBounds();
1190: Rectangle res = null;
1191: double ratio = Constants.DROP_AROUND_RATIO;
1192: Object constraint = getConstraintForLocation(p);
1193: if (constraint == JSplitPane.LEFT) {
1194: res = new Rectangle(0, 0,
1195: (int) (bounds.width * ratio) - 1,
1196: bounds.height - 1);
1197: } else if (constraint == JSplitPane.TOP) {
1198: res = new Rectangle(0, 0, bounds.width - 1,
1199: (int) (bounds.height * ratio) - 1);
1200: } else if (constraint == JSplitPane.RIGHT) {
1201: res = new Rectangle(bounds.width
1202: - (int) (bounds.width * ratio), 0,
1203: (int) (bounds.width * ratio) - 1,
1204: bounds.height - 1);
1205: } else if (constraint == JSplitPane.BOTTOM) {
1206: res = new Rectangle(0, bounds.height
1207: - (int) (bounds.height * ratio),
1208: bounds.width - 1,
1209: (int) (bounds.height * ratio) - 1);
1210: }
1211:
1212: return res;
1213: }
1214:
1215: /** Implements <code>TopComponentDroppable</code>. */
1216: public Object getConstraintForLocation(Point p) {
1217: Rectangle bounds = getDropComponent().getBounds();
1218: Component leftSlide = viewAccessor
1219: .getSlidingModeComponent(Constants.LEFT);
1220: Component rightSlide = viewAccessor
1221: .getSlidingModeComponent(Constants.RIGHT);
1222: Component bottomSlide = viewAccessor
1223: .getSlidingModeComponent(Constants.BOTTOM);
1224: if (null != leftSlide
1225: && p.x < leftSlide.getBounds().width + 10) {
1226: return javax.swing.JSplitPane.LEFT;
1227: } else if (p.y < bounds.y) {
1228: return javax.swing.JSplitPane.TOP;
1229: } else if (null != rightSlide
1230: && null != leftSlide
1231: && p.x > bounds.width - 10
1232: - rightSlide.getBounds().width
1233: - leftSlide.getBounds().width) {
1234: return javax.swing.JSplitPane.RIGHT;
1235: } else if (null != bottomSlide
1236: && p.y > bounds.height - 10
1237: - bottomSlide.getBounds().height) {
1238: return javax.swing.JSplitPane.BOTTOM;
1239: }
1240:
1241: return null;
1242: }
1243:
1244: /** Implements <code>TopComponentDroppable</code>. */
1245: public Component getDropComponent() {
1246: return ((MainWindow) WindowManagerImpl.getInstance()
1247: .getMainWindow()).getDesktop();
1248: }
1249:
1250: /** Implements <code>TopComponentDroppable</code>. */
1251: public ViewElement getDropViewElement() {
1252: return null;
1253: }
1254:
1255: public boolean canDrop(TopComponent transfer, Point location) {
1256: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
1257: || WindowManagerImpl.getInstance()
1258: .isTopComponentAllowedToMoveAnywhere(
1259: transfer)) {
1260: return true;
1261: }
1262:
1263: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
1264: .findMode(transfer);
1265: return mode != null
1266: && (mode.getKind() == Constants.MODE_KIND_VIEW || mode
1267: .getKind() == Constants.MODE_KIND_SLIDING);
1268: }
1269:
1270: public boolean supportsKind(int kind, TopComponent transfer) {
1271: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
1272: || WindowManagerImpl.getInstance()
1273: .isTopComponentAllowedToMoveAnywhere(
1274: transfer)) {
1275: return true;
1276: }
1277:
1278: return kind == Constants.MODE_KIND_VIEW
1279: || kind == Constants.MODE_KIND_SLIDING;
1280: }
1281:
1282: } // End of class CenterPanelDroppable.
1283:
1284: /** Fake helper droppable used when used around */
1285: private class EditorAreaDroppable implements TopComponentDroppable {
1286:
1287: /** Implements <code>TopComponentDroppable</code>. */
1288: public java.awt.Shape getIndicationForLocation(Point p) {
1289: Rectangle bounds = getDropComponent().getBounds();
1290: Rectangle res = null;
1291: double ratio = Constants.DROP_AROUND_RATIO;
1292: Object constraint = getConstraintForLocation(p);
1293: if (constraint == JSplitPane.LEFT) {
1294: res = new Rectangle(0, 0,
1295: (int) (bounds.width * ratio) - 1,
1296: bounds.height - 1);
1297: } else if (constraint == JSplitPane.TOP) {
1298: res = new Rectangle(0, 0, bounds.width - 1,
1299: (int) (bounds.height * ratio) - 1);
1300: } else if (constraint == JSplitPane.RIGHT) {
1301: res = new Rectangle(bounds.width
1302: - (int) (bounds.width * ratio), 0,
1303: (int) (bounds.width * ratio) - 1,
1304: bounds.height - 1);
1305: } else if (constraint == JSplitPane.BOTTOM) {
1306: res = new Rectangle(0, bounds.height
1307: - (int) (bounds.height * ratio),
1308: bounds.width - 1,
1309: (int) (bounds.height * ratio) - 1);
1310: }
1311:
1312: return res;
1313: }
1314:
1315: /** Implements <code>TopComponentDroppable</code>. */
1316: public Object getConstraintForLocation(Point p) {
1317: Rectangle bounds = getDropComponent().getBounds();
1318: Component leftSlide = viewAccessor
1319: .getSlidingModeComponent(Constants.LEFT);
1320: Component rightSlide = viewAccessor
1321: .getSlidingModeComponent(Constants.RIGHT);
1322: Component bottomSlide = viewAccessor
1323: .getSlidingModeComponent(Constants.BOTTOM);
1324: if (null != leftSlide
1325: && p.x < leftSlide.getBounds().width + 10) {
1326: return javax.swing.JSplitPane.LEFT;
1327: } else if (p.y < bounds.y) {
1328: return javax.swing.JSplitPane.TOP;
1329: } else if (null != rightSlide
1330: && null != leftSlide
1331: && p.x > bounds.width - 10
1332: - rightSlide.getBounds().width
1333: - leftSlide.getBounds().width) {
1334: return javax.swing.JSplitPane.RIGHT;
1335: } else if (null != bottomSlide
1336: && p.y > bounds.height - 10
1337: - bottomSlide.getBounds().height) {
1338: return javax.swing.JSplitPane.BOTTOM;
1339: }
1340:
1341: return null;
1342: }
1343:
1344: /** Implements <code>TopComponentDroppable</code>. */
1345: public Component getDropComponent() {
1346: return WindowManagerImpl.getInstance()
1347: .getEditorAreaComponent();
1348: }
1349:
1350: /** Implements <code>TopComponentDroppable</code>. */
1351: public ViewElement getDropViewElement() {
1352: return null;
1353: }
1354:
1355: public boolean canDrop(TopComponent transfer, Point location) {
1356: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
1357: || WindowManagerImpl.getInstance()
1358: .isTopComponentAllowedToMoveAnywhere(
1359: transfer)) {
1360: return true;
1361: }
1362:
1363: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
1364: .findMode(transfer);
1365: return mode != null
1366: && mode.getKind() == Constants.MODE_KIND_EDITOR;
1367: }
1368:
1369: public boolean supportsKind(int kind, TopComponent transfer) {
1370: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
1371: || WindowManagerImpl.getInstance()
1372: .isTopComponentAllowedToMoveAnywhere(
1373: transfer)) {
1374: return true;
1375: }
1376:
1377: return kind == Constants.MODE_KIND_EDITOR;
1378: }
1379:
1380: } // End of class EditorAreaDroppable.
1381:
1382: /** Fake helper droppable used when dropping is done into free area. */
1383: private static class FreeAreaDroppable implements
1384: TopComponentDroppable {
1385:
1386: private Point location;
1387:
1388: public FreeAreaDroppable(Point location) {
1389: this .location = location;
1390: }
1391:
1392: /** Implements <code>TopComponentDroppable</code>. */
1393: public java.awt.Shape getIndicationForLocation(Point p) {
1394: return null;
1395: }
1396:
1397: /** Implements <code>TopComponentDroppable</code>. */
1398: public Object getConstraintForLocation(Point p) {
1399: return new Rectangle(location.x, location.y,
1400: Constants.DROP_NEW_MODE_SIZE.width,
1401: Constants.DROP_NEW_MODE_SIZE.height);
1402: }
1403:
1404: /** Implements <code>TopComponentDroppable</code>. */
1405: public Component getDropComponent() {
1406: return null;
1407: }
1408:
1409: /** Implements <code>TopComponentDroppable</code>. */
1410: public ViewElement getDropViewElement() {
1411: return null;
1412: }
1413:
1414: public boolean canDrop(TopComponent transfer, Point location) {
1415: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
1416: .findMode(transfer);
1417: if (mode == null) {
1418: return false;
1419: }
1420: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
1421: || WindowManagerImpl.getInstance()
1422: .isTopComponentAllowedToMoveAnywhere(
1423: transfer)) {
1424: return true;
1425: }
1426:
1427: // don't accept drop from separated mode with single component in it,
1428: // it makes no sense (because such DnD into free area equals to
1429: // simple window move)
1430: if (mode.getState() == Constants.MODE_STATE_SEPARATED
1431: && mode.getOpenedTopComponents().size() == 1) {
1432: return false;
1433: }
1434:
1435: return true;
1436: }
1437:
1438: public boolean supportsKind(int kind, TopComponent transfer) {
1439: return true;
1440: }
1441:
1442: } // End of class FreeAreaDroppable.
1443:
1444: /**
1445: * droppable for the sliding bars, both inside and outside of the main window.
1446: *
1447: */
1448: private static class CenterSlidingDroppable implements
1449: TopComponentDroppable, EnhancedDragPainter {
1450:
1451: private ViewAccessor accesor;
1452: private TopComponentDroppable original;
1453: private String side;
1454: JPanel pan;
1455: private boolean isShowing;
1456:
1457: public CenterSlidingDroppable(ViewAccessor viewAccesor,
1458: TopComponentDroppable slidingBarDelegate, String side) {
1459: original = slidingBarDelegate;
1460: accesor = viewAccesor;
1461: this .side = side;
1462: pan = new JPanel();
1463: isShowing = false;
1464: }
1465:
1466: public boolean canDrop(TopComponent transfer, Point location) {
1467: return original.canDrop(transfer, location);
1468: }
1469:
1470: public Object getConstraintForLocation(Point location) {
1471: return original.getConstraintForLocation(location);
1472: }
1473:
1474: public Component getDropComponent() {
1475: return original.getDropComponent();
1476: }
1477:
1478: public ViewElement getDropViewElement() {
1479: return original.getDropViewElement();
1480: }
1481:
1482: public Shape getIndicationForLocation(Point location) {
1483: Shape toReturn = original
1484: .getIndicationForLocation(location);
1485: Rectangle dim = original.getDropComponent().getBounds();
1486: if (dim.width < 10 || dim.height < 10) {
1487: Rectangle rect = toReturn.getBounds();
1488: if (Constants.LEFT.equals(side)) {
1489: toReturn = new Rectangle(0, 0, Math.max(rect.width,
1490: Constants.DROP_AREA_SIZE), Math.max(
1491: rect.height, Constants.DROP_AREA_SIZE));
1492: } else if (Constants.RIGHT.equals(side)) {
1493: toReturn = new Rectangle(-Constants.DROP_AREA_SIZE,
1494: 0, Math.max(rect.width,
1495: Constants.DROP_AREA_SIZE), Math
1496: .max(rect.height,
1497: Constants.DROP_AREA_SIZE));
1498: } else if (Constants.BOTTOM.equals(side)) {
1499: toReturn = new Rectangle(0,
1500: -Constants.DROP_AREA_SIZE, Math.max(
1501: rect.width,
1502: Constants.DROP_AREA_SIZE), Math
1503: .max(rect.height,
1504: Constants.DROP_AREA_SIZE));
1505: }
1506: }
1507: return toReturn;
1508: }
1509:
1510: public boolean isWithinSlide(Point location) {
1511: Component root = SwingUtilities.getRootPane(original
1512: .getDropComponent());
1513: Point barLoc = SwingUtilities.convertPoint(root, location,
1514: original.getDropComponent());
1515: if (original.getDropComponent().contains(barLoc)) {
1516: return true;
1517: }
1518: Dimension dim = original.getDropComponent().getSize();
1519: if (Constants.LEFT.equals(side)) {
1520: int abs = Math.abs(barLoc.x);
1521: if (barLoc.y > -Constants.DROP_AREA_SIZE
1522: && barLoc.y < dim.height
1523: + Constants.DROP_AREA_SIZE) {
1524: if (isShowing && abs < Constants.DROP_AREA_SIZE) {
1525: return true;
1526: }
1527: if (!isShowing && barLoc.x <= 0
1528: && barLoc.x > -Constants.DROP_AREA_SIZE) {
1529: return true;
1530: }
1531: }
1532: } else if (Constants.RIGHT.equals(side)) {
1533: if (barLoc.y > -Constants.DROP_AREA_SIZE
1534: && barLoc.y < dim.height
1535: + Constants.DROP_AREA_SIZE) {
1536: if (isShowing
1537: && ((barLoc.x < 0 && barLoc.x > -Constants.DROP_AREA_SIZE) || barLoc.x > 0
1538: && barLoc.x - dim.width < Constants.DROP_AREA_SIZE)) {
1539: return true;
1540: }
1541: if (!isShowing
1542: && barLoc.x >= 0
1543: && barLoc.x < Constants.DROP_AREA_SIZE
1544: + dim.width) {
1545: return true;
1546: }
1547: }
1548: } else if (Constants.BOTTOM.equals(side)) {
1549: if (barLoc.x > -Constants.DROP_AREA_SIZE
1550: && barLoc.x < dim.width
1551: + Constants.DROP_AREA_SIZE) {
1552: if (isShowing
1553: && ((barLoc.y < 0 && barLoc.y > -Constants.DROP_AREA_SIZE) || barLoc.y > 0
1554: && barLoc.y - dim.height < Constants.DROP_AREA_SIZE)) {
1555: return true;
1556: }
1557: if (!isShowing
1558: && barLoc.y >= 0
1559: && barLoc.y < Constants.DROP_AREA_SIZE
1560: + dim.height) {
1561: return true;
1562: }
1563: }
1564: }
1565: return false;
1566:
1567: }
1568:
1569: public boolean supportsKind(int kind, TopComponent transfer) {
1570: return original.supportsKind(kind, transfer);
1571: }
1572:
1573: public void additionalDragPaint(Graphics2D g) {
1574: Rectangle dim = original.getDropComponent().getBounds();
1575: if (dim.width > 10 && dim.height > 10) {
1576: return;
1577: }
1578: isShowing = true;
1579: Component glassPane = ((JComponent) original
1580: .getDropComponent()).getRootPane().getGlassPane();
1581: Point leftTop = SwingUtilities.convertPoint(original
1582: .getDropComponent(), 0, 0, glassPane);
1583: Point firstDivider;
1584: Point secondDevider;
1585:
1586: if (Constants.RIGHT.equals(side)) {
1587: leftTop = new Point(leftTop.x - 24, leftTop.y);
1588: firstDivider = new Point(leftTop);
1589: secondDevider = new Point(leftTop.x, leftTop.y
1590: + dim.height);
1591: } else if (Constants.BOTTOM.equals(side)) {
1592: leftTop = new Point(0, leftTop.y - 24);
1593: firstDivider = new Point(leftTop);
1594: secondDevider = new Point(leftTop.x
1595: + glassPane.getBounds().width, leftTop.y);
1596: } else {
1597: firstDivider = new Point(leftTop.x + 25, leftTop.y);
1598: secondDevider = new Point(leftTop.x + 25, leftTop.y
1599: + dim.height);
1600: }
1601: Rectangle rect = new Rectangle(leftTop.x, leftTop.y, Math
1602: .max(25, dim.width), Math.max(25, dim.height));
1603: if (Constants.BOTTOM.equals(side)) {
1604: // for bottom has special hack to use the whole width
1605: rect.width = glassPane.getBounds().width;
1606: }
1607:
1608: Color col = g.getColor();
1609: g.setColor(pan.getBackground());
1610: g.fill(rect);
1611: g.setColor(pan.getBackground().darker());
1612: g.drawLine(firstDivider.x, firstDivider.y, secondDevider.x,
1613: secondDevider.y);
1614: g.setColor(col);
1615: }
1616:
1617: public Rectangle getPaintArea() {
1618: Rectangle dim = original.getDropComponent().getBounds();
1619: if (dim.width > 10 && dim.height > 10) {
1620: return null;
1621: }
1622: Component glassPane = ((JComponent) original
1623: .getDropComponent()).getRootPane().getGlassPane();
1624: Point leftTop = SwingUtilities.convertPoint(original
1625: .getDropComponent(), 0, 0, glassPane);
1626:
1627: if (Constants.RIGHT.equals(side)) {
1628: leftTop = new Point(leftTop.x - 24, leftTop.y);
1629: } else if (Constants.BOTTOM.equals(side)) {
1630: leftTop = new Point(0, leftTop.y - 24);
1631: }
1632: Rectangle rect = new Rectangle(leftTop.x, leftTop.y, Math
1633: .max(25, dim.width), Math.max(25, dim.height));
1634: if (Constants.BOTTOM.equals(side)) {
1635: // for bottom has special hack to use the whole width
1636: rect.width = glassPane.getBounds().width;
1637: }
1638: return rect;
1639: }
1640: }
1641:
1642: }
|