]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/runtime/DiagramSelectionUpdater.java
Some enhancements to GraphLayer-related utilities for Diagram layers
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / synchronization / runtime / DiagramSelectionUpdater.java
1 /*******************************************************************************
2  * Copyright (c) 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.synchronization.runtime;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Set;
17 import java.util.concurrent.atomic.AtomicReference;
18
19 import org.simantics.diagram.ui.DiagramModelHints;
20 import org.simantics.g2d.canvas.ICanvasContext;
21 import org.simantics.g2d.diagram.DiagramHints;
22 import org.simantics.g2d.diagram.IDiagram;
23 import org.simantics.g2d.diagram.handler.DataElementMap;
24 import org.simantics.g2d.diagram.participant.Selection;
25 import org.simantics.g2d.element.IElement;
26 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
27 import org.simantics.utils.datastructures.hints.IHintContext.Key;
28 import org.simantics.utils.datastructures.hints.IHintObservable;
29 import org.simantics.utils.threads.ThreadUtils;
30
31 /**
32  * @author Tuukka Lehtonen
33  */
34 public class DiagramSelectionUpdater extends HintListenerAdapter {
35
36     private static final boolean    DEBUG_SELECTION_UPDATE = false;
37
38     private final ICanvasContext    ctx;
39     private final Selection         selection;
40     private final IDiagram          diagram;
41
42     private int                     selectionId;
43     private AtomicReference<Set<?>> newSelection           = new AtomicReference<Set<?>>();
44
45     private boolean                 oneshot                = false;
46     private boolean                 tracking               = false;
47
48     public DiagramSelectionUpdater(ICanvasContext ctx) {
49         this.ctx = ctx;
50         this.selection = ctx.getAtMostOneItemOfClass(Selection.class);
51         if (selection == null)
52             throw new IllegalArgumentException("no selection participant");
53         this.diagram = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
54         if (diagram == null)
55             throw new IllegalArgumentException("no diagram");
56     }
57
58     public DiagramSelectionUpdater(ICanvasContext ctx, IDiagram diagram) {
59         this.ctx = ctx;
60         this.selection = ctx.getAtMostOneItemOfClass(Selection.class);
61         if (selection == null)
62             throw new IllegalArgumentException("no selection participant");
63         this.diagram = diagram;
64         if (diagram == null)
65             throw new IllegalArgumentException("no diagram");
66     }
67
68     protected Selection getSelectionParticipant() {
69         return ctx.getSingleItem(Selection.class);
70     }
71
72     public DiagramSelectionUpdater setNewSelection(int selectionId, Set<?> newSelection) {
73         this.selectionId = selectionId;
74         this.newSelection.set(newSelection);
75         return this;
76     }
77
78     public Set<?> getNewSelection() {
79         return newSelection.get();
80     }
81
82     public DiagramSelectionUpdater setOneshot(boolean oneshot) {
83         this.oneshot = oneshot;
84         return this;
85     }
86
87     public DiagramSelectionUpdater track() {
88         if (!tracking) {
89             diagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);
90             tracking = true;
91         }
92         return this;
93     }
94
95     public DiagramSelectionUpdater untrack() {
96         if (tracking) {
97             diagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this);
98             tracking = false;
99         }
100         return this;
101     }
102
103     @Override
104     public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
105         if (!ctx.isDisposed() && key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) {
106             if (DEBUG_SELECTION_UPDATE)
107                 System.out.println(getClass().getSimpleName() + ": DIAGRAM UPDATED @" + System.currentTimeMillis() + ", selection to set: " + newSelection);
108             Set<?> ns = newSelection.getAndSet(null);
109             if (ns != null) {
110                 scheduleSetDiagramSelection(2, ns);
111             }
112         }
113
114         if (oneshot) {
115             // Remove self from listening duties.
116             sender.removeHintListener(this);
117         }
118     }
119
120     private void scheduleSetDiagramSelection(final int tries, final Set<?> data) {
121         ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
122             @Override
123             public void run() {
124                 setDiagramSelectionToData(tries, data);
125             }
126         });
127     }
128
129     private void setDiagramSelectionToData(final int tries, final Set<?> data) {
130         if (DEBUG_SELECTION_UPDATE)
131             System.out.println("setDiagramSelectionToData(" + tries + ", " + data + ")");
132
133         DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);
134         if (dem != null) {
135             final Collection<IElement> newSelection = new ArrayList<IElement>(data.size());
136             for (Object datum : data) {
137                 IElement element = dem.getElement(diagram, datum);
138                 if (DEBUG_SELECTION_UPDATE)
139                     System.out.println("  DATUM " + datum + " -> " + element);
140                 if (element != null) {
141                     newSelection.add(element);
142                 } else {
143                     if (tries > 0) {
144                         // Try later if there are tries left.
145                         ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
146                             @Override
147                             public void run() {
148                                 setDiagramSelectionToData(tries - 1, data);
149                             }
150                         });
151                         return;
152                     }
153                     // Otherwise select whatever is found.
154                 }
155             }
156
157             if (DEBUG_SELECTION_UPDATE)
158                 System.out.println("[" + tries + "] final new selection: " + newSelection);
159
160             if (!newSelection.isEmpty()) {
161                 //for (IElement e : newSelection)
162                 //    e.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);
163                 selection.setSelection(selectionId, newSelection);
164             }
165         }
166     }
167
168 }