package rocks.inspectit.ui.rcp.ci.form.part.business; import java.util.Collections; import java.util.Set; import org.apache.commons.lang.ArrayUtils; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.action.ToolBarManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.forms.DetailsPart; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.MasterDetailsBlock; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import rocks.inspectit.shared.cs.ci.business.expression.AbstractExpression; import rocks.inspectit.shared.cs.ci.business.expression.IContainerExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.AndExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.BooleanExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.NotExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.OrExpression; import rocks.inspectit.shared.cs.ci.business.expression.impl.StringMatchingExpression; import rocks.inspectit.shared.cs.ci.business.impl.IMatchingRuleProvider; import rocks.inspectit.shared.cs.ci.business.valuesource.impl.HttpParameterValueSource; import rocks.inspectit.shared.cs.ci.business.valuesource.impl.MethodParameterValueSource; import rocks.inspectit.ui.rcp.InspectIT; import rocks.inspectit.ui.rcp.InspectITImages; import rocks.inspectit.ui.rcp.action.MenuAction; import rocks.inspectit.ui.rcp.ci.DirtyStateDelegatingManagedForm; import rocks.inspectit.ui.rcp.ci.form.part.business.MatchingRulesEditingElementFactory.BooleanExpressionType; import rocks.inspectit.ui.rcp.ci.form.part.business.MatchingRulesEditingElementFactory.IRulesExpressionType; import rocks.inspectit.ui.rcp.ci.form.part.business.MatchingRulesEditingElementFactory.MatchingRuleType; import rocks.inspectit.ui.rcp.ci.form.part.business.OperandTreeContentProvider.TreeInput; import rocks.inspectit.ui.rcp.ci.form.part.business.rules.AbstractRuleEditingElement; import rocks.inspectit.ui.rcp.ci.listener.IDetailsModifiedListener; import rocks.inspectit.ui.rcp.editor.viewers.StyledCellIndexLabelProvider; import rocks.inspectit.ui.rcp.util.RemoveSelection; import rocks.inspectit.ui.rcp.validation.AbstractValidationManager; import rocks.inspectit.ui.rcp.validation.IControlValidationListener; import rocks.inspectit.ui.rcp.validation.TreeItemControlDecorationManager; import rocks.inspectit.ui.rcp.validation.ValidationControlDecoration; import rocks.inspectit.ui.rcp.validation.ValidationState; /*** * * @author Alexander Wert * */ public class AdvancedMatchingRulesPart extends MasterDetailsBlock implements IMatchingRulesPart, ISelectionChangedListener, IDetailsModifiedListener<AbstractExpression> { /** * {@link IManagedForm} used for this master details block. We use a * {@link DirtyStateDelegatingManagedForm} instance as this {@link MasterDetailsBlock} is * embedded into another master details block, which would cause some problems with selections * when using the same managed form for both master details blocks. */ private IManagedForm managedForm; /** * Section control. */ private Section section; /** * Tree viewer for displaying the advanced expression tree. */ private TreeViewer treeViewer; /** * The root expression. */ private AbstractExpression rootExpression; /** * {@link MenuAction} providing a menu for expression creation. This action is used in the * toolbar (cannot be used in a context menu at the same time). */ private MenuAction createToolbarAction; /** * {@link MenuAction} providing a sub-menu for expression creation. This action is used in the * context menu (cannot be used in a toolbar at the same time). */ private MenuAction createContextMenuAction; /** * Action for removal of an expression. */ private RemoveExpressionAction removeAction; /** * Context menu manager. */ private MenuManager menuManager; /** * Toolbar manager. */ private ToolBarManager toolBarManager; /** * Label holding the description text. */ private Label descriptionLabel; /** * Indicates whether this form part is editable or not. */ private boolean editable; /** * Section title text. */ private final String title; /** * Dirty state. */ private boolean dirty = false; /** * Provider and receiver of the {@link AbstractExpression} instance edited in this form part. */ private IMatchingRuleProvider ruleProvider; /** * Validation manager that is responsible for showing control validation messages and delegating * these messages to parent UI elements. */ private final DelegatingValidationManager validationManager; /** * {@link TreeItemControlDecorationManager} instance for managin tree decorations. */ private final TreeItemControlDecorationManager treeControlDecorationManager = new TreeItemControlDecorationManager(); /** * Content provider for the tree. */ private final OperandTreeContentProvider treeContentProvider = new OperandTreeContentProvider(); /** * {@link ValidationControlDecoration} instance used to check whether at least one expression is * defined in the tree. */ private ValidationControlDecoration<Tree> treeValidation; /** * Constructor. * * @param title * The title of the section. * @param validationManager * {@link AbstractValidationManager} instance of the parent UI element to be notified * on validation state changes. */ public AdvancedMatchingRulesPart(String title, AbstractValidationManager<AbstractExpression> validationManager) { this.title = title; this.validationManager = new DelegatingValidationManager(validationManager); } /** * {@inheritDoc} */ @Override public void createContent(IManagedForm managedForm, Composite parent) { FormToolkit toolkit = managedForm.getToolkit(); section = toolkit.createSection(parent, Section.TITLE_BAR | Section.EXPANDED); section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); section.setText(title); descriptionLabel = toolkit.createLabel(section, ""); descriptionLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); section.setDescriptionControl(descriptionLabel); Composite main = toolkit.createComposite(section); main.setLayout(new GridLayout(1, false)); section.setClient(main); super.createContent(new DirtyStateDelegatingManagedForm(managedForm, section), main); } /** * {@inheritDoc} */ @Override protected void createMasterPart(IManagedForm managedForm, Composite parent) { this.managedForm = managedForm; sashForm.setOrientation(SWT.VERTICAL); FormToolkit toolkit = managedForm.getToolkit(); Composite masterMain = toolkit.createComposite(parent); masterMain.setLayout(new GridLayout(1, false)); Tree tree = toolkit.createTree(masterMain, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2)); treeViewer = new TreeViewer(tree); treeViewer.setContentProvider(treeContentProvider); treeViewer.setLabelProvider(new OperandLabelProvider()); treeViewer.addSelectionChangedListener(this); tree.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.DEL) { ISelection selection = treeViewer.getSelection(); if ((selection instanceof StructuredSelection) && !selection.isEmpty()) { AbstractExpression expression = (AbstractExpression) ((StructuredSelection) selection).getFirstElement(); deleteExpression(expression); } } } }); treeValidation = new ValidationControlDecoration<Tree>(tree, validationManager, false) { @Override protected boolean validate(Tree control) { if (ArrayUtils.isEmpty(control.getItems())) { return false; } else { for (TreeItem childItem : control.getItems()) { if (hasLeafElement(childItem)) { return true; } } return false; } } /** * Checks whether the given TreeItem contains a leaf node that is not a container * expression * * @param item * item to check * @return true, if the sub-tree under the given item contains a leaf node that is not a * container expression */ private boolean hasLeafElement(TreeItem item) { if (ArrayUtils.isEmpty(item.getItems()) && !(item.getData() instanceof IContainerExpression)) { return true; } else if (ArrayUtils.isNotEmpty(item.getItems())) { for (TreeItem childItem : item.getItems()) { if (hasLeafElement(childItem)) { return true; } } } return false; } }; treeValidation.setDescriptionText("At least one leaf expression must be defined!"); } /** * {@inheritDoc} */ @Override protected void registerPages(DetailsPart detailsPart) { this.detailsPart = detailsPart; detailsPart.registerPage(StringMatchingExpression.class, new AdvancedMatchingRulesDetails(this)); detailsPart.registerPage(BooleanExpression.class, new AdvancedMatchingRulesDetails(this)); } /** * {@inheritDoc} */ @Override protected void createToolBarActions(IManagedForm managedForm) { toolBarManager = new ToolBarManager(SWT.HORIZONTAL); createToolbarAction = new MenuAction("Add", InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_ADD)); createToolbarAction.setEnabled(false); createContextMenuAction = new MenuAction("Add", InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_ADD)); createContextMenuAction.setEnabled(false); for (BooleanExpressionType boolenExprType : BooleanExpressionType.values()) { createToolbarAction.addAction(new CreateExpressionAction(boolenExprType)); createContextMenuAction.addAction(new CreateExpressionAction(boolenExprType)); } createToolbarAction.addContributionItem(new Separator()); createContextMenuAction.addContributionItem(new Separator()); for (MatchingRuleType matchingRuleType : MatchingRuleType.values()) { createToolbarAction.addAction(new CreateExpressionAction(matchingRuleType)); createContextMenuAction.addAction(new CreateExpressionAction(matchingRuleType)); } removeAction = new RemoveExpressionAction(); removeAction.setEnabled(false); toolBarManager.add(removeAction); toolBarManager.add(createToolbarAction); ToolBar toolbar = toolBarManager.createControl(section); section.setTextClient(toolbar); toolBarManager.update(true); createToolbarAction.setRunTask(new MenuAction.ToolbarDropDownTask(toolbar)); menuManager = new MenuManager(); menuManager.add(createContextMenuAction); menuManager.add(removeAction); Control control = treeViewer.getControl(); Menu menu = menuManager.createContextMenu(control); control.setMenu(menu); menuManager.update(); } /** * {@inheritDoc} */ @Override public void initContent(IMatchingRuleProvider ruleProvider) { this.ruleProvider = ruleProvider; ISelection selection = treeViewer.getSelection(); setTreeInput(ruleProvider.getMatchingRuleExpression()); treeViewer.setSelection(selection); resizeColumns(); treeValidation.executeValidation(true); } /** * {@inheritDoc} */ @Override public void initialize(IManagedForm form) { } /** * {@inheritDoc} */ @Override public void dispose() { section.dispose(); } /** * {@inheritDoc} */ @Override public boolean isDirty() { return dirty; } /** * {@inheritDoc} */ @Override public void commit(boolean onSave) { if (onSave) { dirty = false; } if (null != ruleProvider) { AbstractExpression expression = constructMatchingRuleExpression(); ruleProvider.setMatchingRuleExpression(expression); } } /** * {@inheritDoc} */ @Override public boolean setFormInput(Object input) { if (input instanceof AbstractExpression) { rootExpression = (AbstractExpression) input; } return true; } /** * {@inheritDoc} */ @Override public void setFocus() { treeViewer.getTree().setFocus(); } /** * {@inheritDoc} */ @Override public boolean isStale() { return false; } /** * {@inheritDoc} */ @Override public void refresh() { treeViewer.refresh(true); resizeColumns(); } /** * {@inheritDoc} */ @Override public void setDescriptionText(String description) { descriptionLabel.setText(description); section.layout(true); } /** * {@inheritDoc} */ @Override public void markDirty() { if (!dirty) { dirty = true; managedForm.dirtyStateChanged(); } } /** * {@inheritDoc} */ @Override public Control getControl() { return section; } /** * {@inheritDoc} */ @Override public ToolBarManager getToolbarManager() { return toolBarManager; } /** * {@inheritDoc} */ @Override public void selectionChanged(SelectionChangedEvent event) { if (event.getSelection() instanceof StructuredSelection) { StructuredSelection selection = (StructuredSelection) event.getSelection(); if (selection.isEmpty() && (null == rootExpression)) { createToolbarAction.setEnabled(true); createContextMenuAction.setEnabled(true); removeAction.setEnabled(false); } else if (selection.isEmpty() && (null != rootExpression)) { createToolbarAction.setEnabled(false); createContextMenuAction.setEnabled(false); removeAction.setEnabled(false); } else if (!selection.isEmpty()) { AbstractExpression expression = (AbstractExpression) selection.getFirstElement(); boolean createEnabled = (expression instanceof IContainerExpression) && ((IContainerExpression) expression).canAddOperand(); createToolbarAction.setEnabled(createEnabled); createContextMenuAction.setEnabled(createEnabled); removeAction.setEnabled(true); } managedForm.fireSelectionChanged(this, selection); menuManager.update(true); toolBarManager.update(true); } } /** * Gets {@link #editable}. * * @return {@link #editable} */ public boolean isEditable() { return editable; } /** * Sets {@link #editable}. * * @param editable * New value for {@link #editable} */ @Override public void setEditable(boolean editable) { this.editable = editable; setEnabledState(); } /** * {@inheritDoc} */ @Override public void contentModified(AbstractExpression modifiedElement) { contentChanged(); } /** * Gets {@link #validationManager}. * * @return {@link #validationManager} */ public AbstractValidationManager<AbstractExpression> getValidationManager() { return validationManager; } /** * Refreshes the contents of this part. */ private void contentChanged() { treeViewer.refresh(true); resizeColumns(); markDirty(); commit(false); } /** * Sets the tree input and performs a validation. * * @param expression * {@link AbstractExpression} to be used for the tree input. */ private void setTreeInput(AbstractExpression expression) { this.rootExpression = expression; treeViewer.setInput(new TreeInput(expression)); if (null != treeValidation) { treeValidation.executeValidation(); } treeViewer.expandAll(); performInitialValidation(rootExpression); } /** * Constructs a {@link AbstractExpression} instance from the contents of this element controls. * * @return Returns a {@link AbstractExpression} instance. */ private AbstractExpression constructMatchingRuleExpression() { AbstractExpression expression = (null == rootExpression) ? new BooleanExpression(false) : rootExpression; expression.setAdvanced(true); return expression; } /** * */ private void resizeColumns() { for (TreeColumn column : treeViewer.getTree().getColumns()) { column.pack(); } } /** * Adds the given {@link AbstractExpression} instance as a child to the currently selected * expression, if possible. If no expression is selected, then the passed * {@link AbstractExpression} instance is inserted as root. * * @param expression * {@link AbstractExpression} to add. */ private void addExpression(AbstractExpression expression) { ISelection selection = treeViewer.getSelection(); if ((selection instanceof StructuredSelection) && !selection.isEmpty()) { AbstractExpression parentExpression = (AbstractExpression) ((StructuredSelection) selection).getFirstElement(); if (parentExpression instanceof IContainerExpression) { ((IContainerExpression) parentExpression).addOperand(expression); } setTreeInput(rootExpression); treeViewer.expandToLevel(expression, 0); treeViewer.setSelection(new StructuredSelection(expression), true); treeValidation.executeValidation(); } else { setTreeInput(expression); contentChanged(); treeViewer.setSelection(new StructuredSelection(rootExpression), true); } contentChanged(); } /** * Removes the given expression from expression tree. * * @param expression * {@link AbstractExpression} instance to delete. */ private void deleteExpression(AbstractExpression expression) { Object parentExpression = treeContentProvider.getParent(expression); if (null == parentExpression) { setTreeInput(null); } else if (parentExpression instanceof IContainerExpression) { ((IContainerExpression) parentExpression).removeOperand(expression); setTreeInput(rootExpression); treeViewer.setSelection(new StructuredSelection(parentExpression), true); } RemoveSelection removeSelection = new RemoveSelection(Collections.singletonList(expression)); managedForm.fireSelectionChanged(this, removeSelection); // notify validation registry to update validation decorations and validation messages due // to the removal of this expression validationManager.validationStatesRemoved(expression); contentChanged(); } /** * Sets the enabled state of this part. */ private void setEnabledState() { toolBarManager.getControl().setEnabled(isEditable()); treeViewer.getControl().getMenu().setEnabled(isEditable()); treeViewer.getTree().setEnabled(isEditable()); } /** * Performs initial validation of the tree elements without the need to create corresponding * editing controls. * * @param expression * {@link AbstractExpression} instance to validate. */ private void performInitialValidation(AbstractExpression expression) { if (expression instanceof IContainerExpression) { for (AbstractExpression child : ((IContainerExpression) expression).getOperands()) { performInitialValidation(child); } } else if (expression instanceof StringMatchingExpression) { Set<ValidationState> validationStates = AbstractRuleEditingElement.validate((StringMatchingExpression) expression); for (ValidationState state : validationStates) { validationManager.validationStateChanged(expression, state); } } } /** * Label provider for the tree viewer that displays the expression tree. * * @author Alexander Wert * */ private static final class OperandLabelProvider extends StyledCellIndexLabelProvider { /** * {@inheritDoc} */ @Override protected StyledString getStyledText(Object element, int index) { StyledString styledString = new StyledString(); if (element instanceof AndExpression) { styledString.append("AND"); styledString.append(" (" + ((AndExpression) element).getNumberOfChildExpressions() + ")", StyledString.QUALIFIER_STYLER); } else if (element instanceof OrExpression) { styledString.append("OR"); styledString.append(" (" + ((OrExpression) element).getNumberOfChildExpressions() + ")", StyledString.QUALIFIER_STYLER); } else if (element instanceof NotExpression) { styledString.append("NOT"); } else if (element instanceof BooleanExpression) { styledString.append("Boolean"); styledString.append(" (" + ((BooleanExpression) element).isValue() + ")", StyledString.QUALIFIER_STYLER); } else if (element instanceof StringMatchingExpression) { StringMatchingExpression stringMatchingExpression = (StringMatchingExpression) element; MatchingRuleType type = MatchingRulesEditingElementFactory.getMatchingRuleType(stringMatchingExpression); styledString.append(type.toString()); switch (type) { case HTTP_PARAMETER: styledString.append(" (Parameter \"" + ((HttpParameterValueSource) stringMatchingExpression.getStringValueSource()).getParameterName() + "\" " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_URL: styledString.append(" (URL " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_SCHEME: styledString.append(" (Scheme " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_SERVER_NAME: styledString.append(" (Server name " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_SERVER_PORT: styledString.append(" (Server port " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_URI: styledString.append(" (URI " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case HTTP_QUERY_STRING: styledString.append(" (Query string " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case IP: styledString.append(" (IP " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case METHOD_SIGNATURE: styledString.append(" (Method signature " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; case METHOD_PARAMETER: String methodSignature = ((MethodParameterValueSource) stringMatchingExpression.getStringValueSource()).getMethodSignature(); int startFromIndex = methodSignature.lastIndexOf('.', methodSignature.indexOf('(')); String method = methodSignature.substring(startFromIndex + 1); int parameterIndex = ((MethodParameterValueSource) stringMatchingExpression.getStringValueSource()).getParameterIndex(); styledString.append(" (Parameter " + parameterIndex + " of method \"" + method + "\" " + stringMatchingExpression.getMatchingType().toString() + " \"" + stringMatchingExpression.getSnippet() + "\")", StyledString.QUALIFIER_STYLER); break; default: break; } } return styledString; } /** * {@inheritDoc} */ @Override protected Image getColumnImage(Object element, int index) { if (element instanceof AbstractExpression) { String imageKey = MatchingRulesEditingElementFactory.getRulesExpressionType((AbstractExpression) element).getImageKey(); return InspectIT.getDefault().getImage(imageKey); } return super.getColumnImage(element, index); } } /** * This action creates an expression depending on the type of {@link BooleanExpressionType} or * {@link MatchingRuleType}. * * @author Alexander Wert * */ private class CreateExpressionAction extends Action { /** * {@link IRulesExpressionType}. */ private final IRulesExpressionType type; /** * Constructor. * * @param type * {@link IRulesExpressionType} describing which type of expression to create. */ CreateExpressionAction(IRulesExpressionType type) { this.type = type; setImageDescriptor(InspectIT.getDefault().getImageDescriptor(type.getImageKey())); setText(type.toString()); } @Override public void run() { AbstractExpression expression = MatchingRulesEditingElementFactory.createExpression(type); addExpression(expression); } } /** * This action removes an expression from the expression tree. * * @author Alexander Wert * */ private class RemoveExpressionAction extends Action { /** * Constructor. */ RemoveExpressionAction() { setImageDescriptor(InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_DELETE)); setText("Delete (DEL)"); } @Override public void run() { ISelection selection = treeViewer.getSelection(); if ((selection instanceof StructuredSelection) && !selection.isEmpty()) { final AbstractExpression expression = (AbstractExpression) ((StructuredSelection) selection).getFirstElement(); deleteExpression(expression); } } } /** * This class is an implementation of the {@link AbstractValidationManager} that delegates * changes directly to a parent {@link AbstractValidationManager} instance and in addition shows * validation messages in the tree viewer. * * @author Alexander Wert * */ private class DelegatingValidationManager extends AbstractValidationManager<AbstractExpression> implements IControlValidationListener { /** * The {@link AbstractValidationManager} instance to delegate validation state changes to. */ private final AbstractValidationManager<AbstractExpression> delegateTo; /** * Constructor. * * @param delegateTo * the {@link AbstractValidationManager} instance to delegate validation state * changes to. */ DelegatingValidationManager(AbstractValidationManager<AbstractExpression> delegateTo) { this.delegateTo = delegateTo; } /** * {@inheritDoc} */ @Override public void validationStateChanged(AbstractExpression key, ValidationState newState) { if (null != delegateTo) { delegateTo.validationStateChanged(key, newState); } super.validationStateChanged(key, newState); } /** * {@inheritDoc} */ @Override public void validationStatesRemoved(AbstractExpression expression) { if (expression instanceof IContainerExpression) { for (AbstractExpression child : ((IContainerExpression) expression).getOperands()) { validationStatesRemoved(child); } } else { super.validationStatesRemoved(expression); if (null != delegateTo) { delegateTo.validationStatesRemoved(expression); } } } /** * {@inheritDoc} */ @Override protected void notifyUpstream(AbstractExpression expression, Set<ValidationState> states) { // nothing to do here } /** * {@inheritDoc} */ @Override protected void showMessage(AbstractExpression expression, Set<ValidationState> states) { String message = ""; for (ValidationState state : states) { message += state.getMessage() + "\n"; } treeControlDecorationManager.showTreeItemControlDecoration(treeViewer, expression, message); } /** * {@inheritDoc} */ @Override protected void hideMessage(AbstractExpression expression) { treeControlDecorationManager.hideTreeItemControlDecoration(treeViewer, expression); } /** * {@inheritDoc} */ @Override public void validationStateChanged(boolean valid, ValidationControlDecoration<?> validationControlDecoration) { if (null != delegateTo) { delegateTo.validationStateChanged(MatchingRulesEditingElementFactory.InvalidExpression.getInstance(), new ValidationState("emptyTree", valid, validationControlDecoration.getDescriptionText())); } } } }