blob: d58973dcd2b8db0429646ac7d31d00aaaf180ec9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.layout;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.internal.WindowTrimProxy;
/**
* Represents one Trim Area.
*
* @since 3.2
*/
public class TrimArea {
// this is no longer necessary, since every piece of window trim defined
// itself as the trim layout data.
// private static final TrimLayoutData defaultData = new TrimLayoutData();
private static final IWindowTrim defaultData = new WindowTrimProxy(null, null, null, 0, true);
/**
* This method separates resizable controls from non-resizable controls.
*
* @param input
* the list of {@link SizeCache} to filter
* @param resizable
* will contain resizable controls from the input list
* @param nonResizable
* will contain non-resizable controls from the input list
* @param width
* if true, we're interested in horizontally-resizable controls.
* Else we're interested in vertically resizable controls
*/
static void filterResizable(List input, List resizable, List nonResizable,
boolean width) {
Iterator iter = input.iterator();
while (iter.hasNext()) {
SizeCache next = (SizeCache) iter.next();
if (next.getControl().isVisible()) {
if (isResizable(next.getControl(), width)) {
resizable.add(next);
} else {
nonResizable.add(next);
}
}
}
}
/**
* Helper function to check for resizeable controls.
* @param control the control to check
* @param horizontally the direction of resizeability.
* @return <code>true</code> if the control is resizeable.
*/
static boolean isResizable(Control control, boolean horizontally) {
IWindowTrim data = getData(control);
if (!data.isResizeable()) {
return false;
}
if (horizontally) {
return data.getWidthHint() == SWT.DEFAULT;
}
return data.getHeightHint() == SWT.DEFAULT;
}
private static IWindowTrim getData(Control control) {
IWindowTrim data = (IWindowTrim) control.getLayoutData();
if (data == null) {
data = defaultData;
}
return data;
}
/**
* Cause the SizeCache to compute it's size.
* @param toCompute the cache to compute
* @param widthHint in pixels
* @param heightHint in pixels
* @return a point
*/
private static Point computeSize(SizeCache toCompute, int widthHint,
int heightHint) {
IWindowTrim data = getData(toCompute.getControl());
if (widthHint == SWT.DEFAULT) {
widthHint = data.getWidthHint();
}
if (heightHint == SWT.DEFAULT) {
heightHint = data.getHeightHint();
}
if (widthHint == SWT.DEFAULT || heightHint == SWT.DEFAULT) {
return toCompute.computeSize(widthHint, heightHint);
}
return new Point(widthHint, heightHint);
}
static int getSize(SizeCache toCompute, int hint, boolean width) {
if (width) {
return computeSize(toCompute, SWT.DEFAULT, hint).x;
}
return computeSize(toCompute, hint, SWT.DEFAULT).y;
}
/**
* Computes the maximum dimensions of controls in the given list
*
* @param caches
* a list of {@link SizeCache}
* @param hint a size hint in pixels
* @param width are we interested in height or width
* @return pixel width
*/
private static int maxDimension(List caches, int hint, boolean width) {
if (hint == SWT.DEFAULT) {
int result = 0;
Iterator iter = caches.iterator();
while (iter.hasNext()) {
SizeCache next = (SizeCache) iter.next();
result = Math.max(getSize(next, SWT.DEFAULT, width), result);
}
return result;
}
List resizable = new ArrayList(caches.size());
List nonResizable = new ArrayList(caches.size());
filterResizable(caches, resizable, nonResizable, width);
int result = 0;
int usedHeight = 0;
Iterator iter = nonResizable.iterator();
while (iter.hasNext()) {
SizeCache next = (SizeCache) iter.next();
Point nextSize = computeSize(next, SWT.DEFAULT, SWT.DEFAULT);
if (width) {
result = Math.max(result, nextSize.x);
usedHeight += nextSize.y;
} else {
result = Math.max(result, nextSize.y);
usedHeight += nextSize.x;
}
}
if (resizable.size() > 0) {
int individualHint = (hint - usedHeight) / resizable.size();
iter = resizable.iterator();
while (iter.hasNext()) {
SizeCache next = (SizeCache) iter.next();
result = Math.max(result, getSize(next, individualHint, width));
}
}
return result;
}
/**
* Our area ID.
*/
private int fId;
/**
* An NLS display name.
*/
private String fDisplayName;
/**
* Each trimArea is an ordered list of TrimDescriptors.
*/
private ArrayList fTrim;
/**
* Relevant modifiers for a piece of trim to create it's control if it's
* interested in this area, like SWT.TOP, SWT.LEFT, etc.
*/
private int fControlModifiers;
/**
* A default size for this trim area.
*/
private int fTrimSize;
/**
* Create the trim area with its ID.
*
* @param id
* @param displayName
* the NLS display name
*/
public TrimArea(int id, String displayName) {
fTrim = new ArrayList();
fId = id;
fDisplayName = displayName;
fControlModifiers = SWT.HORIZONTAL;
}
/**
* return true of the trim area is empty
*
* @return <code>true</code>
*/
public boolean isEmpty() {
return fTrim.isEmpty();
}
/**
* Return the ordered list of trim for this area.
*
* @return a List containing IWindowTrim
*/
public List getTrims() {
List trim = new ArrayList(fTrim.size());
Iterator d = fTrim.iterator();
while (d.hasNext()) {
TrimDescriptor desc = (TrimDescriptor) d.next();
trim.add(desc.getTrim());
}
return trim;
}
/**
* Return the ordered list of trim descriptors for this area.
*
* @return a List containing TrimDescriptor
*/
public List getDescriptors() {
return (List) fTrim.clone();
}
/**
* Set the trim size for this area.
*
* @param size
* the size in pixels.
*/
public void setTrimSize(int size) {
fTrimSize = size;
}
/**
* Return the trim size for this area.
*
* @return the size in pixels
*/
public int getTrimSize() {
return fTrimSize;
}
/**
* Caculate a max dimension for this trim area. It uses a different hint
* depending on its orientation.
*
* @param wHint
* a width hint in pixels
* @param hHint
* a height hint in pixels
* @return the size in pixels
*/
public int calculateTrimSize(int wHint, int hHint) {
int size = 0;
if (!fTrim.isEmpty()) {
size = getTrimSize();
}
if (size == SWT.DEFAULT) {
int hint = isVertical() ? hHint : wHint;
size = maxDimension(getCaches(), hint, isVertical());
}
return size;
}
/**
* return true if this area orientation is vertical.
*
* @return <code>true</code>
*/
public boolean isVertical() {
return (fControlModifiers & SWT.VERTICAL) == SWT.VERTICAL
|| fControlModifiers == SWT.LEFT
|| fControlModifiers == SWT.RIGHT;
}
/**
* The ID for this area.
*
* @return the ID.
*/
public int getId() {
return fId;
}
/**
* The NLS display name for this area.
*
* @return the String display name.
*/
public String getDisplayName() {
return fDisplayName;
}
/**
* Add the descriptor representing a piece of trim to this trim area.
*
* @param desc
* the trim descriptor
*/
public void addTrim(TrimDescriptor desc) {
fTrim.add(desc);
}
/**
* Insert this desc before the other desc. If beforeMe is not
* part of this area it just defaults to an add.
*
* @param desc
* the window trim
* @param beforeMe
* before this trim
*/
public void addTrim(TrimDescriptor desc, TrimDescriptor beforeMe) {
int idx = fTrim.indexOf(beforeMe);
if (idx == -1) {
fTrim.add(desc);
} else {
ListIterator i = fTrim.listIterator(idx);
i.add(desc);
}
}
/**
* Remove the descriptor representing a piece of trim from this trim area.
*
* @param desc
* the trim descriptor
*/
public void removeTrim(TrimDescriptor desc) {
fTrim.remove(desc);
}
/**
* Does this area contain a piece of trim.
*
* @param desc
* the trim
* @return <code>true</code> if we contain the trim.
*/
public boolean contains(TrimDescriptor desc) {
return fTrim.contains(desc);
}
/**
* Takes the trim area and turns it into an List of {@link SizeCache}.
* There can be more items in the return list than there are trim
* descriptors in the area.
*
* @return a list of {@link SizeCache}
*/
public List getCaches() {
ArrayList result = new ArrayList(fTrim.size());
Iterator d = fTrim.iterator();
while (d.hasNext()) {
TrimDescriptor desc = (TrimDescriptor) d.next();
if (desc.getDockingCache() != null) {
result.add(desc.getDockingCache());
}
result.add(desc.getCache());
}
return result;
}
/**
* The bitwise SWT modifiers that this trim area suggests, like SWT.TOP
* or SWT.LEFT. The control modifiers determine the orientation,
* amongst other things.
*
* @return the bitwise OR of the SWT constants.
*/
public int getControlModifiers() {
return fControlModifiers;
}
/**
* The bitwise SWT modifiers that this trim area suggests, like SWT.TOP
* or SWT.LEFT.
*
* @param mod
* the bitwise OR of the SWT constants.
*/
public void setControlModifiers(int mod) {
fControlModifiers = mod;
}
}