blob: 922d54113d9f4c544e1b7f9faabc1fa865507121 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.tools.event.spy.internal.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.e4.tools.event.spy.internal.model.CapturedEventFilter;
import org.eclipse.e4.tools.event.spy.internal.model.ItemToFilter;
import org.eclipse.e4.tools.event.spy.internal.model.Operator;
import org.eclipse.e4.tools.event.spy.internal.util.CapturedEventFilterSerializer;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolTip;
public class CapturedEventFilters {
private final static String NOT_SELECTED_VALUE = "-- expected value --";
public final static String BASE_EVENT_TOPIC = UIEvents.UITopicBase + UIEvents.TOPIC_SEP + UIEvents.ALL_SUB_TOPICS;
private final Composite control;
private Text valueText;
private Combo itemToFilterCombo;
private Combo operatorCombo;
private ToolTip validationErrorToolTip;
private Text baseTopicText;
// For bug 428903 : cache the text value for predestroy to avoid widget disposed exception.
private String baseTopicTextValue = BASE_EVENT_TOPIC;
private List filters;
private java.util.List<CapturedEventFilter> rawFilters;
private final Clipboard clipboard;
/* Layout scheme:
*
* +-- control --------------------------------------------+
* | +-- New filter group -------------------------------+ |
* | | | |
* | | Base topic of... |text|reset to default | |
* | | | |
* | | Capture event when|combo|combo|text|add filter | |
* | | | |
* | +---------------------------------------------------+ |
* | +-- Defined filter group ---------------------------+ |
* | | | |
* | | List | +-- composite -----------------+ | |
* | | | | remove selected | remove all | | |
* | | | +------------------------------+ | |
* | | | |
* | +---------------------------------------------------+ |
* +-------------------------------------------------------+
*
* */
//TODO: Fix layout data for groups
public CapturedEventFilters(Composite outer) {
control = new Composite(outer, SWT.NONE);
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.marginLeft = 0;
layout.fill = true;
control.setLayout(layout);
rawFilters = new ArrayList<CapturedEventFilter>();
clipboard = new Clipboard(control.getDisplay());
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (clipboard != null && !clipboard.isDisposed()) {
clipboard.dispose();
}
}
});
createNewFilterGroup(control);
createDefinedFiltersGroup(control);
}
private void createNewFilterGroup(Composite parent) {
Group newFilterGroup = new Group(parent, SWT.NONE);
newFilterGroup.setText("New filter:");
newFilterGroup.setLayout(new RowLayout(SWT.VERTICAL));
createBaseTopicSection(newFilterGroup);
createAddFilterSection(newFilterGroup);
}
private void createBaseTopicSection(Composite parent) {
parent = new Composite(parent, SWT.NONE);
parent.setLayout(new RowLayout(SWT.HORIZONTAL));
Label label = new Label(parent, SWT.CENTER);
label.setText("Base topic of captured events:");
baseTopicText = new Text(parent, SWT.BORDER);
baseTopicText.setLayoutData(new RowData(312, SWT.DEFAULT));
baseTopicText.setText(BASE_EVENT_TOPIC);
baseTopicText.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent e) {
if (baseTopicText.getText().trim().length() == 0) {
baseTopicText.setText(BASE_EVENT_TOPIC);
}
baseTopicTextValue = baseTopicText.getText();
}
});
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new RowLayout(SWT.HORIZONTAL));
Link link = new Link(composite, SWT.NONE);
link.setText("<a>Reset to default</a>");
link.addListener (SWT.Selection, new Listener() {
public void handleEvent(Event event) {
baseTopicText.setText(BASE_EVENT_TOPIC);
}
});
}
private void createAddFilterSection(Composite parent) {
parent = new Composite(parent, SWT.NONE);
parent.setLayout(new RowLayout(SWT.HORIZONTAL));
Label label = new Label(parent, SWT.CENTER);
label.setText("Capture event when:");
itemToFilterCombo = new Combo(parent, SWT.READ_ONLY);
for (ItemToFilter item: ItemToFilter.values()) {
itemToFilterCombo.add(item.toString());
}
itemToFilterCombo.select(0);
operatorCombo = new Combo(parent, SWT.READ_ONLY);
for (Operator operator: Operator.values()) {
operatorCombo.add(operator.toString());
}
operatorCombo.select(0);
valueText = new Text(parent, SWT.BORDER);
valueText.setLayoutData(new RowData(130, SWT.DEFAULT));
valueText.setText(NOT_SELECTED_VALUE);
valueText.addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
if (valueText.getText().trim().length() == 0) {
valueText.setText(NOT_SELECTED_VALUE);
}
}
public void focusGained(FocusEvent e) {
if (NOT_SELECTED_VALUE.equals(valueText.getText())) {
valueText.setText("");
}
}
});
Link link = new Link(parent, SWT.NONE);
link.setText("<a>Add filter</a>");
link.addListener (SWT.Selection, new Listener() {
public void handleEvent(Event event) {
addFilter();
}
});
}
private void createDefinedFiltersGroup(Composite parent) {
Group definedFiltersGroup = new Group(parent, SWT.NONE);
definedFiltersGroup.setText("Defined filters (relation between filters is AND):");
definedFiltersGroup.setLayout(new RowLayout(SWT.HORIZONTAL));
filters = new List(definedFiltersGroup, SWT.BORDER | SWT.V_SCROLL);
filters.setLayoutData(new RowData(450, 84));
filters.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
selectFilterAt(((List) e.widget).getSelectionIndex());
}
});
filters.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int index = ((List) e.widget).getSelectionIndex();
boolean ctrlPressed = (e.stateMask & SWT.CTRL) == SWT.CTRL;
if (ctrlPressed && e.keyCode == 'c') {
copyFilterAt(index);
e.doit = false;
} else if (ctrlPressed && e.keyCode == 'v') {
pasteFilterAt(index);
}
}
});
Composite composite = new Composite(definedFiltersGroup, SWT.NONE);
composite.setLayout(new RowLayout(SWT.VERTICAL));
Link link = new Link(composite, SWT.NONE);
link.setText("<a>Update selected</a>");
link.addListener (SWT.Selection, new Listener() {
public void handleEvent(Event event) {
updateFilterAt(filters.getSelectionIndex());
}
});
link = new Link(composite, SWT.NONE);
link.setText("<a>Remove selected</a>");
link.addListener (SWT.Selection, new Listener() {
public void handleEvent(Event event) {
removeFilterAt(filters.getSelectionIndex());
}
});
link = new Link(composite, SWT.NONE);
link.setText("<a>Remove all</a>");
link.addListener (SWT.Selection, new Listener() {
public void handleEvent(Event event) {
removeAllFilters();
}
});
}
public Control getControl() {
return control;
}
public void setFilters(Collection<CapturedEventFilter> filters) {
if (filters != null) {
for (CapturedEventFilter filter: filters) {
this.filters.add(filter.toString());
rawFilters.add(filter);
}
}
}
public Collection<CapturedEventFilter> getFilters() {
Map<Integer, CapturedEventFilter> result = new LinkedHashMap<Integer, CapturedEventFilter>();
for (CapturedEventFilter filter: rawFilters) {
result.put(filter.hashCode(), filter);
}
return result.values();
}
public void setBaseTopic(String baseTopic) {
if (baseTopic != null) {
baseTopicText.setText(baseTopic);
}
}
public String getBaseTopic() {
return baseTopicTextValue;
}
public boolean hasFilters() {
return !rawFilters.isEmpty();
}
public int getFiltersCount() {
return rawFilters.size();
}
private CapturedEventFilter createFilter() {
ItemToFilter selectedItemToFilter =
ItemToFilter.toItem(itemToFilterCombo.getItem(itemToFilterCombo.getSelectionIndex()));
if (ItemToFilter.NotSelected.equals(selectedItemToFilter)) {
getTooltip().setText(String.format("%s is not selected", getFieldName(ItemToFilter.NotSelected)));
getTooltip().setVisible(true);
return null;
}
Operator selectedOperator = Operator.toOperator(operatorCombo.getItem(operatorCombo.getSelectionIndex()));
if (Operator.NotSelected.equals(selectedOperator)) {
getTooltip().setText(String.format("%s is not selected", getFieldName(Operator.NotSelected)));
getTooltip().setVisible(true);
return null;
}
String value = valueText.getText();
if (value.length() == 0 || value.equals(NOT_SELECTED_VALUE)) {
getTooltip().setText(String.format("%s is empty", getFieldName(NOT_SELECTED_VALUE)));
getTooltip().setVisible(true);
return null;
}
try {
return new CapturedEventFilter(selectedItemToFilter, selectedOperator, value);
} catch(IllegalArgumentException exc) {
getTooltip().setText(exc.getMessage());
getTooltip().setVisible(true);
}
return null;
}
private ToolTip getTooltip() {
if (validationErrorToolTip == null) {
validationErrorToolTip = new ToolTip(Display.getCurrent().getActiveShell(), SWT.BALLOON | SWT.ICON_WARNING);
}
return validationErrorToolTip;
}
private void addFilter() {
addFilterAt(-1);
}
private void addFilterAt(int index) {
CapturedEventFilter eventFilter = createFilter();
if (eventFilter == null) {
return;
}
String filterAsString = eventFilter.toString();
if (index > -1 && index < rawFilters.size()) {
filters.add(filterAsString, index);
rawFilters.add(index, eventFilter);
} else {
filters.add(filterAsString);
rawFilters.add(eventFilter);
}
clearFilterDefinition();
}
private void removeFilterAt(int index) {
if (index < 0) {
getTooltip().setText("Filter to remove is not selected");
getTooltip().setVisible(true);
return;
}
filters.remove(index);
rawFilters.remove(index);
clearFilterDefinition();
}
private void selectFilterAt(int index) {
if (index > -1) {
CapturedEventFilter filter = rawFilters.get(index);
itemToFilterCombo.setText(filter.getItemToFilter().toString());
operatorCombo.setText(filter.getOperator().toString());
valueText.setText(filter.getValue());
}
}
private void updateFilterAt(int index) {
if (index < 0) {
getTooltip().setText("Filter to update is not selected");
getTooltip().setVisible(true);
return;
}
CapturedEventFilter newFilter = createFilter();
if (newFilter != null) {
CapturedEventFilter filter = rawFilters.get(index);
filter.setItemToFilter(newFilter.getItemToFilter());
filter.setOperator(newFilter.getOperator());
filter.setValue(newFilter.getValue());
filters.setItem(index, newFilter.toString());
}
}
private void copyFilterAt(int index) {
clipboard.setContents(new Object[] {CapturedEventFilterSerializer
.serialize(rawFilters.get(index))}, new Transfer[] {TextTransfer.getInstance()});
}
private void pasteFilterAt(int index) {
String pastedFilter = (String) clipboard.getContents(TextTransfer.getInstance());
CapturedEventFilter filter = CapturedEventFilterSerializer.deserialize(pastedFilter);
if (filter != null && index > -1 && index < filters.getItemCount()) {
filters.add(filter.toString(), index);
rawFilters.add(index, filter);
} else if (filter != null) {
filters.add(filter.toString());
rawFilters.add(filter);
}
}
private void removeAllFilters() {
if (rawFilters == null || rawFilters.isEmpty()) {
getTooltip().setText("Filter list is empty");
getTooltip().setVisible(true);
return;
}
filters.removeAll();
rawFilters.clear();
clearFilterDefinition();
}
private String getFieldName(Object notSelectedName) {
String fieldName = notSelectedName.toString().replaceAll("-", "").trim();
return Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
}
private void clearFilterDefinition() {
itemToFilterCombo.select(0);
operatorCombo.select(0);
valueText.setText(NOT_SELECTED_VALUE);
}
}