24#include <glibmm/regex.h>
49typedef std::map<Glib::ustring, std::list<IdReference> >
refmap_type;
55 "inkscape:connection-end-point",
56 "inkscape:connection-start",
57 "inkscape:connection-start-point",
59 "inkscape:path-effect",
60 "inkscape:perspectiveID",
61 "inkscape:linked-fill",
62 "inkscape:tiled-clone-of",
65#define NUM_HREF_LIKE_ATTRIBUTES (sizeof(href_like_attributes) / sizeof(*href_like_attributes))
77#define NUM_SPIPAINT_PROPERTIES (sizeof(SPIPaint_properties) / sizeof(*SPIPaint_properties))
87#define NUM_SPISHAPES_PROPERTIES (sizeof(SPIShapes_properties) / sizeof(*SPIShapes_properties))
98#define NUM_OTHER_URL_PROPERTIES (sizeof(other_url_properties) / sizeof(*other_url_properties))
109#define NUM_CLIPBOARD_PROPERTIES (sizeof(clipboard_properties) / sizeof(*clipboard_properties))
116 switch (idref.type) {
118 if (idref.elem->getAttribute(idref.attr)) {
119 gchar *new_uri = g_strdup_printf(
"#%s", to_obj->
getId());
120 Glib::ustring value = idref.elem->getAttribute(idref.attr);
122 Glib::ustring old =
"#";
124 size_t posid = value.find(old_id);
125 if (new_uri && posid != Glib::ustring::npos) {
126 if (!g_strcmp0(idref.attr,
"inkscape:linked-fill")) {
127 value = value.replace(posid, old.size() - 1, to_obj->
getId());
129 value = value.replace(posid - 1, old.size(), new_uri);
131 idref.elem->setAttribute(idref.attr, value.c_str());
144 std::string oid; oid.append(
"url(#").append(old_id).append(
")");
145 auto pos = prop.find(oid);
146 if (pos != std::string::npos) {
147 std::string nid; nid.append(
"url(#").append(to_obj->
getId()).append(
")");
148 prop.replace(pos, oid.size(), nid);
152 std::cerr <<
"Failed to switch id -- shouldn't happen" << std::endl;
157 gchar *url = g_strdup_printf(
"url(#%s)", to_obj->
getId());
158 idref.elem->setAttribute(idref.attr, url);
164 gchar *url = g_strdup_printf(
"url(#%s)", to_obj->
getId());
167 Glib::ustring style_string;
169 idref.elem->setAttributeOrRemoveIfEmpty(
"style", style_string);
184 if (!repr_elem)
return;
188 if (!std::strcmp(repr_elem->
name(),
"inkscape:clipboard")) {
197 refmap[uri.c_str() + 1].push_back(idref);
208 if (!std::strcmp(repr_elem->
name(),
"inkscape:path-effect")) {
209 auto lpeobj = cast<LivePathEffectObject>(elem);
221 const gchar *val = repr_elem->
attribute(p->param_key.c_str());
223 gchar **strarray = g_strsplit(val,
"|", 0);
226 Glib::ustring realycopied =
"";
228 while (strarray[i]) {
229 gchar *splitid = g_strdup(g_strstrip(strarray[i]));
230 if (splitid[0] ==
'#') {
231 std::string id(splitid + 1);
232 if (
size_t pos =
id.find(
",")) {
233 if (pos != Glib::ustring::npos) {
238 IdReference idref = {
REF_HREF, elem, p->param_key.c_str()};
243 bool bypass = ((p->param_key ==
"linkeditem") && cloneoriginal);
247 bypass = bypass && !refobj;
248 if (refobj || bypass) {
250 refmap[id].push_back(idref);
254 if (!realycopied.empty()) {
255 realycopied +=
" | ";
257 realycopied += splitid;
266 repr_elem->
setAttribute(p->param_key.c_str(), realycopied.c_str());
268 g_strfreev(strarray);
278 Glib::ustring attfixed =
"";
280 if (!g_strcmp0(attr,
"inkscape:linked-fill")) {
285 const gchar *val = attfixed.c_str();
286 if (!attfixed.empty() && attfixed[0] ==
'#') {
287 gchar **strarray = g_strsplit(val,
";", 0);
290 while (strarray[i]) {
291 if (strarray[i][0] ==
'#') {
292 std::string id(strarray[i] + 1);
293 IdReference idref = {
REF_HREF, elem, attr};
294 refmap[id].push_back(idref);
298 g_strfreev(strarray);
306 for (
unsigned i = 0; i < NUM_SPIPAINT_PROPERTIES; ++i) {
308 const SPIPaint *paint = &(style->*prop);
312 const gchar *
id = obj->
getId();
314 refmap[id].push_back(idref);
320 for (
unsigned i = 0; i < NUM_SPISHAPES_PROPERTIES; ++i) {
322 const SPIShapes *shapes = &(style->*prop);
323 for (
auto *href : shapes->
hrefs) {
324 auto obj = href->getObject();
327 auto shape_id = obj->getId();
329 refmap[shape_id].push_back(idref);
338 const gchar *
id = obj->
getId();
339 IdReference idref = {
REF_STYLE, elem,
"filter" };
340 refmap[id].push_back(idref);
345 const gchar *markers[4] = {
"",
"marker-start",
"marker-mid",
"marker-end" };
351 IdReference idref = {
REF_STYLE, elem, markers[i] };
352 refmap[uri.c_str() + 1].push_back(idref);
359 const gchar *value = repr_elem->
attribute(attr);
363 IdReference idref = {
REF_URL, elem, attr };
364 refmap[uri.c_str() + 1].push_back(idref);
383 const gchar *
id = elem->
getId();
384 bool fix_clashing_ids =
true;
392 if (is<SPGradient>(elem)) {
395 if (cd_obj && is<SPGradient>(cd_obj)) {
396 auto cd_gr = cast<SPGradient>(cd_obj);
397 if ( cd_gr->isEquivalent(cast<SPGradient>(elem))) {
398 fix_clashing_ids =
false;
403 auto lpeobj = cast<LivePathEffectObject>(elem);
406 auto cd_lpeobj = cast<LivePathEffectObject>(cd_obj);
407 if (cd_lpeobj && lpeobj->is_similar(cd_lpeobj)) {
408 fix_clashing_ids = from_clipboard;
412 if (fix_clashing_ids) {
413 std::string old_id(
id);
414 std::string new_id(old_id +
'-');
416 new_id +=
"0123456789"[std::rand() % 10];
417 const char *str = new_id.c_str();
425 if (refmap.find(old_id) != refmap.end()) {
426 id_changes->emplace_back(elem, old_id);
445 id_changelist_type::const_iterator pp;
446 const id_changelist_type::const_iterator pp_end = id_changes.end();
447 for (pp = id_changes.begin(); pp != pp_end; ++pp) {
449 refmap_type::const_iterator pos = refmap.find(pp->second);
450 std::list<IdReference>::const_iterator it;
451 const std::list<IdReference>::const_iterator it_end = pos->second.end();
452 for (it = pos->second.begin(); it != it_end; ++it) {
453 fix_ref(*it, obj, pp->second.c_str());
471 change_clashing_ids(imported_doc, current_doc, imported_root, refmap, &id_changes, from_clipboard);
483 std::string old_id(from_obj->
getId());
487 refmap_type::const_iterator pos = refmap.find(old_id);
488 if (pos != refmap.end()) {
489 std::list<IdReference>::const_iterator it;
490 const std::list<IdReference>::const_iterator it_end = pos->second.end();
491 for (it = pos->second.begin(); it != it_end; ++it) {
498const char valid_id_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:";
510 if (input_id.empty())
515 pos != Glib::ustring::npos;
517 id.replace(pos, 1,
"_");
521 if (isdigit(
c) ||
c ==
'.' ||
c ==
'-') {
541 g_warning(
"No document provided in %s, ID will not be unique.", __func__);
547 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create(
"(.*)-(\\d{1,9})");
548 Glib::MatchInfo info;
549 regex->match(
id, info);
552 if (info.matches()) {
553 base = info.fetch(1);
554 counter = std::stoul(info.fetch(2));
559 id = base + std::to_string(
counter);
573 if (new_name.empty()){
574 g_message(
"Invalid Id, will not change.");
577 gchar *
id = g_strdup(new_name.c_str());
579 Glib::ustring new_name2 = id;
580 if (!isalnum (new_name2[0])) {
581 g_message(
"Invalid Id, will not change.");
590 std::string old_id(elem->
getId());
598 new_name2 +=
"0123456789"[std::rand() % 10];
608 if (refmap.find(old_id) != refmap.end()) {
609 id_changes.emplace_back(elem, old_id);
Lookup dictionary for attributes/properties.
std::vector< Parameter * > param_vector
Interface for refcounted XML nodes.
virtual char const * name() const =0
Get the name of the element node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual NodeType type() const =0
Get the type of the node.
Typed SVG document implementation.
SPRoot * getRoot()
Returns our SPRoot.
SPObject * getObjectById(std::string const &id) const
SPFilter * getObject() const
Filter type internal to SPStyle.
Paint type internal to SPStyle.
bool isPaintserver() const
std::shared_ptr< SPPaintServerReference > href
Shapes type internal to SPStyle.
std::vector< SPShapeReference * > hrefs
char const * value() const
Get value if set, or inherited value, or default value (may be NULL)
SPObject is an abstract base class of all of the document nodes at the SVG document level.
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
char const * getId() const
Returns the objects current ID string.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
T< SPAttr::SHAPE_INSIDE, SPIShapes > shape_inside
SVG2 Text Wrapping.
T< SPAttr::FILTER, SPIFilter > filter
Filter effect.
SPIString * marker_ptrs[SP_MARKER_LOC_QTY]
T< SPAttr::SHAPE_SUBTRACT, SPIShapes > shape_subtract
std::shared_ptr< Css const > css
void change_def_references(SPObject *from_obj, SPObject *to_obj)
const char * clipboard_properties[]
std::pair< SPObject *, Glib::ustring > id_changeitem_type
const SPIShapes SPStyle::* SPIShapes_members[]
const char * SPIShapes_properties[]
static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, SPObject *elem, refmap_type const &refmap, id_changelist_type *id_changes, bool from_clipboard)
Change any IDs that clash with IDs in the current document, and make a list of those changes that wil...
static void find_references(SPObject *elem, refmap_type &refmap, bool from_clipboard)
Build a table of places where IDs are referenced, for a given element.
const char * other_url_properties[]
const SPIPaint SPStyle::* SPIPaint_members[]
std::list< id_changeitem_type > id_changelist_type
static void fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes)
Fix up references to changed IDs.
std::map< Glib::ustring, std::list< IdReference > > refmap_type
const char valid_id_chars[]
void rename_id(SPObject *elem, Glib::ustring const &new_name)
const char * href_like_attributes[]
static void fix_ref(IdReference const &idref, SPObject *to_obj, const char *old_id)
Given an reference (idref), make it point to to_obj instead.
void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard)
This function resolves ID clashes between the document being imported and the current open document: ...
Glib::ustring sanitize_id(const Glib::ustring &input_id)
Convert string to valid XML id.
const char * SPIPaint_properties[]
Glib::ustring generate_similar_unique_id(SPDocument *document, const Glib::ustring &base_name)
Modify 'base_name' to create a new ID that is not used in the 'document'.
TODO: insert short description here.
GType type()
Returns the type used for storing an object of type T inside a value.
@ ELEMENT_NODE
Regular element node, e.g. <group />.
void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str)
Write a style attribute string from a list of properties stored in an SPCSAttr object.
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
SPCSSAttr * sp_repr_css_attr(Node const *repr, gchar const *attr)
Creates a new SPCSSAttr with one attribute (i.e.
char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
Returns a character string of the value of a given style property or a default value if the attribute...
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
SPRoot: SVG <svg> implementation.
SPStyle internal: classes that are internal to SPStyle.
void sp_style_set_property_url(SPObject *item, gchar const *property, SPObject *linked, bool recursive)
SPStyle - a style object for SPItem objects.
std::string extract_uri(char const *s, char const **endptr)
Parse functional URI notation, as per 4.3.4 of CSS 2.1.
URI functions as per 4.3.4 of CSS 2.1 http://www.w3.org/TR/CSS21/syndata.html#uri.