/*******************************************************************************
* Copyright (c) 2000, 2005 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
* Exadel, Inc.
* Red Hat, Inc.
*******************************************************************************/
package org.jboss.tools.common.gef.xpl;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.draw2d.ColorConstants;
public class GEFSplitter extends Composite {
private static final int SASH_WIDTH = 5;
private static final int FIXED_DRAG_MINIMUM = 62;
private static final int OTHER_DRAG_MINIMUM = 0;
private static final String MAINTAIN_SIZE = "maintain size"; //$NON-NLS-1$
private int fixedSize = 150;
private int fixedDragMinimum;
private int otherDragMinimum;
private int orientation = SWT.HORIZONTAL;
private Sash[] sashes = new Sash[0];
private Control[] controls = new Control[0];
private Control maxControl = null;
private Listener sashListener;
private boolean first = true;
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public void addFixedSizeChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
protected void firePropertyChange(int oldValue, int newValue) {
listeners.firePropertyChange(MAINTAIN_SIZE, oldValue, newValue);
}
public void removeFixedSizeChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
public int getFixedSize() {
return fixedSize;
}
public void setFixedSize(int newSize) {
if (newSize == fixedSize) {
return;
}
firePropertyChange(fixedSize, fixedSize = newSize);
}
class SashPainter implements Listener {
public void handleEvent(Event e) {
paint((Sash)e.widget, e.gc);
}
}
public GEFSplitter(Composite parent, int style) {
this(parent, style, FIXED_DRAG_MINIMUM, OTHER_DRAG_MINIMUM);
}
public GEFSplitter(Composite parent, int style, int fixedDragMinimum) {
this(parent, style, fixedDragMinimum, OTHER_DRAG_MINIMUM);
}
public GEFSplitter(Composite parent, int style, int fixedDragMinimum, int otherDragMinimum) {
super(parent, checkStyle(style));
this.fixedDragMinimum = fixedDragMinimum;
this.otherDragMinimum = otherDragMinimum;
if ((style & SWT.VERTICAL) != 0) {
orientation = SWT.VERTICAL;
}
this.addListener(SWT.Resize, new Listener() {
public void handleEvent(Event e) {
layout(true);
}
});
sashListener = new Listener() {
public void handleEvent(Event e) {
onDragSash(e);
}
};
}
private static int checkStyle (int style) {
int mask = SWT.BORDER;
return style & mask;
}
public Point computeSize (int wHint, int hHint, boolean changed) {
Control[] controls = getControls(true);
if (controls.length == 0) return new Point(wHint, hHint);
int width = 0;
int height = 0;
boolean vertical = (getStyle() & SWT.VERTICAL) != 0;
if (vertical) {
width = wHint;
height += (controls.length - 1) * SASH_WIDTH;
} else {
height = hHint;
width += controls.length * SASH_WIDTH;
}
for (int i = 0; i < controls.length; i++) {
if (vertical) {
Point size = controls[i].computeSize(wHint, SWT.DEFAULT);
height += size.y;
} else {
Point size = controls[i].computeSize(SWT.DEFAULT, hHint);
if (controls[i].getData(MAINTAIN_SIZE) != null) {
size.x = fixedSize;
}
width += size.x;
}
}
return new Point(width, height);
}
public int getOrientation() {
return orientation;
}
public Control getMaximizedControl() {
return this.maxControl;
}
private Control[] getControls(boolean onlyVisible) {
Control[] children = getChildren();
Control[] controls = new Control[0];
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Sash)
continue;
if (onlyVisible && !children[i].getVisible()) continue;
Control[] newControls = new Control[controls.length + 1];
System.arraycopy(controls, 0, newControls, 0, controls.length);
newControls[controls.length] = children[i];
controls = newControls;
}
return controls;
}
public void layout(boolean changed) {
Rectangle area = getClientArea();
if (area.width == 0 || area.height == 0) return;
Control[] newControls = getControls(true);
if (controls.length == 0 && newControls.length == 0) return;
controls = newControls;
if (maxControl != null && !maxControl.isDisposed()) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] != maxControl) {
controls[i].setBounds(-200, -200, 0, 0);
} else {
controls[i].setBounds(area);
}
}
return;
}
if (sashes.length < controls.length - 1) {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashes, 0, newSashes, 0, sashes.length);
int sashOrientation =
(orientation == SWT.HORIZONTAL) ? SWT.VERTICAL : SWT.HORIZONTAL;
for (int i = sashes.length; i < newSashes.length; i++) {
newSashes[i] = new Sash(this, sashOrientation);
newSashes[i].setBackground(ColorConstants.button);
newSashes[i].addListener(SWT.Paint, new SashPainter());
newSashes[i].addListener(SWT.Selection, sashListener);
}
sashes = newSashes;
}
if (sashes.length > controls.length - 1) {
if (controls.length == 0) {
for (int i = 0; i < sashes.length; i++) {
sashes[i].dispose();
}
sashes = new Sash[0];
} else {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashes, 0, newSashes, 0, newSashes.length);
for (int i = controls.length - 1; i < sashes.length; i++) {
sashes[i].dispose();
}
sashes = newSashes;
}
}
if (controls.length == 0) return;
if (orientation == SWT.HORIZONTAL) {
int x = area.x;
int width;
for (int i = 0; i < controls.length; i++) {
Control control = controls[i];
if (control.getData(MAINTAIN_SIZE) != null) {
width = fixedSize;
if (width > area.width) {
width = area.width - SASH_WIDTH;
}
} else {
width = Math.max(area.width - fixedSize - SASH_WIDTH, 0);
}
control.setBounds(x, area.y, width, area.height);
x += (width + SASH_WIDTH);
}
sashes[0].setBounds(controls[0].getBounds().x + controls[0].getBounds().width, area.y,
SASH_WIDTH, area.height);
} else {
int y = area.y;
int height;
for (int i = 0; i < controls.length; i++) {
Control control = controls[i];
if (control.getData(MAINTAIN_SIZE) != null) {
height = fixedSize;
if (height > area.height) {
height = area.height - SASH_WIDTH;
}
} else {
height = Math.max(area.height - fixedSize - SASH_WIDTH, 0);
}
control.setBounds(area.x, y, area.width, height);
y += (height + SASH_WIDTH);
}
sashes[0].setBounds(area.x, controls[0].getBounds().y + controls[0].getBounds().height,
area.width, SASH_WIDTH);
}
}
public void maintainSize(Control c) {
Control[] controls = getControls(false);
for (int i = 0; i < controls.length; i++) {
Control ctrl = controls[i];
if (ctrl == c) {
ctrl.setData(MAINTAIN_SIZE, Boolean.TRUE);
}
}
}
void paint(Sash sash, GC gc) {
if (first) {
first = false;
getParent().layout();
}
Point size = sash.getSize();
if (getOrientation() == SWT.HORIZONTAL) {
gc.setForeground(ColorConstants.buttonDarker);
gc.drawLine(SASH_WIDTH - 1, 0, SASH_WIDTH - 1, size.y);
gc.setForeground(ColorConstants.buttonLightest);
gc.drawLine(0, 0, 0, size.y);
} else {
gc.setForeground(ColorConstants.buttonDarker);
gc.drawLine(0, SASH_WIDTH - 1, size.x, SASH_WIDTH - 1);
gc.setForeground(ColorConstants.buttonLightest);
gc.drawLine(0, 0, size.x, 0);
}
}
private void onDragSash(Event event) {
if (event.detail == SWT.DRAG) {
Rectangle area = getClientArea();
if (orientation == SWT.HORIZONTAL) {
if (controls[0].getData(MAINTAIN_SIZE) != null) {
event.x = Math.max(Math.min(area.width - otherDragMinimum - SASH_WIDTH, event.x), fixedDragMinimum);
} else {
event.x = Math.min(Math.max(otherDragMinimum, event.x), area.width - fixedDragMinimum - SASH_WIDTH);
}
} else {
if (controls[0].getData(MAINTAIN_SIZE) != null) {
event.x = Math.max(Math.min(area.height - otherDragMinimum - SASH_WIDTH, event.y), fixedDragMinimum);
} else {
event.x = Math.min(Math.max(otherDragMinimum, event.y), area.height - fixedDragMinimum - SASH_WIDTH);
}
}
return;
}
Sash sash = (Sash)event.widget;
int sashIndex = -1;
for (int i = 0; i < sashes.length; i++) {
if (sashes[i] == sash) {
sashIndex = i;
break;
}
}
if (sashIndex == -1) return;
Control c1 = controls[sashIndex];
Control c2 = controls[sashIndex + 1];
Rectangle b1 = c1.getBounds();
Rectangle b2 = c2.getBounds();
Rectangle sashBounds = sash.getBounds();
if (orientation == SWT.HORIZONTAL) {
int shift = event.x - sashBounds.x;
if (shift == 0) {
return;
}
b1.width += shift;
b2.x += shift;
b2.width -= shift;
} else {
int shift = event.y - sashBounds.y;
if (shift == 0) {
return;
}
b1.height += shift;
b2.y += shift;
b2.height -= shift;
}
c1.setBounds(b1);
sash.setBounds(event.x, event.y, event.width, event.height);
c2.setBounds(b2);
if (orientation == SWT.HORIZONTAL) {
if (c1.getData(MAINTAIN_SIZE) != null) {
setFixedSize(c1.getBounds().width);
} else {
setFixedSize(c2.getBounds().width);
}
} else {
if (c1.getData(MAINTAIN_SIZE) != null) {
setFixedSize(c1.getBounds().height);
} else {
setFixedSize(c2.getBounds().height);
}
}
}
public void setOrientation(int orientation) {
if (this.orientation == orientation) return;
if (orientation != SWT.HORIZONTAL && orientation != SWT.VERTICAL) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
this.orientation = orientation;
int sashOrientation = (orientation == SWT.HORIZONTAL) ? SWT.VERTICAL : SWT.HORIZONTAL;
for (int i = 0; i < sashes.length; i++) {
sashes[i].dispose();
sashes[i] = new Sash(this, sashOrientation);
sashes[i].setBackground(ColorConstants.buttonLightest);
sashes[i].addListener(SWT.Selection, sashListener);
}
layout();
}
public void setLayout (Layout layout) {
}
public void setMaximizedControl(Control control) {
if (control == null) {
if (maxControl != null) {
this.maxControl = null;
layout();
for (int i = 0; i < sashes.length; i++) {
sashes[i].setVisible(true);
}
}
return;
}
for (int i = 0; i < sashes.length; i++) {
sashes[i].setVisible(false);
}
maxControl = control;
layout();
}
}