Code

patch from bug 1497803 by Gustav Broberg; allow to reflow an already flowed text
authorbuliabyak <buliabyak@users.sourceforge.net>
Mon, 8 Jan 2007 11:51:08 +0000 (11:51 +0000)
committerbuliabyak <buliabyak@users.sourceforge.net>
Mon, 8 Jan 2007 11:51:08 +0000 (11:51 +0000)
src/sp-flowtext.cpp
src/sp-flowtext.h
src/text-chemistry.cpp
src/text-chemistry.h
src/verbs.cpp

index 8858d534d0a89ca8cd505c7b8b3204fc58bed194..ec6fd04279c1d82555f0a7b59d36705e6c405321 100644 (file)
@@ -25,6 +25,7 @@
 #include "sp-use.h"
 #include "sp-rect.h"
 #include "text-tag-attributes.h"
+#include "text-chemistry.h"
 
 
 #include "livarot/Shape.h"
@@ -511,40 +512,36 @@ void SPFlowtext::_clearFlow(NRArenaGroup *in_arena)
     }
 }
 
-void SPFlowtext::convert_to_text()
+Inkscape::XML::Node *
+SPFlowtext::getAsText()
 {
-    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-    Inkscape::Selection *selection = sp_desktop_selection(desktop);
-    SPItem *item = selection->singleItem();
-    if (!SP_IS_FLOWTEXT(item)) return;
+    if (!this->layout.outputExists()) return NULL;
 
-    SPFlowtext *group = SP_FLOWTEXT(item);
-
-    if (!group->layout.outputExists()) return;
+    SPItem *item = SP_ITEM(this);
 
     Inkscape::XML::Node *repr = sp_repr_new("svg:text");
     repr->setAttribute("xml:space", "preserve");
-    repr->setAttribute("style", SP_OBJECT_REPR(group)->attribute("style"));
-    NR::Point anchor_point = group->layout.characterAnchorPoint(group->layout.begin());
+    repr->setAttribute("style", SP_OBJECT_REPR(this)->attribute("style"));
+    NR::Point anchor_point = this->layout.characterAnchorPoint(this->layout.begin());
     sp_repr_set_svg_double(repr, "x", anchor_point[NR::X]);
     sp_repr_set_svg_double(repr, "y", anchor_point[NR::Y]);
 
-    for (Inkscape::Text::Layout::iterator it = group->layout.begin() ; it != group->layout.end() ; ) {
-
-           Inkscape::XML::Node *line_tspan = sp_repr_new("svg:tspan");
+    for (Inkscape::Text::Layout::iterator it = this->layout.begin() ; it != this->layout.end() ; ) {
+        Inkscape::XML::Node *line_tspan = sp_repr_new("svg:tspan");
         line_tspan->setAttribute("sodipodi:role", "line");
 
         Inkscape::Text::Layout::iterator it_line_end = it;
         it_line_end.nextStartOfLine();
+
         while (it != it_line_end) {
 
-               Inkscape::XML::Node *span_tspan = sp_repr_new("svg:tspan");
-            NR::Point anchor_point = group->layout.characterAnchorPoint(it);
+            Inkscape::XML::Node *span_tspan = sp_repr_new("svg:tspan");
+            NR::Point anchor_point = this->layout.characterAnchorPoint(it);
             // use kerning to simulate justification and whatnot
             Inkscape::Text::Layout::iterator it_span_end = it;
             it_span_end.nextStartOfSpan();
             Inkscape::Text::Layout::OptionalTextTagAttrs attrs;
-            group->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs);
+            this->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs);
             // set x,y attributes only when we need to
             bool set_x = false;
             bool set_y = false;
@@ -573,9 +570,9 @@ void SPFlowtext::convert_to_text()
             SPObject *source_obj = 0;
             void *rawptr = 0;
             Glib::ustring::iterator span_text_start_iter;
-            group->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter);
+            this->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter);
             source_obj = SP_OBJECT (rawptr);
-            gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, group->style);
+            gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, this->style);
             if (style_text && *style_text) {
                 span_tspan->setAttribute("style", style_text);
                 g_free(style_text);
@@ -586,12 +583,12 @@ void SPFlowtext::convert_to_text()
                 SPObject *span_end_obj = 0;
                 void *rawptr = 0;
                 Glib::ustring::iterator span_text_end_iter;
-                group->layout.getSourceOfCharacter(it_span_end, &rawptr, &span_text_end_iter);
+                this->layout.getSourceOfCharacter(it_span_end, &rawptr, &span_text_end_iter);
                 span_end_obj = SP_OBJECT(rawptr);
                 if (span_end_obj != source_obj) {
-                    if (it_span_end == group->layout.end()) {
+                    if (it_span_end == this->layout.end()) {
                         span_text_end_iter = span_text_start_iter;
-                        for (int i = group->layout.iteratorToCharIndex(it_span_end) - group->layout.iteratorToCharIndex(it) ; i ; --i)
+                        for (int i = this->layout.iteratorToCharIndex(it_span_end) - this->layout.iteratorToCharIndex(it) ; i ; --i)
                             ++span_text_end_iter;
                     } else
                         span_text_end_iter = string->end();    // spans will never straddle a source boundary
@@ -609,24 +606,13 @@ void SPFlowtext::convert_to_text()
             it = it_span_end;
 
             line_tspan->appendChild(span_tspan);
-               Inkscape::GC::release(span_tspan);
+            Inkscape::GC::release(span_tspan);
         }
         repr->appendChild(line_tspan);
-           Inkscape::GC::release(line_tspan);
+        Inkscape::GC::release(line_tspan);
     }
 
-    Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent();
-    parent->appendChild(repr);
-    SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr);
-    sp_item_write_transform(new_item, repr, item->transform);
-    SP_OBJECT(new_item)->updateRepr();
-
-    Inkscape::GC::release(repr);
-    selection->set(new_item);
-    item->deleteObject();
-
-    sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, 
-                     _("Convert flowed text to text"));
+    return repr;
 }
 
 SPItem *SPFlowtext::get_frame(SPItem *after)
index 39f4434405d75db5724c6df94df9dfec75f6efaa..144157dc97cefe2dca5060a6f3a8b7ff4d3d2bb4 100644 (file)
@@ -20,10 +20,9 @@ struct SPFlowtext : public SPItem {
     /** Completely recalculates the layout. */
     void rebuildLayout();
 
-    /** Converts the current selection (which must be a flowroot) into
-    a \<text\> tree, keeping all the formatting and positioning, but losing
-    the automatic wrapping ability. */
-    static void convert_to_text();
+    /** Converts the flowroot in into a \<text\> tree, keeping all the formatting and positioning,
+    but losing the automatic wrapping ability. */
+    Inkscape::XML::Node *getAsText();
 
     SPItem *get_frame(SPItem *after);
 
@@ -56,3 +55,14 @@ GType sp_flowtext_get_type (void);
 SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, NR::Point p1, NR::Point p2);
 
 #endif
+
+/*
+  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:encoding=utf-8:textwidth=99 :
index e2f5b833587f9797437559075e0e412afefef6a9..4ea47fd278fd4caf19e1d9616d5e28126be4c798 100644 (file)
 #include "document.h"
 #include "message-stack.h"
 #include "selection.h"
+#include "style.h"
 #include "desktop-handles.h"
 #include "text-editing.h"
+#include "text-chemistry.h"
 #include "sp-flowtext.h"
 #include "sp-flowregion.h"
 #include "sp-flowdiv.h"
@@ -100,17 +102,32 @@ text_put_on_path()
         return;
     }
 
-    if (SP_IS_FLOWTEXT(text)) {
-        sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put flowtext on a path. Convert flowtext to text first."));
-        return;
-    }
-
     if (SP_IS_RECT(shape)) {
         // rect is the only SPShape which is not <path> yet, and thus SVG forbids us from putting text on it
         sp_desktop_message_stack(desktop)->flash(Inkscape::ERROR_MESSAGE, _("You cannot put text on a rectangle in this version. Convert rectangle to path first."));
         return;
     }
 
+    // if a flowed text is selected, convert it to a regular text object
+    if (SP_IS_FLOWTEXT(text)) {
+        Inkscape::XML::Node *repr = SP_FLOWTEXT(text)->getAsText();
+        Inkscape::XML::Node *parent = SP_OBJECT_REPR(text)->parent();
+        parent->appendChild(repr);
+
+        SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr);
+        sp_item_write_transform(new_item, repr, text->transform);
+        SP_OBJECT(new_item)->updateRepr();
+
+        Inkscape::GC::release(repr);
+        text->deleteObject(); // delete the orignal flowtext
+
+        sp_document_ensure_up_to_date(sp_desktop_document(desktop));
+
+        selection->clear();
+
+        text = new_item; // point to the new text
+    }
+
     Inkscape::Text::Layout const *layout = te_get_layout(text);
     Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin());
 
@@ -255,7 +272,7 @@ text_flow_into_shape()
 
     Inkscape::Selection *selection = sp_desktop_selection(desktop);
 
-    SPItem *text = text_in_selection(selection);
+    SPItem *text = text_or_flowtext_in_selection(selection);
     SPItem *shape = shape_in_selection(selection);
 
     if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) {
@@ -263,9 +280,11 @@ text_flow_into_shape()
         return;
     }
 
-    // remove transform from text, but recursively scale text's fontsize by the expansion
-    SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform));
-    SP_OBJECT_REPR(text)->setAttribute("transform", NULL);
+    if (SP_IS_TEXT(text)) {
+      // remove transform from text, but recursively scale text's fontsize by the expansion
+      SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform));
+      SP_OBJECT_REPR(text)->setAttribute("transform", NULL);
+    }
 
     Inkscape::XML::Node *root_repr = sp_repr_new("svg:flowRoot");
     root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create
@@ -295,16 +314,32 @@ text_flow_into_shape()
         }
     }
 
-    Inkscape::XML::Node *para_repr = sp_repr_new("svg:flowPara");
-    root_repr->appendChild(para_repr);
-    object = doc->getObjectByRepr(para_repr);
-    g_return_if_fail(SP_IS_FLOWPARA(object));
+    if (SP_IS_TEXT(text)) { // flow from text, as string
+        Inkscape::XML::Node *para_repr = sp_repr_new("svg:flowPara");
+        root_repr->appendChild(para_repr);
+        object = doc->getObjectByRepr(para_repr);
+        g_return_if_fail(SP_IS_FLOWPARA(object));
 
-    Inkscape::Text::Layout const *layout = te_get_layout(text);
-    Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end());
+        Inkscape::Text::Layout const *layout = te_get_layout(text);
+        Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end());
+
+        Inkscape::XML::Node *text_repr = sp_repr_new_text(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas!
+        para_repr->appendChild(text_repr);
 
-    Inkscape::XML::Node *text_repr = sp_repr_new_text(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas!
-    para_repr->appendChild(text_repr);
+        Inkscape::GC::release(para_repr);
+        Inkscape::GC::release(text_repr);
+
+    } else { // reflow an already flowed text, preserving paras
+        for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) {
+            if (SP_IS_FLOWPARA(o)) {
+                Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate();
+                root_repr->appendChild(para_repr);
+                object = doc->getObjectByRepr(para_repr);
+                g_return_if_fail(SP_IS_FLOWPARA(object));
+                Inkscape::GC::release(para_repr);
+            }
+        }
+    }
 
     SP_OBJECT(text)->deleteObject (true);
 
@@ -315,8 +350,6 @@ text_flow_into_shape()
 
     Inkscape::GC::release(root_repr);
     Inkscape::GC::release(region_repr);
-    Inkscape::GC::release(para_repr);
-    Inkscape::GC::release(text_repr);
 }
 
 void
@@ -398,6 +431,61 @@ text_unflow ()
                      _("Unflow flowed text"));
 }
 
+void
+flowtext_to_text()
+{
+    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+    Inkscape::Selection *selection = sp_desktop_selection(desktop);
+
+    if (selection->isEmpty()) {
+        sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, 
+                                                 _("Select <b>flowed text(s)</b> to convert."));
+        return;
+    }
+
+    bool did = false;
+
+    GSList *reprs = NULL;
+    GSList *items = g_slist_copy((GSList *) selection->itemList());
+    for (; items != NULL; items = items->next) {
+        
+        SPItem *item = (SPItem *) items->data;
+
+        if (!SP_IS_FLOWTEXT(item))
+            continue;
+
+        did = true;
+
+        Inkscape::XML::Node *repr = SP_FLOWTEXT(item)->getAsText();
+        Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent();
+        parent->appendChild(repr);
+
+        SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr);
+        sp_item_write_transform(new_item, repr, item->transform);
+        SP_OBJECT(new_item)->updateRepr();
+    
+        Inkscape::GC::release(repr);
+        item->deleteObject();
+
+        reprs = g_slist_prepend(reprs, repr);
+    }
+
+    g_slist_free(items);
+
+    if (did) {
+        sp_document_done(sp_desktop_document(desktop), 
+                         SP_VERB_OBJECT_FLOWTEXT_TO_TEXT,
+                         _("Convert flowed text to text"));
+        selection->setReprList(reprs);        
+    } else {
+        sp_desktop_message_stack(desktop)->
+            flash(Inkscape::ERROR_MESSAGE,
+                  _("<b>No flowed text(s)</b> to convert in the selection."));
+    }
+
+    g_slist_free(reprs);
+}
 
 
 /*
index 77fd44a614d375aba5eb2cd074bd242bc957a4ee..7762b8fbcb122c37da5e9ace2c18e84ef7b85ac5 100644 (file)
@@ -19,6 +19,7 @@ void text_remove_from_path (void);
 void text_remove_all_kerns (void);
 void text_flow_into_shape();
 void text_unflow();
+void flowtext_to_text();
 
 #endif
 
index 9c25c761d9afe250b1fd4ce6aa82e517626f92e9..476170e994e4c94926db73c7dc56e67f37b86f13 100644 (file)
@@ -1276,7 +1276,7 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata )
             text_unflow();
             break;
         case SP_VERB_OBJECT_FLOWTEXT_TO_TEXT:
-            SPFlowtext::convert_to_text();
+            flowtext_to_text();
             break;
         case SP_VERB_OBJECT_FLIP_HORIZONTAL:
             if (tools_isactive(dt, TOOLS_NODES)) {