--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.diagram.synchronization.runtime;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Set;\r
+import java.util.concurrent.atomic.AtomicReference;\r
+\r
+import org.simantics.diagram.ui.DiagramModelHints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.DataElementMap;\r
+import org.simantics.g2d.diagram.participant.Selection;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.datastructures.hints.IHintObservable;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class DiagramSelectionUpdater extends HintListenerAdapter {\r
+\r
+ private static final boolean DEBUG_SELECTION_UPDATE = false;\r
+\r
+ private final ICanvasContext ctx;\r
+ private final Selection selection;\r
+ private final IDiagram diagram;\r
+\r
+ private int selectionId;\r
+ private AtomicReference<Set<?>> newSelection = new AtomicReference<Set<?>>();\r
+\r
+ private boolean oneshot = false;\r
+ private boolean tracking = false;\r
+\r
+ public DiagramSelectionUpdater(ICanvasContext ctx) {\r
+ this.ctx = ctx;\r
+ this.selection = ctx.getAtMostOneItemOfClass(Selection.class);\r
+ if (selection == null)\r
+ throw new IllegalArgumentException("no selection participant");\r
+ this.diagram = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);\r
+ if (diagram == null)\r
+ throw new IllegalArgumentException("no diagram");\r
+ }\r
+\r
+ public DiagramSelectionUpdater(ICanvasContext ctx, IDiagram diagram) {\r
+ this.ctx = ctx;\r
+ this.selection = ctx.getAtMostOneItemOfClass(Selection.class);\r
+ if (selection == null)\r
+ throw new IllegalArgumentException("no selection participant");\r
+ this.diagram = diagram;\r
+ if (diagram == null)\r
+ throw new IllegalArgumentException("no diagram");\r
+ }\r
+\r
+ protected Selection getSelectionParticipant() {\r
+ return ctx.getSingleItem(Selection.class);\r
+ }\r
+\r
+ public DiagramSelectionUpdater setNewSelection(int selectionId, Set<?> newSelection) {\r
+ this.selectionId = selectionId;\r
+ this.newSelection.set(newSelection);\r
+ return this;\r
+ }\r
+\r
+ public Set<?> getNewSelection() {\r
+ return newSelection.get();\r
+ }\r
+\r
+ public DiagramSelectionUpdater setOneshot(boolean oneshot) {\r
+ this.oneshot = oneshot;\r
+ return this;\r
+ }\r
+\r
+ public DiagramSelectionUpdater track() {\r
+ if (!tracking) {\r
+ diagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);\r
+ tracking = true;\r
+ }\r
+ return this;\r
+ }\r
+\r
+ public DiagramSelectionUpdater untrack() {\r
+ if (tracking) {\r
+ diagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);\r
+ tracking = false;\r
+ }\r
+ return this;\r
+ }\r
+\r
+ @Override\r
+ public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
+ if (!ctx.isDisposed() && key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) {\r
+ if (DEBUG_SELECTION_UPDATE)\r
+ System.out.println(getClass().getSimpleName() + ": DIAGRAM UPDATED @" + System.currentTimeMillis() + ", selection to set: " + newSelection);\r
+ Set<?> ns = newSelection.getAndSet(null);\r
+ if (ns != null) {\r
+ scheduleSetDiagramSelection(2, ns);\r
+ }\r
+ }\r
+\r
+ if (oneshot) {\r
+ // Remove self from listening duties.\r
+ sender.removeHintListener(this);\r
+ }\r
+ }\r
+\r
+ private void scheduleSetDiagramSelection(final int tries, final Set<?> data) {\r
+ ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ setDiagramSelectionToData(tries, data);\r
+ }\r
+ });\r
+ }\r
+\r
+ private void setDiagramSelectionToData(final int tries, final Set<?> data) {\r
+ if (DEBUG_SELECTION_UPDATE)\r
+ System.out.println("setDiagramSelectionToData(" + tries + ", " + data + ")");\r
+\r
+ DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);\r
+ if (dem != null) {\r
+ final Collection<IElement> newSelection = new ArrayList<IElement>(data.size());\r
+ for (Object datum : data) {\r
+ IElement element = dem.getElement(diagram, datum);\r
+ if (DEBUG_SELECTION_UPDATE)\r
+ System.out.println(" DATUM " + datum + " -> " + element);\r
+ if (element != null) {\r
+ newSelection.add(element);\r
+ } else {\r
+ if (tries > 0) {\r
+ // Try later if there are tries left.\r
+ ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ setDiagramSelectionToData(tries - 1, data);\r
+ }\r
+ });\r
+ return;\r
+ }\r
+ // Otherwise select whatever is found.\r
+ }\r
+ }\r
+\r
+ if (DEBUG_SELECTION_UPDATE)\r
+ System.out.println("[" + tries + "] final new selection: " + newSelection);\r
+\r
+ if (!newSelection.isEmpty()) {\r
+ //for (IElement e : newSelection)\r
+ // e.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);\r
+ selection.setSelection(selectionId, newSelection);\r
+ }\r
+ }\r
+ }\r
+\r
+}\r