Copying and pasting

Templates

The design of the IBM® ILOG® Dojo Diagrammer can be divided in two main scenarios:
in the first scenario, the Diagram widget is used to display the contents of a data store as a diagram.
in the second scenario, a Selection is typically composed of GFX shapes that are created at the UI level and are not bound to data store.
This division affects the copy-and-paste functionality. In the first scenario, if you copy and paste content in a data store, the duplication occurs in the data store and the graphics reflect the change through dependency updates. In the second scenario, the duplication occurs at the GFX level. A user might also want user data to be stored and applied in the copy-and-paste operations, including user data that is not currently visible. These operations produce different results depending on the scenario used.
To address this variability, the IBM® ILOG® Dojo Diagrammer provides a library with template operations that allow you implement customizations.

Representation

The representation of copied elements must be independent from the context. For example, the representation must be present even if there is no GFX surface active (for example, when there is no DataStore connection). The representation is similar to the serialization algorithm in dojox.gfx, which has this property (independence from platform/renderer). The serialization converts GFX objects into a JSON-compatible JavaScript object representation, independent from the renderer and from the existence of the surface. The same concept is applied for representing copied shapes.

Serialization and deserialization

The class Serializer handles skeleton logic for serialization, and in particular, copy-and-paste operations. Copy operations are serialized into the clipboard, and paste operations are deserialized from the clipboard.
The ibm_ilog.diagram.util.Serializer class has a set of user callbacks that handle the finer details of the data that is copied. The callbacks include a function for getting the identifiers associated with copied entities, and a serialization function for each entity in a graph.
The serialization callbacks generate and return the representation of the associated entity. This data is used by the associated user callback for deserialization, so you must put all the data necessary for reconstruction of the entity in the appropriate context.
The deserialization callbacks create new entities based on their existing representation. These callbacks receive the data serialized by the user callbacks, including a dictionary by ID of all the new entities already created in the deserialization process, and the container in which the new entity is created by the current callback. A deserialization callback must also return an object that represents the newly created entity through the deserialization. This value is stored in the dictionary for further callback calls in the process, and is passed as the container argument in calls to the children of the entity (in the case of subgraphs).
The following callbacks are used in the serialization and deserialization process:
  • getId identifies serialized graph elements through the serialization/deserialization process.
  • serializeNodeData is used to serialize a node. Use this callback function to create the appropriate representation for a node that will later be used by the corresponding deserialization function.
  • serializeLinkData is used to serialize a link. Use this callback function to create the appropriate representation for a link that will later be used by the corresponding deserialization function.
  • serializeSubgraphData is used to serialize a subgraph. Use this callback function to create the appropriate representation for a subgraph that will later be used by the corresponding deserialization function.
  • deserializeNodeData deserializes a node from the serialized data into the given container.
  • deserializeLinkData deserializes a link from the serialized data into the given container.
  • deserializeSubgraphData deserializes a subgraph from the serialized data into the given container.
For copy-and-paste customizations, call the serialize(entity) function and then deserialize(representation,container) function. The entity argument is the object that is serialized. The representation argument is the result obtained from the previous call to serialize, and container is the object compatible with the user-defined objects returned in the deserializeSubgraph callback. The deserialize function collects the results of the user callbacks and returns them in a data structure.

Example

The following example shows how to write a basic data store-based graph serializer:
var serializer = new ibm_ilog.diagram.util.Serializer({
   getId: function(ge) {
      return ge.getId();
   },
   serializeNodeData: function(ge){
      return {
         transform:m.clone(ge.getTransform())
      };
   },
   deserializeNodeData: function(s,newByOldId,container){
      var node = container.graph.createNode();
      node.setTransform(s.transform);
      return {created:node};
   },
   serializeSubgraphData: function(ge){
      return {
         transform:m.clone(ge.getTransform())
      };
   },
   deserializeSubgraphData: function(s,newByOldId,container){
      var sg = container.graph.createSubgraph();
      sg.setTransform(s.transform);
      return {created:sg,graph:sg.getGraph()};
   },
   serializeLinkData: function(ge){
      return {
         startId:ge.getStartNode().getId(),
         endId:ge.getEndNode().getId()
      };
   },
   deserializeLinkData: function(s,newByOldId,container){
      var link = container.graph.createLink();
      link.setStartNode(newByOldId.item(s.startId).created);
      link.setEndNode(newByOldId.item(s.endId).created);
      return {created:link};
   }
});