summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGail Carmichael <gail.banaszkiewicz@gmail.com>2007-07-17 17:39:06 +0000
committergbanaszk <gbanaszk@users.sourceforge.net>2007-07-17 17:39:06 +0000
commit65013deec0bd76a9d120769e045848b547d52a78 (patch)
tree7e622cd36a16704dc250a494e4b0e3009dae6eea /src
parentUnfuzzied (diff)
downloadinkscape-65013deec0bd76a9d120769e045848b547d52a78.tar.gz
inkscape-65013deec0bd76a9d120769e045848b547d52a78.zip
A few additions to ensure that editing trefs is not allowed (and doesn't cause a crash). Also allows all trefs within a selection to be 'unlinked'.
(bzr r3261)
Diffstat (limited to 'src')
-rw-r--r--src/selection-chemistry.cpp14
-rw-r--r--src/sp-tref.cpp119
-rw-r--r--src/sp-tref.h2
-rw-r--r--src/text-context.cpp28
-rw-r--r--src/text-editing.cpp61
-rw-r--r--src/text-editing.h4
6 files changed, 159 insertions, 69 deletions
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index dd6ab6eb8..188ace06b 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -2122,6 +2122,18 @@ sp_selection_unlink()
{
SPItem *item = (SPItem *) items->data;
+ if (SP_IS_TEXT(item)) {
+ SPObject *tspan = sp_tref_convert_to_tspan(SP_OBJECT(item));
+
+ if (tspan) {
+ SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+
+ // Set unlink to true, and fall into the next if which
+ // will include this text item in the new selection
+ unlinked = true;
+ }
+
if (!(SP_IS_USE(item) || SP_IS_TREF(item))) {
// keep the non-use item in the new selection
new_select = g_slist_prepend(new_select, item);
@@ -2132,7 +2144,7 @@ sp_selection_unlink()
if (SP_IS_USE(item)) {
unlink = sp_use_unlink(SP_USE(item));
} else /*if (SP_IS_TREF(use))*/ {
- unlink = SP_ITEM(sp_tref_convert_to_tspan(SP_TREF(item)));
+ unlink = SP_ITEM(sp_tref_convert_to_tspan(SP_OBJECT(item)));
}
unlinked = true;
diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp
index d5479b6cd..28db57990 100644
--- a/src/sp-tref.cpp
+++ b/src/sp-tref.cpp
@@ -559,55 +559,84 @@ build_string_from_root(Inkscape::XML::Node *root, Glib::ustring *retString)
* The code is based partially on sp_use_unlink
*/
SPObject *
-sp_tref_convert_to_tspan(SPTRef *tref)
+sp_tref_convert_to_tspan(SPObject *obj)
{
SPObject * new_tspan = NULL;
- if (tref && tref->stringChild) {
- Inkscape::XML::Node *tref_repr = SP_OBJECT_REPR(tref);
- Inkscape::XML::Node *tref_parent = sp_repr_parent(tref_repr);
+ ////////////////////
+ // BASE CASE
+ ////////////////////
+ if (SP_IS_TREF(obj)) {
- SPDocument *document = SP_OBJECT(tref)->document;
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
-
- Inkscape::XML::Node *new_tspan_repr = xml_doc->createElement("svg:tspan");
-
- // Add the new tspan element just after the current tref
- tref_parent->addChild(new_tspan_repr, tref_repr);
- Inkscape::GC::release(new_tspan_repr);
-
- new_tspan = document->getObjectByRepr(new_tspan_repr);
-
- // Create a new string child for the tspan
- Inkscape::XML::Node *new_string_repr = SP_OBJECT_REPR(tref->stringChild)->duplicate(xml_doc);
- new_tspan_repr->addChild(new_string_repr, NULL);
-
- SPObject * new_string_child = document->getObjectByRepr(new_string_repr);
-
- // Merge style from the tref
- SPStyle *new_tspan_sty = SP_OBJECT_STYLE(new_tspan);
- SPStyle const *tref_sty = SP_OBJECT_STYLE(tref);
- sp_style_merge_from_dying_parent(new_tspan_sty, tref_sty);
- sp_style_merge_from_parent(new_tspan_sty, new_tspan->parent->style);
-
-
- SP_OBJECT(new_tspan)->updateRepr();
-
- // Hold onto our SPObject and repr for now.
- sp_object_ref(SP_OBJECT(tref), NULL);
- Inkscape::GC::anchor(tref_repr);
-
- // Remove ourselves, not propagating delete events to avoid a
- // chain-reaction with other elements that might reference us.
- SP_OBJECT(tref)->deleteObject(false);
-
- // Give the copy our old id and let go of our old repr.
- new_tspan_repr->setAttribute("id", tref_repr->attribute("id"));
- Inkscape::GC::release(tref_repr);
-
- // Establish the succession and let go of our object.
- SP_OBJECT(tref)->setSuccessor(new_tspan);
- sp_object_unref(SP_OBJECT(tref), NULL);
+ SPTRef *tref = SP_TREF(obj);
+
+ if (tref && tref->stringChild) {
+ Inkscape::XML::Node *tref_repr = SP_OBJECT_REPR(tref);
+ Inkscape::XML::Node *tref_parent = sp_repr_parent(tref_repr);
+
+ SPDocument *document = SP_OBJECT(tref)->document;
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+
+ Inkscape::XML::Node *new_tspan_repr = xml_doc->createElement("svg:tspan");
+
+ // Add the new tspan element just after the current tref
+ tref_parent->addChild(new_tspan_repr, tref_repr);
+ Inkscape::GC::release(new_tspan_repr);
+
+ new_tspan = document->getObjectByRepr(new_tspan_repr);
+
+ // Create a new string child for the tspan
+ Inkscape::XML::Node *new_string_repr = SP_OBJECT_REPR(tref->stringChild)->duplicate(xml_doc);
+ new_tspan_repr->addChild(new_string_repr, NULL);
+
+ //SPObject * new_string_child = document->getObjectByRepr(new_string_repr);
+
+ // Merge style from the tref
+ SPStyle *new_tspan_sty = SP_OBJECT_STYLE(new_tspan);
+ SPStyle const *tref_sty = SP_OBJECT_STYLE(tref);
+ sp_style_merge_from_dying_parent(new_tspan_sty, tref_sty);
+ sp_style_merge_from_parent(new_tspan_sty, new_tspan->parent->style);
+
+
+ SP_OBJECT(new_tspan)->updateRepr();
+
+ // Hold onto our SPObject and repr for now.
+ sp_object_ref(SP_OBJECT(tref), NULL);
+ Inkscape::GC::anchor(tref_repr);
+
+ // Remove ourselves, not propagating delete events to avoid a
+ // chain-reaction with other elements that might reference us.
+ SP_OBJECT(tref)->deleteObject(false);
+
+ // Give the copy our old id and let go of our old repr.
+ new_tspan_repr->setAttribute("id", tref_repr->attribute("id"));
+ Inkscape::GC::release(tref_repr);
+
+ // Establish the succession and let go of our object.
+ SP_OBJECT(tref)->setSuccessor(new_tspan);
+ sp_object_unref(SP_OBJECT(tref), NULL);
+ }
+ }
+ ////////////////////
+ // RECURSIVE CASE
+ ////////////////////
+ else {
+ GSList *l = NULL;
+ for (SPObject *child = sp_object_first_child(obj) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
+ sp_object_ref (SP_OBJECT (child), obj);
+ l = g_slist_prepend (l, child);
+ }
+ l = g_slist_reverse (l);
+ while (l) {
+ SPObject *child = SP_OBJECT (l->data);
+ l = g_slist_remove (l, child);
+
+ // Note that there may be more than one conversion happening here, so if it's not a
+ // tref being passed into this function, the returned value can't be specifically known
+ new_tspan = sp_tref_convert_to_tspan(child);
+
+ sp_object_unref (SP_OBJECT (child), obj);
+ }
}
return new_tspan;
diff --git a/src/sp-tref.h b/src/sp-tref.h
index eea8207e3..2e79a28c3 100644
--- a/src/sp-tref.h
+++ b/src/sp-tref.h
@@ -63,7 +63,7 @@ void sp_tref_update_text(SPTRef *tref);
bool sp_tref_reference_allowed(SPTRef *tref, SPObject *possible_ref);
bool sp_tref_fully_contained(SPObject *start_item, Glib::ustring::iterator &start,
SPObject *end_item, Glib::ustring::iterator &end);
-SPObject * sp_tref_convert_to_tspan(SPTRef *item);
+SPObject * sp_tref_convert_to_tspan(SPObject *item);
#endif /* !SP_TREF_H */
diff --git a/src/text-context.cpp b/src/text-context.cpp
index b45cd6e58..f3f974c6f 100644
--- a/src/text-context.cpp
+++ b/src/text-context.cpp
@@ -916,7 +916,9 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
sp_text_context_setup_text(tc);
tc->nascent_object = 0; // we don't need it anymore, having created a real <text>
}
- tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+ tc->text_sel_start = tc->text_sel_end
+ = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, SP_TE_DELETE_OTHER);
+
tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start);
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
@@ -925,9 +927,16 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
return TRUE;
case GDK_BackSpace:
if (tc->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys
- if (tc->text_sel_start == tc->text_sel_end)
+ sp_te_deletion_type deleteType = SP_TE_DELETE_OTHER;
+
+ if (tc->text_sel_start == tc->text_sel_end) {
tc->text_sel_start.prevCursorPosition();
- tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+ deleteType = SP_TE_DELETE_SINGLE_BACKSPACE;
+ }
+
+ tc->text_sel_start = tc->text_sel_end
+ = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, deleteType);
+
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
@@ -937,9 +946,16 @@ sp_text_context_root_handler(SPEventContext *const ec, GdkEvent *const event)
case GDK_Delete:
case GDK_KP_Delete:
if (tc->text) {
- if (tc->text_sel_start == tc->text_sel_end)
+ sp_te_deletion_type deleteType = SP_TE_DELETE_OTHER;
+
+ if (tc->text_sel_start == tc->text_sel_end) {
tc->text_sel_end.nextCursorPosition();
- tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+ deleteType = SP_TE_SINGLE_DELETE;
+ }
+
+ tc->text_sel_start = tc->text_sel_end
+ = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, deleteType);
+
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
sp_document_done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
@@ -1291,7 +1307,7 @@ bool sp_text_delete_selection(SPEventContext *ec)
if (tc->text_sel_start == tc->text_sel_end)
return false;
- tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end);
+ tc->text_sel_start = tc->text_sel_end = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, SP_TE_DELETE_OTHER);
sp_text_context_update_cursor(tc);
sp_text_context_update_text_selection(tc);
return true;
diff --git a/src/text-editing.cpp b/src/text-editing.cpp
index bed837cef..2ad894cc6 100644
--- a/src/text-editing.cpp
+++ b/src/text-editing.cpp
@@ -138,7 +138,7 @@ char * dump_hexy(const gchar * utf8)
Inkscape::Text::Layout::iterator sp_te_replace(SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, gchar const *utf8)
{
- Inkscape::Text::Layout::iterator new_start = sp_te_delete(item, start, end);
+ Inkscape::Text::Layout::iterator new_start = sp_te_delete(item, start, end, SP_TE_DELETE_OTHER);
return sp_te_insert(item, new_start, utf8);
}
@@ -148,13 +148,28 @@ Inkscape::Text::Layout::iterator sp_te_replace(SPItem *item, Inkscape::Text::Lay
static bool is_line_break_object(SPObject const *object)
{
- return SP_IS_TEXT(object)
- || (SP_IS_TSPAN(object) && SP_TSPAN(object)->role != SP_TSPAN_ROLE_UNSPECIFIED)
- || SP_IS_TEXTPATH(object)
- || SP_IS_FLOWDIV(object)
- || SP_IS_FLOWPARA(object)
- || SP_IS_FLOWLINE(object)
- || SP_IS_FLOWREGIONBREAK(object);
+ bool is_line_break = false;
+
+ if (object) {
+ if (SP_IS_TEXT(object)
+ || SP_IS_TEXTPATH(object)
+ || SP_IS_FLOWDIV(object)
+ || SP_IS_FLOWPARA(object)
+ || SP_IS_FLOWLINE(object)
+ || SP_IS_FLOWREGIONBREAK(object)) {
+
+ is_line_break = true;
+ }
+
+ if (SP_IS_TSPAN(object) && SP_TSPAN(object)->role != SP_TSPAN_ROLE_UNSPECIFIED) {
+ SPObject *prev_object = SP_OBJECT_PREV(object);
+ if (prev_object && SP_IS_TSPAN(prev_object)) {
+ is_line_break = true;
+ }
+ }
+ }
+
+ return is_line_break;
}
/** returns the attributes for an object, or NULL if it isn't a text,
@@ -334,7 +349,7 @@ Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *item, Inkscape::Text
{
// Disable newlines in a textpath; TODO: maybe on Enter in a textpath, separate it into two
// texpaths attached to the same path, with a vertical shift
- if (SP_IS_TEXT_TEXTPATH (item))
+ if (SP_IS_TEXT_TEXTPATH (item) || SP_IS_TREF(item))
return position;
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
@@ -350,6 +365,12 @@ Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *item, Inkscape::Text
if (split_obj == 0 || is_line_break_object(split_obj)) {
if (split_obj == 0) split_obj = item->lastChild();
+
+ if (SP_IS_TREF(split_obj)) {
+ desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message);
+ return position;
+ }
+
if (split_obj) {
Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(split_obj));
Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj));
@@ -660,7 +681,8 @@ of figuring out what is a line break and how to delete one. Returns the
lesser of \a start and \a end, because that is where the cursor should be
put after the deletion is done. */
Inkscape::Text::Layout::iterator
-sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end)
+sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start,
+ Inkscape::Text::Layout::iterator const &end, sp_te_deletion_type deletionType)
{
if (start == end) return start;
Inkscape::Text::Layout::iterator first, last;
@@ -701,10 +723,15 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inksc
// If the parent is a tref, editing on this particular string is disallowed.
if (SP_IS_TREF(SP_OBJECT_PARENT(start_item))) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message);
- return end;
+
+ // Compensate so the cursor doesn't move when hitting backspace
+ if (deletionType == SP_TE_DELETE_SINGLE_BACKSPACE) {
+ first = last;
+ }
+
+ } else {
+ erase_from_spstring(SP_STRING(start_item), start_text_iter, end_text_iter);
}
-
- erase_from_spstring(SP_STRING(start_item), start_text_iter, end_text_iter);
}
} else {
SPObject *sub_item = start_item;
@@ -715,7 +742,11 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inksc
// If the parent is a tref, editing on this particular string is disallowed.
if (SP_IS_TREF(SP_OBJECT_PARENT(sub_item))) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message);
- return end;
+ // Compensate so the cursor doesn't move when hitting backspace
+ if (deletionType == SP_TE_DELETE_SINGLE_BACKSPACE) {
+ //first = last;
+ }
+ break;
}
Glib::ustring *string = &SP_STRING(sub_item)->string;
@@ -1686,7 +1717,7 @@ static bool tidy_xml_tree_recursively(SPObject *root)
bool changes = false;
for (SPObject *child = root->firstChild() ; child != NULL ; ) {
- if (SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) {
+ if (SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child) || SP_IS_TREF(child)) {
child = SP_OBJECT_NEXT(child);
continue;
}
diff --git a/src/text-editing.h b/src/text-editing.h
index dba763f75..8955d1e30 100644
--- a/src/text-editing.h
+++ b/src/text-editing.h
@@ -34,9 +34,11 @@ SPStyle const * sp_te_style_at_position(SPItem const *text, Inkscape::Text::Layo
Inkscape::Text::Layout::iterator sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gchar const *utf8);
Inkscape::Text::Layout::iterator sp_te_replace(SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, gchar const *utf8);
-Inkscape::Text::Layout::iterator sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end);
Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *text, Inkscape::Text::Layout::iterator const &position);
+enum sp_te_deletion_type { SP_TE_DELETE_SINGLE_BACKSPACE, SP_TE_SINGLE_DELETE, SP_TE_DELETE_OTHER };
+Inkscape::Text::Layout::iterator sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, sp_te_deletion_type deletionType);
+
gchar *sp_te_get_string_multiline(SPItem const *text);
Glib::ustring sp_te_get_string_multiline(SPItem const *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end);
void sp_te_set_repr_text_multiline(SPItem *text, gchar const *str);