org.eclipse.ui.internal.PartSashContainer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of workbench Show documentation
Show all versions of workbench Show documentation
This plug-in contains the bulk of the Workbench implementation, and depends on JFace, SWT, and Core Runtime. It cannot be used independently from org.eclipse.ui. Workbench client plug-ins should not depend directly on this plug-in.
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 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
* Cagatay Kavukcuoglu
* - Fix for bug 10025 - Resizing views should not use height ratios
* Chris Gross [email protected] Bug 107443
*******************************************************************************/
package org.eclipse.ui.internal;
import java.util.ArrayList;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
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.IPageLayout;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.internal.dnd.AbstractDropTarget;
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.SwtUtil;
/**
* Abstract container that groups various layout
* parts (possibly other containers) together as
* a unit. Manages the placement and size of these
* layout part based on the location of sashes within
* the container.
*/
public abstract class PartSashContainer extends LayoutPart implements
ILayoutContainer, IDragOverListener {
protected Composite parent;
protected ControlListener resizeListener;
protected LayoutTree root;
private Composite parentWidget;
private LayoutPart zoomedPart;
protected WorkbenchPage page;
boolean active = false;
boolean layoutDirty = false;
/* Array of LayoutPart */
protected ArrayList children = new ArrayList();
private SashContainerDropTarget dropTarget;
protected static class RelationshipInfo {
protected LayoutPart part;
protected LayoutPart relative;
protected int relationship;
/**
* Preferred size for the left child (this would be the size, in pixels of the child
* at the time the sash was last moved)
*/
protected int left;
/**
* Preferred size for the right child (this would be the size, in pixels of the child
* at the time the sash was last moved)
*/
protected int right;
/**
* Computes the "ratio" for this container. That is, the ratio of the left side over
* the sum of left + right. This is only used for serializing PartSashContainers in
* a form that can be read by old versions of Eclipse. This can be removed if this
* is no longer required.
*
* @return the pre-Eclipse 3.0 sash ratio
*/
public float getRatio() {
int total = left + right;
if (total > 0) {
return (float) left / (float) total;
}
return 0.5f;
}
}
private class SashContainerDropTarget extends AbstractDropTarget {
private int side;
private int cursor;
private LayoutPart targetPart;
private LayoutPart sourcePart;
public SashContainerDropTarget(LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
this.setTarget(sourcePart, side, cursor, targetPart);
}
public void setTarget(LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
this.side = side;
this.targetPart = targetPart;
this.sourcePart = sourcePart;
this.cursor = cursor;
}
public void drop() {
if (side != SWT.NONE) {
LayoutPart visiblePart = sourcePart;
if (sourcePart instanceof PartStack) {
visiblePart = getVisiblePart((PartStack) sourcePart);
}
dropObject(getVisibleParts(sourcePart), visiblePart,
targetPart, side);
}
}
public Cursor getCursor() {
return DragCursors.getCursor(DragCursors
.positionToDragCursor(cursor));
}
public Rectangle getSnapRectangle() {
Rectangle targetBounds;
if (targetPart != null) {
targetBounds = DragUtil.getDisplayBounds(targetPart
.getControl());
} else {
targetBounds = DragUtil.getDisplayBounds(getParent());
}
if (side == SWT.CENTER || side == SWT.NONE) {
return targetBounds;
}
int distance = Geometry.getDimension(targetBounds, !Geometry
.isHorizontal(side));
return Geometry.getExtrudedEdge(targetBounds,
(int) (distance * getDockingRatio(sourcePart, targetPart)),
side);
}
}
public PartSashContainer(String id, final WorkbenchPage page, Composite parentWidget) {
super(id);
this.page = page;
this.parentWidget = parentWidget;
resizeListener = new ControlAdapter() {
public void controlResized(ControlEvent e) {
resizeSashes();
}
};
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.ILayoutContainer#obscuredByZoom(org.eclipse.ui.internal.LayoutPart)
*/
public boolean childObscuredByZoom(LayoutPart toTest) {
LayoutPart zoomPart = getZoomedPart();
if (zoomPart != null && toTest != zoomPart) {
return true;
}
return isObscuredByZoom();
}
/**
* Given an object associated with a drag (a PartPane or PartStack), this returns
* the actual PartPanes being dragged.
*
* @param pane
* @return
*/
private PartPane[] getVisibleParts(LayoutPart pane) {
if (pane instanceof PartPane) {
return new PartPane[] { (PartPane) pane };
} else if (pane instanceof PartStack) {
PartStack stack = (PartStack) pane;
LayoutPart[] children = stack.getChildren();
ArrayList result = new ArrayList(children.length);
for (int idx = 0; idx < children.length; idx++) {
LayoutPart next = children[idx];
if (next instanceof PartPane) {
result.add(next);
}
}
return (PartPane[]) result.toArray(new PartPane[result.size()]);
}
return new PartPane[0];
}
/**
* Find the sashs around the specified part.
*/
public void findSashes(LayoutPart pane, PartPane.Sashes sashes) {
if (root == null) {
return;
}
LayoutTree part = root.find(pane);
if (part == null) {
return;
}
part.findSashes(sashes);
}
/**
* Add a part.
*/
public void add(LayoutPart child) {
if (child == null) {
return;
}
addEnhanced(child, SWT.RIGHT, 0.5f, findBottomRight());
}
/**
* Add a new part relative to another. This should be used in place of add
.
* It differs as follows:
*
* - relationships are specified using SWT direction constants
* - the ratio applies to the newly added child -- not the upper-left child
*
*
* @param child new part to add to the layout
* @param swtDirectionConstant one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT
* @param ratioForNewPart a value between 0.0 and 1.0 specifying how much space will be allocated for the newly added part
* @param relative existing part indicating where the new child should be attached
* @since 3.0
*/
void addEnhanced(LayoutPart child, int swtDirectionConstant,
float ratioForNewPart, LayoutPart relative) {
int relativePosition = PageLayout
.swtConstantToLayoutPosition(swtDirectionConstant);
float ratioForUpperLeftPart;
if (relativePosition == IPageLayout.RIGHT
|| relativePosition == IPageLayout.BOTTOM) {
ratioForUpperLeftPart = 1.0f - ratioForNewPart;
} else {
ratioForUpperLeftPart = ratioForNewPart;
}
add(child, relativePosition, ratioForUpperLeftPart, relative);
}
/**
* Add a part relative to another. For compatibility only. New code should use
* addEnhanced, above.
*
* @param child the new part to add
* @param relationship one of PageLayout.TOP, PageLayout.BOTTOM, PageLayout.LEFT, or PageLayout.RIGHT
* @param ratio a value between 0.0 and 1.0, indicating how much space will be allocated to the UPPER-LEFT pane
* @param relative part where the new part will be attached
*/
public void add(LayoutPart child, int relationship, float ratio,
LayoutPart relative) {
boolean isHorizontal = (relationship == IPageLayout.LEFT || relationship == IPageLayout.RIGHT);
LayoutTree node = null;
if (root != null && relative != null) {
node = root.find(relative);
}
Rectangle bounds;
if (getParent() == null) {
Control control = getPage().getClientComposite();
if (control != null && !control.isDisposed()) {
bounds = control.getBounds();
} else {
bounds = new Rectangle(0, 0, 800, 600);
}
bounds.x = 0;
bounds.y = 0;
} else {
bounds = getBounds();
}
int totalSize = measureTree(bounds, node, isHorizontal);
int left = (int) (totalSize * ratio);
int right = totalSize - left;
add(child, relationship, left, right, relative);
}
static int measureTree(Rectangle outerBounds, LayoutTree toMeasure,
boolean horizontal) {
if (toMeasure == null) {
return Geometry.getDimension(outerBounds, horizontal);
}
LayoutTreeNode parent = toMeasure.getParent();
if (parent == null) {
return Geometry.getDimension(outerBounds, horizontal);
}
if (parent.getSash().isHorizontal() == horizontal) {
return measureTree(outerBounds, parent, horizontal);
}
boolean isLeft = parent.isLeftChild(toMeasure);
LayoutTree otherChild = parent.getChild(!isLeft);
if (otherChild.isVisible()) {
int left = parent.getSash().getLeft();
int right = parent.getSash().getRight();
int childSize = isLeft ? left : right;
int bias = parent.getCompressionBias();
// Normalize bias: 1 = we're fixed, -1 = other child is fixed
if (isLeft) {
bias = -bias;
}
if (bias == 1) {
// If we're fixed, return the fixed size
return childSize;
} else if (bias == -1) {
// If the other child is fixed, return the size of the parent minus the fixed size of the
// other child
return measureTree(outerBounds, parent, horizontal)
- (left + right - childSize);
}
// Else return the size of the parent, scaled appropriately
return measureTree(outerBounds, parent, horizontal) * childSize
/ (left + right);
}
return measureTree(outerBounds, parent, horizontal);
}
protected void addChild(RelationshipInfo info) {
LayoutPart child = info.part;
children.add(child);
if (root == null) {
root = new LayoutTree(child);
} else {
//Add the part to the tree.
int vertical = (info.relationship == IPageLayout.LEFT || info.relationship == IPageLayout.RIGHT) ? SWT.VERTICAL
: SWT.HORIZONTAL;
boolean left = info.relationship == IPageLayout.LEFT
|| info.relationship == IPageLayout.TOP;
LayoutPartSash sash = new LayoutPartSash(this, vertical);
sash.setSizes(info.left, info.right);
if ((parent != null) && !(child instanceof PartPlaceholder)) {
sash.createControl(parent);
}
root = root.insert(child, left, sash, info.relative);
}
childAdded(child);
if (active) {
child.createControl(parent);
child.setVisible(true);
child.setContainer(this);
resizeChild(child);
}
}
/**
* Adds the child using ratio and position attributes
* from the specified placeholder without replacing
* the placeholder
*
* FIXME: I believe there is a bug in computeRelation()
* when a part is positioned relative to the editorarea.
* We end up with a null relative and 0.0 for a ratio.
*/
void addChildForPlaceholder(LayoutPart child, LayoutPart placeholder) {
RelationshipInfo newRelationshipInfo = new RelationshipInfo();
newRelationshipInfo.part = child;
if (root != null) {
newRelationshipInfo.relationship = IPageLayout.RIGHT;
newRelationshipInfo.relative = root.findBottomRight();
newRelationshipInfo.left = 200;
newRelationshipInfo.right = 200;
}
// find the relationship info for the placeholder
RelationshipInfo[] relationships = computeRelation();
for (int i = 0; i < relationships.length; i++) {
RelationshipInfo info = relationships[i];
if (info.part == placeholder) {
newRelationshipInfo.left = info.left;
newRelationshipInfo.right = info.right;
newRelationshipInfo.relationship = info.relationship;
newRelationshipInfo.relative = info.relative;
}
}
addChild(newRelationshipInfo);
flushLayout();
}
/**
* See ILayoutContainer#allowBorder
*/
public boolean allowsBorder() {
return true;
}
/**
* Notification that a child layout part has been
* added to the container. Subclasses may override
* this method to perform any container specific
* work.
*/
protected void childAdded(LayoutPart child) {
if (isDeferred()) {
child.deferUpdates(true);
}
}
/**
* Notification that a child layout part has been
* removed from the container. Subclasses may override
* this method to perform any container specific
* work.
*/
protected void childRemoved(LayoutPart child) {
if (isDeferred()) {
child.deferUpdates(false);
}
}
/**
* Returns an array with all the relation ship between the
* parts.
*/
public RelationshipInfo[] computeRelation() {
LayoutTree treeRoot = root;
ArrayList list = new ArrayList();
if (treeRoot == null) {
return new RelationshipInfo[0];
}
RelationshipInfo r = new RelationshipInfo();
r.part = treeRoot.computeRelation(list);
list.add(0, r);
RelationshipInfo[] result = new RelationshipInfo[list.size()];
list.toArray(result);
return result;
}
public void setActive(boolean isActive) {
if (isActive == active) {
return;
}
active = isActive;
ArrayList children = (ArrayList) this.children.clone();
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
if (child instanceof PartStack) {
PartStack stack = (PartStack) child;
stack.setActive(isActive);
}
}
if (isActive) {
createControl(parentWidget);
parent.addControlListener(resizeListener);
DragUtil.addDragTarget(parent, this);
DragUtil.addDragTarget(parent.getShell(), this);
//ArrayList children = (ArrayList) this.children.clone();
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
child.setContainer(this);
child.setVisible(zoomedPart == null || child == zoomedPart);
if (!(child instanceof PartStack)) {
if (root != null) {
LayoutTree node = root.find(child);
if (node != null) {
node.flushCache();
}
}
}
}
if (root != null) {
//root.flushChildren();
if (!isZoomed()) {
root.createControl(parent);
}
}
resizeSashes();
} else {
DragUtil.removeDragTarget(parent, this);
DragUtil.removeDragTarget(parent.getShell(), this);
// remove all Listeners
if (resizeListener != null && parent != null) {
parent.removeControlListener(resizeListener);
}
if (children != null) {
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
child.setContainer(null);
if (child instanceof PartStack) {
child.setVisible(false);
}
}
}
disposeSashes();
//dispose();
}
}
/**
* @see LayoutPart#getControl
*/
public void createControl(Composite parentWidget) {
if (this.parent != null) {
return;
}
parent = createParent(parentWidget);
ArrayList children = (ArrayList) this.children.clone();
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
child.createControl(parent);
}
}
/**
* Subclasses override this method to specify
* the composite to use to parent all children
* layout parts it contains.
*/
protected abstract Composite createParent(Composite parentWidget);
/**
* @see LayoutPart#dispose
*/
public void dispose() {
if (parent == null) {
return;
}
if (children != null) {
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
// In PartSashContainer dispose really means deactivate, so we
// only dispose PartTabFolders.
if (child instanceof PartStack) {
child.dispose();
}
}
}
disposeParent();
this.parent = null;
}
/**
* Subclasses override this method to dispose
* of any swt resources created during createParent.
*/
protected abstract void disposeParent();
/**
* Dispose all sashs used in this perspective.
*/
public void disposeSashes() {
if (root != null) {
root.disposeSashes();
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#setVisible(boolean)
*/
public void setVisible(boolean makeVisible) {
if (makeVisible == getVisible()) {
return;
}
if (!SwtUtil.isDisposed(this.parent)) {
this.parent.setEnabled(makeVisible);
}
super.setVisible(makeVisible);
ArrayList children = (ArrayList) this.children.clone();
for (int i = 0, length = children.size(); i < length; i++) {
LayoutPart child = (LayoutPart) children.get(i);
child.setVisible(makeVisible && (zoomedPart == null || child == zoomedPart));
}
}
/**
* Return the most bottom right part or null if none.
*/
public LayoutPart findBottomRight() {
if (root == null) {
return null;
}
return root.findBottomRight();
}
/**
* @see LayoutPart#getBounds
*/
public Rectangle getBounds() {
return this.parent.getBounds();
}
/**
* @see ILayoutContainer#getChildren
*/
public LayoutPart[] getChildren() {
LayoutPart[] result = new LayoutPart[children.size()];
children.toArray(result);
return result;
}
/**
* @see LayoutPart#getControl
*/
public Control getControl() {
return this.parent;
}
public LayoutTree getLayoutTree() {
return root;
}
/**
* For themes.
*
* @return the current WorkbenchPage.
*/
public WorkbenchPage getPage() {
return page;
}
/**
* Returns the composite used to parent all the
* layout parts contained within.
*/
public Composite getParent() {
return parent;
}
protected boolean isChild(LayoutPart part) {
return children.indexOf(part) >= 0;
}
/**
* Returns whether this container is zoomed.
*/
public boolean isZoomed() {
return (zoomedPart != null);
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#forceLayout(org.eclipse.ui.internal.LayoutPart)
*/
public void resizeChild(LayoutPart childThatChanged) {
if (root != null) {
LayoutTree tree = root.find(childThatChanged);
if (tree != null) {
tree.flushCache();
}
}
flushLayout();
}
/**
* Remove a part.
*/
public void remove(LayoutPart child) {
if (child == getZoomedPart()) {
childRequestZoomOut();
}
if (!isChild(child)) {
return;
}
children.remove(child);
if (root != null) {
root = root.remove(child);
}
childRemoved(child);
if (active) {
child.setVisible(false);
child.setContainer(null);
flushLayout();
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#forceLayout()
*/
public void flushLayout() {
layoutDirty = true;
super.flushLayout();
if (layoutDirty) {
resizeSashes();
}
}
/**
* Replace one part with another.
*/
public void replace(LayoutPart oldChild, LayoutPart newChild) {
if (!isChild(oldChild)) {
return;
}
if (oldChild == getZoomedPart()) {
if (newChild instanceof PartPlaceholder) {
childRequestZoomOut();
} else {
zoomedPart.setZoomed(false);
zoomedPart = newChild;
zoomedPart.setZoomed(true);
}
}
children.remove(oldChild);
children.add(newChild);
childAdded(newChild);
if (root != null) {
LayoutTree leaf = null;
leaf = root.find(oldChild);
if (leaf != null) {
leaf.setPart(newChild);
}
}
childRemoved(oldChild);
if (active) {
oldChild.setVisible(false);
oldChild.setContainer(null);
newChild.createControl(parent);
newChild.setContainer(this);
newChild.setVisible(zoomedPart == null || zoomedPart == newChild);
resizeChild(newChild);
}
}
private void resizeSashes() {
layoutDirty = false;
if (!active) {
return;
}
if (isZoomed()) {
getZoomedPart().setBounds(parent.getClientArea());
} else {
if (root != null) {
root.setBounds(parent.getClientArea());
}
}
}
/**
* Returns the maximum size that can be utilized by this part if the given width and
* height are available. Parts can overload this if they have a quantized set of preferred
* sizes.
*
* @param width available horizontal space (pixels)
* @return returns a new point where point.x is <= availableWidth and point.y is <= availableHeight
*/
public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredParallel) {
if (isZoomed()) {
return getZoomedPart().computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
}
if (root != null) {
return root.computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
}
return preferredParallel;
}
public int getSizeFlags(boolean width) {
if (isZoomed()) {
return getZoomedPart().getSizeFlags(width);
}
if (root != null) {
return root.getSizeFlags(width);
}
return 0;
}
/**
* @see LayoutPart#setBounds
*/
public void setBounds(Rectangle r) {
this.parent.setBounds(r);
}
/**
* Zoom in on a particular layout part.
*
* The implementation of zoom is quite simple. When zoom occurs we create
* a zoom root which only contains the zoom part. We store the old
* root in unzoomRoot and then active the zoom root. When unzoom occurs
* we restore the unzoomRoot and dispose the zoom root.
*
* Note: Method assumes we are active.
*/
private void zoomIn(LayoutPart part) {
// Sanity check.
if (isZoomed()) {
return;
}
// Hide the sashes
root.disposeSashes();
// Make all parts invisible except for the zoomed part
LayoutPart[] children = getChildren();
for (int i = 0; i < children.length; i++) {
LayoutPart child = children[i];
child.setVisible(child == part);
}
zoomedPart = part;
// Notify the part that it has been zoomed
part.setZoomed(true);
// Remember that we need to trigger a layout
layoutDirty = true;
}
/**
* Returns the currently zoomed part or null if none
*
* @return the currently zoomed part or null if none
* @since 3.1
*/
public LayoutPart getZoomedPart() {
return zoomedPart;
}
public void childRequestZoomIn(LayoutPart toZoom) {
if (!SwtUtil.isDisposed(this.parent)) {
this.parent.setRedraw(false);
}
try {
zoomIn(toZoom);
requestZoomIn();
if (layoutDirty) {
resizeSashes();
}
} finally {
if (!SwtUtil.isDisposed(this.parent)) {
this.parent.setRedraw(true);
}
}
}
public void childRequestZoomOut() {
if (!SwtUtil.isDisposed(this.parent)) {
this.parent.setRedraw(false);
}
try {
zoomOut();
requestZoomOut();
if (layoutDirty) {
resizeSashes();
}
} finally {
if (!SwtUtil.isDisposed(this.parent)) {
this.parent.setRedraw(true);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#setZoomed(boolean)
*/
public void setZoomed(boolean isZoomed) {
if (!isZoomed) {
zoomOut();
} else {
if (!isZoomed()) {
LayoutPart toZoom = pickPartToZoom();
if (toZoom != null) {
zoomIn(toZoom);
}
}
}
super.setZoomed(isZoomed);
}
public LayoutPart pickPartToZoom() {
return findBottomRight();
}
/**
* Zoom out.
*
* See zoomIn for implementation details.
*
* Note: Method assumes we are active.
*/
private void zoomOut() {
// Sanity check.
if (!isZoomed()) {
return;
}
LayoutPart zoomedPart = this.zoomedPart;
this.zoomedPart = null;
// Inform the part that it is no longer zoomed
zoomedPart.setZoomed(false);
// Make all children visible
LayoutPart[] children = getChildren();
for (int i = 0; i < children.length; i++) {
LayoutPart child = children[i];
child.setVisible(true);
}
// Recreate the sashes
root.createControl(getParent());
// Ensure that the part being un-zoomed will have its size refreshed.
LayoutTree node = root.find(zoomedPart);
node.flushCache();
layoutDirty = true;
}
/* (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, Rectangle dragRectangle) {
if (!(draggedObject instanceof LayoutPart)) {
return null;
}
final LayoutPart sourcePart = (LayoutPart) draggedObject;
if (!isStackType(sourcePart) && !isPaneType(sourcePart)) {
return null;
}
boolean differentWindows = sourcePart.getWorkbenchWindow() != getWorkbenchWindow();
boolean editorDropOK = ((sourcePart instanceof EditorPane) &&
sourcePart.getWorkbenchWindow().getWorkbench() ==
getWorkbenchWindow().getWorkbench());
if (differentWindows && !editorDropOK) {
return null;
}
Rectangle containerBounds = DragUtil.getDisplayBounds(parent);
LayoutPart targetPart = null;
ILayoutContainer sourceContainer = isStackType(sourcePart) ? (ILayoutContainer) sourcePart
: sourcePart.getContainer();
// If this container has no visible children
if (getVisibleChildrenCount(this) == 0) {
return createDropTarget(sourcePart, SWT.CENTER, SWT.CENTER, null);
}
if (containerBounds.contains(position)) {
if (root != null) {
targetPart = root.findPart(parent.toControl(position));
}
if (targetPart != null) {
final Control targetControl = targetPart.getControl();
final Rectangle targetBounds = DragUtil
.getDisplayBounds(targetControl);
int side = Geometry.getClosestSide(targetBounds, position);
int distance = Geometry.getDistanceFromEdge(targetBounds, position, side);
// is the source coming from a standalone part
boolean standalone = (isStackType(sourcePart)
&& ((PartStack) sourcePart).isStandalone())
|| (isPaneType(sourcePart)
&& ((PartPane) sourcePart).getStack()!=null
&& ((PartPane) sourcePart).getStack().isStandalone());
// Only allow dropping onto an existing stack from different windows
if (differentWindows && targetPart instanceof EditorStack) {
IDropTarget target = targetPart.getDropTarget(draggedObject, position);
return target;
}
// Reserve the 5 pixels around the edge of the part for the drop-on-edge cursor
if (distance >= 5 && !standalone) {
// Otherwise, ask the part if it has any special meaning for this drop location
IDropTarget target = targetPart.getDropTarget(draggedObject, position);
if (target != null) {
return target;
}
}
if (distance > 30 && isStackType(targetPart) && !standalone) {
if (targetPart instanceof ILayoutContainer) {
ILayoutContainer targetContainer = (ILayoutContainer)targetPart;
if (targetContainer.allowsAdd(sourcePart)) {
side = SWT.CENTER;
}
}
}
// If the part doesn't want to override this drop location then drop on the edge
// A "pointless drop" would be one that will put the dragged object back where it started.
// Note that it should be perfectly valid to drag an object back to where it came from -- however,
// the drop should be ignored.
boolean pointlessDrop = isZoomed();
if (sourcePart == targetPart) {
pointlessDrop = true;
}
if ((sourceContainer != null)
&& (sourceContainer == targetPart)
&& getVisibleChildrenCount(sourceContainer) <= 1) {
pointlessDrop = true;
}
if (side == SWT.CENTER
&& sourcePart.getContainer() == targetPart) {
pointlessDrop = true;
}
int cursor = side;
if (pointlessDrop) {
side = SWT.NONE;
cursor = SWT.CENTER;
}
return createDropTarget(sourcePart, side, cursor, targetPart);
}
} else {
// We only allow dropping into a stack, not creating one
if (differentWindows)
return null;
int side = Geometry.getClosestSide(containerBounds, position);
boolean pointlessDrop = isZoomed();
if ((isStackType(sourcePart) && sourcePart.getContainer() == this)
|| (sourcePart.getContainer() != null
&& isPaneType(sourcePart)
&& getVisibleChildrenCount(sourcePart.getContainer()) <= 1)
&& ((LayoutPart)sourcePart.getContainer()).getContainer() == this) {
if (root == null || getVisibleChildrenCount(this) <= 1) {
pointlessDrop = true;
}
}
int cursor = Geometry.getOppositeSide(side);
if (pointlessDrop) {
side = SWT.NONE;
}
return createDropTarget(sourcePart, side, cursor, null);
}
return null;
}
/**
* @param sourcePart
* @param targetPart
* @param side
* @param cursor
* @return
* @since 3.1
*/
private SashContainerDropTarget createDropTarget(final LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
if (dropTarget == null) {
dropTarget = new SashContainerDropTarget(sourcePart, side, cursor,
targetPart);
} else {
dropTarget.setTarget(sourcePart, side, cursor, targetPart);
}
return dropTarget;
}
/**
* Returns true iff this PartSashContainer allows its parts to be stacked onto the given
* container.
*
* @param container
* @return
*/
public abstract boolean isStackType(LayoutPart toTest);
public abstract boolean isPaneType(LayoutPart toTest);
/* (non-Javadoc)
* @see org.eclipse.ui.internal.PartSashContainer#dropObject(org.eclipse.ui.internal.LayoutPart, org.eclipse.ui.internal.LayoutPart, int)
*/
protected void dropObject(PartPane[] toDrop, LayoutPart visiblePart,
LayoutPart targetPart, int side) {
getControl().setRedraw(false);
// Targetpart is null if there isn't a part under the cursor (all the parts are
// hidden or the container is empty). In this case, the actual side doesn't really
// since we'll be the only visible container and will fill the entire space. However,
// we can't leave it as SWT.CENTER since we can't stack if we don't have something
// to stack on. In this case, we pick SWT.BOTTOM -- this will insert the new pane
// below any currently-hidden parts.
if (targetPart == null && side == SWT.CENTER) {
side = SWT.BOTTOM;
}
if (side == SWT.CENTER) {
if (isStackType(targetPart)) {
PartStack stack = (PartStack) targetPart;
for (int idx = 0; idx < toDrop.length; idx++) {
PartPane next = toDrop[idx];
stack(next, stack);
}
}
} else {
PartStack newPart = createStack();
// if the toDrop array has 1 item propogate the stack
// appearance
if (toDrop.length == 1 && toDrop[0].getStack()!=null) {
toDrop[0].getStack().copyAppearanceProperties(newPart);
}
for (int idx = 0; idx < toDrop.length; idx++) {
PartPane next = toDrop[idx];
stack(next, newPart);
}
addEnhanced(newPart, side, getDockingRatio(newPart, targetPart),
targetPart);
}
if (visiblePart != null) {
setVisiblePart(visiblePart.getContainer(), visiblePart);
}
getControl().setRedraw(true);
if (visiblePart != null) {
visiblePart.setFocus();
}
}
protected abstract PartStack createStack();
public void stack(LayoutPart newPart, ILayoutContainer container) {
getControl().setRedraw(false);
// Only deref the part if it is being referenced in -this- perspective
Perspective persp = page.getActivePerspective();
PerspectiveHelper pres = (persp != null) ? persp.getPresentation() : null;
if (pres != null && newPart instanceof ViewPane) {
ViewPane vp = (ViewPane) newPart;
IViewReference vRef = vp.getViewReference();
LayoutPart fpp = pres.findPart(vRef.getId(), vRef.getSecondaryId());
if (fpp != null) {
// Remove the part from old container.
derefPart(newPart);
}
}
else {
// Remove the part from old container.
derefPart(newPart);
}
// Reparent part and add it to the workbook
newPart.reparent(getParent());
container.add(newPart);
getControl().setRedraw(true);
}
/**
* @param container
* @param visiblePart
*/
protected abstract void setVisiblePart(ILayoutContainer container,
LayoutPart visiblePart);
/**
* @param container
* @return
*/
protected abstract LayoutPart getVisiblePart(ILayoutContainer container);
/**
* @param sourcePart
*/
protected void derefPart(LayoutPart sourcePart) {
ILayoutContainer container = sourcePart.getContainer();
if (container != null) {
container.remove(sourcePart);
}
if (container instanceof LayoutPart) {
if (isStackType((LayoutPart) container)) {
PartStack stack = (PartStack) container;
if (stack.getChildren().length == 0) {
remove(stack);
stack.dispose();
}
}
}
}
protected int getVisibleChildrenCount(ILayoutContainer container) {
// Treat null as an empty container
if (container == null) {
return 0;
}
LayoutPart[] children = container.getChildren();
int count = 0;
for (int idx = 0; idx < children.length; idx++) {
if (!(children[idx] instanceof PartPlaceholder)) {
count++;
}
}
return count;
}
protected float getDockingRatio(LayoutPart dragged, LayoutPart target) {
return 0.5f;
}
/**
* Writes a description of the layout to the given string buffer.
* This is used for drag-drop test suites to determine if two layouts are the
* same. Like a hash code, the description should compare as equal iff the
* layouts are the same. However, it should be user-readable in order to
* help debug failed tests. Although these are english readable strings,
* they should not be translated or equality tests will fail.
*
* @param buf
*/
public void describeLayout(StringBuffer buf) {
if (root == null) {
return;
}
if (isZoomed()) {
buf.append("zoomed "); //$NON-NLS-1$
root.describeLayout(buf);
} else {
buf.append("layout "); //$NON-NLS-1$
root.describeLayout(buf);
}
}
/**
* Adds a new child to the container relative to some part
*
* @param child
* @param relationship
* @param left preferred pixel size of the left/top child
* @param right preferred pixel size of the right/bottom child
* @param relative relative part
*/
void add(LayoutPart child, int relationship, int left, int right,
LayoutPart relative) {
if (child == null) {
return;
}
if (relative != null && !isChild(relative)) {
return;
}
if (relationship < IPageLayout.LEFT
|| relationship > IPageLayout.BOTTOM) {
relationship = IPageLayout.LEFT;
}
// store info about relative positions
RelationshipInfo info = new RelationshipInfo();
info.part = child;
info.relationship = relationship;
info.left = left;
info.right = right;
info.relative = relative;
addChild(info);
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.ILayoutContainer#isZoomed(org.eclipse.ui.internal.LayoutPart)
*/
public boolean childIsZoomed(LayoutPart toTest) {
return toTest == getZoomedPart();
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.ILayoutContainer#allowsAutoFocus()
*/
public boolean allowsAutoFocus() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#startDeferringEvents()
*/
protected void startDeferringEvents() {
super.startDeferringEvents();
LayoutPart[] deferredChildren = (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
for (int i = 0; i < deferredChildren.length; i++) {
LayoutPart child = deferredChildren[i];
child.deferUpdates(true);
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#handleDeferredEvents()
*/
protected void handleDeferredEvents() {
super.handleDeferredEvents();
LayoutPart[] deferredChildren = (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
for (int i = 0; i < deferredChildren.length; i++) {
LayoutPart child = deferredChildren[i];
child.deferUpdates(false);
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.LayoutPart#testInvariants()
*/
public void testInvariants() {
super.testInvariants();
// If we have a parent container, ensure that we are displaying the zoomed appearance iff
// our parent is zoomed in on us
if (getContainer() != null) {
Assert.isTrue((getZoomedPart() != null) == (getContainer().childIsZoomed(this)));
}
LayoutPart[] childArray = getChildren();
for (int idx = 0; idx < childArray.length; idx++) {
childArray[idx].testInvariants();
}
// If we're zoomed, ensure that we're actually zoomed into one of our children
if (isZoomed()) {
Assert.isTrue(children.contains(zoomedPart));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy