diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2016-06-12 08:25:42 +0000 |
|---|---|---|
| committer | tavmjong-free <tavmjong@free.fr> | 2016-06-12 08:25:42 +0000 |
| commit | 6ed2673499ca548767bb7d2edb453a228ece86fd (patch) | |
| tree | d1a4293bbd40102f2c5aeea26991f05c786ed256 /src/attribute-sort-util.cpp | |
| parent | Extensions: Use underscored variants of parameters / attribute names in inter... (diff) | |
| download | inkscape-6ed2673499ca548767bb7d2edb453a228ece86fd.tar.gz inkscape-6ed2673499ca548767bb7d2edb453a228ece86fd.zip | |
Optionally sort attributes and properties into a canonical order.
Useful for comparing different versions of an SVG file.
(bzr r14980)
Diffstat (limited to 'src/attribute-sort-util.cpp')
| -rw-r--r-- | src/attribute-sort-util.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/attribute-sort-util.cpp b/src/attribute-sort-util.cpp new file mode 100644 index 000000000..ef08a142f --- /dev/null +++ b/src/attribute-sort-util.cpp @@ -0,0 +1,206 @@ +/* + * attribute-sort-util.cpp + * + * Created on: Jun 10, 2016 + * Author: Tavmjong Bah + */ + +/** + * Utility functions for sorting attributes by name. + */ + +#include <fstream> +#include <sstream> +#include <string> +#include <iostream> +#include <vector> +#include <utility> // std::pair +#include <algorithm> // std::sort + +#include "attribute-sort-util.h" + +#include "xml/repr.h" +#include "xml/attribute-record.h" +#include "xml/sp-css-attr.h" + +#include "attributes.h" + +using Inkscape::XML::Node; +using Inkscape::XML::AttributeRecord; +using Inkscape::Util::List; + +/** + * Sort attributes by name. + */ +void sp_attribute_sort_tree(Node *repr) { + + g_return_if_fail (repr != NULL); + + sp_attribute_sort_recursive( repr ); +} + +/** + * Sort recursively over all elements. + */ +void sp_attribute_sort_recursive(Node *repr) { + + g_return_if_fail (repr != NULL); + + if( repr->type() == Inkscape::XML::ELEMENT_NODE ) { + Glib::ustring element = repr->name(); + + // Only sort elements in svg namespace + if( element.substr(0,4) == "svg:" ) { + sp_attribute_sort_element( repr ); + } + } + + for(Node *child=repr->firstChild() ; child ; child = child->next()) { + sp_attribute_sort_recursive( child ); + } +} + +/** + * Compare function + */ +bool cmp(std::pair< Glib::ustring, Glib::ustring > const &a, + std::pair< Glib::ustring, Glib::ustring > const &b) { + unsigned val_b = sp_attribute_lookup(b.first.c_str()); + if (val_b == 0) return true; // Unknown attributes at end. + return sp_attribute_lookup(a.first.c_str()) < val_b; +} + +/** + * Sort attributes on an element + */ +void sp_attribute_sort_element(Node *repr) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE); + + // Glib::ustring element = repr->name(); + // Glib::ustring id = (repr->attribute( "id" )==NULL ? "" : repr->attribute( "id" )); + + sp_attribute_sort_style(repr); + + // Sort attributes: + + // It doesn't seem possible to sort a List directly so we dump the list into + // a std::list and sort that. Not very efficient. Sad. + List<AttributeRecord const> attributes = repr->attributeList(); + + std::vector<std::pair< Glib::ustring, Glib::ustring > > my_list; + for ( List<AttributeRecord const> iter = attributes ; iter ; ++iter ) { + + Glib::ustring attribute = g_quark_to_string(iter->key); + Glib::ustring value = (const char*)iter->value; + + // C++11 my_list.emlace_back(attribute, value); + my_list.push_back(std::make_pair(attribute,value)); + } + std::sort(my_list.begin(), my_list.end(), cmp); + // Delete all attributes. + //for (auto it: my_list) { + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + repr->setAttribute( it->first.c_str(), NULL, false ); + } + // Insert all attributes in proper order + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + repr->setAttribute( it->first.c_str(), it->second.c_str(), false ); + } +} + + +/** + * Sort CSS style on an element. + */ +void sp_attribute_sort_style(Node *repr) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE); + + // Find element's style + SPCSSAttr *css = sp_repr_css_attr( repr, "style" ); + sp_attribute_sort_style(repr, css); + + // Convert css node's properties data to string and set repr node's attribute "style" to that string. + // sp_repr_css_set( repr, css, "style"); // Don't use as it will cause loop. + Glib::ustring value; + sp_repr_css_write_string(css, value); + if( value.empty() ) { + repr->setAttribute("style", NULL ); + } else { + repr->setAttribute("style", value.c_str()); + } + + sp_repr_css_attr_unref( css ); +} + + +/** + * Sort CSS style on an element. + */ +Glib::ustring sp_attribute_sort_style(Node *repr, gchar const *string) { + + g_return_val_if_fail (repr != NULL, NULL); + g_return_val_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE, NULL); + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string( css, string ); + sp_attribute_sort_style(repr, css); + Glib::ustring string_cleaned; + sp_repr_css_write_string (css, string_cleaned); + + sp_repr_css_attr_unref( css ); + + return string_cleaned; +} + + +/** + * Sort CSS style on an element. + */ +void sp_attribute_sort_style(Node* repr, SPCSSAttr *css) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (css != NULL); + + Glib::ustring element = repr->name(); + Glib::ustring id = (repr->attribute( "id" )==NULL ? "" : repr->attribute( "id" )); + + // Loop over all properties in "style" node. + std::vector<std::pair< Glib::ustring, Glib::ustring > > my_list; + for ( List<AttributeRecord const> iter = css->attributeList() ; iter ; ++iter ) { + + Glib::ustring property = g_quark_to_string(iter->key); + Glib::ustring value = (const char*)iter->value; + + // C++11 my_list.emlace_back(property, value); + my_list.push_back(std::make_pair(property,value)); + } + std::sort(my_list.begin(), my_list.end(), cmp); + // Delete all attributes. + //for (auto it: my_list) { + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + sp_repr_css_set_property( css, it->first.c_str(), NULL ); + } + // Insert all attributes in proper order + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + sp_repr_css_set_property( css, it->first.c_str(), it->second.c_str() ); + } +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |
