diff options
Diffstat (limited to 'bundles/org.eclipse.e4.tools.event.spy')
29 files changed, 1881 insertions, 0 deletions
diff --git a/bundles/org.eclipse.e4.tools.event.spy/.classpath b/bundles/org.eclipse.e4.tools.event.spy/.classpath new file mode 100644 index 00000000..64c5e31b --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.e4.tools.event.spy/.project b/bundles/org.eclipse.e4.tools.event.spy/.project new file mode 100644 index 00000000..d26d07f7 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.e4.tools.event.spy</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.e4.tools.event.spy/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.tools.event.spy/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..af0f20f9 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/bundles/org.eclipse.e4.tools.event.spy/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.tools.event.spy/META-INF/MANIFEST.MF new file mode 100644 index 00000000..8b49e598 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-SymbolicName: org.eclipse.e4.tools.event.spy;singleton:=true +Bundle-Version: 0.15.0.qualifier +Bundle-Vendor: %Bundle-Vendor +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.e4.core.di;bundle-version="1.3.0", + org.eclipse.e4.ui.workbench, + org.eclipse.e4.core.contexts;bundle-version="1.3.0", + org.eclipse.e4.ui.model.workbench;bundle-version="1.0.0", + org.eclipse.e4.core.services;bundle-version="1.1.0", + javax.inject;bundle-version="1.0.0", + org.eclipse.e4.ui.bindings;bundle-version="0.10.100", + org.eclipse.core.resources;bundle-version="3.8.100", + org.eclipse.jdt.core;bundle-version="3.9.0", + org.eclipse.jdt.ui;bundle-version="3.9.0", + org.eclipse.pde.core;bundle-version="3.9.0", + org.eclipse.pde.ui;bundle-version="3.8.0", + org.eclipse.pde.runtime;bundle-version="3.4.400", + org.eclipse.osgi.services;bundle-version="3.3.100", + org.eclipse.e4.ui.services;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-ActivationPolicy: lazy +Import-Package: javax.annotation;version="1.1.0" diff --git a/bundles/org.eclipse.e4.tools.event.spy/build.properties b/bundles/org.eclipse.e4.tools.event.spy/build.properties new file mode 100644 index 00000000..e9863e28 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/bundles/org.eclipse.e4.tools.event.spy/plugin.xml b/bundles/org.eclipse.e4.tools.event.spy/plugin.xml new file mode 100644 index 00000000..e9395f19 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/plugin.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.4"?> +<plugin> + <extension + id="org.eclipse.e4.tools.event.spy" + name="E4 Event spy" + point="org.eclipse.e4.workbench.model"> + <processor + beforefragment="false" + class="org.eclipse.e4.tools.event.spy.Installer"> + </processor> + </extension> + +</plugin> diff --git a/bundles/org.eclipse.e4.tools.event.spy/pom.xml b/bundles/org.eclipse.e4.tools.event.spy/pom.xml new file mode 100644 index 00000000..84fb6caf --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/pom.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.e4.tools</groupId> + <artifactId>e4-tools-aggregator</artifactId> + <version>0.15.0-SNAPSHOT</version> + <relativePath>../../</relativePath> + </parent> + + <groupId>org.eclipse.e4</groupId> + <artifactId>org.eclipse.e4.tools.event.spy</artifactId> + <version>0.15.0.qualifier</version> + <packaging>eclipse-plugin</packaging> + +</project> diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/BindingDescriptor.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/BindingDescriptor.java new file mode 100644 index 00000000..a24513c1 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/BindingDescriptor.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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; + +public enum BindingDescriptor { + OpenSpyDialogInDialogAndWindow("M2+M3+F8", "org.eclipse.ui.contexts.dialogAndWindow"); + + private String bindingContextId; + + private String keySequence; + + private BindingDescriptor(String keySequence, String bindingContextId) { + this.keySequence = keySequence; + this.bindingContextId = bindingContextId; + } + + public String getBindingContextId() { + return bindingContextId; + } + + public String getKeySequence() { + return keySequence; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/CommandDescriptor.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/CommandDescriptor.java new file mode 100644 index 00000000..866ddf47 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/CommandDescriptor.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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; + +public enum CommandDescriptor { + OpenSpyDialog("org.eclipse.e4.tools.event.spy.openSpyDialog.cmd", "Open event spy dialog"); + + private String id; + + private String name; + + private CommandDescriptor(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Constants.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Constants.java new file mode 100644 index 00000000..61c8a3e2 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Constants.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * 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; + +import org.eclipse.e4.tools.event.spy.util.PluginUtils; +import org.eclipse.e4.ui.bindings.EBindingService; + +public class Constants { + public static final String PLUGIN_ID = PluginUtils.getBundleId(Constants.class); + + public static final String BINDING_MODIFIED_BY_USER_TAG = EBindingService.TYPE_ATTR_TAG + ":user"; + + public static final String BINDING_DELETED_BY_USER_TAG = EBindingService.DELETED_BINDING_TAG; +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Installer.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Installer.java new file mode 100644 index 00000000..d175ba4b --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/Installer.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * 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; + + +import javax.inject.Inject; + +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.tools.event.spy.handlers.OpenSpyDialogHandler; +import org.eclipse.e4.tools.event.spy.util.LoggerWrapper; +import org.eclipse.e4.tools.event.spy.util.PluginUtils; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.commands.MBindingTable; +import org.eclipse.e4.ui.model.application.commands.MCommand; +import org.eclipse.e4.ui.model.application.commands.MCommandsFactory; +import org.eclipse.e4.ui.model.application.commands.MHandler; +import org.eclipse.e4.ui.model.application.commands.MKeyBinding; + +@SuppressWarnings("restriction") +public class Installer { + @Inject + private MApplication application; + + @Inject + private LoggerWrapper logger; + + @Execute + public void execute() { + logger.info("installing ..."); + + registerCommand(CommandDescriptor.OpenSpyDialog, BindingDescriptor.OpenSpyDialogInDialogAndWindow, OpenSpyDialogHandler.class); + + logger.info("installed"); + } + + private void registerCommand(CommandDescriptor commandDesc, BindingDescriptor bindingDesc, Class<?> handlerCls) { + MCommand command = getCommand(application, commandDesc); + if (command == null) { + command = createCommand(commandDesc); + application.getCommands().add(command); + } + + Object binding = getBindingOrBindingTable(application, command, bindingDesc); + if (binding == null) { + logger.warn("binding context ''{0}'' for command ''{1}'' not found", + bindingDesc.getBindingContextId(), commandDesc.getName()); + return; + } + + if (binding instanceof MKeyBinding) { + MKeyBinding keyBinding = (MKeyBinding) binding; + if (keyBinding.getTags().contains(Constants.BINDING_MODIFIED_BY_USER_TAG)) { + logger.info("key binding for command ''{0}'' changed to {1}", commandDesc.getName(), keyBinding.getKeySequence()); + + } else if (keyBinding.getTags().contains(Constants.BINDING_DELETED_BY_USER_TAG)) { + logger.info("key binding for command ''{0}'' has been deleted. The command is disabled", commandDesc.getName()); + } + return; //command already processed + } + + ((MBindingTable) binding).getBindings().add(createKeyBinding(command, bindingDesc)); + logger.info("key binding for command ''{0}'' is {1}", commandDesc.getName(), bindingDesc.getKeySequence()); + + MHandler handler = getHandler(application, commandDesc); + if (handler == null) { + handler = createHandler(command, handlerCls); + application.getHandlers().add(handler); + } + } + + private MCommand getCommand(MApplication application, CommandDescriptor descriptor) { + for (MCommand command: application.getCommands()) { + if (descriptor.getId().equals(command.getElementId())) { + return command; + } + } + return null; + } + + private MCommand createCommand(CommandDescriptor descriptor) { + MCommand command = MCommandsFactory.INSTANCE.createCommand(); + command.setElementId(descriptor.getId()); + command.setCommandName(descriptor.getName()); + command.setContributorURI(PluginUtils.getContributorURI()); + return command; + } + + private MHandler getHandler(MApplication application, CommandDescriptor descriptor) { + for (MHandler handler: application.getHandlers()) { + if (descriptor.getId().equals(handler.getElementId())) { + return handler; + } + } + return null; + } + + private MHandler createHandler(MCommand command, Class<?> handlerCls) { + MHandler handler = MCommandsFactory.INSTANCE.createHandler(); + handler.setElementId(command.getElementId()); + handler.setCommand(command); + handler.setContributionURI(PluginUtils.getContributionURI(handlerCls)); + handler.setContributorURI(PluginUtils.getContributorURI()); + return handler; + } + + private Object getBindingOrBindingTable(MApplication application, MCommand command, BindingDescriptor descriptor) { + MBindingTable result = null; + for (MBindingTable bindingTable: application.getBindingTables()) { + for (MKeyBinding keyBinding : bindingTable.getBindings()) { + if (keyBinding.getCommand() == command) { + return bindingTable; + } + } + if (descriptor.getBindingContextId().equals(bindingTable.getBindingContext().getElementId())) { + result = bindingTable; + } + } + return result; + } + + private MKeyBinding createKeyBinding(MCommand command, BindingDescriptor descriptor) { + MKeyBinding keyBinding = MCommandsFactory.INSTANCE.createKeyBinding(); + keyBinding.setElementId(command.getElementId()); + keyBinding.setCommand(command); + keyBinding.setKeySequence(descriptor.getKeySequence()); + keyBinding.setContributorURI(PluginUtils.getContributorURI()); + return keyBinding; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/CapturedEventFilterMatcher.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/CapturedEventFilterMatcher.java new file mode 100644 index 00000000..a360cd33 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/CapturedEventFilterMatcher.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * 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.core; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.e4.tools.event.spy.model.CapturedEvent; +import org.eclipse.e4.tools.event.spy.model.CapturedEventFilter; +import org.eclipse.e4.tools.event.spy.model.ItemToFilter; +import org.eclipse.e4.tools.event.spy.model.Operator; +import org.eclipse.e4.tools.event.spy.model.Parameter; +import org.eclipse.e4.tools.event.spy.model.SpecialValue; + +public class CapturedEventFilterMatcher { + public boolean matches(CapturedEvent event, CapturedEventFilter filter) { + Object value = getItemToFilterValue(event, filter.getItemToFilter()); + + if (value instanceof List) { + List<?> list = (List<?>) value; + for (Object item: list) { + if (matches(filter.getValue(), item, filter.getOperator())) { + return true; + } + } + return false; + } + return matches(filter.getValue(), value, filter.getOperator()); + } + + private Object getItemToFilterValue(CapturedEvent event, ItemToFilter itemToFilter) { + if (itemToFilter.equals(ItemToFilter.Topic)) { + return event.getTopic(); + } + if (itemToFilter.equals(ItemToFilter.Publisher)) { + return event.getPublisherClassName(); + } + if (itemToFilter.equals(ItemToFilter.ChangedElement)) { + return event.getChangedElementClassName(); + } + if (itemToFilter.equals(ItemToFilter.ParameterName)) { + List<String> names = new ArrayList<String>(); + for (Parameter parameter: event.getParameters()) { + names.add(parameter.getName()); + } + return names; + } + if (itemToFilter.equals(ItemToFilter.ParameterValue)) { + List<Object> values = new ArrayList<Object>(); + for (Parameter parameter: event.getParameters()) { + values.add(parameter.getValue()); + } + return values; + } + if (itemToFilter.equals(ItemToFilter.ParameterNameAndValue)) { + List<String> nameAndValues = new ArrayList<String>(); + for (Parameter parameter: event.getParameters()) { + String nameAndValue = String.format(SpecialValue.NameAndValue.toString(), parameter.getName().trim(), + (parameter.getValue() == null? SpecialValue.Null: parameter.getValue().toString().trim())); + nameAndValues.add(nameAndValue); + } + return nameAndValues; + } + + throw new IllegalArgumentException("Not supported item to filter found: " + itemToFilter.toString()); + } + + private boolean matches(String expected, Object current, Operator operator) { + if (SpecialValue.Null.toString().equalsIgnoreCase(expected)) { + return operator.isPositive()? matchesToNull(current): !matchesToNull(current); + } + if ( SpecialValue.EmptyString.toString().equalsIgnoreCase(expected)) { + return operator.isPositive()? matchesToEmptyString(current): !matchesToEmptyString(current); + } + if (Operator.Equals.equals(operator)) { + return equalsTo(expected, current); + } + if (Operator.NotEquals.equals(operator)) { + return !equalsTo(expected, current); + } + if (Operator.Contains.equals(operator)) { + return contains(expected, current); + } + if (Operator.NotContains.equals(operator)) { + return !contains(expected, current); + } + if (Operator.StartsWith.equals(operator)) { + return startsWith(expected, current); + } + if (Operator.NotStartsWith.equals(operator)) { + return !startsWith(expected, current); + } + + throw new IllegalArgumentException("Not supported operator found: " + operator); + } + + private boolean matchesToEmptyString(Object current) { + return current != null && current instanceof String && current.toString().isEmpty(); + } + + private boolean matchesToNull(Object current) { + return current == null || current.toString().equalsIgnoreCase(SpecialValue.Null.toString()); + } + + private boolean equalsTo(String expected, Object current) { + return current != null && expected.equalsIgnoreCase(current.toString()); + } + + private boolean contains(String expected, Object current) { + return current != null && current.toString().toLowerCase().contains(expected.toLowerCase()); + } + + private boolean startsWith(String expected, Object current) { + return current != null && current.toString().toLowerCase().startsWith(expected.toLowerCase()); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/EventMonitor.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/EventMonitor.java new file mode 100644 index 00000000..6d0f900a --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/core/EventMonitor.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * 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.core; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.tools.event.spy.model.CapturedEvent; +import org.eclipse.e4.tools.event.spy.model.CapturedEventFilter; +import org.eclipse.e4.ui.internal.workbench.UIEventPublisher; +import org.eclipse.e4.ui.services.internal.events.EventBroker; +import org.eclipse.e4.ui.workbench.UIEvents; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; + +public class EventMonitor { + + public interface NewEventListener { + void newEvent(CapturedEvent event); + } + + private final static String TOPIC = UIEvents.UITopicBase + UIEvents.TOPIC_SEP + UIEvents.ALL_SUB_TOPICS; + + @SuppressWarnings({"serial", "restriction"}) + private static Set<Integer> EVENT_HELPER_CLASSES = new HashSet<Integer>() {{ + add(UIEvents.class.getName().hashCode()); + add(UIEventPublisher.class.getName().hashCode()); + }}; + + private Collection<CapturedEventFilter> filters; + + private IEventBroker eventBroker; + + private NewEventListener listener; + + private CapturedEventFilterMatcher eventFilterMatcher; + + private EventHandler eventHandler = new EventHandler() { + public void handleEvent(Event event) { + if (listener == null) { + return; + } + + CapturedEvent capturedEvent = new CapturedEvent(); + capturedEvent.setTopic(event.getTopic()); + capturedEvent.setPublisherClassName(getPublisherClassName()); + + for (String propertyName: event.getPropertyNames()) { + Object value = event.getProperty(propertyName); + capturedEvent.addParameter(propertyName, value); + if (value != null && UIEvents.EventTags.ELEMENT.equals(propertyName)) { + capturedEvent.setChangedElementClassName(value.getClass().getName()); + } + } + + if (shouldBeCaptured(capturedEvent)) { + listener.newEvent(capturedEvent); + } + } + }; + + public EventMonitor(IEventBroker eventBroker) { + this.eventBroker = eventBroker; + } + + public void start(Collection<CapturedEventFilter> filters) { + this.filters = filters; + eventBroker.subscribe(TOPIC, eventHandler); + } + + public void stop() { + eventBroker.unsubscribe(eventHandler); + } + + public void setNewEventListener(NewEventListener listener) { + this.listener = listener; + } + + private boolean shouldBeCaptured(CapturedEvent event) { + if (filters != null) { + Iterator<CapturedEventFilter> iter = filters.iterator(); + while (iter.hasNext()) { + if (!getEventFilterMatcher().matches(event, iter.next())) { + return false; + } + } + } + return true; + } + + private String getPublisherClassName() { + StackTraceElement items[] = Thread.currentThread().getStackTrace(); + boolean foundEventBroker = false; + + for (int i=0; i<items.length; i++) { + String clsName = items[i].getClassName(); + if (!foundEventBroker && clsName.equals(EventBroker.class.getName())) { + foundEventBroker = true; + } else if (foundEventBroker) { + if (!EVENT_HELPER_CLASSES.contains(clsName.hashCode())) { + return String.format("%s (%s:%d)", clsName, items[i].getMethodName(), items[i].getLineNumber()); + } + } + } + return ""; + } + + private CapturedEventFilterMatcher getEventFilterMatcher() { + if (eventFilterMatcher == null) { + eventFilterMatcher = new CapturedEventFilterMatcher(); + } + return eventFilterMatcher; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/handlers/OpenSpyDialogHandler.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/handlers/OpenSpyDialogHandler.java new file mode 100644 index 00000000..2d059763 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/handlers/OpenSpyDialogHandler.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * 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.handlers; + +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.tools.event.spy.ui.SpyDialog; + +public class OpenSpyDialogHandler { + @Execute + public void execute(IEclipseContext context) { + ContextInjectionFactory.make(SpyDialog.class, context).open(); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEvent.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEvent.java new file mode 100644 index 00000000..060b8f57 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEvent.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CapturedEvent { + private String topic; + + private String publisherClassName = ""; + + private String changedElementClassName = ""; + + private List<Parameter> parameters; + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getTopic() { + return topic; + } + + public void setPublisherClassName(String publisherClassName) { + this.publisherClassName = publisherClassName; + } + + public String getPublisherClassName() { + return publisherClassName; + } + + public void setChangedElementClassName(String changedElementClassName) { + this.changedElementClassName = changedElementClassName; + } + + public String getChangedElementClassName() { + return changedElementClassName; + } + + public void addParameter(String name, Object value) { + if (parameters == null) { + parameters = new ArrayList<Parameter>(); + } + parameters.add(new Parameter(name, value)); + } + + @SuppressWarnings("unchecked") + public List<Parameter> getParameters() { + return parameters != null? parameters: Collections.EMPTY_LIST; + } + + public boolean hasParameters() { + return parameters != null; + } + + @Override + public String toString() { + return topic; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventFilter.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventFilter.java new file mode 100644 index 00000000..e7706fd5 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventFilter.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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.model; + +public class CapturedEventFilter { + private final static String FILTER_AS_STRING_PATTERN = "Capture event when '%s' %s '%s'"; + + private final ItemToFilter itemToFilter; + + private final Operator operator; + + private final String value; + + public CapturedEventFilter(ItemToFilter itemToFilter, Operator operator, String value) { + this.itemToFilter = itemToFilter; + this.operator = operator; + this.value = normalize(itemToFilter, value); + } + + public ItemToFilter getItemToFilter() { + return itemToFilter; + } + + public Operator getOperator() { + return operator; + } + + public String getValue() { + return value; + } + + private String normalize(ItemToFilter itemToFilter, String value) { + if (ItemToFilter.ParameterNameAndValue.equals(itemToFilter)) { + String[] splitted = value.split("="); + if (splitted.length != 2) { + throw new IllegalArgumentException("Invalid value format, it should be: " + + String.format(SpecialValue.NameAndValue.toString(), "Name", "Value")); + } + return String.format(SpecialValue.NameAndValue.toString(), splitted[0].trim(), splitted[1].trim()); + } + return value; + } + + @Override + public String toString() { + return String.format(FILTER_AS_STRING_PATTERN, itemToFilter, operator, value); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventTreeSelection.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventTreeSelection.java new file mode 100644 index 00000000..6dddc176 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/CapturedEventTreeSelection.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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.model; + +public class CapturedEventTreeSelection { + private String selection; + + private boolean parameter; + + public CapturedEventTreeSelection(String selection, boolean parameter) { + this.selection = selection; + this.parameter = parameter; + } + + public String getSelection() { + return selection; + } + + public boolean isParameter() { + return parameter; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/ItemToFilter.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/ItemToFilter.java new file mode 100644 index 00000000..1565bebd --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/ItemToFilter.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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.model; + + +public enum ItemToFilter { + NotSelected("-- item to filter --"), + Topic("Topic"), + ParameterName("Parameter name"), + ParameterNameAndValue("Parameter name and value"), + ParameterValue("Some parameter value"), + Publisher("Event publisher"), + ChangedElement("Changed element"); + + private String text; + + private ItemToFilter(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + + public static ItemToFilter toItem(String text) { + for (ItemToFilter item: values()) { + if (item.text.equals(text)) { + return item; + } + } + throw new IllegalArgumentException(String.format("%s not found for: %s", + ItemToFilter.class.getSimpleName(), text)); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Operator.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Operator.java new file mode 100644 index 00000000..135a1898 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Operator.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.model; + +public enum Operator { + NotSelected("-- operator --", false), + Equals("equals to", true), + NotEquals("not equals to", false), + Contains("contains", true), + NotContains("not contains", false), + StartsWith("starts with", true), + NotStartsWith("not starts with", false); + + private String text; + + private boolean positive; + + private Operator(String text, boolean positive) { + this.text = text; + this.positive = positive; + } + + @Override + public String toString() { + return text; + } + + public boolean isPositive() { + return positive; + } + + public static Operator toOperator(String text) { + for (Operator operator: values()) { + if (operator.text.equals(text)) { + return operator; + } + } + throw new IllegalArgumentException(String.format("%s not found for: %s", + Operator.class.getSimpleName(), text)); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Parameter.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Parameter.java new file mode 100644 index 00000000..2de4d103 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/Parameter.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.model; + +public class Parameter { + private String name; + private Object value; + + public Parameter(String name, Object value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public Object getValue() { + return value; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/SpecialValue.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/SpecialValue.java new file mode 100644 index 00000000..30145559 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/model/SpecialValue.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.model; + +public enum SpecialValue { + Null("null"), + EmptyString("empty"), + NameAndValue("%s=%s"); + + private String text; + + private SpecialValue(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventFilters.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventFilters.java new file mode 100644 index 00000000..5ddd7187 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventFilters.java @@ -0,0 +1,265 @@ +/******************************************************************************* + * 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.ui; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.e4.tools.event.spy.model.CapturedEventFilter; +import org.eclipse.e4.tools.event.spy.model.ItemToFilter; +import org.eclipse.e4.tools.event.spy.model.Operator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +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 --"; + + private Composite control; + + private Text valueText; + + private Combo itemToFilterCombo; + + private Combo operatorCombo; + + private ToolTip validationErrorToolTip; + + private List filters; + + private Map<Integer, CapturedEventFilter> rawFilters; + + + /* Layout scheme: + * + * +-- control --------------------------------------------+ + * | +-- New filter group -------------------------------+ | + * | | | | + * | | 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); + + 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.HORIZONTAL)); + + Label label = new Label(newFilterGroup, SWT.CENTER); + label.setText("Capture event when:"); + + itemToFilterCombo = new Combo(newFilterGroup, SWT.READ_ONLY); + for (ItemToFilter item: ItemToFilter.values()) { + itemToFilterCombo.add(item.toString()); + } + itemToFilterCombo.select(0); + + operatorCombo = new Combo(newFilterGroup, SWT.READ_ONLY); + for (Operator operator: Operator.values()) { + operatorCombo.add(operator.toString()); + } + operatorCombo.select(0); + + valueText = new Text(newFilterGroup, 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().isEmpty()) { + valueText.setText(NOT_SELECTED_VALUE); + } + } + public void focusGained(FocusEvent e) { + if (NOT_SELECTED_VALUE.equals(valueText.getText())) { + valueText.setText(""); + } + } + }); + + Link link = new Link(newFilterGroup, SWT.NONE); + link.setText("<a>Add filter</a>"); + link.addListener (SWT.Selection, new Listener() { + public void handleEvent(Event event) { + addNewFilter(); + } + }); + } + + 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); + filters.setLayoutData(new RowData(403, 84)); + + + Composite composite = new Composite(definedFiltersGroup, SWT.NONE); + composite.setLayout(new RowLayout(SWT.VERTICAL)); + + Link 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; + } + + @SuppressWarnings("unchecked") + public Collection<CapturedEventFilter> getFilters() { + return rawFilters == null || rawFilters.isEmpty()? Collections.EMPTY_LIST: rawFilters.values(); + } + + public boolean hasFilters() { + return rawFilters != null && !rawFilters.isEmpty(); + } + + public int getFiltersCount() { + return rawFilters == null? 0: rawFilters.size(); + } + + private void addNewFilter() { + 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; + } + + 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; + } + + String value = valueText.getText(); + if (value.isEmpty() || value.equals(NOT_SELECTED_VALUE)) { + getTooltip().setText(String.format("%s is empty", getFieldName(NOT_SELECTED_VALUE))); + getTooltip().setVisible(true); + return; + } + + CapturedEventFilter eventFilter = null; + try { + eventFilter = new CapturedEventFilter(selectedItemToFilter, selectedOperator, value); + } catch(IllegalArgumentException exc) { + getTooltip().setText(exc.getMessage()); + getTooltip().setVisible(true); + return; + } + + if (rawFilters == null) { + rawFilters = new HashMap<Integer, CapturedEventFilter>(); + } + + String filterAsString = eventFilter.toString(); + if (rawFilters.containsKey(filterAsString.hashCode())) { + getTooltip().setText(String.format("Filter has been already added: %s", filterAsString)); + getTooltip().setVisible(true); + return; + } + + filters.add(filterAsString); + rawFilters.put(filterAsString.hashCode(), eventFilter); + + itemToFilterCombo.select(0); + operatorCombo.select(0); + valueText.setText(NOT_SELECTED_VALUE); + } + + private ToolTip getTooltip() { + if (validationErrorToolTip == null) { + validationErrorToolTip = new ToolTip(Display.getCurrent().getActiveShell(), SWT.BALLOON | SWT.ICON_WARNING); + } + return validationErrorToolTip; + } + + private void removeFilterAt(int index) { + if (index < 0) { + getTooltip().setText("Filter to remove is not selected"); + getTooltip().setVisible(true); + return; + } + + String filterAsString = filters.getItem(index); + filters.remove(index); + rawFilters.remove(filterAsString.hashCode()); + } + + private void removeAllFilters() { + if (rawFilters == null || rawFilters.isEmpty()) { + getTooltip().setText("Filter list is empty"); + getTooltip().setVisible(true); + return; + } + + filters.removeAll(); + rawFilters.clear(); + } + + private String getFieldName(Object notSelectedName) { + String fieldName = notSelectedName.toString().replaceAll("-", "").trim(); + return Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventTree.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventTree.java new file mode 100644 index 00000000..7e0b23e7 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/CapturedEventTree.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * 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.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.e4.tools.event.spy.model.CapturedEvent; +import org.eclipse.e4.tools.event.spy.model.CapturedEventTreeSelection; +import org.eclipse.e4.tools.event.spy.model.ItemToFilter; +import org.eclipse.e4.tools.event.spy.model.Parameter; +import org.eclipse.e4.tools.event.spy.util.ParameterFormatter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.TreeEvent; +import org.eclipse.swt.events.TreeListener; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; + + + +public class CapturedEventTree { + + public interface SelectionListener { + void selectionChanged(CapturedEventTreeSelection selection); + } + + private Tree tree; + + private SelectionListener selectionListener; + + private List<ItemToFilter> columns = new ArrayList<ItemToFilter>(); + + + /* Layout scheme: + * + * +-- parent---------------+ + * | | + * | Tree | + * | | + * +------------------------+ + * + * */ + + public CapturedEventTree(Composite parent) { + tree = new Tree(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + TreeColumn column = new TreeColumn(tree, SWT.LEFT); + column.setText(ItemToFilter.Topic.toString()); + column.setWidth(350); + columns.add(ItemToFilter.Topic); + + column = new TreeColumn(tree, SWT.LEFT); + column.setText(ItemToFilter.Publisher.toString()); + column.setWidth(150); + columns.add(ItemToFilter.Publisher); + + column = new TreeColumn(tree, SWT.LEFT); + column.setText(ItemToFilter.ChangedElement.toString()); + column.setWidth(150); + columns.add(ItemToFilter.ChangedElement); + + addTreeEventListeners(); + } + + @SuppressWarnings("unchecked") + private void addTreeEventListeners() { + tree.addTreeListener(new TreeListener() { + public void treeExpanded(TreeEvent e) { + TreeItem item = (TreeItem) e.item; + TreeItem paramItem = item.getItem(0); + if (paramItem.getText().isEmpty()) { + for (Parameter param: (List<Parameter>) paramItem.getData()) { + if (paramItem == null) { + paramItem = new TreeItem(item, SWT.NONE); + } + paramItem.setText(ParameterFormatter.toString(param)); + paramItem = null; + } + } + + } + public void treeCollapsed(TreeEvent e) { + } + }); + + tree.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + } + public void mouseDoubleClick(MouseEvent e) { + + } + public void mouseDown(MouseEvent e) { + TreeItem[] items = tree.getSelection(); + if (items == null || items.length == 0) { + return; + } + int selectedItemIndex = -1; + for (int i=0; i<columns.size(); i++) { + Rectangle rec = items[0].getBounds(i); + if (e.x >= rec.x && e.x <= rec.x + rec.width) { + selectedItemIndex = i; + break; + } + } + if (selectedItemIndex >= 0 && selectionListener != null) { + String selection = items[0].getText(selectedItemIndex); + if (!selection.isEmpty()) { + selectionListener.selectionChanged(new CapturedEventTreeSelection(selection,items[0].getItemCount() == 0)); + } + } + } + }); + } + + public void addEvent(CapturedEvent event) { + TreeItem item = new TreeItem(tree, SWT.NONE); + + item.setText(columns.indexOf(ItemToFilter.Topic), event.getTopic()); + item.setText(columns.indexOf(ItemToFilter.Publisher), event.getPublisherClassName()); + item.setText(columns.indexOf(ItemToFilter.ChangedElement), event.getChangedElementClassName()); + + if (event.hasParameters()) { + item = new TreeItem(item, SWT.NONE); + item.setData(event.getParameters()); + } + } + + public void setSelectionListener(SelectionListener selectionListener) { + this.selectionListener = selectionListener; + } + + public Control getControl() { + return tree; + } + + public void removeAll() { + tree.removeAll(); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/SpyDialog.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/SpyDialog.java new file mode 100644 index 00000000..e7a29f18 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/SpyDialog.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * 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.ui; + +import javax.inject.Inject; + +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.tools.event.spy.core.EventMonitor; +import org.eclipse.e4.tools.event.spy.model.CapturedEvent; +import org.eclipse.e4.tools.event.spy.model.CapturedEventTreeSelection; +import org.eclipse.e4.tools.event.spy.util.LoggerWrapper; +import org.eclipse.e4.tools.event.spy.util.PDEUtils; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + +public class SpyDialog extends Dialog implements EventMonitor.NewEventListener { + private final static String DIALOG_TITLE = "Event spy dialog"; + + private final static String[] SHOW_FILTER_LINK_TEXT = new String[]{"Show filters", "Hide filters"}; + + private CapturedEventTree capturedEventTree; + + private CapturedEventFilters capturedEventFilters; + + private Composite outer; + + private EventMonitor eventMonitor; + + private ToggleLink showFiltersLink; + + @Inject + private LoggerWrapper logger; + + @Inject + private IEventBroker eventBroker; + + @Inject + public SpyDialog(Shell shell) { + super(shell); + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE); + } + + /* Layout scheme: + * + * +-- Outer ----------------------------------------+ + * | +-- actionBar --------------------------------+ | + * | | | | + * | | Start capturing events | ShowFiltersLink | | + * | | | | + * | +---------------------------------------------+ | + * +-------------------------------------------------+ + * | | + * | CapturedEventFilters | + * | | + * +-------------------------------------------------+ + * | | + * | CapturedEventTree | + * | | + * +-------------------------------------------------+ + * | | + * | Close | + * | | + * +-------------------------------------------------+ + * + * */ + + @Override + protected Point getInitialSize() { + return new Point(600, 400); + } + + @Override + protected Control createDialogArea(Composite parent) { + outer = (Composite) super.createDialogArea(parent); + + createActionBar(outer); + createFilters(outer); + createCapturedEventTree(outer); + + return outer; + } + + private void createActionBar(Composite parent) { + Composite actionBar = new Composite(parent, SWT.NONE); + GridData gridData = createDefaultGridData(); + gridData.grabExcessVerticalSpace = false; + actionBar.setLayoutData(gridData); + + RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); + rowLayout.spacing = 20; + actionBar.setLayout(rowLayout); + + ToggleLink link = new ToggleLink(actionBar); + link.setText(new String[]{"Start capturing events", "Stop capturing events"}); + link.setClickListener(new ToggleLink.ClickListener() { + public void clicked(boolean toggled) { + if (toggled) { + captureEvents(); + } else { + stopCaptureEvents(); + } + } + }); + + showFiltersLink = new ToggleLink(actionBar); + showFiltersLink.setText(new String[]{SHOW_FILTER_LINK_TEXT[0], SHOW_FILTER_LINK_TEXT[1]}); + showFiltersLink.getControl().setLayoutData(new RowData(130, SWT.DEFAULT)); + showFiltersLink.setClickListener(new ToggleLink.ClickListener() { + public void clicked(boolean toggled) { + showFilters(toggled); + } + }); + } + + private void createFilters(Composite parent) { + capturedEventFilters = new CapturedEventFilters(outer); + capturedEventFilters.getControl().setVisible(false); + GridData gridData = createDefaultGridData(); + gridData.grabExcessVerticalSpace = false; + gridData.exclude = true; + capturedEventFilters.getControl().setLayoutData(gridData); + } + + private void createCapturedEventTree(Composite parent) { + capturedEventTree = new CapturedEventTree(outer); + capturedEventTree.getControl().setLayoutData(createDefaultGridData()); + capturedEventTree.setSelectionListener(new CapturedEventTree.SelectionListener() { + public void selectionChanged(CapturedEventTreeSelection selection) { + openResource(selection); + } + }); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(DIALOG_TITLE); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, "Close", false); + } + + public void captureEvents() { + capturedEventTree.removeAll(); + if (eventMonitor == null) { + eventMonitor = new EventMonitor(eventBroker); + eventMonitor.setNewEventListener(this); + } + eventMonitor.start(capturedEventFilters.getFilters()); + getShell().setText(DIALOG_TITLE + " - capturing..."); + } + + public void stopCaptureEvents() { + if (eventMonitor != null) { + eventMonitor.stop(); + } + getShell().setText(DIALOG_TITLE); + } + + public void newEvent(CapturedEvent event) { + capturedEventTree.addEvent(event); + } + + private void openResource(CapturedEventTreeSelection selection) { + String name = selection.getSelection(); + if (selection.isParameter()) { + String[] splitted = selection.getSelection().split("="); + if (splitted.length == 2) { + name = splitted[1]; + } + } + + try { + PDEUtils.openClass(name); + } catch(ClassNotFoundException exc) { + logger.warn(exc.getMessage()); + } + } + + private void showFilters(boolean filtersVisible) { + capturedEventFilters.getControl().setVisible(filtersVisible); + ((GridData) capturedEventFilters.getControl().getLayoutData()).exclude = !filtersVisible; + + //Filters have been set and filters UI is not visible so we have to mark it to user + if (!filtersVisible && capturedEventFilters.hasFilters()) { + showFiltersLink.setText(new String[] { String.format("%s (%d)", SHOW_FILTER_LINK_TEXT[0], + capturedEventFilters.getFiltersCount()), SHOW_FILTER_LINK_TEXT[1]}); + } else { + showFiltersLink.setText(new String[] {SHOW_FILTER_LINK_TEXT[0], SHOW_FILTER_LINK_TEXT[1]}); + } + + outer.layout(false); + } + + private GridData createDefaultGridData() { + GridData gridData = new GridData(); + gridData.verticalAlignment = GridData.FILL; + gridData.verticalSpan = 2; + gridData.grabExcessVerticalSpace = true; + gridData.horizontalAlignment = GridData.FILL; + gridData.grabExcessHorizontalSpace = true; + return gridData; + } + + /** for testing/modifying dialog UI + public static void main(String... args) { + Display display = new Display (); + Shell shell = new Shell (display); + shell.open (); + + SpyDialog dialog = new SpyDialog(shell); + + dialog.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch ()) display.sleep (); + } + display.dispose (); + } + */ +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/ToggleLink.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/ToggleLink.java new file mode 100644 index 00000000..58e71944 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/ui/ToggleLink.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.ui; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Listener; + +public class ToggleLink { + private Link link; + + private ClickListener listener; + + private String[] text = {"", ""}; + + public interface ClickListener { + void clicked(boolean toggled); + } + + public ToggleLink(Composite parent) { + link = new Link(parent, SWT.NONE); + link.setSize(SWT.DEFAULT, SWT.DEFAULT); + link.addListener (SWT.Selection, new Listener() { + public void handleEvent(Event event) { + updateText(); + if (listener != null) { + listener.clicked(isToggled()); + } + } + }); + } + + private void updateText() { + String textToUpdate = link.getText().contains(text[0])? text[1]: text[0]; + setText(textToUpdate); + } + + private void setText(String text) { + link.setText(String.format("<a>%s</a>", text)); + } + + public void setClickListener(ClickListener listener) { + this.listener = listener; + } + + public void setText(String[] text /*normal text, toggle text*/) { + this.text = text; + setText(isToggled()? text[1]: text[0]); + } + + public Control getControl() { + return link; + } + + private boolean isToggled() { + return link.getText().contains(text[1]); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/LoggerWrapper.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/LoggerWrapper.java new file mode 100644 index 00000000..cb3a95d5 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/LoggerWrapper.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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.util; + +import javax.inject.Inject; + +import org.eclipse.e4.core.di.annotations.Creatable; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.log.Logger; +import org.eclipse.e4.tools.event.spy.Constants; + +@Creatable +public class LoggerWrapper extends Logger { + @Optional + @Inject + private Logger logger; + + @Override + public boolean isErrorEnabled() { + if (logger != null) { + return logger.isErrorEnabled(); + } + return false; + } + + @Override + public boolean isTraceEnabled() { + if (logger != null) { + return logger.isTraceEnabled(); + } + return false; + } + + @Override + public boolean isWarnEnabled() { + if (logger != null) { + return logger.isWarnEnabled(); + } + return false; + } + + @Override + public boolean isInfoEnabled() { + if (logger != null) { + return logger.isInfoEnabled(); + } + return false; + } + + @Override + public boolean isDebugEnabled() { + if (logger != null) { + return logger.isDebugEnabled(); + } + return false; + } + + @Override + public void error(Throwable t, String message) { + if (logger != null && isErrorEnabled()) { + logger.error(t, withPluginInfo(message)); + } + } + + @Override + public void warn(Throwable t, String message) { + if (logger != null && isWarnEnabled()) { + logger.warn(t, withPluginInfo(message)); + } + } + + @Override + public void info(Throwable t, String message) { + if (logger != null && isInfoEnabled()) { + logger.info(t, withPluginInfo(message)); + } + } + + @Override + public void trace(Throwable t, String message) { + if (logger != null && isTraceEnabled()) { + logger.trace(t, withPluginInfo(message)); + } + } + + @Override + public void debug(Throwable t) { + if (logger != null && isDebugEnabled()) { + logger.debug(t); + } + } + + @Override + public void debug(Throwable t, String message) { + if (logger != null && isDebugEnabled()) { + logger.debug(t, withPluginInfo(message)); + } + } + + private String withPluginInfo(String message) { + return String.format("Plugin '%s': %s", Constants.PLUGIN_ID, message); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PDEUtils.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PDEUtils.java new file mode 100644 index 00000000..274aadf5 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PDEUtils.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * 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.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.pde.core.plugin.IPluginModelBase; +import org.eclipse.pde.core.plugin.PluginRegistry; +import org.eclipse.pde.internal.core.PDECore; +import org.eclipse.pde.internal.core.SearchablePluginsManager; +import org.eclipse.pde.internal.runtime.PDERuntimeMessages; +import org.eclipse.pde.internal.runtime.PDERuntimePlugin; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PartInitException; + +public class PDEUtils { + private final static Pattern CLASS_NAME_PATTERN = Pattern.compile("(([a-zA-Z_]+[0-9]*\\.)+[a-zA-Z_]+[a-z0-9]*)"); + + public static void openClass(String clsName) throws ClassNotFoundException { + Matcher matcher = CLASS_NAME_PATTERN.matcher(clsName); + if (matcher.find()) { + try { + clsName = matcher.group(1).trim(); + openClass(Class.forName(clsName)); + } catch(ClassNotFoundException exc) { + throw new ClassNotFoundException("Class not found in the bundle classpath: " + clsName); + } + } + } + + public static void openClass(Class<?> cls) { + IPluginModelBase model = PluginRegistry.findModel(PluginUtils.getBundleId(cls)); + IResource resource = model != null ? model.getUnderlyingResource() : null; + IJavaProject project = null; + + // if we don't find a model + if (model == null) { + MessageDialog.openError(Display.getCurrent().getActiveShell(), PDERuntimeMessages.SpyIDEUtil_noSourceFound_title, + NLS.bind(PDERuntimeMessages.SpyIDEUtil_noSourceFound_message, new Object[] {cls.getName()})); + return; + } + + if (resource != null) { // project is open in workspace + project = JavaCore.create(resource.getProject()); + } else { + SearchablePluginsManager manager = PDECore.getDefault().getSearchablePluginsManager(); + try { + manager.createProxyProject(new NullProgressMonitor()); + manager.addToJavaSearch(new IPluginModelBase[] {model}); + project = manager.getProxyProject(); + } catch (CoreException e) { + } + } + if (project != null) + openInEditor(project, cls.getName()); + } + + private static void openInEditor(IJavaProject project, String clazz) { + try { + IType type = project.findType(clazz); + JavaUI.openInEditor(type, false, true); + } catch (JavaModelException e) { + PDERuntimePlugin.log(e); + } catch (PartInitException e) { + PDERuntimePlugin.log(e); + } + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/ParameterFormatter.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/ParameterFormatter.java new file mode 100644 index 00000000..9ebc147c --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/ParameterFormatter.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.util; + +import org.eclipse.e4.tools.event.spy.model.Parameter; + +public class ParameterFormatter { + //TODO: Add some parameter formatting and break to long strings into multiple lines + public static String toString(Parameter parameter) { + return String.format("%s = %s", parameter.getName(), parameter.getValue()); + } +} diff --git a/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PluginUtils.java b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PluginUtils.java new file mode 100644 index 00000000..cf3524f2 --- /dev/null +++ b/bundles/org.eclipse.e4.tools.event.spy/src/org/eclipse/e4/tools/event/spy/util/PluginUtils.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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.util; + +import org.eclipse.e4.tools.event.spy.Constants; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class PluginUtils { + public static String getContributorURI() { + return String.format("platform:/plugin/%s", Constants.PLUGIN_ID); + } + + public static String getContributionURI(Class<?> contributionCls) { + return String.format("bundleclass://%s/%s", Constants.PLUGIN_ID, contributionCls.getName()); + } + + public static String getBundleId(Class<?> cls) { + Bundle bundle = FrameworkUtil.getBundle(cls); + if (bundle == null) { + throw new IllegalArgumentException("Cannot find bundle for class: " + cls.getName()); + } + return bundle.getSymbolicName(); + } +} |