[dia] svg: layer import/export via named groups <g id="LayerName"></g>



commit 647ce815ced916b0b35ad7a3f7618e32783ea0dd
Author: Hans Breuer <hans breuer org>
Date:   Sat Sep 29 20:24:27 2012 +0200

    svg: layer import/export via named groups <g id="LayerName"></g>
    
    Export: overwriting DiaRenderer::draw_layer() to wrap every layer's
    objects into their own named group. This seems to be the common way to
    transport layer information via SVG.
    
    Import: Every top level item which is a group with a name/id we are converting
    back to a layer. This is consistent with our SVG export and does
    also work with layers from Sodipodi/Inkscape/iDraw/...

 plug-ins/svg/render_svg.c |   35 +++++++++++++++++++++++++++++++++++
 plug-ins/svg/svg-import.c |   35 ++++++++++++++++++++++++++++++++---
 2 files changed, 67 insertions(+), 3 deletions(-)
---
diff --git a/plug-ins/svg/render_svg.c b/plug-ins/svg/render_svg.c
index 029a0ad..fc25afd 100644
--- a/plug-ins/svg/render_svg.c
+++ b/plug-ins/svg/render_svg.c
@@ -83,6 +83,10 @@ GType svg_renderer_get_type (void) G_GNUC_CONST;
 
 static DiaSvgRenderer *new_svg_renderer(DiagramData *data, const char *filename);
 
+static void draw_layer (DiaRenderer *self,
+			Layer       *layer,
+			gboolean     active,
+			Rectangle   *update);
 static void draw_object       (DiaRenderer *renderer,
                                DiaObject   *object,
 			       DiaMatrix   *matrix);
@@ -201,6 +205,7 @@ svg_renderer_class_init (SvgRendererClass *klass)
 
   renderer_class->begin_render = begin_render;
   renderer_class->end_render = end_render;
+  renderer_class->draw_layer = draw_layer;
   renderer_class->draw_object = draw_object;
   renderer_class->draw_rounded_rect = draw_rounded_rect;
   renderer_class->fill_rounded_rect = fill_rounded_rect;
@@ -271,6 +276,36 @@ new_svg_renderer(DiagramData *data, const char *filename)
 }
 
 /*!
+ * \brief Wrap every layer into it's own group
+ * This method intercepts DiaRenderer::draw_layer() to wrap every layer's
+ * object into their own named group. This seems to be the common way to
+ * transport layer information via SVG.
+ * \memberof SvgRenderer
+ */
+static void
+draw_layer (DiaRenderer *self,
+	    Layer       *layer,
+	    gboolean     active,
+	    Rectangle   *update)
+{
+  DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
+  SvgRenderer *svg_renderer = SVG_RENDERER (self);
+  xmlNodePtr layer_group;
+
+  g_queue_push_tail (svg_renderer->parents, renderer->root);
+
+  /* modifying the root pointer so everything below us gets into the new node */
+  renderer->root = layer_group = xmlNewNode (renderer->svg_name_space, (const xmlChar *)"g");
+
+  if (layer->name)
+    xmlSetProp(renderer->root, (const xmlChar *)"id", (xmlChar *) layer->name);
+
+  DIA_RENDERER_CLASS (parent_class)->draw_layer (self, layer, active, update);
+
+  renderer->root = g_queue_pop_tail (svg_renderer->parents);
+  xmlAddChild (renderer->root, layer_group);
+}
+/*!
  * \brief Wrap every object in \<g\>\</g\> and apply transformation
  *
  * We could try to be smart and count the objects we using for the object.
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index 405c942..e6e1753 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -945,6 +945,10 @@ read_items (xmlNodePtr   startnode,
 
 
   for (node = startnode; node != NULL; node = node->next) {
+    /* Points to the *first* object created by this node (used to be the last one).
+     * Dia may split a single SVG element into multiple DiaObjects. If so these objects
+     * should be grouped or at least inherit all the same node properties
+     */
     DiaObject *obj = NULL;
 
     if (xmlIsBlankNode(node)) continue;
@@ -1022,9 +1026,11 @@ read_items (xmlNodePtr   startnode,
       if (items)
 	obj = g_list_last(items)->data;
     } else if(!xmlStrcmp(node->name, (const xmlChar *)"path")) {
+      /* the path element might be split into multiple objects */
+      int first = g_list_length (items);
       items = read_path_svg(node, parent_gs, items, ctx);
-      if (items)
-	obj = g_list_last(items)->data;
+      if (items && g_list_nth(items, first))
+	obj = g_list_nth(items, first)->data;
     } else if(!xmlStrcmp(node->name, (const xmlChar *)"image")) {
       items = read_image_svg(node, parent_gs, items, filename_svg);
       if (items)
@@ -1096,6 +1102,7 @@ read_items (xmlNodePtr   startnode,
 	    dia_object_set_meta (sub, "url", (char *)href);
 	  }
 	}
+	obj = moreitems->data;
         items = g_list_concat (items, moreitems);
       }
       if (href)
@@ -1210,10 +1217,32 @@ import_svg(const gchar *filename, DiagramData *dia, DiaContext *ctx, void* user_
     items = read_items (root->xmlChildrenNode, NULL, defs_ht, filename, ctx);
     g_hash_table_destroy (defs_ht);
   }
+  /* Every top level item which is a group with a name/id we are converting
+   * back to a layer. This is consistent with our SVG export and does
+   * also work with layers from Sodipodi/Inkscape/iDraw/...
+   */
   for (item = items; item != NULL; item = g_list_next (item)) {
     DiaObject *obj = (DiaObject *)item->data;
-    layer_add_object(dia->active_layer, obj);
+    gchar *name = NULL;
+
+    if (IS_GROUP(obj) && ((name = dia_object_get_meta (obj, "id")) != NULL)) {
+      DiaObject *group = (DiaObject *)item->data;
+      /* new_layer() is taking ownership of the name */
+      Layer *layer = new_layer (g_strdup (name), dia);
+
+      /* layer_add_objects() is taking ownership of the list */
+      layer_add_objects (layer, g_list_copy (group_objects (group)));
+      data_add_layer (dia, layer);
+      group_destroy_shallow (group);
+      g_free (name);
+    } else {
+      /* Just as before: throw it in the active layer */
+      DiaObject *obj = (DiaObject *)item->data;
+      layer_add_object(dia->active_layer, obj);
+    }
+
   }
+
   g_list_free (items);
   xmlFreeDoc(doc);
   /* set 'display' setting */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]