| /******************************************************************************* |
| * Copyright (c) 2000, 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.gef.ui.parts; |
| |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| |
| import org.eclipse.swt.events.PaintEvent; |
| import org.eclipse.swt.events.PaintListener; |
| import org.eclipse.swt.graphics.GC; |
| 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.swt.widgets.ControlPaintHandler; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Layout; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Sash; |
| |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.rap.swt.SWT; |
| |
| class Splitter extends Composite { |
| |
| public static final int DEFAULT_SASH_WIDTH = 5; |
| private static final int DRAG_MINIMUM = 62; |
| private static final String MAINTAIN_SIZE = "maintain size"; //$NON-NLS-1$ |
| |
| private int fixedSize = 150; |
| private int orientation = SWT.VERTICAL; |
| private Sash[] sashes = new Sash[0]; |
| private Control[] controls = new Control[0]; |
| private Control maxControl = null; |
| private Listener sashListener; |
| private int sashWidth = DEFAULT_SASH_WIDTH; |
| |
| /** |
| * PropertyChangeSupport |
| */ |
| 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 Splitter(Composite parent, int style) { |
| super(parent, checkStyle(style)); |
| |
| if ((style & SWT.HORIZONTAL) != 0) |
| orientation = SWT.HORIZONTAL; |
| |
| 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) * getSashWidth(); |
| } else { |
| height = hHint; |
| width += controls.length * getSashWidth(); |
| } |
| 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; |
| } |
| } |
| // if (wHint != SWT.DEFAULT) width = wHint; |
| // if (hHint != SWT.DEFAULT) height = hHint; |
| |
| return new Point(width, height); |
| } |
| |
| /** |
| * Answer SWT.HORIZONTAL if the controls in the SashForm are laid out side |
| * by side. Answer SWT.VERTICAL if the controls in the SashForm are laid out |
| * top to bottom. |
| */ |
| public int getOrientation() { |
| return orientation; |
| } |
| |
| public int getSashWidth() { |
| return sashWidth; |
| } |
| |
| /** |
| * Answer the control that currently is maximized in the SashForm. This |
| * value may be null. |
| */ |
| 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; |
| } |
| |
| // keep just the right number of sashes |
| 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); |
| ControlPaintHandler helper = new ControlPaintHandler( |
| newSashes[i]); |
| helper.addPaintListener(new PaintListener() { |
| public void paintControl(PaintEvent e) { |
| paint((Sash) e.widget, e.gc); |
| } |
| }); |
| 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; |
| |
| // @TODO |
| // This only works if the orientation is horizontal, there are two |
| // children and one |
| // of them has been set to maintain its size. |
| 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 - getSashWidth(); |
| } |
| control.setBounds(x, area.y, width, area.height); |
| x += width + getSashWidth(); |
| } else { |
| width = Math.max(area.width - fixedSize - getSashWidth(), 0); |
| control.setBounds(x, area.y, width, area.height); |
| x += (width + getSashWidth()); |
| } |
| } |
| if (sashes.length > 0) |
| sashes[0].setBounds( |
| controls[0].getBounds().x + controls[0].getBounds().width, |
| area.y, getSashWidth(), area.height); |
| } |
| |
| 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, new Boolean(true)); |
| break; |
| } |
| } |
| } |
| |
| void paint(Sash sash, GC gc) { |
| if (getSashWidth() == 0) |
| return; |
| Point size = sash.getSize(); |
| if (getOrientation() == SWT.HORIZONTAL) { |
| gc.setForeground(ColorConstants.buttonDarker); |
| gc.drawLine(getSashWidth() - 1, 0, getSashWidth() - 1, size.y); |
| gc.setForeground(ColorConstants.buttonLightest); |
| gc.drawLine(0, 0, 0, size.y); |
| } else { |
| gc.setForeground(ColorConstants.buttonDarker); |
| gc.drawLine(0, 0, size.x, 0); |
| gc.drawLine(0, getSashWidth() - 1, size.x, getSashWidth() - 1); |
| gc.setForeground(ColorConstants.buttonLightest); |
| gc.drawLine(0, 1, size.x, 1); |
| } |
| } |
| |
| private void onDragSash(Event event) { |
| if (event.detail == SWT.DRAG) { |
| // constrain feedback |
| Rectangle area = getClientArea(); |
| if (orientation == SWT.HORIZONTAL) { |
| if (controls[0].getData(MAINTAIN_SIZE) != null) { |
| event.x = Math.max(event.x, DRAG_MINIMUM); |
| } else { |
| event.x = Math.min(event.x, area.width - DRAG_MINIMUM |
| - getSashWidth()); |
| } |
| } else { |
| event.y = Math.min(event.y, area.height - DRAG_MINIMUM |
| - getSashWidth()); |
| } |
| 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(); |
| controls = getControls(false); |
| |
| Rectangle sashBounds = sash.getBounds(); |
| if (orientation == SWT.HORIZONTAL) { |
| int shift = event.x - sashBounds.x; |
| b1.width += shift; |
| b2.x += shift; |
| b2.width -= shift; |
| } else { |
| int shift = event.y - sashBounds.y; |
| 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); |
| // @TODO |
| // This will only work when you have two controls, one of whom is set to |
| // maintain size |
| if (c1.getData(MAINTAIN_SIZE) != null) { |
| setFixedSize(c1.getBounds().width); |
| } else { |
| setFixedSize(c2.getBounds().width); |
| } |
| } |
| |
| /** |
| * If orientation is SWT.HORIZONTAL, lay the controls in the SashForm out |
| * side by side. If orientation is SWT.VERTICAL, lay the controls in the |
| * SashForm out top to bottom. |
| */ |
| 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 setSashWidth(int width) { |
| sashWidth = width; |
| } |
| |
| public void setLayout(Layout layout) { |
| // SashForm does not use Layout |
| } |
| |
| /** |
| * Specify the control that should take up the entire client area of the |
| * SashForm. If one control has been maximized, and this method is called |
| * with a different control, the previous control will be minimized and the |
| * new control will be maximized.. if the value of control is null, the |
| * SashForm will minimize all controls and return to the default layout |
| * where all controls are laid out separated by sashes. |
| */ |
| 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(); |
| |
| } |
| |
| } |