blob: c8e70be3316801e9efdb703c21a3bfd7636a2ad4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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 org.eclipse.swt.SWT;
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.Layout;
/**
* This class wraps a control with a complex computeSize method. It uses caching
* to reduce the number of times the control's computeSize method is called. This
* allows controls (such as Coolbars and wrapping text) with slow computeSize
* operations to be used inside layouts and composites that use inefficient caching.
* <p>
* For example, you want to use Coolbar A inside composite B. Rather than making A
* a direct child of B, place it inside a CacheWrapper and insert the CacheWrapper
* into B. Any layout data that would normally be attached to the control itself
* should be attached to the wrapper instead:
* </p>
* <code>
*
* // Unoptimized code
* Toolbar myToolbar = new Toolbar(someParent, SWT.WRAP);
* myToolbar.setLayoutData(someLayoutData);
* </code>
* <code>
*
* // Optimized code
* CacheWrapper myWrapper = new CacheWrapper(someParent);
* Toolbar myToolbar = new Toolbar(myWrapper.getControl(), SWT.WRAP);
* myWrapper.getControl().setLayoutData(someLayoutData);
* </code>
* <p>
* CacheWrapper creates a Composite which should have exactly one child: the control
* whose size should be cached. Note that CacheWrapper does NOT respect the flushCache
* argument to layout() and computeSize(). This is intentional, since the whole point of
* this class is to workaround layouts with poor caching, and such layouts will typically
* be too eager about flushing the caches of their children. However, this means that you
* MUST manually call flushCache() whenver the child's preferred size changes (and before
* the parent is layed out).
* </p>
*
* @since 3.0
*/
public class CacheWrapper {
private Composite proxy;
private SizeCache cache = new SizeCache();
private Rectangle lastBounds = new Rectangle(0, 0, 0, 0);
private class WrapperLayout extends Layout implements ICachingLayout {
protected Point computeSize(Composite composite, int wHint, int hHint,
boolean flushCache) {
Control[] children = composite.getChildren();
if (children.length != 1) {
return new Point(0, 0);
}
cache.setControl(children[0]);
return cache.computeSize(wHint, hHint);
}
protected void layout(Composite composite, boolean flushCache) {
Control[] children = composite.getChildren();
if (children.length != 1) {
return;
}
Control child = children[0];
Rectangle newBounds = composite.getClientArea();
if (!newBounds.equals(lastBounds)) {
child.setBounds(newBounds);
lastBounds = newBounds;
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.layout.ICachingLayout#flush(org.eclipse.swt.widgets.Control)
*/
public void flush(Control dirtyControl) {
CacheWrapper.this.flushCache();
}
}
/**
* Creates a <code>CacheWrapper</code> with the given parent
*
* @param parent
*/
public CacheWrapper(Composite parent) {
proxy = new Composite(parent, SWT.NONE);
proxy.setLayout(new WrapperLayout());
}
/**
* Flush the cache. Call this when the child has changed in order to force
* the size to be recomputed in the next resize event.
*/
public void flushCache() {
cache.flush();
}
/**
* Use this as the parent of the real control.
*
* @return the proxy contol. It should be given exactly one child.
*/
public Composite getControl() {
return proxy;
}
/**
* Dispose of any widgets created by this wrapper.
*/
public void dispose() {
if (proxy != null) {
proxy.dispose();
proxy = null;
}
}
}