View Issue Details

IDProjectCategoryView StatusLast Update
0016784ScribusScripterpublic2024-06-06 03:53
ReporterMattMiller Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version1.6.0.svn 
Summary0016784: Support "Unlink Text Frames and Cut Text"
DescriptionScripter should have some analog to the GUI option "Item | Text Frame Links | Unlink Text Frames and Cut Text."
Additional InformationAttached is a patch to add an optional "cut_text" boolean flag to the current unlinkTextFrames() function. If set the new flag mirrors "Item | Text Frame Links | Unlink Text Frames and Cut Text" the same way that the function without the flag mirrors "Item | Text Frame Links | Unlink Text Frames."

I have some concerns, though:

1. api_textitem.cpp also contains a reference to unlinkTextFrames(), but I don't see how to add a boolean arg to that. Does this file need to be updated?

2. cmdtext.cpp currently has almost no functions with optional arguments other than the optional object name. The attached adds a function with an optional bool. This seems to be related to concern 1. above, since, for example, the current function isTextOverflowing() also uses a boolean, but that function is excluded from api_textitem.cpp.

3. The documentation for unlinkTextFrames() states, "If the frame was in the middle of a chain, the previous and next frames will be connected, eg 'a->b->c' becomes 'a->c' when you unlinkTextFrames(b)." However, I don't see that behavior. Whether I unlink via the GUI or via Scripter, and whether I cut text or not, it seems that breaking a link just separates the chain into two chains. In other words, it seems that the chain 'a->b->c->d' becomes the two chains 'a->b' and 'c->d' when you unlinkTextFrames(c).

Thanks for helping me with my first contribution.
Tagsscripter
PatchYes

Activities

MattMiller

2022-04-23 18:12

reporter  

unlink_and_cut_text.txt (2,327 bytes)   
$ svn diff
Index: Scribus/scribus/plugins/scriptplugin/cmdtext.cpp
===================================================================
--- Scribus/scribus/plugins/scriptplugin/cmdtext.cpp    (revision 25083)
+++ Scribus/scribus/plugins/scriptplugin/cmdtext.cpp    (working copy)
@@ -1329,7 +1329,8 @@
 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
 {
        char *name;
-       if (!PyArg_ParseTuple(args, "es", "utf-8", &name))
+       bool cut_text;
+       if (!PyArg_ParseTuple(args, "es|b", "utf-8", &name, &cut_text))
                return nullptr;
        if (!checkHaveDocument())
                return nullptr;
@@ -1366,7 +1367,14 @@
        for (uint s = 0; s < a2; ++s)
                item->BackBox->itemText.append(item->itemText.take(0));
 */
-       item->prevInChain()->unlink();
+       if (cut_text)
+       {
+               item->unlinkWithText();
+       }
+       else
+       {
+               item->prevInChain()->unlink();
+       }
        // enable 'save icon' stuff
        ScCore->primaryMainWindow()->slotDocCh();
        ScCore->primaryMainWindow()->view->DrawNew();
Index: Scribus/scribus/plugins/scriptplugin_py2x/cmdtext.cpp
===================================================================
--- Scribus/scribus/plugins/scriptplugin_py2x/cmdtext.cpp       (revision 25083)
+++ Scribus/scribus/plugins/scriptplugin_py2x/cmdtext.cpp       (working copy)
@@ -1330,7 +1330,8 @@
 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
 {
        char *name;
-       if (!PyArg_ParseTuple(args, "es", "utf-8", &name))
+       bool cut_text;
+       if (!PyArg_ParseTuple(args, "es|b", "utf-8", &name, &cut_text))
                return nullptr;
        if (!checkHaveDocument())
                return nullptr;
@@ -1367,7 +1368,14 @@
        for (uint s = 0; s < a2; ++s)
                item->BackBox->itemText.append(item->itemText.take(0));
 */
-       item->prevInChain()->unlink();
+       if (cut_text)
+       {
+               item->unlinkWithText();
+       }
+       else
+       {
+               item->prevInChain()->unlink();
+       }
        // enable 'save icon' stuff
        ScCore->primaryMainWindow()->slotDocCh();
        ScCore->primaryMainWindow()->view->DrawNew();
unlink_and_cut_text.txt (2,327 bytes)   

MattMiller

2022-04-24 14:42

reporter   ~0049630

Here's a matching patch for the doc, which also corrects the description of how the linkage looks after an unlink. Let me know if other files need to be updated.
unlink_and_cut_text-doc.txt (1,378 bytes)   
$ svn diff ./Scribus/doc/en/scripterapi-textframes.html
Index: Scribus/doc/en/scripterapi-textframes.html
===================================================================
--- Scribus/doc/en/scripterapi-textframes.html  (revision 25083)
+++ Scribus/doc/en/scripterapi-textframes.html  (working copy)
@@ -246,8 +246,8 @@
 <p>May raise WrongFrameTypeError if the target frame is not an text frame</p></dd>

 <dt><a name="-unlinkTextFrames"><strong>unlinkTextFrames</strong></a>(...)</dt>
-<dd><code>unlinkTextFrames("name")</code>
-<p>Remove the specified (named) object from the text frame flow/linkage. If the frame was in the middle of a chain, the previous and next frames will be connected, eg 'a-&gt;b-&gt;c' becomes 'a-&gt;c' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(b)'</p>
+<dd><code>unlinkTextFrames("name", [cut_text])</code>
+<p>Remove the specified (named) object from the text frame flow/linkage. For example, the chain 'a-&gt;b-&gt;c-&gt;d' becomes the two chains 'a-&gt;b' and 'c-&gt;d' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(c). If "cut_text" is set to a non-zero value the text in the chain is cut to match the new frame linkage, otherwise the text flow ends just before the unlinked frame.</p>
 <p>May throw <a href="#ScribusException">ScribusException</a> if linking rules are violated.</p></dd>

 </dl>
unlink_and_cut_text-doc.txt (1,378 bytes)   

MattMiller

2024-06-05 15:12

reporter   ~0051196

Here's the patch updated to apply to revision 26172:

Index: doc/en/scripterapi-textframes.html
===================================================================
--- doc/en/scripterapi-textframes.html (revision 26172)
+++ doc/en/scripterapi-textframes.html (working copy)
@@ -133,8 +133,8 @@
 

Relayout the whole text chain whom the text frame "name" belongs. If "name" is not given the currently selected item is used.

</dd>

 <dt><a name="-linkTextFrames">linkTextFrames</a>(...)</dt>
-<dd><code>linkTextFrames("fromname", "toname")</code>
-

Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame.


+<dd><code>linkTextFrames("fromname", "toname", [addPARSEP])</code>
+

Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame. If "addPARSEP" is omitted or set to a non-zero value (or True) then a paragraph separator is added to the end of the source frame text if needed to prevent a paragraph from crossing the frames. If "addParsep" is set to zero (or False) then no such paragraph separator is added.


 

May throw #ScribusException if linking rules are violated.

</dd>

 <dt><a name="-selectFrameText">selectFrameText</a>(...)</dt>
@@ -246,8 +246,8 @@
 

May raise WrongFrameTypeError if the target frame is not an text frame

</dd>

 <dt><a name="-unlinkTextFrames">unlinkTextFrames</a>(...)</dt>
-<dd><code>unlinkTextFrames("name")</code>
-

Remove the specified (named) object from the text frame flow/linkage. If the frame was in the middle of a chain, the previous and next frames will be connected, eg 'a->b->c' becomes 'a->c' when you #-unlinkTextFrames(b)'


+<dd><code>unlinkTextFrames("name", [cut_text])</code>
+

Remove the specified (named) object from the text frame flow/linkage. For example, the chain 'a->b->c->d' becomes the two chains 'a->b' and 'c->d' when you #-unlinkTextFrames(c). If "cut_text" is set to a non-zero value (or True) the text in the chain is cut to match the new frame linkage, otherwise the text flow ends just before the unlinked frame.


 

May throw #ScribusException if linking rules are violated.

</dd>

 </dl>
Index: scribus/plugins/scriptplugin/cmdtext.cpp
===================================================================
--- scribus/plugins/scriptplugin/cmdtext.cpp (revision 26172)
+++ scribus/plugins/scriptplugin/cmdtext.cpp (working copy)
@@ -1319,8 +1319,9 @@
 {
        PyESString name1;
        PyESString name2;
+ bool addPARSEP = true;

- if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr()))
+ if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr(), &addPARSEP))
                return nullptr;
        if (!checkHaveDocument())
                return nullptr;
@@ -1351,7 +1352,7 @@
                return nullptr;
        }
        // references to the others boxes
- fromItem->link(toItem);
+ fromItem->link(toItem, addPARSEP);
        ScCore->primaryMainWindow()->view->DrawNew();
        // enable 'save icon' stuff
        ScCore->primaryMainWindow()->slotDocCh();
@@ -1362,7 +1363,8 @@
 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
 {
        PyESString name;
- if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr()))
+ bool cut_text;
+ if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr(), &cut_text))
                return nullptr;
        if (!checkHaveDocument())
                return nullptr;
@@ -1399,7 +1401,14 @@
        for (uint s = 0; s < a2; ++s)
                item->BackBox->itemText.append(item->itemText.take(0));
 */
- item->prevInChain()->unlink();
+ if (cut_text)
+ {
+ item->unlinkWithText();
+ }
+ else
+ {
+ item->prevInChain()->unlink();
+ }
        // enable 'save icon' stuff
        ScCore->primaryMainWindow()->slotDocCh();
        ScCore->primaryMainWindow()->view->DrawNew();

MattMiller

2024-06-05 15:22

reporter   ~0051197

I see that TABs didn't come through in the patch I copied and pasted directly to the note. Here's the patch as an attachment.
svn_diff.txt (4,074 bytes)   
Index: doc/en/scripterapi-textframes.html
===================================================================
--- doc/en/scripterapi-textframes.html	(revision 26172)
+++ doc/en/scripterapi-textframes.html	(working copy)
@@ -133,8 +133,8 @@
 <p>Relayout the whole text chain whom the text frame "name" belongs. If "name" is not given the currently selected item is used.</p></dd>
 
 <dt><a name="-linkTextFrames"><strong>linkTextFrames</strong></a>(...)</dt>
-<dd><code>linkTextFrames("fromname", "toname")</code>
-<p>Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame.</p>
+<dd><code>linkTextFrames("fromname", "toname", [addPARSEP])</code>
+<p>Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame. If "addPARSEP" is omitted or set to a non-zero value (or True) then a paragraph separator is added to the end of the source frame text if needed to prevent a paragraph from crossing the frames. If "addParsep" is set to zero (or False) then no such paragraph separator is added.</p>
 <p>May throw <a href="#ScribusException">ScribusException</a> if linking rules are violated.</p></dd>
 
 <dt><a name="-selectFrameText"><strong>selectFrameText</strong></a>(...)</dt>
@@ -246,8 +246,8 @@
 <p>May raise WrongFrameTypeError if the target frame is not an text frame</p></dd>
 
 <dt><a name="-unlinkTextFrames"><strong>unlinkTextFrames</strong></a>(...)</dt>
-<dd><code>unlinkTextFrames("name")</code>
-<p>Remove the specified (named) object from the text frame flow/linkage. If the frame was in the middle of a chain, the previous and next frames will be connected, eg 'a-&gt;b-&gt;c' becomes 'a-&gt;c' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(b)'</p>
+<dd><code>unlinkTextFrames("name", [cut_text])</code>
+<p>Remove the specified (named) object from the text frame flow/linkage. For example, the chain 'a-&gt;b-&gt;c-&gt;d' becomes the two chains 'a-&gt;b' and 'c-&gt;d' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(c). If "cut_text" is set to a non-zero value (or True) the text in the chain is cut to match the new frame linkage, otherwise the text flow ends just before the unlinked frame.</p>
 <p>May throw <a href="#ScribusException">ScribusException</a> if linking rules are violated.</p></dd>
 
 </dl>
Index: scribus/plugins/scriptplugin/cmdtext.cpp
===================================================================
--- scribus/plugins/scriptplugin/cmdtext.cpp	(revision 26172)
+++ scribus/plugins/scriptplugin/cmdtext.cpp	(working copy)
@@ -1319,8 +1319,9 @@
 {
 	PyESString name1;
 	PyESString name2;
+	bool addPARSEP = true;
 
-	if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr()))
+	if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr(), &addPARSEP))
 		return nullptr;
 	if (!checkHaveDocument())
 		return nullptr;
@@ -1351,7 +1352,7 @@
 		return nullptr;
 	}
 	// references to the others boxes
-	fromItem->link(toItem);
+	fromItem->link(toItem, addPARSEP);
 	ScCore->primaryMainWindow()->view->DrawNew();
 	// enable 'save icon' stuff
 	ScCore->primaryMainWindow()->slotDocCh();
@@ -1362,7 +1363,8 @@
 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
 {
 	PyESString name;
-	if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr()))
+	bool cut_text;
+	if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr(), &cut_text))
 		return nullptr;
 	if (!checkHaveDocument())
 		return nullptr;
@@ -1399,7 +1401,14 @@
 	for (uint s = 0; s < a2; ++s)
 		item->BackBox->itemText.append(item->itemText.take(0));
 */
-	item->prevInChain()->unlink();
+	if (cut_text)
+	{
+		item->unlinkWithText();
+	}
+	else
+	{
+		item->prevInChain()->unlink();
+	}
 	// enable 'save icon' stuff
 	ScCore->primaryMainWindow()->slotDocCh();
 	ScCore->primaryMainWindow()->view->DrawNew();
svn_diff.txt (4,074 bytes)   

MattMiller

2024-06-05 15:40

reporter   ~0051198

On reviewing this patch I see that I also address issue 0016794 here.

ale

2024-06-05 16:06

manager   ~0051199

hi matt

can i suggest you to use a better name than addPARSEP ?

- all caps is not really pythonic
- i would not use abbreviations for the argument name (add_paragraph?)
- no need to document the usage of integers for booleans (even if they might work)
- i would document the default value in the docs' signature ([add_paragraph=True])

also, for compatibility reasons, you should probably set the default to the current behavior (which for cut_text is False...)

MattMiller

2024-06-06 03:53

reporter   ~0051202

ale,

Here's a new patch that makes the suggested changes. Thanks for your help.
svn_diff-2.txt (4,033 bytes)   
Index: doc/en/scripterapi-textframes.html
===================================================================
--- doc/en/scripterapi-textframes.html	(revision 26172)
+++ doc/en/scripterapi-textframes.html	(working copy)
@@ -133,8 +133,8 @@
 <p>Relayout the whole text chain whom the text frame "name" belongs. If "name" is not given the currently selected item is used.</p></dd>
 
 <dt><a name="-linkTextFrames"><strong>linkTextFrames</strong></a>(...)</dt>
-<dd><code>linkTextFrames("fromname", "toname")</code>
-<p>Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame.</p>
+<dd><code>linkTextFrames("fromname", "toname", [add_paragraph=True])</code>
+<p>Link two text frames. The frame named "fromname" is linked to the frame named "toname". The source frame must not already link to another frame. The target frame must not be linked from another frame. If "add_paragraph" is omitted or set to True then a paragraph separator is added to the end of the source frame text if needed to prevent a paragraph from crossing the frames, otherwise no such paragraph separator is added.</p>
 <p>May throw <a href="#ScribusException">ScribusException</a> if linking rules are violated.</p></dd>
 
 <dt><a name="-selectFrameText"><strong>selectFrameText</strong></a>(...)</dt>
@@ -246,8 +246,8 @@
 <p>May raise WrongFrameTypeError if the target frame is not an text frame</p></dd>
 
 <dt><a name="-unlinkTextFrames"><strong>unlinkTextFrames</strong></a>(...)</dt>
-<dd><code>unlinkTextFrames("name")</code>
-<p>Remove the specified (named) object from the text frame flow/linkage. If the frame was in the middle of a chain, the previous and next frames will be connected, eg 'a-&gt;b-&gt;c' becomes 'a-&gt;c' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(b)'</p>
+<dd><code>unlinkTextFrames("name", [cut_text=False])</code>
+<p>Remove the specified (named) object from the text frame flow/linkage. For example, the chain 'a-&gt;b-&gt;c-&gt;d' becomes the two chains 'a-&gt;b' and 'c-&gt;d' when you <a href="#-unlinkTextFrames">unlinkTextFrames</a>(c). If "cut_text" is set to True the text in the chain is cut to match the new frame linkage, otherwise the text flow ends just before the unlinked frame.</p>
 <p>May throw <a href="#ScribusException">ScribusException</a> if linking rules are violated.</p></dd>
 
 </dl>
Index: scribus/plugins/scriptplugin/cmdtext.cpp
===================================================================
--- scribus/plugins/scriptplugin/cmdtext.cpp	(revision 26172)
+++ scribus/plugins/scriptplugin/cmdtext.cpp	(working copy)
@@ -1319,8 +1319,9 @@
 {
 	PyESString name1;
 	PyESString name2;
+	bool add_paragraph = true;
 
-	if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr()))
+	if (!PyArg_ParseTuple(args, "eses", "utf-8", name1.ptr(), "utf-8", name2.ptr(), &add_paragraph))
 		return nullptr;
 	if (!checkHaveDocument())
 		return nullptr;
@@ -1351,7 +1352,7 @@
 		return nullptr;
 	}
 	// references to the others boxes
-	fromItem->link(toItem);
+	fromItem->link(toItem, add_paragraph);
 	ScCore->primaryMainWindow()->view->DrawNew();
 	// enable 'save icon' stuff
 	ScCore->primaryMainWindow()->slotDocCh();
@@ -1362,7 +1363,8 @@
 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
 {
 	PyESString name;
-	if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr()))
+	bool cut_text = false;
+	if (!PyArg_ParseTuple(args, "es", "utf-8", name.ptr(), &cut_text))
 		return nullptr;
 	if (!checkHaveDocument())
 		return nullptr;
@@ -1399,7 +1401,14 @@
 	for (uint s = 0; s < a2; ++s)
 		item->BackBox->itemText.append(item->itemText.take(0));
 */
-	item->prevInChain()->unlink();
+	if (cut_text)
+	{
+		item->unlinkWithText();
+	}
+	else
+	{
+		item->prevInChain()->unlink();
+	}
 	// enable 'save icon' stuff
 	ScCore->primaryMainWindow()->slotDocCh();
 	ScCore->primaryMainWindow()->view->DrawNew();
svn_diff-2.txt (4,033 bytes)   

Issue History

Date Modified Username Field Change
2022-04-23 18:12 MattMiller New Issue
2022-04-23 18:12 MattMiller Tag Attached: scripter
2022-04-23 18:12 MattMiller File Added: unlink_and_cut_text.txt
2022-04-24 14:42 MattMiller Note Added: 0049630
2022-04-24 14:42 MattMiller File Added: unlink_and_cut_text-doc.txt
2024-06-05 15:12 MattMiller Note Added: 0051196
2024-06-05 15:22 MattMiller Note Added: 0051197
2024-06-05 15:22 MattMiller File Added: svn_diff.txt
2024-06-05 15:40 MattMiller Note Added: 0051198
2024-06-05 16:06 ale Note Added: 0051199
2024-06-06 03:53 MattMiller Note Added: 0051202
2024-06-06 03:53 MattMiller File Added: svn_diff-2.txt