1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 #include "cmdtext.h"
8 
9 #include "appmodes.h"
10 #include "cmdutil.h"
11 #include "hyphenator.h"
12 #include "pageitem_textframe.h"
13 #include "prefsmanager.h"
14 #include "scribuscore.h"
15 #include "scribusdoc.h"
16 #include "scribusview.h"
17 #include "selection.h"
18 #include "util.h"
19 
20 
21 template<typename T>
22 class ApplyCharstyleHelper
23 {
24 	PageItem* m_item;
25 	T m_value;
26 
27 public:
ApplyCharstyleHelper(PageItem * item,T v)28 	ApplyCharstyleHelper(PageItem* item, T v) : m_item(item), m_value(v) {}
29 
apply(void (CharStyle::* f)(T),int p,int len)30 	void apply(void (CharStyle::*f)(T), int p, int len)
31 	{
32 		CharStyle cs;
33 		(cs.*f)(m_value);
34 		if (m_item->HasSel)
35 		{
36 			int max = qMax(p + len, m_item->itemText.length());
37 			for (int i = p; i < max; i++)
38 			{
39 				if (m_item->itemText.selected(i))
40 					m_item->itemText.applyCharStyle(i, 1, cs);
41 			}
42 		}
43 		else
44 		{
45 			m_item->itemText.applyCharStyle(p, len, cs);
46 		}
47 	}
48 
49 };
50 
scribus_getfontsize(PyObject *,PyObject * args)51 PyObject *scribus_getfontsize(PyObject* /* self */, PyObject* args)
52 {
53 	char *Name = const_cast<char*>("");
54 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
55 		return nullptr;
56 	if (!checkHaveDocument())
57 		return nullptr;
58 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
59 	if (item == nullptr)
60 		return nullptr;
61 	if (!(item->isTextFrame()) && !(item->isPathText()))
62 	{
63 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get font size of non-text frame.","python error").toLocal8Bit().constData());
64 		return nullptr;
65 	}
66 	if (item->HasSel)
67 	{
68 		for (int i = 0; i < item->itemText.length(); i++)
69 			if (item->itemText.selected(i))
70 				return PyFloat_FromDouble(static_cast<double>(item->itemText.charStyle(i).fontSize() / 10.0));
71 		return nullptr;
72 	}
73 	return PyFloat_FromDouble(static_cast<double>(item->currentCharStyle().fontSize() / 10.0));
74 }
75 
scribus_getfont(PyObject *,PyObject * args)76 PyObject *scribus_getfont(PyObject* /* self */, PyObject* args)
77 {
78 	char *Name = const_cast<char*>("");
79 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
80 		return nullptr;
81 	if (!checkHaveDocument())
82 		return nullptr;
83 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
84 	if (item == nullptr)
85 		return nullptr;
86 	if (!(item->isTextFrame()) && !(item->isPathText()))
87 	{
88 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get font of non-text frame.","python error").toLocal8Bit().constData());
89 		return nullptr;
90 	}
91 	if (item->HasSel)
92 	{
93 		for (int i = 0; i < item->itemText.length(); i++)
94 			if (item->itemText.selected(i))
95 				return PyUnicode_FromString(item->itemText.charStyle(i).font().scName().toUtf8());
96 		return nullptr;
97 	}
98 	return PyUnicode_FromString(item->currentCharStyle().font().scName().toUtf8());
99 }
100 
scribus_gettextcolor(PyObject *,PyObject * args)101 PyObject *scribus_gettextcolor(PyObject* /* self */, PyObject* args)
102 {
103 	char *Name = const_cast<char*>("");
104 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
105 		return nullptr;
106 	if (!checkHaveDocument())
107 		return nullptr;
108 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
109 	if (item == nullptr)
110 		return nullptr;
111     if (!(item->isTextFrame()) && !(item->isPathText()))
112 	{
113 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text color of non-text frame.", "python error").toLocal8Bit().constData());
114 		return nullptr;
115 	}
116 	if (item->HasSel)
117 	{
118 		for (int i = 0; i < item->itemText.length(); ++i)
119 		{
120 			if (item->itemText.selected(i))
121 				return PyUnicode_FromString(item->itemText.charStyle(i).fillColor().toUtf8());
122 		}
123         return nullptr;
124 	}
125     return PyUnicode_FromString(item->currentCharStyle().fillColor().toUtf8());
126 }
127 
scribus_gettextshade(PyObject *,PyObject * args)128 PyObject *scribus_gettextshade(PyObject* /* self */, PyObject* args)
129 {
130 	char *Name = const_cast<char*>("");
131 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
132 		return nullptr;
133 	if (!checkHaveDocument())
134 		return nullptr;
135 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
136 	if (item == nullptr)
137 		return nullptr;
138 	if (!(item->isTextFrame()) && !(item->isPathText()))
139 	{
140 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text color of non-text frame.", "python error").toLocal8Bit().constData());
141 		return nullptr;
142 	}
143 	if (item->HasSel)
144 	{
145 		for (int i = 0; i < item->itemText.length(); ++i)
146 		{
147 			if (item->itemText.selected(i))
148 				return PyLong_FromLong(item->itemText.charStyle(i).fillShade());
149 		}
150 		return nullptr;
151 	}
152 	return PyLong_FromLong(item->currentCharStyle().fillShade());
153 }
154 
scribus_gettextlength(PyObject *,PyObject * args)155 PyObject *scribus_gettextlength(PyObject* /* self */, PyObject* args)
156 {
157 	char *Name = const_cast<char*>("");
158 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
159 		return nullptr;
160 	if (!checkHaveDocument())
161 		return nullptr;
162 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
163 	if (item == nullptr)
164 		return nullptr;
165 	if (!(item->isTextFrame()) && !(item->isPathText()))
166 	{
167 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text size of non-text frame.","python error").toLocal8Bit().constData());
168 		return nullptr;
169 	}
170 	return PyLong_FromLong(static_cast<long>(item->itemText.length()));
171 }
172 
scribus_gettextlines(PyObject *,PyObject * args)173 PyObject *scribus_gettextlines(PyObject* /* self */, PyObject* args)
174 {
175 	char *Name = const_cast<char*>("");
176 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
177 		return nullptr;
178 	if (!checkHaveDocument())
179 		return nullptr;
180 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
181 	if (item == nullptr)
182 		return nullptr;
183 	if (!(item->isTextFrame()) && !(item->isPathText()))
184 	{
185 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get number of lines of non-text frame.","python error").toLocal8Bit().constData());
186 		return nullptr;
187 	}
188 	return PyLong_FromLong(static_cast<long>(item->textLayout.lines()));
189 }
190 
scribus_gettextverticalalignment(PyObject *,PyObject * args)191 PyObject *scribus_gettextverticalalignment(PyObject* /* self */, PyObject* args)
192 {
193 	char *Name = const_cast<char*>("");
194 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
195 		return nullptr;
196 	if (!checkHaveDocument())
197 		return nullptr;
198 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
199 	if (item == nullptr)
200 		return nullptr;
201 	if (!item->isTextFrame())
202 	{
203 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get vertical alignment of non-text frame.", "python error").toLocal8Bit().constData());
204 		return nullptr;
205 	}
206 	return PyLong_FromLong(static_cast<long>(item->verticalAlignment()));
207 }
208 
scribus_getcolumns(PyObject *,PyObject * args)209 PyObject *scribus_getcolumns(PyObject* /* self */, PyObject* args)
210 {
211 	char *Name = const_cast<char*>("");
212 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
213 		return nullptr;
214 	if (!checkHaveDocument())
215 		return nullptr;
216 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
217 	if (item == nullptr)
218 		return nullptr;
219 	if (!item->isTextFrame())
220 	{
221 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column count of non-text frame.","python error").toLocal8Bit().constData());
222 		return nullptr;
223 	}
224 	return PyLong_FromLong(static_cast<long>(item->m_columns));
225 }
226 
scribus_getcolumngap(PyObject *,PyObject * args)227 PyObject *scribus_getcolumngap(PyObject* /* self */, PyObject* args)
228 {
229 	char *Name = const_cast<char*>("");
230 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
231 		return nullptr;
232 	if (!checkHaveDocument())
233 		return nullptr;
234 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
235 	if (item == nullptr)
236 		return nullptr;
237 	if (!item->isTextFrame())
238 	{
239 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column gap of non-text frame.", "python error").toLocal8Bit().constData());
240 		return nullptr;
241 	}
242 	return PyFloat_FromDouble(PointToValue(static_cast<double>(item->m_columnGap)));
243 }
244 
scribus_getfontfeatures(PyObject *,PyObject * args)245 PyObject *scribus_getfontfeatures(PyObject* /* self */, PyObject* args)
246 {
247 	char *Name = const_cast<char*>("");
248 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
249 		return nullptr;
250 	if (!checkHaveDocument())
251 		return nullptr;
252 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
253 	if (item == nullptr)
254 		return nullptr;
255 	if (!(item->isTextFrame()) && !(item->isPathText()))
256 	{
257 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get fontfeatures of non-text frame.","python error").toLocal8Bit().constData());
258 		return nullptr;
259 	}
260 	if (item->HasSel)
261 	{
262 		for (int i = 0; i < item->itemText.length(); i++)
263 			if (item->itemText.selected(i))
264 				return PyUnicode_FromString(item->itemText.charStyle(i).fontFeatures().toUtf8());
265 		return nullptr;
266 	}
267 	return PyUnicode_FromString(item->currentCharStyle().fontFeatures().toUtf8());
268 }
269 
scribus_getfirstlinkedframe(PyObject *,PyObject * args)270 PyObject *scribus_getfirstlinkedframe(PyObject* /* self */, PyObject* args)
271 {
272 	char *Name = const_cast<char*>("");
273 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
274 		return nullptr;
275 	if (!checkHaveDocument())
276 		return nullptr;
277 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
278 	if (item == nullptr)
279 		return nullptr;
280 	if (!item->isTextFrame())
281 	{
282 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
283 		return nullptr;
284 	}
285 
286 	return PyUnicode_FromString(item->firstInChain()->itemName().toUtf8());
287 }
288 
scribus_getlastlinkedframe(PyObject *,PyObject * args)289 PyObject *scribus_getlastlinkedframe(PyObject* /* self */, PyObject* args)
290 {
291 	char *Name = const_cast<char*>("");
292 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
293 		return nullptr;
294 	if (!checkHaveDocument())
295 		return nullptr;
296 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
297 	if (item == nullptr)
298 		return nullptr;
299 	if (!item->isTextFrame())
300 	{
301 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
302 		return nullptr;
303 	}
304 
305 	return PyUnicode_FromString(item->lastInChain()->itemName().toUtf8());
306 }
307 
scribus_getnextlinkedframe(PyObject *,PyObject * args)308 PyObject *scribus_getnextlinkedframe(PyObject* /* self */, PyObject* args)
309 {
310 	char *Name = const_cast<char*>("");
311 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
312 		return nullptr;
313 	if (!checkHaveDocument())
314 		return nullptr;
315 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
316 	if (item == nullptr)
317 		return nullptr;
318 	if (!item->isTextFrame())
319 	{
320 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
321 		return nullptr;
322 	}
323 
324 	if (item->nextInChain() != nullptr)
325 		return PyUnicode_FromString(item->nextInChain()->itemName().toUtf8());
326 
327 	Py_RETURN_NONE;
328 }
329 
scribus_getprevlinkedframe(PyObject *,PyObject * args)330 PyObject *scribus_getprevlinkedframe(PyObject* /* self */, PyObject* args)
331 {
332 	char *Name = const_cast<char*>("");
333 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
334 		return nullptr;
335 	if (!checkHaveDocument())
336 		return nullptr;
337 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
338 	if (item == nullptr)
339 		return nullptr;
340 	if (!item->isTextFrame())
341 	{
342 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
343 		return nullptr;
344 	}
345 
346 	if (item->prevInChain() != nullptr)
347 		return PyUnicode_FromString(item->prevInChain()->itemName().toUtf8());
348 
349 	Py_RETURN_NONE;
350 }
351 
scribus_getfirstlineoffset(PyObject *,PyObject * args)352 PyObject *scribus_getfirstlineoffset(PyObject* /* self */, PyObject* args)
353 {
354 	char *Name = const_cast<char*>("");
355 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
356 		return nullptr;
357 	if (!checkHaveDocument())
358 		return nullptr;
359 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
360 	if (item == nullptr)
361 		return nullptr;
362 	if (!item->isTextFrame())
363 	{
364 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get first line offset of non-text frame.", "python error").toLocal8Bit().constData());
365 		return nullptr;
366 	}
367 	return PyLong_FromLong(static_cast<long>(item->firstLineOffset()));
368 }
369 
scribus_getlinespacing(PyObject *,PyObject * args)370 PyObject *scribus_getlinespacing(PyObject* /* self */, PyObject* args)
371 {
372 	char *Name = const_cast<char*>("");
373 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
374 		return nullptr;
375 	if (!checkHaveDocument())
376 		return nullptr;
377 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
378 	if (item == nullptr)
379 		return nullptr;
380 	if (!item->isTextFrame())
381 	{
382 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get line space of non-text frame.","python error").toLocal8Bit().constData());
383 		return nullptr;
384 	}
385 	return PyFloat_FromDouble(static_cast<double>(item->currentStyle().lineSpacing()));
386 }
387 
scribus_gettextdistances(PyObject *,PyObject * args)388 PyObject *scribus_gettextdistances(PyObject* /* self */, PyObject* args)
389 {
390 	char *Name = const_cast<char*>("");
391 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
392 		return nullptr;
393 	if (!checkHaveDocument())
394 		return nullptr;
395 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
396 	if (item == nullptr)
397 		return nullptr;
398 	if (!item->isTextFrame())
399 	{
400 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text distances of non-text frame.","python error").toLocal8Bit().constData());
401 		return nullptr;
402 	}
403 	return Py_BuildValue("(dddd)",
404 	        PointToValue(item->textToFrameDistLeft()),
405 	        PointToValue(item->textToFrameDistRight()),
406 	        PointToValue(item->textToFrameDistTop()),
407 	        PointToValue(item->textToFrameDistBottom()));
408 }
409 
scribus_getframetext(PyObject *,PyObject * args)410 PyObject *scribus_getframetext(PyObject* /* self */, PyObject* args)
411 {
412 	char *Name = const_cast<char*>("");
413 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
414 		return nullptr;
415 	if (!checkHaveDocument())
416 		return nullptr;
417 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
418 	if (item == nullptr)
419 		return nullptr;
420 	if (!(item->isTextFrame()) && !(item->isPathText()))
421 	{
422 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData());
423 		return nullptr;
424 	}
425 
426 	const StoryText& story = item->itemText;
427 	QString text;
428 	text.reserve(story.hasSelection() ? story.selectionLength() : story.length());
429 	for (int i = item->firstInFrame(); i <= item->lastInFrame(); ++i)
430 	{
431 		if (item->HasSel)
432 		{
433 			if (story.selected(i))
434 				text += story.text(i);
435 		}
436 		else
437 		{
438 			text += story.text(i);
439 		}
440 	}
441 	return PyUnicode_FromString(text.toUtf8());
442 }
443 
scribus_getalltext(PyObject *,PyObject * args)444 PyObject *scribus_getalltext(PyObject* /* self */, PyObject* args)
445 {
446 	char *Name = const_cast<char*>("");
447 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
448 		return nullptr;
449 	if (!checkHaveDocument())
450 		return nullptr;
451 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
452 	if (item == nullptr)
453 		return nullptr;
454 	if (!(item->isTextFrame()) && !(item->isPathText()))
455 	{
456 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData());
457 		return nullptr;
458 	}
459 
460 	// collect all chars from a storytext
461 	const StoryText& story = item->itemText;
462 	QString text;
463 	text.reserve(story.hasSelection() ? story.selectionLength() : story.length());
464 	for (int i = 0; i < story.length(); i++)
465 	{
466 		if (item->HasSel)
467 		{
468 			if (story.selected(i))
469 				text += story.text(i);
470 		}
471 		else
472 		{
473 			text += story.text(i);
474 		}
475 	}
476 	return PyUnicode_FromString(text.toUtf8());
477 }
478 
scribus_settext(PyObject *,PyObject * args)479 PyObject *scribus_settext(PyObject* /* self */, PyObject* args)
480 {
481 	char *Name = const_cast<char*>("");
482 	char *Text;
483 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Text, "utf-8", &Name))
484 		return nullptr;
485 	if (!checkHaveDocument())
486 		return nullptr;
487 	PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name));
488 	if (currItem == nullptr)
489 		return nullptr;
490 	if (!(currItem->isTextFrame()) && !(currItem->isPathText()))
491 	{
492 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text of non-text frame.","python error").toLocal8Bit().constData());
493 		return nullptr;
494 	}
495 	QString userText = QString::fromUtf8(Text);
496 	userText.replace("\r\n", SpecialChars::PARSEP);
497 	userText.replace(QChar('\n') , SpecialChars::PARSEP);
498 	PyMem_Free(Text);
499 	currItem->itemText.clear();
500 	currItem->itemText.insertChars(0, userText);
501 	currItem->invalidateLayout();
502 
503 	Py_RETURN_NONE;
504 }
505 
scribus_inserttext(PyObject *,PyObject * args)506 PyObject *scribus_inserttext(PyObject* /* self */, PyObject* args)
507 {
508 	char *Name = const_cast<char*>("");
509 	char *Text;
510 	int pos;
511 	if (!PyArg_ParseTuple(args, "esi|es", "utf-8", &Text, &pos, "utf-8", &Name))
512 		return nullptr;
513 	if (!checkHaveDocument())
514 		return nullptr;
515 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
516 	if (item == nullptr)
517 		return nullptr;
518 	if (!(item->isTextFrame()) && !(item->isPathText()))
519 	{
520 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot insert text into non-text frame.","python error").toLocal8Bit().constData());
521 		return nullptr;
522 	}
523 	QString textData = QString::fromUtf8(Text);
524 	textData.replace("\r\n", SpecialChars::PARSEP);
525 	textData.replace(QChar('\n') , SpecialChars::PARSEP);
526 	PyMem_Free(Text);
527 	if ((pos < -1) || (pos > static_cast<int>(item->itemText.length())))
528 	{
529 		PyErr_SetString(PyExc_IndexError, QObject::tr("Insert index out of bounds.","python error").toLocal8Bit().constData());
530 		return nullptr;
531 	}
532 	if (pos == -1)
533 		pos = item->itemText.length();
534 	item->itemText.insertChars(pos, textData, true);
535 	item->invalidateLayout();
536 
537 	Py_RETURN_NONE;
538 }
539 
scribus_inserthtmltext(PyObject *,PyObject * args)540 PyObject *scribus_inserthtmltext(PyObject* /* self */, PyObject* args)
541 {
542 	char *name = const_cast<char*>("");
543 	char *file;
544 
545 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &file, "utf-8", &name)) {
546 		return nullptr;
547 	}
548 
549 	if (!checkHaveDocument()) {
550 		return nullptr;
551 	}
552 
553 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
554 	if (item == nullptr) {
555 		return nullptr;
556 	}
557 
558 	if (!(item->isTextFrame()) && !(item->isPathText())) {
559 		PyErr_SetString(WrongFrameTypeError,
560 				QObject::tr("Cannot insert text into non-text frame.",
561 					"python error").toLocal8Bit().constData());
562 		return nullptr;
563 	}
564 
565 	QString fileName = QString::fromUtf8(file);
566 
567 	gtGetText gt(ScCore->primaryMainWindow()->doc);
568 	gt.launchImporter(-1, fileName, false, QString("utf-8"), false, true, item);
569 
570 	// FIXME: PyMem_Free() - are any needed??
571 	Py_RETURN_NONE;
572 }
573 
scribus_layouttext(PyObject *,PyObject * args)574 PyObject *scribus_layouttext(PyObject* /* self */, PyObject* args)
575 {
576 	char *Name = const_cast<char*>("");
577 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
578 		return nullptr;
579 	if (!checkHaveDocument())
580 		return nullptr;
581 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
582 	if (item == nullptr)
583 		return nullptr;
584 	if (!item->isTextFrame() && !item->isPathText())
585 	{
586 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot layout text of a non-text frame.", "python error").toLocal8Bit().constData());
587 		return nullptr;
588 	}
589 	item->layout();
590 
591 	Py_RETURN_NONE;
592 }
593 
scribus_layouttextchain(PyObject *,PyObject * args)594 PyObject *scribus_layouttextchain(PyObject* /* self */, PyObject* args)
595 {
596 	char *Name = const_cast<char*>("");
597 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
598 		return nullptr;
599 	if (!checkHaveDocument())
600 		return nullptr;
601 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
602 	if (item == nullptr)
603 		return nullptr;
604 	if (!item->isTextFrame() && !item->isPathText())
605 	{
606 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot layout text chain for a non-text frame.", "python error").toLocal8Bit().constData());
607 		return nullptr;
608 	}
609 
610 	if (item->isPathText())
611 	{
612 		item->layout();
613 		Py_RETURN_NONE;
614 	}
615 
616 	PageItem* firstFrame = item->firstInChain();
617 	PageItem* nextFrame = firstFrame;
618 	while (nextFrame)
619 	{
620 		nextFrame->layout();
621 		nextFrame = nextFrame->nextInChain();
622 	}
623 
624 	Py_RETURN_NONE;
625 }
626 
scribus_settextalignment(PyObject *,PyObject * args)627 PyObject *scribus_settextalignment(PyObject* /* self */, PyObject* args)
628 {
629 	char *Name = const_cast<char*>("");
630 	int alignment;
631 	if (!PyArg_ParseTuple(args, "i|es", &alignment, "utf-8", &Name))
632 		return nullptr;
633 	if (!checkHaveDocument())
634 		return nullptr;
635 	if ((alignment > 4) || (alignment < 0))
636 	{
637 		PyErr_SetString(PyExc_ValueError, QObject::tr("Alignment out of range. Use one of the scribus.ALIGN_* constants.","python error").toLocal8Bit().constData());
638 		return nullptr;
639 	}
640 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
641 	if (item == nullptr)
642 		return nullptr;
643 	if (!item->isTextFrame())
644 	{
645 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text alignment on a non-text frame.","python error").toLocal8Bit().constData());
646 		return nullptr;
647 	}
648 
649 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
650 	int oldAppMode  = ScCore->primaryMainWindow()->doc->appMode;
651 
652 	Selection tmpSelection(nullptr, false);
653 	tmpSelection.addItem(item);
654 	if (item->HasSel)
655 		doc->appMode = modeEdit;
656 	doc->itemSelection_SetAlignment(alignment, &tmpSelection);
657 	doc->appMode = oldAppMode;
658 
659 	Py_RETURN_NONE;
660 }
661 
scribus_setdirection(PyObject *,PyObject * args)662 PyObject *scribus_setdirection(PyObject* /* self */, PyObject* args)
663 {
664 	char *Name = const_cast<char*>("");
665 	int direction;
666 	if (!PyArg_ParseTuple(args, "i|es", &direction, "utf-8", &Name))
667 		return nullptr;
668 	if (!checkHaveDocument())
669 		return nullptr;
670 	if ((direction > 1) || (direction < 0))
671 	{
672 		PyErr_SetString(PyExc_ValueError, QObject::tr("direction out of range. Use one of the scribus.DIRECTION* constants.","python error").toLocal8Bit().constData());
673 		return nullptr;
674 	}
675 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
676 	if (item == nullptr)
677 		return nullptr;
678 	if (!item->isTextFrame())
679 	{
680 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text direction on a non-text frame.","python error").toLocal8Bit().constData());
681 		return nullptr;
682 	}
683 
684 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
685 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
686 
687 	Selection tmpSelection(nullptr, false);
688 	tmpSelection.addItem(item);
689 	if (item->HasSel)
690 		doc->appMode = modeEdit;
691 	doc->itemSelection_SetDirection(direction, &tmpSelection);
692 	doc->appMode = oldAppMode;
693 
694 	Py_RETURN_NONE;
695 }
696 
scribus_setfontsize(PyObject *,PyObject * args)697 PyObject *scribus_setfontsize(PyObject* /* self */, PyObject* args)
698 {
699 	char *Name = const_cast<char*>("");
700 	double size;
701 	if (!PyArg_ParseTuple(args, "d|es", &size, "utf-8", &Name))
702 		return nullptr;
703 	if (!checkHaveDocument())
704 		return nullptr;
705 	if ((size > 512) || (size < 1))
706 	{
707 		PyErr_SetString(PyExc_ValueError, QObject::tr("Font size out of bounds - must be 1 <= size <= 512.","python error").toLocal8Bit().constData());
708 		return nullptr;
709 	}
710 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
711 	if (item == nullptr)
712 		return nullptr;
713 
714 	if (!item->isTextFrame())
715 	{
716 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font size on a non-text frame.","python error").toLocal8Bit().constData());
717 		return nullptr;
718 	}
719 
720 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
721 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
722 
723 	Selection tmpSelection(nullptr, false);
724 	tmpSelection.addItem(item);
725 	if (item->HasSel)
726 		doc->appMode = modeEdit;
727 	doc->itemSelection_SetFontSize(qRound(size * 10.0), &tmpSelection);
728 	doc->appMode = oldAppMode;
729 
730 	Py_RETURN_NONE;
731 }
732 
scribus_setfontfeatures(PyObject *,PyObject * args)733 PyObject *scribus_setfontfeatures(PyObject* /* self */, PyObject* args)
734 {
735 	char *Name = const_cast<char*>("");
736 	char *fontfeature = const_cast<char*>("");
737 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &fontfeature, "utf-8", &Name))
738 		return nullptr;
739 	if (!checkHaveDocument())
740 		return nullptr;
741 
742 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
743 	if (item == nullptr)
744 		return nullptr;
745 
746 	if (!item->isTextFrame())
747 	{
748 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font feature on a non-text frame.","python error").toLocal8Bit().constData());
749 		return nullptr;
750 	}
751 
752 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
753 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
754 
755 	Selection tmpSelection(nullptr, false);
756 	tmpSelection.addItem(item);
757 	if (item->HasSel)
758 		doc->appMode = modeEdit;
759 	doc->itemSelection_SetFontFeatures(QString::fromUtf8(fontfeature), &tmpSelection);
760 	doc->appMode = oldAppMode;
761 
762 	Py_RETURN_NONE;
763 }
764 
scribus_setfont(PyObject *,PyObject * args)765 PyObject *scribus_setfont(PyObject* /* self */, PyObject* args)
766 {
767 	char *Name = const_cast<char*>("");
768 	char *Font = const_cast<char*>("");
769 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Font, "utf-8", &Name))
770 		return nullptr;
771 	if (!checkHaveDocument())
772 		return nullptr;
773 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
774 	if (item == nullptr)
775 		return nullptr;
776 	if (!(item->isTextFrame()) && !(item->isPathText()))
777 	{
778 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font on a non-text frame.","python error").toLocal8Bit().constData());
779 		return nullptr;
780 	}
781 	if (!PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.contains(QString::fromUtf8(Font)))
782 	{
783 		PyErr_SetString(PyExc_ValueError, QObject::tr("Font not found.", "python error").toLocal8Bit().constData());
784 		return nullptr;
785 	}
786 
787 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
788 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
789 
790 	Selection tmpSelection(nullptr, false);
791 	tmpSelection.addItem(item);
792 	if (item->HasSel)
793 		doc->appMode = modeEdit;
794 	doc->itemSelection_SetFont(QString::fromUtf8(Font), &tmpSelection);
795 	doc->appMode = oldAppMode;
796 
797 	Py_RETURN_NONE;
798 }
799 
scribus_setfirstlineoffset(PyObject *,PyObject * args)800 PyObject *scribus_setfirstlineoffset(PyObject* /* self */, PyObject* args)
801 {
802 	char *Name = const_cast<char*>("");
803 	int offset;
804 	if (!PyArg_ParseTuple(args, "i|es", &offset, "utf-8", &Name))
805 		return nullptr;
806 	if (!checkHaveDocument())
807 		return nullptr;
808 	if (offset < 0 || offset > (int) FLOPBaselineGrid)
809 	{
810 		PyErr_SetString(PyExc_ValueError, QObject::tr("First line offset out of bounds, Use one of the scribus.FLOP_* constants.", "python error").toLocal8Bit().constData());
811 		return nullptr;
812 	}
813 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
814 	if (item == nullptr)
815 		return nullptr;
816 	if (!item->isTextFrame())
817 	{
818 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set first line offset on a non-text frame.", "python error").toLocal8Bit().constData());
819 		return nullptr;
820 	}
821 	item->setFirstLineOffset((FirstLineOffsetPolicy) offset);
822 	item->update();
823 
824 	Py_RETURN_NONE;
825 }
826 
scribus_setlinespacing(PyObject *,PyObject * args)827 PyObject *scribus_setlinespacing(PyObject* /* self */, PyObject* args)
828 {
829 	char *Name = const_cast<char*>("");
830 	double w;
831 	if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name))
832 		return nullptr;
833 	if (!checkHaveDocument())
834 		return nullptr;
835 	if (w < 0.1)
836 	{
837 		PyErr_SetString(PyExc_ValueError, QObject::tr("Line space out of bounds, must be >= 0.1.","python error").toLocal8Bit().constData());
838 		return nullptr;
839 	}
840 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
841 	if (item == nullptr)
842 		return nullptr;
843 	if (!item->isTextFrame())
844 	{
845 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set line spacing on a non-text frame.","python error").toLocal8Bit().constData());
846 		return nullptr;
847 	}
848 
849 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
850 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
851 
852 	Selection tmpSelection(nullptr, false);
853 	tmpSelection.addItem(item);
854 	if (item->HasSel)
855 		doc->appMode = modeEdit;
856 	doc->itemSelection_SetLineSpacing(w, &tmpSelection);
857 	doc->appMode = oldAppMode;
858 
859 	Py_RETURN_NONE;
860 }
861 
scribus_setlinespacingmode(PyObject *,PyObject * args)862 PyObject *scribus_setlinespacingmode(PyObject* /* self */, PyObject* args)
863 {
864 	char *Name = const_cast<char*>("");
865 	int w;
866 	if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name))
867 		return nullptr;
868 	if (!checkHaveDocument())
869 		return nullptr;
870 	if (w < 0 || w > 3) // Use constants?
871 	{
872 		PyErr_SetString(PyExc_ValueError, QObject::tr("Line space mode invalid, must be 0, 1 or 2","python error").toLocal8Bit().constData());
873 		return nullptr;
874 	}
875 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
876 	if (item == nullptr)
877 		return nullptr;
878 	if (!item->isTextFrame())
879 	{
880 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set line spacing mode on a non-text frame.","python error").toLocal8Bit().constData());
881 		return nullptr;
882 	}
883 
884 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
885 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
886 
887 	Selection tmpSelection(nullptr, false);
888 	tmpSelection.addItem(item);
889 	if (item->HasSel)
890 		doc->appMode = modeEdit;
891 	doc->itemSelection_SetLineSpacingMode(w, &tmpSelection);
892 	doc->appMode = oldAppMode;
893 
894 	Py_RETURN_NONE;
895 }
896 
scribus_settextdistances(PyObject *,PyObject * args)897 PyObject *scribus_settextdistances(PyObject* /* self */, PyObject* args)
898 {
899 	char *Name = const_cast<char*>("");
900 	double l,r,t,b;
901 	if (!PyArg_ParseTuple(args, "dddd|es", &l, &r, &t, &b, "utf-8", &Name))
902 		return nullptr;
903 	if (!checkHaveDocument())
904 		return nullptr;
905 	if (l < 0.0 || r < 0.0 || t < 0.0 || b < 0.0)
906 	{
907 		PyErr_SetString(PyExc_ValueError, QObject::tr("Text distances out of bounds, must be positive.","python error").toLocal8Bit().constData());
908 		return nullptr;
909 	}
910 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
911 	if (item == nullptr)
912 		return nullptr;
913 	if (!item->isTextFrame())
914 	{
915 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text distances on a non-text frame.","python error").toLocal8Bit().constData());
916 		return nullptr;
917 	}
918 	item->setTextToFrameDist(ValueToPoint(l), ValueToPoint(r), ValueToPoint(t), ValueToPoint(b));
919 
920 	Py_RETURN_NONE;
921 }
922 
scribus_setcolumngap(PyObject *,PyObject * args)923 PyObject *scribus_setcolumngap(PyObject* /* self */, PyObject* args)
924 {
925 	char *Name = const_cast<char*>("");
926 	double w;
927 	if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name))
928 		return nullptr;
929 	if (!checkHaveDocument())
930 		return nullptr;
931 	if (w < 0.0)
932 	{
933 		PyErr_SetString(PyExc_ValueError, QObject::tr("Column gap out of bounds, must be positive.","python error").toLocal8Bit().constData());
934 		return nullptr;
935 	}
936 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
937 	if (item == nullptr)
938 		return nullptr;
939 	if (!item->isTextFrame())
940 	{
941 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set column gap on a non-text frame.","python error").toLocal8Bit().constData());
942 		return nullptr;
943 	}
944 	item->m_columnGap = ValueToPoint(w);
945 
946 	Py_RETURN_NONE;
947 }
948 
scribus_setcolumns(PyObject *,PyObject * args)949 PyObject *scribus_setcolumns(PyObject* /* self */, PyObject* args)
950 {
951 	char *Name = const_cast<char*>("");
952 	int w;
953 	if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name))
954 		return nullptr;
955 	if (!checkHaveDocument())
956 		return nullptr;
957 	if (w < 1)
958 	{
959 		PyErr_SetString(PyExc_ValueError, QObject::tr("Column count out of bounds, must be > 1.","python error").toLocal8Bit().constData());
960 		return nullptr;
961 	}
962 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
963 	if (item == nullptr)
964 		return nullptr;
965 	if (!item->isTextFrame())
966 	{
967 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set number of columns on a non-text frame.","python error").toLocal8Bit().constData());
968 		return nullptr;
969 	}
970 	item->m_columns = w;
971 
972 	Py_RETURN_NONE;
973 }
974 
scribus_settextverticalalignment(PyObject *,PyObject * args)975 PyObject *scribus_settextverticalalignment(PyObject* /* self */, PyObject* args)
976 {
977 	char *Name = const_cast<char*>("");
978 	int alignment;
979 	if (!PyArg_ParseTuple(args, "i|es", &alignment, "utf-8", &Name))
980 		return nullptr;
981 	if (!checkHaveDocument())
982 		return nullptr;
983 	if (alignment < 0 || alignment > 2)
984 	{
985 		PyErr_SetString(PyExc_ValueError, QObject::tr("Vertical alignment out of bounds, Use one of the scribus.ALIGNV_* constants.", "python error").toLocal8Bit().constData());
986 		return nullptr;
987 	}
988 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
989 	if (item == nullptr)
990 		return nullptr;
991 	if (!item->isTextFrame())
992 	{
993 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set vertical alignment on a non-text frame.", "python error").toLocal8Bit().constData());
994 		return nullptr;
995 	}
996 	item->setVerticalAlignment(alignment);
997 	item->update();
998 
999 	Py_RETURN_NONE;
1000 }
1001 
scribus_selectframetext(PyObject *,PyObject * args)1002 PyObject *scribus_selectframetext(PyObject* /* self */, PyObject* args)
1003 {
1004 	char *Name = const_cast<char*>("");
1005 	int start, selcount;
1006 	if (!PyArg_ParseTuple(args, "ii|es", &start, &selcount, "utf-8", &Name))
1007 		return nullptr;
1008 	if (!checkHaveDocument())
1009 		return nullptr;
1010 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1011 	if (item == nullptr)
1012 		return nullptr;
1013 
1014 	if (!(item->isTextFrame()) && !(item->isPathText()))
1015 	{
1016 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot select text in a non-text frame", "python error").toLocal8Bit().constData());
1017 		return nullptr;
1018 	}
1019 	if (selcount < -1)
1020 	{
1021 		PyErr_SetString(PyExc_IndexError, QObject::tr("Count must be positive, 0 or -1", "python error").toLocal8Bit().constData());
1022 		return nullptr;
1023 	}
1024 
1025 	if (start < 0 || (selcount > 0 && ((item->lastInFrame() == -1) || (selcount + start > item->lastInFrame() - item->firstInFrame() + 1))))
1026 	{
1027 		PyErr_SetString(PyExc_IndexError, QObject::tr("Selection index out of bounds", "python error").toLocal8Bit().constData());
1028 		return nullptr;
1029 	}
1030 	start += item->firstInFrame();
1031 	if (selcount == -1)
1032 		selcount = item->lastInFrame() + 1 - start;
1033 	item->itemText.deselectAll();
1034 	if (selcount == 0)
1035 	{
1036 		item->HasSel = false;
1037 		Py_RETURN_NONE;
1038 	}
1039 	item->itemText.select(start, selcount, true);
1040 	item->HasSel = true;
1041 
1042 	Py_RETURN_NONE;
1043 }
1044 
scribus_selecttext(PyObject *,PyObject * args)1045 PyObject *scribus_selecttext(PyObject* /* self */, PyObject* args)
1046 {
1047 	char *Name = const_cast<char*>("");
1048 	int start, selcount;
1049 	if (!PyArg_ParseTuple(args, "ii|es", &start, &selcount, "utf-8", &Name))
1050 		return nullptr;
1051 	if (!checkHaveDocument())
1052 		return nullptr;
1053 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1054 	if (item == nullptr)
1055 		return nullptr;
1056 	if (selcount == -1)
1057 	{
1058 		// user wants to select all after the start point -- CR
1059 		selcount = item->itemText.length() - start;
1060 		if (selcount < 0)
1061 			// user passed start that's > text in the frame
1062 			selcount = 0;
1063 	}
1064 	// cr 2005-01-18 fixed off-by-one with end bound that made selecting the last char impossible
1065 	if ((start < 0) || ((start + selcount) > static_cast<int>(item->itemText.length())))
1066 	{
1067 		PyErr_SetString(PyExc_IndexError, QObject::tr("Selection index out of bounds", "python error").toLocal8Bit().constData());
1068 		return nullptr;
1069 	}
1070 	if (!(item->isTextFrame()) && !(item->isPathText()))
1071 	{
1072 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot select text in a non-text frame", "python error").toLocal8Bit().constData());
1073 		return nullptr;
1074 	}
1075 	/* FIXME: not sure if we should make this check or not
1076 	if (start > ende)
1077 	{
1078 		PyErr_SetString(PyExc_ValueError, QString("Selection start > selection end").toLocal8Bit().constData());
1079 		return nullptr;
1080 	}
1081 	*/
1082 	item->itemText.deselectAll();
1083 	if (selcount == 0)
1084 	{
1085 		item->HasSel = false;
1086 		Py_RETURN_NONE;
1087 	}
1088 	item->itemText.select(start, selcount, true);
1089 	item->HasSel = true;
1090 
1091 	Py_RETURN_NONE;
1092 }
1093 
scribus_deletetext(PyObject *,PyObject * args)1094 PyObject *scribus_deletetext(PyObject* /* self */, PyObject* args)
1095 {
1096 	char *Name = const_cast<char*>("");
1097 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
1098 		return nullptr;
1099 	if (!checkHaveDocument())
1100 		return nullptr;
1101 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1102 	if (item == nullptr)
1103 		return nullptr;
1104 	if (!item->isTextFrame() && !item->isPathText())
1105 	{
1106 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot delete text from a non-text frame.","python error").toLocal8Bit().constData());
1107 		return nullptr;
1108 	}
1109 	PageItem_TextFrame* tf_item = item->asTextFrame();
1110 	if (tf_item)
1111 	{
1112 		if (tf_item->HasSel)
1113 			tf_item->deleteSelectedTextFromFrame();
1114 		else
1115 			tf_item->itemText.clear();
1116 	}
1117 	else
1118 	{
1119 		//Path text cannot have selected text, :( FIXME
1120 		if (item->isPathText())
1121 			item->itemText.clear();
1122 	}
1123 	Py_RETURN_NONE;
1124 }
1125 
scribus_settextfill(PyObject *,PyObject * args)1126 PyObject *scribus_settextfill(PyObject* /* self */, PyObject* args)
1127 {
1128 	char *Name = const_cast<char*>("");
1129 	char *Color;
1130 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name))
1131 		return nullptr;
1132 	if (!checkHaveDocument())
1133 		return nullptr;
1134 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1135 	if (item == nullptr)
1136 		return nullptr;
1137 	if (!item->isTextFrame() && !item->isPathText())
1138 	{
1139 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text fill on a non-text frame.","python error").toLocal8Bit().constData());
1140 		return nullptr;
1141 	}
1142 	ApplyCharstyleHelper<QString>(item, QString::fromUtf8(Color)).apply(&CharStyle::setFillColor, 0, item->itemText.length());
1143 	Py_RETURN_NONE;
1144 }
1145 
scribus_settextstroke(PyObject *,PyObject * args)1146 PyObject *scribus_settextstroke(PyObject* /* self */, PyObject* args)
1147 {
1148 	char *Name = const_cast<char*>("");
1149 	char *Color;
1150 	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name))
1151 		return nullptr;
1152 	if (!checkHaveDocument())
1153 		return nullptr;
1154 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1155 	if (item == nullptr)
1156 		return nullptr;
1157 	if (!item->isTextFrame() && !item->isPathText())
1158 	{
1159 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text stroke on a non-text frame.","python error").toLocal8Bit().constData());
1160 		return nullptr;
1161 	}
1162 	ApplyCharstyleHelper<QString>(item, QString::fromUtf8(Color)).apply(&CharStyle::setStrokeColor, 0, item->itemText.length());
1163 	Py_RETURN_NONE;
1164 }
1165 
1166 
scribus_settextscalingh(PyObject *,PyObject * args)1167 PyObject *scribus_settextscalingh(PyObject* /* self */, PyObject* args)
1168 {
1169 	char *Name = const_cast<char*>("");
1170 	double sc;
1171 	if (!PyArg_ParseTuple(args, "d|es", &sc, "utf-8", &Name))
1172 		return nullptr;
1173 	if (!checkHaveDocument())
1174 		return nullptr;
1175 	if (sc < 10)
1176 	{
1177 		PyErr_SetString(PyExc_ValueError, QObject::tr("Character scaling out of bounds, must be >= 10","python error").toLocal8Bit().constData());
1178 		return nullptr;
1179 	}
1180 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1181 	if (item == nullptr)
1182 		return nullptr;
1183 	if (!item->isTextFrame())
1184 	{
1185 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set character scaling on a non-text frame.","python error").toLocal8Bit().constData());
1186 		return nullptr;
1187 	}
1188 
1189 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
1190 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
1191 
1192 	Selection tmpSelection(nullptr, false);
1193 	tmpSelection.addItem(item);
1194 	if (item->HasSel)
1195 		doc->appMode = modeEdit;
1196 	doc->itemSelection_SetScaleH(qRound(sc * 10), &tmpSelection);
1197 	doc->appMode = oldAppMode;
1198 
1199 	Py_RETURN_NONE;
1200 }
1201 
1202 
scribus_settextscalingv(PyObject *,PyObject * args)1203 PyObject *scribus_settextscalingv(PyObject* /* self */, PyObject* args)
1204 {
1205 	char *Name = const_cast<char*>("");
1206 	double sc;
1207 	if (!PyArg_ParseTuple(args, "d|es", &sc, "utf-8", &Name))
1208 		return nullptr;
1209 	if (!checkHaveDocument())
1210 		return nullptr;
1211 	if (sc < 10)
1212 	{
1213 		PyErr_SetString(PyExc_ValueError, QObject::tr("Character scaling out of bounds, must be >= 10","python error").toLocal8Bit().constData());
1214 		return nullptr;
1215 	}
1216 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1217 	if (item == nullptr)
1218 		return nullptr;
1219 	if (!item->isTextFrame())
1220 	{
1221 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set character scaling on a non-text frame.","python error").toLocal8Bit().constData());
1222 		return nullptr;
1223 	}
1224 
1225 	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
1226 	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;
1227 
1228 	Selection tmpSelection(nullptr, false);
1229 	tmpSelection.addItem(item);
1230 	if (item->HasSel)
1231 		doc->appMode = modeEdit;
1232 	doc->itemSelection_SetScaleV(qRound(sc * 10), &tmpSelection);
1233 	doc->appMode = oldAppMode;
1234 
1235 	Py_RETURN_NONE;
1236 }
1237 
1238 
scribus_settextshade(PyObject *,PyObject * args)1239 PyObject *scribus_settextshade(PyObject* /* self */, PyObject* args)
1240 {
1241 	char *Name = const_cast<char*>("");
1242 	int w;
1243 	if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name))
1244 		return nullptr;
1245 	if (!checkHaveDocument())
1246 		return nullptr;
1247 	if ((w < 0) || (w > 100))
1248 		Py_RETURN_NONE;
1249 
1250 	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
1251 	if (item == nullptr)
1252 		return nullptr;
1253 	if (!item->isTextFrame() && !item->isPathText())
1254 	{
1255 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text shade on a non-text frame.","python error").toLocal8Bit().constData());
1256 		return nullptr;
1257 	}
1258 	ApplyCharstyleHelper<double>(item, w).apply(&CharStyle::setFillShade, 0, item->itemText.length());
1259 	Py_RETURN_NONE;
1260 }
1261 
scribus_linktextframes(PyObject *,PyObject * args)1262 PyObject *scribus_linktextframes(PyObject* /* self */, PyObject* args)
1263 {
1264 	char *name1;
1265 	char *name2;
1266 
1267 	if (!PyArg_ParseTuple(args, "eses", "utf-8", &name1, "utf-8", &name2))
1268 		return nullptr;
1269 	if (!checkHaveDocument())
1270 		return nullptr;
1271 	PageItem *fromitem = GetUniqueItem(QString::fromUtf8(name1));
1272 	if (fromitem == nullptr)
1273 		return nullptr;
1274 	PageItem *toitem = GetUniqueItem(QString::fromUtf8(name2));
1275 	if (toitem == nullptr)
1276 		return nullptr;
1277 	if (!(fromitem->isTextFrame()) || !(toitem->isTextFrame()))
1278 	{
1279 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only link text frames.","python error").toLocal8Bit().constData());
1280 		return nullptr;
1281 	}
1282 /*	if (toitem->itemText.length() > 0)
1283 	{
1284 		PyErr_SetString(ScribusException, QObject::tr("Target frame must be empty.","python error").toLocal8Bit().constData());
1285 		return nullptr;
1286 	}*/
1287 	if (toitem->nextInChain() != nullptr)
1288 	{
1289 		PyErr_SetString(ScribusException, QObject::tr("Target frame links to another frame.","python error").toLocal8Bit().constData());
1290 		return nullptr;
1291 	}
1292 	if (toitem->prevInChain() != nullptr)
1293 	{
1294 		PyErr_SetString(ScribusException, QObject::tr("Target frame is linked to by another frame.","python error").toLocal8Bit().constData());
1295 		return nullptr;
1296 	}
1297 	if (toitem == fromitem)
1298 	{
1299 		PyErr_SetString(ScribusException, QObject::tr("Source and target are the same object.","python error").toLocal8Bit().constData());
1300 		return nullptr;
1301 	}
1302 	// references to the others boxes
1303 	fromitem->link(toitem);
1304 	ScCore->primaryMainWindow()->view->DrawNew();
1305 	// enable 'save icon' stuff
1306 	ScCore->primaryMainWindow()->slotDocCh();
1307 
1308 	Py_RETURN_NONE;
1309 }
1310 
scribus_unlinktextframes(PyObject *,PyObject * args)1311 PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args)
1312 {
1313 	char *name;
1314 	if (!PyArg_ParseTuple(args, "es", "utf-8", &name))
1315 		return nullptr;
1316 	if (!checkHaveDocument())
1317 		return nullptr;
1318 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1319 	if (item == nullptr)
1320 		return nullptr;
1321 	if (!item->isTextFrame())
1322 	{
1323 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot unlink a non-text frame.","python error").toLocal8Bit().constData());
1324 		return nullptr;
1325 	}
1326 	// only linked
1327 	if (item->prevInChain() == nullptr)
1328 	{
1329 		PyErr_SetString(ScribusException, QObject::tr("Object is not a linked text frame, can't unlink.","python error").toLocal8Bit().constData());
1330 		return nullptr;
1331 	}
1332 /*	if (item->NextBox == 0)
1333 	{
1334 		PyErr_SetString(ScribusException, QObject::tr("Object the last frame in a series, can't unlink. Unlink the previous frame instead.","python error").toLocal8Bit().constData());
1335 		return nullptr;
1336 	}
1337 	*/
1338 /*	PageItem* nextbox = item->NextBox;
1339 
1340 	while (nextbox != 0)
1341 	{
1342 		uint a = nextbox->itemText.count();
1343 		for (uint s=0; s<a; ++s)
1344 			item->itemText.append(nextbox->itemText.take(0));
1345 		nextbox = nextbox->NextBox;
1346 	} // while
1347 	uint a2 = item->itemText.count();
1348 	for (uint s = 0; s < a2; ++s)
1349 		item->BackBox->itemText.append(item->itemText.take(0));
1350 */
1351 	item->prevInChain()->unlink();
1352 	// enable 'save icon' stuff
1353 	ScCore->primaryMainWindow()->slotDocCh();
1354 	ScCore->primaryMainWindow()->view->DrawNew();
1355 
1356 	Py_RETURN_NONE;
1357 }
1358 
1359 /*
1360  * Convert the selected text frame to outlines.
1361  *
1362  * 2004-09-07 (Craig Ringer)
1363  * 2004-09-14 pv frame type, optional frame name param
1364  */
scribus_outlinetext(PyObject *,PyObject * args)1365 PyObject *scribus_outlinetext(PyObject* /* self */, PyObject* args)
1366 {
1367 	char *name = const_cast<char*>("");
1368 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
1369 		return nullptr;
1370 	if (!checkHaveDocument())
1371 		return nullptr;
1372 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1373 	if (item == nullptr)
1374 		return nullptr;
1375 	if (!item->isTextFrame())
1376 	{
1377 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot convert a non-text frame to outlines.","python error").toLocal8Bit().constData());
1378 		return nullptr;
1379 	}
1380 	if (item->invalid)
1381 		item->layout();
1382 	ScCore->primaryMainWindow()->view->deselectItems(true);
1383 	ScCore->primaryMainWindow()->view->selectItem(item);
1384 	ScCore->primaryMainWindow()->view->TextToPath();
1385 
1386 	Py_RETURN_NONE;
1387 }
1388 
scribus_istextoverflowing(PyObject * self,PyObject * args,PyObject * kw)1389 PyObject *scribus_istextoverflowing(PyObject * self, PyObject* args, PyObject* kw)
1390 {
1391 	int nolinks = 0;
1392 	char *name = const_cast<char*>("");
1393 	char *kwargs[] = {const_cast<char*>("name"), const_cast<char*>("nolinks"), nullptr};
1394 	if (!PyArg_ParseTupleAndKeywords(args, kw, "|esi", kwargs, "utf-8", &name, &nolinks))
1395 		return nullptr;
1396 	if (!checkHaveDocument())
1397 		return nullptr;
1398 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1399 	if (item == nullptr)
1400 		return nullptr;
1401 	if (!item->isTextFrame())
1402 	{
1403 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Only text frames can be checked for overflowing", "python error").toLocal8Bit().constData());
1404 		return nullptr;
1405 	}
1406 	/* original solution
1407 	if (item->itemText.count() > item->MaxChars)
1408 	return PyBool_FromLong(static_cast<long>(true));
1409 	return PyBool_FromLong(static_cast<long>(false)); */
1410 	/*
1411 	 uint firstFrame = 0;
1412 	if (nolinks)
1413 		firstFrame = item->itemText.count();
1414 	uint chars = item->itemText.count();
1415 	uint maxchars = item->MaxChars;
1416 	while (item->NextBox != 0) {
1417 		item = item->NextBox;
1418 		chars += item->itemText.count();
1419 		maxchars += item->MaxChars;
1420 	}
1421 	// no overrun
1422 	if (nolinks)
1423 		return PyLong_FromLong(maxchars - firstFrame);
1424 
1425 	if (maxchars > chars)
1426 		return PyLong_FromLong(0);
1427 	// number of overrunning letters
1428 	return PyLong_FromLong(static_cast<long>(chars - maxchars));
1429 	 */
1430 	// refresh overflow information
1431 	item->invalidateLayout();
1432 	item->layout();
1433 	return PyLong_FromLong(static_cast<long>(item->frameOverflows()));
1434 }
1435 
1436 /*
1437  * Does hyphenation on the given text frame.
1438  * 08.12.2007: Joachim Neu
1439  */
scribus_hyphenatetext(PyObject *,PyObject * args)1440 PyObject *scribus_hyphenatetext(PyObject*, PyObject* args)
1441 {
1442 	char *name = const_cast<char*>("");
1443 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
1444 		return nullptr;
1445 	if (!checkHaveDocument())
1446 		return nullptr;
1447 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1448 	if (item == nullptr)
1449 		return nullptr;
1450 	if (!item->isTextFrame())
1451 	{
1452 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only hyphenate text frame", "python error").toLocal8Bit().constData());
1453 		return nullptr;
1454 	}
1455 	ScCore->primaryMainWindow()->doc->docHyphenator->slotHyphenate(item);
1456 	return PyBool_FromLong(1);
1457 }
1458 
1459 /*
1460  * Does dehyphenation on the given text frame.
1461  * 13.12.2007: Joachim Neu
1462  */
scribus_dehyphenatetext(PyObject *,PyObject * args)1463 PyObject *scribus_dehyphenatetext(PyObject*, PyObject* args)
1464 {
1465 	char *name = const_cast<char*>("");
1466 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
1467 		return nullptr;
1468 	if (!checkHaveDocument())
1469 		return nullptr;
1470 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1471 	if (item == nullptr)
1472 		return nullptr;
1473 	if (!item->isTextFrame())
1474 	{
1475 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only dehyphenate text frame", "python error").toLocal8Bit().constData());
1476 		return nullptr;
1477 	}
1478 	ScCore->primaryMainWindow()->doc->docHyphenator->slotDeHyphenate(item);
1479 	return PyBool_FromLong(1);
1480 }
1481 
scribus_setpdfbookmark(PyObject *,PyObject * args)1482 PyObject *scribus_setpdfbookmark(PyObject* /* self */, PyObject* args)
1483 {
1484 	char *name = const_cast<char*>("");
1485 	bool toggle;
1486 	if (!PyArg_ParseTuple(args, "b|es", &toggle, "utf-8", &name))
1487 		return nullptr;
1488 	if (!checkHaveDocument())
1489 		return nullptr;
1490 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1491 	if (item == nullptr)
1492 		return nullptr;
1493 	if (!item->isTextFrame())
1494 	{
1495 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Can't set bookmark on a non-text frame", "python error").toLocal8Bit().constData());
1496 		return nullptr;
1497 	}
1498 	if (item->isBookmark == toggle)
1499 		Py_RETURN_NONE;
1500 	if (toggle)
1501 	{
1502 		item->setIsAnnotation(false);
1503 		ScCore->primaryMainWindow()->AddBookMark(item);
1504 	}
1505 	else
1506 		ScCore->primaryMainWindow()->DelBookMark(item);
1507 	item->isBookmark = toggle;
1508 
1509 	Py_RETURN_NONE;
1510 }
1511 
scribus_ispdfbookmark(PyObject *,PyObject * args)1512 PyObject *scribus_ispdfbookmark(PyObject* /* self */, PyObject* args)
1513 {
1514 	char *name = const_cast<char*>("");
1515 	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
1516 		return nullptr;
1517 	if (!checkHaveDocument())
1518 		return nullptr;
1519 	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
1520 	if (item == nullptr)
1521 		return nullptr;
1522 	if (!item->isTextFrame())
1523 	{
1524 		PyErr_SetString(WrongFrameTypeError, QObject::tr("Can't get info from a non-text frame", "python error").toLocal8Bit().constData());
1525 		return nullptr;
1526 	}
1527 	if (item->isBookmark)
1528 		return PyBool_FromLong(1);
1529 	return PyBool_FromLong(0);
1530 }
1531 
1532 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
1533 with header files structure untouched (docstrings are kept near declarations)
1534 PV */
cmdtextdocwarnings()1535 void cmdtextdocwarnings()
1536 {
1537 	QStringList s;
1538 	s << scribus_dehyphenatetext__doc__
1539 	  << scribus_deletetext__doc__
1540 	  << scribus_getalltext__doc__
1541 	  << scribus_getcolumngap__doc__
1542 	  << scribus_getcolumns__doc__
1543 	  << scribus_getfirstlineoffset__doc__
1544 	  << scribus_getfirstlinkedframe__doc__
1545 	  << scribus_getfont__doc__
1546 	  << scribus_getfontfeatures__doc__
1547 	  << scribus_getfontsize__doc__
1548 	  << scribus_getframetext__doc__
1549 	  << scribus_getlastlinkedframe__doc__
1550 	  << scribus_getlinespacing__doc__
1551 	  << scribus_getnextlinkedframe__doc__
1552 	  << scribus_getprevlinkedframe__doc__
1553 	  << scribus_gettext__doc__ // Deprecated
1554 	  << scribus_gettextcolor__doc__
1555 	  << scribus_gettextdistances__doc__
1556 	  << scribus_gettextlength__doc__
1557 	  << scribus_gettextlines__doc__
1558 	  << scribus_gettextshade__doc__
1559 	  << scribus_gettextverticalalignment__doc__
1560 	  << scribus_hyphenatetext__doc__
1561 	  << scribus_inserthtmltext__doc__
1562 	  << scribus_inserttext__doc__
1563 	  << scribus_ispdfbookmark__doc__
1564 	  << scribus_istextoverflowing__doc__
1565 	  << scribus_layouttext__doc__
1566 	  << scribus_layouttextchain__doc__
1567 	  << scribus_linktextframes__doc__
1568 	  << scribus_outlinetext__doc__
1569 	  << scribus_selectframetext__doc__
1570 	  << scribus_selecttext__doc__
1571 	  << scribus_setcolumngap__doc__
1572 	  << scribus_setcolumns__doc__
1573 	  << scribus_setdirection__doc__
1574 	  << scribus_setfirstlineoffset__doc__
1575 	  << scribus_setfont__doc__
1576 	  << scribus_setfontfeatures__doc__
1577 	  << scribus_setfontsize__doc__
1578 	  << scribus_setlinespacing__doc__
1579 	  << scribus_setlinespacingmode__doc__
1580 	  << scribus_setpdfbookmark__doc__
1581 	  << scribus_settextdistances__doc__
1582 	  << scribus_settext__doc__
1583 	  << scribus_settextalignment__doc__
1584 	  << scribus_settextfill__doc__
1585 	  << scribus_settextscalingh__doc__
1586 	  << scribus_settextscalingv__doc__
1587 	  << scribus_settextshade__doc__
1588 	  << scribus_settextstroke__doc__
1589 	  << scribus_settextverticalalignment__doc__
1590 	  << scribus_tracetext__doc__
1591 	  << scribus_unlinktextframes__doc__;
1592 }
1593