/******************************************************************************* * Copyright (c) 2007, 2013 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.diagram.participant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.ui.contexts.IContextActivation; import org.eclipse.ui.contexts.IContextService; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; import org.simantics.utils.ObjectUtils; import org.simantics.utils.threads.IThreadWorkQueue; import org.simantics.utils.threads.ThreadUtils; /** * ContextUtil manages the activeness of Eclipse Workbench UI context related to * an ICanvasContext and an IContextService (possibly local to a workbench part). * * @author Tuukka Lehtonen */ public class ContextUtil extends AbstractCanvasParticipant { private static final boolean DEBUG = false; private final IContextService service; private final IThreadWorkQueue thread; private final Map activations = new ConcurrentHashMap(); public ContextUtil(IContextService service, IThreadWorkQueue contextManipulationThread) { assert service != null; assert contextManipulationThread != null; this.service = service; this.thread = contextManipulationThread; } public void inContextThread(Runnable r) { exec(r, true); } private void debug(String s) { debug(false, s); } private void debug(boolean trace, String s) { if (DEBUG) { System.out.println(getClass().getSimpleName() + "(" + ObjectUtils.hashCode(getContext()) + "): " + s); if (trace) { StackTraceElement[] es = new Exception().getStackTrace(); int e = 0; System.out.println("Invoked from: "); for (int i = 0; i < 2 && e < es.length; ++e) { if (es[e].getClassName().equals(getClass().getName())) continue; System.out.println("\t" + es[e].toString()); ++i; } } } } private void checkThread() { if (!thread.currentThreadAccess()) { throw new IllegalStateException("not in context thread, use ContextUtil.inContextThread(Runnable)"); } } private void exec(Runnable r) { exec(r, false); } private void exec(Runnable r, boolean allowSchedule) { if (!allowSchedule) checkThread(); // Context access thread is disposed already? if (thread.getThread() == null) return; if (thread.currentThreadAccess()) { if (DEBUG) debug("RUNNING " + r); r.run(); } else { if (DEBUG) debug("SCHEDULING " + r); ThreadUtils.asyncExec(thread, r); } } @Override public void removedFromContext(ICanvasContext ctx) { exec(new Runnable() { @Override public void run() { deactivateAll(); } }, true); super.removedFromContext(ctx); } private void doActivate(String contextId) { if(!activations.containsKey(contextId)) { IContextActivation activation = service.activateContext(contextId); if (activation != null) { if (DEBUG) debug("ACTIVATED context: " + contextId); activations.put(contextId, activation); } } else { if (DEBUG) debug("TRIED TO ACTIVATE DUPLICATE CONTEXT: " + contextId); } } public void activate(final String contextId) { checkThread(); if (DEBUG) debug(true, "activate(" + contextId + ")"); assert contextId != null; exec(new Runnable() { @Override public void run() { doActivate(contextId); } }); } public void activate(final Collection contextIds) { if (DEBUG) debug(true, "activate contexts (" + contextIds + ")"); if (contextIds.isEmpty()) return; exec(new Runnable() { @Override public void run() { for (String id : contextIds) { doActivate(id); } } }); } // public void deactivate(String contextId) { // checkThread(); // assert contextId != null; // final IContextActivation activation = activations.remove(contextId); // if (activation == null) { // debug("WARNING: cannot deactivate inactive context: " + contextId); // return; // } // exec(new Runnable() { // @Override // public void run() { // if (DEBUG_ACTIVATIONS) // debug("DE-ACT context: " + activation.getContextId()); // service.deactivateContext(activation); // } // }); // } public void deactivate(Collection contextIds) { checkThread(); assert contextIds != null; for(String id : contextIds) { final IContextActivation a = activations.remove(id); if (DEBUG) debug(true, "deactivate(" + id + "): " + a); if (a != null) exec(new Runnable() { @Override public void run() { if (DEBUG) debug("DE-ACT context: " + a.getContextId()); service.deactivateContext(a); } }); } } public void deactivate(IContextActivation activation) { checkThread(); assert activation != null; final IContextActivation a = activations.remove(activation.getContextId()); if (DEBUG) debug(true, "deactivate(" + activation + "): " + a); if (a == activation) exec(new Runnable() { @Override public void run() { if (DEBUG) debug("DE-ACT context: " + a.getContextId()); service.deactivateContext(a); } }); } public void deactivateAll() { checkThread(); final Collection acts = getActivations(); if (DEBUG) debug(true, "DE-ACTIVATE ALL INVOKED, " + acts.size() + " contexts to deactivate"); activations.clear(); exec(new Runnable() { @Override public void run() { if (DEBUG) debug("\tDE-ACTIVATE ALL " + acts.size() + " contexts:"); for (IContextActivation a : acts) { if (DEBUG) debug("\t\tDE-ACT context: " + a.getContextId()); service.deactivateContext(a); } } }); } public synchronized Collection getActivations() { return Collections.unmodifiableCollection(new ArrayList(activations.values())); } public synchronized Collection getActivatedContextIds() { return Collections.unmodifiableCollection(new ArrayList(activations.keySet())); } }