001: /*******************************************************************************
002: * Copyright (c) 2004, 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 org.eclipse.swt.SWT;
013: import org.eclipse.swt.graphics.Point;
014: import org.eclipse.swt.graphics.Rectangle;
015: import org.eclipse.swt.widgets.Composite;
016: import org.eclipse.swt.widgets.Control;
017: import org.eclipse.swt.widgets.Layout;
018:
019: /**
020: * This class wraps a control with a complex computeSize method. It uses caching
021: * to reduce the number of times the control's computeSize method is called. This
022: * allows controls (such as Coolbars and wrapping text) with slow computeSize
023: * operations to be used inside layouts and composites that use inefficient caching.
024: * <p>
025: * For example, you want to use Coolbar A inside composite B. Rather than making A
026: * a direct child of B, place it inside a CacheWrapper and insert the CacheWrapper
027: * into B. Any layout data that would normally be attached to the control itself
028: * should be attached to the wrapper instead:
029: * </p>
030: * <code>
031: *
032: * // Unoptimized code
033: * Toolbar myToolbar = new Toolbar(someParent, SWT.WRAP);
034: * myToolbar.setLayoutData(someLayoutData);
035: * </code>
036: * <code>
037: *
038: * // Optimized code
039: * CacheWrapper myWrapper = new CacheWrapper(someParent);
040: * Toolbar myToolbar = new Toolbar(myWrapper.getControl(), SWT.WRAP);
041: * myWrapper.getControl().setLayoutData(someLayoutData);
042: * </code>
043: * <p>
044: * CacheWrapper creates a Composite which should have exactly one child: the control
045: * whose size should be cached. Note that CacheWrapper does NOT respect the flushCache
046: * argument to layout() and computeSize(). This is intentional, since the whole point of
047: * this class is to workaround layouts with poor caching, and such layouts will typically
048: * be too eager about flushing the caches of their children. However, this means that you
049: * MUST manually call flushCache() whenver the child's preferred size changes (and before
050: * the parent is layed out).
051: * </p>
052: *
053: * @since 3.0
054: */
055: public class CacheWrapper {
056: private Composite proxy;
057:
058: private SizeCache cache = new SizeCache();
059:
060: private Rectangle lastBounds = new Rectangle(0, 0, 0, 0);
061:
062: private class WrapperLayout extends Layout implements
063: ICachingLayout {
064: protected Point computeSize(Composite composite, int wHint,
065: int hHint, boolean flushCache) {
066: Control[] children = composite.getChildren();
067: if (children.length != 1) {
068: return new Point(0, 0);
069: }
070:
071: cache.setControl(children[0]);
072:
073: return cache.computeSize(wHint, hHint);
074: }
075:
076: protected void layout(Composite composite, boolean flushCache) {
077: Control[] children = composite.getChildren();
078: if (children.length != 1) {
079: return;
080: }
081:
082: Control child = children[0];
083: Rectangle newBounds = composite.getClientArea();
084: if (!newBounds.equals(lastBounds)) {
085: child.setBounds(newBounds);
086: lastBounds = newBounds;
087: }
088:
089: }
090:
091: /* (non-Javadoc)
092: * @see org.eclipse.ui.internal.layout.ICachingLayout#flush(org.eclipse.swt.widgets.Control)
093: */
094: public void flush(Control dirtyControl) {
095: CacheWrapper.this .flushCache();
096: }
097: }
098:
099: /**
100: * Creates a <code>CacheWrapper</code> with the given parent
101: *
102: * @param parent
103: */
104: public CacheWrapper(Composite parent) {
105: proxy = new Composite(parent, SWT.NONE);
106:
107: proxy.setLayout(new WrapperLayout());
108: }
109:
110: /**
111: * Flush the cache. Call this when the child has changed in order to force
112: * the size to be recomputed in the next resize event.
113: */
114: public void flushCache() {
115: cache.flush();
116: }
117:
118: /**
119: * Use this as the parent of the real control.
120: *
121: * @return the proxy contol. It should be given exactly one child.
122: */
123: public Composite getControl() {
124: return proxy;
125: }
126:
127: /**
128: * Dispose of any widgets created by this wrapper.
129: */
130: public void dispose() {
131: if (proxy != null) {
132: proxy.dispose();
133: proxy = null;
134: }
135: }
136: }
|