X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fsynchronization%2Fgraph%2Flayer%2FGraphLayerManager.java;h=41947ef993c49bc937b39eedddb0a0cbf3d25460;hp=b060adaadc2ed359705f0f80109d4ced2453a9ef;hb=d11fef0101853949671492de5b49ea94892ced78;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/layer/GraphLayerManager.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/layer/GraphLayerManager.java index b060adaad..41947ef99 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/layer/GraphLayerManager.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/layer/GraphLayerManager.java @@ -1,537 +1,535 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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.graph.layer; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - -import org.simantics.databoard.Bindings; -import org.simantics.db.AsyncReadGraph; -import org.simantics.db.ReadGraph; -import org.simantics.db.Resource; -import org.simantics.db.WriteGraph; -import org.simantics.db.common.procedure.adapter.AsyncProcedureAdapter; -import org.simantics.db.exception.CancelTransactionException; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.exception.ServiceException; -import org.simantics.db.procedure.AsyncProcedure; -import org.simantics.diagram.stubs.DiagramResource; -import org.simantics.diagram.synchronization.IModificationQueue; -import org.simantics.diagram.synchronization.ModificationAdapter; -import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; -import org.simantics.g2d.diagram.DiagramHints; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.handler.ElementLayers; -import org.simantics.g2d.layers.IEditableLayer; -import org.simantics.g2d.layers.IEditableLayer.ILayerListener; -import org.simantics.g2d.layers.IEditableLayer.LayerChangeEvent; -import org.simantics.g2d.layers.ILayer; -import org.simantics.g2d.layers.ILayers; -import org.simantics.g2d.layers.ILayersEditor; -import org.simantics.g2d.layers.ILayersEditor.ILayersEditorListener; -import org.simantics.g2d.layers.SimpleLayer; -import org.simantics.g2d.layers.SimpleLayers; -import org.simantics.layer0.Layer0; - -/** - * @author Tuukka Lehtonen - */ -public class GraphLayerManager { - - class LayerListener implements ILayersEditorListener, ILayerListener { - @Override - public void layerAdded(final ILayer layer) { - modificationQueue.offer(new CreateLayer(layer, getDiagramResource()), null); - modificationQueue.flush(); - } - - @Override - public void layerRemoved(final ILayer layer) { - modificationQueue.offer(new RemoveLayer(layer, getDiagramResource()), null); - modificationQueue.flush(); - } - - @Override - public void layerActivated(ILayer layer) { - postActivation(layer, true); - } - - @Override - public void layerDeactivated(ILayer layer) { - postActivation(layer, false); - } - - @Override - public void ignoreFocusChanged(boolean value) { - // Ignore, not written to graph. - } - - @Override - public void ignoreVisibilityChanged(boolean value) { - // Ignore, not written to graph. - } - - void postActivation(ILayer layer, boolean activated) { - modificationQueue.offer(new LayerActivation(layer, activated), null); - modificationQueue.flush(); - } - - @Override - public void layerChanged(LayerChangeEvent event) { - LayerChange change = null; - if (IEditableLayer.PROP_NAME.equals(event.getProperty())) { - String oldName = (String) event.getOldValue(); - String newName = (String) event.getNewValue(); - synchronized (layers) { - GraphLayer gl = layers.remove(oldName); - if (gl == null) - return; - layers.put(newName, gl.withName(newName)); - change = new LayerChange(event, gl); - } - } - if (change != null) { - modificationQueue.offer(change, null); - modificationQueue.flush(); - } - } - } - - public static final boolean DEBUG_LAYERS = false; - - IModificationQueue modificationQueue; - Resource diagram; - Layer0 l0; - DiagramResource dia; - - /** - * All the layers currently loaded from the diagram. - */ - ConcurrentMap layers = new ConcurrentHashMap(); - - SimpleLayers layerEditor; - - /** - * The listener for ILayersEditor and all IEditableLayer. - */ - LayerListener layerListener = new LayerListener(); - - public GraphLayerManager(ReadGraph graph, IModificationQueue modificationQueue, Resource diagram) { - this.modificationQueue = modificationQueue; - this.diagram = diagram; - this.l0 = Layer0.getInstance(graph); - this.dia = DiagramResource.getInstance(graph); - } - - public void dispose() { - for (ILayer layer : layerEditor.getLayers()) { - if (layer instanceof IEditableLayer) { - ((IEditableLayer) layer).removeLayerListener(layerListener); - } - } - layers.clear(); - } - - Resource getDiagramResource() { - return diagram; - } - - // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - // LAYERS BEGIN - // ------------------------------------------------------------------------ - - class CreateLayer extends ModificationAdapter { - final ILayer layer; - - final Resource diagram; - - public CreateLayer(ILayer layer, Resource diagram) { - super(LOW_PRIORITY); - assert layer != null; - this.layer = layer; - this.diagram = diagram; - - if (layer instanceof IEditableLayer) { - ((IEditableLayer) layer).addLayerListener(layerListener); - } - } - - @Override - public void perform(WriteGraph g) throws Exception { - String newName = layer.getName(); - for (Resource l : g.getObjects(diagram, dia.HasLayer)) { - String name = g.getRelatedValue(l, l0.HasName); - if (newName.equals(name)) { - return; - } - } - GraphLayer l = new GraphLayerUtil(g).createLayer(newName, false); - g.claim(diagram, dia.HasLayer, l.getLayer()); - layers.put(newName, l); - } - } - - class RemoveLayer extends ModificationAdapter { - final ILayer layer; - - final Resource diagram; - - public RemoveLayer(ILayer layer, Resource diagram) { - super(LOW_PRIORITY); - assert layer != null; - this.layer = layer; - this.diagram = diagram; - - if (layer instanceof IEditableLayer) { - ((IEditableLayer) layer).removeLayerListener(layerListener); - } - } - - @Override - public void perform(WriteGraph g) throws Exception { - String removedName = layer.getName(); - for (Resource l : g.getObjects(diagram, dia.HasLayer)) { - String name = g.getRelatedValue(l, l0.HasName); - if (removedName.equals(name)) { - g.denyStatement(diagram, dia.HasLayer, l); - deleteLayer(g, l); - - // NOTE: leave the layer tags intact, remove them gradually - // by checking the validity of all layer tags during element - // writeback. - layers.remove(name); - return; - } - } - } - - void deleteLayer(WriteGraph g, Resource layer) throws DatabaseException { - g.deny(layer); - } - } - - class LayerActivation extends ModificationAdapter { - final ILayer layer; - - final boolean activated; - - public LayerActivation(ILayer layer, boolean activated) { - super(LOW_PRIORITY); - assert layer != null; - this.layer = layer; - this.activated = activated; - } - - @Override - public void perform(WriteGraph g) throws Exception { - GraphLayer gl = layers.get(layer.getName()); - if (gl == null) - throw new CancelTransactionException("Diagram has no matching layer description: " + layer.getName()); - - g.claimLiteral(gl.getLayer(), dia.IsActive, Boolean.valueOf(activated)); - } - } - - class LayerChange extends ModificationAdapter { - final LayerChangeEvent event; - - final GraphLayer gl; - - public LayerChange(LayerChangeEvent event, GraphLayer gl) { - super(LOW_PRIORITY); - assert event != null; - assert gl != null; - this.event = event; - this.gl = gl; - } - - @Override - public void perform(WriteGraph g) throws Exception { -// Resource name = g.getSingleObject(gl.getLayer(), b.HasName); -// g.claimValue(name, event.getSource().getName()); - g.claimLiteral(gl.getLayer(), l0.HasName, event.getSource().getName(), Bindings.STRING); - } - } - - void deleteTag(WriteGraph g, Resource tag) throws DatabaseException { - g.deny(tag); - } - - Collection getActiveLayers(ReadGraph g) throws DatabaseException { - Collection result = new ArrayList(); - for (GraphLayer gl : layers.values()) { - Boolean active = g.getPossibleRelatedValue(gl.getLayer(), dia.IsActive); - if (Boolean.TRUE.equals(active)) { - result.add(gl); - } - } - return result; - } - - void tagElementWithActiveLayers(WriteGraph g, Resource element) throws DatabaseException { - Collection activeLayers = getActiveLayers(g); - for (GraphLayer activeLayer : activeLayers) { - DiagramGraphUtil.tag(g, element, activeLayer.getVisible(), true); - DiagramGraphUtil.tag(g, element, activeLayer.getFocusable(), true); - } - } - - GraphLayer loadLayer(ReadGraph g, Resource layer) throws DatabaseException { - String name = g.getRelatedValue(layer, l0.HasName); - Resource visible = g.getSingleObject(layer, dia.HasVisibleTag); - Resource focusable = g.getSingleObject(layer, dia.HasFocusableTag); - return new GraphLayer(name, layer, visible, focusable); - } - - public ILayersEditor loadLayers(IDiagram diagram, ReadGraph g, Resource diagramResource) throws DatabaseException { - SimpleLayers result = new SimpleLayers(); - ConcurrentMap newLayers = new ConcurrentHashMap(); - - String[] fixed = diagram.getHint(DiagramHints.KEY_FIXED_LAYERS); - if (fixed != null) { - -// for (String name : fixed) { -// SimpleLayer l = new SimpleLayer(name); -// result.addLayer(l); -// result.activate(l); -// } - - // We need to put GraphLayer to newLayers so... - for (Resource layer : g.getObjects(diagramResource, dia.HasLayer)) { - GraphLayer gl = loadLayer(g, layer); - for (String name : fixed) { - if (name.equals(gl.getName())) { - SimpleLayer l = new SimpleLayer(gl.getName()); - newLayers.put(gl.getName(), gl); - result.addLayer(l); - result.activate(l); - } - } - } - - } else { - - if (DEBUG_LAYERS) - System.out.println("Loading layers"); - - for (Resource layer : g.getObjects(diagramResource, dia.HasLayer)) { - GraphLayer gl = loadLayer(g, layer); - SimpleLayer l = new SimpleLayer(gl.getName()); - - newLayers.put(gl.getName(), gl); - result.addLayer(l); - - Boolean active = g.getPossibleRelatedValue(layer, dia.IsActive); - if (active == null) - active = Boolean.FALSE; - - if (DEBUG_LAYERS) - System.out.println(" Loaded " + (active ? "active" : "inactive") + " layer '" + gl.getName() + "'"); - - l.addLayerListener(layerListener); - if (active) - result.activate(l); - } - - if (DEBUG_LAYERS) - System.out.println("Loaded " + newLayers.size() + " layers"); - - } - - this.layers = newLayers; - this.layerEditor = result; - this.layerEditor.addListener(layerListener); - - return result; - } - - public void loadLayersForElement(ReadGraph graph, ILayersEditor layersEditor, IElement e, Resource element) - throws DatabaseException { - if (DEBUG_LAYERS) - System.out.println("Loading layers for element " + element + " - " + e); - - Set visible = null; - Set focusable = null; - - for (ILayer l : layersEditor.getLayers()) { - GraphLayer gl = layers.get(l.getName()); - if (gl != null) { - if (graph.hasStatement(element, gl.getVisible(), element)) { - if (visible == null) - visible = new HashSet(4); - visible.add(l); - if (DEBUG_LAYERS) - System.out.println(" Visible on layer '" + gl.getName() + "'"); - } - if (graph.hasStatement(element, gl.getFocusable(), element)) { - if (focusable == null) - focusable = new HashSet(4); - focusable.add(l); - if (DEBUG_LAYERS) - System.out.println(" Focusable on layer '" + gl.getName() + "'"); - } - } - } - - if (visible == null) - visible = new HashSet(1); - if (focusable == null) - focusable = new HashSet(1); - - e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); - e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); - } - - /** - * @param graph - * @param layersEditor - * @param e - * @param element - * @param procedure a procedure whose exception method may be called 0 to - * many times depending on how many errors occur during layer loading - * @throws DatabaseException - */ - public void loadLayersForElement(AsyncReadGraph graph, ILayersEditor layersEditor, final IElement e, - Resource element, final AsyncProcedure callback) { - if (DEBUG_LAYERS) - System.out.println("Loading layers for element " + element + " - " + e); - - final Set visible = new HashSet(2); - final Set focusable = new HashSet(2); - - // NOTE: must not set layer hints into element until the layer sets have - // been properly loaded. - - Set allLayers = layersEditor.getLayers(); - if (allLayers.isEmpty()) { - e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); - e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); - callback.execute(graph, e); - return; - } - - final AtomicInteger ready = new AtomicInteger(allLayers.size() * 2); - - for (final ILayer l : allLayers) { - final GraphLayer gl = layers.get(l.getName()); - if (gl != null) { - graph.forHasStatement(element, gl.getVisible(), element, new AsyncProcedureAdapter() { - @Override - public void execute(AsyncReadGraph graph, Boolean result) { - synchronized (visible) { - visible.add(l); - } - if (DEBUG_LAYERS) - System.out.println(" Visible on layer '" + gl.getName() + "'"); - if (ready.decrementAndGet() == 0) { - e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); - e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); - callback.execute(graph, e); - } - } - @Override - public void exception(AsyncReadGraph graph, Throwable t) { - callback.exception(graph, t); - } - }); - graph.forHasStatement(element, gl.getFocusable(), element, new AsyncProcedureAdapter() { - @Override - public void execute(AsyncReadGraph graph, Boolean result) { - synchronized (focusable) { - focusable.add(l); - } - if (DEBUG_LAYERS) - System.out.println(" Focusable on layer '" + gl.getName() + "'"); - if (ready.decrementAndGet() == 0) { - e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); - e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); - callback.execute(graph, e); - } - } - @Override - public void exception(AsyncReadGraph graph, Throwable t) { - callback.exception(graph, t); - } - }); - - } else { - - if (ready.addAndGet(-2) == 0) { - e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); - e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); - callback.execute(graph, e); - } - - } - } - } - - void putElementOnVisibleLayers(IDiagram diagram, IElement element) { - // Make the new element visible and focusable on all currently - // active layers. - ILayers diagramLayers = diagram.getHint(DiagramHints.KEY_LAYERS); - if (diagramLayers != null) { - element.setHint(ElementHints.KEY_VISIBLE_LAYERS, new HashSet()); - element.setHint(ElementHints.KEY_FOCUS_LAYERS, new HashSet()); - Set visibleLayers = diagramLayers.getVisibleLayers(); - - if (DEBUG_LAYERS) - System.out.println("Marking element visible and focusable only on visible layers: " + visibleLayers); - - for (ElementLayers elementLayers : element.getElementClass().getItemsByClass(ElementLayers.class)) { - for (ILayer layer : visibleLayers) { - elementLayers.setVisibility(element, layer, true); - elementLayers.setFocusability(element, layer, true); - } - } - } - } - - public void putElementOnVisibleLayers(IDiagram diagram, WriteGraph g, Resource element) throws DatabaseException { - // Make the new element visible and focusable on all currently - // active layers. - ILayers diagramLayers = diagram.getHint(DiagramHints.KEY_LAYERS); - if (diagramLayers != null) { - Set visibleLayers = diagramLayers.getVisibleLayers(); - - if (DEBUG_LAYERS) - System.out.println("Marking element visible and focusable in the graph on visible layers: " - + visibleLayers); - - for (ILayer layer : visibleLayers) { - GraphLayer gl = layers.get(layer.getName()); - if (gl != null) { - DiagramGraphUtil.tag(g, element, gl.getVisible(), true); - DiagramGraphUtil.tag(g, element, gl.getFocusable(), true); - } - } - } - } - - public void removeFromAllLayers(WriteGraph graph, Resource element) throws ServiceException { - // Remove element from all layers. - graph.deny(element, dia.IsVisible); - graph.deny(element, dia.IsFocusable); - } - - public GraphLayer getGraphLayer(String name) { - return layers.get(name); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 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.graph.layer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +import org.simantics.databoard.Bindings; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.procedure.adapter.AsyncProcedureAdapter; +import org.simantics.db.exception.CancelTransactionException; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.procedure.AsyncProcedure; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.diagram.synchronization.IModificationQueue; +import org.simantics.diagram.synchronization.ModificationAdapter; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.g2d.diagram.DiagramHints; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.ElementLayers; +import org.simantics.g2d.layers.IEditableLayer; +import org.simantics.g2d.layers.IEditableLayer.ILayerListener; +import org.simantics.g2d.layers.IEditableLayer.LayerChangeEvent; +import org.simantics.g2d.layers.ILayer; +import org.simantics.g2d.layers.ILayers; +import org.simantics.g2d.layers.ILayersEditor; +import org.simantics.g2d.layers.ILayersEditor.ILayersEditorListener; +import org.simantics.g2d.layers.SimpleLayers; +import org.simantics.layer0.Layer0; + +/** + * @author Tuukka Lehtonen + */ +public class GraphLayerManager { + + class LayerListener implements ILayersEditorListener, ILayerListener { + @Override + public void layerAdded(final ILayer layer) { + modificationQueue.offer(new CreateLayer(layer, getDiagramResource()), null); + modificationQueue.flush(); + } + + @Override + public void layerRemoved(final ILayer layer) { + modificationQueue.offer(new RemoveLayer(layer, getDiagramResource()), null); + modificationQueue.flush(); + } + + @Override + public void layerActivated(ILayer layer) { + postActivation(layer, true); + } + + @Override + public void layerDeactivated(ILayer layer) { + postActivation(layer, false); + } + + @Override + public void ignoreFocusChanged(boolean value) { + // Ignore, not written to graph. + } + + @Override + public void ignoreVisibilityChanged(boolean value) { + // Ignore, not written to graph. + } + + void postActivation(ILayer layer, boolean activated) { + modificationQueue.offer(new LayerActivation(layer, activated), null); + modificationQueue.flush(); + } + + @Override + public void layerChanged(LayerChangeEvent event) { + LayerChange change = null; + if (IEditableLayer.PROP_NAME.equals(event.getProperty())) { + String oldName = (String) event.getOldValue(); + String newName = (String) event.getNewValue(); + synchronized (layers) { + GraphLayer gl = layers.remove(oldName); + if (gl == null) + return; + layers.put(newName, gl.withName(newName)); + change = new LayerChange(event, gl); + } + } + if (change != null) { + modificationQueue.offer(change, null); + modificationQueue.flush(); + } + } + } + + public static final boolean DEBUG_LAYERS = false; + + IModificationQueue modificationQueue; + Resource diagram; + Layer0 l0; + DiagramResource dia; + + /** + * All the layers currently loaded from the diagram. + */ + ConcurrentMap layers = new ConcurrentHashMap(); + + SimpleLayers layerEditor; + + /** + * The listener for ILayersEditor and all IEditableLayer. + */ + LayerListener layerListener = new LayerListener(); + + public GraphLayerManager(ReadGraph graph, IModificationQueue modificationQueue, Resource diagram) { + this.modificationQueue = modificationQueue; + this.diagram = diagram; + this.l0 = Layer0.getInstance(graph); + this.dia = DiagramResource.getInstance(graph); + } + + public void dispose() { + for (ILayer layer : layerEditor.getLayers()) { + if (layer instanceof IEditableLayer) { + ((IEditableLayer) layer).removeLayerListener(layerListener); + } + } + layers.clear(); + } + + Resource getDiagramResource() { + return diagram; + } + + // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + // LAYERS BEGIN + // ------------------------------------------------------------------------ + + class CreateLayer extends ModificationAdapter { + final ILayer layer; + + final Resource diagram; + + public CreateLayer(ILayer layer, Resource diagram) { + super(LOW_PRIORITY); + assert layer != null; + this.layer = layer; + this.diagram = diagram; + + if (layer instanceof IEditableLayer) { + ((IEditableLayer) layer).addLayerListener(layerListener); + } + } + + @Override + public void perform(WriteGraph g) throws Exception { + String newName = layer.getName(); + for (Resource layer : g.getObjects(diagram, dia.HasLayer)) { + String name = g.getRelatedValue(layer, l0.HasName); + if (newName.equals(name)) { + return; + } + } + + IGraphLayerUtil util = g.adapt(DiagramResource.getInstance(g).Layer, IGraphLayerUtil.class); + GraphLayer layer = util.createLayer(g, newName, false); + g.claim(diagram, dia.HasLayer, layer.getLayer()); + layers.put(newName, layer); + } + } + + class RemoveLayer extends ModificationAdapter { + final ILayer layer; + + final Resource diagram; + + public RemoveLayer(ILayer layer, Resource diagram) { + super(LOW_PRIORITY); + assert layer != null; + this.layer = layer; + this.diagram = diagram; + + if (layer instanceof IEditableLayer) { + ((IEditableLayer) layer).removeLayerListener(layerListener); + } + } + + @Override + public void perform(WriteGraph g) throws Exception { + String removedName = layer.getName(); + for (Resource l : g.getObjects(diagram, dia.HasLayer)) { + String name = g.getRelatedValue(l, l0.HasName); + if (removedName.equals(name)) { + g.denyStatement(diagram, dia.HasLayer, l); + deleteLayer(g, l); + + // NOTE: leave the layer tags intact, remove them gradually + // by checking the validity of all layer tags during element + // writeback. + layers.remove(name); + return; + } + } + } + + void deleteLayer(WriteGraph g, Resource layer) throws DatabaseException { + g.deny(layer); + } + } + + class LayerActivation extends ModificationAdapter { + final ILayer layer; + + final boolean activated; + + public LayerActivation(ILayer layer, boolean activated) { + super(LOW_PRIORITY); + assert layer != null; + this.layer = layer; + this.activated = activated; + } + + @Override + public void perform(WriteGraph g) throws Exception { + GraphLayer gl = layers.get(layer.getName()); + if (gl == null) + throw new CancelTransactionException("Diagram has no matching layer description: " + layer.getName()); + + g.claimLiteral(gl.getLayer(), dia.IsActive, Boolean.valueOf(activated)); + } + } + + class LayerChange extends ModificationAdapter { + final LayerChangeEvent event; + + final GraphLayer gl; + + public LayerChange(LayerChangeEvent event, GraphLayer gl) { + super(LOW_PRIORITY); + assert event != null; + assert gl != null; + this.event = event; + this.gl = gl; + } + + @Override + public void perform(WriteGraph g) throws Exception { +// Resource name = g.getSingleObject(gl.getLayer(), b.HasName); +// g.claimValue(name, event.getSource().getName()); + g.claimLiteral(gl.getLayer(), l0.HasName, event.getSource().getName(), Bindings.STRING); + } + } + + void deleteTag(WriteGraph g, Resource tag) throws DatabaseException { + g.deny(tag); + } + + Collection getActiveLayers(ReadGraph g) throws DatabaseException { + Collection result = new ArrayList(); + for (GraphLayer gl : layers.values()) { + Boolean active = g.getPossibleRelatedValue(gl.getLayer(), dia.IsActive); + if (Boolean.TRUE.equals(active)) { + result.add(gl); + } + } + return result; + } + + void tagElementWithActiveLayers(WriteGraph g, Resource element) throws DatabaseException { + Collection activeLayers = getActiveLayers(g); + for (GraphLayer activeLayer : activeLayers) { + DiagramGraphUtil.tag(g, element, activeLayer.getVisible(), true); + DiagramGraphUtil.tag(g, element, activeLayer.getFocusable(), true); + } + } + + public ILayersEditor loadLayers(IDiagram diagram, ReadGraph g, Resource diagramResource) throws DatabaseException { + + SimpleLayers result = new SimpleLayers(); + ConcurrentMap newLayers = new ConcurrentHashMap(); + + String[] fixed = diagram.getHint(DiagramHints.KEY_FIXED_LAYERS); + if (fixed != null) { + +// for (String name : fixed) { +// SimpleLayer l = new SimpleLayer(name); +// result.addLayer(l); +// result.activate(l); +// } + + // We need to put GraphLayer to newLayers so... + for (Resource layer : g.getObjects(diagramResource, dia.HasLayer)) { + IGraphLayerUtil layerUtil = g.adapt(g.getSingleObject(layer, Layer0.getInstance(g).InstanceOf), IGraphLayerUtil.class); + + GraphLayer gl = layerUtil.loadLayer(g, layer); + for (String name : fixed) { + if (name.equals(gl.getName())) { + ILayer l = gl.getILayer(); + newLayers.put(gl.getName(), gl); + result.addLayer(l); + result.activate(l); + } + } + } + + } else { + + if (DEBUG_LAYERS) + System.out.println("Loading layers"); + + for (Resource layer : g.getObjects(diagramResource, dia.HasLayer)) { + IGraphLayerUtil layerUtil = g.adapt(g.getSingleObject(layer, Layer0.getInstance(g).InstanceOf), IGraphLayerUtil.class); + GraphLayer gl = layerUtil.loadLayer(g, layer); + ILayer l = gl.getILayer(); + + newLayers.put(gl.getName(), gl); + result.addLayer(l); + + Boolean active = g.getPossibleRelatedValue(layer, dia.IsActive); + if (active == null) + active = Boolean.FALSE; + + if (DEBUG_LAYERS) + System.out.println(" Loaded " + (active ? "active" : "inactive") + " layer '" + gl.getName() + "'"); + + if (l instanceof IEditableLayer) + ((IEditableLayer) l).addLayerListener(layerListener); + if (active) + result.activate(l); + } + + if (DEBUG_LAYERS) + System.out.println("Loaded " + newLayers.size() + " layers"); + + } + + this.layers = newLayers; + this.layerEditor = result; + this.layerEditor.addListener(layerListener); + + return result; + } + + public void loadLayersForElement(ReadGraph graph, ILayersEditor layersEditor, IElement e, Resource element) + throws DatabaseException { + if (DEBUG_LAYERS) + System.out.println("Loading layers for element " + element + " - " + e); + + Set visible = null; + Set focusable = null; + + for (ILayer l : layersEditor.getLayers()) { + GraphLayer gl = layers.get(l.getName()); + if (gl != null) { + if (graph.hasStatement(element, gl.getVisible(), element)) { + if (visible == null) + visible = new HashSet(4); + visible.add(l); + if (DEBUG_LAYERS) + System.out.println(" Visible on layer '" + gl.getName() + "'"); + } + if (graph.hasStatement(element, gl.getFocusable(), element)) { + if (focusable == null) + focusable = new HashSet(4); + focusable.add(l); + if (DEBUG_LAYERS) + System.out.println(" Focusable on layer '" + gl.getName() + "'"); + } + } + } + + if (visible == null) + visible = new HashSet(1); + if (focusable == null) + focusable = new HashSet(1); + + e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); + e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); + } + + /** + * @param graph + * @param layersEditor + * @param e + * @param element + * @param procedure a procedure whose exception method may be called 0 to + * many times depending on how many errors occur during layer loading + * @throws DatabaseException + */ + public void loadLayersForElement(AsyncReadGraph graph, ILayersEditor layersEditor, final IElement e, + Resource element, final AsyncProcedure callback) { + if (DEBUG_LAYERS) + System.out.println("Loading layers for element " + element + " - " + e); + + final Set visible = new HashSet(2); + final Set focusable = new HashSet(2); + + // NOTE: must not set layer hints into element until the layer sets have + // been properly loaded. + + Set allLayers = layersEditor.getLayers(); + if (allLayers.isEmpty()) { + e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); + e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); + callback.execute(graph, e); + return; + } + + final AtomicInteger ready = new AtomicInteger(allLayers.size() * 2); + + for (final ILayer l : allLayers) { + final GraphLayer gl = layers.get(l.getName()); + if (gl != null) { + graph.forHasStatement(element, gl.getVisible(), element, new AsyncProcedureAdapter() { + @Override + public void execute(AsyncReadGraph graph, Boolean result) { + synchronized (visible) { + visible.add(l); + } + if (DEBUG_LAYERS) + System.out.println(" Visible on layer '" + gl.getName() + "'"); + if (ready.decrementAndGet() == 0) { + e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); + e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); + callback.execute(graph, e); + } + } + @Override + public void exception(AsyncReadGraph graph, Throwable t) { + callback.exception(graph, t); + } + }); + graph.forHasStatement(element, gl.getFocusable(), element, new AsyncProcedureAdapter() { + @Override + public void execute(AsyncReadGraph graph, Boolean result) { + synchronized (focusable) { + focusable.add(l); + } + if (DEBUG_LAYERS) + System.out.println(" Focusable on layer '" + gl.getName() + "'"); + if (ready.decrementAndGet() == 0) { + e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); + e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); + callback.execute(graph, e); + } + } + @Override + public void exception(AsyncReadGraph graph, Throwable t) { + callback.exception(graph, t); + } + }); + + } else { + + if (ready.addAndGet(-2) == 0) { + e.setHint(ElementHints.KEY_VISIBLE_LAYERS, visible); + e.setHint(ElementHints.KEY_FOCUS_LAYERS, focusable); + callback.execute(graph, e); + } + + } + } + } + + void putElementOnVisibleLayers(IDiagram diagram, IElement element) { + // Make the new element visible and focusable on all currently + // active layers. + ILayers diagramLayers = diagram.getHint(DiagramHints.KEY_LAYERS); + if (diagramLayers != null) { + element.setHint(ElementHints.KEY_VISIBLE_LAYERS, new HashSet()); + element.setHint(ElementHints.KEY_FOCUS_LAYERS, new HashSet()); + Set visibleLayers = diagramLayers.getVisibleLayers(); + + if (DEBUG_LAYERS) + System.out.println("Marking element visible and focusable only on visible layers: " + visibleLayers); + + for (ElementLayers elementLayers : element.getElementClass().getItemsByClass(ElementLayers.class)) { + for (ILayer layer : visibleLayers) { + elementLayers.setVisibility(element, layer, true); + elementLayers.setFocusability(element, layer, true); + } + } + } + } + + public void putElementOnVisibleLayers(IDiagram diagram, WriteGraph g, Resource element) throws DatabaseException { + // Make the new element visible and focusable on all currently + // active layers. + ILayers diagramLayers = diagram.getHint(DiagramHints.KEY_LAYERS); + if (diagramLayers != null) { + Set visibleLayers = diagramLayers.getVisibleLayers(); + + if (DEBUG_LAYERS) + System.out.println("Marking element visible and focusable in the graph on visible layers: " + + visibleLayers); + + for (ILayer layer : visibleLayers) { + GraphLayer gl = layers.get(layer.getName()); + if (gl != null) { + gl.forEachTag(tag -> DiagramGraphUtil.tag(g, element, tag, true)); + } + } + } + } + + public void removeFromAllLayers(WriteGraph graph, Resource element) throws ServiceException { + // Remove element from all layers. + graph.deny(element, dia.IsVisible); + graph.deny(element, dia.IsFocusable); + } + + public GraphLayer getGraphLayer(String name) { + return layers.get(name); + } + +}