cmdtext.cpp 48.1 KB
Newer Older
1
2
3
4
5
6
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
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
18
19
#include "selection.h"
#include "util.h"

20

21
template<typename T>
Jean Ghali's avatar
Jean Ghali committed
22
23
24
25
26
class ApplyCharstyleHelper
{
	PageItem* m_item;
	T m_value;

27
public:
Jean Ghali's avatar
Jean Ghali committed
28
	ApplyCharstyleHelper(PageItem* item, T v) : m_item(item), m_value(v) {}
29
30
31
32

	void apply(void (CharStyle::*f)(T), int p, int len)
	{
		CharStyle cs;
Jean Ghali's avatar
Jean Ghali committed
33
34
		(cs.*f)(m_value);
		if (m_item->HasSel)
35
		{
Jean Ghali's avatar
Jean Ghali committed
36
37
			int max = qMax(p + len, m_item->itemText.length());
			for (int i = p; i < max; i++)
38
			{
Jean Ghali's avatar
Jean Ghali committed
39
40
				if (m_item->itemText.selected(i))
					m_item->itemText.applyCharStyle(i, 1, cs);
41
42
43
44
			}
		}
		else
		{
Jean Ghali's avatar
Jean Ghali committed
45
			m_item->itemText.applyCharStyle(p, len, cs);
46
47
48
49
50
		}
	}

};

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;
Jean Ghali's avatar
Jean Ghali committed
56
	if (!checkHaveDocument())
57
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
58
59
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
60
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
	}
Jean Ghali's avatar
Jean Ghali committed
66
	if (item->HasSel)
67
	{
Jean Ghali's avatar
Jean Ghali committed
68
69
70
		for (int i = 0; i < item->itemText.length(); i++)
			if (item->itemText.selected(i))
				return PyFloat_FromDouble(static_cast<double>(item->itemText.charStyle(i).fontSize() / 10.0));
71
		return nullptr;
72
	}
Jean Ghali's avatar
Jean Ghali committed
73
	return PyFloat_FromDouble(static_cast<double>(item->currentCharStyle().fontSize() / 10.0));
74
75
}

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;
Jean Ghali's avatar
Jean Ghali committed
81
	if (!checkHaveDocument())
82
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
83
84
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
85
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
	}
Jean Ghali's avatar
Jean Ghali committed
91
	if (item->HasSel)
92
	{
Jean Ghali's avatar
Jean Ghali committed
93
94
		for (int i = 0; i < item->itemText.length(); i++)
			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
}

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
PyObject *scribus_gettextcolor(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
    if (!(item->isTextFrame()) && !(item->isPathText()))
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text color of non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
	if (item->HasSel)
	{
		for (int i = 0; i < item->itemText.length(); ++i)
		{
			if (item->itemText.selected(i))
121
				return PyUnicode_FromString(item->itemText.charStyle(i).fillColor().toUtf8());
122
123
124
		}
        return nullptr;
	}
125
    return PyUnicode_FromString(item->currentCharStyle().fillColor().toUtf8());
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}

PyObject *scribus_gettextshade(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!(item->isTextFrame()) && !(item->isPathText()))
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text color of non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
	if (item->HasSel)
	{
		for (int i = 0; i < item->itemText.length(); ++i)
		{
			if (item->itemText.selected(i))
148
				return PyLong_FromLong(item->itemText.charStyle(i).fillShade());
149
150
151
		}
		return nullptr;
	}
152
	return PyLong_FromLong(item->currentCharStyle().fillShade());
153
154
}

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;
Jean Ghali's avatar
Jean Ghali committed
160
	if (!checkHaveDocument())
161
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
162
163
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
164
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
}

173
174
175
176
PyObject *scribus_gettextlines(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
177
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
178
	if (!checkHaveDocument())
179
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
180
181
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
182
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
}

191
192
193
194
195
196
197
PyObject *scribus_gettextverticalalignment(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
198
199
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
200
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
201
	if (!item->isTextFrame())
202
203
204
205
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get vertical alignment of non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
206
	return PyLong_FromLong(static_cast<long>(item->verticalAlignment()));
207
208
}

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;
Jean Ghali's avatar
Jean Ghali committed
214
	if (!checkHaveDocument())
215
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
216
217
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
218
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
}

227
228
229
230
231
232
233
PyObject *scribus_getcolumngap(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
234
235
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
236
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
237
	if (!item->isTextFrame())
238
239
240
241
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column gap of non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
242
	return PyFloat_FromDouble(PointToValue(static_cast<double>(item->m_columnGap)));
243
244
}

245
246
247
248
PyObject *scribus_getfontfeatures(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
249
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
250
	if (!checkHaveDocument())
251
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
252
253
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
254
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
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
	}
Jean Ghali's avatar
Jean Ghali committed
260
	if (item->HasSel)
261
	{
Jean Ghali's avatar
Jean Ghali committed
262
263
		for (int i = 0; i < item->itemText.length(); i++)
			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
}

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
PyObject *scribus_getfirstlinkedframe(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
		return nullptr;
	}

	return PyUnicode_FromString(item->firstInChain()->itemName().toUtf8());
}

PyObject *scribus_getlastlinkedframe(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
		return nullptr;
	}

	return PyUnicode_FromString(item->lastInChain()->itemName().toUtf8());
}

PyObject *scribus_getnextlinkedframe(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
		return nullptr;
	}

	if (item->nextInChain() != nullptr)
		return PyUnicode_FromString(item->nextInChain()->itemName().toUtf8());

	Py_RETURN_NONE;
}

PyObject *scribus_getprevlinkedframe(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get linked frames of non-text frame.","python error").toLocal8Bit().constData());
		return nullptr;
	}

	if (item->prevInChain() != nullptr)
		return PyUnicode_FromString(item->prevInChain()->itemName().toUtf8());

	Py_RETURN_NONE;
}

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
PyObject *scribus_getfirstlineoffset(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get first line offset of non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
	return PyLong_FromLong(static_cast<long>(item->firstLineOffset()));
}

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;
Jean Ghali's avatar
Jean Ghali committed
375
	if (!checkHaveDocument())
376
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
377
378
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	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
	}
Jean Ghali's avatar
Jean Ghali committed
385
	return PyFloat_FromDouble(static_cast<double>(item->currentStyle().lineSpacing()));
386
387
}

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
PyObject *scribus_getlinespacingmode(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get line spacing mode of non-text frame.","python error").toLocal8Bit().constData());
		return nullptr;
	}
	return PyFloat_FromDouble(static_cast<double>(item->currentStyle().lineSpacingMode()));
}

406
407
408
409
PyObject *scribus_gettextdistances(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
410
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
411
	if (!checkHaveDocument())
412
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
413
414
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
415
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
416
	if (!item->isTextFrame())
417
418
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text distances of non-text frame.","python error").toLocal8Bit().constData());
419
		return nullptr;
420
421
	}
	return Py_BuildValue("(dddd)",
Jean Ghali's avatar
Jean Ghali committed
422
423
424
425
	        PointToValue(item->textToFrameDistLeft()),
	        PointToValue(item->textToFrameDistRight()),
	        PointToValue(item->textToFrameDistTop()),
	        PointToValue(item->textToFrameDistBottom()));
426
427
}

428
PyObject *scribus_getframetext(PyObject* /* self */, PyObject* args)
429
{
430
	char *Name = const_cast<char*>("");
431
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
432
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
433
	if (!checkHaveDocument())
434
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
435
436
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
437
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
438
	if (!(item->isTextFrame()) && !(item->isPathText()))
439
	{
440
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData());
441
		return nullptr;
442
	}
443
444
445
	
	const StoryText& story = item->itemText;
	QString text;
446
	text.reserve(story.hasSelection() ? story.selectionLength() : story.length());
Jean Ghali's avatar
Jean Ghali committed
447
	for (int i = item->firstInFrame(); i <= item->lastInFrame(); ++i)
448
	{
Jean Ghali's avatar
Jean Ghali committed
449
		if (item->HasSel)
450
		{
451
452
			if (story.selected(i))
				text += story.text(i);
453
		}
Petr Vanek's avatar
Petr Vanek committed
454
455
		else
		{
456
			text += story.text(i);
Petr Vanek's avatar
Petr Vanek committed
457
		}
458
	}
459
	return PyUnicode_FromString(text.toUtf8());
460
461
}

462
PyObject *scribus_getalltext(PyObject* /* self */, PyObject* args)
463
{
464
	char *Name = const_cast<char*>("");
465
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
466
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
467
	if (!checkHaveDocument())
468
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
469
470
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
471
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
472
	if (!(item->isTextFrame()) && !(item->isPathText()))
473
	{
474
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData());
475
		return nullptr;
476
	}
Andreas Vox's avatar
Andreas Vox committed
477
478

	// collect all chars from a storytext
479
480
	const StoryText& story = item->itemText;
	QString text;
481
	text.reserve(story.hasSelection() ? story.selectionLength() : story.length());
482
	for (int i = 0; i < story.length(); i++)
Petr Vanek's avatar
Petr Vanek committed
483
	{
Jean Ghali's avatar
Jean Ghali committed
484
		if (item->HasSel)
Petr Vanek's avatar
Petr Vanek committed
485
		{
486
487
			if (story.selected(i))
				text += story.text(i);
Petr Vanek's avatar
Petr Vanek committed
488
489
490
		}
		else
		{
491
			text += story.text(i);
Petr Vanek's avatar
Petr Vanek committed
492
		}
493
	}
494
	return PyUnicode_FromString(text.toUtf8());
495
496
}

497
PyObject *scribus_settext(PyObject* /* self */, PyObject* args)
498
{
499
	char *Name = const_cast<char*>("");
500
	char *Text;
501
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Text, "utf-8", &Name))
502
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
503
	if (!checkHaveDocument())
504
		return nullptr;
505
	PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name));
506
507
	if (currItem == nullptr)
		return nullptr;
508
	if (!(currItem->isTextFrame()) && !(currItem->isPathText()))
509
	{
510
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text of non-text frame.","python error").toLocal8Bit().constData());
511
		return nullptr;
512
	}
513
514
515
	QString userText = QString::fromUtf8(Text);
	userText.replace("\r\n", SpecialChars::PARSEP);
	userText.replace(QChar('\n') , SpecialChars::PARSEP);
Franz Schmid's avatar
Franz Schmid committed
516
	PyMem_Free(Text);
517
	currItem->itemText.clear();
518
	currItem->itemText.insertChars(0, userText);
519
	currItem->invalidateLayout();
520

521
	Py_RETURN_NONE;
522
523
}

524
PyObject *scribus_inserttext(PyObject* /* self */, PyObject* args)
525
{
526
	char *Name = const_cast<char*>("");
527
	char *Text;
528
	int pos;
529
	if (!PyArg_ParseTuple(args, "esi|es", "utf-8", &Text, &pos, "utf-8", &Name))
530
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
531
	if (!checkHaveDocument())
532
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
533
534
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
535
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
536
	if (!(item->isTextFrame()) && !(item->isPathText()))
537
	{
538
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot insert text into non-text frame.","python error").toLocal8Bit().constData());
539
		return nullptr;
540
	}
541
542
543
	QString textData = QString::fromUtf8(Text);
	textData.replace("\r\n", SpecialChars::PARSEP);
	textData.replace(QChar('\n') , SpecialChars::PARSEP);
Franz Schmid's avatar
Franz Schmid committed
544
	PyMem_Free(Text);
Jean Ghali's avatar
Jean Ghali committed
545
	if ((pos < -1) || (pos > static_cast<int>(item->itemText.length())))
Petr Vanek's avatar
Petr Vanek committed
546
	{
547
		PyErr_SetString(PyExc_IndexError, QObject::tr("Insert index out of bounds.","python error").toLocal8Bit().constData());
548
		return nullptr;
Petr Vanek's avatar
Petr Vanek committed
549
	}
550
	if (pos == -1)
Jean Ghali's avatar
Jean Ghali committed
551
552
		pos = item->itemText.length();
	item->itemText.insertChars(pos, textData, true);
553
554
	item->invalidateLayout();

555
	Py_RETURN_NONE;
556
557
}

558
559
PyObject *scribus_inserthtmltext(PyObject* /* self */, PyObject* args)
{
560
561
	char *name = const_cast<char*>("");
	char *file;
562

563
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &file, "utf-8", &name)) {
564
		return nullptr;
565
	}
566

Jean Ghali's avatar
Jean Ghali committed
567
	if (!checkHaveDocument()) {
568
		return nullptr;
569
	}
570

Jean Ghali's avatar
Jean Ghali committed
571
572
	PageItem *item = GetUniqueItem(QString::fromUtf8(name));
	if (item == nullptr) {
573
		return nullptr;
574
	}
575

Jean Ghali's avatar
Jean Ghali committed
576
	if (!(item->isTextFrame()) && !(item->isPathText())) {
577
578
579
		PyErr_SetString(WrongFrameTypeError,
				QObject::tr("Cannot insert text into non-text frame.",
					"python error").toLocal8Bit().constData());
580
		return nullptr;
581
	}
582
583
584

	QString fileName = QString::fromUtf8(file);

585
	gtGetText gt(ScCore->primaryMainWindow()->doc);
Jean Ghali's avatar
Jean Ghali committed
586
	gt.launchImporter(-1, fileName, false, QString("utf-8"), false, true, item);
587

588
589
	// FIXME: PyMem_Free() - are any needed??
	Py_RETURN_NONE;
590
591
}

592
593
594
595
596
597
598
599
600
601
602
603
PyObject *scribus_layouttext(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame() && !item->isPathText())
	{
604
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot layout text of a non-text frame.", "python error").toLocal8Bit().constData());
605
606
607
608
609
610
611
		return nullptr;
	}
	item->layout();

	Py_RETURN_NONE;
}

612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
PyObject *scribus_layouttextchain(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame() && !item->isPathText())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot layout text chain for a non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}

	if (item->isPathText())
	{
		item->layout();
		Py_RETURN_NONE;
	}
	
	PageItem* firstFrame = item->firstInChain();
	PageItem* nextFrame = firstFrame;
	while (nextFrame)
	{
		nextFrame->layout();
		nextFrame = nextFrame->nextInChain();
	}

	Py_RETURN_NONE;
}

645
PyObject *scribus_settextalignment(PyObject* /* self */, PyObject* args)
646
{
647
	char *Name = const_cast<char*>("");
Petr Vanek's avatar
Petr Vanek committed
648
	int alignment;
649
	if (!PyArg_ParseTuple(args, "i|es", &alignment, "utf-8", &Name))
650
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
651
	if (!checkHaveDocument())
652
		return nullptr;
Petr Vanek's avatar
Petr Vanek committed
653
	if ((alignment > 4) || (alignment < 0))
654
	{
655
		PyErr_SetString(PyExc_ValueError, QObject::tr("Alignment out of range. Use one of the scribus.ALIGN_* constants.","python error").toLocal8Bit().constData());
656
		return nullptr;
657
	}
Jean Ghali's avatar
Jean Ghali committed
658
659
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
660
		return nullptr;
661
	if (!item->isTextFrame())
662
	{
663
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text alignment on a non-text frame.","python error").toLocal8Bit().constData());
664
		return nullptr;
665
	}
666
667
668
669
670
671
	
	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
	int oldAppMode  = ScCore->primaryMainWindow()->doc->appMode;

	Selection tmpSelection(nullptr, false);
	tmpSelection.addItem(item);
Jean Ghali's avatar
Jean Ghali committed
672
	if (item->HasSel)
673
674
675
		doc->appMode = modeEdit;
	doc->itemSelection_SetAlignment(alignment, &tmpSelection);
	doc->appMode = oldAppMode;
676

677
	Py_RETURN_NONE;
678
679
}

680
681
682
683
684
PyObject *scribus_setdirection(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	int direction;
	if (!PyArg_ParseTuple(args, "i|es", &direction, "utf-8", &Name))
685
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
686
	if (!checkHaveDocument())
687
		return nullptr;
688
689
690
	if ((direction > 1) || (direction < 0))
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("direction out of range. Use one of the scribus.DIRECTION* constants.","python error").toLocal8Bit().constData());
691
		return nullptr;
692
	}
Jean Ghali's avatar
Jean Ghali committed
693
694
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
695
		return nullptr;
696
	if (!item->isTextFrame())
697
698
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text direction on a non-text frame.","python error").toLocal8Bit().constData());
699
		return nullptr;
700
	}
701
702
703
704
705
706

	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;

	Selection tmpSelection(nullptr, false);
	tmpSelection.addItem(item);
Jean Ghali's avatar
Jean Ghali committed
707
	if (item->HasSel)
708
709
710
		doc->appMode = modeEdit;
	doc->itemSelection_SetDirection(direction, &tmpSelection);
	doc->appMode = oldAppMode;
711
712
713
714

	Py_RETURN_NONE;
}

715
PyObject *scribus_setfontsize(PyObject* /* self */, PyObject* args)
716
{
717
	char *Name = const_cast<char*>("");
718
	double size;
719
	if (!PyArg_ParseTuple(args, "d|es", &size, "utf-8", &Name))
720
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
721
	if (!checkHaveDocument())
722
		return nullptr;
723
	if ((size > 512) || (size < 1))
724
	{
725
		PyErr_SetString(PyExc_ValueError, QObject::tr("Font size out of bounds - must be 1 <= size <= 512.","python error").toLocal8Bit().constData());
726
		return nullptr;
727
	}
Jean Ghali's avatar
Jean Ghali committed
728
729
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
730
		return nullptr;
Petr Vanek's avatar
Petr Vanek committed
731

Jean Ghali's avatar
Jean Ghali committed
732
	if (!item->isTextFrame())
733
	{
734
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font size on a non-text frame.","python error").toLocal8Bit().constData());
735
		return nullptr;
736
	}
737
738
739
740
741
742

	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;

	Selection tmpSelection(nullptr, false);
	tmpSelection.addItem(item);
Jean Ghali's avatar
Jean Ghali committed
743
	if (item->HasSel)
744
745
746
		doc->appMode = modeEdit;
	doc->itemSelection_SetFontSize(qRound(size * 10.0), &tmpSelection);
	doc->appMode = oldAppMode;
747

748
	Py_RETURN_NONE;
749
750
}

751
752
753
754
755
PyObject *scribus_setfontfeatures(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	char *fontfeature = const_cast<char*>("");
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &fontfeature, "utf-8", &Name))
756
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
757
	if (!checkHaveDocument())
758
		return nullptr;
759

Jean Ghali's avatar
Jean Ghali committed
760
761
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
762
		return nullptr;
763

Jean Ghali's avatar
Jean Ghali committed
764
	if (!item->isTextFrame())
765
766
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font feature on a non-text frame.","python error").toLocal8Bit().constData());
767
		return nullptr;
768
	}
769
770
771
772
773
774

	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;

	Selection tmpSelection(nullptr, false);
	tmpSelection.addItem(item);
Jean Ghali's avatar
Jean Ghali committed
775
	if (item->HasSel)
776
777
778
		doc->appMode = modeEdit;
	doc->itemSelection_SetFontFeatures(QString::fromUtf8(fontfeature), &tmpSelection);
	doc->appMode = oldAppMode;
779

780
781
782
	Py_RETURN_NONE;
}

783
PyObject *scribus_setfont(PyObject* /* self */, PyObject* args)
784
{
785
786
	char *Name = const_cast<char*>("");
	char *Font = const_cast<char*>("");
787
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Font, "utf-8", &Name))
788
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
789
	if (!checkHaveDocument())
790
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
791
792
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
793
		return nullptr;
Jean Ghali's avatar
Jean Ghali committed
794
	if (!(item->isTextFrame()) && !(item->isPathText()))
Petr Vanek's avatar
Petr Vanek committed
795
	{
796
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font on a non-text frame.","python error").toLocal8Bit().constData());
797
		return nullptr;
Petr Vanek's avatar
Petr Vanek committed
798
	}
799
	if (!PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.contains(QString::fromUtf8(Font)))
800
	{
801
		PyErr_SetString(PyExc_ValueError, QObject::tr("Font not found.", "python error").toLocal8Bit().constData());
802
		return nullptr;
Petr Vanek's avatar
Petr Vanek committed
803
	}
804
805
806
807
808
809
810
811
812
813
814

	ScribusDoc* doc = ScCore->primaryMainWindow()->doc;
	int oldAppMode = ScCore->primaryMainWindow()->doc->appMode;

	Selection tmpSelection(nullptr, false);
	tmpSelection.addItem(item);
	if (item->HasSel)
		doc->appMode = modeEdit;
	doc->itemSelection_SetFont(QString::fromUtf8(Font), &tmpSelection);
	doc->appMode = oldAppMode;

815
	Py_RETURN_NONE;
816
817
}

818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
PyObject *scribus_setfirstlineoffset(PyObject* /* self */, PyObject* args)
{
	char *Name = const_cast<char*>("");
	int offset;
	if (!PyArg_ParseTuple(args, "i|es", &offset, "utf-8", &Name))
		return nullptr;
	if (!checkHaveDocument())
		return nullptr;
	if (offset < 0 || offset > (int) FLOPBaselineGrid)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("First line offset out of bounds, Use one of the scribus.FLOP_* constants.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
	if (item == nullptr)
		return nullptr;
	if (!item->isTextFrame())
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set first line offset on a non-text frame.", "python error").toLocal8Bit().constData());
		return nullptr;
	}
	item->setFirstLineOffset((FirstLineOffsetPolicy) offset);
	item->update();

	Py_RETURN_NONE;
}

845
PyObject *scribus_setlinespacing(PyObject* /* self */, PyObject* args)
846
{
847
	char *Name = const_cast<char*>("");
848
	double w;