package rocks.inspectit.ui.rcp.ci.form.part.business;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.ToolBar;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.SectionPart;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import rocks.inspectit.shared.cs.ci.business.expression.AbstractExpression;
import rocks.inspectit.shared.cs.ci.business.expression.impl.BooleanExpression;
import rocks.inspectit.shared.cs.ci.business.expression.impl.OrExpression;
import rocks.inspectit.shared.cs.ci.business.impl.IMatchingRuleProvider;
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.form.part.business.MatchingRulesEditingElementFactory.MatchingRuleType;
import rocks.inspectit.ui.rcp.ci.form.part.business.rules.AbstractRuleEditingElement;
import rocks.inspectit.ui.rcp.ci.listener.IDetailsModifiedListener;
import rocks.inspectit.ui.rcp.validation.AbstractValidationManager;
import rocks.inspectit.ui.rcp.validation.IControlValidationListener;
import rocks.inspectit.ui.rcp.validation.ValidationControlDecoration;
import rocks.inspectit.ui.rcp.validation.ValidationState;
/**
* Composite element for matching rules viewing, creation and modification.
*
* @author Alexander Wert
*
*/
public class SimpleMatchingRulesPart extends SectionPart implements IMatchingRulesPart, IControlValidationListener {
/**
* Checks whether the passed {@link AbstractExpression} can be displayed by the
* {@link SimpleMatchingRulesPart}.
*
* @param expression
* {@link AbstractExpression} instance to check.
* @return true, if {@link SimpleMatchingRulesPart} can display the passed
* {@link AbstractExpression} instance.
*/
public static boolean canShowRule(AbstractExpression expression) {
if (expression instanceof OrExpression) {
for (AbstractExpression childExpression : ((OrExpression) expression).getOperands()) {
try {
MatchingRulesEditingElementFactory.getMatchingRuleType(childExpression);
} catch (IllegalArgumentException e) {
return false;
}
}
return true;
}
return false;
}
/**
* List of {@link AbstractRuleEditingElement} comprised in this element.
*/
private final List<AbstractRuleEditingElement<?>> ruleElements = new ArrayList<AbstractRuleEditingElement<?>>();
/**
* Main {@link Composite} of this element.
*/
private Composite main;
/**
* Indicates whether this element is in the initialization phase.
*/
private boolean initializationPhase = false;
/**
* Label holding the description text.
*/
private Label descriptionLabel;
/**
* Indicates whether this form part is editable or not.
*/
private boolean editable;
/**
* The toolbar manager used in this part.
*/
private ToolBarManager toolBarManager;
/**
* Title of the section.
*/
private final String title;
/**
* Provider and receiver of the {@link AbstractExpression} instance edited in this form part.
*/
private IMatchingRuleProvider ruleProvider;
/**
* The upstream validation manager.
*/
private final AbstractValidationManager<AbstractExpression> validationManager;
/**
* {@link ValidationControlDecoration} instance used to check whether at least one expression is
* defined in the list.
*/
private ValidationControlDecoration<Label> listValidation;
/**
* Constructor.
*
* @param title
* The title of the section.
* @param parent
* parent {@link Composite}.
* @param managedForm
* the {@link IManagedForm} to add this part to.
* @param validationManager
* {@link AbstractValidationManager} instance to be notified on validation state
* changes.
*/
public SimpleMatchingRulesPart(String title, Composite parent, IManagedForm managedForm, AbstractValidationManager<AbstractExpression> validationManager) {
super(parent, managedForm.getToolkit(), Section.TITLE_BAR | Section.EXPANDED);
this.title = title;
this.validationManager = validationManager;
}
/**
* {@inheritDoc}
*/
@Override
public void createContent(IManagedForm managedForm, Composite parent) {
this.getSection().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
FormToolkit toolkit = managedForm.getToolkit();
getSection().setText(title);
ScrolledForm form = toolkit.createScrolledForm(getSection());
form.setLayout(new GridLayout(1, false));
form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
main = form.getBody();
main.setBackground(parent.getBackground());
GridLayout layout = new GridLayout(AbstractRuleEditingElement.NUM_GRID_COLUMNS, false);
layout.horizontalSpacing = 8;
main.setLayout(layout);
main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
toolkit.decorateFormHeading(form.getForm());
getSection().setClient(form);
descriptionLabel = toolkit.createLabel(getSection(), "");
descriptionLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
getSection().setDescriptionControl(descriptionLabel);
createToolbar();
updateEnabledState();
listValidation = new ValidationControlDecoration<Label>(descriptionLabel, this, false) {
@Override
protected boolean validate(Label control) {
return !ruleElements.isEmpty();
}
};
listValidation.setDescriptionText("At least one rule expression must be defined!");
}
/**
*
* {@inheritDoc}
*/
@Override
public void initContent(IMatchingRuleProvider ruleProvider) {
initializationPhase = true;
this.ruleProvider = ruleProvider;
reset();
AbstractExpression matchingRuleExpression = ruleProvider.getMatchingRuleExpression();
if (canShowRule(matchingRuleExpression)) {
for (AbstractExpression expression : ((OrExpression) matchingRuleExpression).getOperands()) {
addNewRuleEditingElement(expression);
}
}
main.layout(true, true);
initializationPhase = false;
listValidation.executeValidation(true);
}
/**
* Sets the description text for this section.
*
* @param description
* new description text.
*/
@Override
public void setDescriptionText(String description) {
descriptionLabel.setText(description);
getSection().layout(true);
}
/**
* {@inheritDoc}
*/
@Override
public Control getControl() {
return getSection();
}
/**
* {@inheritDoc}
*/
@Override
public ToolBarManager getToolbarManager() {
return toolBarManager;
}
/**
* {@inheritDoc}
*/
@Override
public void commit(boolean onSave) {
if (null != ruleProvider) {
AbstractExpression expression = constructMatchingRuleExpression();
ruleProvider.setMatchingRuleExpression(expression);
}
if (onSave) {
super.commit(onSave);
}
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
getManagedForm().removePart(this);
getSection().dispose();
}
/**
* 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;
updateEnabledState();
}
/**
* {@inheritDoc}
*/
@Override
public void validationStateChanged(boolean valid, ValidationControlDecoration<?> validationControlDecoration) {
validationManager.validationStateChanged(MatchingRulesEditingElementFactory.InvalidExpression.getInstance(),
new ValidationState("emptyList", valid, validationControlDecoration.getDescriptionText()));
}
/**
* Constructs a {@link AbstractExpression} instance from the contents of this element controls.
*
* @return Returns a {@link AbstractExpression} instance.
*/
private AbstractExpression constructMatchingRuleExpression() {
List<AbstractExpression> activeExpressions = new ArrayList<AbstractExpression>();
for (AbstractRuleEditingElement<?> ruleComposite : ruleElements) {
AbstractExpression expression = ruleComposite.getExpression();
if (null != expression) {
activeExpressions.add(expression);
}
}
AbstractExpression matchingRuleExpression = null;
if (!activeExpressions.isEmpty()) {
AbstractExpression[] expressions = new AbstractExpression[activeExpressions.size()];
activeExpressions.toArray(expressions);
matchingRuleExpression = new OrExpression(expressions);
}
if (null == matchingRuleExpression) {
matchingRuleExpression = new BooleanExpression(false);
}
matchingRuleExpression.setAdvanced(false);
return matchingRuleExpression;
}
/**
* Sets the enabled state of this part.
*/
private void updateEnabledState() {
if (null != toolBarManager) {
toolBarManager.getControl().setEnabled(isEditable());
}
}
/**
* Creates tool bar for creation of new rules.
*
*/
private void createToolbar() {
MenuAction createNewRuleMenu = new MenuAction();
createNewRuleMenu.setImageDescriptor(InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_ADD));
createNewRuleMenu.setToolTipText("Add new rule");
for (MatchingRuleType type : MatchingRuleType.values()) {
createNewRuleMenu.addAction(new AddMatchingRuleCompositeAction(type));
}
toolBarManager = new ToolBarManager();
final ToolBar toolbar = toolBarManager.createControl(getSection());
toolBarManager.add(createNewRuleMenu);
toolBarManager.update(true);
createNewRuleMenu.setRunTask(new MenuAction.ToolbarDropDownTask(toolbar));
getSection().setTextClient(toolbar);
}
/**
* Resets the contents of the controls within this part.
*/
private void reset() {
for (AbstractRuleEditingElement<?> ruleElement : ruleElements) {
ruleElement.dispose();
}
ruleElements.clear();
}
/**
* Adds a new rule editing element to this composite element.
*
* @param expression
* {@link AbstractExpression} instance to add.
*/
private void addNewRuleEditingElement(AbstractExpression expression) {
AbstractRuleEditingElement<?> ruleComposite = MatchingRulesEditingElementFactory.createRuleComposite(expression, isEditable(), validationManager);
ruleElements.add(ruleComposite);
listValidation.executeValidation();
commit(false);
ruleComposite.createControls(main, getManagedForm().getToolkit(), true);
ruleComposite.addModifyListener(new IDetailsModifiedListener<AbstractExpression>() {
@Override
public void contentModified(AbstractExpression modifiedElement) {
commit(false);
markDirty();
}
});
ruleComposite.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent event) {
if ((event.data instanceof AbstractRuleEditingElement) && !initializationPhase) {
ruleElements.remove(event.data);
listValidation.executeValidation();
main.layout(true, true);
ruleProvider.setMatchingRuleExpression(constructMatchingRuleExpression());
markDirty();
}
}
});
main.layout(true, true);
ruleComposite.initialize();
if (!initializationPhase) {
markDirty();
}
}
/**
* This action adds a new {@link AbstractRuleEditingElement} instance depending on the
* {@link MatchingRuleType} type.
*
* @author Alexander Wert
*
*/
private class AddMatchingRuleCompositeAction extends Action {
/**
* {@link MatchingRuleType}.
*/
private final MatchingRuleType type;
/**
* Default constructor.
*
* @param type
* {@link MatchingRuleType}
*/
AddMatchingRuleCompositeAction(MatchingRuleType type) {
this.type = type;
setText(type.toString());
setImageDescriptor(InspectIT.getDefault().getImageDescriptor(type.getImageKey()));
}
@Override
public void run() {
addNewRuleEditingElement(MatchingRulesEditingElementFactory.createExpression(type));
}
}
}