/******************************************************************************* * Copyright (c) 2011 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.synchronization.runtime; import java.util.ArrayList; import java.util.Collection; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.simantics.diagram.ui.DiagramModelHints; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.diagram.handler.DataElementMap; import org.simantics.g2d.diagram.participant.Selection; import org.simantics.g2d.element.IElement; import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintObservable; import org.simantics.utils.threads.ThreadUtils; /** * @author Tuukka Lehtonen */ public class DiagramSelectionUpdater extends HintListenerAdapter { private static final boolean DEBUG_SELECTION_UPDATE = false; private final ICanvasContext ctx; private final Selection selection; private final IDiagram diagram; private int selectionId; private AtomicReference> newSelection = new AtomicReference>(); private boolean oneshot = false; private boolean tracking = false; public DiagramSelectionUpdater(ICanvasContext ctx) { this.ctx = ctx; this.selection = ctx.getAtMostOneItemOfClass(Selection.class); if (selection == null) throw new IllegalArgumentException("no selection participant"); this.diagram = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM); if (diagram == null) throw new IllegalArgumentException("no diagram"); } public DiagramSelectionUpdater(ICanvasContext ctx, IDiagram diagram) { this.ctx = ctx; this.selection = ctx.getAtMostOneItemOfClass(Selection.class); if (selection == null) throw new IllegalArgumentException("no selection participant"); this.diagram = diagram; if (diagram == null) throw new IllegalArgumentException("no diagram"); } protected Selection getSelectionParticipant() { return ctx.getSingleItem(Selection.class); } public DiagramSelectionUpdater setNewSelection(int selectionId, Set newSelection) { this.selectionId = selectionId; this.newSelection.set(newSelection); return this; } public Set getNewSelection() { return newSelection.get(); } public DiagramSelectionUpdater setOneshot(boolean oneshot) { this.oneshot = oneshot; return this; } public DiagramSelectionUpdater track() { if (!tracking) { diagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this); tracking = true; } return this; } public DiagramSelectionUpdater untrack() { if (tracking) { diagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, this); tracking = false; } return this; } @Override public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { if (!ctx.isDisposed() && key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) { if (DEBUG_SELECTION_UPDATE) System.out.println(getClass().getSimpleName() + ": DIAGRAM UPDATED @" + System.currentTimeMillis() + ", selection to set: " + newSelection); Set ns = newSelection.getAndSet(null); if (ns != null) { scheduleSetDiagramSelection(2, ns); } } if (oneshot) { // Remove self from listening duties. sender.removeHintListener(this); } } private void scheduleSetDiagramSelection(final int tries, final Set data) { ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() { @Override public void run() { setDiagramSelectionToData(tries, data); } }); } private void setDiagramSelectionToData(final int tries, final Set data) { if (DEBUG_SELECTION_UPDATE) System.out.println("setDiagramSelectionToData(" + tries + ", " + data + ")"); DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class); if (dem != null) { final Collection newSelection = new ArrayList(data.size()); for (Object datum : data) { IElement element = dem.getElement(diagram, datum); if (DEBUG_SELECTION_UPDATE) System.out.println(" DATUM " + datum + " -> " + element); if (element != null) { newSelection.add(element); } else { if (tries > 0) { // Try later if there are tries left. ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() { @Override public void run() { setDiagramSelectionToData(tries - 1, data); } }); return; } // Otherwise select whatever is found. } } if (DEBUG_SELECTION_UPDATE) System.out.println("[" + tries + "] final new selection: " + newSelection); if (!newSelection.isEmpty()) { //for (IElement e : newSelection) // e.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY); selection.setSelection(selectionId, newSelection); } } } }