1 /*******************************************************************************
\r
2 * Copyright (c) 2011 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.diagram.synchronization.runtime;
\r
14 import java.util.ArrayList;
\r
15 import java.util.Collection;
\r
16 import java.util.Set;
\r
17 import java.util.concurrent.atomic.AtomicReference;
\r
19 import org.simantics.diagram.ui.DiagramModelHints;
\r
20 import org.simantics.g2d.canvas.ICanvasContext;
\r
21 import org.simantics.g2d.diagram.DiagramHints;
\r
22 import org.simantics.g2d.diagram.IDiagram;
\r
23 import org.simantics.g2d.diagram.handler.DataElementMap;
\r
24 import org.simantics.g2d.diagram.participant.Selection;
\r
25 import org.simantics.g2d.element.IElement;
\r
26 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
\r
27 import org.simantics.utils.datastructures.hints.IHintContext.Key;
\r
28 import org.simantics.utils.datastructures.hints.IHintObservable;
\r
29 import org.simantics.utils.threads.ThreadUtils;
\r
32 * @author Tuukka Lehtonen
\r
34 public class DiagramSelectionUpdater extends HintListenerAdapter {
\r
36 private static final boolean DEBUG_SELECTION_UPDATE = false;
\r
38 private final ICanvasContext ctx;
\r
39 private final Selection selection;
\r
40 private final IDiagram diagram;
\r
42 private int selectionId;
\r
43 private AtomicReference<Set<?>> newSelection = new AtomicReference<Set<?>>();
\r
45 private boolean oneshot = false;
\r
46 private boolean tracking = false;
\r
48 public DiagramSelectionUpdater(ICanvasContext ctx) {
\r
50 this.selection = ctx.getAtMostOneItemOfClass(Selection.class);
\r
51 if (selection == null)
\r
52 throw new IllegalArgumentException("no selection participant");
\r
53 this.diagram = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
\r
54 if (diagram == null)
\r
55 throw new IllegalArgumentException("no diagram");
\r
58 public DiagramSelectionUpdater(ICanvasContext ctx, IDiagram diagram) {
\r
60 this.selection = ctx.getAtMostOneItemOfClass(Selection.class);
\r
61 if (selection == null)
\r
62 throw new IllegalArgumentException("no selection participant");
\r
63 this.diagram = diagram;
\r
64 if (diagram == null)
\r
65 throw new IllegalArgumentException("no diagram");
\r
68 protected Selection getSelectionParticipant() {
\r
69 return ctx.getSingleItem(Selection.class);
\r
72 public DiagramSelectionUpdater setNewSelection(int selectionId, Set<?> newSelection) {
\r
73 this.selectionId = selectionId;
\r
74 this.newSelection.set(newSelection);
\r
78 public Set<?> getNewSelection() {
\r
79 return newSelection.get();
\r
82 public DiagramSelectionUpdater setOneshot(boolean oneshot) {
\r
83 this.oneshot = oneshot;
\r
87 public DiagramSelectionUpdater track() {
\r
89 diagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);
\r
95 public DiagramSelectionUpdater untrack() {
\r
97 diagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);
\r
104 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
\r
105 if (!ctx.isDisposed() && key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) {
\r
106 if (DEBUG_SELECTION_UPDATE)
\r
107 System.out.println(getClass().getSimpleName() + ": DIAGRAM UPDATED @" + System.currentTimeMillis() + ", selection to set: " + newSelection);
\r
108 Set<?> ns = newSelection.getAndSet(null);
\r
110 scheduleSetDiagramSelection(2, ns);
\r
115 // Remove self from listening duties.
\r
116 sender.removeHintListener(this);
\r
120 private void scheduleSetDiagramSelection(final int tries, final Set<?> data) {
\r
121 ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
\r
123 public void run() {
\r
124 setDiagramSelectionToData(tries, data);
\r
129 private void setDiagramSelectionToData(final int tries, final Set<?> data) {
\r
130 if (DEBUG_SELECTION_UPDATE)
\r
131 System.out.println("setDiagramSelectionToData(" + tries + ", " + data + ")");
\r
133 DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);
\r
135 final Collection<IElement> newSelection = new ArrayList<IElement>(data.size());
\r
136 for (Object datum : data) {
\r
137 IElement element = dem.getElement(diagram, datum);
\r
138 if (DEBUG_SELECTION_UPDATE)
\r
139 System.out.println(" DATUM " + datum + " -> " + element);
\r
140 if (element != null) {
\r
141 newSelection.add(element);
\r
144 // Try later if there are tries left.
\r
145 ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
\r
147 public void run() {
\r
148 setDiagramSelectionToData(tries - 1, data);
\r
153 // Otherwise select whatever is found.
\r
157 if (DEBUG_SELECTION_UPDATE)
\r
158 System.out.println("[" + tries + "] final new selection: " + newSelection);
\r
160 if (!newSelection.isEmpty()) {
\r
161 //for (IElement e : newSelection)
\r
162 // e.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);
\r
163 selection.setSelection(selectionId, newSelection);
\r