blob: a6f3cd406a8a06c627645f5231bcff62cb5028ea [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2012 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.ui.internal.workbench;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.contexts.RunAndTrack;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.internal.contexts.EclipseContext;
import org.eclipse.e4.core.internal.contexts.IContextDisposalListener;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ISelectionListener;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
public class SelectionAggregator {
static final String OUT_SELECTION = "org.eclipse.ui.output.selection"; //$NON-NLS-1$
static final String OUT_POST_SELECTION = "org.eclipse.ui.output.postSelection"; //$NON-NLS-1$
private ListenerList genericListeners = new ListenerList();
private ListenerList genericPostListeners = new ListenerList();
private Map<String, ListenerList> targetedListeners = new HashMap<String, ListenerList>();
private Map<String, ListenerList> targetedPostListeners = new HashMap<String, ListenerList>();
private Set<IEclipseContext> tracked = new HashSet<IEclipseContext>();
private EventHandler eventHandler = new EventHandler() {
public void handleEvent(Event event) {
Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
if (element instanceof MPart) {
MPart part = (MPart) element;
String partId = part.getElementId();
if (targetedListeners.containsKey(partId))
track(part);
}
}
};
private MPart activePart;
private IEclipseContext context;
private EPartService partService;
private IEventBroker eventBroker;
private Logger logger;
@Inject
SelectionAggregator(IEclipseContext context, EPartService partService,
IEventBroker eventBroker, Logger logger) {
super();
this.context = context;
this.partService = partService;
this.eventBroker = eventBroker;
this.logger = logger;
}
@PreDestroy
void preDestroy() {
genericListeners.clear();
genericPostListeners.clear();
targetedListeners.clear();
targetedPostListeners.clear();
eventBroker.unsubscribe(eventHandler);
}
@PostConstruct
void postConstruct() {
eventBroker.subscribe(UIEvents.Context.TOPIC_CONTEXT, eventHandler);
}
@Inject
void setPart(@Optional @Named(IServiceConstants.ACTIVE_PART) final MPart part) {
if ((part != null) && (activePart != part)) {
activePart = part;
track(part);
}
}
private void notifyListeners(final MPart part, final Object selection) {
for (Object listener : genericListeners.getListeners()) {
final ISelectionListener myListener = (ISelectionListener) listener;
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
myListener.selectionChanged(part, selection);
}
public void handleException(Throwable exception) {
logger.error(exception);
}
});
}
notifyTargetedListeners(part, selection);
}
private void notifyTargetedListeners(final MPart part, final Object selection) {
String id = part.getElementId();
if (id != null) {
ListenerList listenerList = targetedListeners.get(id);
if (listenerList != null) {
for (Object listener : listenerList.getListeners()) {
final ISelectionListener myListener = (ISelectionListener) listener;
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
myListener.selectionChanged(part, selection);
}
public void handleException(Throwable exception) {
logger.error(exception);
}
});
}
}
}
}
private void notifyPostListeners(final MPart part, final Object selection) {
for (Object listener : genericPostListeners.getListeners()) {
final ISelectionListener myListener = (ISelectionListener) listener;
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
myListener.selectionChanged(part, selection);
}
public void handleException(Throwable exception) {
logger.error(exception);
}
});
}
notifyTargetedPostListeners(part, selection);
}
private void notifyTargetedPostListeners(final MPart part, final Object selection) {
String id = part.getElementId();
if (id != null) {
ListenerList listenerList = targetedPostListeners.get(id);
if (listenerList != null) {
for (Object listener : listenerList.getListeners()) {
final ISelectionListener myListener = (ISelectionListener) listener;
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
myListener.selectionChanged(part, selection);
}
public void handleException(Throwable exception) {
logger.error(exception);
}
});
}
}
}
}
private void track(final MPart part) {
final IEclipseContext myContext = this.context;
IEclipseContext context = part.getContext();
if (context != null && tracked.add(context)) {
if (context instanceof EclipseContext) {
((EclipseContext) context).notifyOnDisposal(new IContextDisposalListener() {
public void disposed(IEclipseContext context) {
tracked.remove(context);
}
});
}
context.runAndTrack(new RunAndTrack() {
private boolean initial = true;
public boolean changed(IEclipseContext context) {
final Object selection = context.get(OUT_SELECTION);
if (initial) {
initial = false;
if (selection == null) {
return true;
}
}
if (activePart == part) {
myContext.set(IServiceConstants.ACTIVE_SELECTION, selection);
runExternalCode(new Runnable() {
public void run() {
notifyListeners(part, selection);
}
});
} else {
runExternalCode(new Runnable() {
public void run() {
notifyTargetedListeners(part, selection);
}
});
// we don't need to keep tracking non-active parts unless
// they have targeted listeners
String partId = part.getElementId();
boolean continueTracking = targetedListeners.containsKey(partId)
|| targetedPostListeners.containsKey(partId);
if (!continueTracking) {
tracked.remove(part.getContext());
}
return continueTracking;
}
return true;
}
});
context.runAndTrack(new RunAndTrack() {
private boolean initial = true;
public boolean changed(IEclipseContext context) {
final Object postSelection = context.get(OUT_POST_SELECTION);
if (initial) {
initial = false;
if (postSelection == null) {
return true;
}
}
if (activePart == part) {
runExternalCode(new Runnable() {
public void run() {
notifyPostListeners(part, postSelection);
}
});
} else {
runExternalCode(new Runnable() {
public void run() {
notifyTargetedPostListeners(part, postSelection);
}
});
// we don't need to keep tracking non-active parts unless
// they have targeted listeners
String partId = part.getElementId();
boolean continueTracking = targetedListeners.containsKey(partId)
|| targetedPostListeners.containsKey(partId);
return continueTracking;
}
return true;
}
});
}
}
public Object getSelection() {
return context.get(IServiceConstants.ACTIVE_SELECTION);
}
public void addSelectionListener(ISelectionListener listener) {
genericListeners.add(listener);
}
public void addPostSelectionListener(ISelectionListener listener) {
genericPostListeners.add(listener);
}
public void removeSelectionListener(ISelectionListener listener) {
// we may have been destroyed already, see bug 310113
if (context != null) {
genericListeners.remove(listener);
}
}
public void removePostSelectionListener(ISelectionListener listener) {
// we may have been destroyed already, see bug 310113
if (context != null) {
genericPostListeners.remove(listener);
}
}
public void addSelectionListener(String partId, ISelectionListener listener) {
ListenerList listeners = targetedListeners.get(partId);
if (listeners == null) {
listeners = new ListenerList();
targetedListeners.put(partId, listeners);
}
listeners.add(listener);
MPart part = partService.findPart(partId);
if (part != null)
track(part);
}
public void addPostSelectionListener(String partId, ISelectionListener listener) {
ListenerList listeners = targetedPostListeners.get(partId);
if (listeners == null) {
listeners = new ListenerList();
targetedPostListeners.put(partId, listeners);
}
listeners.add(listener);
MPart part = partService.findPart(partId);
if (part != null)
track(part);
}
public void removeSelectionListener(String partId, ISelectionListener listener) {
// we may have been destroyed already, see bug 310113
if (context != null) {
ListenerList listeners = targetedListeners.get(partId);
if (listeners != null) {
listeners.remove(listener);
}
}
}
public void removePostSelectionListener(String partId, ISelectionListener listener) {
// we may have been destroyed already, see bug 310113
if (context != null) {
ListenerList listeners = targetedPostListeners.get(partId);
if (listeners != null) {
listeners.remove(listener);
}
}
}
public Object getSelection(String partId) {
MPart part = partService.findPart(partId);
if (part == null) {
return null;
}
IEclipseContext partContext = part.getContext();
if (partContext == null) {
return null;
}
return partContext.get(OUT_SELECTION);
}
}