/******************************************************************************* * Copyright 2012 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.common.ui.viewers; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ControlEditor; import org.eclipse.swt.custom.TreeEditor; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.TreeItem; /** * Abstract implementation of the {@link IControlViewerHelper} interface. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) * * @param <T> * {@link ControlEditor} type */ public abstract class ControlViewerHelper<T extends ControlEditor> implements IControlViewerHelper { private IControlProvider controlProvider; private final Map<Item, ControlItem> controls = new HashMap<Item, ControlItem>(); /** * @return A new {@link ControlEditor} for editing an item in this Viewer */ public abstract T createEditor(); /** * Set the given editor's control and item. * <p/> * For a tree, this should call * {@link TreeEditor#setEditor(Control, TreeItem)}. * * @param editor * Editor to call * @param control * Control used for editing * @param item * Item being edited */ public abstract void setEditor(T editor, Control control, Item item); /** * @return The control used to render this Viewer's items */ public abstract Composite getViewerControl(); @Override public IControlProvider getControlProvider() { return controlProvider; } @Override public void setControlProvider(IControlProvider controlProvider) { this.controlProvider = controlProvider; } @Override public void associate(Object element, Item item) { //create an associate a control with the item/element if (controlProvider != null && item instanceof TreeItem) { TreeItem treeItem = (TreeItem) item; ControlItem controlItem = controls.get(item); if (controlItem == null) { setupControl(element, treeItem); } else { boolean reuseControl = controlProvider.updateControl(controlItem.control, element, item, controlItem.editor); if (reuseControl) { //ensure the control is layout correctly controlItem.editor.layout(); } else { //don't reuse the old control; pack it up and create a new one packupControl(item); setupControl(element, treeItem); } } } else { packupControl(item); } } @Override public void disassociate(Item item) { packupControl(item); } private void setupControl(Object element, TreeItem item) { controls.put(item, new ControlItem(element, item)); } private void packupControl(Item item) { ControlItem controlItem = controls.remove(item); if (controlItem != null) { controlItem.dispose(); } } @Override public Composite getControlForItem(Item item) { if (controlProvider != null && item != null) { ControlItem controlItem = controls.get(item); if (controlItem != null) { return controlItem.composite; } } return null; } /** * Helper class which stores required objects for each tree item. */ private class ControlItem { public final Object element; public final TreeItem item; public final T editor; public final BoundedComposite composite; public final Control control; public ControlItem(Object element, TreeItem item) { this.element = element; this.item = item; this.editor = createEditor(); Composite viewerControl = getViewerControl(); this.composite = new BoundedComposite(viewerControl, SWT.NONE, this); this.composite.setBackground(viewerControl.getBackground()); this.control = controlProvider == null ? null : controlProvider.getControl(composite, element, item, editor); setEditor(editor, composite, item); } public void dispose() { if (control != null) { controlProvider.disposeControl(control, element, item); } composite.dispose(); editor.dispose(); } } /** * {@link Composite} subclass which provides the ability to prevent its * bounds being set, storing the requested bounds instead. */ private class BoundedComposite extends Composite { private final ControlItem controlItem; public BoundedComposite(Composite parent, int style, ControlItem controlItem) { super(parent, style); this.controlItem = controlItem; setLayout(new FillLayout()); } @Override public void setBounds(int x, int y, int width, int height) { if (controlProvider != null) { Rectangle bounds = new Rectangle(x, y, width, height); Rectangle overriddenBounds = controlProvider.overrideBounds(bounds, controlItem.control, controlItem.element, controlItem.item); bounds = overriddenBounds != null ? overriddenBounds : bounds; x = bounds.x; y = bounds.y; width = bounds.width; height = bounds.height; } super.setBounds(x, y, width, height); } } }