package com.peterhi.ui.obsolete;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import com.peterhi.ui.UI;
public final class DockContainer extends Composite implements Listener {
public static enum Position {
LEFT,
TOP,
RIGHT,
BOTTOM;
public Orientation getOrientation() {
if (this == TOP) {
return Orientation.VERTICAL;
}
if (this == BOTTOM) {
return Orientation.VERTICAL;
}
return Orientation.HORIZONTAL;
}
public boolean isVertical() {
return getOrientation().isVertical();
}
public boolean isPositiveDirection() {
if (this == RIGHT) {
return true;
}
if (this == BOTTOM) {
return true;
}
return false;
}
}
public static enum Orientation {
HORIZONTAL,
VERTICAL;
public boolean isVertical() {
if (this == VERTICAL) {
return true;
}
return false;
}
}
static enum TouchResult {
NONE,
BEFORE,
AFTER
}
public static final class Specification {
private final Control reference;
private final Position position;
private final float proportion;
public Specification(Control reference, Position position, float proportion) {
if (position == null) {
throw new NullPointerException("Position is null.");
}
if (proportion <= 0.0f) {
throw new IllegalArgumentException(MessageFormat.format("Proportion {0} is less than or equal to zero.", Float.toString(proportion)));
}
if (proportion >= 1.0f) {
throw new IllegalArgumentException(MessageFormat.format("Proportion {0} is greater than or equal to one.", Float.toString(proportion)));
}
this.reference = reference;
this.position = position;
this.proportion = proportion;
}
public Control getReference() {
return reference;
}
public Position getPosition() {
return position;
}
public Orientation getOrientation() {
return position.getOrientation();
}
public boolean isVertical() {
return position.isVertical();
}
public float getProportion() {
return proportion;
}
}
public static final class ControlAlreadyDockedException extends Exception {
private static final long serialVersionUID = -7572638040253760184L;
public ControlAlreadyDockedException() {
super();
}
public ControlAlreadyDockedException(String message, Throwable cause) {
super(message, cause);
}
public ControlAlreadyDockedException(String message) {
super(message);
}
public ControlAlreadyDockedException(Throwable cause) {
super(cause);
}
}
public static final class NoSuchReferenceControlException extends Exception {
private static final long serialVersionUID = 2887015206953145133L;
public NoSuchReferenceControlException() {
super();
}
public NoSuchReferenceControlException(String message, Throwable cause) {
super(message, cause);
}
public NoSuchReferenceControlException(String message) {
super(message);
}
public NoSuchReferenceControlException(Throwable cause) {
super(cause);
}
}
public static final class InsufficientControlSizeException extends Exception {
private static final long serialVersionUID = -4126025456097998310L;
public InsufficientControlSizeException() {
super();
}
public InsufficientControlSizeException(String message, Throwable cause) {
super(message, cause);
}
public InsufficientControlSizeException(String message) {
super(message);
}
public InsufficientControlSizeException(Throwable cause) {
super(cause);
}
}
static final class XYComparator implements Comparator<Object> {
private static XYComparator xComparator;
private static XYComparator yComparator;
public static XYComparator getInstance(Orientation orientation) {
XYComparator instance;
if (orientation.isVertical()) {
if (yComparator == null) {
yComparator = new XYComparator(orientation);
}
instance = yComparator;
} else {
if (xComparator == null) {
xComparator = new XYComparator(orientation);
}
instance = xComparator;
}
return instance;
}
private final Orientation orientation;
protected XYComparator(Orientation orientation) {
if (orientation == null) {
throw new NullPointerException();
}
this.orientation = orientation;
}
public Orientation getOrientation() {
return orientation;
}
public boolean isVertical() {
return orientation.isVertical();
}
@Override
public int compare(Object object, Object other) {
Bounds bounds = getBounds(object);
Bounds otherBounds = getBounds(other);
int result = isVertical() ? (bounds.getTop() - otherBounds.getTop()) : (bounds.getLeft() - otherBounds.getLeft());
if (result == 0) {
result = isVertical() ? (bounds.getLeft() - otherBounds.getLeft()) : (bounds.getTop() - otherBounds.getTop());
}
if (result == 0) {
result = object.hashCode() - other.hashCode();
}
return result;
}
private Bounds getBounds(Object object) {
try {
Class<?> type = object.getClass();
Method getBounds = type.getMethod("getBounds");
Rectangle rectangle = (Rectangle )getBounds.invoke(object);
Bounds bounds = Bounds.fromRectangle(rectangle);
return bounds;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
abstract static class Sizer {
private final DockContainer parent;
private final Rectangle bounds;
public Sizer(DockContainer parent, Rectangle bounds) {
if (parent == null) {
throw new NullPointerException();
}
if (bounds == null) {
throw new NullPointerException();
}
this.parent = parent;
this.bounds = bounds;
}
public final DockContainer getParent() {
return parent;
}
public final Rectangle getBounds() {
return bounds;
}
public abstract Group[] getGroups();
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((bounds == null) ? 0 : bounds.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Sizer other = (Sizer) obj;
if (bounds == null) {
if (other.bounds != null)
return false;
} else if (!bounds.equals(other.bounds))
return false;
return true;
}
protected final Group getGroup(Orientation orientation) {
XYComparator comp = XYComparator.getInstance(orientation);
SortedSet<Sizer> sizers = new TreeSet<Sizer>(comp);
getGroup(this, orientation, false, sizers);
getGroup(this, orientation, true, sizers);
Sizer[] ref = sizers.toArray(new Sizer[sizers.size()]);
if (ref[0] instanceof Grip) {
sizers.remove(ref[0]);
}
if (ref[ref.length - 1] instanceof Grip) {
sizers.remove(ref[ref.length - 1]);
}
Group group = new Group(parent, sizers.toArray(new Sizer[sizers.size()]), orientation);
return group;
}
private void getGroup(Sizer current, Orientation orientation, boolean positiveDirection, SortedSet<Sizer> sizers) {
if (current == null) {
throw new NullPointerException();
}
if (orientation == null) {
throw new NullPointerException();
}
if (sizers == null) {
throw new NullPointerException();
}
Bounds clientArea = Bounds.fromRectangle(parent.getClientArea());
Bounds bounds = Bounds.fromRectangle(current.getBounds());
sizers.add(current);
if (orientation.isVertical()) {
if (positiveDirection) {
if (bounds.getBottom() >= clientArea.getBottom()) {
return;
}
} else {
if (bounds.getTop() <= clientArea.getTop()) {
return;
}
}
} else {
if (positiveDirection) {
if (bounds.getRight() >= clientArea.getRight()) {
return;
}
} else {
if (bounds.getLeft() <= clientArea.getLeft()) {
return;
}
}
}
Sizer[] others = parent.getSizers();
if (orientation.isVertical()) {
for (Sizer other : others) {
if (current.equals(other)) {
continue;
}
if (other instanceof Split) {
Split split = (Split )other;
if (split.getOrientation() != orientation) {
continue;
}
}
Bounds otherBounds = Bounds.fromRectangle(other.getBounds());
if (bounds.getLeft() != otherBounds.getLeft()) {
continue;
}
if (bounds.getRight() != otherBounds.getRight()) {
continue;
}
if (bounds.getTop() > otherBounds.getBottom() || bounds.getBottom() < otherBounds.getTop()) {
continue;
}
if (positiveDirection) {
if (otherBounds.getTop() > bounds.getTop()) {
getGroup(other, orientation, positiveDirection, sizers);
}
} else {
if (bounds.getTop() > otherBounds.getTop()) {
getGroup(other, orientation, positiveDirection, sizers);
}
}
}
} else {
for (Sizer other : others) {
if (current.equals(other)) {
continue;
}
if (other instanceof Split) {
Split split = (Split )other;
if (split.getOrientation() != orientation) {
continue;
}
}
Bounds otherBounds = Bounds.fromRectangle(other.getBounds());
if (bounds.getTop() != otherBounds.getTop()) {
continue;
}
if (bounds.getBottom() != otherBounds.getBottom()) {
continue;
}
if (bounds.getLeft() > otherBounds.getRight() || bounds.getRight() < otherBounds.getLeft()) {
continue;
}
if (positiveDirection) {
if (otherBounds.getLeft() > bounds.getLeft()) {
getGroup(other, orientation, positiveDirection, sizers);
}
} else {
if (bounds.getLeft() > otherBounds.getLeft()) {
getGroup(other, orientation, positiveDirection, sizers);
}
}
}
}
}
}
static final class Split extends Sizer {
private final Orientation orientation;
public Split(DockContainer parent, Rectangle bounds, Orientation orientation) {
super(parent, bounds);
if (orientation == null) {
throw new NullPointerException();
}
this.orientation = orientation;
}
public Orientation getOrientation() {
return orientation;
}
public boolean isVertical() {
return orientation.isVertical();
}
@Override
public Group[] getGroups() {
return new Group[] { getGroup(orientation) };
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result
+ ((orientation == null) ? 0 : orientation.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
Split other = (Split) obj;
if (orientation != other.orientation)
return false;
return true;
}
}
static final class Grip extends Sizer {
public Grip(DockContainer parent, Rectangle bounds) {
super(parent, bounds);
}
@Override
public Group[] getGroups() {
return new Group[] { getGroup(Orientation.HORIZONTAL),
getGroup(Orientation.VERTICAL) };
}
}
static final class Group {
private final DockContainer parent;
private final Sizer[] sizers;
private final Orientation orientation;
public Group(DockContainer parent, Sizer[] sizers, Orientation orientation) {
if (parent == null) {
throw new NullPointerException();
}
if (sizers == null) {
throw new NullPointerException();
}
if (orientation == null) {
throw new NullPointerException();
}
if (sizers.length <= 0) {
throw new IllegalArgumentException();
}
this.parent = parent;
this.orientation = orientation;
this.sizers = Arrays.copyOf(sizers, sizers.length);
XYComparator comp = XYComparator.getInstance(orientation);
Arrays.sort(this.sizers, comp);
}
public DockContainer getParent() {
return parent;
}
public Orientation getOrientation() {
return orientation;
}
public boolean isVertical() {
return orientation.isVertical();
}
public int size() {
return sizers.length;
}
public Sizer get(int index) {
return sizers[index];
}
public int indexOf(Sizer sizer) {
for (int i = 0; i < sizers.length; i++) {
Sizer other = sizers[i];
if (other.equals(sizer)) {
return i;
}
}
return -1;
}
public boolean contains(Sizer sizer) {
int index = indexOf(sizer);
return index != -1;
}
public Sizer[] getSizers() {
return Arrays.copyOf(sizers, sizers.length);
}
public Split[] getSplits() {
XYComparator comp = XYComparator.getInstance(getOrientation());
SortedSet<Split> splits = new TreeSet<Split>(comp);
for (Sizer other : sizers) {
if (other instanceof Split) {
Split split = (Split )other;
splits.add(split);
}
}
return splits.toArray(new Split[splits.size()]);
}
public Grip[] getGrips() {
XYComparator comp = XYComparator.getInstance(getOrientation());
SortedSet<Grip> grips = new TreeSet<Grip>(comp);
for (Sizer other : sizers) {
if (other instanceof Grip) {
Grip grip = (Grip )other;
grips.add(grip);
}
}
return grips.toArray(new Grip[grips.size()]);
}
public Rectangle getBounds() {
Bounds bounds = Bounds.newInstance();
for (int i = 0; i < sizers.length; i++) {
Sizer sizer = sizers[i];
Bounds sizerBounds = Bounds.fromRectangle(sizer.getBounds());
if (i == 0) {
bounds.setLeft(sizerBounds.getLeft(), false);
bounds.setTop(sizerBounds.getTop(), false);
bounds.setRight(sizerBounds.getRight(), false);
bounds.setBottom(sizerBounds.getBottom(), false);
} else {
if (sizerBounds.getLeft() < bounds.getLeft()) {
bounds.setLeft(bounds.getLeft(), false);
}
if (sizerBounds.getTop() < bounds.getTop()) {
bounds.setTop(bounds.getTop(), false);
}
if (sizerBounds.getRight() > bounds.getRight()) {
bounds.setRight(sizerBounds.getRight(), false);
}
if (sizerBounds.getBottom() > bounds.getBottom()) {
bounds.setBottom(sizerBounds.getBottom(), false);
}
}
}
return bounds.toRectangle();
}
public Control[][] getAffects() {
XYComparator comp = XYComparator.getInstance(getOrientation());
SortedSet<Control> before = new TreeSet<Control>(comp);
SortedSet<Control> after = new TreeSet<Control>(comp);
Control[] controls = parent.getControls();
for (Control control : controls) {
Bounds controlBounds = Bounds.fromRectangle(control.getBounds());
TouchResult result = getTouchResult(controlBounds);
if (result == TouchResult.BEFORE) {
before.add(control);
} else if (result == TouchResult.AFTER) {
after.add(control);
}
}
return new Control[][] {
before.toArray(new Control[before.size()]),
after.toArray(new Control[after.size()])
};
}
public Group[][] getConflicts() {
XYComparator comp = XYComparator.getInstance(isVertical() ? Orientation.HORIZONTAL : Orientation.VERTICAL);
SortedSet<Group> before = new TreeSet<Group>(comp);
SortedSet<Group> after = new TreeSet<Group>(comp);
Group[] groups = parent.getGroups();
Bounds bounds = Bounds.fromRectangle(getBounds());
for (Group group : groups) {
if (equals(group)) {
continue;
}
if (getOrientation() != group.getOrientation()) {
continue;
}
Bounds groupBounds = Bounds.fromRectangle(group.getBounds());
if (isVertical()) {
if (bounds.getTop() <= groupBounds.getBottom() && bounds.getBottom() >= groupBounds.getTop()) {
if (groupBounds.getRight() <= bounds.getLeft()) {
before.add(group);
}
if (bounds.getRight() <= groupBounds.getLeft()) {
after.add(group);
}
}
} else {
if (bounds.getLeft() <= groupBounds.getRight() && bounds.getRight() >= groupBounds.getLeft()) {
if (groupBounds.getBottom() <= bounds.getTop()) {
before.add(group);
}
if (bounds.getBottom() <= groupBounds.getTop()) {
after.add(group);
}
}
}
}
return new Group[][] {
before.toArray(new Group[before.size()]),
after.toArray(new Group[after.size()])
};
}
public Group[][] getConnects() {
XYComparator comp = XYComparator.getInstance(getOrientation());
SortedSet<Group> before = new TreeSet<Group>(comp);
SortedSet<Group> after = new TreeSet<Group>(comp);
Group[] groups = parent.getGroups();
for (Group group : groups) {
if (equals(group)) {
continue;
}
if (getOrientation() == group.getOrientation()) {
continue;
}
Bounds groupBounds = Bounds.fromRectangle(group.getBounds());
TouchResult result = getTouchResult(groupBounds);
if (result == TouchResult.BEFORE) {
before.add(group);
} else if (result == TouchResult.AFTER) {
after.add(group);
}
}
return new Group[][] {
before.toArray(new Group[before.size()]),
after.toArray(new Group[after.size()])
};
}
public Group[][] getSnaps() {
Bounds bounds = Bounds.fromRectangle(getBounds());
Point first = new Point(0, 0);
Point last = new Point(0, 0);
if (isVertical()) {
first.x = bounds.getCenterX();
first.y = bounds.getTop() - bounds.getWidth() / 2;
last.x = bounds.getCenterX();
last.y = bounds.getBottom() + bounds.getWidth() / 2;
} else {
first.x = bounds.getLeft() - bounds.getHeight() / 2;
first.y = bounds.getCenterY();
last.x = bounds.getRight() + bounds.getHeight() / 2;
last.y = bounds.getCenterY();
}
XYComparator comp = XYComparator.getInstance(isVertical() ? Orientation.HORIZONTAL : Orientation.VERTICAL);
SortedSet<Group> before = new TreeSet<Group>(comp);
SortedSet<Group> after = new TreeSet<Group>(comp);
Group[] groups = parent.getGroups();
for (Group group : groups) {
if (getOrientation() == group.getOrientation()) {
continue;
}
Rectangle groupBounds = group.getBounds();
if (groupBounds.contains(first)) {
Group[][] connected = group.getConnects();
Group[] groupsBefore = connected[0];
for (Group groupBefore : groupsBefore) {
before.add(groupBefore);
}
} else if (groupBounds.contains(last)) {
Group[][] connected = group.getConnects();
Group[] groupsAfter = connected[1];
for (Group groupAfter : groupsAfter) {
after.add(groupAfter);
}
}
}
before.remove(this);
after.remove(this);
return new Group[][] {
before.toArray(new Group[before.size()]),
after.toArray(new Group[after.size()])
};
}
public Group[] getIntersects() {
XYComparator comp = XYComparator.getInstance(getOrientation());
SortedSet<Group> intersected = new TreeSet<Group>(comp);
Group[] groups = parent.getGroups();
Rectangle bounds = getBounds();
for (Group group : groups) {
if (equals(group)) {
continue;
}
if (getOrientation() == group.getOrientation()) {
continue;
}
Rectangle groupBounds = group.getBounds();
if (bounds.intersects(groupBounds)) {
intersected.add(group);
}
}
return intersected.toArray(new Group[intersected.size()]);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((orientation == null) ? 0 : orientation.hashCode());
result = prime * result + Arrays.hashCode(sizers);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Group other = (Group) obj;
if (orientation != other.orientation)
return false;
if (!Arrays.equals(sizers, other.sizers))
return false;
return true;
}
private TouchResult getTouchResult(Bounds controlBounds) {
if (controlBounds == null) {
throw new NullPointerException();
}
Bounds bounds = Bounds.fromRectangle(getBounds());
TouchResult result = TouchResult.NONE;
if (isVertical()) {
if (controlBounds.getTop() <= bounds.getBottom() && controlBounds.getBottom() >= bounds.getTop()) {
if (controlBounds.getRight() == bounds.getLeft()) {
result = TouchResult.BEFORE;
}
if (bounds.getRight() == controlBounds.getLeft()) {
result = TouchResult.AFTER;
}
}
} else {
if (controlBounds.getLeft() <= bounds.getRight() && controlBounds.getRight() >= bounds.getLeft()) {
if (controlBounds.getBottom() == bounds.getTop()) {
result = TouchResult.BEFORE;
}
if (bounds.getBottom() == controlBounds.getTop()) {
result = TouchResult.AFTER;
}
}
}
return result;
}
}
static class DragGroupInfo {
private final Group group;
private final Rectangle cachedBounds = new Rectangle(0, 0, 0, 0);
private Control[][] cachedAffects;
private Group[][] cachedConflicts;
private Group[][] cachedConnects;
private Group[][] cachedSnaps;
private Group[] cachedIntersects;
public DragGroupInfo(Group group) {
this.group = group;
}
public Group getGroup() {
return group;
}
public Rectangle getCachedBounds() {
return new Rectangle(cachedBounds.x, cachedBounds.y, cachedBounds.width, cachedBounds.height);
}
public void setCachedBounds(Rectangle value) {
if (value == null) {
throw new NullPointerException();
}
cachedBounds.x = value.x;
cachedBounds.y = value.y;
cachedBounds.width = value.width;
cachedBounds.height = value.height;
}
public Control[][] getCachedAffects() {
return cachedAffects;
}
public void setCachedAffects(Control[][] value) {
cachedAffects = value;
}
public Group[][] getCachedConflicts() {
return cachedConflicts;
}
public void setCachedConflicts(Group[][] value) {
cachedConflicts = value;
}
public Group[][] getCachedConnects() {
return cachedConnects;
}
public void setCachedConnects(Group[][] value) {
cachedConnects = value;
}
public Group[][] getCachedSnaps() {
return cachedSnaps;
}
public void setCachedSnaps(Group[][] value) {
cachedSnaps = value;
}
public Group[] getCachedIntersects() {
return cachedIntersects;
}
public void setCachedIntersects(Group[] value) {
cachedIntersects = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((group == null) ? 0 : group.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DragGroupInfo other = (DragGroupInfo) obj;
if (group == null) {
if (other.group != null)
return false;
} else if (!group.equals(other.group))
return false;
return true;
}
}
static class DragInfo {
private final Map<Control, Bounds> controlBoundsCached = new HashMap<Control, Bounds>();
private DragGroupInfo[] groupInfos;
private final Point location = new Point(0, 0);
private final Point offset = new Point(0, 0);
public DragInfo() {
}
public Control[] getControlsCached() {
return controlBoundsCached.keySet().toArray(new Control[controlBoundsCached.size()]);
}
public void putControlBoundsCached(Control control, Bounds bounds) {
controlBoundsCached.put(control, bounds);
}
public Bounds getControlBoundsCached(Control control) {
return controlBoundsCached.get(control);
}
public DragGroupInfo[] getGroupInfos() {
return groupInfos;
}
public void setGroupInfos(DragGroupInfo[] value) {
if (value == null) {
throw new NullPointerException();
}
groupInfos = value;
}
public boolean contains(Group group) {
return getGroupInfo(group) != null;
}
public DragGroupInfo getGroupInfo(Group group) {
for (DragGroupInfo groupInfo : groupInfos) {
if (groupInfo.getGroup().equals(group)) {
return groupInfo;
}
}
return null;
}
public Point getLocation() {
return new Point(location.x, location.y);
}
public void setLocation(Point value) {
if (value == null) {
throw new NullPointerException();
}
location.x = value.x;
location.y = value.y;
}
public Point getOffset() {
return new Point(offset.x, offset.y);
}
public void setOffset(Point value) {
if (value == null) {
throw new NullPointerException();
}
offset.x = value.x;
offset.y = value.y;
}
}
private static final int BAR_SIZE = 20;
private static final int MIN_SIZE = 50;
private final List<Control> controls = new ArrayList<Control>();
private Bounds oldClient;
private DragInfo dragInfo;
public DockContainer(Composite parent, int style) {
super(parent, style);
addListener(SWT.Resize, this);
addListener(SWT.MouseEnter, this);
addListener(SWT.MouseExit, this);
addListener(SWT.MouseDown, this);
addListener(SWT.MouseMove, this);
addListener(SWT.MouseUp, this);
}
public void setMinimumShellSize(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle clientArea = shell.getClientArea();
int xDiff = bounds.width - clientArea.width;
int yDiff = bounds.height - clientArea.height;
Point minSize = computeSize(0, 0);
minSize.x += xDiff;
minSize.y += yDiff;
shell.setMinimumSize(minSize);
}
@Override
public void handleEvent(Event event) {
if (event.widget == this && event.type == SWT.Resize) {
if (oldClient == null) {
oldClient = Bounds.fromRectangle(getClientArea());
}
layout();
oldClient = Bounds.fromRectangle(getClientArea());
}
if (event.widget == this && event.type == SWT.MouseEnter) {
updateCursor(event.x, event.y);
}
if (event.widget == this && event.type == SWT.MouseExit) {
updateCursor(event.x, event.y);
}
if (event.widget == this && event.type == SWT.MouseDown && event.button == 1 && dragInfo == null) {
beginDrag(event.x, event.y, ((event.stateMask & SWT.SHIFT) != SWT.SHIFT));
}
if (event.widget == this && event.type == SWT.MouseMove) {
updateCursor(event.x, event.y);
if (dragInfo != null) {
doDrag(event.x, event.y);
}
}
if (event.widget == this && event.type == SWT.MouseUp && event.button == 1 && dragInfo != null) {
endDrag();
}
if (event.widget != this && event.widget instanceof Control && event.type == SWT.Dispose) {
Control control = (Control )event.widget;
undock(control);
}
}
private void beginDrag(int x, int y, boolean detach) {
dragInfo = new DragInfo();
dragInfo.setLocation(new Point(x, y));
Sizer[] sizers = getSizersAt(x, y);
Point offset = new Point(0, 0);
for (Sizer sizer : sizers) {
Bounds bounds = Bounds.fromRectangle(sizer.getBounds());
offset.x = x - bounds.getLeft();
offset.y = y - bounds.getTop();
break;
}
dragInfo.setOffset(offset);
Group[] groups = getGroupsAt(x, y);
Set<DragGroupInfo> groupInfos = new HashSet<DragGroupInfo>();
for (Group group : groups) {
if (detach) {
group = detachGroup(group, x, y);
}
DragGroupInfo groupInfo = new DragGroupInfo(group);
Rectangle bounds = group.getBounds();
Control[][] affected = group.getAffects();
for (Control[] array : affected) {
for (Control item : array) {
Bounds controlBounds = Bounds.fromRectangle(item.getBounds());
dragInfo.putControlBoundsCached(item, controlBounds);
}
}
Group[][] conflicted = group.getConflicts();
Group[][] connected = group.getConnects();
Group[][] snapped = group.getSnaps();
Group[] intersected = group.getIntersects();
groupInfo.setCachedBounds(bounds);
groupInfo.setCachedAffects(affected);
groupInfo.setCachedConflicts(conflicted);
groupInfo.setCachedConnects(connected);
groupInfo.setCachedSnaps(snapped);
groupInfo.setCachedIntersects(intersected);
groupInfos.add(groupInfo);
}
dragInfo.setGroupInfos(groupInfos.toArray(new DragGroupInfo[groupInfos.size()]));
}
private void doDrag(int x, int y) {
Point newLocation = new Point(x, y);
Point oldLocation = dragInfo.getLocation();
Point offset = dragInfo.getOffset();
newLocation.x -= offset.x;
newLocation.y -= offset.y;
normalizeLocation(newLocation);
newLocation.x += offset.x;
newLocation.y += offset.y;
Point moved = new Point(newLocation.x - oldLocation.x, newLocation.y - oldLocation.y);
DragGroupInfo[] groupInfos = dragInfo.getGroupInfos();
for (DragGroupInfo groupInfo : groupInfos) {
Group group = groupInfo.getGroup();
Control[][] affects = groupInfo.getCachedAffects();
Control[] affectsBefore = affects[0];
Control[] affectsAfter = affects[1];
for (Control affectBefore : affectsBefore) {
Bounds bounds = dragInfo.getControlBoundsCached(affectBefore);
if (group.isVertical()) {
bounds.setRight(bounds.getRight() + moved.x, false);
} else {
bounds.setBottom(bounds.getBottom() + moved.y, false);
}
dragInfo.putControlBoundsCached(affectBefore, bounds);
}
for (Control affectAfter : affectsAfter) {
Bounds bounds = dragInfo.getControlBoundsCached(affectAfter);
if (group.isVertical()) {
bounds.setLeft(bounds.getLeft() + moved.x, false);
} else {
bounds.setTop(bounds.getTop() + moved.y, false);
}
dragInfo.putControlBoundsCached(affectAfter, bounds);
}
}
Control[] controls = dragInfo.getControlsCached();
for (Control control : controls) {
Bounds bounds = dragInfo.getControlBoundsCached(control);
control.setBounds(bounds.toRectangle());
}
dragInfo.setLocation(newLocation);
}
private void endDrag() {
dragInfo = null;
layout();
}
private Group detachGroup(Group oldGroup, int x, int y) {
Group[] intersects = oldGroup.getIntersects();
XYComparator comp = XYComparator.getInstance(oldGroup.getOrientation());
SortedSet<Sizer> sizers = new TreeSet<Sizer>(comp);
Bounds boundary = Bounds.fromRectangle(getClientArea());
if (oldGroup.isVertical()) {
for (int i = 0; i < intersects.length; i++) {
Group intersect = intersects[i];
Bounds xsect = Bounds.fromRectangle(intersect.getBounds());
if (xsect.getBottom() <= y) {
boundary.setTop(xsect.getBottom(), false);
}
}
for (int i = intersects.length - 1; i >= 0; i--) {
Group intersect = intersects[i];
Bounds xsect = Bounds.fromRectangle(intersect.getBounds());
if (xsect.getTop() >= y) {
boundary.setBottom(xsect.getTop(), false);
}
}
for (int i = 0; i < oldGroup.size(); i++) {
Sizer sizer = oldGroup.get(i);
Bounds sizerBounds = Bounds.fromRectangle(sizer.getBounds());
if (sizerBounds.getTop() >= boundary.getTop() && sizerBounds.getBottom() <= boundary.getBottom()) {
sizers.add(sizer);
}
}
} else {
for (int i = 0; i < intersects.length; i++) {
Group intersect = intersects[i];
Bounds xsect = Bounds.fromRectangle(intersect.getBounds());
if (xsect.getRight() <= x) {
boundary.setLeft(xsect.getRight(), false);
}
}
for (int i = intersects.length - 1; i >= 0; i--) {
Group intersect = intersects[i];
Bounds xsect = Bounds.fromRectangle(intersect.getBounds());
if (xsect.getLeft() >= x) {
boundary.setRight(xsect.getLeft(), false);
}
}
for (int i = 0; i < oldGroup.size(); i++) {
Sizer sizer = oldGroup.get(i);
Bounds sizerBounds = Bounds.fromRectangle(sizer.getBounds());
if (sizerBounds.getLeft() >= boundary.getLeft() && sizerBounds.getRight() <= boundary.getRight()) {
sizers.add(sizer);
}
}
}
Group newGroup = new Group(this, sizers.toArray(new Sizer[sizers.size()]), oldGroup.getOrientation());
return newGroup;
}
private void normalizeLocation(Point location) {
DragGroupInfo[] groupInfos = dragInfo.getGroupInfos();
for (DragGroupInfo groupInfo : groupInfos) {
Group group = groupInfo.getGroup();
Group[][] snaps = groupInfo.getCachedSnaps();
for (Group[] array : snaps) {
for (Group item : array) {
Bounds bounds = Bounds.fromRectangle(item.getBounds());
if (group.isVertical()) {
if (location.x < bounds.getRight() && location.x + BAR_SIZE > bounds.getLeft()) {
location.x = bounds.getLeft();
}
} else {
if (location.y < bounds.getBottom() && location.y + BAR_SIZE > bounds.getTop()) {
location.y = bounds.getTop();
}
}
}
}
}
for (DragGroupInfo groupInfo : groupInfos) {
Group group = groupInfo.getGroup();
Bounds bounds = Bounds.fromRectangle(groupInfo.getCachedBounds());
if (group.isVertical()) {
if (location.x < bounds.getRight() && location.x + BAR_SIZE > bounds.getLeft()) {
location.x = bounds.getLeft();
}
} else {
if (location.y < bounds.getBottom() && location.y + BAR_SIZE > bounds.getTop()) {
location.y = bounds.getTop();
}
}
}
Bounds bounds = Bounds.fromRectangle(getClientArea());
for (DragGroupInfo groupInfo : groupInfos) {
Group group = groupInfo.getGroup();
Group[][] conflicts = groupInfo.getCachedConflicts();
Group[] conflictsBefore = conflicts[0];
Group[] conflictsAfter = conflicts[1];
if (conflictsBefore.length > 0) {
Group conflictBefore = conflictsBefore[conflictsBefore.length - 1];
Bounds boundsBefore = Bounds.fromRectangle(conflictBefore.getBounds());
if (group.isVertical()) {
if (bounds.getLeft() < boundsBefore.getRight()) {
bounds.setLeft(boundsBefore.getRight(), false);
}
} else {
if (bounds.getTop() < boundsBefore.getBottom()) {
bounds.setTop(boundsBefore.getBottom(), false);
}
}
}
if (conflictsAfter.length > 0) {
Group conflictAfter = conflictsAfter[0];
Bounds boundsAfter = Bounds.fromRectangle(conflictAfter.getBounds());
if (group.isVertical()) {
if (bounds.getRight() > boundsAfter.getLeft()) {
bounds.setRight(boundsAfter.getLeft(), false);
}
} else {
if (bounds.getBottom() > boundsAfter.getTop()) {
bounds.setBottom(boundsAfter.getTop(), false);
}
}
}
}
bounds.setRight(bounds.getRight() - BAR_SIZE, false);
bounds.setBottom(bounds.getBottom() - BAR_SIZE, false);
bounds.setLeft(bounds.getLeft() + MIN_SIZE, false);
bounds.setTop(bounds.getTop() + MIN_SIZE, false);
bounds.setRight(bounds.getRight() - MIN_SIZE, false);
bounds.setBottom(bounds.getBottom() - MIN_SIZE, false);
if (location.x > bounds.getRight()) {
location.x = bounds.getRight();
}
if (location.x < bounds.getLeft()) {
location.x = bounds.getLeft();
}
if (location.y > bounds.getBottom()) {
location.y = bounds.getBottom();
}
if (location.y < bounds.getTop()) {
location.y = bounds.getTop();
}
}
public Control[] getControls() {
Control[] array = controls.toArray(new Control[controls.size()]);
XYComparator comp = XYComparator.getInstance(Orientation.HORIZONTAL);
Arrays.sort(array, comp);
return controls.toArray(array);
}
@Override
public void setLayout(Layout layout) {
}
@Override
public Point computeSize(int widthHint, int heightHint, boolean changed) {
Point computedSize = super.computeSize(widthHint, heightHint, changed);
Control xMin = null;
Control yMin = null;
int minWidth = 0;
int minHeight = 0;
Control[] controls = getControls();
Arrays.sort(controls, XYComparator.getInstance(Orientation.HORIZONTAL));
for (Control control : controls) {
Rectangle bounds = control.getBounds();
if (xMin == null) {
xMin = control;
minWidth = bounds.width;
} else if (bounds.width < minWidth) {
xMin = control;
minWidth = bounds.width;
}
if (yMin == null) {
yMin = control;
minHeight = bounds.height;
} else if (bounds.height < minHeight) {
yMin = control;
minHeight = bounds.height;
}
}
Rectangle clientArea = getClientArea();
if (xMin != null) {
float xProportion = (float )MIN_SIZE / (float )minWidth;
minWidth = Math.round(clientArea.width * xProportion);
}
if (yMin != null) {
float yProportion = (float )MIN_SIZE / (float )minHeight;
minHeight = Math.round(clientArea.height * yProportion);
}
if (xMin != null && computedSize.x < minWidth) {
computedSize.x = minWidth;
}
if (yMin != null && computedSize.y < minHeight) {
computedSize.y = minHeight;
}
return computedSize;
}
@Override
public void layout(boolean changed) {
try {
Bounds newClient = Bounds.fromRectangle(getClientArea());
Map<Control, Bounds> controlBounds = computeLayoutBounds(newClient);
for (Control key : controlBounds.keySet()) {
Bounds value = controlBounds.get(key);
key.setBounds(value.toRectangle());
}
} catch (RuntimeException ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public boolean isDockable(Control control, Specification specification) {
if (control == null) {
throw new NullPointerException("Control is null.");
}
try {
Map<Control, Rectangle> controlBounds = computeDockBounds(control, specification);
return !controlBounds.isEmpty();
} catch (Exception ex) {
return false;
}
}
public void dock(Control control, Specification specification) {
if (control == null) {
throw new NullPointerException("Control is null.");
}
if (controls.contains(control)) {
throw new IllegalArgumentException();
}
try {
Map<Control, Rectangle> controlBounds = computeDockBounds(control, specification);
if (controlBounds.isEmpty()) {
throw new IllegalArgumentException(MessageFormat.format("The control {0} is not dockable.", control));
}
for (Control key : controlBounds.keySet()) {
Rectangle value = controlBounds.get(key);
key.setBounds(value);
}
controls.add(control);
control.addListener(SWT.Dispose, this);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalArgumentException(MessageFormat.format("Invalid arguments while docking control {0}.", control), ex);
}
}
public void undock(Control control) {
if (control == null) {
throw new NullPointerException();
}
if (!controls.contains(control)) {
throw new IllegalArgumentException();
}
Bounds bounds = Bounds.fromRectangle(control.getBounds());
Control[] left = getControlsNear(control, Position.LEFT);
Control[] top = getControlsNear(control, Position.TOP);
Control[] right = getControlsNear(control, Position.RIGHT);
Control[] bottom = getControlsNear(control, Position.BOTTOM);
boolean done = false;
if (!done && left.length > 0) {
Bounds leftTop = Bounds.fromRectangle(left[0].getBounds());
Bounds leftBottom = Bounds.fromRectangle(left[left.length - 1].getBounds());
if (leftTop.getTop() == bounds.getTop() && leftBottom.getBottom() == bounds.getBottom()) {
for (Control item : left) {
Bounds itemBounds = Bounds.fromRectangle(item.getBounds());
itemBounds.setRight(bounds.getRight(), false);
item.setBounds(itemBounds.toRectangle());
}
done = true;
}
}
if (!done && top.length > 0) {
Bounds topLeft = Bounds.fromRectangle(top[0].getBounds());
Bounds topRight = Bounds.fromRectangle(top[top.length - 1].getBounds());
if (topLeft.getLeft() == bounds.getLeft() && topRight.getRight() == bounds.getRight()) {
for (Control item : top) {
Bounds itemBounds = Bounds.fromRectangle(item.getBounds());
itemBounds.setBottom(bounds.getBottom(), false);
item.setBounds(itemBounds.toRectangle());
}
done = true;
}
}
if (!done && right.length > 0) {
Bounds rightTop = Bounds.fromRectangle(right[0].getBounds());
Bounds rightBottom = Bounds.fromRectangle(right[right.length - 1].getBounds());
if (rightTop.getTop() == bounds.getTop() && rightBottom.getBottom() == bounds.getBottom()) {
for (Control item : right) {
Bounds itemBounds = Bounds.fromRectangle(item.getBounds());
itemBounds.setLeft(bounds.getLeft(), false);
item.setBounds(itemBounds.toRectangle());
}
done = true;
}
}
if (!done && bottom.length > 0) {
Bounds bottomLeft = Bounds.fromRectangle(bottom[0].getBounds());
Bounds bottomRight = Bounds.fromRectangle(bottom[bottom.length - 1].getBounds());
if (bottomLeft.getLeft() == bounds.getLeft() && bottomRight.getRight() == bounds.getRight()) {
for (Control item : bottom) {
Bounds itemBounds = Bounds.fromRectangle(item.getBounds());
itemBounds.setTop(bounds.getTop(), false);
item.setBounds(itemBounds.toRectangle());
}
done = true;
}
}
control.removeListener(SWT.Dispose, this);
controls.remove(control);
control.setBounds(0, 0, 0, 0);
}
Split[] getSplits() {
Control[] controls = getControls();
SortedSet<Split> splits = new TreeSet<Split>(XYComparator.getInstance(Orientation.HORIZONTAL));
for (Control control : controls) {
Bounds bounds = Bounds.fromRectangle(control.getBounds());
for (Control other : controls) {
Bounds otherBounds = Bounds.fromRectangle(other.getBounds());
Bounds splitBounds = Bounds.newInstance();
if (bounds.getLeft() <= otherBounds.getRight() && bounds.getRight() >= otherBounds.getLeft()) {
splitBounds.setLeft(Math.max(bounds.getLeft(), otherBounds.getLeft()), false);
splitBounds.setTop(Math.min(bounds.getBottom(), otherBounds.getBottom()), false);
splitBounds.setRight(Math.min(bounds.getRight(), otherBounds.getRight()), false);
splitBounds.setBottom(Math.max(bounds.getTop(), otherBounds.getTop()), false);
if (splitBounds.isValid() && splitBounds.getHeight() == BAR_SIZE) {
Split split = new Split(this, splitBounds.toRectangle(), Orientation.HORIZONTAL);
splits.add(split);
}
} else if (bounds.getTop() <= otherBounds.getBottom() && bounds.getBottom() >= otherBounds.getTop()) {
splitBounds.setLeft(Math.min(bounds.getRight(), otherBounds.getRight()), false);
splitBounds.setTop(Math.max(bounds.getTop(), otherBounds.getTop()), false);
splitBounds.setRight(Math.max(bounds.getLeft(), otherBounds.getLeft()), false);
splitBounds.setBottom(Math.min(bounds.getBottom(), otherBounds.getBottom()), false);
if (splitBounds.isValid() && splitBounds.getWidth() == BAR_SIZE) {
Split split = new Split(this, splitBounds.toRectangle(), Orientation.VERTICAL);
splits.add(split);
}
}
}
}
return splits.toArray(new Split[splits.size()]);
}
Grip[] getGrips() {
Split[] splits = getSplits();
Bounds clientArea = Bounds.fromRectangle(getClientArea());
SortedSet<Grip> grips = new TreeSet<Grip>(XYComparator.getInstance(Orientation.HORIZONTAL));
for (Split split : splits) {
Bounds bounds = Bounds.fromRectangle(split.getBounds());
Grip before = null;
Grip after = null;
if (split.isVertical()) {
if (bounds.getTop() > clientArea.getTop()) {
Bounds rBefore = Bounds.fromXYWidthHeight(bounds.getLeft(), bounds.getTop() - BAR_SIZE, BAR_SIZE, BAR_SIZE);
before = new Grip(this, rBefore.toRectangle());
}
if (bounds.getBottom() < clientArea.getBottom()) {
Bounds rAfter = Bounds.fromXYWidthHeight(bounds.getLeft(), bounds.getBottom(), BAR_SIZE, BAR_SIZE);
after = new Grip(this, rAfter.toRectangle());
}
} else {
if (bounds.getLeft() > clientArea.getLeft()) {
Bounds rBefore = Bounds.fromXYWidthHeight(bounds.getLeft() - BAR_SIZE, bounds.getTop(), BAR_SIZE, BAR_SIZE);
before = new Grip(this, rBefore.toRectangle());
}
if (bounds.getRight() < clientArea.getRight()) {
Bounds rAfter = Bounds.fromXYWidthHeight(bounds.getRight(), bounds.getTop(), BAR_SIZE, BAR_SIZE);
after = new Grip(this, rAfter.toRectangle());
}
}
if (before != null) {
grips.add(before);
}
if (after != null) {
grips.add(after);
}
}
return grips.toArray(new Grip[grips.size()]);
}
Sizer[] getSizers() {
Split[] splits = getSplits();
Grip[] grips = getGrips();
XYComparator xComp = XYComparator.getInstance(Orientation.HORIZONTAL);
SortedSet<Sizer> sizers = new TreeSet<Sizer>(xComp);
for (Split split : splits) {
sizers.add(split);
}
for (Grip grip : grips) {
sizers.add(grip);
}
return sizers.toArray(new Sizer[sizers.size()]);
}
Group[] getGroups() {
Split[] splits = getSplits();
XYComparator xComp = XYComparator.getInstance(Orientation.HORIZONTAL);
SortedSet<Group> groups = new TreeSet<Group>(xComp);
for (Split split : splits) {
Group[] array = split.getGroups();
for (Group item : array) {
groups.add(item);
}
}
return groups.toArray(new Group[groups.size()]);
}
private Control[] getControlsNear(Control control, Position position) {
if (control == null) {
throw new NullPointerException();
}
if (position == null) {
throw new NullPointerException();
}
Bounds bounds = Bounds.fromRectangle(control.getBounds());
XYComparator comp = XYComparator.getInstance(position.isVertical() ? Orientation.HORIZONTAL : Orientation.VERTICAL);
SortedSet<Control> controlsNear = new TreeSet<Control>(comp);
Control[] controls = getControls();
for (Control aControl : controls) {
if (aControl == control) {
continue;
}
Bounds aBounds = Bounds.fromRectangle(aControl.getBounds());
if (position.isVertical()) {
if (aBounds.getLeft() <= bounds.getRight() && aBounds.getRight() >= bounds.getLeft()) {
if (position == Position.TOP) {
if (aBounds.getBottom() + BAR_SIZE == bounds.getTop()) {
controlsNear.add(aControl);
}
} else if (position == Position.BOTTOM) {
if (bounds.getBottom() + BAR_SIZE == aBounds.getTop()) {
controlsNear.add(aControl);
}
}
}
} else {
if (aBounds.getTop() <= bounds.getBottom() && aBounds.getBottom() >= bounds.getTop()) {
if (position == Position.LEFT) {
if (aBounds.getRight() + BAR_SIZE == bounds.getLeft()) {
controlsNear.add(aControl);
}
} else if (position == Position.RIGHT) {
if (bounds.getRight() + BAR_SIZE == aBounds.getLeft()) {
controlsNear.add(aControl);
}
}
}
}
}
return controlsNear.toArray(new Control[controlsNear.size()]);
}
private Sizer[] getSizersAt(int x, int y) {
XYComparator xComp = XYComparator.getInstance(Orientation.HORIZONTAL);
SortedSet<Sizer> sizersAt = new TreeSet<Sizer>(xComp);
Sizer[] sizers = getSizers();
for (Sizer sizer : sizers) {
if (sizer.getBounds().contains(x, y)) {
sizersAt.add(sizer);
}
}
return sizersAt.toArray(new Sizer[sizersAt.size()]);
}
private Group[] getGroupsAt(int x, int y) {
Sizer[] sizers = getSizersAt(x, y);
XYComparator xComp = XYComparator.getInstance(Orientation.HORIZONTAL);
SortedSet<Group> groupsAt = new TreeSet<Group>(xComp);
for (Sizer sizer : sizers) {
Group[] groups = sizer.getGroups();
for (Group group : groups) {
groupsAt.add(group);
}
}
return groupsAt.toArray(new Group[groupsAt.size()]);
}
private void updateCursor(int x, int y) {
int id = SWT.CURSOR_ARROW;
if (dragInfo != null) {
DragGroupInfo[] groupInfos = dragInfo.getGroupInfos();
if (groupInfos.length == 1) {
Group group = groupInfos[0].getGroup();
id = group.isVertical() ? SWT.CURSOR_SIZEWE : SWT.CURSOR_SIZENS;
} else if (groupInfos.length > 1) {
id = SWT.CURSOR_SIZEALL;
}
} else {
Sizer[] sizers = getSizers();
for (Sizer sizer : sizers) {
Rectangle bounds = sizer.getBounds();
if (bounds.contains(x, y)) {
if (sizer instanceof Grip) {
id = SWT.CURSOR_SIZEALL;
} else if (sizer instanceof Split) {
Split split = (Split )sizer;
id = split.isVertical() ? SWT.CURSOR_SIZEWE : SWT.CURSOR_SIZENS;
}
break;
}
}
}
Cursor cursor = getDisplay().getSystemCursor(id);
setCursor(cursor);
}
private Map<Control, Bounds> computeLayoutBounds(Bounds newClient) throws InsufficientControlSizeException {
XYComparator xComp = XYComparator.getInstance(Orientation.HORIZONTAL);
XYComparator yComp = XYComparator.getInstance(Orientation.VERTICAL);
Control[] controls = getControls();
Arrays.sort(controls, xComp);
SortedMap<Control, SortedSet<Control>> xNexts = new TreeMap<Control, SortedSet<Control>>(xComp);
SortedMap<Control, SortedSet<Control>> yNexts = new TreeMap<Control, SortedSet<Control>>(yComp);
SortedSet<Control> xEnds = new TreeSet<Control>(yComp);
SortedSet<Control> yEnds = new TreeSet<Control>(xComp);
Map<Control, Bounds> controlBounds = new HashMap<Control, Bounds>();
for (Control control : controls) {
Bounds bounds = Bounds.fromRectangle(control.getBounds());
controlBounds.put(control, bounds);
}
for (Control control : controls) {
Bounds bounds = controlBounds.get(control);
if (bounds.getRight() == oldClient.getRight()) {
xEnds.add(control);
} else for (Control x : controls) {
if (x == control) {
continue;
}
Bounds xBounds = controlBounds.get(x);
if (bounds.getTop() > xBounds.getBottom() || bounds.getBottom() < xBounds.getTop()) {
continue;
}
if (bounds.getRight() + BAR_SIZE != xBounds.getLeft()) {
continue;
}
SortedSet<Control> xNext = xNexts.get(control);
if (xNext == null) {
xNext = new TreeSet<Control>(yComp);
xNexts.put(control, xNext);
}
xNext.add(x);
}
if (bounds.getBottom() == oldClient.getBottom()) {
yEnds.add(control);
} else for (Control y : controls) {
if (y == control) {
continue;
}
Bounds yBounds = controlBounds.get(y);
if (bounds.getLeft() > yBounds.getRight() || bounds.getRight() < yBounds.getLeft()) {
continue;
}
if (bounds.getBottom() + BAR_SIZE != yBounds.getTop()) {
continue;
}
SortedSet<Control> yNext = yNexts.get(control);
if (yNext == null) {
yNext = new TreeSet<Control>(xComp);
yNexts.put(control, yNext);
}
yNext.add(y);
}
}
for (Control control : controls) {
Bounds bounds = controlBounds.get(control);
if (bounds.getLeft() > oldClient.getLeft()) {
bounds.setWidth(bounds.getWidth() + BAR_SIZE / 2, false);
}
if (bounds.getTop() > oldClient.getTop()) {
bounds.setHeight(bounds.getHeight() + BAR_SIZE / 2, false);
}
if (bounds.getRight() < oldClient.getRight()) {
bounds.setWidth(bounds.getWidth() + BAR_SIZE / 2, true);
}
if (bounds.getBottom() < oldClient.getBottom()) {
bounds.setHeight(bounds.getHeight() + BAR_SIZE / 2, true);
}
}
float xProportion = (float )newClient.getWidth() / (float )oldClient.getWidth();
float yProportion = (float )newClient.getHeight() / (float )oldClient.getHeight();
for (Control control : controls) {
Bounds bounds = controlBounds.get(control);
bounds.setWidth(Math.round(bounds.getWidth() * xProportion), true);
bounds.setHeight(Math.round(bounds.getHeight() * yProportion), true);
}
for (Control x : xNexts.keySet()) {
Bounds xBounds = controlBounds.get(x);
SortedSet<Control> nexts = xNexts.get(x);
for (Control next : nexts) {
Bounds nextBounds = controlBounds.get(next);
nextBounds.setLeft(xBounds.getRight(), true);
}
}
for (Control y : yNexts.keySet()) {
Bounds yBounds = controlBounds.get(y);
SortedSet<Control> nexts = yNexts.get(y);
for (Control next : nexts) {
Bounds nextBounds = controlBounds.get(next);
nextBounds.setTop(yBounds.getBottom(), true);
}
}
for (Control x : xEnds) {
Bounds xBounds = controlBounds.get(x);
int diff = newClient.getRight() - xBounds.getRight();
xBounds.setWidth(xBounds.getWidth() + diff, true);
}
for (Control y: yEnds) {
Bounds yBounds = controlBounds.get(y);
int diff = newClient.getBottom() - yBounds.getBottom();
yBounds.setHeight(yBounds.getHeight() + diff, true);
}
for (Control control : controls) {
Bounds bounds = controlBounds.get(control);
if (bounds.getLeft() > newClient.getLeft()) {
bounds.setWidth(bounds.getWidth() - BAR_SIZE / 2, false);
}
if (bounds.getTop() > newClient.getTop()) {
bounds.setHeight(bounds.getHeight() - BAR_SIZE / 2, false);
}
if (bounds.getRight() < newClient.getRight()) {
bounds.setWidth(bounds.getWidth() - BAR_SIZE / 2, true);
}
if (bounds.getBottom() < newClient.getBottom()) {
bounds.setHeight(bounds.getHeight() - BAR_SIZE / 2, true);
}
}
return controlBounds;
}
private Map<Control, Rectangle> computeDockBounds(Control control, Specification specification) throws InsufficientControlSizeException, ControlAlreadyDockedException, NoSuchReferenceControlException {
if (control == null) {
throw new NullPointerException("Control is null.");
}
Composite parent = control.getParent();
if (parent != this) {
throw new SWTException(SWT.ERROR_INVALID_PARENT, MessageFormat.format("Cannot compute bounds for control {0}.", control));
}
if (controls.contains(control)) {
throw new ControlAlreadyDockedException(MessageFormat.format("The control {0} is already docked.", control));
}
Map<Control, Rectangle> controlBounds = new HashMap<Control, Rectangle>();
if (controls.isEmpty()) {
Rectangle newBounds = getClientArea();
if (newBounds.width < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient width for the control {0}.", control));
}
if (newBounds.height < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient height for the control {0}.", control));
}
controlBounds.put(control, newBounds);
} else {
if (specification == null) {
throw new NullPointerException("Specification is null.");
}
Control reference = specification.getReference();
if (!controls.contains(reference)) {
throw new NoSuchReferenceControlException(MessageFormat.format("No such reference control {0}.", reference));
}
Rectangle refBounds = reference.getBounds();
Rectangle newBounds = new Rectangle(refBounds.x, refBounds.y, refBounds.width, refBounds.height);
Rectangle oldBounds = new Rectangle(refBounds.x, refBounds.y, refBounds.width, refBounds.height);
if (specification.isVertical()) {
int height = refBounds.height - BAR_SIZE;
newBounds.height = Math.round(height * specification.getProportion());
oldBounds.height = height - newBounds.height;
} else {
int width = refBounds.width - BAR_SIZE;
newBounds.width = Math.round(width * specification.getProportion());
oldBounds.width = width - newBounds.width;
}
Position position = specification.getPosition();
if (position == Position.TOP) {
oldBounds.y = refBounds.y + refBounds.height - oldBounds.height;
} else if (position == Position.RIGHT) {
newBounds.x = refBounds.x + refBounds.width - newBounds.width;
} else if (position == Position.BOTTOM) {
newBounds.y = refBounds.y + refBounds.height - newBounds.height;
} else {
oldBounds.x = refBounds.x + refBounds.width - oldBounds.width;
}
if (newBounds.width < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient width for the control {0}.", control));
}
if (newBounds.height < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient height for the control {0}.", control));
}
if (oldBounds.width < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient width for the control {0}.", reference));
}
if (oldBounds.height < MIN_SIZE) {
throw new InsufficientControlSizeException(MessageFormat.format("Insufficient height for the control {0}.", reference));
}
controlBounds.put(control, newBounds);
controlBounds.put(reference, oldBounds);
}
return controlBounds;
}
public static void main(String[] args) throws Exception {
Display display = Display.getDefault();
final Shell shell = new Shell(display);
final DockContainer container = new DockContainer(shell, SWT.NONE);
shell.addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event) {
container.setMinimumShellSize(shell);
}
});
shell.setLayout(new FillLayout());
shell.setSize(1366, 768);
{
Listener listener = new Listener() {
@Override
public void handleEvent(Event event) {
// container.undock((Control )event.widget);
UI.dispose(event.widget);
}
};
/*Button view0 = new Button(container, SWT.NONE);
view0.setText("View 0");
container.dock(view0, null);
Button view1 = new Button(container, SWT.NONE);
view1.setText("View 1");
container.dock(view1, new Specification(view0, Position.RIGHT, 0.75f));
Button view2 = new Button(container, SWT.NONE);
view2.setText("View 2");
container.dock(view2, new Specification(view1, Position.RIGHT, 0.667f));
Button view3 = new Button(container, SWT.NONE);
view3.setText("View 3");
container.dock(view3, new Specification(view2, Position.RIGHT, 0.5f));*/
/*Button view0 = new Button(container, SWT.NONE);
view0.setText("View 0");
container.dock(view0, null);
Button view1 = new Button(container, SWT.NONE);
view1.setText("View 1");
container.dock(view1, new Specification(view0, Position.RIGHT, 0.3f));
Button view2 = new Button(container, SWT.NONE);
view2.setText("View 2");
container.dock(view2, new Specification(view1, Position.BOTTOM, 0.6f));*/
/*Button view0 = new Button(container, SWT.NONE);
view0.setText("View 0");
container.dock(view0, null);
Button view1 = new Button(container, SWT.NONE);
view1.setText("View 1");
container.dock(view1, new Specification(view0, Position.BOTTOM, 0.5f));
Button view2 = new Button(container, SWT.NONE);
view2.setText("View 2");
container.dock(view2, new Specification(view0, Position.LEFT, 0.497f));
Button view3 = new Button(container, SWT.NONE);
view3.setText("View 3");
container.dock(view3, new Specification(view1, Position.RIGHT, 0.497f));*/
Button view0 = new Button(container, SWT.NONE);
view0.setText("View 0");
view0.addListener(SWT.Selection, listener);
container.dock(view0, null);
Button view1 = new Button(container, SWT.NONE);
view1.setText("View 1");
view1.addListener(SWT.Selection, listener);
container.dock(view1, new Specification(view0, Position.BOTTOM, 0.5f));
Button view2 = new Button(container, SWT.NONE);
view2.setText("View 2");
view2.addListener(SWT.Selection, listener);
container.dock(view2, new Specification(view0, Position.LEFT, 0.2f));
Button view3 = new Button(container, SWT.NONE);
view3.setText("View 3");
view3.addListener(SWT.Selection, listener);
container.dock(view3, new Specification(view1, Position.RIGHT, 0.2f));
Button view4 = new Button(container, SWT.NONE);
view4.setText("View 4");
view4.addListener(SWT.Selection, listener);
container.dock(view4, new Specification(view0, Position.LEFT, 0.3f));
Button view5 = new Button(container, SWT.NONE);
view5.setText("View 5");
view5.addListener(SWT.Selection, listener);
container.dock(view5, new Specification(view1, Position.RIGHT, 0.3f));
/*Button view0 = new Button(container, SWT.NONE);
view0.setText("View 0");
container.dock(view0, null);
Button view1 = new Button(container, SWT.NONE);
view1.setText("View 1");
container.dock(view1, new Specification(view0, Position.BOTTOM, 0.5f));
Button view2 = new Button(container, SWT.NONE);
view2.setText("View 2");
container.dock(view2, new Specification(view0, Position.LEFT, 0.5f));
Button view3 = new Button(container, SWT.NONE);
view3.setText("View 3");
container.dock(view3, new Specification(view1, Position.RIGHT, 0.5f));
Button view4 = new Button(container, SWT.NONE);
view4.setText("View 4");
container.dock(view4, new Specification(view3, Position.RIGHT, 0.5f));*/
}
container.setMinimumShellSize(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}