View Issue Details

IDProjectCategoryView StatusLast Update
0016000ScribusScripterpublic2020-08-11 20:56
Reporterale Assigned Toale  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version1.5.6.svn 
Fixed in Version1.5.6.svn 
Summary0016000: Scripter: behavior of setCharacterStyle() depends on the frame name being defined
DescriptionsetCharacterStyle() applies the style to the whole frame when no frame name is passed as argument and to the current selection when a frame name is passed.

this the actual behavior and the documented one.

the behavior should be changed to always apply the style to the current selection if one is defined.

using character styles in the scripter is a rather new thing, and i don't think that there is anybody relying on this behavior to set the charstyle of the full frame.
TagsNo tags attached.
PatchYes

Activities

ale

2019-12-12 15:20

manager   ~0047252

i've patched both the setStyle and setCharacterStyle to behave in a new way:

from the new docstring:

- Apply the style named "style".
- If name is not specified, the current selected item is used.
- If the current item has a text selection, the style is applied to the selection.

this corresponds -- as an example -- to the behavior of getStyle().

i can't think that somebody is relying on the current behavior, where -- despite a selection being defined -- the style is applied to the frame if no name is defined for the current item.
in such a ca case, a sane script will make sure that there is no text selection before applying the style to the item.
scripter-setstyle.diff (7,652 bytes)   
diff --git a/scribus/plugins/scriptplugin/cmdobj.cpp b/scribus/plugins/scriptplugin/cmdobj.cpp
index 04534b865..e3a96a89f 100644
--- a/scribus/plugins/scriptplugin/cmdobj.cpp
+++ b/scribus/plugins/scriptplugin/cmdobj.cpp
@@ -641,63 +641,36 @@ PyObject *scribus_setstyle(PyObject* /* self */, PyObject* args)
 		return nullptr;
 	}
 
-	// First, find the style number associated with the requested style
-	// by scanning through the styles looking for the name. If
-	// we can't find it, raise PyExc_Exception.
-	// FIXME: Should use a more specific exception.
-	bool found = false;
-	QString paraStyleName = QString::fromUtf8(style);
-	// We start at zero here because it's OK to match an internal name
+	QString styleName = QString::fromUtf8(style);
+	QString itemName = QString::fromUtf8(name);
+
 	ScribusDoc*  currentDoc = ScCore->primaryMainWindow()->doc;
 	ScribusView* currentView = ScCore->primaryMainWindow()->view;
-	ScribusMainWindow* currentWin = ScCore->primaryMainWindow();
-	const StyleSet<ParagraphStyle> &docParagraphStyles = currentDoc->paragraphStyles();
-	int docParagraphStylesCount = docParagraphStyles.count();
-	for (int i=0; i < docParagraphStylesCount; ++i)
+
+	if (!currentDoc->paragraphStyles().contains(styleName))
 	{
-		if (docParagraphStyles[i].name() == paraStyleName) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
-		// whoops, the user specified an invalid style, complain loudly.
 		PyErr_SetString(NotFoundError, QObject::tr("Style not found.","python error").toLocal8Bit().constData());
 		return nullptr;
 	}
-	// for current item only
-	if (currentDoc->m_Selection->isEmpty() || (strlen(name) > 0))
+
+	int mode{modeNormal};
+	bool isCurrentItem = itemName.isEmpty() || itemName == currentDoc->m_Selection->itemAt(0)->itemName();
+
+	if (!isCurrentItem)
 	{
-		// Store text selection as clearing object selection
-		// will also clear text selection
-		int selectionStart = -1;
-		int selectionLength = item->itemText.selectionLength();
-		if (selectionLength > 0)
-			selectionStart = item->itemText.startOfSelection();
-		// quick hack to always apply on the right frame - pv
-		currentView->deselectItems(true);
-		//CB I dont think we need to draw here. Its faster if we dont.
+		currentView->deselectItems();
 		currentView->selectItem(item, false);
-		// Restore text selection if necessary
-		if (selectionStart >= 0)
+		if (ScCore->primaryMainWindow()->doc->appMode == modeEdit)
 		{
-			item->itemText.deselectAll();
-			item->itemText.select(selectionStart, selectionLength);
-			item->HasSel = true;
+			mode = currentDoc->appMode;
+			currentDoc->appMode = modeNormal;
 		}
-		// Now apply the style.
-		int mode = currentDoc->appMode;
-		currentDoc->appMode = modeEdit;
-		currentWin->setNewParStyle(paraStyleName);
-		currentDoc->appMode = mode;
 	}
-	else // for multiple selection
-	{
-		int mode = currentDoc->appMode;
-		currentDoc->appMode = modeNormal;
-		currentDoc->itemSelection_SetNamedParagraphStyle(paraStyleName);
+
+	currentDoc->itemSelection_SetNamedParagraphStyle(styleName);
+
+	if (mode != modeNormal)
 		currentDoc->appMode = mode;
-	}
 
 	Py_RETURN_NONE;
 }
@@ -724,63 +697,36 @@ PyObject *scribus_setcharstyle(PyObject* /* self */, PyObject* args)
 		return nullptr;
 	}
 
-	// First, find the style number associated with the requested style
-	// by scanning through the styles looking for the name. If
-	// we can't find it, raise PyExc_Exception.
-	// FIXME: Should use a more specific exception.
-	bool found = false;
-	QString charStyleName = QString::fromUtf8(style);
-	// We start at zero here because it's OK to match an internal name
+	QString styleName = QString::fromUtf8(style);
+	QString itemName = QString::fromUtf8(name);
+
 	ScribusDoc*  currentDoc = ScCore->primaryMainWindow()->doc;
 	ScribusView* currentView = ScCore->primaryMainWindow()->view;
-	ScribusMainWindow* currentWin = ScCore->primaryMainWindow();
-	const StyleSet<CharStyle> &docCharStyles = currentDoc->charStyles();
-	int docCharacterStylesCount = docCharStyles.count();
-	for (int i = 0; i < docCharacterStylesCount; ++i)
+
+	if (!currentDoc->charStyles().contains(styleName))
 	{
-		if (docCharStyles[i].name() == charStyleName) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
-		// whoops, the user specified an invalid style, complain loudly.
 		PyErr_SetString(NotFoundError, QObject::tr("Character style not found.", "python error").toLocal8Bit().constData());
 		return nullptr;
 	}
-	// for current item only
-	if (currentDoc->m_Selection->isEmpty() || (strlen(name) > 0))
+
+	int mode{modeNormal};
+	bool isCurrentItem = itemName.isEmpty() || itemName == currentDoc->m_Selection->itemAt(0)->itemName();
+
+	if (!isCurrentItem)
 	{
-		// Store text selection as clearing object selection
-		// will also clear text selection
-		int selectionStart = -1;
-		int selectionLength = item->itemText.selectionLength();
-		if (selectionLength > 0)
-			selectionStart = item->itemText.startOfSelection();
-		// quick hack to always apply on the right frame - pv
-		currentView->deselectItems(true);
-		//CB I dont think we need to draw here. Its faster if we dont.
+		currentView->deselectItems();
 		currentView->selectItem(item, false);
-		// Restore text selection if necessary
-		if (selectionStart >= 0)
+		if (ScCore->primaryMainWindow()->doc->appMode == modeEdit)
 		{
-			item->itemText.deselectAll();
-			item->itemText.select(selectionStart, selectionLength);
-			item->HasSel = true;
-		}	
-		// Now apply the style.
-		int mode = ScCore->primaryMainWindow()->doc->appMode;
-		currentDoc->appMode = modeEdit;
-		currentWin->setNewCharStyle(charStyleName);
-		currentDoc->appMode = mode;
+			mode = currentDoc->appMode;
+			currentDoc->appMode = modeNormal;
+		}
 	}
-	else // for multiple selection
-	{
-		int mode = currentDoc->appMode;
-		currentDoc->appMode = modeNormal;
-		currentDoc->itemSelection_SetNamedCharStyle(charStyleName);
+
+	currentDoc->itemSelection_SetNamedCharStyle(styleName);
+
+	if (mode != modeNormal)
 		currentDoc->appMode = mode;
-	}
 
 	Py_RETURN_NONE;
 }
diff --git a/scribus/plugins/scriptplugin/cmdobj.h b/scribus/plugins/scriptplugin/cmdobj.h
index d2296fb41..27a910c7a 100644
--- a/scribus/plugins/scriptplugin/cmdobj.h
+++ b/scribus/plugins/scriptplugin/cmdobj.h
@@ -256,9 +256,9 @@ PyObject *scribus_getstyle(PyObject * /*self*/, PyObject* args);
 PyDoc_STRVAR(scribus_setstyle__doc__,
 QT_TR_NOOP("setStyle(\"style\" [, \"name\"])\n\
 \n\
-Apply the named \"style\" to the object named \"name\". If object name is\n\
-given, style is applied to the current text selection in object \"name\".\n\
-If no object name is given, style is applied on selected object.\n\
+Apply the paragraph style named \"style\".\n\
+If \"name\" is not specified, the current selected item is used.\n\
+If the current item has a text selection, the style is applied to the selection.\n\
 "));
 /**
  Craig Ringer, 2004-09-09
@@ -271,10 +271,10 @@ PyObject *scribus_setstyle(PyObject * /*self*/, PyObject* args);
 /*! docstring */
 PyDoc_STRVAR(scribus_setcharstyle__doc__,
 	QT_TR_NOOP("setCharacterStyle(\"style\" [, \"name\"])\n\
+Apply the character style named \"style\".\n\
+If \"name\" is not specified, the current selected item is used.\n\
+If the current item has a text selection, the style is applied to the selection.\n\
 \n\
-Apply the named character \"style\" to the object named \"name\". If object name is\n\
-given, style is applied to the current text selection in object \"name\".\n\
-If no object name is given, style is applied on selected object.\n\
 "));
 /**
 Apply the named character style to the currently selected object.
scripter-setstyle.diff (7,652 bytes)   

Issue History

Date Modified Username Field Change
2019-12-10 09:26 ale New Issue
2019-12-12 15:20 ale File Added: scripter-setstyle.diff
2019-12-12 15:20 ale Note Added: 0047252
2019-12-12 15:21 ale Summary Scripter: behavior of setCharacterStyle() depends on the frame name being defined => [PATCH] Scripter: behavior of setCharacterStyle() depends on the frame name being defined
2019-12-12 15:21 ale Patch No => Yes
2019-12-12 15:21 ale Assigned To => ale
2019-12-12 15:21 ale Status new => assigned
2020-05-05 15:10 jghali Summary [PATCH] Scripter: behavior of setCharacterStyle() depends on the frame name being defined => Scripter: behavior of setCharacterStyle() depends on the frame name being defined
2020-05-05 15:10 jghali Status assigned => resolved
2020-05-05 15:10 jghali Resolution open => fixed
2020-05-05 15:10 jghali Fixed in Version => 1.5.6.svn
2020-08-11 20:56 cbradney Status resolved => closed