001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.layout;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015: import java.util.ListIterator;
016:
017: import org.eclipse.swt.SWT;
018: import org.eclipse.swt.graphics.Point;
019: import org.eclipse.swt.widgets.Control;
020: import org.eclipse.ui.internal.WindowTrimProxy;
021:
022: /**
023: * Represents one Trim Area.
024: *
025: * @since 3.2
026: */
027: public class TrimArea {
028: // this is no longer necessary, since every piece of window trim defined
029: // itself as the trim layout data.
030: // private static final TrimLayoutData defaultData = new TrimLayoutData();
031: private static final IWindowTrim defaultData = new WindowTrimProxy(
032: null, null, null, 0, true);
033:
034: /**
035: * This method separates resizable controls from non-resizable controls.
036: *
037: * @param input
038: * the list of {@link SizeCache} to filter
039: * @param resizable
040: * will contain resizable controls from the input list
041: * @param nonResizable
042: * will contain non-resizable controls from the input list
043: * @param width
044: * if true, we're interested in horizontally-resizable controls.
045: * Else we're interested in vertically resizable controls
046: */
047: static void filterResizable(List input, List resizable,
048: List nonResizable, boolean width) {
049: Iterator iter = input.iterator();
050: while (iter.hasNext()) {
051: SizeCache next = (SizeCache) iter.next();
052:
053: if (next.getControl().isVisible()) {
054: if (isResizable(next.getControl(), width)) {
055: resizable.add(next);
056: } else {
057: nonResizable.add(next);
058: }
059: }
060: }
061: }
062:
063: /**
064: * Helper function to check for resizeable controls.
065: * @param control the control to check
066: * @param horizontally the direction of resizeability.
067: * @return <code>true</code> if the control is resizeable.
068: */
069: static boolean isResizable(Control control, boolean horizontally) {
070: IWindowTrim data = getData(control);
071:
072: if (!data.isResizeable()) {
073: return false;
074: }
075:
076: if (horizontally) {
077: return data.getWidthHint() == SWT.DEFAULT;
078: }
079:
080: return data.getHeightHint() == SWT.DEFAULT;
081: }
082:
083: private static IWindowTrim getData(Control control) {
084: IWindowTrim data = (IWindowTrim) control.getLayoutData();
085: if (data == null) {
086: data = defaultData;
087: }
088:
089: return data;
090: }
091:
092: /**
093: * Cause the SizeCache to compute it's size.
094: * @param toCompute the cache to compute
095: * @param widthHint in pixels
096: * @param heightHint in pixels
097: * @return a point
098: */
099: private static Point computeSize(SizeCache toCompute,
100: int widthHint, int heightHint) {
101: IWindowTrim data = getData(toCompute.getControl());
102:
103: if (widthHint == SWT.DEFAULT) {
104: widthHint = data.getWidthHint();
105: }
106:
107: if (heightHint == SWT.DEFAULT) {
108: heightHint = data.getHeightHint();
109: }
110:
111: if (widthHint == SWT.DEFAULT || heightHint == SWT.DEFAULT) {
112: return toCompute.computeSize(widthHint, heightHint);
113: }
114:
115: return new Point(widthHint, heightHint);
116: }
117:
118: static int getSize(SizeCache toCompute, int hint, boolean width) {
119: if (width) {
120: return computeSize(toCompute, SWT.DEFAULT, hint).x;
121: }
122:
123: return computeSize(toCompute, hint, SWT.DEFAULT).y;
124: }
125:
126: /**
127: * Computes the maximum dimensions of controls in the given list
128: *
129: * @param caches
130: * a list of {@link SizeCache}
131: * @param hint a size hint in pixels
132: * @param width are we interested in height or width
133: * @return pixel width
134: */
135: private static int maxDimension(List caches, int hint, boolean width) {
136:
137: if (hint == SWT.DEFAULT) {
138: int result = 0;
139: Iterator iter = caches.iterator();
140:
141: while (iter.hasNext()) {
142: SizeCache next = (SizeCache) iter.next();
143:
144: result = Math.max(getSize(next, SWT.DEFAULT, width),
145: result);
146: }
147:
148: return result;
149: }
150:
151: List resizable = new ArrayList(caches.size());
152: List nonResizable = new ArrayList(caches.size());
153:
154: filterResizable(caches, resizable, nonResizable, width);
155:
156: int result = 0;
157: int usedHeight = 0;
158:
159: Iterator iter = nonResizable.iterator();
160:
161: while (iter.hasNext()) {
162: SizeCache next = (SizeCache) iter.next();
163:
164: Point nextSize = computeSize(next, SWT.DEFAULT, SWT.DEFAULT);
165:
166: if (width) {
167: result = Math.max(result, nextSize.x);
168: usedHeight += nextSize.y;
169: } else {
170: result = Math.max(result, nextSize.y);
171: usedHeight += nextSize.x;
172: }
173: }
174:
175: if (resizable.size() > 0) {
176: int individualHint = (hint - usedHeight) / resizable.size();
177:
178: iter = resizable.iterator();
179:
180: while (iter.hasNext()) {
181: SizeCache next = (SizeCache) iter.next();
182:
183: result = Math.max(result, getSize(next, individualHint,
184: width));
185: }
186: }
187:
188: return result;
189: }
190:
191: /**
192: * Our area ID.
193: */
194: private int fId;
195:
196: /**
197: * An NLS display name.
198: */
199: private String fDisplayName;
200:
201: /**
202: * Each trimArea is an ordered list of TrimDescriptors.
203: */
204: private ArrayList fTrim;
205:
206: /**
207: * Relevant modifiers for a piece of trim to create it's control if it's
208: * interested in this area, like SWT.TOP, SWT.LEFT, etc.
209: */
210: private int fControlModifiers;
211:
212: /**
213: * A default size for this trim area.
214: */
215: private int fTrimSize;
216:
217: /**
218: * Create the trim area with its ID.
219: *
220: * @param id
221: * @param displayName
222: * the NLS display name
223: */
224: public TrimArea(int id, String displayName) {
225: fTrim = new ArrayList();
226: fId = id;
227: fDisplayName = displayName;
228: fControlModifiers = SWT.HORIZONTAL;
229: }
230:
231: /**
232: * return true of the trim area is empty
233: *
234: * @return <code>true</code>
235: */
236: public boolean isEmpty() {
237: return fTrim.isEmpty();
238: }
239:
240: /**
241: * Return the ordered list of trim for this area.
242: *
243: * @return a List containing IWindowTrim
244: */
245: public List getTrims() {
246: List trim = new ArrayList(fTrim.size());
247: Iterator d = fTrim.iterator();
248:
249: while (d.hasNext()) {
250: TrimDescriptor desc = (TrimDescriptor) d.next();
251: trim.add(desc.getTrim());
252: }
253: return trim;
254: }
255:
256: /**
257: * Return the ordered list of trim descriptors for this area.
258: *
259: * @return a List containing TrimDescriptor
260: */
261: public List getDescriptors() {
262: return (List) fTrim.clone();
263: }
264:
265: /**
266: * Set the trim size for this area.
267: *
268: * @param size
269: * the size in pixels.
270: */
271: public void setTrimSize(int size) {
272: fTrimSize = size;
273: }
274:
275: /**
276: * Return the trim size for this area.
277: *
278: * @return the size in pixels
279: */
280: public int getTrimSize() {
281: return fTrimSize;
282: }
283:
284: /**
285: * Caculate a max dimension for this trim area. It uses a different hint
286: * depending on its orientation.
287: *
288: * @param wHint
289: * a width hint in pixels
290: * @param hHint
291: * a height hint in pixels
292: * @return the size in pixels
293: */
294: public int calculateTrimSize(int wHint, int hHint) {
295: int size = 0;
296: if (!fTrim.isEmpty()) {
297: size = getTrimSize();
298: }
299:
300: if (size == SWT.DEFAULT) {
301: int hint = isVertical() ? hHint : wHint;
302: size = maxDimension(getCaches(), hint, isVertical());
303: }
304: return size;
305: }
306:
307: /**
308: * return true if this area orientation is vertical.
309: *
310: * @return <code>true</code>
311: */
312: public boolean isVertical() {
313: return (fControlModifiers & SWT.VERTICAL) == SWT.VERTICAL
314: || fControlModifiers == SWT.LEFT
315: || fControlModifiers == SWT.RIGHT;
316: }
317:
318: /**
319: * The ID for this area.
320: *
321: * @return the ID.
322: */
323: public int getId() {
324: return fId;
325: }
326:
327: /**
328: * The NLS display name for this area.
329: *
330: * @return the String display name.
331: */
332: public String getDisplayName() {
333: return fDisplayName;
334: }
335:
336: /**
337: * Add the descriptor representing a piece of trim to this trim area.
338: *
339: * @param desc
340: * the trim descriptor
341: */
342: public void addTrim(TrimDescriptor desc) {
343: fTrim.add(desc);
344: }
345:
346: /**
347: * Insert this desc before the other desc. If beforeMe is not
348: * part of this area it just defaults to an add.
349: *
350: * @param desc
351: * the window trim
352: * @param beforeMe
353: * before this trim
354: */
355: public void addTrim(TrimDescriptor desc, TrimDescriptor beforeMe) {
356: int idx = fTrim.indexOf(beforeMe);
357: if (idx == -1) {
358: fTrim.add(desc);
359: } else {
360: ListIterator i = fTrim.listIterator(idx);
361: i.add(desc);
362: }
363: }
364:
365: /**
366: * Remove the descriptor representing a piece of trim from this trim area.
367: *
368: * @param desc
369: * the trim descriptor
370: */
371: public void removeTrim(TrimDescriptor desc) {
372: fTrim.remove(desc);
373: }
374:
375: /**
376: * Does this area contain a piece of trim.
377: *
378: * @param desc
379: * the trim
380: * @return <code>true</code> if we contain the trim.
381: */
382: public boolean contains(TrimDescriptor desc) {
383: return fTrim.contains(desc);
384: }
385:
386: /**
387: * Takes the trim area and turns it into an List of {@link SizeCache}.
388: * There can be more items in the return list than there are trim
389: * descriptors in the area.
390: *
391: * @return a list of {@link SizeCache}
392: */
393: public List getCaches() {
394: ArrayList result = new ArrayList(fTrim.size());
395: Iterator d = fTrim.iterator();
396: while (d.hasNext()) {
397: TrimDescriptor desc = (TrimDescriptor) d.next();
398: if (desc.getDockingCache() != null) {
399: result.add(desc.getDockingCache());
400: }
401: result.add(desc.getCache());
402: }
403: return result;
404: }
405:
406: /**
407: * The bitwise SWT modifiers that this trim area suggests, like SWT.TOP
408: * or SWT.LEFT. The control modifiers determine the orientation,
409: * amongst other things.
410: *
411: * @return the bitwise OR of the SWT constants.
412: */
413: public int getControlModifiers() {
414: return fControlModifiers;
415: }
416:
417: /**
418: * The bitwise SWT modifiers that this trim area suggests, like SWT.TOP
419: * or SWT.LEFT.
420: *
421: * @param mod
422: * the bitwise OR of the SWT constants.
423: */
424: public void setControlModifiers(int mod) {
425: fControlModifiers = mod;
426: }
427: }
|