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