Package org.eclipse.ui.internal

Source Code of org.eclipse.ui.internal.TrimDropTarget$ActualTrimDropTarget

/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal;

import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.internal.dnd.DragBorder;
import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.internal.dnd.IDragOverListener;
import org.eclipse.ui.internal.dnd.IDropTarget;
import org.eclipse.ui.internal.dnd.IDropTarget2;
import org.eclipse.ui.internal.layout.IWindowTrim;
import org.eclipse.ui.internal.layout.LayoutUtil;
import org.eclipse.ui.internal.layout.TrimDescriptor;
import org.eclipse.ui.internal.layout.TrimLayout;
import org.eclipse.ui.internal.layout.TrimToolBarBase;

/**
*/
/*package*/class TrimDropTarget implements IDragOverListener {
 
    private final class ActualTrimDropTarget implements IDropTarget2 {
        public IWindowTrim draggedTrim;
       
        // tracking parameters
      private DragBorder border = null;
      private int dockedArea;
       
        // Holder for the position of trim that is 'floating' with the cursor
      private int cursorAreaId;
        private int initialAreaId;
        private IWindowTrim initialInsertBefore;       
    private Rectangle initialLocation;

        /**
         * Constructor
         */
        private ActualTrimDropTarget() {
            super();

            draggedTrim = null;
            dockedArea = SWT.NONE;
           
            initialAreaId = SWT.NONE;
            initialInsertBefore = null;
        }
       
        /**
         * This method is used to delineate separate trims dragging events. The -first- drag
         * event will set this and then it will remain constant until the drag gesture is done;
         * either by dropping or escaping. Once the gesture is finished the trim value is set
         * back to 'null'.
         *
         * @param trim The trim item currently being dragged.
         */
        public void startDrag(IWindowTrim trim) {
          // Are we starting a new drag?
          if (draggedTrim != trim) {
              // remember the dragged trim
              draggedTrim = trim;
             
              // Remember the location that we were in initially so we
              // can go back there on an cancel...
              initialAreaId = layout.getTrimAreaId(draggedTrim.getControl());
             
              // Determine who we were placed 'before' in the trim
              initialInsertBefore = getInsertBefore(initialAreaId, draggedTrim);
             
              // Remember the location that the control used to be at for animation purposes
              initialLocation = DragUtil.getDisplayBounds(draggedTrim.getControl());
                           
              // The dragged trim is always initially docked
              dockedArea = initialAreaId;
          }
        }
               
        /**
         * Determine the trim area from the point. To avoid clashing at the 'corners' due to extending the trim area's
         * rectangles we first ensure that the point is not actually -within- a trim area before we check the extended
         * rectangles.
         *
         * @param pos The current cursor pos
         * @return the Trim area that the cursor is in or SWT.NONE if the point is not in an area
         */
        private int getTrimArea(Point pos) {
          // First, check if we're actually -within- a trim area (i.e. no boundary extensions)
          int areaId = getTrimArea(pos, 0);
         
          // If we are not inside a trim area...are we 'close' to one?
          if (areaId == SWT.NONE) {
        areaId = getTrimArea(pos, TrimDragPreferences.getThreshold());
      }
         
          // not inside any trim area
          return areaId;
        }
       
        /**
         * Checks the trims areas against the given position. Each trim area is 'extended' into
         * the workbench page by the value of <code>extendedBoundaryWidth</code> before the checking
         * takes place.
         *
         * @param pos The point to check against
         * @param extendedBoundaryWidth The amount to extend the trim area's 'inner' edge by
         *
         * @return The trim area or SWT.NONE if the point is not within any extended trim area's rect.
         */
        private int getTrimArea(Point pos, int extendedBoundaryWidth) {
          int[] areaIds = layout.getAreaIds();
          for (int i = 0; i < areaIds.length; i++) {
        Rectangle trimRect = layout.getTrimRect(windowComposite, areaIds[i]);
        trimRect = Geometry.toControl(windowComposite, trimRect);

        // Only check 'valid' sides
        if ( (areaIds[i] & getValidSides()) != SWT.NONE) {
          // TODO: more confusion binding 'areaIds' to SWT 'sides'
              switch (areaIds[i]) {
          case SWT.LEFT:
            trimRect.width += extendedBoundaryWidth;
           
            if (pos.y >= trimRect.y &&
              pos.y <= (trimRect.y+trimRect.height) &&
              pos.x <= (trimRect.x+trimRect.width)) {
              return areaIds[i];
            }
            break;
          case SWT.RIGHT:
            trimRect.x -= extendedBoundaryWidth;
            trimRect.width += extendedBoundaryWidth;
           
            if (pos.y >= trimRect.y &&
              pos.y <= (trimRect.y+trimRect.height) &&
              pos.x >= trimRect.x) {
              return areaIds[i];
            }
            break;
          case SWT.TOP:
            trimRect.height += extendedBoundaryWidth;
           
            if (pos.x >= trimRect.x &&
              pos.x <= (trimRect.x+trimRect.width) &&
              pos.y <= (trimRect.y+trimRect.height)) {
              return areaIds[i];
            }
            break;
          case SWT.BOTTOM:
            trimRect.y -= extendedBoundaryWidth;
            trimRect.height += extendedBoundaryWidth;
           
            if (pos.x >= trimRect.x &&
              pos.x <= (trimRect.x+trimRect.width) &&
              pos.y >= trimRect.y) {
              return areaIds[i];
            }
            break;
              }
        }
      }
         
          // not inside any trim area
          return SWT.NONE;
        }
       
        /**
         * Determine the window trim that the currently dragged trim should be inserted
         * before.
         * @param areaId The area id that is being checked
         * @param pos The position used to determine the correct insertion trim
         * @return The trim to 'dock' the draggedTrim before
         */
        private IWindowTrim getInsertBefore(int areaId, Point pos) {
          boolean isHorizontal = (areaId == SWT.TOP) || (areaId == SWT.BOTTOM);
         
          // Walk the trim area and return the first one that the positon
          // is 'after'.
          List tDescs = layout.getTrimArea(areaId).getDescriptors();
          for (Iterator iter = tDescs.iterator(); iter.hasNext();) {
        TrimDescriptor desc = (TrimDescriptor) iter.next();
       
        // Skip ourselves
        if (desc.getTrim() == draggedTrim) {
          continue;
        }
       
        // Now, check
        Rectangle bb = desc.getCache().getControl().getBounds();
        Point center = Geometry.centerPoint(bb);
        if (isHorizontal) {
          if (pos.x < center.x) {
            return desc.getTrim();
          }
        }
        else {
          if (pos.y < center.y) {
            return desc.getTrim();
          }
        }
      }
         
          return null;
        }
       
        /**
         * Returns the trim that is 'before' the given trim in the given area
         *
         * @param areaId The areaId of the trim
         * @param trim The trim to find the element after
         *
         * @return The trim that the given trim is 'before'
         */
        private IWindowTrim getInsertBefore(int areaId, IWindowTrim trim) {
          List tDescs = layout.getTrimArea(areaId).getDescriptors();
          for (Iterator iter = tDescs.iterator(); iter.hasNext();) {
        TrimDescriptor desc = (TrimDescriptor) iter.next();
        if (desc.getTrim() == trim) {
          if (iter.hasNext()) {
            desc = (TrimDescriptor) iter.next();
            return desc.getTrim();
          }
          return null;
        }
      }
         
          return null;
        }
       
        /**
         * Recalculates the drop information based on the current cursor pos.
         *
         * @param pos The cursor position
         */
        public void track(Point pos) {
          // Convert the mouse positon into 'local' coords
          Rectangle r = new Rectangle(pos.x, pos.y, 1,1);
          r = Geometry.toControl(windowComposite, r);
          pos.x = r.x;
          pos.y = r.y;
                   
          // Are we 'inside' a trim area ?
          cursorAreaId = getTrimArea(pos);

          // Provide tracking for the appropriate 'mode'
          if (cursorAreaId != SWT.NONE) {
        trackInsideTrimArea(pos);
      } else {
        trackOutsideTrimArea(pos);
      }
        }
      
        /**
         * Perform the feedback used when the cursor is 'inside' a particular trim area.
         * The current implementation will place the dragged trim into the trim area at
         * the location determined by the supplied point.
         *
         * @param pos The point to use to determine where in the trim area the dragged trim
         * should be located.
         */
        private void trackInsideTrimArea(Point pos) {
          // Where should we be?
          int newArea = getTrimArea(pos);
          IWindowTrim newInsertBefore = getInsertBefore(newArea, pos);

          // if we're currently undocked then we should dock
          boolean shouldDock = dockedArea == SWT.NONE;
         
          // If we're already docked then only update if there's a change in area or position
          if (dockedArea != SWT.NONE) {
            // Where are we now?
            IWindowTrim curInsertBefore = getInsertBefore(dockedArea, draggedTrim);
           
            // If we're already docked we should only update if there's a change
            shouldDock = dockedArea != newArea || curInsertBefore != newInsertBefore;
          }
         
          // Do we have to do anything?
          if (shouldDock) {
            // (Re)dock the trim in the new location
            dock(newArea, newInsertBefore);
          }
        }
       
        /**
         * Provide the dragging feedback when the cursor is -not- explicitly inside
         * a particular trim area.
         *
         */
        private void trackOutsideTrimArea(Point pos) {
          // If we -were- docked then undock
          if (dockedArea != SWT.NONE) {
        undock();
      }
       
        border.setLocation(pos, SWT.BOTTOM);
        }
               
        /**
         * Return the set of valid sides that a piece of trim can be docked on. We
         * arbitrarily extend this to include any areas that won't cause a change in orientation
         *
         * @return The extended drop 'side' set
         */
        private int getValidSides() {
          int result = draggedTrim.getValidSides();
          if (result == SWT.NONE) {
        return result;
      }

          // For now, if we can dock...we can dock -anywhere-
          return SWT.TOP | SWT.BOTTOM | SWT.LEFT | SWT.RIGHT;
        }

        /**
         * The user either cancelled the drag or tried to drop the trim in an invalid
         * area...put the trim back in the last location it was in
         */
        private void redock() {
          // Since the control might move 'far' we'll provide an animation
          Rectangle startRect = DragUtil.getDisplayBounds(draggedTrim.getControl());
            RectangleAnimation animation = new RectangleAnimation(
                    windowComposite.getShell(), startRect, initialLocation, 300);
            animation.schedule();

            dock(initialAreaId, initialInsertBefore);
        }
       
    /* (non-Javadoc)
         * @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
         */
        public void drop() {
          // If we aren't docked then restore the initial location
          if (dockedArea == SWT.NONE) {
        redock();
      }
        }

        /**
         * Remove the trim frmo its current 'docked' location and attach it
         * to the cursor...
         */
        private void undock() {
          // Remove the trim from the layout
          layout.removeTrim(draggedTrim);
             LayoutUtil.resize(draggedTrim.getControl());
            
             // Re-orient the widget to its -original- side and size
          draggedTrim.dock(initialAreaId);
          draggedTrim.getControl().setSize(initialLocation.width, initialLocation.height);
            
             // Create a new dragging border onto the dragged trim
          // Special check for TrimPart...should be generalized
          boolean wantsFrame = !(draggedTrim instanceof TrimToolBarBase);
             border = new DragBorder(windowComposite, draggedTrim.getControl(), wantsFrame);

             dockedArea = SWT.NONE;
        }
       
        /**
         * Return the 'undocked' trim to its previous location in the layout
         */
        private void dock(int areaId, IWindowTrim insertBefore) {
          // remove the drag 'border'
          if (border != null) {
        border.dispose();
        border = null;
          }
     
      // Update the trim's orientation if necessary
      draggedTrim.dock(areaId);

      // Add the trim into the layout
            layout.addTrim(areaId, draggedTrim, insertBefore);
             LayoutUtil.resize(draggedTrim.getControl());
            
             // Remember the area that we're currently docked in
             dockedArea = areaId;
        }
         
        /* (non-Javadoc)
         * @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
         */
        public Cursor getCursor() {
          // If the trim isn't docked then show the 'no smoking' sign
          if (cursorAreaId == SWT.NONE) {
        return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_NO);
      }
         
          // It's docked; show the four-way arrow cursor
          return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
        }

        /* (non-Javadoc)
         * @see org.eclipse.ui.internal.dnd.IDropTarget#getSnapRectangle()
         */
        public Rectangle getSnapRectangle() {
          // TODO: KLUDGE!! We don't want to show -any- snap rect
          // but Tracker won't allow that so place it where it won't be visible
          return new Rectangle(100000, 0,0,0);
        }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.dnd.IDropTarget2#dragFinished(boolean)
     */
    public void dragFinished(boolean dropPerformed) {
      // If we didn't perform a drop then restore the original position
      if (!dropPerformed && dockedArea == SWT.NONE) {
        // Force the dragged trim back into its original position...       
        redock();
      }
     
      // Set the draggedTrim to null. This indicates that we're no longer
      // dragging the trim. The first call to the TrimDropTarget's 'drag' method
      // will reset this the next time a drag starts.
      draggedTrim = null;
    }
    }
   
    private ActualTrimDropTarget dropTarget;
   
    private TrimLayout layout;
    private Composite windowComposite;

    /**
     * Create a new drop target capable of accepting IWindowTrim items
     *
     * @param someComposite The control owning the TrimLayout
     * @param theWindow the workbenchWindow
     */
    public TrimDropTarget(Composite someComposite, WorkbenchWindow theWindow) {
        layout = (TrimLayout) someComposite.getLayout();
        windowComposite = someComposite;

        // Create an instance of a drop target to use
        dropTarget = new ActualTrimDropTarget();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
     */
    public IDropTarget drag(Control currentControl, Object draggedObject,
            Point position, final Rectangle dragRectangle) {
     
      // Have to be dragging trim
      if (!(draggedObject instanceof IWindowTrim)) {
      return null;
    }
     
      // OK, we're dragging trim. is it from -this- shell?
      IWindowTrim trim = (IWindowTrim) draggedObject;
      if (trim.getControl().getShell() != windowComposite.getShell()) {
      return null;
    }
     
      // If this is the -first- drag then inform the drop target
      if (dropTarget.draggedTrim == null) {
        dropTarget.startDrag(trim);
      }

      // Forward on to the 'actual' drop target for feedback
      dropTarget.track(position);
     
      // Spin the paint loop after every track
      windowComposite.getDisplay().update();
     
    return dropTarget;
    }
}
TOP

Related Classes of org.eclipse.ui.internal.TrimDropTarget$ActualTrimDropTarget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.