/*
* This software is Copyright 2005,2006,2007,2008 Langdale Consultants.
* Langdale Consultants can be contacted at: http://www.langdale.com.au
*/
package au.com.langdale.ui.builder;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ICheckable;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.part.PageBook;
import au.com.langdale.ui.plumbing.Observer;
import au.com.langdale.ui.plumbing.Plumbing;
import au.com.langdale.ui.util.IconCache;
/**
* A base class for form content and associated logic. See the base class, Plumbing,
* for details of the form update/refresh logic.
*
* This class holds a collection of controls and viewers, accessible by name,
* and the event listeners needed to link them to the plumbing.
*
* They can be retrieved by that name with an accessor method of the appropriate type
* such as getText() or getButton(). The accessor methods are generally required
* to implement the plumbing update() and refresh() methods.
*
* The widgets are built with a FormToolkit which determines their look and feel.
*
* FormToolkit is an eclipse UI concept. This class also provides factory
* methods for FormToolkits.
*/
public class Assembly extends Plumbing {
private FormToolkit toolkit;
private Map subjects;
private Control root;
private ButtonObserver buttonObserver;
/**
* An Assembly requires a FormToolkit, that may be shared with other assemblies.
* The synchronous argument determines the behaviour of the assembly's plumbing.
*/
public Assembly(FormToolkit toolkit, Observer observer, boolean synchronous) {
super(observer, synchronous);
this.toolkit = toolkit;
subjects = new HashMap();
}
/**
* A sub-assembly is linked to the same event plumbing as its parent
* and uses the same form construction toolkit.
* @param parent
*/
public Assembly(Assembly parent) {
super(parent);
toolkit = parent.toolkit;
subjects = new HashMap();
}
@Override
public void dispose() {
super.dispose();
if( root != null)
root.dispose();
};
/**
* Create an assembly that can realise the given template
* and shares a controller and toolkit with the present assembly.
*/
public Assembly createSubAssembly(Composite parent, Template template) {
Assembly sub = new Assembly(this);
sub.realise(parent, template);
return sub;
}
/**
* Create an assembly that can realise the given template with the given
* form construction toolkit. The synchronous argument determines the
* behaviour of the plumbing.
*/
public static Assembly createAssembly(Composite parent, Template template, FormToolkit toolkit, Observer observer, boolean synchronous) {
Assembly assembly = new Assembly(toolkit, observer, synchronous);
assembly.realise(parent, template);
return assembly;
}
/**
* Build a widget hierarchy under the given composite
* using the given template associated with this assembly.
*
* This method should only be called once as the
* Template will hook widget events and register
* them against their names.
*/
public Control realise(Composite parent, Template template) {
root = template.realise(parent, this);
return root;
}
/**
* Add a generic button and hyperlink observer that will be attached to
* all buttons and markup regions.
*/
public void setButtonObserver(ButtonObserver obs) {
this.buttonObserver = obs;
}
/**
* Set the given checkbox tree or table viewer to multiple selection mode if
* state is true otherwise to single selection mode.
*/
public void setCheckMultiple(ICheckable viewer, boolean state) {
if( state) {
viewer.removeCheckStateListener(singleCheckedListener);
viewer.addCheckStateListener(checkStateListener);
}
else{
viewer.removeCheckStateListener(checkStateListener);
viewer.addCheckStateListener(singleCheckedListener);
}
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public Text getText(String name) {
return (Text) getControl(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public FormText getMarkup(String name) {
return (FormText) getControl(name);
}
/**
* Convenience to set a widget's text in one operation.
*/
public Control setTextValue(String name, String value) {
Control widget = getControl(name);
if(value == null)
value = "";
if( widget instanceof Text)
setText((Text) widget, value);
else if(widget instanceof Label)
setText((Label) widget, value);
else if(widget instanceof Button)
setText((Button) widget, value);
return widget;
}
/**
* Add a listener to a button.
* @return
*/
public void addListener( String name, SelectionListener listener) {
getButton(name).addSelectionListener(listener);
}
/**
* Add listener to a markup region.
*/
public void addListener( String name, IHyperlinkListener listener) {
getMarkup(name).addHyperlinkListener(listener);
}
/**
* Convenience to locate an icon and set the image of a control.
*/
public Control setIconForObject(String name, Object value) {
Control widget = getControl(name);
if( widget instanceof Button )
((Button)widget).setImage(IconCache.getIcons().get(value, 32));
else if( widget instanceof Label)
((Label)widget).setImage(IconCache.getIcons().get(value, 32));
return widget;
}
private void setText(Text widget, String value) {
if( ! widget.getText().equals(value))
widget.setText(value);
}
private void setText(Label widget, String value) {
widget.setText(value);
widget.getParent().layout(true);
}
private void setText(Button widget, String value) {
widget.setText(value);
widget.getParent().layout(true);
}
/**
* Make the named control visible along with the
* stack layer to which it belongs. A Stack and its
* layers are created with Stack().
*/
public void showStackLayer(String name) {
Object subject = subjects.get(name);
if( subject instanceof Viewer)
showStackLayer(((Viewer)subject).getControl());
else
showStackLayer((Control)subject);
}
private void showStackLayer(Control control) {
Composite parent = control.getParent();
if( parent instanceof PageBook) {
PageBook book = (PageBook) parent;
book.showPage(control);
book.getParent().layout(true, true);
}
if( parent != null) {
showStackLayer(parent);
}
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public Label getLabel(String name) {
return (Label) getControl(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public TreeViewer getTreeViewer(String name) {
return (TreeViewer) getViewer(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public CheckboxTreeViewer getCheckboxTreeViewer(String name) {
return (CheckboxTreeViewer) getViewer(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public CheckboxTableViewer getCheckboxTableViewer(String name) {
return (CheckboxTableViewer) getViewer(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public ArrayComposite getArrayComposite(String name) {
return (ArrayComposite) getControl(name);
}
/**
* Get a widget from the realised hierarchy of the indicated type and given name.
*/
public Button getButton(String name) {
return (Button) getControl(name);
}
/**
* Convenience to set a Button widget's selected value in one operation.
*/
public Button setButtonValue(String name, boolean value) {
Button widget = getButton(name);
widget.setSelection(value);
return widget;
}
/**
* Get the root widget, which was created by the realise() method.
*/
public Control getRoot() {
return root;
}
/**
* Get the Form widget (if one was used) or null.
*/
public ScrolledForm getForm() {
if( root instanceof ScrolledForm)
return (ScrolledForm) root;
else
return null;
}
public FormToolkit getToolkit() {
return toolkit;
}
/**
* Get a generic control.
*/
public Control getControl(String name) {
return (Control) subjects.get(name);
}
/**
* Get a generic Viewer.
*/
public Viewer getViewer(String name) {
return (Viewer) subjects.get(name);
}
/**
* Register a control under its name.
*/
public void putControl(String name, Control control) {
subjects.put(name, control);
}
/**
* Register a viewer under its name.
*/
public void putViewer(String name, Viewer viewer) {
subjects.put(name, viewer);
}
public final SelectionListener selectionListener = new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
fireWidgetEvent();
}
public void widgetSelected(SelectionEvent e) {
fireWidgetEvent();
}
};
public final SelectionListener refreshSelectionListener = new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
doRefresh();
}
public void widgetSelected(SelectionEvent e) {
doRefresh();
}
};
public SelectionListener createButtonListener(final String name) {
return new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
if( buttonObserver != null )
buttonObserver.clicked(name);
}
public void widgetSelected(SelectionEvent e) {
if( buttonObserver != null )
buttonObserver.clicked(name);
}
};
}
public final IHyperlinkListener hyperlinkListener = new IHyperlinkListener() {
public void linkActivated(HyperlinkEvent e) {
if( buttonObserver != null )
buttonObserver.clicked(e.getHref().toString());
}
public void linkEntered(HyperlinkEvent e) {
if( buttonObserver != null )
buttonObserver.entered(e.getHref().toString());
}
public void linkExited(HyperlinkEvent e) {
if( buttonObserver != null )
buttonObserver.exited(e.getHref().toString());
}
};
public final ModifyListener modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
fireWidgetEvent();
}
};
public final ISelectionChangedListener selectionChangedlistener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
fireWidgetEvent();
}
};
public final ICheckStateListener checkStateListener = new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
fireWidgetEvent();
}
};
private final ICheckStateListener singleCheckedListener = new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
if( event.getChecked()) {
ICheckable checkable = event.getCheckable();
if( checkable instanceof CheckboxTreeViewer) {
CheckboxTreeViewer source = (CheckboxTreeViewer) checkable;
source.setCheckedElements(new Object[] {event.getElement()});
}
else if( checkable instanceof CheckboxTableViewer ) {
CheckboxTableViewer source = (CheckboxTableViewer) event.getCheckable();
source.setCheckedElements(new Object[] {event.getElement()});
}
}
fireWidgetEvent();
}
};
/**
* Create a form toolkit that uses default dialog background colour.
*/
public static FormToolkit createDialogToolkit() {
FormToolkit toolkit = createFormToolkit();
toolkit.setBackground(null);
return toolkit;
}
/**
* Create a form toolkit that uses form background colour.
*/
public static FormToolkit createFormToolkit() {
Display display = PlatformUI.getWorkbench().getDisplay();
FormToolkit toolkit = new FormToolkit(display);
toolkit.setBorderStyle(SWT.BORDER);
return toolkit;
}
}