/*******************************************************************************
* Copyright (c) 2012, 2014 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.ui.views.controls;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.jface.dialogs.IDialogPage;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer;
import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode;
import org.eclipse.tcf.te.runtime.properties.PropertiesContainer;
import org.eclipse.tcf.te.runtime.services.ServiceManager;
import org.eclipse.tcf.te.runtime.services.interfaces.IPropertiesAccessService;
import org.eclipse.tcf.te.ui.controls.AbstractDecoratedDialogPageControl;
import org.eclipse.tcf.te.ui.jface.interfaces.IValidatingContainer;
import org.eclipse.tcf.te.ui.swt.SWTControlUtil;
import org.eclipse.tcf.te.ui.views.interfaces.ICategory;
import org.eclipse.tcf.te.ui.views.nls.Messages;
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
import org.eclipse.ui.navigator.CommonViewerSorter;
/**
* Abstract context selector control.
* <p>
* Allows to present a configurable set of elements from the data model from which the user can
* select one or more elements.
* <p>
* Default properties:
* <ul>
* <li>PROPERTY_SHOW_GHOST_MODEL_NODES = false</li>
* <li>PROPERTY_MULTI_CONTEXT_SELECTOR = false</li>
* </ul>
*/
public abstract class AbstractContextSelectorControl extends AbstractDecoratedDialogPageControl implements ISelectionProvider {
/**
* Property: If set to <code>true</code>, ghost model nodes will be shown within the tree.
*/
public static final String PROPERTY_SHOW_GHOST_MODEL_NODES = "showGhostModelNodes"; //$NON-NLS-1$
/**
* Property: If set to <code>true</code>, the control will be created as multi
* context control. That means that more than one tree item will be
* checkmarkable. In single context selector mode, only one tree item
* can be checkmarked at the same time.
*/
public static final String PROPERTY_MULTI_CONTEXT_SELECTOR = "multiContextSelector"; //$NON-NLS-1$
// The last failure cause
private Throwable lastFailureCause;
// Flag for controlling if at least one element has to be selected
private boolean requireSelection = true;
/**
* List of selection changed listeners.
*/
private final List<ISelectionChangedListener> selectionListeners = new ArrayList<ISelectionChangedListener>();
/**
* Control properties. See predefined property constants within the class and subclass
* implementations. Property changes are not notified.
*/
private final IPropertiesContainer properties = new PropertiesContainer();
// Reference to the tree viewer control used.
private TreeViewer viewer;
// The current selection within the tree viewer.
/* default */ ISelection selection;
/**
* Constant to return an empty viewer filter array.
*/
protected final static ViewerFilter[] NO_FILTERS = new ViewerFilter[0];
/**
* Constant to return an empty selected model context array.
*/
protected final static IModelNode[] NO_CONTEXTS = new IModelNode[0];
// Currently active set of viewer filters.
private ViewerFilter[] filters;
// Currently active checkbox tree viewer check action listener
private ICheckStateListener listener;
/**
* Default implementation of the context selector controls tree viewer.
*/
protected class ContextSelectorTreeViewer extends ContainerCheckedTreeViewer {
/**
* Constructor.
*
* @param parent The parent control.
* @param style The SWT style bits used to create the tree.
*/
public ContextSelectorTreeViewer(Composite parent, int style) {
// make sure that the passed in style bits are not contaminated
// by the CheckboxTreeViewer.
this(new Tree(parent, style));
}
/**
* Constructor.
*
* @param parent The parent control.
*/
public ContextSelectorTreeViewer(Composite parent) {
super(parent);
}
/**
* Constructor.
*
* @param tree The tree control.
*/
public ContextSelectorTreeViewer(Tree tree) {
super(tree);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.TreeViewer#isExpandable(java.lang.Object)
*/
@Override
public boolean isExpandable(Object element) {
boolean expandable = super.isExpandable(element);
// adjust the expandable action if the element does not have
// children after the filtering.
if (expandable) {
expandable = getFilteredChildren(element).length > 0;
}
return expandable;
}
/**
* Returns the child items for the given element if any.
*
* @param element The element.
* @return The child items of the element or <code>null</code> if none.
*/
public Item[] getChildren(Object element) {
Widget item = findItem(element);
return getChildren(item);
}
/* (non-Javadoc)
* @see org.eclipse.ui.dialogs.ContainerCheckedTreeViewer#doCheckStateChanged(java.lang.Object)
*/
@Override
protected void doCheckStateChanged(Object element) {
// Our ghost model elements requires some special handling, as
// these elements should be never checked fully. Try to determine
// if we have to double check on the parents action.
boolean skipDoubleCheckParentState = false;
// If the element isn't one of our model elements, pass on to
// to super implementation
skipDoubleCheckParentState |= !(element instanceof IModelNode);
// If the element is one of our model elements and it is not
// a ghost node, the parent can't be a ghost node either.
if (!skipDoubleCheckParentState) {
skipDoubleCheckParentState |= !isGhost((IModelNode) element);
}
// If the element is a ghost model element, then we have to check
// on the parent as well.
if (!skipDoubleCheckParentState) {
IPropertiesAccessService service = ServiceManager.getInstance().getService(IPropertiesAccessService.class);
IModelNode parent = service != null ? (IModelNode)service.getParent(element) : null;
skipDoubleCheckParentState |= parent == null || !isGhost(parent);
}
// Call the super implementation to check the item and
// updating parents and children the first time
super.doCheckStateChanged(element);
if (!skipDoubleCheckParentState) {
// Get the tree item for the element and check the parent items
// for being associated with ghost model elements.
Widget item = findItem(element);
if (item instanceof TreeItem) {
TreeItem treeItem = ((TreeItem) item).getParentItem();
while (treeItem != null) {
Object data = treeItem.getData();
// If a child item is checked, otherwise we wouldn't come here, and this
// parent item isn't expanded, we must(!) expand the item now here by force,
// otherwise we will loose the checked states of the children elements!
if (!treeItem.getExpanded()) {
treeItem.setExpanded(true);
}
// Decide if we shall gray the checked action.
// --> The checked action is grayed if the item is a ghost.
boolean isGhost = data instanceof IModelNode && isGhost((IModelNode) data);
if (!treeItem.getGrayed() && isGhost) {
treeItem.setGrayed(true);
}
// go one level up in the hierarchy
treeItem = treeItem.getParentItem();
}
}
}
}
}
/**
* Returns if or if not the given model node is a ghost node.
*
* @param node The model node. Must not be <code>null</code>.
* @return <code>True</code> if the node is a ghost node, <code>false</code> otherwise.
*/
/* default */ boolean isGhost(IModelNode node) {
Assert.isNotNull(node);
IPropertiesAccessService service = ServiceManager.getInstance().getService(node, IPropertiesAccessService.class);
if (service != null) {
Object value = service.getProperty(node, IModelNode.PROPERTY_IS_GHOST);
if (value instanceof Boolean) {
return ((Boolean)value).booleanValue();
} else if (value instanceof String) {
return Boolean.valueOf((String)value).booleanValue();
}
return false;
}
try {
return node.isProperty(IModelNode.PROPERTY_IS_GHOST, true);
} catch (AssertionFailedException e) { /* ignored on purpose */ }
return false;
}
/**
* Default implementation of the context selector controls check action listener.
*/
protected class ContextSelectedCheckStateListener implements ICheckStateListener {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
*/
@Override
public void checkStateChanged(CheckStateChangedEvent event) {
Object element = event.getElement();
boolean checked = event.getChecked();
onCheckStateChanged(element, checked);
// validate the parent page if there is one set
if (getParentPage() instanceof IValidatingContainer) {
((IValidatingContainer) getParentPage()).validate();
}
}
}
/**
* Default implementation of the context selector controls viewer filter.
*/
protected class ContextSelectorViewerFilter extends ViewerFilter {
/**
* Returns if or if not ghost model elements should be visible within the model context
* selector controls tree viewer. Default is not to show the ghost model elements.
*
* @return <code>True</code> to show the ghost model elements, <code>false</code> otherwise.
*/
protected boolean doShowGhostModelElements() {
return getPropertiesContainer().getBooleanProperty(PROPERTY_SHOW_GHOST_MODEL_NODES);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof ICategory) {
return ((ICategory)element).isEnabled();
}
else if (element instanceof IModelNode) {
if (isGhost((IModelNode) element)) {
return doShowGhostModelElements();
}
return true;
}
return false;
}
}
/**
* Constructor.
*
* @param parentPage The parent target connection page this control is embedded in. Might be
* <code>null</code> if the control is not associated with a page.
*/
public AbstractContextSelectorControl(IDialogPage parentPage) {
super(parentPage);
selectionListeners.clear();
// initialize the properties
initializeProperties(getPropertiesContainer());
}
/**
* Returns the properties container associated with this control.
*
* @return The properties container.
*/
public final IPropertiesContainer getPropertiesContainer() {
return properties;
}
/**
* Initialize the properties associated with this control.
*
* @param properties The properties container. Must not be <code>null</code>.
*/
protected void initializeProperties(IPropertiesContainer properties) {
Assert.isNotNull(properties);
properties.setProperty(PROPERTY_SHOW_GHOST_MODEL_NODES, false);
properties.setProperty(PROPERTY_MULTI_CONTEXT_SELECTOR, false);
}
/**
* Set the last failure cause to display.
*
* @param cause The last failure case or <code>null</code>.
*/
public final void setLastFailureCause(Throwable cause) {
lastFailureCause = cause;
if (getParentPage() instanceof IValidatingContainer) {
((IValidatingContainer)getParentPage()).validate();
}
}
/**
* Returns the last failure cause to display.
*
* @return The last failure cause or <code>null</code>.
*/
public final Throwable getLastFailureCause() {
return lastFailureCause;
}
/**
* Returns the default title text which should be used by the enclosing controls or windows if
* these controls do need to set a title.
* <p>
* The default implementation returns <code>null</code>.
*
* @return The default title text or <code>null</code> if none.
*/
public String getDefaultTitle() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.controls.BaseControl#dispose()
*/
@Override
public void dispose() {
viewer = null;
super.dispose();
}
/**
* Returns the list of checked model node contexts. The elements are in the order they appear
* within the tree from top to bottom. The client of the control is in charge detecting any type
* of hierarchy or other relationships between the elements.
*
* @return The list of checked model node contexts or an empty list of none.
*/
public IModelNode[] getCheckedModelContexts() {
// This method does return something useful only if it is a checkable
// tree viewer and the check style is set for the tree.
if (!getViewer().getControl().isDisposed() && getViewer() instanceof ContainerCheckedTreeViewer && (getTreeViewerStyle() & SWT.CHECK) != 0) {
ContainerCheckedTreeViewer viewer = (ContainerCheckedTreeViewer) getViewer();
// Get the list of checked elements. Checked elements includes the grayed elements
List<?> checked = viewer.getCheckedElements() != null ? Arrays.asList(viewer.getCheckedElements()) : Collections.emptyList();
// Get the list of grayed elements.
List<?> grayed = viewer.getGrayedElements() != null ? Arrays.asList(viewer.getGrayedElements()) : Collections.emptyList();
// There must be at least one element checked
if (!checked.isEmpty()) {
List<IModelNode> contexts = new ArrayList<IModelNode>();
for (Object element : checked) {
// If the context is a model node and the parent container node is fully
// checked, drop the model node and the use the container node only.
if (element instanceof IModelNode) {
IModelNode node = (IModelNode) element;
// Determine the parent node
IPropertiesAccessService service = ServiceManager.getInstance().getService(node, IPropertiesAccessService.class);
IModelNode parent = service != null ? (IModelNode)service.getParent(node) : node.getParent();
if (parent != null && checked.contains(parent) && !grayed.contains(parent)) {
continue;
}
}
// If the element is a model node and not grayed,
// add the element to the list of checked contexts.
if (element instanceof IModelNode && !grayed.contains(element)) {
contexts.add((IModelNode) element);
}
}
return contexts.toArray(new IModelNode[contexts.size()]);
}
}
return NO_CONTEXTS;
}
/**
* Called from the default check action listener implementation if the checked action of an element has changed.
*
* @param element The element checked or unchecked. Must not be <code>null</code>.
* @param checked <code>True</code> if the model node has been checked, <code>false</code> if
* unchecked.
*/
protected void onCheckStateChanged(Object element, boolean checked) {
// In case the control is operating in single context selector mode,
// we have to uncheck any other element than the given checked one.
if (checked && getPropertiesContainer().isProperty(PROPERTY_MULTI_CONTEXT_SELECTOR, false)) {
if (getViewer() instanceof ContextSelectorTreeViewer) {
// Node: Within here, only methods which do not fire the check action listeners
// again must be used!
ContextSelectorTreeViewer viewer = (ContextSelectorTreeViewer)getViewer();
// If the checked node is a container node and has children, select
// the first children of the container.
Item[] childItems = viewer.getChildren(element);
if (childItems != null && childItems.length > 1) {
// Take the first item as element to be checked
viewer.setCheckedElements(new Object[] { childItems[0].getData() });
} else {
// Set the passed in element node checked
viewer.setCheckedElements(new Object[] { element });
}
}
}
}
/**
* Sets the list of checked model node contexts.
*
* @param contexts The list of model node contexts. Must not be <code>null</code>.
*/
public void setCheckedModelContexts(IModelNode[] contexts) {
Assert.isNotNull(contexts);
// This method does nothing if the tree viewer isn't a checkable tree viewer.
if (getViewer() instanceof ContainerCheckedTreeViewer && (getTreeViewerStyle() & SWT.CHECK) != 0) {
ContainerCheckedTreeViewer viewer = (ContainerCheckedTreeViewer) getViewer();
// Set the checked elements. This will trigger the validation of the
// checked action of all the parent and children elements.
viewer.setCheckedElements(contexts);
// Make sure that at least the first checked element is visible to the user
if (contexts.length > 0) {
viewer.setSelection(new StructuredSelection(contexts[0]), true);
}
}
}
/**
* Returns the controls associated tree viewer.
*
* @return The tree viewer instance or <code>null</code> if not created yet.
*/
public final TreeViewer getViewer() {
return viewer;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.controls.BaseControl#setupPanel(org.eclipse.swt.widgets.Composite)
*/
@Override
public void setupPanel(Composite parent) {
super.setupPanel(parent);
// Create the container composite for the tree control.
Composite composite = doCreateTopContainerComposite(parent);
Assert.isNotNull(composite);
// Create the viewer
viewer = createTreeViewerControl(composite);
// And now configure the listeners
configureControlListener();
// Trigger a selection changed event to give listeners
// a chance to initialize their enabled action correctly
viewer.setSelection(viewer.getSelection());
}
/**
* Create the top container composite.
*
* @param parent The parent composite. Must not be <code>null</code>.
* @return The top container composite. Must not be <code>null</code>.
*/
protected Composite doCreateTopContainerComposite(Composite parent) {
Assert.isNotNull(parent);
// Set the default layout data attributes for the composite
int style = GridData.FILL_BOTH;
int heightHint = SWT.DEFAULT;
// Fallback to standard non-form controls and create a composite which extends
// in both directions and has no margins
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
GridData layoutData = new GridData(style);
layoutData.heightHint = heightHint;
composite.setLayoutData(layoutData);
return composite;
}
/**
* Creates the tree viewer control. Override to return a custom tree viewer implementation.
*
* @param parent The parent composite of the tree viewer. Must not be <code>null</code>.
* @return The tree viewer control. Must be never <code>null</code>.
*/
protected TreeViewer createTreeViewerControl(Composite parent) {
Assert.isNotNull(parent);
CheckboxTreeViewer viewer = doCreateNewTreeViewerControl(parent, getTreeViewerStyle());
doConfigureTreeViewerControl(viewer);
viewer.setInput(getInitialViewerInput());
doEnableControl(viewer);
return viewer;
}
/**
* Creates a new instance of the tree viewer control to use. This method will be called from
* {@link #createTreeViewerControl(Composite)} if creating the tree viewer instance.
*
* @param parent The parent composite of the tree viewer. Must not be <code>null</code>.
* @param style The SWT style bits.
*
* @return The tree viewer instance. Must not be <code>null</code>.
*/
protected CheckboxTreeViewer doCreateNewTreeViewerControl(Composite parent, int style) {
return new ContextSelectorTreeViewer(parent, style);
}
/**
* Configure the tree viewer control.
*
* @param viewer The tree viewer instance. Must not be <code>null</code>.
*/
protected void doConfigureTreeViewerControl(CheckboxTreeViewer viewer) {
Assert.isNotNull(viewer);
viewer.setUseHashlookup(true);
doConfigureTreeLayoutData(viewer.getTree());
doConfigureTreeContentAndLabelProvider(viewer);
viewer.setSorter(doCreateViewerSorter());
if ((getTreeViewerStyle() & SWT.CHECK) != 0 && getViewerCheckStateListener(viewer) != null) {
viewer.addCheckStateListener(getViewerCheckStateListener(viewer));
}
if (hasViewerFilters()) {
viewer.setFilters(getViewerFilters());
}
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
selection = event.getSelection();
fireSelectionChanged();
}
});
doCreateControlDecoration(viewer.getTree(), viewer.getTree().getParent());
}
/**
* Configure the tree's layout data. The layout data set to the tree must be of type
* <code>GridData</code>.
*
* @param tree The tree to configure. Must not be <code>null</code>.
*/
protected void doConfigureTreeLayoutData(Tree tree) {
GridData layoutData = new GridData(GridData.FILL_HORIZONTAL);
layoutData.heightHint = 150;
tree.setLayoutData(layoutData);
}
/**
* Returns the style bits to apply to the tree viewer.
* <p>
* The default set tree viewer style bits are:
* <ul>
* <li>SWT.SINGLE</li>
* <li>SWT.H_SCROLL</li>
* <li>SWT.V_SCROLL</li>
* <li>SWT.BORDER</li>
*
* @return The style bits to apply to the tree viewer.
*/
protected int getTreeViewerStyle() {
return SWT.CHECK | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.MULTI;
}
/**
* Creates the viewer sorter instance to associated to the controls tree viewer.
*
* @return The viewer sorter to associate or <code>null</code> if none.
*/
protected ViewerSorter doCreateViewerSorter() {
return new CommonViewerSorter();
}
/**
* Returns if or if not to associate viewer filters to the controls tree viewer. If this method
* returns <code>true</code>, {@link #doCreateViewerFilters()} must return not null!
*
* @return <code>True</code> if to associate viewer filters, <code>false</code> otherwise.
*/
protected boolean hasViewerFilters() {
return true;
}
/**
* Creates a returns a new set of the viewer filters to associated to the controls tree viewer.
* This method will be called from {@link #getViewerFilters()} in case the method
* {@link #hasViewerFilters()} returns <code>true</code> and no viewer filters got created
* before.
*
* @return The viewer filters to associate or <code>null</code> if none.
*/
protected ViewerFilter[] doCreateViewerFilters() {
return new ViewerFilter[] { new ContextSelectorViewerFilter() };
}
/**
* Returns the associated viewer filters of the controls tree viewer. If the control does have
* viewer filters ({@link #hasViewerFilters()} returns <code>true</code>) and the viewer filters
* had not yet been created, the method calls {@link #doCreateViewerFilters()}.
*
* @return The associated viewer filters of the controls tree viewer or the constant
* {@link #NO_FILTERS}.
*/
protected ViewerFilter[] getViewerFilters() {
if (filters == null && hasViewerFilters()) {
filters = doCreateViewerFilters();
}
return filters != null ? filters : NO_FILTERS;
}
/**
* Creates a new checkbox tree viewer check action listener. This method will be called from
* {@link #getViewerCheckStateListener()} in case the listener did not got created before.
*
* @param viewer The checkbox tree viewer. Must not be <code>null</code>.
* @return The checkbox tree viewer check action listener or <code>null</code> if none.
*/
protected ICheckStateListener doCreateViewerCheckStateListener(CheckboxTreeViewer viewer) {
Assert.isNotNull(viewer);
return new ContextSelectedCheckStateListener();
}
/**
* Returns the associated checkbox tree viewer check action listener. If the listener had not yet
* been created, the method calls {@link #doCreateLabelProvider()}.
*
* @param viewer The checkbox tree viewer. Must not be <code>null</code>.
* @return The associated checkbox tree viewer check action listener or <code>null</code> if
* none.
*/
protected ICheckStateListener getViewerCheckStateListener(CheckboxTreeViewer viewer) {
Assert.isNotNull(viewer);
if (listener == null) {
listener = doCreateViewerCheckStateListener(viewer);
}
return listener;
}
/**
* Returns the initial input object to set to the controls tree viewer.
*
* @return The initial viewer input to set or <code>null</code> if none.
*/
protected abstract Object getInitialViewerInput();
/**
* Configure content and label provider.
* @param viewer The tree viewer.
*/
protected abstract void doConfigureTreeContentAndLabelProvider(TreeViewer viewer);
/**
* Enables the tree control.
*
* @param viewer The tree viewer object. Must not be <code>null</code>.
*/
protected void doEnableControl(TreeViewer viewer) {
Assert.isNotNull(viewer);
SWTControlUtil.setEnabled(viewer.getTree(), viewer.getTree().getItemCount() > 0);
}
/**
* Refresh the controls viewer and check the viewers enablement. This method is called by the
* standard refresh toolbar item, if the control has a toolbar.
*/
public void refresh() {
if (viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
viewer.refresh(true);
doEnableControl(viewer);
}
}
/**
* Called from {@link #setupPanel(Composite)} before returning the control to the caller.
* Override to plug-in and configure any custom listener the subclassed control might need.
*/
protected void configureControlListener() {
}
/**
* Sets the given selection to the viewer.
*
* @param selection The selection to set. Must not be <code>null</code>.
*/
@Override
public void setSelection(ISelection selection) {
Assert.isNotNull(selection);
this.selection = selection;
if (viewer != null) {
viewer.setSelection(selection, true);
}
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
*/
@Override
public ISelection getSelection() {
return selection;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
*/
@Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
if (listener != null && !selectionListeners.contains(listener)) {
selectionListeners.add(listener);
}
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
*/
@Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
if (listener != null) {
selectionListeners.remove(listener);
}
}
/**
* Fire the selection changed event to the registered listeners.
*/
/* default */ void fireSelectionChanged() {
if (selection != null) {
SelectionChangedEvent event = new SelectionChangedEvent(this, selection);
for (ISelectionChangedListener listener : selectionListeners) {
listener.selectionChanged(event);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.controls.BaseControl#isValid()
*/
@Override
public boolean isValid() {
boolean valid = super.isValid();
if (!valid) return valid;
// If there is a last failure cause set, show that failure cause
valid = getLastFailureCause() == null;
if (!valid) {
setMessage(getLastFailureCause().getLocalizedMessage(), IMessageProvider.ERROR);
}
// The remote context selector control is only valid, if at least one
// element has been checked (if operating with CHECK style set)
if (valid && (getTreeViewerStyle() & SWT.CHECK) != 0 && requireSelection) {
int count = getCheckedModelContexts().length;
valid = count == 1 || (count > 1 && getPropertiesContainer().isProperty(PROPERTY_MULTI_CONTEXT_SELECTOR, true));
// if we are not valid here, it can only mean, that there is
// no connectable checked.
if (!valid) {
String messageId = "AbstractContextSelectorControl_error_noContextSelected"; //$NON-NLS-1$
if (getPropertiesContainer().isProperty(PROPERTY_MULTI_CONTEXT_SELECTOR, true)) {
messageId += "_multi"; //$NON-NLS-1$
}
else {
messageId += "_single"; //$NON-NLS-1$
}
setMessage(getMessageForId(messageId), getMessageTypeForId(messageId, IMessageProvider.ERROR));
}
}
if (getControlDecoration() != null) {
// Setup and show the control decoration if necessary
if (isEnabled() && (!valid || (getMessage() != null && getMessageType() != IMessageProvider.NONE))) {
// Update the control decorator
updateControlDecoration(getMessage(), getMessageType());
} else {
updateControlDecoration(null, IMessageProvider.NONE);
}
}
return valid;
}
/**
* Returns the message text for the given message id. Subclass in case different
* message text should be used for standard messages.
*
* @param messageId The message id. Must not be <code>null</code>.
* @return The message text.
*/
protected String getMessageForId(String messageId) {
Assert.isNotNull(messageId);
return Messages.getString(messageId);
}
/**
* Returns the message type for the given message id. Subclass in case different
* message types should by used for standard messages. The default implementation
* returns the proposed message type unchanged.
*
* @param messageId The message id. Must not be <code>null</code>.
* @param proposed The proposed message type.
* @return The message type for the given message id.
*/
protected int getMessageTypeForId(String messageId, int proposed) {
Assert.isNotNull(messageId);
return proposed;
}
/**
* Configures whether a selection is required or not.
*/
public void setRequireSelection(boolean value) {
requireSelection = value;
}
}