diff options
| author | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
|---|---|---|
| committer | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
| commit | 7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch) | |
| tree | 4430b556abac0ad660a0aacf1887d77f85d8be02 /scribus/plugins/scriptplugin | |
| download | scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.gz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.xz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.zip | |
Branch 1.3.5 tree to 1.4.x tree, goodbye 1.3.x
git-svn-id: svn://scribus.net/branches/Version14x/Scribus@17163 11d20701-8431-0410-a711-e3c959e3b870
Diffstat (limited to 'scribus/plugins/scriptplugin')
99 files changed, 20418 insertions, 0 deletions
diff --git a/scribus/plugins/scriptplugin/CMakeLists.txt b/scribus/plugins/scriptplugin/CMakeLists.txt new file mode 100644 index 0000000..6ed7b4d --- /dev/null +++ b/scribus/plugins/scriptplugin/CMakeLists.txt @@ -0,0 +1,73 @@ +INCLUDE_DIRECTORIES( +${CMAKE_SOURCE_DIR} +${CMAKE_SOURCE_DIR}/scribus +) + +ADD_SUBDIRECTORY(samples) +ADD_SUBDIRECTORY(scripts) + +SET(SCRIPTER_PLUGIN_UI_SRC + pconsole.ui + runscriptdialog.ui + scripterprefsgui.ui +) + +SET(SCRIPTER_PLUGIN_MOC_CLASSES + pconsole.h + scriptplugin.h + scriptercore.h + scripterprefsgui.h + runscriptdialog.h +) + +SET(SCRIPTER_PLUGIN_SOURCES + cmdcolor.cpp + cmddialog.cpp + cmddoc.cpp + cmdgetprop.cpp + cmdgetsetprop.cpp + cmdmani.cpp + cmdmisc.cpp + cmdobj.cpp + cmdpage.cpp + cmdsetprop.cpp + cmdstyle.cpp + cmdtext.cpp + cmdutil.cpp + guiapp.cpp + objimageexport.cpp + objpdffile.cpp + objprinter.cpp + pconsole.cpp + runscriptdialog.cpp + scriptercore.cpp + scripterprefsgui.cpp + scriptplugin.cpp + svgimport.cpp +) + +SET(SCRIBUS_SCRIPTER_PLUGIN "scriptplugin") + +QT4_WRAP_UI(SCRIPTER_PLUGIN_UI_SOURCES ${SCRIPTER_PLUGIN_UI_SRC} ) +QT4_WRAP_CPP(SCRIPTER_PLUGIN_MOC_SOURCES ${SCRIPTER_PLUGIN_MOC_CLASSES}) + +ADD_LIBRARY(${SCRIBUS_SCRIPTER_PLUGIN} MODULE + ${SCRIPTER_PLUGIN_SOURCES} + ${SCRIPTER_PLUGIN_MOC_SOURCES} + ${SCRIPTER_PLUGIN_UI_SOURCES}) + +TARGET_LINK_LIBRARIES(${SCRIBUS_SCRIPTER_PLUGIN} + ${PYTHON_LIBRARIES} +) + +TARGET_LINK_LIBRARIES(${SCRIBUS_SCRIPTER_PLUGIN} ${PLUGIN_LIBRARIES}) + +INSTALL(TARGETS ${SCRIBUS_SCRIPTER_PLUGIN} + LIBRARY + DESTINATION ${PLUGINDIR} + PERMISSIONS ${PLUGIN_PERMISSIONS} +) + +ADD_DEPENDENCIES(${SCRIBUS_SCRIPTER_PLUGIN} ${EXE_NAME}) + +# SET_TARGET_PROPERTIES(${SCRIBUS_SCRIPTER_PLUGIN} PROPERTIES VERSION "0.0.0") diff --git a/scribus/plugins/scriptplugin/README.BOOST b/scribus/plugins/scriptplugin/README.BOOST new file mode 100644 index 0000000..281c4a9 --- /dev/null +++ b/scribus/plugins/scriptplugin/README.BOOST @@ -0,0 +1,50 @@ +Experimental support for the use of Boost::Python has been added to the Python +interface. All Boost code is exported in a separate module, scribus2, that is +only created if Boost::Python is available. + +Currently there's no autotools support for this in Scribus, so to compile the +scripter with this highly experimental feature you must: + +$ make clean +$ make CXXFLAGS=" -Wno-extra -Wno-unused -DHAVE_BOOST_PYTHON -fexceptions " LDFLAGS=" -lboost_python " +$ make install + +For more information on Boost::Python see: + http://www.boost.org/libs/python/doc/ + http://www-eleves-isia.cma.fr/documentation/BoostDoc/boost_1_29_0/libs/python/doc/tutorial/ + +It's strongly recommended that you read the FAQ at: + http://www.boost.org/libs/python/doc/v2/faq.html +(probably once before reading the code, and again after). + +All the fun stuff is in the `scribus2' module and is used for manipulating +paragraph styles. There are currently two (dirty hack) interfaces. One is a +"value based" interface - ask for a /copy of/ a style, add a style by /copying/ +it into the style list, etc. The other interface is reference based - get a +dict of references to the existing styles and modify them directly. Soon, +hopefully, add and remove styles from the dict as if it was a Python one too. +The value based interface is safer but clumsier; the reference based one +can be a tad dangerous but is very handy. + +Examples: + +>>> import scribus2 +>>> p = scribus2.ParagraphStyle() +>>> p.Vname = "testing" +>>> scribus2.addStyle(p) +>>> scribus2.getStyleNames() +[ blah, blah, blah , "testing" ] +>>> scribus2.getStylesRef()['testing'].Vname = "newname" +>>> scribus2.getStyleNames() +[ blah, blah, blah, "newname"] +>>> ref = scribus2.getStyleRef("newname") +>>> ref.Vname = "renamed" +>>> scribus2.getStyleNames() +[ blah, blah, blah, "renamed"] +>>> val = scribus2.getStyleVal("renamed") +>>> val.Vname = "doesnothing" +>>> scribus2.getStyleNames() +[ blah, blah, blah, "renamed"] +>>> scribus2.addStyle(val) +>>> scribus2.getStyleNames() +[ blah, blah, blah, "renamed", "doesnothing"] diff --git a/scribus/plugins/scriptplugin/cmdcolor.cpp b/scribus/plugins/scriptplugin/cmdcolor.cpp new file mode 100644 index 0000000..485ca5d --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdcolor.cpp @@ -0,0 +1,285 @@ +/* +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. +*/ +#include "cmdcolor.h" +#include "cmdutil.h" +#include "prefsmanager.h" +#include "commonstrings.h" +#include "scribuscore.h" +#include "sccolorengine.h" + +PyObject *scribus_colornames(PyObject* /* self */) +{ + ColorList edc; + PyObject *l; + int cc = 0; + edc = ScCore->primaryMainWindow()->HaveDoc ? ScCore->primaryMainWindow()->doc->PageColors : PrefsManager::instance()->colorSet(); + ColorList::Iterator it; + l = PyList_New(edc.count()); + for (it = edc.begin(); it != edc.end(); ++it) + { + PyList_SetItem(l, cc, PyString_FromString(it.key().toUtf8())); + cc++; + } + return l; +} + +PyObject *scribus_getcolor(PyObject* /* self */, PyObject* args) +{ + ColorList edc; + char *Name = const_cast<char*>(""); + int c, m, y, k; + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot get a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + edc = ScCore->primaryMainWindow()->HaveDoc ? ScCore->primaryMainWindow()->doc->PageColors : PrefsManager::instance()->colorSet(); + ScribusDoc* currentDoc = ScCore->primaryMainWindow()->HaveDoc ? ScCore->primaryMainWindow()->doc : NULL; + QString col = QString::fromUtf8(Name); + if (!edc.contains(col)) + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found.","python error").toLocal8Bit().constData()); + return NULL; + } + CMYKColor cmykValues; + ScColorEngine::getCMYKValues(edc[col], currentDoc, cmykValues); + cmykValues.getValues(c, m, y, k); + return Py_BuildValue("(iiii)", static_cast<long>(c), static_cast<long>(m), static_cast<long>(y), static_cast<long>(k)); +} + +PyObject *scribus_getcolorasrgb(PyObject* /* self */, PyObject* args) +{ + ColorList edc; + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot get a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + edc = ScCore->primaryMainWindow()->HaveDoc ? ScCore->primaryMainWindow()->doc->PageColors : PrefsManager::instance()->colorSet(); + ScribusDoc* currentDoc = ScCore->primaryMainWindow()->HaveDoc ? ScCore->primaryMainWindow()->doc : NULL; + QString col = QString::fromUtf8(Name); + if (!edc.contains(col)) + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found.","python error").toLocal8Bit().constData()); + return NULL; + } + QColor rgb = ScColorEngine::getRGBColor(edc[col], currentDoc); + return Py_BuildValue("(iii)", static_cast<long>(rgb.red()), static_cast<long>(rgb.green()), static_cast<long>(rgb.blue())); +} + +PyObject *scribus_setcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int c, m, y, k; + if (!PyArg_ParseTuple(args, "esiiii", "utf-8", &Name, &c, &m, &y, &k)) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot change a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + if (ScCore->primaryMainWindow()->HaveDoc) + { + if (!ScCore->primaryMainWindow()->doc->PageColors.contains(col)) + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found in document.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->PageColors[col].setColor(c, m, y, k); + } + else + { + ColorList* colorList=PrefsManager::instance()->colorSetPtr(); + if (!colorList->contains(col)) + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found in default colors.","python error").toLocal8Bit().constData()); + return NULL; + } + (*colorList)[col].setColor(c, m, y, k); + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_newcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int c, m, y, k; + if (!PyArg_ParseTuple(args, "esiiii", "utf-8", &Name, &c, &m, &y, &k)) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot create a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + if (ScCore->primaryMainWindow()->HaveDoc) + { + if (!ScCore->primaryMainWindow()->doc->PageColors.contains(col)) + ScCore->primaryMainWindow()->doc->PageColors.insert(col, ScColor(c, m, y, k)); + else + // FIXME: Given that we have a changeColour function, should we really be + // silently changing colours in newColour? + ScCore->primaryMainWindow()->doc->PageColors[col].setColor(c, m, y, k); + } + else + { + ColorList* colorList=PrefsManager::instance()->colorSetPtr(); + if (!colorList->contains(col)) + colorList->insert(col, ScColor(c, m, y, k)); + else + // FIXME: Given that we have a changeColour function, should we really be + // silently changing colours in newColour? + (*colorList)[col].setColor(c, m, y, k); + } + // Py_INCREF(Py_None); + // return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_delcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Repl = const_cast<char*>(CommonStrings::None.toLatin1().constData()); + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Name, "utf-8", &Repl)) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot delete a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + QString rep = QString::fromUtf8(Repl); + if (ScCore->primaryMainWindow()->HaveDoc) + { + if (ScCore->primaryMainWindow()->doc->PageColors.contains(col) && (ScCore->primaryMainWindow()->doc->PageColors.contains(rep) || (rep == CommonStrings::None))) + { + ScCore->primaryMainWindow()->doc->PageColors.remove(col); + ReplaceColor(col, rep); + } + else + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found in document.","python error").toLocal8Bit().constData()); + return NULL; + } + } + else + { + ColorList* colorList=PrefsManager::instance()->colorSetPtr(); + if (colorList->contains(col)) + colorList->remove(col); + else + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found in default colors.","python error").toLocal8Bit().constData()); + return NULL; + } + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_replcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Repl = const_cast<char*>(CommonStrings::None.toLatin1().constData()); + //FIXME: this should definitely use keyword arguments + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Name, "utf-8", &Repl)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot replace a color with an empty name.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + QString rep = QString::fromUtf8(Repl); + if (ScCore->primaryMainWindow()->doc->PageColors.contains(col) && (ScCore->primaryMainWindow()->doc->PageColors.contains(rep) || (rep == CommonStrings::None))) + ReplaceColor(col, rep); + else + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_isspotcolor(PyObject * /*self*/, PyObject* args) +{ + char *Name = const_cast<char*>(""); + + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Color name cannot be an empty string.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + if (ScCore->primaryMainWindow()->doc->PageColors.contains(col)) + { + return PyBool_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->PageColors[col].isSpotColor())); + } + else + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_RETURN_NONE; +} + +PyObject *scribus_setspotcolor(PyObject * /*self*/, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int enable; + + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &enable)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (strcmp(Name, "") == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Color name cannot be an empty string.","python error").toLocal8Bit().constData()); + return NULL; + } + QString col = QString::fromUtf8(Name); + if (ScCore->primaryMainWindow()->doc->PageColors.contains(col)) + { + ScCore->primaryMainWindow()->doc->PageColors[col].setSpotColor(static_cast<bool>(enable)); + } + else + { + PyErr_SetString(NotFoundError, QObject::tr("Color not found.","python error").toLocal8Bit().constData()); + return NULL; + } + Py_RETURN_NONE; +} + + + +/*! HACK: this removes "warning: 'blash' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdcolordocswarnings() +{ + QStringList s; + s << scribus_colornames__doc__ << scribus_getcolor__doc__ << scribus_getcolorasrgb__doc__; + s << scribus_setcolor__doc__ << scribus_newcolor__doc__ << scribus_delcolor__doc__; + s << scribus_replcolor__doc__ << scribus_isspotcolor__doc__ << scribus_setspotcolor__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdcolor.h b/scribus/plugins/scriptplugin/cmdcolor.h new file mode 100644 index 0000000..bf3f551 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdcolor.h @@ -0,0 +1,140 @@ +/* +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. +*/ +#ifndef CMDCOLOR_H +#define CMDCOLOR_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Managing Colors */ + +/*! docstring */ +PyDoc_STRVAR(scribus_colornames__doc__, +QT_TR_NOOP("getColorNames() -> list\n\ +\n\ +Returns a list containing the names of all defined colors in the document.\n\ +If no document is open, returns a list of the default document colors.\n\ +")); +/** Returns a list with colours available in doc or in prefs. */ +PyObject *scribus_colornames(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_getcolor__doc__, +QT_TR_NOOP("getColor(\"name\") -> tuple\n\ +\n\ +Returns a tuple (C, M, Y, K) containing the four color components of the\n\ +color \"name\" from the current document. If no document is open, returns\n\ +the value of the named color from the default document colors.\n\ +\n\ +May raise NotFoundError if the named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Returns a CMYK tuple of the specified color. */ +PyObject *scribus_getcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getcolorasrgb__doc__, +QT_TR_NOOP("getColorAsRGB(\"name\") -> tuple\n\ +\n\ +Returns a tuple (R,G,B) containing the three color components of the\n\ +color \"name\" from the current document, converted to the RGB color\n\ +space. If no document is open, returns the value of the named color\n\ +from the default document colors.\n\ +\n\ +May raise NotFoundError if the named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Returns a CMYK tuple of the specified color. */ +PyObject *scribus_getcolorasrgb(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setcolor__doc__, +QT_TR_NOOP("changeColor(\"name\", c, m, y, k)\n\ +\n\ +Changes the color \"name\" to the specified CMYK value. The color value is\n\ +defined via four components c = Cyan, m = Magenta, y = Yellow and k = Black.\n\ +Color components should be in the range from 0 to 255.\n\ +\n\ +May raise NotFoundError if the named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Sets named color with C,M,Y,K params. */ +PyObject *scribus_setcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newcolor__doc__, +QT_TR_NOOP("defineColor(\"name\", c, m, y, k)\n\ +\n\ +Defines a new color \"name\". The color Value is defined via four components:\n\ +c = Cyan, m = Magenta, y = Yellow and k = Black. Color components should be in\n\ +the range from 0 to 255.\n\ +\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Creates new color with name, C, M, Y, K params. */ +PyObject *scribus_newcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_delcolor__doc__, +QT_TR_NOOP("deleteColor(\"name\", \"replace\")\n\ +\n\ +Deletes the color \"name\". Every occurence of that color is replaced by the\n\ +color \"replace\". If not specified, \"replace\" defaults to the color\n\ +\"None\" - transparent.\n\ +\n\ +deleteColor works on the default document colors if there is no document open.\n\ +In that case, \"replace\", if specified, has no effect.\n\ +\n\ +May raise NotFoundError if a named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Deletes named color */ +PyObject *scribus_delcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_replcolor__doc__, +QT_TR_NOOP("replaceColor(\"name\", \"replace\")\n\ +\n\ +Every occurence of the color \"name\" is replaced by the color \"replace\".\n\ +\n\ +May raise NotFoundError if a named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Replaces color with the 2nd one. */ +PyObject *scribus_replcolor(PyObject * /*self*/, PyObject* args); + + +/*! docstring */ +PyDoc_STRVAR(scribus_isspotcolor__doc__, +QT_TR_NOOP("isSpotColor(\"name\") -> bool\n\ +\n\ +Returns True if the color \"name\" is a spot color.\n\ +See also setSpotColor()\n\ +\n\ +May raise NotFoundError if a named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Replaces color with the 2nd one. */ +PyObject *scribus_isspotcolor(PyObject * /*self*/, PyObject* args); + + + +/*! docstring */ +PyDoc_STRVAR(scribus_setspotcolor__doc__, +QT_TR_NOOP("setSpotColor(\"name\", spot)\n\ +\n\ +Set the color \"name\" as a spot color if spot parameter is True.\n\ +See also isSpotColor()\n\ +\n\ +May raise NotFoundError if a named color wasn't found.\n\ +May raise ValueError if an invalid color name is specified.\n\ +")); +/** Replaces color with the 2nd one. */ +PyObject *scribus_setspotcolor(PyObject * /*self*/, PyObject* args); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmddialog.cpp b/scribus/plugins/scriptplugin/cmddialog.cpp new file mode 100644 index 0000000..68b4865 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmddialog.cpp @@ -0,0 +1,145 @@ +/* +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. +*/ +#include "cmddialog.h" +#include "cmdutil.h" +#include "scribuscore.h" +#include "customfdialog.h" +#include "stylemanager.h" + +#include <QMessageBox> +#include <QCursor> +#include <QInputDialog> + + +PyObject *scribus_newdocdia(PyObject* /* self */) +{ + QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor)); + bool ret = ScCore->primaryMainWindow()->slotFileNew(); + QApplication::changeOverrideCursor(Qt::ArrowCursor); + return PyInt_FromLong(static_cast<long>(ret)); +} + +PyObject *scribus_filedia(PyObject* /* self */, PyObject* args, PyObject* kw) +{ + char *caption = const_cast<char*>(""); + char *filter = const_cast<char*>(""); + char *defName = const_cast<char*>(""); + int haspreview = 0; + int issave = 0; + int isdir = 0; + // FIXME: parsing named params failure. e.g. fileDialog(caption="foo", issave=True) + // FIXME: it's a bug in Python. I'm monitoring it + // https://sourceforge.net/tracker/index.php?func=detail&aid=893549&group_id=5470&atid=105470 + char* kwargs[] = {const_cast<char*>("caption"), const_cast<char*>("filter"), + const_cast<char*>("defaultname"), const_cast<char*>("haspreview"), + const_cast<char*>("issave"), const_cast<char*>("isdir"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "es|esesiii", kwargs, + "utf-8", &caption, "utf-8", &filter, "utf-8", &defName, + &haspreview, &issave, &isdir)) + { + return NULL; + } + QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor)); + /* nobool = Nothing doing boolean for CFileDialog last attrs. + Due the 'isdir' parameter. CFileDialog needs the last 2 pointers + initialized. */ + bool nobool = false; + int optionFlags = 0; + if (haspreview) + optionFlags |= fdShowPreview; + if (issave) + optionFlags |= fdExistingFiles; + if (isdir) + optionFlags |= fdDirectoriesOnly; + QString fName = ScCore->primaryMainWindow()->CFileDialog(".", + QString::fromUtf8(caption), + QString::fromUtf8(filter), + QString::fromUtf8(defName), + optionFlags, + &nobool, + &nobool, + &nobool + ); +// QApplication::restoreOverrideCursor(); + // FIXME: filename return unicode OK? + return PyString_FromString(fName.toUtf8()); +} + +PyObject *scribus_messdia(PyObject* /* self */, PyObject* args, PyObject* kw) +{ + char *caption = const_cast<char*>(""); + char *message = const_cast<char*>(""); + uint result; + QMessageBox::Icon ico = QMessageBox::NoIcon; + int butt1 = QMessageBox::Ok|QMessageBox::Default; + int butt2 = QMessageBox::NoButton; + int butt3 = QMessageBox::NoButton; + char* kwargs[] = {const_cast<char*>("caption"), const_cast<char*>("message"), + const_cast<char*>("icon"), const_cast<char*>("button1"), + const_cast<char*>("button2"), const_cast<char*>("button3"), NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "eses|iiii", kwargs, "utf-8", &caption, "utf-8", &message, &ico, &butt1, &butt2, &butt3)) + return NULL; + QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor)); + QMessageBox mb(QString::fromUtf8(caption), QString::fromUtf8(message), ico, butt1, butt2, butt3, ScCore->primaryMainWindow()); + result = mb.exec(); +// QApplication::restoreOverrideCursor(); + return PyInt_FromLong(static_cast<long>(result)); +} + +PyObject *scribus_valdialog(PyObject* /* self */, PyObject* args) +{ + char *caption = const_cast<char*>(""); + char *message = const_cast<char*>(""); + char *value = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "eses|es", "utf-8", &caption, "utf-8", &message, "utf-8", &value)) + return NULL; + QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor)); + QString txt = QInputDialog::getText(ScCore->primaryMainWindow(), + QString::fromUtf8(caption), + QString::fromUtf8(message), + QLineEdit::Normal, + QString::fromUtf8(value)); +// QApplication::restoreOverrideCursor(); + return PyString_FromString(txt.toUtf8()); +} + +PyObject *scribus_newstyledialog(PyObject*, PyObject* args) +{ + if(!checkHaveDocument()) + return NULL; + + ScribusDoc *d = ScCore->primaryMainWindow()->doc; + bool ok; + QString s = QInputDialog::getText(ScCore->primaryMainWindow(), "New Paragraph Style", + "Enter name of the new paragraph style:", QLineEdit::Normal, + QString::null, &ok); + + if (ok && !s.isEmpty()) + { + StyleSet<ParagraphStyle> st; + st.redefine(d->paragraphStyles(), true); + ParagraphStyle p; + p.setName(s); + st.create(p); + d->redefineStyles(st, false); + ScCore->primaryMainWindow()->styleMgr()->setDoc(d); + return PyString_FromString(s.toUtf8()); + } + else + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blash' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmddialogdocwarnings() +{ + QStringList s; + s << scribus_newdocdia__doc__ << scribus_filedia__doc__ << scribus_messdia__doc__; + s << scribus_valdialog__doc__ << scribus_newstyledialog__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmddialog.h b/scribus/plugins/scriptplugin/cmddialog.h new file mode 100644 index 0000000..52f8ef3 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmddialog.h @@ -0,0 +1,115 @@ +/* +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. +*/ +#ifndef CMDDIALOG_H +#define CMDDIALOG_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Calling Dialogs from Scribus */ + +/*! docstring */ +PyDoc_STRVAR(scribus_newdocdia__doc__, +QT_TR_NOOP("newDocDialog() -> bool\n\ +\n\ +Displays the \"New Document\" dialog box. Creates a new document if the user\n\ +accepts the settings. Does not create a document if the user presses cancel.\n\ +Returns true if a new document was created.\n\ +")); +/** Raises the Scribus New Document dialog */ +PyObject *scribus_newdocdia(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_filedia__doc__, +QT_TR_NOOP("fileDialog(\"caption\", [\"filter\", \"defaultname\", haspreview, issave, isdir]) -> string with filename\n\ +\n\ +Shows a File Open dialog box with the caption \"caption\". Files are filtered\n\ +with the filter string \"filter\". A default filename or file path can also\n\ +supplied, leave this string empty when you don't want to use it. A value of\n\ +True for haspreview enables a small preview widget in the FileSelect box. When\n\ +the issave parameter is set to True the dialog acts like a \"Save As\" dialog\n\ +otherwise it acts like a \"File Open Dialog\". When the isdir parameter is True\n\ +the dialog shows and returns only directories. The default for all of the\n\ +optional parameters is False.\n\ +\n\ +The filter, if specified, takes the form 'comment (*.type *.type2 ...)'.\n\ +For example 'Images (*.png *.xpm *.jpg)'.\n\ +\n\ +Refer to the Qt-Documentation for QFileDialog for details on filters.\n\ +\n\ +Example: fileDialog('Open input', 'CSV files (*.csv)')\n\ +Example: fileDialog('Save report', defaultname='report.txt', issave=True)\n\ +")); +/** Raises file dialog. + Params - caption, filter, default name and opt. pre, mode. */ +PyObject *scribus_filedia(PyObject * /*self*/, PyObject* args, PyObject* kw); +/* duplicity Sends a string into the Message Bar +PyObject *scribus_mess(PyObject *self, PyObject* args); +*/ + +/*! docstring */ +PyDoc_STRVAR(scribus_messdia__doc__, +QT_TR_NOOP("messageBox(\"caption\", \"message\",\n\ + icon=ICON_NONE, button1=BUTTON_OK|BUTTONOPT_DEFAULT,\n\ + button2=BUTTON_NONE, button3=BUTTON_NONE) -> integer\n\ +\n\ +Displays a message box with the title \"caption\", the message \"message\", and\n\ +an icon \"icon\" and up to 3 buttons. By default no icon is used and a single\n\ +button, OK, is displayed. Only the caption and message arguments are required,\n\ +though setting an icon and appropriate button(s) is strongly\n\ +recommended. The message text may contain simple HTML-like markup.\n\ +\n\ +Returns the number of the button the user pressed. Button numbers start\n\ +at 1.\n\ +\n\ +For the icon and the button parameters there are predefined constants available\n\ +with the same names as in the Qt Documentation. These are the BUTTON_* and\n\ +ICON_* constants defined in the module. There are also two extra constants that\n\ +can be binary-ORed with button constants:\n\ + BUTTONOPT_DEFAULT Pressing enter presses this button.\n\ + BUTTONOPT_ESCAPE Pressing escape presses this button.\n\ +\n\ +Usage examples:\n\ +result = messageBox('Script failed',\n\ + 'This script only works when you have a text frame selected.',\n\ + ICON_ERROR)\n\ +result = messageBox('Monkeys!', 'Something went ook! <i>Was it a monkey?</i>',\n\ + ICON_WARNING, BUTTON_YES|BUTTONOPT_DEFAULT,\n\ + BUTTON_NO, BUTTON_IGNORE|BUTTONOPT_ESCAPE)\n\ +\n\ +Defined button and icon constants:\n\ +BUTTON_NONE, BUTTON_ABORT, BUTTON_CANCEL, BUTTON_IGNORE, BUTTON_NO,\n\ +BUTTON_NOALL, BUTTON_OK, BUTTON_RETRY, BUTTON_YES, BUTTON_YESALL,\n\ +ICON_NONE, ICON_INFORMATION, ICON_WARNING, ICON_CRITICAL.\n\ +")); +/** Displays a message box with - caption, message, icon, button + and two more buttons optional. */ +PyObject *scribus_messdia(PyObject * /*self*/, PyObject* args, PyObject* kw); + +/*! docstring */ +PyDoc_STRVAR(scribus_valdialog__doc__, +QT_TR_NOOP("valueDialog(caption, message [,defaultvalue]) -> string\n\ +\n\ +Shows the common 'Ask for string' dialog and returns its value as a string\n\ +Parameters: window title, text in the window and optional 'default' value.\n\ +\n\ +Example: valueDialog('title', 'text in the window', 'optional')\n\ +")); +/* 09/24/2004 petr vanek */ +PyObject *scribus_valdialog(PyObject * /*self*/, PyObject* args); + + +PyDoc_STRVAR(scribus_newstyledialog__doc__, +QT_TR_NOOP("newStyleDialog() -> string\n\ +\n\ +Shows 'Create new paragraph style' dialog. Function returns real\n\ +style name or None when user cancels the dialog.\n\ +")); +/* 09/24/2004 petr vanek */ +PyObject *scribus_newstyledialog(PyObject * /*self*/, PyObject* args); + +#endif diff --git a/scribus/plugins/scriptplugin/cmddoc.cpp b/scribus/plugins/scriptplugin/cmddoc.cpp new file mode 100644 index 0000000..52187e4 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmddoc.cpp @@ -0,0 +1,377 @@ +/* +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. +*/ +#include "cmddoc.h" +#include "cmdutil.h" +#include "units.h" +#include "documentinformation.h" +#include "scribuscore.h" + +/* +newDocument(size, margins, orientation, firstPageNumber, + unit, pagesType, firstPageOrder)*/ +PyObject *scribus_newdocument(PyObject* /* self */, PyObject* args) +{ + double topMargin, bottomMargin, leftMargin, rightMargin; + double pageWidth, pageHeight; + int orientation, firstPageNr, unit, pagesType, facingPages, firstPageOrder, numPages; + + PyObject *p, *m; + + if ((!PyArg_ParseTuple(args, "OOiiiiii", &p, &m, &orientation, + &firstPageNr, &unit, + &pagesType, + &firstPageOrder, + &numPages)) || + (!PyArg_ParseTuple(p, "dd", &pageWidth, &pageHeight)) || + (!PyArg_ParseTuple(m, "dddd", &leftMargin, &rightMargin, + &topMargin, &bottomMargin))) + return NULL; + if (numPages <= 0) + numPages = 1; + if (pagesType == 0) + { + facingPages = 0; + firstPageOrder = 0; + } + else + facingPages = 1; + // checking the bounds + if (pagesType < firstPageOrder) + { + PyErr_SetString(ScribusException, QObject::tr("firstPageOrder is bigger than allowed.","python error").toLocal8Bit().constData()); + return NULL; + } + + pageWidth = value2pts(pageWidth, unit); + pageHeight = value2pts(pageHeight, unit); + if (orientation == 1) + { + double x = pageWidth; + pageWidth = pageHeight; + pageHeight = x; + } + leftMargin = value2pts(leftMargin, unit); + rightMargin = value2pts(rightMargin, unit); + topMargin = value2pts(topMargin, unit); + bottomMargin = value2pts(bottomMargin, unit); + + bool ret = ScCore->primaryMainWindow()->doFileNew(pageWidth, pageHeight, + topMargin, leftMargin, rightMargin, bottomMargin, + // autoframes. It's disabled in python + // columnDistance, numberCols, autoframes, + 0, 1, false, + pagesType, unit, firstPageOrder, + orientation, firstPageNr, "Custom", true, numPages); + ScCore->primaryMainWindow()->doc->pageSets[pagesType].FirstPage = firstPageOrder; + + return PyInt_FromLong(static_cast<long>(ret)); +} + +PyObject *scribus_newdoc(PyObject* /* self */, PyObject* args) +{ + qDebug("WARNING: newDoc() procedure is obsolete, it will be removed in a forthcoming release. Use newDocument() instead."); + double b, h, lr, tpr, btr, rr, ebr; + int unit, ds, fsl, fNr, ori; + PyObject *p, *m; + if ((!PyArg_ParseTuple(args, "OOiiiii", &p, &m, &ori, &fNr, &unit, &ds, &fsl)) || + (!PyArg_ParseTuple(p, "dd", &b, &h)) || + (!PyArg_ParseTuple(m, "dddd", &lr, &rr, &tpr, &btr))) + return NULL; + + b = value2pts(b, unit); + h = value2pts(h, unit); + if (ori == 1) + { + ebr = b; + b = h; + h = ebr; + } + /*! \todo Obsolete! In the case of no facing pages use only firstpageleft + scripter is not new-page-size ready. + What is it: don't allow to use wrong FSL constant in the case of + onesided document. */ + if (ds!=1 && fsl>0) + fsl = 0; + // end of hack + + tpr = value2pts(tpr, unit); + lr = value2pts(lr, unit); + rr = value2pts(rr, unit); + btr = value2pts(btr, unit); + + bool ret = ScCore->primaryMainWindow()->doFileNew(b, h, tpr, lr, rr, btr, 0, 1, false, ds, unit, fsl, ori, fNr, "Custom", true); + // qApp->processEvents(); + return PyInt_FromLong(static_cast<long>(ret)); +} + +PyObject *scribus_setmargins(PyObject* /* self */, PyObject* args) +{ + double lr, tpr, btr, rr; + if (!PyArg_ParseTuple(args, "dddd", &lr, &rr, &tpr, &btr)) + return NULL; + if(!checkHaveDocument()) + return NULL; + MarginStruct margins(ValueToPoint(tpr), ValueToPoint(lr), ValueToPoint(btr), ValueToPoint(rr)); + ScCore->primaryMainWindow()->doc->resetPage(margins, ScCore->primaryMainWindow()->doc->currentPageLayout); + ScCore->primaryMainWindow()->view->reformPages(); + ScCore->primaryMainWindow()->doc->setModified(true); + ScCore->primaryMainWindow()->view->GotoPage(ScCore->primaryMainWindow()->doc->currentPageNumber()); + ScCore->primaryMainWindow()->view->DrawNew(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_closedoc(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->doc->setModified(false); + bool ret = ScCore->primaryMainWindow()->slotFileClose(); + qApp->processEvents(); + return PyInt_FromLong(static_cast<long>(ret)); +} + +PyObject *scribus_havedoc(PyObject* /* self */) +{ + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->HaveDoc)); +} + +PyObject *scribus_opendoc(PyObject* /* self */, PyObject* args) +{ + char *Name; + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + bool ret = ScCore->primaryMainWindow()->loadDoc(QString::fromUtf8(Name)); + if (!ret) + { + PyErr_SetString(ScribusException, QObject::tr("Failed to open document.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyBool_FromLong(static_cast<long>(true)); +// Py_INCREF(Py_True); // compatibility: return true, not none, on success +// return Py_True; +// Py_RETURN_TRUE; +} + +PyObject *scribus_savedoc(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->slotFileSave(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getdocname(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + if (! ScCore->primaryMainWindow()->doc->hasName) + { + return PyString_FromString(""); + } + return PyString_FromString(ScCore->primaryMainWindow()->doc->DocName.toUtf8()); +} + +PyObject *scribus_savedocas(PyObject* /* self */, PyObject* args) +{ + char *Name; + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + bool ret = ScCore->primaryMainWindow()->DoFileSave(QString::fromUtf8(Name)); + if (!ret) + { + PyErr_SetString(ScribusException, QObject::tr("Failed to save document.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyBool_FromLong(static_cast<long>(true)); +// Py_INCREF(Py_True); // compatibility: return true, not none, on success +// return Py_True; +// Py_RETURN_TRUE; +} + +PyObject *scribus_setinfo(PyObject* /* self */, PyObject* args) +{ + char *Author; + char *Title; + char *Desc; + // z means string, but None becomes a NULL value. QString() + // will correctly handle NULL. + if (!PyArg_ParseTuple(args, "zzz", &Author, &Title, &Desc)) + return NULL; + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->doc->documentInfo.setAuthor(QString::fromUtf8(Author)); + ScCore->primaryMainWindow()->doc->documentInfo.setTitle(QString::fromUtf8(Title)); + ScCore->primaryMainWindow()->doc->documentInfo.setComments(QString::fromUtf8(Desc)); + ScCore->primaryMainWindow()->slotDocCh(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setunit(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((e < UNITMIN) || (e > UNITMAX)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Unit out of range. Use one of the scribus.UNIT_* constants.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->slotChangeUnit(e); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getunit(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->unitIndex())); +} + +PyObject *scribus_loadstylesfromfile(PyObject* /* self */, PyObject *args) +{ + char *fileName; + if (!PyArg_ParseTuple(args, "es", "utf-8", &fileName)) + return NULL; + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->doc->loadStylesFromFile(QString::fromUtf8(fileName)); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setdoctype(PyObject* /* self */, PyObject* args) +{ + int fp, fsl; + if (!PyArg_ParseTuple(args, "ii", &fp, &fsl)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (ScCore->primaryMainWindow()->doc->currentPageLayout == fp) + ScCore->primaryMainWindow()->doc->pageSets[ScCore->primaryMainWindow()->doc->currentPageLayout].FirstPage = fsl; + ScCore->primaryMainWindow()->view->reformPages(); + ScCore->primaryMainWindow()->view->GotoPage(ScCore->primaryMainWindow()->doc->currentPageNumber()); // is this needed? + ScCore->primaryMainWindow()->view->DrawNew(); // is this needed? + //CB TODO ScCore->primaryMainWindow()->pagePalette->RebuildPage(); // is this needed? + ScCore->primaryMainWindow()->slotDocCh(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_closemasterpage(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->view->hideMasterPage(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_masterpagenames(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + PyObject* names = PyList_New(ScCore->primaryMainWindow()->doc->MasterPages.count()); + QMap<QString,int>::const_iterator it(ScCore->primaryMainWindow()->doc->MasterNames.constBegin()); + QMap<QString,int>::const_iterator itEnd(ScCore->primaryMainWindow()->doc->MasterNames.constEnd()); + int n = 0; + for ( ; it != itEnd; ++it ) + { + PyList_SET_ITEM(names, n++, PyString_FromString(it.key().toUtf8().data()) ); + } + return names; +} + +PyObject *scribus_editmasterpage(PyObject* /* self */, PyObject* args) +{ + char* name = 0; + if (!PyArg_ParseTuple(args, "es", const_cast<char*>("utf-8"), &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const QString masterPageName(name); + const QMap<QString,int>& masterNames(ScCore->primaryMainWindow()->doc->MasterNames); + const QMap<QString,int>::const_iterator it(masterNames.find(masterPageName)); + if ( it == masterNames.constEnd() ) + { + PyErr_SetString(PyExc_ValueError, "Master page not found"); + return NULL; + } + ScCore->primaryMainWindow()->view->showMasterPage(*it); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject* scribus_createmasterpage(PyObject* /* self */, PyObject* args) +{ + char* name = 0; + if (!PyArg_ParseTuple(args, "es", const_cast<char*>("utf-8"), &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const QString masterPageName(name); + if (ScCore->primaryMainWindow()->doc->MasterNames.contains(masterPageName)) + { + PyErr_SetString(PyExc_ValueError, "Master page already exists"); + return NULL; + } + ScCore->primaryMainWindow()->doc->addMasterPage(ScCore->primaryMainWindow()->doc->MasterPages.count(), masterPageName); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject* scribus_deletemasterpage(PyObject* /* self */, PyObject* args) +{ + char* name = 0; + if (!PyArg_ParseTuple(args, "es", const_cast<char*>("utf-8"), &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const QString masterPageName(name); + if (!ScCore->primaryMainWindow()->doc->MasterNames.contains(masterPageName)) + { + PyErr_SetString(PyExc_ValueError, "Master page does not exist"); + return NULL; + } + if (masterPageName == "Normal") + { + PyErr_SetString(PyExc_ValueError, "Can not delete the Normal master page"); + return NULL; + } + bool oldMode = ScCore->primaryMainWindow()->doc->masterPageMode(); + ScCore->primaryMainWindow()->doc->setMasterPageMode(true); + ScCore->primaryMainWindow()->DeletePage2(ScCore->primaryMainWindow()->doc->MasterNames[masterPageName]); + ScCore->primaryMainWindow()->doc->setMasterPageMode(oldMode); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmddocdocwarnings() +{ + QStringList s; + s << scribus_newdocument__doc__ << scribus_newdoc__doc__ << scribus_closedoc__doc__ << scribus_havedoc__doc__ << scribus_opendoc__doc__ << scribus_savedoc__doc__ << scribus_getdocname__doc__ << scribus_savedocas__doc__ << scribus_setinfo__doc__ <<scribus_setmargins__doc__ <<scribus_setunit__doc__ <<scribus_getunit__doc__ <<scribus_loadstylesfromfile__doc__ <<scribus_setdoctype__doc__ <<scribus_closemasterpage__doc__ <<scribus_masterpagenames__doc__ <<scribus_editmasterpage__doc__ <<scribus_createmasterpage__doc__ <<scribus_deletemasterpage__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmddoc.h b/scribus/plugins/scriptplugin/cmddoc.h new file mode 100644 index 0000000..833a881 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmddoc.h @@ -0,0 +1,270 @@ +/* +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. +*/ +#ifndef CMDDOC_H +#define CMDDOC_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Document related Commands */ + +PyDoc_STRVAR(scribus_newdocument__doc__, +QT_TR_NOOP("newDocument(size, margins, orientation, firstPageNumber,\n\ + unit, pagesType, firstPageOrder, numPages) -> bool\n\ +\n\ +Creates a new document and returns true if successful. The parameters have the\n\ +following meaning:\n\ +\n\ +size = A tuple (width, height) describing the size of the document. You can\n\ +use predefined constants named PAPER_<paper_type> e.g. PAPER_A4 etc.\n\ +\n\ +margins = A tuple (left, right, top, bottom) describing the document\n\ +margins\n\ +\n\ +orientation = the page orientation - constants PORTRAIT, LANDSCAPE\n\ +\n\ +firstPageNumer = is the number of the first page in the document used for\n\ +pagenumbering. While you'll usually want 1, it's useful to have higher\n\ +numbers if you're creating a document in several parts.\n\ +\n\ +unit: this value sets the measurement units used by the document. Use a\n\ +predefined constant for this, one of: UNIT_INCHES, UNIT_MILLIMETERS,\n\ +UNIT_PICAS, UNIT_POINTS.\n\ +\n\ +pagesType = One of the predefined constants PAGE_n. PAGE_1 is single page,\n\ +PAGE_2 is for double sided documents, PAGE_3 is for 3 pages fold and\n\ +PAGE_4 is 4-fold.\n\ +\n\ +firstPageOrder = What is position of first page in the document.\n\ +Indexed from 0 (0 = first).\n\ +\n\ +numPage = Number of pages to be created.\n\ +\n\ +The values for width, height and the margins are expressed in the given unit\n\ +for the document. PAPER_* constants are expressed in points. If your document\n\ +is not in points, make sure to account for this.\n\ +\n\ +example: newDocument(PAPER_A4, (10, 10, 20, 20), LANDSCAPE, 7, UNIT_POINTS,\n\ +PAGE_4, 3, 1)\n\ +\n\ +May raise ScribusError if is firstPageOrder bigger than allowed by pagesType.\n\ +")); +/** Creates a new document e.g. (Paper_A4, Margins, 1, 1, 1, NoFacingPages, FirstPageLeft) + first 2 args are lists (tuples) */ +PyObject *scribus_newdocument(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newdoc__doc__, +QT_TR_NOOP("newDoc(size, margins, orientation, firstPageNumber,\n\ + unit, facingPages, firstSideLeft) -> bool\n\ +\n\ +WARNING: Obsolete procedure! Use newDocument instead.\n\ +\n\ +Creates a new document and returns true if successful. The parameters have the\n\ +following meaning:\n\ +\n\ + size = A tuple (width, height) describing the size of the document. You can\n\ + use predefined constants named PAPER_<paper_type> e.g. PAPER_A4 etc.\n\ +\n\ + margins = A tuple (left, right, top, bottom) describing the document\n\ + margins\n\ +\n\ + orientation = the page orientation - constants PORTRAIT, LANDSCAPE\n\ +\n\ + firstPageNumer = is the number of the first page in the document used for\n\ + pagenumbering. While you'll usually want 1, it's useful to have higher\n\ + numbers if you're creating a document in several parts.\n\ +\n\ + unit: this value sets the measurement units used by the document. Use a\n\ + predefined constant for this, one of: UNIT_INCHES, UNIT_MILLIMETERS,\n\ + UNIT_PICAS, UNIT_POINTS.\n\ +\n\ + facingPages = FACINGPAGES, NOFACINGPAGES\n\ +\n\ + firstSideLeft = FIRSTPAGELEFT, FIRSTPAGERIGHT\n\ +\n\ +The values for width, height and the margins are expressed in the given unit\n\ +for the document. PAPER_* constants are expressed in points. If your document\n\ +is not in points, make sure to account for this.\n\ +\n\ +example: newDoc(PAPER_A4, (10, 10, 20, 20), LANDSCAPE, 1, UNIT_POINTS,\n\ + FACINGPAGES, FIRSTPAGERIGHT)\n\ +")); +/** Creates a new document e.g. (Paper_A4, Margins, 1, 1, 1, NoFacingPages, FirstPageLeft) + first 2 args are lists (tuples) */ +PyObject *scribus_newdoc(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_closedoc__doc__, +QT_TR_NOOP("closeDoc()\n\ +\n\ +Closes the current document without prompting to save.\n\ +\n\ +May throw NoDocOpenError if there is no document to close\n\ +")); +/** Closes active doc. No params */ +PyObject *scribus_closedoc(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_havedoc__doc__, +QT_TR_NOOP("haveDoc() -> bool\n\ +\n\ +Returns true if there is a document open.\n\ +")); +/** Checks if is a document opened. */ +PyObject *scribus_havedoc(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_opendoc__doc__, +QT_TR_NOOP("openDoc(\"name\")\n\ +\n\ +Opens the document \"name\".\n\ +\n\ +May raise ScribusError if the document could not be opened.\n\ +")); +/** Opens a document with given name. */ +PyObject *scribus_opendoc(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_savedoc__doc__, +QT_TR_NOOP("saveDoc()\n\ +\n\ +Saves the current document with its current name, returns true if successful.\n\ +If the document has not already been saved, this may bring up an interactive\n\ +save file dialog.\n\ +\n\ +If the save fails, there is currently no way to tell.\n\ +")); +PyObject *scribus_savedoc(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_getdocname__doc__, +QT_TR_NOOP("getDocName() -> string\n\ +\n\ +Returns the name the document was saved under.\n\ +If the document was not saved before the name is empty.\n\ +")); +/** Saves active document with given name */ +PyObject *scribus_getdocname(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_savedocas__doc__, +QT_TR_NOOP("saveDocAs(\"name\")\n\ +\n\ +Saves the current document under the new name \"name\" (which may be a full or\n\ +relative path).\n\ +\n\ +May raise ScribusError if the save fails.\n\ +")); +/** Saves active document with given name */ +PyObject *scribus_savedocas(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setinfo__doc__, +QT_TR_NOOP("setInfo(\"author\", \"info\", \"description\") -> bool\n\ +\n\ +Sets the document information. \"Author\", \"Info\", \"Description\" are\n\ +strings.\n\ +")); +/** Sets document infos - author, title and description */ +PyObject *scribus_setinfo(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setmargins__doc__, +QT_TR_NOOP("setMargins(lr, rr, tr, br)\n\ +\n\ +Sets the margins of the document, Qt::DockLeft(lr), Qt::DockRight(rr), Qt::DockTop(tr) and Qt::DockBottom(br)\n\ +margins are given in the measurement units of the document - see UNIT_<type>\n\ +constants.\n\ +")); +/** Sets document margins - left, right, top and bottom. */ +PyObject *scribus_setmargins(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setunit__doc__, +QT_TR_NOOP("setUnit(type)\n\ +\n\ +Changes the measurement unit of the document. Possible values for \"unit\" are\n\ +defined as constants UNIT_<type>.\n\ +\n\ +May raise ValueError if an invalid unit is passed.\n\ +")); +/** Changes unit scale. */ +PyObject *scribus_setunit(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getunit__doc__, +QT_TR_NOOP("getUnit() -> integer (Scribus unit constant)\n\ +\n\ +Returns the measurement units of the document. The returned value will be one\n\ +of the UNIT_* constants:\n\ +UNIT_INCHES, UNIT_MILLIMETERS, UNIT_PICAS, UNIT_POINTS.\n\ +")); +/** Returns actual unit scale. */ +PyObject *scribus_getunit(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_loadstylesfromfile__doc__, +QT_TR_NOOP("loadStylesFromFile(\"filename\")\n\ +\n\ +Loads paragraph styles from the Scribus document at \"filename\" into the\n\ +current document.\n\ +")); +/** Loads styles from another .sla file (craig r.)*/ +PyObject *scribus_loadstylesfromfile(PyObject * /*self*/, PyObject *args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setdoctype__doc__, +QT_TR_NOOP("setDocType(facingPages, firstPageLeft)\n\ +\n\ +Sets the document type. To get facing pages set the first parameter to\n\ +FACINGPAGES, to switch facingPages off use NOFACINGPAGES instead. If you want\n\ +to be the first page a left side set the second parameter to FIRSTPAGELEFT, for\n\ +a right page use FIRSTPAGERIGHT.\n\ +")); +PyObject *scribus_setdoctype(PyObject * /*self*/, PyObject* args); + +PyDoc_STRVAR(scribus_closemasterpage__doc__, +QT_TR_NOOP("closeMasterPage()\n\ +\n\ +Closes the currently active master page, if any, and returns editing\n\ +to normal. Begin editing with editMasterPage().\n\ +")); +PyObject* scribus_closemasterpage(PyObject* self); + +PyDoc_STRVAR(scribus_masterpagenames__doc__, +QT_TR_NOOP("masterPageNames()\n\ +\n\ +Returns a list of the names of all master pages in the document.\n\ +")); +PyObject* scribus_masterpagenames(PyObject* self); + +PyDoc_STRVAR(scribus_editmasterpage__doc__, +QT_TR_NOOP("editMasterPage(pageName)\n\ +\n\ +Enables master page editing and opens the named master page\n\ +for editing. Finish editing with closeMasterPage().\n\ +")); +PyObject* scribus_editmasterpage(PyObject* self, PyObject* args); + +PyDoc_STRVAR(scribus_createmasterpage__doc__, +QT_TR_NOOP("createMasterPage(pageName)\n\ +\n\ +Creates a new master page named pageName and opens it for\n\ +editing.\n\ +")); +PyObject* scribus_createmasterpage(PyObject* self, PyObject* args); + +PyDoc_STRVAR(scribus_deletemasterpage__doc__, +QT_TR_NOOP("deleteMasterPage(pageName)\n\ +\n\ +Delete the named master page.\n\ +")); +PyObject* scribus_deletemasterpage(PyObject* self, PyObject* args); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdgetprop.cpp b/scribus/plugins/scriptplugin/cmdgetprop.cpp new file mode 100644 index 0000000..a786ccb --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdgetprop.cpp @@ -0,0 +1,345 @@ +/* +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. +*/ +#include "cmdgetprop.h" +#include "cmdutil.h" +#include "scribuscore.h" + +/* getObjectType(name) */ +PyObject *scribus_getobjecttype(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PageItem *item = NULL; + QString result = ""; + + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + + if(!checkHaveDocument()) + return NULL; + + item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + + if (item->itemType() == PageItem::TextFrame) { + result = "TextFrame"; + } else if (item->itemType() == PageItem::PathText) { + result = "PathText"; + } else if (item->itemType() == PageItem::ImageFrame) { + result = "ImageFrame"; + } else if (item->itemType() == PageItem::Line) { + result = "Line"; + } else if (item->itemType() == PageItem::Polygon) { + result = "Polygon"; + } else if (item->itemType() == PageItem::PolyLine) { + result = "Polyline"; + } else if (item->itemType() == PageItem::LatexFrame) { + result = "LatexFrame"; + } else if (item->itemType() == PageItem::Multiple) { + result = "Multiple"; + } + + return PyString_FromString(result.toUtf8()); +} + +PyObject *scribus_getfillcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyString_FromString(i->fillColor().toUtf8()) : NULL; +} + +PyObject *scribus_getfilltrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyFloat_FromDouble(static_cast<double>(1.0 - i->fillTransparency())) : NULL; +} + +PyObject *scribus_getfillblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->fillBlendmode())) : NULL; +} + +PyObject *scribus_getlinecolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PageItem *it; + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if ((it->HasSel) && ((it->itemType() == PageItem::TextFrame) || (it->itemType() == PageItem::PathText))) + { + for (int b = 0; b < it->itemText.length(); ++b) + { + if (it->itemText.selected(b)) + return PyString_FromString(it->itemText.charStyle(b).fillColor().toUtf8()); + } + } + else + return PyString_FromString(it->lineColor().toUtf8()); + PyErr_SetString(NotFoundError, QObject::tr("Color not found - python error", "python error").toLocal8Bit().constData()); + return NULL; +} + +PyObject *scribus_getlinetrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyFloat_FromDouble(static_cast<double>(1.0 - i->lineTransparency())) : NULL; +} + +PyObject *scribus_getlineblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->lineBlendmode())) : NULL; +} + +PyObject *scribus_getlinewidth(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyFloat_FromDouble(static_cast<double>(i->lineWidth())) : NULL; +} + +PyObject *scribus_getlineshade(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PageItem *it; + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if ((it->HasSel) && ((it->itemType() == PageItem::TextFrame) || (it->itemType() == PageItem::PathText))) + { + for (int b = 0; b < it->itemText.length(); ++b) + { + if (it->itemText.selected(b)) + return PyInt_FromLong(static_cast<long>(it->itemText.charStyle(b).fillShade())); + } + } + else + return PyInt_FromLong(static_cast<long>(it->lineShade())); + return PyInt_FromLong(0L); +} + +PyObject *scribus_getlinejoin(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->PLineJoin)) : NULL; +} + +PyObject *scribus_getlinecap(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->PLineEnd)) : NULL; +} + +PyObject *scribus_getlinestyle(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->PLineArt)) : NULL; +} + +PyObject *scribus_getfillshade(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->fillShade())) : NULL; +} + +PyObject *scribus_getcornerrad(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyInt_FromLong(static_cast<long>(i->cornerRadius())) : NULL; +} + +PyObject *scribus_getimgscale(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? Py_BuildValue("(ff)", i->imageXScale() / 72.0 * i->pixm.imgInfo.xres, i->imageYScale() / 72.0 * i->pixm.imgInfo.yres) : NULL; +} + +PyObject *scribus_getimgname(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyString_FromString(i->Pfile.toUtf8()) : NULL; +} + +PyObject *scribus_getposi(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (!i) + return NULL; + return Py_BuildValue("(ff)", docUnitXToPageX(i->xPos()), + docUnitYToPageY(i->yPos())); +} + +PyObject *scribus_getsize(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return (i != NULL) ? Py_BuildValue("(ff)", PointToValue(i->width()), PointToValue(i->height())) : NULL; +} + +PyObject *scribus_getrotation(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + return i != NULL ? PyFloat_FromDouble(static_cast<double>(i->rotation() * -1)) : NULL; +} + +PyObject *scribus_getallobj(PyObject* /* self */, PyObject* args) +{ + PyObject *l; + int typ = -1; + uint counter = 0; + uint counter2 = 0; + uint pageNr = ScCore->primaryMainWindow()->doc->currentPageNumber(); + if (!PyArg_ParseTuple(args, "|i", &typ)) + return NULL; + if(!checkHaveDocument()) + return NULL; + // have doc already + if (typ != -1) + { + for (int lam2 = 0; lam2 < ScCore->primaryMainWindow()->doc->Items->count(); ++lam2) + { + if ((ScCore->primaryMainWindow()->doc->Items->at(lam2)->itemType() == typ) && (pageNr == static_cast<uint>(ScCore->primaryMainWindow()->doc->Items->at(lam2)->OwnPage))) + counter++; + } + } + else + { + for (int lam2 = 0; lam2 < ScCore->primaryMainWindow()->doc->Items->count(); ++lam2) + { + if (pageNr == static_cast<uint>(ScCore->primaryMainWindow()->doc->Items->at(lam2)->OwnPage)) + counter++; + } + } + + l = PyList_New(counter); + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Items->count(); ++lam) + { + if (pageNr == static_cast<uint>(ScCore->primaryMainWindow()->doc->Items->at(lam)->OwnPage)) + { + if (typ != -1) + { + if (ScCore->primaryMainWindow()->doc->Items->at(lam)->itemType() == typ) + { + PyList_SetItem(l, counter2, PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(lam)->itemName().toUtf8())); + counter2++; + } + } + else + { + PyList_SetItem(l, counter2, PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(lam)->itemName().toUtf8())); + counter2++; + } + } + } + return l; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdgetpropdocwarnings() +{ + QStringList s; + s << scribus_getobjecttype__doc__ << scribus_getfillcolor__doc__ + << scribus_getfilltrans__doc__ << scribus_getfillblend__doc__ + << scribus_getlinecolor__doc__ << scribus_getlinetrans__doc__ + << scribus_getlineblend__doc__ << scribus_getlinewidth__doc__ + << scribus_getlineshade__doc__ << scribus_getlinejoin__doc__ + << scribus_getlinecap__doc__ << scribus_getlinestyle__doc__ + << scribus_getfillshade__doc__ << scribus_getcornerrad__doc__ + << scribus_getimgscale__doc__ << scribus_getimgname__doc__ + << scribus_getposi__doc__ << scribus_getsize__doc__ + << scribus_getrotation__doc__ << scribus_getallobj__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdgetprop.h b/scribus/plugins/scriptplugin/cmdgetprop.h new file mode 100644 index 0000000..f2d89c5 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdgetprop.h @@ -0,0 +1,223 @@ +/* +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. +*/ +#ifndef CMDGETPROP_H +#define CMDGETPROP_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Query-Functions */ + +/*! docstring */ +PyDoc_STRVAR(scribus_getobjecttype__doc__, +QT_TR_NOOP("getObjectType([\"name\"]) -> string\n\ +\n\ +Get type of object \"name\" as a string.\n\ +")); +/** Get Object Type of name. */ +PyObject *scribus_getobjecttype(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getfillcolor__doc__, +QT_TR_NOOP("getFillColor([\"name\"]) -> string\n\ +\n\ +Returns the name of the fill color of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Returns fill color of the object */ +PyObject *scribus_getfillcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getfilltrans__doc__, +QT_TR_NOOP("getFillTransparency([\"name\"]) -> float\n\ +\n\ +Returns the fill transparency of the object \"name\". If \"name\"\n\ +is not given the currently selected Item is used.\n\ +")); +/*! Returns fill transparency of the object */ +PyObject *scribus_getfilltrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getfillblend__doc__, +QT_TR_NOOP("getFillBlendmode([\"name\"]) -> integer\n\ +\n\ +Returns the fill blendmode of the object \"name\". If \"name\"\n\ +is not given the currently selected Item is used.\n\ +")); +/*! Returns fill blendmode of the object */ +PyObject *scribus_getfillblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinecolor__doc__, +QT_TR_NOOP("getLineColor([\"name\"]) -> string\n\ +\n\ +Returns the name of the line color of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Returns color of the line */ +PyObject *scribus_getlinecolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinetrans__doc__, +QT_TR_NOOP("getLineTransparency([\"name\"]) -> float\n\ +\n\ +Returns the line transparency of the object \"name\". If \"name\"\n\ +is not given the currently selected Item is used.\n\ +")); +/*! Returns line transparency of the object */ +PyObject *scribus_getlinetrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlineblend__doc__, +QT_TR_NOOP("getLineBlendmode([\"name\"]) -> integer\n\ +\n\ +Returns the line blendmode of the object \"name\". If \"name\"\n\ +is not given the currently selected Item is used.\n\ +")); +/*! Returns line blendmode of the object */ +PyObject *scribus_getlineblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinewidth__doc__, +QT_TR_NOOP("getLineWidth([\"name\"]) -> integer\n\ +\n\ +Returns the line width of the object \"name\". If \"name\"\n\ +is not given the currently selected Item is used.\n\ +")); +/*! Returns width of the line */ +PyObject *scribus_getlinewidth(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlineshade__doc__, +QT_TR_NOOP("getLineShade([\"name\"]) -> integer\n\ +\n\ +Returns the shading value of the line color of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Returns shading of the line */ +PyObject *scribus_getlineshade(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinejoin__doc__, +QT_TR_NOOP("getLineJoin([\"name\"]) -> integer (see constants)\n\ +\n\ +Returns the line join style of the object \"name\". If \"name\" is not given\n\ +the currently selected item is used. The join types are:\n\ +JOIN_BEVEL, JOIN_MITTER, JOIN_ROUND\n\ +")); +/*! Returns join type of the line */ +PyObject *scribus_getlinejoin(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinecap__doc__, +QT_TR_NOOP("getLineCap([\"name\"]) -> integer (see constants)\n\ +\n\ +Returns the line cap style of the object \"name\". If \"name\" is not given the\n\ +currently selected item is used. The cap types are:\n\ +CAP_FLAT, CAP_ROUND, CAP_SQUARE\n\ +")); +/*! Returns cap type of the line */ +PyObject *scribus_getlinecap(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinestyle__doc__, +QT_TR_NOOP("getLineStyle([\"name\"]) -> integer (see constants)\n\ +\n\ +Returns the line style of the object \"name\". If \"name\" is not given the\n\ +currently selected item is used. Line style constants are:\n\ +LINE_DASH, LINE_DASHDOT, LINE_DASHDOTDOT, LINE_DOT, LINE_SOLID\n\ +")); +/*! Returns style type of the line */ +PyObject *scribus_getlinestyle(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getfillshade__doc__, +QT_TR_NOOP("getFillShade([\"name\"]) -> integer\n\ +\n\ +Returns the shading value of the fill color of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Returns fill shade of the object */ +PyObject *scribus_getfillshade(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getcornerrad__doc__, +QT_TR_NOOP("getCornerRadius([\"name\"]) -> integer\n\ +\n\ +Returns the corner radius of the object \"name\". The radius is\n\ +expressed in points. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Returns corner radius of the object */ +PyObject *scribus_getcornerrad(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getimgscale__doc__, +QT_TR_NOOP("getImageScale([\"name\"]) -> (x,y)\n\ +\n\ +Returns a (x, y) tuple containing the scaling values of the image frame\n\ +\"name\". If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Returns image scale of the object */ +PyObject *scribus_getimgscale(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getimgname__doc__, +QT_TR_NOOP("getImageName([\"name\"]) -> string\n\ +\n\ +Returns the filename for the image in the image frame. If \"name\" is not\n\ +given the currently selected item is used.\n\ +")); +/*! Returns image name of the object */ +PyObject *scribus_getimgname(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getposi__doc__, +QT_TR_NOOP("getPosition([\"name\"]) -> (x,y)\n\ +\n\ +Returns a (x, y) tuple with the position of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +The position is expressed in the actual measurement unit of the document\n\ +- see UNIT_<type> for reference.\n\ +")); +/*! Returns position of the object */ +PyObject *scribus_getposi(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getsize__doc__, +QT_TR_NOOP("getSize([\"name\"]) -> (width,height)\n\ +\n\ +Returns a (width, height) tuple with the size of the object \"name\".\n\ +If \"name\" is not given the currently selected item is used. The size is\n\ +expressed in the current measurement unit of the document - see UNIT_<type>\n\ +for reference.\n\ +")); +/*! Returns size of the object */ +PyObject *scribus_getsize(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getrotation__doc__, +QT_TR_NOOP("getRotation([\"name\"]) -> integer\n\ +\n\ +Returns the rotation of the object \"name\". The value is expressed in degrees,\n\ +and clockwise is positive. If \"name\" is not given the currently selected item\n\ +is used.\n\ +")); +/*! Returns rotation of the object */ +PyObject *scribus_getrotation(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getallobj__doc__, +QT_TR_NOOP("getAllObjects() -> list\n\ +\n\ +Returns a list containing the names of all objects on the current page.\n\ +")); +/*! Returns a list with all objects in page */ +PyObject *scribus_getallobj(PyObject * /*self*/, PyObject* args); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdgetsetprop.cpp b/scribus/plugins/scriptplugin/cmdgetsetprop.cpp new file mode 100644 index 0000000..0f12e64 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdgetsetprop.cpp @@ -0,0 +1,499 @@ +/* +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. +*/ +#include "cmdgetsetprop.h" +#include "cmdutil.h" + +#include <QMetaObject> +#include <QMetaProperty> +#include <QList> +#include <QObject> +#include <QObjectList> + +QObject* getQObjectFromPyArg(PyObject* arg) +{ + if (PyString_Check(arg)) + // It's a string. Look for a pageItem by that name. Do NOT accept a + // selection. + return getPageItemByName(QString::fromUtf8(PyString_AsString(arg))); + else if (PyCObject_Check(arg)) + { + // It's a PyCObject, ie a wrapped pointer. Check it's not NULL + // and return it. + // FIXME: Try to check that its a pointer to a QObject instance + QObject* tempObject = (QObject*)PyCObject_AsVoidPtr(arg); + if (!tempObject) + { + PyErr_SetString(PyExc_TypeError, "INTERNAL: Passed NULL PyCObject"); + return NULL; + } + else + return tempObject; + } + else + { + // It's not a type we know what to do with + PyErr_SetString(PyExc_TypeError, QObject::tr("Argument must be page item name, or PyCObject instance").toLocal8Bit().constData()); + return NULL; + } +} + + +PyObject* wrapQObject(QObject* obj) +{ + return PyCObject_FromVoidPtr((void*)obj, NULL); +} + + +const char* getpropertytype(QObject* obj, const char* propname, bool includesuper) +{ + const QMetaObject* objmeta = obj->metaObject(); + int i = objmeta->indexOfProperty(propname); + if (i == -1) + return NULL; + QMetaProperty propmeta = objmeta->property(i); + if (!propmeta.isValid()) + return NULL; + const char* type = propmeta.typeName(); + return type; +} + + +PyObject* scribus_propertyctype(PyObject* /*self*/, PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + char* propertyname = NULL; + int includesuper = 1; + char* kwargs[] = {const_cast<char*>("object"), + const_cast<char*>("property"), + const_cast<char*>("includesuper"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "Oes|i", kwargs, + &objArg, "ascii", &propertyname, &includesuper)) + return NULL; + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + // Look up the property and retrive its type information + const char* type = getpropertytype( (QObject*)obj, propertyname, includesuper); + if (type == NULL) + { + PyErr_SetString(PyExc_KeyError, QObject::tr("Property not found").toLocal8Bit().constData()); + return NULL; + } + return PyString_FromString(type); +} + +PyObject* convert_QStringList_to_PyListObject(QStringList& origlist) +{ + PyObject* resultList = PyList_New(0); + if (!resultList) + return NULL; + + for ( QStringList::Iterator it = origlist.begin(); it != origlist.end(); ++it ) + if (PyList_Append(resultList, PyString_FromString((*it).toUtf8().data())) == -1) + return NULL; + + return resultList; +} + + +PyObject* convert_QObjectList_to_PyListObject(QObjectList* origlist) +{ + PyObject* resultList = PyList_New(0); + if (!resultList) + return NULL; + + PyObject* objPtr = NULL; + // Loop over the objects in the list and add them to the python + // list wrapped in PyCObjects . + for (int i = 0; i < origlist->count(); ++i) + { + // Wrap up the object pointer + objPtr = wrapQObject(origlist->at(i)); + if (!objPtr) + { + // Failed to wrap the object. An exception is already set. + Py_DECREF(resultList); + return NULL; + } + // and add it to the list + if (PyList_Append(resultList, (PyObject*)objPtr) == -1) + return NULL; + } + return resultList; +} + +/*Qt4 we either need to copy QObject::qChildHelper or rewrite this + +PyObject* scribus_getchildren(PyObject* , PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + char* ofclass = NULL; + char* ofname = NULL; + int recursive = 0; + int regexpmatch = 0; + char* kwnames[] = {const_cast<char*>("object"), + const_cast<char*>("ofclass"), + const_cast<char*>("ofname"), + const_cast<char*>("regexpmatch"), + const_cast<char*>("recursive"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|esesii", kwnames, + &objArg, "ascii", &ofclass, "ascii", &ofname, ®expmatch, &recursive)) + return NULL; + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + // Our job is to return a Python list containing the children of this + // widget (as PyCObjects). +//qt4 FIXME QObjectList* children; +//qt4 FIXME children = obj->queryList(ofclass, ofname, regexpmatch, recursive); + PyObject* itemlist = 0; +//qt4 FIXME itemlist = convert_QObjectList_to_PyListObject(children); +//qt4 FIXME delete children; + return itemlist; +} + + +// Perform a recursive (by default) search for the named child, possibly of a +// select class. +PyObject* scribus_getchild(PyObject* , PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + char* childname = NULL; + char* ofclass = NULL; + bool recursive = true; + char* kwnames[] = {const_cast<char*>("object"), + const_cast<char*>("childname"), + const_cast<char*>("ofclass"), + const_cast<char*>("recursive"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "Oes|esi", kwnames, + &objArg, "ascii", &childname, "ascii", &ofclass, &recursive)) + return NULL; + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + // Search for the child, possibly restricting the search to children + // of a particular type, and possibly recursively searching through + // grandchildren etc. + QObject* child = obj->child(childname, ofclass, recursive); + if (child == NULL) + { + PyErr_SetString(PyExc_KeyError, QObject::tr("Child not found").toLocal8Bit().constData()); + return NULL; + } + + return wrapQObject(child); +} +*/ + +PyObject* scribus_getpropertynames(PyObject* /*self*/, PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + int includesuper = 1; + char* kwargs[] = {const_cast<char*>("object"), + const_cast<char*>("includesuper"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|i", kwargs, + &objArg, &includesuper)) + return NULL; + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + // Retrive the object's meta object so we can query it + const QMetaObject* objmeta = obj->metaObject(); + if (!objmeta) + return NULL; + + // Return the list of properties + QStringList propertyNames; + int propertyOffset = includesuper ? 0 : objmeta->propertyOffset(); + for(int i = propertyOffset; i < objmeta->propertyCount(); ++i) + { + QString propName = objmeta->property(i).name(); + propertyNames << QString::fromLatin1(objmeta->property(i).name()); + } + return convert_QStringList_to_PyListObject(propertyNames); +} + + +PyObject* scribus_getproperty(PyObject* /*self*/, PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + char* propertyName = NULL; + char* kwargs[] = {const_cast<char*>("object"), + const_cast<char*>("property"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "Oes", kwargs, + &objArg, "ascii", &propertyName)) + return NULL; + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + // Get the QMetaProperty for the property, so we can check + // if it's a set/enum and do name/value translation. + const QMetaObject* objmeta = obj->metaObject(); + int i = objmeta->indexOfProperty(propertyName); + if (i == -1) + { + PyErr_SetString(PyExc_ValueError, + QObject::tr("Property not found").toLocal8Bit().data()); + return NULL; + } + + QMetaProperty propmeta = objmeta->property(i); + if (!propmeta.isValid()) + { + PyErr_SetString(PyExc_ValueError, + QObject::tr("Invalid property").toLocal8Bit().data()); + return NULL; + } + + // Get the property value as a variant type + QVariant prop = obj->property(propertyName); + + // Convert the property to an instance of the closest matching Python type. + PyObject* resultobj = NULL; + // NUMERIC TYPES + if (prop.type() == QVariant::Int) + resultobj = PyLong_FromLong(prop.toInt()); + else if (prop.type() == QVariant::Double) + resultobj = PyFloat_FromDouble(prop.toDouble()); + // BOOLEAN + else if (prop.type() == QVariant::Bool) + resultobj = PyBool_FromLong(prop.toBool()); + // STRING TYPES + else if (prop.type() == QVariant::ByteArray) + resultobj = PyString_FromString(prop.toByteArray().data()); + else if (prop.type() == QVariant::String) + resultobj = PyString_FromString(prop.toString().toUtf8().data()); + // HIGHER ORDER TYPES + else if (prop.type() == QVariant::Point) + { + // Return a QPoint as an (x,y) tuple. + QPoint pt = prop.toPoint(); + return Py_BuildValue("(ii)", pt.x(), pt.y()); + } + else if (prop.type() == QVariant::Rect) + { + // Return a QRect as an (x,y,width,height) tuple. + // FIXME: We should really construct and return an object that + // matches the API of QRect and has properties to keep + // left/top/right/bottom and x/y/width/height in sync. + QRect r = prop.toRect(); + return Py_BuildValue("(iiii)", r.x(), r.y(), r.width(), r.height()); + } + else if (prop.type() == QVariant::StringList) + { + QStringList tmp = prop.toStringList(); + return convert_QStringList_to_PyListObject(tmp); + } + // UNHANDLED TYPE + else + { + PyErr_SetString(PyExc_TypeError, QObject::tr("Couldn't convert result type '%1'.").arg(prop.typeName()).toLocal8Bit().constData() ); + return resultobj; + } + + // Return the resulting Python object + if (resultobj == NULL) + { + // An exception was set while assigning to resultobj + assert(PyErr_Occurred()); + return NULL; + } + else + return resultobj; +} + + + +PyObject* scribus_setproperty(PyObject* /*self*/, PyObject* args, PyObject* kw) +{ + PyObject* objArg = NULL; + char* propertyName = NULL; + PyObject* objValue = NULL; + char* kwargs[] = {const_cast<char*>("object"), + const_cast<char*>("property"), + const_cast<char*>("value"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "OesO", kwargs, + &objArg, "ascii", &propertyName, &objValue)) + return NULL; + + // We're going to hang on to the value object for a while, so + // claim a reference to it. + Py_INCREF(objValue); + + // Get the QObject* the object argument refers to + QObject* obj = getQObjectFromPyArg(objArg); + if (!obj) + return NULL; + objArg = NULL; // no need to decref, it's borrowed + + const char* propertyTypeName = getpropertytype(obj, propertyName, true); + if (propertyTypeName == NULL) + return NULL; + QString propertyType = QString::fromLatin1(propertyTypeName); + + // Did we know how to convert the value argument to the right type? + bool matched = false; + // Did the set call succceed? + bool success = false; + + // Check the C++ type of the property, and try to convert the passed + // PyObject to something sensible looking for it. + // FIXME: handle enums/sets + // NUMERIC TYPES + // These are unfortuately a TOTAL PITA because of the multitude of + // C and Python numeric types. TODO This needs to be broken out into a subroutine. + if (propertyType == "bool") + { + matched = true; + if (PyObject_IsTrue(objValue) == 0) + success = obj->setProperty(propertyName, 0); + else if (PyObject_IsTrue(objValue) == 1) + success = obj->setProperty(propertyName, 1); + else if (PyInt_Check(objValue)) + success = obj->setProperty(propertyName, PyInt_AsLong(objValue) == 0); + else if (PyLong_Check(objValue)) + success = obj->setProperty(propertyName, PyLong_AsLong(objValue) == 0); + else + matched = false; + } + else if (propertyType == "int") + { + matched = true; + if (PyObject_IsTrue(objValue) == 0) + success = obj->setProperty(propertyName, 0); + else if (PyObject_IsTrue(objValue) == 1) + success = obj->setProperty(propertyName, 1); + else if (PyInt_Check(objValue)) + success = obj->setProperty(propertyName, (int)PyInt_AsLong(objValue)); + else if (PyLong_Check(objValue)) + success = obj->setProperty(propertyName, (int)PyLong_AsLong(objValue)); + else + matched = false; + } + else if (propertyType == "double") + { + matched = true; + // FIXME: handle int, long and bool too + if (PyFloat_Check(objValue)) + success = obj->setProperty(propertyName, PyFloat_AsDouble(objValue)); + else + matched = false; + } + // STRING TYPES + else if (propertyType == "QString") + { + matched = true; + if (PyString_Check(objValue)) + success = obj->setProperty(propertyName, QString::fromUtf8(PyString_AsString(objValue))); + else if (PyUnicode_Check(objValue)) + { + // Get a pointer to the internal buffer of the Py_Unicode object, which is UCS2 formatted + const unsigned short * ucs2Data = (const unsigned short *)PyUnicode_AS_UNICODE(objValue); + // and make a new QString from it (the string is copied) + success = obj->setProperty(propertyName, QString::fromUtf16(ucs2Data)); + } + else + matched = false; + } + else if (propertyType == "QCString") + { + matched = true; + if (PyString_Check(objValue)) + { + // FIXME: should raise an exception instead of mangling the string when + // out of charset chars present. + QString utfString = QString::fromUtf8(PyString_AsString(objValue)); + success = obj->setProperty(propertyName, utfString.toAscii()); + } + else if (PyUnicode_Check(objValue)) + { + // Get a pointer to the internal buffer of the Py_Unicode object, which is UCS2 formatted + const unsigned short * utf16Data = (const unsigned short *)PyUnicode_AS_UNICODE(objValue); + // and make a new QString from it (the string is copied) + success = obj->setProperty(propertyName, QString::fromUtf16(utf16Data).toAscii()); + } + else + matched = false; + } + // HIGHER ORDER TYPES + // ... which I can't be stuffed supporting yet. FIXME. + else + { + Py_DECREF(objValue); + PyErr_SetString(PyExc_TypeError, + QObject::tr("Property type '%1' not supported").arg(propertyType).toLocal8Bit().constData()); + return NULL; + } + + // If `matched' is false, we recognised the C type but weren't able to + // convert the passed Python value to anything suitable. + if (!matched) + { + // Get a string representation of the object + PyObject* objRepr = PyObject_Repr(objValue); + Py_DECREF(objValue); // We're done with it now + if (!objRepr) + return NULL; + // Extract the repr() string + QString reprString = QString::fromUtf8(PyString_AsString(objRepr)); + Py_DECREF(objRepr); + + // And return an error + PyErr_SetString(PyExc_TypeError, + QObject::tr("Couldn't convert '%1' to property type '%2'").arg(reprString).arg(propertyType).toLocal8Bit().constData()); + return NULL; + } + + // `success' is the return value of the setProperty() call + if (!success) + { + Py_DECREF(objValue); + PyErr_SetString(PyExc_ValueError, QObject::tr("Types matched, but setting property failed.").toLocal8Bit().constData()); + return NULL; + } + + Py_DECREF(objValue); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdgetsetpropdocwarnings() +{ + QStringList s; + s << scribus_propertyctype__doc__ << scribus_getpropertynames__doc__ << scribus_getproperty__doc__ << scribus_setproperty__doc__; + //Qt4 << scribus_getchildren__doc__ << scribus_getchild__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdgetsetprop.h b/scribus/plugins/scriptplugin/cmdgetsetprop.h new file mode 100644 index 0000000..7a2e508 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdgetsetprop.h @@ -0,0 +1,206 @@ +/* +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. +*/ +#ifndef CMD_GETSETPROP_H +#define CMD_GETSETPROP_H + +// Pulls in Python.h first +#include "cmdvar.h" +#include <QStringList> + + +/** + * @brief Return a pointer to the QObject that the PyObject* args refers to + * + * This function looks up the PyObject* argument and tries to return a + * corresponding QObject. + * + * If the argument is a PyCObject, it will return the contained pointer. + * If the pointer is NULL an exception is set before returning. + * + * If the argument is a string, a PageItem by that name will be looked for + * and, if found, returned. If no such object could be found, an exception + * is set and NULL is returned. + * + * If any other type is specified, an exception is set and NULL is returned. + * + * @attention may return NULL with an exception set + * + * @sa wrapQObject() + */ +QObject* getQObjectFromPyArg(PyObject* arg); + + +/** + * @brief Return a PyCObject containing the passed QObject pointer + * @sa getQObjectFromPyArg() + * @attention may return NULL with an exception set + */ +PyObject* wrapQObject(QObject* obj); + + +/** + * @brief Convert a QStringList to a Python list of str objects + * @attention may return NULL with an exception set + */ +PyObject* convert_QStringList_to_PyListObject(QStringList& origlist); + +/** + * @brief Convert a QObjectList to a Python list of PyCObjects + * @attention may return NULL with an exception set + */ +PyObject* convert_QObjectList_to_PyListObject(QObjectList* origlist); + +/** + * @brief return the name of the C type of the specified property + * + * Look up `propname' on `obj', searching through parent classes if + * `includsuper' is true. Get and return the name of the C type + * of the property. + * + * If the property cannot be found, a null string is returned. NO + * EXCEPTION IS SET. + * + * @sa scribus_propertyctype() + */ +const char* getpropertytype(QObject* obj, const char* propname, bool includesuper = true); + +/** + * @brief Get name of C type of property of object + * @returns Python string object containing name of C type of property. + * @sa getpropertytype(), scribus_getproperty(), scribus_setproperty() + */ +PyDoc_STRVAR(scribus_propertyctype__doc__, +QT_TR_NOOP("getPropertyCType(object, property, includesuper=True)\n\ +\n\ +Returns the name of the C type of `property' of `object'. See getProperty()\n\ +for details of arguments.\n\ +\n\ +If `includesuper' is true, search inherited properties too.\n\ +")); +PyObject* scribus_propertyctype(PyObject* /*self*/, PyObject* args, PyObject* kw); + + +/** + * @brief Return a list of the property names of the passed object + * + * See the Python docstring for details on this function. + * + * @sa QMetaObject::propertyNames(), scribus_getproperty(), + * scribus_setproperty() + */ +PyDoc_STRVAR(scribus_getpropertynames__doc__, +QT_TR_NOOP("getPropertyNames(object, includesuper=True)\n\ +\n\ +Return a list of property names supported by `object'.\n\ +If `includesuper' is true, return properties supported\n\ +by parent classes as well.\n\ +")); +PyObject* scribus_getpropertynames(PyObject* self, PyObject* args, PyObject* kw); + + +/** + * @brief Generic Python getter for Qt object properties + * + * This getter uses the Qt property interface (see the Qt object + * model documentation) to provide a generic getter for any property + * of a supported type. It finds the closest Python type match to the + * property's C++ type, converts the property value to the Python type, + * and returns it. + * + * If an unsupported type is encountered, TypeError will be raised. + * + * See the Python docstring for details of this function's Python + * interface. + * + * @sa scribus_setproperty(), QObject::property(), QMetaObject. + * scribus_propertyctype() + */ +PyDoc_STRVAR(scribus_getproperty__doc__, +QT_TR_NOOP("getProperty(object, property)\n\ +\n\ +Return the value of the property `property' of the passed `object'.\n\ +\n\ +The `object' argument may be a string, in which case the named PageItem\n\ +is searched for. It may also be a PyCObject, which may point to any\n\ +C++ QObject instance.\n\ +\n\ +The `property' argument must be a string, and is the name of the property\n\ +to look up on `object'.\n\ +\n\ +The return value varies depending on the type of the property.\n\ +")); +PyObject* scribus_getproperty(PyObject* /*self*/, PyObject* args, PyObject* kw); + + +/** + * @brief Generic setter for Qt object properties + * + * This setter uses the Qt property intercace to provide a generic setter + * for any property of a supported type. It checks the Property's C type + * and attempts to convert the passed Python object to a compatible type, + * then call the object's property setter method with the converted value. + * + * If an unsupported type is encountered, TypeError will be raised. + * If the passed object can't be converted to a compatible type, + * TypeError will be raised. + * + * See the Python docstring for details of this function's Python + * interface. + * + * @sa scribus_getproperty(), QObject::property(), QMetaObject, + * scribus_propertyctype() + */ +PyDoc_STRVAR(scribus_setproperty__doc__, +QT_TR_NOOP("setProperty(object, property, value)\n\ +\n\ +Set `property' of `object' to `value'. If `value' cannot be converted to a type\n\ +compatible with the type of `property', an exception is raised. An exception may\n\ +also be raised if the underlying setter fails.\n\ +\n\ +See getProperty() for more information.\n\ +")); +PyObject* scribus_setproperty(PyObject* /*self*/, PyObject* args, PyObject* kw); + + +/** + * @brief Return a list of children of the passed object + * + * See the Python docstring for details on this function. + * + * @sa QObject::children(), scribus_getchild() + */ +/*Qt4 +PyDoc_STRVAR(scribus_getchildren__doc__, +QT_TR_NOOP("getChildren(object, ofclass=None, ofname=None, regexpmatch=False, recursive=True)\n\ +\n\ +Return a list of children of `object', possibly restricted to children\n\ +of class named `ofclass' or children named `ofname'. If `recursive' is true,\n\ +search recursively through children, grandchildren, etc.\n\ +\n\ +See QObject::children() in the Qt docs for more information.\n\ +")); +PyObject* scribus_getchildren(PyObject* self, PyObject* args, PyObject* kw); +*/ + +/** + * @brief Return a wrapped PyObject* for the named child, if found. + * + * See the Python docstring for details on this function. + * + * @sa QObject::child(), scribus_children() + */ +/*Qt4 +PyDoc_STRVAR(scribus_getchild__doc__, +QT_TR_NOOP("getChild(object, childname, ofclass=None, recursive=True)\n\ +\n\ +Return the first child of `object' named `childname', possibly restricting\n\ +the search to children of type name `ofclass'. If `recursive' is true,\n\ +search recursively through children, grandchildren, etc.\n\ +")); +PyObject* scribus_getchild(PyObject* self, PyObject* args, PyObject* kw); +*/ +#endif diff --git a/scribus/plugins/scriptplugin/cmdmani.cpp b/scribus/plugins/scriptplugin/cmdmani.cpp new file mode 100644 index 0000000..d9875d5 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdmani.cpp @@ -0,0 +1,492 @@ +/* +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. +*/ +#include "cmdmani.h" +#include "cmdutil.h" +#include "propertiespalette.h" //CB argh.. noooooooooooooooooooooooooooooooooooo FIXME see other FIXME +#include "selection.h" +#include "scribuscore.h" +#include "undomanager.h" + +PyObject *scribus_loadimage(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Image; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Image, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + if (!item->asImageFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Target is not an image frame.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->LoadPict(QString::fromUtf8(Image), item->ItemNr); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_scaleimage(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + if (! item->asImageFrame()) + { + PyErr_SetString(ScribusException, QObject::tr("Specified item not an image frame.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->itemSelection_SetImageScale(x, y); //CB why when this is done above? + ScCore->primaryMainWindow()->doc->updatePic(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setimagescale(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + if (! item->asImageFrame()) + { + PyErr_SetString(ScribusException, QObject::tr("Specified item not an image frame.","python error").toLocal8Bit().constData()); + return NULL; + } + double newScaleX = x / item->pixm.imgInfo.xres * 72.0; + double newScaleY = y / item->pixm.imgInfo.yres * 72.0; + ScCore->primaryMainWindow()->doc->itemSelection_SetImageScale(newScaleX, newScaleY); //CB why when this is done above? + ScCore->primaryMainWindow()->doc->updatePic(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setimageoffset(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + if (! item->asImageFrame()) + { + PyErr_SetString(ScribusException, QObject::tr("Specified item not an image frame.","python error").toLocal8Bit().constData()); + return NULL; + } + + // Grab the old selection - but use it only where is there any + Selection tempSelection(*ScCore->primaryMainWindow()->doc->m_Selection); + bool hadOrigSelection = (tempSelection.count() != 0); + + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + // Clear the selection + ScCore->primaryMainWindow()->view->Deselect(); + // Select the item, which will also select its group if + // there is one. + ScCore->primaryMainWindow()->view->SelectItemNr(item->ItemNr); + + // offset + double newOffsetX = x / ((item->imageXScale() != 0.0) ? item->imageXScale() : 1); + double newOffsetY = y / ((item->imageYScale() != 0.0) ? item->imageYScale() : 1); + ScCore->primaryMainWindow()->doc->itemSelection_SetImageOffset(newOffsetX, newOffsetY); //CB why when this is done above? + ScCore->primaryMainWindow()->doc->updatePic(); + + // Now restore the selection. + ScCore->primaryMainWindow()->view->Deselect(); + if (hadOrigSelection) + *ScCore->primaryMainWindow()->doc->m_Selection=tempSelection; + + // Py_INCREF(Py_None); + // return Py_None; + Py_RETURN_NONE; +} + + +PyObject *scribus_moveobjrel(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item==NULL) + return NULL; + // Grab the old selection - but use it only where is there any + Selection tempSelection(*ScCore->primaryMainWindow()->doc->m_Selection); + bool hadOrigSelection = (tempSelection.count() != 0); + + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + // Clear the selection + ScCore->primaryMainWindow()->view->Deselect(); + // Select the item, which will also select its group if + // there is one. + ScCore->primaryMainWindow()->view->SelectItemNr(item->ItemNr); + // Move the item, or items + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + ScCore->primaryMainWindow()->view->startGroupTransaction(Um::Move, "", Um::IMove); + ScCore->primaryMainWindow()->doc->moveGroup(ValueToPoint(x), ValueToPoint(y)); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + } + else + ScCore->primaryMainWindow()->doc->MoveItem(ValueToPoint(x), ValueToPoint(y), item); + // Now restore the selection. + ScCore->primaryMainWindow()->view->Deselect(); + if (hadOrigSelection) + *ScCore->primaryMainWindow()->doc->m_Selection=tempSelection; + + Py_RETURN_NONE; +} + +PyObject *scribus_moveobjabs(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + // Grab the old selection - but use it only where is there any + Selection tempSelection(*ScCore->primaryMainWindow()->doc->m_Selection); + bool hadOrigSelection = (tempSelection.count() != 0); + + // Clear the selection + ScCore->primaryMainWindow()->view->Deselect(); + // Select the item, which will also select its group if + // there is one. + ScCore->primaryMainWindow()->view->SelectItemNr(item->ItemNr); + // Move the item, or items + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + ScCore->primaryMainWindow()->view->startGroupTransaction(Um::Move, "", Um::IMove); + double x2, y2, w, h; + ScCore->primaryMainWindow()->doc->m_Selection->getGroupRect(&x2, &y2, &w, &h); + ScCore->primaryMainWindow()->doc->moveGroup(pageUnitXToDocX(x) - x2, pageUnitYToDocY(y) - y2); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + } + else + ScCore->primaryMainWindow()->doc->MoveItem(pageUnitXToDocX(x) - item->xPos(), pageUnitYToDocY(y) - item->yPos(), item); + // Now restore the selection. + ScCore->primaryMainWindow()->view->Deselect(); + if (hadOrigSelection) + *ScCore->primaryMainWindow()->doc->m_Selection=tempSelection; + + Py_RETURN_NONE; +} + +PyObject *scribus_rotobjrel(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x; + if (!PyArg_ParseTuple(args, "d|es", &x, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + ScCore->primaryMainWindow()->doc->RotateItem(item->rotation() - x, item->ItemNr); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_rotobjabs(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x; + if (!PyArg_ParseTuple(args, "d|es", &x, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + ScCore->primaryMainWindow()->doc->RotateItem(x * -1.0, item->ItemNr); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_sizeobjabs(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double x, y; + if (!PyArg_ParseTuple(args, "dd|es", &x, &y, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(Name)); + if (item == NULL) + return NULL; + ScCore->primaryMainWindow()->doc->SizeItem(ValueToPoint(x), ValueToPoint(y), item->ItemNr); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_groupobj(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PyObject *il = 0; + if (!PyArg_ParseTuple(args, "|O", &il)) + return NULL; + if (!checkHaveDocument()) + return NULL; + if (il == 0 && ScCore->primaryMainWindow()->doc->m_Selection->count() < 2) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("Need selection or argument list of items to group", "python error").toLocal8Bit().constData()); + return NULL; + } + Selection *tempSelection=0; + Selection *finalSelection=0; + //uint ap = ScCore->primaryMainWindow()->doc->currentPage()->pageNr(); + // If we were passed a list of items to group... + if (il != 0) + { + int len = PyList_Size(il); + tempSelection = new Selection(ScCore->primaryMainWindow(), false); + for (int i = 0; i < len; i++) + { + // FIXME: We might need to explicitly get this string as utf8 + // but as sysdefaultencoding is utf8 it should be a no-op to do + // so anyway. + Name = PyString_AsString(PyList_GetItem(il, i)); + PageItem *ic = GetUniqueItem(QString::fromUtf8(Name)); + if (ic == NULL) + { + delete tempSelection; + return NULL; + } + tempSelection->addItem (ic, true); + } + finalSelection=tempSelection; + } + else + finalSelection=ScCore->primaryMainWindow()->doc->m_Selection; + if (finalSelection->count() < 2) + { + // We can't very well group only one item + PyErr_SetString(NoValidObjectError, QObject::tr("Cannot group less than two items", "python error").toLocal8Bit().constData()); + finalSelection=0; + delete tempSelection; + return NULL; + } + ScCore->primaryMainWindow()->doc->itemSelection_GroupObjects(false, false, finalSelection); + finalSelection=0; + delete tempSelection; + Py_RETURN_NONE; +} + +PyObject *scribus_ungroupobj(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + ScCore->primaryMainWindow()->view->Deselect(); + ScCore->primaryMainWindow()->view->SelectItemNr(i->ItemNr); + ScCore->primaryMainWindow()->UnGroupObj(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_scalegroup(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double sc; + if (!PyArg_ParseTuple(args, "d|es", &sc, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (sc == 0.0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot scale by 0%.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + ScCore->primaryMainWindow()->view->Deselect(); + ScCore->primaryMainWindow()->view->SelectItemNr(i->ItemNr); +// int h = ScCore->primaryMainWindow()->view->frameResizeHandle; +// ScCore->primaryMainWindow()->view->frameResizeHandle = 1; + ScCore->primaryMainWindow()->view->startGroupTransaction(Um::Resize, "", Um::IResize); + ScCore->primaryMainWindow()->doc->scaleGroup(sc, sc); + ScCore->primaryMainWindow()->view->endGroupTransaction(); +// ScCore->primaryMainWindow()->view->frameResizeHandle = h; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getselobjnam(PyObject* /* self */, PyObject* args) +{ + int i = 0; + if (!PyArg_ParseTuple(args, "|i", &i)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((i < static_cast<int>(ScCore->primaryMainWindow()->doc->m_Selection->count())) && (i > -1)) + return PyString_FromString(ScCore->primaryMainWindow()->doc->m_Selection->itemAt(i)->itemName().toUtf8()); + else + // FIXME: Should probably return None if no selection? + return PyString_FromString(""); +} + +PyObject *scribus_selcount(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->m_Selection->count())); +} + +PyObject *scribus_selectobj(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + ScCore->primaryMainWindow()->view->SelectItemNr(i->ItemNr); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_deselect(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->view->Deselect(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_lockobject(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + item->toggleLock(); + if (item->locked()) + return PyInt_FromLong(1); + return PyInt_FromLong(0); +} + +PyObject *scribus_islocked(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + // FIXME: Rather than toggling the lock, we should probably let the user set the lock state + // and instead provide a different function like toggleLock() + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if (item->locked()) + return PyBool_FromLong(1); + return PyBool_FromLong(0); +} + +PyObject *scribus_setscaleimagetoframe(PyObject* /* self */, PyObject* args, PyObject* kw) +{ + char *name = const_cast<char*>(""); + long int scaleToFrame = 0; + long int proportional = 1; + char* kwargs[] = {const_cast<char*>("scaletoframe"), + const_cast<char*>("proportional"), const_cast<char*>("name"), NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "i|ies", kwargs, &scaleToFrame, &proportional, "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if (! item->asImageFrame()) + { + PyErr_SetString(ScribusException, QObject::tr("Specified item not an image frame.","python error").toLocal8Bit().constData()); + return NULL; + } + // Set the item to scale if appropriate. ScaleType 1 is free + // scale, 0 is scale to frame. + item->ScaleType = scaleToFrame == 0; + // Now, if the user has chosen to set the proportional mode, + // set it. 1 is proportional, 0 is free aspect. + if (proportional != -1) + item->AspectRatio = proportional > 0; + // Force the braindead app to notice the changes + + //FIXME emit or something so we dont need this + ScCore->primaryMainWindow()->propertiesPalette->setScaleAndOffset(item->imageXScale(), item->imageYScale(), item->imageXOffset(), item->imageYOffset()); + item->AdjustPictScale(); + //ScCore->primaryMainWindow()->view->AdjustPictScale(item); + + item->update(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdmanidocwarnings() +{ + QStringList s; + s << scribus_moveobjrel__doc__ << scribus_moveobjabs__doc__ + << scribus_rotobjrel__doc__ << scribus_rotobjabs__doc__ + << scribus_sizeobjabs__doc__ << scribus_getselobjnam__doc__ + << scribus_selcount__doc__ << scribus_selectobj__doc__ + << scribus_deselect__doc__ << scribus_groupobj__doc__ + << scribus_ungroupobj__doc__ << scribus_scalegroup__doc__ + << scribus_loadimage__doc__ << scribus_scaleimage__doc__ + << scribus_setimagescale__doc__ << scribus_lockobject__doc__ + << scribus_islocked__doc__ << scribus_setscaleimagetoframe__doc__ + << scribus_setimageoffset__doc__ ; +} diff --git a/scribus/plugins/scriptplugin/cmdmani.h b/scribus/plugins/scriptplugin/cmdmani.h new file mode 100644 index 0000000..d29ac3c --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdmani.h @@ -0,0 +1,231 @@ +/* +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. +*/ +#ifndef CMDMANI_H +#define CMDMANI_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Manipulating Objects */ + +/*! docstring */ +PyDoc_STRVAR(scribus_moveobjrel__doc__, +QT_TR_NOOP("moveObject(dx, dy [, \"name\"])\n\ +\n\ +Moves the object \"name\" by dx and dy relative to its current position. The\n\ +distances are expressed in the current measurement unit of the document (see\n\ +UNIT constants). If \"name\" is not given the currently selected item is used.\n\ +If the object \"name\" belongs to a group, the whole group is moved.\n\ +")); +/*! Move REL the object */ +PyObject *scribus_moveobjrel(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_moveobjabs__doc__, +QT_TR_NOOP("moveObjectAbs(x, y [, \"name\"])\n\ +\n\ +Moves the object \"name\" to a new location. The coordinates are expressed in\n\ +the current measurement unit of the document (see UNIT constants). If \"name\"\n\ +is not given the currently selected item is used. If the object \"name\"\n\ +belongs to a group, the whole group is moved.\n\ +")); +/*! Move ABS the object */ +PyObject *scribus_moveobjabs(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_rotobjrel__doc__, +QT_TR_NOOP("rotateObject(rot [, \"name\"])\n\ +\n\ +Rotates the object \"name\" by \"rot\" degrees relatively. The object is\n\ +rotated by the vertex that is currently selected as the rotation point - by\n\ +default, the top left vertex at zero rotation. Positive values mean counter\n\ +clockwise rotation when the default rotation point is used. If \"name\" is not\n\ +given the currently selected item is used.\n\ +")); +/*! Rotate REL the object */ +PyObject *scribus_rotobjrel(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_rotobjabs__doc__, +QT_TR_NOOP("rotateObjectAbs(rot [, \"name\"])\n\ +\n\ +Sets the rotation of the object \"name\" to \"rot\". Positive values\n\ +mean counter clockwise rotation. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Rotate ABS the object */ +PyObject *scribus_rotobjabs(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_sizeobjabs__doc__, +QT_TR_NOOP("sizeObject(width, height [, \"name\"])\n\ +\n\ +Resizes the object \"name\" to the given width and height. If \"name\"\n\ +is not given the currently selected item is used.\n\ +")); +/*! Resize ABS the object */ +PyObject *scribus_sizeobjabs(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getselobjnam__doc__, +QT_TR_NOOP("getSelectedObject([nr]) -> string\n\ +\n\ +Returns the name of the selected object. \"nr\" if given indicates the number\n\ +of the selected object, e.g. 0 means the first selected object, 1 means the\n\ +second selected Object and so on.\n\ +")); +/*! Returns name of the selected object */ +PyObject *scribus_getselobjnam(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_selcount__doc__, +QT_TR_NOOP("selectionCount() -> integer\n\ +\n\ +Returns the number of selected objects.\n\ +")); +/*! Returns count of the selected object */ +PyObject *scribus_selcount(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_selectobj__doc__, +QT_TR_NOOP("selectObject(\"name\")\n\ +\n\ +Selects the object with the given \"name\".\n\ +")); +/*! Count selection */ +PyObject *scribus_selectobj(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_deselect__doc__, +QT_TR_NOOP("deselectAll()\n\ +\n\ +Deselects all objects in the whole document.\n\ +")); +/*! Remove all selection */ +PyObject *scribus_deselect(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_groupobj__doc__, +QT_TR_NOOP("groupObjects(list)\n\ +\n\ +Groups the objects named in \"list\" together. \"list\" must contain the names\n\ +of the objects to be grouped. If \"list\" is not given the currently selected\n\ +items are used.\n\ +")); +/*! Group objects named in list. */ +PyObject *scribus_groupobj(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_ungroupobj__doc__, +QT_TR_NOOP("unGroupObjects(\"name\")\n\n\ +Destructs the group the object \"name\" belongs to.\ +If \"name\" is not given the currently selected item is used.")); +/*! Ungroup objects named in list. */ +PyObject *scribus_ungroupobj(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_scalegroup__doc__, +QT_TR_NOOP("scaleGroup(factor [,\"name\"])\n\ +\n\ +Scales the group the object \"name\" belongs to. Values greater than 1 enlarge\n\ +the group, values smaller than 1 make the group smaller e.g a value of 0.5\n\ +scales the group to 50 % of its original size, a value of 1.5 scales the group\n\ +to 150 % of its original size. The value for \"factor\" must be greater than\n\ +0. If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise ValueError if an invalid scale factor is passed.\n\ +")); +/*! Scale group with object name */ +PyObject *scribus_scalegroup(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_loadimage__doc__, +QT_TR_NOOP("loadImage(\"filename\" [, \"name\"])\n\ +\n\ +Loads the picture \"picture\" into the image frame \"name\". If \"name\" is\n\ +not given the currently selected item is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not an image frame\n\ +")); +/*! Loads image file into frame. */ +PyObject *scribus_loadimage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_scaleimage__doc__, +QT_TR_NOOP("scaleImage(x, y [, \"name\"])\n\ +\n\ +Sets the internal scaling factors of the picture in the image frame \"name\".\n\ +If \"name\" is not given the currently selected item is used. A number of 1\n\ +means 100 %. Internal scaling factors are different from the values shown on \n\ +properties palette. Note : deprecated, use setImageScale() instead.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not an image frame\n\ +")); +/*! Scale Image. */ +PyObject *scribus_scaleimage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setimagescale__doc__, +QT_TR_NOOP("setImageScale(x, y [, \"name\"])\n\ +\n\ +Sets the scaling factors of the picture in the image frame \"name\".\n\ +If \"name\" is not given the currently selected item is used. A number of 1\n\ +means 100 %. Scaling factors are equal to the values shown on properties palette.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not an image frame\n\ +")); +/*! Scale Image. */ +PyObject *scribus_setimagescale(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setimageoffset__doc__, +QT_TR_NOOP("setImageOffset(x, y [, \"name\"])\n\ +\n\ +Sets the position of the picture in the image frame \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +The specified offset values are equal to the values shown on \n\ +properties palette when point unit is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not an image frame\n\ +")); +/*! Scale Image. */ +PyObject *scribus_setimageoffset(PyObject * /*self*/, PyObject* args); + + +/*! docstring */ +PyDoc_STRVAR(scribus_lockobject__doc__, +QT_TR_NOOP("lockObject([\"name\"]) -> bool\n\ +\n\ +Locks the object \"name\" if it's unlocked or unlock it if it's locked.\n\ +If \"name\" is not given the currently selected item is used. Returns true\n\ +if locked.\n\ +")); +/*! (Un)Lock the object 2004/7/10 pv.*/ +PyObject *scribus_lockobject(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_islocked__doc__, +QT_TR_NOOP("isLocked([\"name\"]) -> bool\n\ +\n\ +Returns true if is the object \"name\" locked. If \"name\" is not given the\n\ +currently selected item is used.\n\ +")); +/*! Status of locking 2004/7/10 pv.*/ +PyObject *scribus_islocked(PyObject * /*self*/, PyObject* args); + +PyDoc_STRVAR(scribus_setscaleimagetoframe__doc__, +QT_TR_NOOP("setScaleImageToFrame(scaletoframe, proportional=None, name=<selection>)\n\ +\n\ +Sets the scale to frame on the selected or specified image frame to `scaletoframe'.\n\ +If `proportional' is specified, set fixed aspect ratio scaling to `proportional'.\n\ +Both `scaletoframe' and `proportional' are boolean.\n\ +\n\ +May raise WrongFrameTypeError.\n\ +")); +PyObject *scribus_setscaleimagetoframe(PyObject * /*self*/, PyObject* args, PyObject* kwargs); + +#endif diff --git a/scribus/plugins/scriptplugin/cmdmisc.cpp b/scribus/plugins/scriptplugin/cmdmisc.cpp new file mode 100644 index 0000000..a6f5ce0 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdmisc.cpp @@ -0,0 +1,793 @@ +/* +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. +*/ +#include "cmdmisc.h" +#include "cmdutil.h" + +#include "qbuffer.h" +#include "qpixmap.h" +//Added by qt3to4: +#include <QList> + +#include "scribuscore.h" +#include "fonts/scfontmetrics.h" +#include "prefsmanager.h" + +PyObject *scribus_setredraw(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->doc->DoDrawing = static_cast<bool>(e); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_fontnames(PyObject* /* self */) +{ + int cc2 = 0; + SCFontsIterator it2(PrefsManager::instance()->appPrefs.AvailFonts); + for ( ; it2.hasNext() ; it2.next()) + { + if (it2.current().usable()) + cc2++; + } + PyObject *l = PyList_New(cc2); + SCFontsIterator it(PrefsManager::instance()->appPrefs.AvailFonts); + int cc = 0; + for ( ; it.hasNext() ; it.next()) + { + if (it.current().usable()) + { + PyList_SetItem(l, cc, PyString_FromString(it.currentKey().toUtf8())); + cc++; + } + } + return l; +} + +PyObject *scribus_xfontnames(PyObject* /* self */) +{ + PyObject *l = PyList_New(PrefsManager::instance()->appPrefs.AvailFonts.count()); + SCFontsIterator it(PrefsManager::instance()->appPrefs.AvailFonts); + int cc = 0; + PyObject *row; + for ( ; it.hasNext() ; it.next()) + { + row = Py_BuildValue((char*)"(sssiis)", + it.currentKey().toUtf8().data(), + it.current().family().toUtf8().data(), + it.current().psName().toUtf8().data(), + it.current().subset(), + it.current().embedPs(), + it.current().fontFilePath().toUtf8().data() + ); + PyList_SetItem(l, cc, row); + cc++; + } // for + return l; +} + +// This function is fairly complex because it can either save its output to a +// file, or return it as a Python string. +PyObject *scribus_renderfont(PyObject* /*self*/, PyObject* args, PyObject* kw) +{ + char *Name = const_cast<char*>(""); + char *FileName = const_cast<char*>(""); + char *Sample = const_cast<char*>(""); + char *format = NULL; + int Size; + bool ret = false; + char *kwargs[] = {const_cast<char*>("fontname"), + const_cast<char*>("filename"), + const_cast<char*>("sample"), + const_cast<char*>("size"), + const_cast<char*>("format"), + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "esesesi|es", kwargs, + "utf-8", &Name, "utf-8", &FileName, "utf-8", &Sample, &Size, "ascii", &format)) + return NULL; + if (!PrefsManager::instance()->appPrefs.AvailFonts.contains(QString::fromUtf8(Name))) + { + PyErr_SetString(NotFoundError, QObject::tr("Font not found.","python error").toLocal8Bit().constData()); + return NULL; + } + QString ts = QString::fromUtf8(Sample); + if (ts.isEmpty()) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot render an empty sample.","python error").toLocal8Bit().constData()); + return NULL; + } + if (!format) + // User specified no format, so use the historical default of PPM format. + format = const_cast<char*>("PPM"); + QPixmap pm = FontSample(PrefsManager::instance()->appPrefs.AvailFonts[QString::fromUtf8(Name)], Size, ts, Qt::white); + // If the user specified an empty filename, return the image data as + // a string. Otherwise, save it to disk. + if (QString::fromUtf8(FileName).isEmpty()) + { + QByteArray buffer_string = ""; + QBuffer buffer(&buffer_string); + buffer.open(QIODevice::WriteOnly); + bool ret = pm.save(&buffer, format); + if (!ret) + { + PyErr_SetString(ScribusException, QObject::tr("Unable to save pixmap","scripter error").toLocal8Bit().constData()); + return NULL; + } + int bufferSize = buffer.size(); + buffer.close(); + // Now make a Python string from the data we generated + PyObject* stringPython = PyString_FromStringAndSize(buffer_string,bufferSize); + // Return even if the result is NULL (error) since an exception will have been + // set in that case. + return stringPython; + } + else + // Save the pixmap to a file, since the filename is non-empty + { + ret = pm.save(QString::fromUtf8(FileName), format); + if (!ret) + { + PyErr_SetString(PyExc_Exception, QObject::tr("Unable to save pixmap","scripter error").toLocal8Bit().constData()); + return NULL; + } + // For historical reasons, we need to return true on success. +// Py_INCREF(Py_True); +// return Py_True; +// Py_RETURN_TRUE; + return PyBool_FromLong(static_cast<long>(true)); + } +} + +PyObject *scribus_getlayers(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + PyObject *l; + l = PyList_New(ScCore->primaryMainWindow()->doc->Layers.count()); + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + PyList_SetItem(l, lam, PyString_FromString(ScCore->primaryMainWindow()->doc->Layers[lam].Name.toUtf8())); + return l; +} + +PyObject *scribus_setactlayer(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = ScCore->primaryMainWindow()->doc->setActiveLayer(QString::fromUtf8(Name)); + if (found) + ScCore->primaryMainWindow()->changeLayer(ScCore->primaryMainWindow()->doc->activeLayer()); + else + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getactlayer(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + return PyString_FromString(ScCore->primaryMainWindow()->doc->activeLayerName().toUtf8()); +} + +PyObject *scribus_senttolayer(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Layer = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Layer, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Layer == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + ScCore->primaryMainWindow()->view->SelectItemNr(i->ItemNr); + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + ScCore->primaryMainWindow()->view->SelectItemNr(i->ItemNr); + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Layer)) + { + i->LayerNr = static_cast<int>(lam); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(ScribusException, QString("Layer not found").toLocal8Bit().constData()); + return NULL; + } + +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layervisible(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 1; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QString("Cannot have an empty layer name").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].isViewable = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layerprint(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 1; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].isPrintable = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layerlock(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 1; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].isEditable = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layeroutline(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 1; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].outlineMode = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layerflow(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 1; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].flowControl = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layerblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int vis = 0; + if (!PyArg_ParseTuple(args, "esi", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QString("Cannot have an empty layer name").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].blendMode = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_layertrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double vis = 1.0; + if (!PyArg_ParseTuple(args, "esd", "utf-8", &Name, &vis)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QString("Cannot have an empty layer name").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScCore->primaryMainWindow()->doc->Layers[lam].transparency = vis; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_glayervisib(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = static_cast<int>(ScCore->primaryMainWindow()->doc->Layers[lam].isViewable); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayerprint(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = static_cast<int>(ScCore->primaryMainWindow()->doc->Layers[lam].isPrintable); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayerlock(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = static_cast<int>(ScCore->primaryMainWindow()->doc->Layers[lam].isEditable); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayeroutline(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = static_cast<int>(ScCore->primaryMainWindow()->doc->Layers[lam].outlineMode); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayerflow(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = static_cast<int>(ScCore->primaryMainWindow()->doc->Layers[lam].flowControl); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayerblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + int i = 0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = ScCore->primaryMainWindow()->doc->Layers[lam].blendMode; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i)); +} + +PyObject *scribus_glayertrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + double i = 1.0; + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); lam++) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + i = ScCore->primaryMainWindow()->doc->Layers[lam].transparency; + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyFloat_FromDouble(i); +} + +PyObject *scribus_removelayer(PyObject* /* self */, PyObject* args) +{ +//FIXME: Use the docs remove layer code + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty layer name.","python error").toLocal8Bit().constData()); + return NULL; + } + if (ScCore->primaryMainWindow()->doc->Layers.count() == 1) + { + PyErr_SetString(ScribusException, QObject::tr("Cannot remove the last layer.","python error").toLocal8Bit().constData()); + return NULL; + } + bool found = false; + for (int lam=0; lam < ScCore->primaryMainWindow()->doc->Layers.count(); ++lam) + { + if (ScCore->primaryMainWindow()->doc->Layers[lam].Name == QString::fromUtf8(Name)) + { + ScLayer it2 = ScCore->primaryMainWindow()->doc->Layers.at(lam); + int num2 = it2.LNr; + if (!num2) + { + // FIXME: WTF DOES THIS DO? + Py_INCREF(Py_None); + return Py_None; + } + ScCore->primaryMainWindow()->doc->removeLayer(num2); + ScCore->primaryMainWindow()->doc->Layers.removeLayerByNumber(num2); + ScCore->primaryMainWindow()->doc->setActiveLayer(0); + ScCore->primaryMainWindow()->changeLayer(0); + found = true; + break; + } + } + if (!found) + { + PyErr_SetString(NotFoundError, QObject::tr("Layer not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_createlayer(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot create layer without a name.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->addLayer(QString::fromUtf8(Name), true); + ScCore->primaryMainWindow()->changeLayer(ScCore->primaryMainWindow()->doc->activeLayer()); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_filequit(PyObject* /* self */, PyObject* args) +{ + QMetaObject::invokeMethod(ScCore->primaryMainWindow(), "slotFileQuit", Qt::QueuedConnection); + Py_RETURN_NONE; +} + +PyObject *scribus_getlanguage(PyObject* /* self */) +{ + return PyString_FromString(ScCore->getGuiLanguage().toUtf8()); +} + +/*! 04.01.2007 : Joachim Neu : Moves item selection to front. */ +PyObject *scribus_moveselectiontofront(PyObject*) +{ + ScCore->primaryMainWindow()->doc->bringItemSelectionToFront(); + Py_RETURN_NONE; +} + +/*! 04.01.2007 : Joachim Neu : Moves item selection to back. */ +PyObject *scribus_moveselectiontoback(PyObject*) +{ + ScCore->primaryMainWindow()->doc->sendItemSelectionToBack(); + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdmiscdocwarnings() +{ + QStringList s; + s << scribus_setredraw__doc__ <<scribus_fontnames__doc__ + << scribus_xfontnames__doc__ <<scribus_renderfont__doc__ + << scribus_getlayers__doc__ << scribus_setactlayer__doc__ + << scribus_getactlayer__doc__ << scribus_senttolayer__doc__ + << scribus_layervisible__doc__ << scribus_layerprint__doc__ + << scribus_layerlock__doc__ << scribus_layeroutline__doc__ + << scribus_layerflow__doc__ << scribus_layerblend__doc__ + << scribus_layertrans__doc__ << scribus_glayervisib__doc__ + << scribus_glayerprint__doc__ << scribus_glayerlock__doc__ + << scribus_glayeroutline__doc__ << scribus_glayerflow__doc__ + << scribus_glayerblend__doc__ << scribus_glayertrans__doc__ + << scribus_removelayer__doc__ << scribus_createlayer__doc__ + << scribus_getlanguage__doc__ << scribus_moveselectiontofront__doc__ + << scribus_moveselectiontoback__doc__<< scribus_filequit__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdmisc.h b/scribus/plugins/scriptplugin/cmdmisc.h new file mode 100644 index 0000000..48f857a --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdmisc.h @@ -0,0 +1,353 @@ +/* +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. +*/ +#ifndef CMDMISC_H +#define CMDMISC_H + +// Pulls in <Python.h> first +#include "cmdvar.h" +//Added by qt3to4: +#include <QPixmap> + +/** Other Commands */ + +/*! docstring */ +PyDoc_STRVAR(scribus_setredraw__doc__, +QT_TR_NOOP("setRedraw(bool)\n\ +\n\ +Disables page redraw when bool = False, otherwise redrawing is enabled.\n\ +This change will persist even after the script exits, so make sure to call\n\ +setRedraw(True) in a finally: clause at the top level of your script.\n\ +")); +/*! Enable/disable page redrawing. */ +PyObject *scribus_setredraw(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_fontnames__doc__, +QT_TR_NOOP("getFontNames() -> list\n\ +\n\ +Returns a list with the names of all available fonts.\n\ +")); +/*! simple list of font names. */ +PyObject *scribus_fontnames(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_xfontnames__doc__, +QT_TR_NOOP("getXFontNames() -> list of tuples\n\ +\n\ +Returns a larger font info. It's a list of the tuples with:\n\ +[ (Scribus name, Family, Real name, subset (1|0), embed PS (1|0), font file), (...), ... ]\n\ +")); +/*! + return a list of the tuples with + Scribus name, Family, Real name, subset (1|0), embed PS (1|0), font file +*/ +PyObject *scribus_xfontnames(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_renderfont__doc__, +QT_TR_NOOP("renderFont(\"name\", \"filename\", \"sample\", size, format=\"PPM\") -> bool\n\ +\n\ +Creates an image preview of font \"name\" with given text \"sample\" and size.\n\ +If \"filename\" is not \"\", image is saved into \"filename\". Otherwise\n\ +image data is returned as a string. The optional \"format\" argument\n\ +specifies the image format to generate, and supports any format allowed\n\ +by QPixmap.save(). Common formats are PPM, JPEG, PNG and XPM.\n\ +\n\ +May raise NotFoundError if the specified font can't be found.\n\ +May raise ValueError if an empty sample or filename is passed.\n\ +")); +/*! Font example to image. */ +PyObject *scribus_renderfont(PyObject* /*self*/, PyObject* args, PyObject* kw); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlayers__doc__, +QT_TR_NOOP("getLayers() -> list\n\ +\n\ +Returns a list with the names of all defined layers.\n\ +")); +/*! List of the layers */ +PyObject *scribus_getlayers(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_setactlayer__doc__, +QT_TR_NOOP("setActiveLayer(\"name\")\n\ +\n\ +Sets the active layer to the layer named \"name\".\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Move into layer */ +PyObject *scribus_setactlayer(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getactlayer__doc__, +QT_TR_NOOP("getActiveLayer() -> string\n\ +\n\ +Returns the name of the current active layer.\n\ +")); +/*! Get layer name */ +PyObject *scribus_getactlayer(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_senttolayer__doc__, +QT_TR_NOOP("sentToLayer(\"layer\" [, \"name\"])\n\ +\n\ +Sends the object \"name\" to the layer \"layer\". The layer must exist.\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Move object from one layer to other one */ +PyObject *scribus_senttolayer(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layervisible__doc__, +QT_TR_NOOP("setLayerVisible(\"layer\", visible)\n\ +\n\ +Sets the layer \"layer\" to be visible or not. If is the visible set to false\n\ +the layer is invisible.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_layervisible(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layerprint__doc__, +QT_TR_NOOP("setLayerPrintable(\"layer\", printable)\n\ +\n\ +Sets the layer \"layer\" to be printable or not. If is the\n\ +printable set to false the layer won't be printed.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layerprint(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layerlock__doc__, +QT_TR_NOOP("setLayerLocked(\"layer\", locked)\n\ +\n\ +Sets the layer \"layer\" to be locked or not. If locked is set to\n\ +true the layer will be locked.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layerlock(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layeroutline__doc__, +QT_TR_NOOP("setLayerOutlined(\"layer\", outline)\n\ +\n\ +Sets the layer \"layer\" to be locked or not. If outline is set to\n\ +true the layer will be displayed outlined.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layeroutline(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layerflow__doc__, +QT_TR_NOOP("setLayerFlow(\"layer\", flow)\n\ +\n\ +Sets the layers \"layer\" flowcontrol to flow. If flow is set to\n\ +true text in layers above this one will flow around objects on this layer.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layerflow(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layerblend__doc__, +QT_TR_NOOP("setLayerBlendmode(\"layer\", blend)\n\ +\n\ +Sets the layers \"layer\" blendmode to blend.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layerblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_layertrans__doc__, +QT_TR_NOOP("setLayerTransparency(\"layer\", trans)\n\ +\n\ +Sets the layers \"layer\" transparency to trans.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_layertrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayervisib__doc__, +QT_TR_NOOP("isLayerVisible(\"layer\") -> bool\n\ +\n\ +Returns whether the layer \"layer\" is visible or not, a value of True means\n\ +that the layer \"layer\" is visible, a value of False means that the layer\n\ +\"layer\" is invisible.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayervisib(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayerprint__doc__, +QT_TR_NOOP("isLayerPrintable(\"layer\") -> bool\n\ +\n\ +Returns whether the layer \"layer\" is printable or not, a value of True means\n\ +that the layer \"layer\" can be printed, a value of False means that printing\n\ +the layer \"layer\" is disabled.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer printable */ +PyObject *scribus_glayerprint(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayerlock__doc__, +QT_TR_NOOP("isLayerLocked(\"layer\") -> bool\n\ +\n\ +Returns whether the layer \"layer\" is locked or not, a value of True means\n\ +that the layer \"layer\" is editable, a value of False means that the layer\n\ +\"layer\" is locked.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayerlock(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayeroutline__doc__, +QT_TR_NOOP("isLayerOutlined(\"layer\") -> bool\n\ +\n\ +Returns whether the layer \"layer\" is outlined or not, a value of True means\n\ +that the layer \"layer\" is outlined, a value of False means that the layer\n\ +\"layer\" is normal.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayeroutline(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayerflow__doc__, +QT_TR_NOOP("isLayerFlow(\"layer\") -> bool\n\ +\n\ +Returns whether text flows around objects on layer \"layer\", a value of True means\n\ +that text flows around, a value of False means that the text does not flow around.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayerflow(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayerblend__doc__, +QT_TR_NOOP("getLayerBlendmode(\"layer\") -> int\n\ +\n\ +Returns the \"layer\" layer blendmode,\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayerblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_glayertrans__doc__, +QT_TR_NOOP("getLayerTransparency(\"layer\") -> float\n\ +\n\ +Returns the \"layer\" layer transparency,\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Set layer visible */ +PyObject *scribus_glayertrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_removelayer__doc__, +QT_TR_NOOP("deleteLayer(\"layer\")\n\ +\n\ +Deletes the layer with the name \"layer\". Nothing happens if the layer doesn't\n\ +exists or if it's the only layer in the document.\n\ +\n\ +May raise NotFoundError if the layer can't be found.\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! Remove layer */ +PyObject *scribus_removelayer(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_createlayer__doc__, +QT_TR_NOOP("createLayer(layer)\n\ +\n\ +Creates a new layer with the name \"name\".\n\ +\n\ +May raise ValueError if the layer name isn't acceptable.\n\ +")); +/*! New layer */ +PyObject *scribus_createlayer(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_filequit__doc__, +QT_TR_NOOP("fileQuit()\n\ +\n\ +Quit Scribus.\n\ +")); +/*! Quit Scribus */ +PyObject *scribus_filequit(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlanguage__doc__, +QT_TR_NOOP("getGuiLanguage() -> string\n\ +\n\ +Returns a string with the -lang value.\n\ +")); +/*! Language of the GUI */ +PyObject *scribus_getlanguage(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_moveselectiontofront__doc__, +QT_TR_NOOP("moveSelectionToFront()\n\ +\n\ +Moves current selection to front.\n\ +")); +/*! 04.01.2007 : Joachim Neu : Moves item selection to front. */ +PyObject *scribus_moveselectiontofront(PyObject*); + +/*! docstring */ +PyDoc_STRVAR(scribus_moveselectiontoback__doc__, +QT_TR_NOOP("moveSelectionToFront()\n\ +\n\ +Moves current selection to back.\n\ +")); +/*! 04.01.2007 : Joachim Neu : Moves item selection to back. */ +PyObject *scribus_moveselectiontoback(PyObject*); + +#endif + + diff --git a/scribus/plugins/scriptplugin/cmdobj.cpp b/scribus/plugins/scriptplugin/cmdobj.cpp new file mode 100644 index 0000000..de7f3a7 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdobj.cpp @@ -0,0 +1,703 @@ +/* +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. +*/ +#include "cmdobj.h" +#include "cmdutil.h" +#include "selection.h" +#include "util_math.h" +#include "commonstrings.h" +#include "scribuscore.h" + + +PyObject *scribus_newrect(PyObject* /* self */, PyObject* args) +{ + double x, y, w, h; + char *Name = const_cast<char*>(""); + + if (!PyArg_ParseTuple(args, "dddd|es", &x, &y, &w, &h, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error")); +// return NULL; +// } + int i = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, + pageUnitXToDocX(x), pageUnitYToDocY(y), + ValueToPoint(w), ValueToPoint(h), + ScCore->primaryMainWindow()->doc->toolSettings.dWidth, + ScCore->primaryMainWindow()->doc->toolSettings.dBrush, ScCore->primaryMainWindow()->doc->toolSettings.dPen, true); +// ScCore->primaryMainWindow()->doc->setRedrawBounding(ScCore->primaryMainWindow()->doc->Items->at(i)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } +// if (Name != EMPTY_STRING) +// ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(QString::fromUtf8(Name)); + return PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(i)->itemName().toUtf8()); +} + + +PyObject *scribus_newellipse(PyObject* /* self */, PyObject* args) +{ + double x, y, w, h; + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "dddd|es", &x, &y, &w, &h, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + int i = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, + pageUnitXToDocX(x), + pageUnitYToDocY(y), + ValueToPoint(w), + ValueToPoint(h), + ScCore->primaryMainWindow()->doc->toolSettings.dWidth, + ScCore->primaryMainWindow()->doc->toolSettings.dBrush, + ScCore->primaryMainWindow()->doc->toolSettings.dPen, + true); +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error")); +// return NULL; +// } +// ScCore->primaryMainWindow()->doc->setRedrawBounding(ScCore->primaryMainWindow()->doc->Items->at(i)); +// if (Name != EMPTY_STRING) +// ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } + return PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(i)->itemName().toUtf8()); +} + + +PyObject *scribus_newimage(PyObject* /* self */, PyObject* args) +{ + double x, y, w, h; + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "dddd|es", &x, &y, &w, &h, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + int i = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, + pageUnitXToDocX(x), + pageUnitYToDocY(y), + ValueToPoint(w), + ValueToPoint(h), + 1, ScCore->primaryMainWindow()->doc->toolSettings.dBrushPict, + CommonStrings::None, true); +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error")); +// return NULL; +// } +// ScCore->primaryMainWindow()->doc->setRedrawBounding(ScCore->primaryMainWindow()->doc->Items->at(i)); +// if (Name != EMPTY_STRING) +// ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } + return PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(i)->itemName().toUtf8()); +} + + +PyObject *scribus_newtext(PyObject* /* self */, PyObject* args) +{ + double x, y, w, h; + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "dddd|es", &x, &y, &w, &h, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + int i = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, + pageUnitXToDocX(x), + pageUnitYToDocY(y), + ValueToPoint(w), + ValueToPoint(h), + ScCore->primaryMainWindow()->doc->toolSettings.dWidth, CommonStrings::None, + ScCore->primaryMainWindow()->doc->toolSettings.dPenText, true); +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error")); +// return NULL; +// } +// ScCore->primaryMainWindow()->doc->setRedrawBounding(ScCore->primaryMainWindow()->doc->Items->at(i)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } + return PyString_FromString(ScCore->primaryMainWindow()->doc->Items->at(i)->itemName().toUtf8()); +} + +PyObject *scribus_newline(PyObject* /* self */, PyObject* args) +{ + double x, y, w, h; + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "dddd|es", &x, &y, &w, &h, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + x = pageUnitXToDocX(x); + y = pageUnitYToDocY(y); + w = pageUnitXToDocX(w); + h = pageUnitYToDocY(h); +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, +// QObject::tr("An object with the requested name already exists.", +// "python error")); +// return NULL; +// } + int i = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::Line, PageItem::Unspecified, + x, y, w, h, + ScCore->primaryMainWindow()->doc->toolSettings.dWidth, + ScCore->primaryMainWindow()->doc->toolSettings.dBrush, + ScCore->primaryMainWindow()->doc->toolSettings.dPen, true); + PageItem *it = ScCore->primaryMainWindow()->doc->Items->at(i); + it->setRotation(xy2Deg(w-x, h-y)); + it->setWidthHeight(sqrt(pow(x-w, 2.0) + pow(y-h, 2.0)), 1.0); + it->Sizing = false; + it->updateClip(); + it->setRedrawBounding(); +// ScCore->primaryMainWindow()->doc->setRedrawBounding(it); +/* WTF? maybe I'll examine who's author later. Or maybe I'll remove it later ;) + it->PoLine.resize(4); + it->PoLine.setPoint(0, 0, 0); + it->PoLine.setPoint(1, 0, 0); + it->PoLine.setPoint(2, w-x, h-y); + it->PoLine.setPoint(3, w-x, h-y); + FPoint np2 = getMinClipF(&it->PoLine); + if (np2.x() < 0) + { + it->PoLine.translate(-np2.x(), 0); + ScCore->primaryMainWindow()->view->MoveItem(np2.x(), 0, it); + } + if (np2.y() < 0) + { + it->PoLine.translate(0, -np2.y()); + ScCore->primaryMainWindow()->view->MoveItem(0, np2.y(), it); + } + ScCore->primaryMainWindow()->view->SizeItem(it->PoLine.WidthHeight().x(), + it->PoLine.WidthHeight().y(), i, false, false, false); + ScCore->primaryMainWindow()->view->AdjustItemSize(it);*/ +// if (Name != EMPTY_STRING) +// it->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } + return PyString_FromString(it->itemName().toUtf8()); +} + + +PyObject *scribus_polyline(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PyObject *il; + // FIXME: PyList_Check failing will cause the function to return NULL w/o an exception. Separarate out the check. + if ((!PyArg_ParseTuple(args, "O|es", &il, "utf-8", &Name)) || (!PyList_Check(il))) + return NULL; + if(!checkHaveDocument()) + return NULL; + int len = PyList_Size(il); + if (len < 4) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must contain at least two points (four values).","python error").toLocal8Bit().constData()); + return NULL; + } + if ((len % 2) != 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must contain an even number of values.","python error").toLocal8Bit().constData()); + return NULL; + } +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error").toLocal8Bit().constData()); +// return NULL; +// } + double x, y, w, h; + int i = 0; + x = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + y = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + int ic = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, x, y, 1, 1, ScCore->primaryMainWindow()->doc->toolSettings.dWidth, ScCore->primaryMainWindow()->doc->toolSettings.dBrush, ScCore->primaryMainWindow()->doc->toolSettings.dPen, true); + PageItem *it = ScCore->primaryMainWindow()->doc->Items->at(ic); + it->PoLine.resize(2); + it->PoLine.setPoint(0, 0, 0); + it->PoLine.setPoint(1, 0, 0); + int pp = 6; + for (i = 2; i < len - 2; i += 2) + { + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+1)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-4, w-x, h-y); + it->PoLine.setPoint(pp-3, w-x, h-y); + it->PoLine.setPoint(pp-2, w-x, h-y); + it->PoLine.setPoint(pp-1, w-x, h-y); + pp += 4; + } + pp -= 2; + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-2)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-1)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-2, w-x, h-y); + it->PoLine.setPoint(pp-1, w-x, h-y); + FPoint np2 = getMinClipF(&it->PoLine); + if (np2.x() < 0) + { + it->PoLine.translate(-np2.x(), 0); + ScCore->primaryMainWindow()->doc->MoveItem(np2.x(), 0, it); + } + if (np2.y() < 0) + { + it->PoLine.translate(0, -np2.y()); + ScCore->primaryMainWindow()->doc->MoveItem(0, np2.y(), it); + } + ScCore->primaryMainWindow()->doc->SizeItem(it->PoLine.WidthHeight().x(), it->PoLine.WidthHeight().y(), ic, false, false, false); + ScCore->primaryMainWindow()->doc->AdjustItemSize(it); +// if (Name != EMPTY_STRING) +// { +// it->setItemName(QString::fromUtf8(Name)); +// } + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(ic)->setItemName(objName); + } + return PyString_FromString(it->itemName().toUtf8()); +} + + +PyObject *scribus_polygon(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PyObject *il; + // FIXME: PyList_Check failing will cause the function to return NULL w/o an exception. Separarate out the check. + if ((!PyArg_ParseTuple(args, "O|es", &il, "utf-8", &Name)) || (!PyList_Check(il))) + return NULL; + if(!checkHaveDocument()) + return NULL; + int len = PyList_Size(il); + if (len < 6) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must contain at least three points (six values).","python error").toLocal8Bit().constData()); + return NULL; + } + if ((len % 2) != 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must contain an even number of values.","python error").toLocal8Bit().constData()); + return NULL; + } +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error").toLocal8Bit().constData()); +// return NULL; +// } + double x, y, w, h; + int i = 0; + x = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + y = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + int ic = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, x, y, 1, 1, ScCore->primaryMainWindow()->doc->toolSettings.dWidth, ScCore->primaryMainWindow()->doc->toolSettings.dBrush, ScCore->primaryMainWindow()->doc->toolSettings.dPen, true); + PageItem *it = ScCore->primaryMainWindow()->doc->Items->at(ic); + it->PoLine.resize(2); + it->PoLine.setPoint(0, 0, 0); + it->PoLine.setPoint(1, 0, 0); + int pp = 6; + for (i = 2; i < len - 2; i += 2) + { + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+1)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-4, w-x, h-y); + it->PoLine.setPoint(pp-3, w-x, h-y); + it->PoLine.setPoint(pp-2, w-x, h-y); + it->PoLine.setPoint(pp-1, w-x, h-y); + pp += 4; + } + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-2)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-1)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-4, w-x, h-y); + it->PoLine.setPoint(pp-3, w-x, h-y); + it->PoLine.setPoint(pp-2, w-x, h-y); + it->PoLine.setPoint(pp-1, w-x, h-y); + pp += 2; + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-2, 0, 0); + it->PoLine.setPoint(pp-1, 0, 0); + FPoint np2 = getMinClipF(&it->PoLine); + if (np2.x() < 0) + { + it->PoLine.translate(-np2.x(), 0); + ScCore->primaryMainWindow()->doc->MoveItem(np2.x(), 0, it); + } + if (np2.y() < 0) + { + it->PoLine.translate(0, -np2.y()); + ScCore->primaryMainWindow()->doc->MoveItem(0, np2.y(), it); + } + ScCore->primaryMainWindow()->doc->SizeItem(it->PoLine.WidthHeight().x(), it->PoLine.WidthHeight().y(), ic, false, false, false); + ScCore->primaryMainWindow()->doc->AdjustItemSize(it); +// if (Name != EMPTY_STRING) +// it->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(ic)->setItemName(objName); + } + return PyString_FromString(it->itemName().toUtf8()); +} + +PyObject *scribus_bezierline(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + PyObject *il; + // FIXME: PyList_Check failing will cause the function to return NULL w/o an exception. Separarate out the check. + if ((!PyArg_ParseTuple(args, "O|es", &il, "utf-8", &Name)) || (!PyList_Check(il))) + return NULL; + if(!checkHaveDocument()) + return NULL; + int len = PyList_Size(il); + if (len < 8) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must contain at least four points (eight values).","python error").toLocal8Bit().constData()); + return NULL; + } + if ((len % 6) != 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Point list must have a multiple of six values.","python error").toLocal8Bit().constData()); + return NULL; + } +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error").toLocal8Bit().constData()); +// return NULL; +// } + double x, y, w, h, kx, ky, kx2, ky2; + int i = 0; + x = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + y = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + kx = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + ky = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + kx2 = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + ky2 = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + i++; + //int ic = ScCore->primaryMainWindow()->view->PaintPolyLine(x, y, 1, 1, ScCore->primaryMainWindow()->doc->toolSettings.dWidth, ScCore->primaryMainWindow()->doc->toolSettings.dBrush, ScCore->primaryMainWindow()->doc->toolSettings.dPen); + int ic = ScCore->primaryMainWindow()->doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, x, y, 1, 1, ScCore->primaryMainWindow()->doc->toolSettings.dWidth, ScCore->primaryMainWindow()->doc->toolSettings.dBrush, ScCore->primaryMainWindow()->doc->toolSettings.dPen, true); + PageItem *it = ScCore->primaryMainWindow()->doc->Items->at(ic); + it->PoLine.resize(2); + it->PoLine.setPoint(0, 0, 0); + it->PoLine.setPoint(1, kx-x, ky-y); + int pp = 6; + for (i = 6; i < len - 6; i += 6) + { + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+1)))); + kx = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+2)))); + ky = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+3)))); + kx2 = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+4)))); + ky2 = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, i+5)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-4, w-x, h-y); + it->PoLine.setPoint(pp-3, kx-x, ky-y); + it->PoLine.setPoint(pp-2, it->PoLine.point(pp-4)); + it->PoLine.setPoint(pp-1, kx2-x, ky2-y); + pp += 4; + } + pp -= 2; + w = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-6)))); + h = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-5)))); + kx = pageUnitXToDocX(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-4)))); + ky = pageUnitYToDocY(static_cast<double>(PyFloat_AsDouble(PyList_GetItem(il, len-3)))); + it->PoLine.resize(pp); + it->PoLine.setPoint(pp-2, w-x, h-y); + it->PoLine.setPoint(pp-1, kx-x, ky-y); + FPoint np2 = getMinClipF(&it->PoLine); + if (np2.x() < 0) + { + it->PoLine.translate(-np2.x(), 0); + ScCore->primaryMainWindow()->doc->MoveItem(np2.x(), 0, it); + } + if (np2.y() < 0) + { + it->PoLine.translate(0, -np2.y()); + ScCore->primaryMainWindow()->doc->MoveItem(0, np2.y(), it); + } + ScCore->primaryMainWindow()->doc->SizeItem(it->PoLine.WidthHeight().x(), it->PoLine.WidthHeight().y(), ic, false, false, false); + ScCore->primaryMainWindow()->doc->AdjustItemSize(it); +// if (Name != EMPTY_STRING) +// it->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(ic)->setItemName(objName); + } + return PyString_FromString(it->itemName().toUtf8()); +} + + +/* 03/31/2004 - xception handling + */ +PyObject *scribus_pathtext(PyObject* /* self */, PyObject* args) +{ + double x, y; + char *Name = const_cast<char*>(""); + char *TextB = const_cast<char*>(""); + char *PolyB = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "ddeses|es", &x, &y, "utf-8", &TextB, "utf-8", &PolyB, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; +// if (ItemExists(QString::fromUtf8(Name))) +// { +// PyErr_SetString(NameExistsError, QObject::tr("An object with the requested name already exists.","python error")); +// return NULL; +// } + //FIXME: Why use GetItem not GetUniqueItem? Maybe use GetUniqueItem and use the exceptions + // its sets for us? + int i = GetItem(QString::fromUtf8(TextB)); + int ii = GetItem(QString::fromUtf8(PolyB)); + if ((i == -1) || (ii == -1)) + { + PyErr_SetString(NotFoundError, QObject::tr("Object not found.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(ScCore->primaryMainWindow()->doc->Items->at(i)); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(ScCore->primaryMainWindow()->doc->Items->at(ii)); + PageItem *it = ScCore->primaryMainWindow()->doc->Items->at(i); + ScCore->primaryMainWindow()->view->ToPathText(); + ScCore->primaryMainWindow()->doc->MoveItem(pageUnitXToDocX(x) - it->xPos(), pageUnitYToDocY(y) - it->yPos(), it); +// if (Name != EMPTY_STRING) +// it->setItemName(QString::fromUtf8(Name)); + if (Name != EMPTY_STRING) + { + QString objName = QString::fromUtf8(Name); + if (!ItemExists(objName)) + ScCore->primaryMainWindow()->doc->Items->at(i)->setItemName(objName); + } + return PyString_FromString(it->itemName().toUtf8()); +} + + +/* 03/21/2004 - exception raised when Name doesn't exists. Doesn't crash then. (subik) + */ +PyObject *scribus_deleteobj(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + ScCore->primaryMainWindow()->doc->itemSelection_DeleteItem(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + + +/* 03/21/2004 - exception raises by non existent name (subik) + */ +PyObject *scribus_textflow(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + int state = -1; + + if (!PyArg_ParseTuple(args, "es|i", "utf-8", &name, &state)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i == NULL) + return NULL; + if (state == -1) + { + if (i->textFlowAroundObject()) + i->setTextFlowMode(PageItem::TextFlowDisabled); + else + i->setTextFlowMode(PageItem::TextFlowUsesFrameShape); + } + else if( state == (int) PageItem::TextFlowDisabled ) + i->setTextFlowMode(PageItem::TextFlowDisabled); + else if( state == (int) PageItem::TextFlowUsesFrameShape ) + i->setTextFlowMode(PageItem::TextFlowUsesFrameShape); + else if( state == (int) PageItem::TextFlowUsesBoundingBox ) + i->setTextFlowMode(PageItem::TextFlowUsesBoundingBox); + else if( state == (int) PageItem::TextFlowUsesContourLine ) + i->setTextFlowMode(PageItem::TextFlowUsesContourLine); + ScCore->primaryMainWindow()->view->DrawNew(); + ScCore->primaryMainWindow()->slotDocCh(true); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + + +PyObject *scribus_objectexists(PyObject* /* self */, PyObject* args) +{ + char* name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (ItemExists(QString::fromUtf8(name))) + return PyBool_FromLong(static_cast<long>(true)); + return PyBool_FromLong(static_cast<long>(false)); +} + +/* + * Craig Ringer, 2004-09-09 + * Apply the named style to the currently selected object. + * pv, 2004-09-13, optionaly param objectName + "check the page" stuff + */ +PyObject *scribus_setstyle(PyObject* /* self */, PyObject* args) +{ + char *style = const_cast<char*>(""); + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &style, "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if ((item->itemType() == PageItem::TextFrame) || (item->itemType() == PageItem::PathText)) + { + // 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; + uint styleid = 0; + // We start at zero here because it's OK to match an internal name + int docParagraphStylesCount=ScCore->primaryMainWindow()->doc->paragraphStyles().count(); + for (int i=0; i < docParagraphStylesCount; ++i) + { + if (ScCore->primaryMainWindow()->doc->paragraphStyles()[i].name() == QString::fromUtf8(style)) { + found = true; + styleid = i; + 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 NULL; + } + // for current item only + if (ScCore->primaryMainWindow()->doc->m_Selection->count() == 0 || name != EMPTY_STRING) + { + // quick hack to always apply on the right frame - pv + ScCore->primaryMainWindow()->view->Deselect(true); + //CB I dont think we need to draw here. Its faster if we dont. + ScCore->primaryMainWindow()->view->SelectItem(item, false); + // Now apply the style. + int mode = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->setNewParStyle(QString::fromUtf8(style)); + ScCore->primaryMainWindow()->doc->appMode = mode; + } + else // for multiple selection + { + int mode = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->appMode = modeNormal; + ScCore->primaryMainWindow()->doc->itemSelection_ApplyParagraphStyle(ScCore->primaryMainWindow()->doc->paragraphStyles()[styleid]); + ScCore->primaryMainWindow()->doc->appMode = mode; + } + } + else + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set style on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/* + * Craig Ringer, 2004-09-09 + * Enumerate all known paragraph styles + */ +PyObject *scribus_getstylenames(PyObject* /* self */) +{ + PyObject *styleList; + if(!checkHaveDocument()) + return NULL; + styleList = PyList_New(0); + for (int i=0; i < ScCore->primaryMainWindow()->doc->paragraphStyles().count(); ++i) + { + if (PyList_Append(styleList, PyString_FromString(ScCore->primaryMainWindow()->doc->paragraphStyles()[i].name().toUtf8()))) + { + // An exception will have already been set by PyList_Append apparently. + return NULL; + } + } + return styleList; +} + +PyObject *scribus_duplicateobject(PyObject * /* self */, PyObject *args) +{ + char* name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) { + return NULL; + } + if(!checkHaveDocument()) { + return NULL; + } + // Is there a special name given? Yes -> add this to selection + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i != NULL) { + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + } + else + return NULL; + // do the duplicate + ScCore->primaryMainWindow()->slotEditCopy(); + ScCore->primaryMainWindow()->slotEditPaste(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdobjdocwarnings() +{ + QStringList s; + s << scribus_newrect__doc__ <<scribus_newellipse__doc__ << scribus_newimage__doc__ << scribus_newtext__doc__ << scribus_newline__doc__ <<scribus_polyline__doc__ << scribus_polygon__doc__ << scribus_bezierline__doc__ <<scribus_pathtext__doc__ <<scribus_deleteobj__doc__ <<scribus_textflow__doc__ <<scribus_objectexists__doc__ <<scribus_setstyle__doc__ <<scribus_getstylenames__doc__ <<scribus_duplicateobject__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdobj.h b/scribus/plugins/scriptplugin/cmdobj.h new file mode 100644 index 0000000..d44ac6f --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdobj.h @@ -0,0 +1,263 @@ +/* +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. +*/ +#ifndef CMDOBJ_H +#define CMDOBJ_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Object related Commands */ + +/*! docstring */ +PyDoc_STRVAR(scribus_newrect__doc__, +QT_TR_NOOP("createRect(x, y, width, height, [\"name\"]) -> string\n\ +\n\ +Creates a new rectangle on the current page and returns its name. The\n\ +coordinates are given in the current measurement units of the document\n\ +(see UNIT constants). \"name\" should be a unique identifier for the object\n\ +because you need this name to reference that object in future. If \"name\"\n\ +is not given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +")); +/** Creates a rectangular with params X, Y (base position) + b, h (width, height) and optional name of the object. + */ +PyObject *scribus_newrect(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newellipse__doc__, +QT_TR_NOOP("createEllipse(x, y, width, height, [\"name\"]) -> string\n\ +\n\ +Creates a new ellipse on the current page and returns its name.\n\ +The coordinates are given in the current measurement units of the document\n\ +(see UNIT constants). \"name\" should be a unique identifier for the object\n\ +because you need this name for further referencing of that object. If \"name\"\n\ +is not given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +")); +/** Creates an ellipse with x, y, b and h - name optionally + params. + */ +PyObject *scribus_newellipse(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newimage__doc__, +QT_TR_NOOP("createImage(x, y, width, height, [\"name\"]) -> string\n\ +\n\ +Creates a new picture frame on the current page and returns its name. The\n\ +coordinates are given in the current measurement units of the document.\n\ +\"name\" should be a unique identifier for the object because you need this\n\ +name for further access to that object. If \"name\" is not given Scribus will\n\ +create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +")); +/** Creates an image frame - x, y, b, h and opt. name. */ +PyObject *scribus_newimage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newtext__doc__, +QT_TR_NOOP("createText(x, y, width, height, [\"name\"]) -> string\n\ +\n\ +Creates a new text frame on the actual page and returns its name.\n\ +The coordinates are given in the actual measurement unit of the document (see\n\ +UNIT constants). \"name\" should be a unique identifier for the object because\n\ +you need this name for further referencing of that object. If \"name\" is not\n\ +given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +")); +/** Creates a text frame - x, y, b, h and opt. name. */ +PyObject *scribus_newtext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_newline__doc__, +QT_TR_NOOP("createLine(x1, y1, x2, y2, [\"name\"]) -> string\n\ +\n\ +Creates a new line from the point(x1, y1) to the point(x2, y2) and returns\n\ +its name. The coordinates are given in the current measurement unit of the\n\ +document (see UNIT constants). \"name\" should be a unique identifier for the\n\ +object because you need this name for further access to that object. If\n\ +\"name\" is not given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +")); +/** Creates a line object - x, y, b, h and opt. name. */ +PyObject *scribus_newline(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_polyline__doc__, +QT_TR_NOOP("createPolyLine(list, [\"name\"]) -> string\n\ +\n\ +Creates a new polyline and returns its name. The points for the polyline are\n\ +stored in the list \"list\" in the following order: [x1, y1, x2, y2...xn. yn].\n\ +The coordinates are given in the current measurement units of the document (see\n\ +UNIT constants). \"name\" should be a unique identifier for the object because\n\ +you need this name for further access to that object. If \"name\" is not given\n\ +Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +May raise ValueError if an insufficient number of points is passed or if\n\ +the number of values passed don't group into points without leftovers.\n\ +")); +/** Creates a polygon line - list with points and opt. name as params. */ +PyObject *scribus_polyline(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_polygon__doc__, +QT_TR_NOOP("createPolygon(list, [\"name\"]) -> string\n\ +\n\ +Creates a new polygon and returns its name. The points for the polygon are\n\ +stored in the list \"list\" in the following order: [x1, y1, x2, y2...xn. yn].\n\ +At least three points are required. There is no need to repeat the first point\n\ +to close the polygon. The polygon is automatically closed by connecting the\n\ +first and the last point. The coordinates are given in the current measurement\n\ +units of the document (see UNIT constants). \"name\" should be a unique\n\ +identifier for the object because you need this name for further access to that\n\ +object. If \"name\" is not given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +May raise ValueError if an insufficient number of points is passed or if\n\ +the number of values passed don't group into points without leftovers.\n\ +")); +/** Creates a polygon - list with points and opt. name as params. */ +PyObject *scribus_polygon(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_bezierline__doc__, +QT_TR_NOOP("createBezierLine(list, [\"name\"]) -> string\n\ +\n\ +Creates a new bezier curve and returns its name. The points for the bezier\n\ +curve are stored in the list \"list\" in the following order:\n\ +[x1, y1, kx1, ky1, x2, y2, kx2, ky2...xn. yn, kxn. kyn]\n\ +In the points list, x and y mean the x and y coordinates of the point and kx\n\ +and ky meaning the control point for the curve. The coordinates are given in\n\ +the current measurement units of the document (see UNIT constants). \"name\"\n\ +should be a unique identifier for the object because you need this name for\n\ +further access to that object. If \"name\" is not given Scribus will create one\n\ +for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +May raise ValueError if an insufficient number of points is passed or if\n\ +the number of values passed don't group into points without leftovers.\n\ +")); +/** Creates a Bezier line - list with points and opt. name as params. */ +PyObject *scribus_bezierline(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_pathtext__doc__, +QT_TR_NOOP("createPathText(x, y, \"textbox\", \"beziercurve\", [\"name\"]) -> string\n\ +\n\ +Creates a new pathText by merging the two objects \"textbox\" and\n\ +\"beziercurve\" and returns its name. The coordinates are given in the current\n\ +measurement unit of the document (see UNIT constants). \"name\" should be a\n\ +unique identifier for the object because you need this name for further access\n\ +to that object. If \"name\" is not given Scribus will create one for you.\n\ +\n\ +May raise NameExistsError if you explicitly pass a name that's already used.\n\ +May raise NotFoundError if one or both of the named base object don't exist.\n\ +")); +/** Joins 2 objects - textframe and line - into text on path. + Uses x, y (base of the new object), name of the text frame, + name of the line and opt. new name as params. */ +PyObject *scribus_pathtext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_deleteobj__doc__, +QT_TR_NOOP("deleteObject([\"name\"])\n\ +\n\ +Deletes the item with the name \"name\". If \"name\" is not given the currently\n\ +selected item is deleted.\n\ +")); +/** Deletes an object - if is the name given the named object is + deleted else the active object erased. */ +PyObject *scribus_deleteobj(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_textflow__doc__, +QT_TR_NOOP("textFlowMode(\"name\" [, state])\n\ +\n\ +Enables/disables \"Text Flows Around Frame\" feature for object \"name\".\n\ +Called with parameters string name and optional int \"state\" (0 <= state <= 3).\n\ +Setting \"state\" to 0 will disable text flow.\n\ +Setting \"state\" to 1 will make text flow around object frame.\n\ +Setting \"state\" to 2 will make text flow around bounding box.\n\ +Setting \"state\" to 3 will make text flow around contour line.\n\ +If \"state\" is not passed, text flow is toggled.\n\ +")); +/** +Enables/disables "Text Flows Around Object" feature for object. +Called with params string objectName and state 0|1|2|3. +When set to 0 disable flowing, 1 text flows around frame, +2 around bounding box, 3 around contour line. When is second param +empty flowing is reverted. +02/28/2004 petr vanek + */ +PyObject *scribus_textflow(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_objectexists__doc__, +QT_TR_NOOP("objectExists([\"name\"]) -> bool\n\ +\n\ +Test if an object with specified name really exists in the document.\n\ +The optional parameter is the object name. When no object name is given,\n\ +returns True if there is something selected.\n\ +")); +/** +User test if an object with specified name really exists in +the doc. Object name as param. +03/29/2004 petr vanek +ObjectName is now optional. When none set, search for selection... +07/11/2004 pv +*/ +PyObject *scribus_objectexists(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setstyle__doc__, +QT_TR_NOOP("setStyle(\"style\" [, \"name\"])\n\ +\n\ +Apply the named \"style\" to the object named \"name\". If is no object name\n\ +given, it's applied on the selected object.\n\ +")); +/** + Craig Ringer, 2004-09-09 + Apply the named style to the currently selected object. + pv, 2004-09-13, optionaly param objectName + "check the page" stuff + */ +PyObject *scribus_setstyle(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getstylenames__doc__, +QT_TR_NOOP("getAllStyles() -> list\n\ +\n\ +Return a list of the names of all paragraph styles in the current document.\n\ +")); +/** + Craig Ringer, 2004-09-09 + Enumerate all known paragraph styles +*/ +PyObject *scribus_getstylenames(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_duplicateobject__doc__, +QT_TR_NOOP("duplicateObject([\"name\"]) -> string\n\ +\n\ +creates a Duplicate of the selected Object (or Selection Group).\n\ +")); +/** + Christian Hausknecht, 2006-07-12 + duplicate an object +*/ +PyObject *scribus_duplicateobject(PyObject * /* self */, PyObject *args); + +/* Internal function not intended for general use; no docstring */ +PyObject* scribus_getframetype(PyObject* self, PyObject* args, PyObject* kw); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdpage.cpp b/scribus/plugins/scriptplugin/cmdpage.cpp new file mode 100644 index 0000000..52ad3f2 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdpage.cpp @@ -0,0 +1,517 @@ +/* +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. +*/ +#include "cmdpage.h" +#include "cmdutil.h" +#include "page.h" +#include "scribuscore.h" +#include "commonstrings.h" + + +PyObject *scribus_actualpage(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->currentPageNumber() + 1)); +} + +PyObject *scribus_redraw(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->view->DrawNew(); + qApp->processEvents(); + // Py_INCREF(Py_None); + // return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_pageposition(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + e--; + if ((e < 0) || (e > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count())-1)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->locationOfPage(e))); +} + +PyObject *scribus_savepageeps(PyObject* /* self */, PyObject* args) +{ + char *Name; + if (!PyArg_ParseTuple(args, "es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + QString epsError; + bool ret = ScCore->primaryMainWindow()->DoSaveAsEps(QString::fromUtf8(Name), epsError); + if (!ret) + { + QString message = QObject::tr("Failed to save EPS.","python error"); + if (!epsError.isEmpty()) + message += QString("\n%1").arg(epsError); + PyErr_SetString(ScribusException, message.toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_True); // return True not None for backward compat +// return Py_True; +// Py_RETURN_TRUE; + return PyBool_FromLong(static_cast<long>(true)); +} + +PyObject *scribus_deletepage(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + e--; + if ((e < 0) || (e > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count())-1)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->DeletePage2(e); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_gotopage(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + e--; + if ((e < 0) || (e > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count())-1)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->view->GotoPage(e); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_newpage(PyObject* /* self */, PyObject* args) +{ + int e; + char *name = const_cast<char*>(""); + QString qName(CommonStrings::trMasterPageNormal); + if (!PyArg_ParseTuple(args, "i|es", &e, "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + + int loc = (e > -1) ? e : ScCore->primaryMainWindow()->doc->Pages->count(); + if (ScCore->primaryMainWindow()->doc->pageSets[ScCore->primaryMainWindow()->doc->currentPageLayout].Columns != 1) + { + switch (ScCore->primaryMainWindow()->doc->locationOfPage(loc)) + { + case LeftPage: + qName = CommonStrings::trMasterPageNormalLeft; + break; + case RightPage: + qName = CommonStrings::trMasterPageNormalRight; + break; + case MiddlePage: + qName = CommonStrings::trMasterPageNormalMiddle; + break; + } + } + if (QString(name).length() != 0) + qName = QString::fromUtf8(name); + + if (!ScCore->primaryMainWindow()->doc->MasterNames.contains(qName)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Given master page name does not match any existing.","python error").toLocal8Bit().constData()); + return NULL; + } + if (e < 0) + ScCore->primaryMainWindow()->slotNewPageP(loc, qName); + else + { + e--; + if ((e < 0) || (e > static_cast<int>(loc - 1))) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->slotNewPageP(e, qName); + } +// Py_INCREF(Py_None); + // return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_pagecount(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + return PyInt_FromLong(static_cast<long>(ScCore->primaryMainWindow()->doc->Pages->count())); +} + +PyObject *scribus_pagedimension(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + PyObject *t; + t = Py_BuildValue( + "(dd)", + PointToValue(ScCore->primaryMainWindow()->doc->pageWidth), // it's just view scale... * ScCore->primaryMainWindow()->doc->Scale), + PointToValue(ScCore->primaryMainWindow()->doc->pageHeight) // * ScCore->primaryMainWindow()->doc->Scale) + ); + return t; +} + +PyObject *scribus_pagensize(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + e--; + if ((e < 0) || (e > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count())-1)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + PyObject *t; + t = Py_BuildValue( + "(dd)", + PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->width()), + PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->height()) + ); + return t; +} + +PyObject *scribus_pagenmargins(PyObject* /* self */, PyObject* args) +{ + int e; + if (!PyArg_ParseTuple(args, "i", &e)) + return NULL; + if(!checkHaveDocument()) + return NULL; + e--; + if ((e < 0) || (e > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count())-1)) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Page number out of range.","python error").toLocal8Bit().constData()); + return NULL; + } + PyObject *margins = NULL; + margins = Py_BuildValue("ffff", PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->Margins.Top), + PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->Margins.Left), + PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->Margins.Right), + PointToValue(ScCore->primaryMainWindow()->doc->Pages->at(e)->Margins.Bottom)); + return margins; +} + +PyObject *scribus_getpageitems(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + if (ScCore->primaryMainWindow()->doc->Items->count() == 0) + return Py_BuildValue((char*)"[]"); + uint counter = 0; + int pageNr = ScCore->primaryMainWindow()->doc->currentPageNumber(); + for (int lam2 = 0; lam2 < ScCore->primaryMainWindow()->doc->Items->count(); ++lam2) + { + if (pageNr == ScCore->primaryMainWindow()->doc->Items->at(lam2)->OwnPage) + counter++; + } + PyObject *l = PyList_New(counter); + PyObject *row; + counter = 0; + for (int i = 0; i<ScCore->primaryMainWindow()->doc->Items->count(); ++i) + { + if (pageNr == ScCore->primaryMainWindow()->doc->Items->at(i)->OwnPage) + { + row = Py_BuildValue((char*)"(sii)", + ScCore->primaryMainWindow()->doc->Items->at(i)->itemName().toUtf8().constData(), + ScCore->primaryMainWindow()->doc->Items->at(i)->itemType(), + ScCore->primaryMainWindow()->doc->Items->at(i)->ItemNr + ); + PyList_SetItem(l, counter, row); + counter++; + } + } // for + return l; +} + +PyObject *scribus_getHguides(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.horizontals(GuideManagerCore::Standard); + int n = g.count();//ScCore->primaryMainWindow()->doc->currentPage->YGuides.count(); + if (n == 0) + return Py_BuildValue((char*)"[]"); + int i; + double tmp; + PyObject *l, *guide; + l = PyList_New(0); + for (i=0; i<n; i++) + { + tmp = g[i]; + guide = Py_BuildValue("d", PointToValue(tmp)); + PyList_Append(l, guide); + } + return l; +} + +PyObject *scribus_setHguides(PyObject* /* self */, PyObject* args) +{ + PyObject *l; + if (!PyArg_ParseTuple(args, "O", &l)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (!PyList_Check(l)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("argument is not list: must be list of float values.","python error").toLocal8Bit().constData()); + return NULL; + } + int i, n; + n = PyList_Size(l); + double guide; + ScCore->primaryMainWindow()->doc->currentPage()->guides.clearHorizontals(GuideManagerCore::Standard); + for (i=0; i<n; i++) + { + if (!PyArg_Parse(PyList_GetItem(l, i), "d", &guide)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("argument contains non-numeric values: must be list of float values.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->currentPage()->guides.addHorizontal(ValueToPoint(guide), GuideManagerCore::Standard); + } + Py_INCREF(Py_None); + return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getVguides(PyObject* /* self */) +{ + if(!checkHaveDocument()) + return NULL; + Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.verticals(GuideManagerCore::Standard); + int n = g.count();//ScCore->primaryMainWindow()->doc->currentPage->XGuides.count(); + if (n == 0) + return Py_BuildValue((char*)"[]"); + int i; + double tmp; + PyObject *l, *guide; + l = PyList_New(0); + for (i=0; i<n; i++) + { + tmp = g[i]; + guide = Py_BuildValue("d", PointToValue(tmp)); + PyList_Append(l, guide); + } + return l; +} + +PyObject *scribus_setVguides(PyObject* /* self */, PyObject* args) +{ + PyObject *l; + if (!PyArg_ParseTuple(args, "O", &l)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (!PyList_Check(l)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("argument is not list: must be list of float values.","python error").toLocal8Bit().constData()); + return NULL; + } + int i, n; + n = PyList_Size(l); + double guide; + ScCore->primaryMainWindow()->doc->currentPage()->guides.clearVerticals(GuideManagerCore::Standard); + for (i=0; i<n; i++) + { + if (!PyArg_Parse(PyList_GetItem(l, i), "d", &guide)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("argument contains no-numeric values: must be list of float values.","python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->currentPage()->guides.addVertical(ValueToPoint(guide), GuideManagerCore::Standard); + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_getpagemargins(PyObject* /* self */) +{ + PyObject *margins = NULL; + if(!checkHaveDocument()) + return NULL; + margins = Py_BuildValue("ffff", PointToValue(ScCore->primaryMainWindow()->doc->pageMargins.Top), + PointToValue(ScCore->primaryMainWindow()->doc->pageMargins.Left), + PointToValue(ScCore->primaryMainWindow()->doc->pageMargins.Right), + PointToValue(ScCore->primaryMainWindow()->doc->pageMargins.Bottom)); + return margins; +} + +/*! + \fn import_addpages(int total, int pos) + \author Alessandro Pira <alex@alessandropira.org> + \date 11-11-2007 + \param total number of pages to add, pos: position in the document + \param pos position of the imported pages + \retval void + */ +// This function is used by scribus_importpage() to add new pages +void import_addpages(int total, int pos) { + for (int i=0; i<total; i++) + { + int locreal = pos + i; + int loc = pos + i + 1; + + if (loc > ScCore->primaryMainWindow()->doc->Pages->count()) + loc = ScCore->primaryMainWindow()->doc->Pages->count(); + + QString qName(CommonStrings::trMasterPageNormal); + + if (ScCore->primaryMainWindow()->doc->pageSets[ScCore->primaryMainWindow()->doc->currentPageLayout].Columns != 1) { + ScCore->primaryMainWindow()->doc->locationOfPage(loc); + switch (ScCore->primaryMainWindow()->doc->locationOfPage(loc)) + { + case LeftPage: + qName = CommonStrings::trMasterPageNormalLeft; + break; + case RightPage: + qName = CommonStrings::trMasterPageNormalRight; + break; + case MiddlePage: + qName = CommonStrings::trMasterPageNormalMiddle; + break; + } + } + ScCore->primaryMainWindow()->slotNewPageP(locreal, qName); + } +} + +/*! + \fn scribus_importpage(PyObject*, PyObject* args) + \author Alessandro Pira <alex@alessandropira.org> + \date 11-11-2007 + \param PyObject unused reference + \param args Python function args ("fromDoc", (pageList), [create, imortwhere, importwherePage]) + \retval Py_RETURN_NONE if ok, null if error + */ +PyObject *scribus_importpage(PyObject* /* self */, PyObject* args) +{ + char *doc = NULL; + PyObject *pages = NULL; + int createPageI = 1; + int importWhere = 2; + int importWherePage = 0; + + if (!PyArg_ParseTuple(args, "sO|iii", &doc, &pages, &createPageI, &importWhere, &importWherePage)) + return NULL; + if(!checkHaveDocument()) + return NULL; + + if (!PyTuple_Check(pages)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("second argument is not tuple: must be tuple of int values.","python error").toLocal8Bit().constData()); + return NULL; + } + + Py_INCREF(pages); + std::vector<int> pageNs; + int i, n, p; + n = PyTuple_Size(pages); + for (i=0; i<n; i++) + { + if (!PyArg_Parse(PyTuple_GetItem(pages, i), "i", &p)) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("second argument contains non-numeric values: must be list of int values.","python error").toLocal8Bit().constData()); + Py_DECREF(pages); + return NULL; + } + pageNs.push_back(p); + } + Py_DECREF(pages); + + QString fromDoc = QString(doc); + bool createPage = (createPageI != 0); + + int startPage=0, nrToImport=pageNs.size(); + bool doIt = true; + + if (ScCore->primaryMainWindow()->doc->masterPageMode()) + { + if (nrToImport > 1) + ScCore->primaryMainWindow()->loadPage(fromDoc, pageNs[0] - 1, false); + doIt = false; + } + else if (createPage) + { + if (importWhere == 0) //Before page + startPage = importWherePage; + else if (importWhere == 1) //After page + startPage = importWherePage + 1; + else //at end + startPage = ScCore->primaryMainWindow()->doc->DocPages.count();// + 1; + + import_addpages(nrToImport, startPage); + } + else + { + startPage = ScCore->primaryMainWindow()->doc->currentPage()->pageNr() + 1; + if (nrToImport > (ScCore->primaryMainWindow()->doc->DocPages.count() - ScCore->primaryMainWindow()->doc->currentPage()->pageNr())) + { + int tmp=nrToImport - (ScCore->primaryMainWindow()->doc->DocPages.count() - ScCore->primaryMainWindow()->doc->currentPage()->pageNr()); + import_addpages(tmp, ScCore->primaryMainWindow()->doc->DocPages.count()); + } + } + + if (doIt) + { + if (nrToImport > 0) + { + int counter = startPage + 1; + for (int i = 0; i < nrToImport; ++i) + { + ScCore->primaryMainWindow()->view->GotoPa(counter); + ScCore->primaryMainWindow()->loadPage(fromDoc, pageNs[i] - 1, false); + counter++; + } + } + } + + Py_RETURN_NONE; +} + + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdpagedocwarnings() +{ + QStringList s; + s << scribus_newpage__doc__ << scribus_pageposition__doc__ + << scribus_actualpage__doc__ << scribus_redraw__doc__ + << scribus_savepageeps__doc__ << scribus_deletepage__doc__ + << scribus_gotopage__doc__ << scribus_pagecount__doc__ + << scribus_getHguides__doc__ << scribus_setHguides__doc__ + << scribus_getVguides__doc__ << scribus_setVguides__doc__ + << scribus_pagedimension__doc__ << scribus_getpageitems__doc__ + << scribus_getpagemargins__doc__ << scribus_importpage__doc__ + << scribus_pagensize__doc__ << scribus_pagenmargins__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdpage.h b/scribus/plugins/scriptplugin/cmdpage.h new file mode 100644 index 0000000..c3880d5 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdpage.h @@ -0,0 +1,228 @@ +/* +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. +*/ +#ifndef CMDPAGE_H +#define CMDPAGE_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Page related Commands */ + +/*! docstring */ +PyDoc_STRVAR(scribus_newpage__doc__, +QT_TR_NOOP("newPage(where [,\"masterpage\"])\n\ +\n\ +Creates a new page. If \"where\" is -1 the new Page is appended to the\n\ +document, otherwise the new page is inserted before \"where\". Page numbers are\n\ +counted from 1 upwards, no matter what the displayed first page number of your\n\ +document is. The optional parameter \"masterpage\" specifies the name of the\n\ +master page for the new page.\n\ +\n\ +May raise IndexError if the page number is out of range\n\ +")); +/*! new page */ +PyObject *scribus_newpage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_actualpage__doc__, +QT_TR_NOOP("currentPage() -> integer\n\ +\n\ +Returns the number of the current working page. Page numbers are counted from 1\n\ +upwards, no matter what the displayed first page number of your document is.\n\ +")); +/*! get actual page */ +PyObject *scribus_actualpage(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_redraw__doc__, +QT_TR_NOOP("redrawAll()\n\ +\n\ +Redraws all pages.\n\ +")); +/*! redraw all */ +PyObject *scribus_redraw(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_pageposition__doc__, +QT_TR_NOOP("getPageType() -> integer\n\ +\n\ +Returns the type of the Page, 0 means left Page, 1 is a middle Page and 2 is a right Page\n\ +")); +/*! Go to page */ +PyObject *scribus_pageposition(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_savepageeps__doc__, +QT_TR_NOOP("savePageAsEPS(\"name\")\n\ +\n\ +Saves the current page as an EPS to the file \"name\".\n\ +\n\ +May raise ScribusError if the save failed.\n\ +")); +/*! Export page as EPS file */ +PyObject *scribus_savepageeps(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_deletepage__doc__, +QT_TR_NOOP("deletePage(nr)\n\ +\n\ +Deletes the given page. Does nothing if the document contains only one page.\n\ +Page numbers are counted from 1 upwards, no matter what the displayed first\n\ +page number is.\n\ +\n\ +May raise IndexError if the page number is out of range\n\ +")); +/*! Delete page */ +PyObject *scribus_deletepage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_gotopage__doc__, +QT_TR_NOOP("gotoPage(nr)\n\ +\n\ +Moves to the page \"nr\" (that is, makes the current page \"nr\"). Note that\n\ +gotoPage doesn't (currently) change the page the user's view is displaying, it\n\ +just sets the page that script commands will operates on.\n\ +\n\ +May raise IndexError if the page number is out of range.\n\ +")); +/*! Go to page */ +PyObject *scribus_gotopage(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_pagecount__doc__, +QT_TR_NOOP("pageCount() -> integer\n\ +\n\ +Returns the number of pages in the document.\n\ +")); +/*! Go to page */ +PyObject *scribus_pagecount(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_getHguides__doc__, +QT_TR_NOOP("getHGuides() -> list\n\ +\n\ +Returns a list containing positions of the horizontal guides. Values are in the\n\ +document's current units - see UNIT_<type> constants.\n\ +")); +/*! get H guides */ +PyObject *scribus_getHguides(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_setHguides__doc__, +QT_TR_NOOP("setHGuides(list)\n\ +\n\ +Sets horizontal guides. Input parameter must be a list of guide positions\n\ +measured in the current document units - see UNIT_<type> constants.\n\ +\n\ +Example: setHGuides(getHGuides() + [200.0, 210.0] # add new guides without any lost\n\ + setHGuides([90,250]) # replace current guides entirely\n\ +")); +/*! set H guides */ +PyObject *scribus_setHguides(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getVguides__doc__, +QT_TR_NOOP("getVGuides()\n\ +\n\ +See getHGuides.\n\ +")); +/*! get V guides */ +PyObject *scribus_getVguides(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_setVguides__doc__, +QT_TR_NOOP("setVGuides()\n\ +\n\ +See setHGuides.\n\ +")); +/*! set V guides */ +PyObject *scribus_setVguides(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_pagedimension__doc__, +QT_TR_NOOP("getPageSize() -> tuple\n\ +\n\ +Returns a tuple with document page dimensions measured in the document's current units.\n\ +See UNIT_<type> constants and getPageMargins()\n\ +")); +/** +returns a tuple with page domensions in used system +e.g. when is the doc in picas returns picas ;) +(Petr Vanek 02/17/04) +*/ +PyObject *scribus_pagedimension(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_pagensize__doc__, +QT_TR_NOOP("getPageNSize(nr) -> tuple\n\ +\n\ +Returns a tuple with a particular page's size measured in the document's current units.\n\ +See UNIT_<type> constants and getPageMargins()\n\ +")); +/** +returns a tuple with a particular page's size in used system +e.g. when is the doc in picas returns picas ;) +*/ +PyObject *scribus_pagensize(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getpagemargins__doc__, +QT_TR_NOOP("getPageMargins()\n\ +\n\ +Returns the document page margins as a (top, left, right, bottom) tuple in the document's current\n\ +units. See UNIT_<type> constants and getPageSize().\n\ +")); +/** +returns a tuple with page margins +Craig Ringer, Petr Vanek 09/25/2004 +*/ +PyObject *scribus_getpagemargins(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_pagenmargins__doc__, +QT_TR_NOOP("getPageNMargins(nr) -> tuple\n\ +\n\ +Returns a tuple with a particular page's margins measured in the document's current units.\n\ +See UNIT_<type> constants and getPageMargins()\n\ +")); +/** +returns a tuple with a particular page's size in used system +e.g. when is the doc in picas returns picas ;) +*/ +PyObject *scribus_pagenmargins(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getpageitems__doc__, +QT_TR_NOOP("getPageItems() -> list\n\ +\n\ +Returns a list of tuples with items on the current page. The tuple is:\n\ +(name, objectType, order) E.g. [('Text1', 4, 0), ('Image1', 2, 1)]\n\ +means that object named 'Text1' is a text frame (type 4) and is the first at\n\ +the page...\n\ +")); +/** +returns a list of tuples with items on the actual page +TODO: solve utf/iso chars in object names +(Petr Vanek 03/02/2004) +*/ +PyObject *scribus_getpageitems(PyObject * /*self*/); + +/*! importpage */ +PyDoc_STRVAR(scribus_importpage__doc__, +QT_TR_NOOP("importPage(\"fromDoc\", (pageList), [create, imortwhere, importwherePage])\n\ +\n\ +Imports a set of pages (given as a tuple) from an existing document (the file name must be given). This functions maps the \"Page->Import\" dropdown menu function.\n\ +fromDoc: string; the filename of the document to import pages from\n\ +pageList: tuple with page numbers of pages to import\n\ +create: number; 0 to replace existing pages, 1 (default) to insert new pages\n\ +importWhere: number; the page number (of the current document) at which import the pages\n\ +importWherePage: number; used if create==1; 0 to create pages before selected page; 1 to create pages after selected page; 2 (default) to create pages at the end of the document\n\ +")); +PyObject *scribus_importpage(PyObject */*self*/, PyObject* args); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdsetprop.cpp b/scribus/plugins/scriptplugin/cmdsetprop.cpp new file mode 100644 index 0000000..2f82272 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdsetprop.cpp @@ -0,0 +1,398 @@ +/* +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. +*/ +#include "cmdsetprop.h" +#include "cmdutil.h" +#include "scribuscore.h" + +PyObject *scribus_setgradfill(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color1; + char *Color2; + int typ, shade1, shade2; + if (!PyArg_ParseTuple(args, "iesiesi|es", &typ, "utf-8", &Color1, &shade1, "utf-8", &Color2, &shade2, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((shade1 < 0) || (shade1 > 100) || (shade2 < 0) || (shade2 > 100)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Stop shade out of bounds, must be 0 <= shade <= 100.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name)); + if (currItem == NULL) + return NULL; + QColor tmp; + currItem->fill_gradient.clearStops(); + QString c1 = QString::fromUtf8(Color1); + QString c2 = QString::fromUtf8(Color2); + currItem->SetQColor(&tmp, c1, shade1); + currItem->fill_gradient.addStop(tmp, 0.0, 0.5, 1.0, c1, shade1); + currItem->SetQColor(&tmp, c2, shade2); + currItem->fill_gradient.addStop(tmp, 1.0, 0.5, 1.0, c2, shade2); + currItem->GrType = typ; + switch (currItem->GrType) + { + case 0: + case 1: + currItem->GrStartX = 0; + currItem->GrStartY = currItem->height() / 2.0; + currItem->GrEndX = currItem->width(); + currItem->GrEndY = currItem->height() / 2.0; + break; + case 2: + currItem->GrStartX = currItem->width() / 2.0; + currItem->GrStartY = 0; + currItem->GrEndX = currItem->width() / 2.0; + currItem->GrEndY = currItem->height(); + break; + case 3: + currItem->GrStartX = 0; + currItem->GrStartY = 0; + currItem->GrEndX = currItem->width(); + currItem->GrEndY = currItem->height(); + break; + case 4: + currItem->GrStartX = 0; + currItem->GrStartY = currItem->height(); + currItem->GrEndX = currItem->width(); + currItem->GrEndY = 0; + break; + case 5: + currItem->GrStartX = currItem->width() / 2.0; + currItem->GrStartY = currItem->height() / 2.0; + if (currItem->width() >= currItem->height()) + { + currItem->GrEndX = currItem->width(); + currItem->GrEndY = currItem->height() / 2.0; + } + else + { + currItem->GrEndX = currItem->width() / 2.0; + currItem->GrEndY = currItem->height(); + } + break; + default: + break; + } + //ScCore->primaryMainWindow()->view->updateGradientVectors(currItem); + currItem->updateGradientVectors(); + currItem->update(); + Py_RETURN_NONE; +} + +PyObject *scribus_setgradstop(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color1; + int shade1; + double rampPoint, opacity; + if (!PyArg_ParseTuple(args, "esidd|es", "utf-8", &Color1, &shade1, &opacity, &rampPoint, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((shade1 < 0) || (shade1 > 100)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Stop shade out of bounds, must be 0 <= shade <= 100.","python error").toLocal8Bit().constData()); + return NULL; + } + if ((rampPoint < 0.0) || (rampPoint > 1.0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Ramp point out of bounds, must be 0 <= rampPoint <= 1.","python error").toLocal8Bit().constData()); + return NULL; + } + if ((opacity < 0.0) || (opacity > 1.0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Opacity out of bounds, must be 0 <= transparency <= 1.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name)); + if (currItem == NULL) + return NULL; + QColor tmp; + QString c1 = QString::fromUtf8(Color1); + currItem->SetQColor(&tmp, c1, shade1); + currItem->fill_gradient.setStop(tmp, rampPoint, 0.5, opacity, c1, shade1); + currItem->updateGradientVectors(); + currItem->update(); + Py_RETURN_NONE; +} + +PyObject *scribus_setfillcolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setFillColor(QString::fromUtf8(Color)); + Py_RETURN_NONE; +} + +PyObject *scribus_setfilltrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double w; + if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0.0) || (w > 1.0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Transparency out of bounds, must be 0 <= transparency <= 1.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setFillTransparency(1.0 - w); + Py_RETURN_NONE; +} + +PyObject *scribus_setfillblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0) || (w > 15)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Blendmode out of bounds, must be 0 <= blendmode <= 15.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setFillBlendmode(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinecolor(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + it->setLineColor(QString::fromUtf8(Color)); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinetrans(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double w; + if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0.0) || (w > 1.0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Transparency out of bounds, must be 0 <= transparency <= 1.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setLineTransparency(1.0 - w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlineblend(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0) || (w > 15)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Blendmode out of bounds, must be 0 <= blendmode <= 15.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setLineBlendmode(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinewidth(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double w; + if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0.0) || (w > 300.0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Line width out of bounds, must be 0 <= line_width <= 300.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setLineWidth(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlineshade(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0) || (w > 100)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Line shade out of bounds, must be 0 <= shade <= 100.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + it->setLineShade(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setfillshade(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0) || (w > 100)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Fill shade out of bounds, must be 0 <= shade <= 100.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->setFillShade(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinejoin(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->PLineJoin = Qt::PenJoinStyle(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinecap(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->PLineEnd = Qt::PenCapStyle(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setlinestyle(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + i->PLineArt = Qt::PenStyle(w); + Py_RETURN_NONE; +} + +PyObject *scribus_setcornerrad(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (w < 0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Corner radius must be a positive number.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name)); + if (currItem == NULL) + return NULL; + // apply rounding + currItem->setCornerRadius(w); + currItem->SetFrameRound(); + ScCore->primaryMainWindow()->doc->setRedrawBounding(currItem); + ScCore->primaryMainWindow()->view->SetFrameRounded(); + Py_RETURN_NONE; +} + +PyObject *scribus_setmultiline(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Style = NULL; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Style, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name)); + if (currItem == NULL) + return NULL; + if (!ScCore->primaryMainWindow()->doc->MLineStyles.contains(QString::fromUtf8(Style))) + { + PyErr_SetString(NotFoundError, QObject::tr("Line style not found.","python error").toLocal8Bit().constData()); + return NULL; + } + currItem->NamedLStyle = QString::fromUtf8(Style); + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdsetpropdocwarnings() +{ + QStringList s; + s << scribus_setgradfill__doc__ << scribus_setgradstop__doc__ + << scribus_setfillcolor__doc__ << scribus_setfilltrans__doc__ + << scribus_setfillblend__doc__ << scribus_setlinecolor__doc__ + << scribus_setlinetrans__doc__ << scribus_setlineblend__doc__ + << scribus_setlinewidth__doc__ << scribus_setlineshade__doc__ + << scribus_setlinejoin__doc__ << scribus_setlinecap__doc__ + << scribus_setlinestyle__doc__ << scribus_setfillshade__doc__ + << scribus_setcornerrad__doc__ << scribus_setmultiline__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdsetprop.h b/scribus/plugins/scriptplugin/cmdsetprop.h new file mode 100644 index 0000000..991608c --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdsetprop.h @@ -0,0 +1,197 @@ +/* +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. +*/ +#ifndef CMDSETPROP_H +#define CMDSETPROP_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/** Setting Object Properties */ + +/*! docstring */ +PyDoc_STRVAR(scribus_setgradfill__doc__, +QT_TR_NOOP("setGradientFill(type, \"color1\", shade1, \"color2\", shade2, [\"name\"])\n\ +\n\ +Sets the gradient fill of the object \"name\" to type. Color descriptions are\n\ +the same as for setFillColor() and setFillShade(). See the constants for\n\ +available types (FILL_<type>).\n\ +")); +/*! Set gradient */ +PyObject *scribus_setgradfill(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setgradstop__doc__, +QT_TR_NOOP("setGradientStop(\"color\", shade, opacity, ramppoint, [\"name\"])\n\ +\n\ +Set or add a gradient stop to the gradient fill of the object \"name\" at position ramppoint.\n\ +Color descriptions are the same as for setFillColor() and setFillShade(). setGradientFill()\n\ +must have been called previously for the gradient fill to be visible.\n\ +")); +/*! Set gradient */ +PyObject *scribus_setgradstop(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfillcolor__doc__, +QT_TR_NOOP("setFillColor(\"color\", [\"name\"])\n\ +\n\ +Sets the fill color of the object \"name\" to the color \"color\". \"color\"\n\ +is the name of one of the defined colors. If \"name\" is not given the\n\ +currently selected item is used.\n\ +")); +/*! Set fill color */ +PyObject *scribus_setfillcolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfilltrans__doc__, +QT_TR_NOOP("setFillTransparency(transparency, [\"name\"])\n\ +\n\ +Sets the fill transparency of the object \"name\" to transparency\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set fill transparency */ +PyObject *scribus_setfilltrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfillblend__doc__, +QT_TR_NOOP("setFillBlendmode(blendmode, [\"name\"])\n\ +\n\ +Sets the fill blendmode of the object \"name\" to blendmode\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set fill blendmode */ +PyObject *scribus_setfillblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinecolor__doc__, +QT_TR_NOOP("setLineColor(\"color\", [\"name\"])\n\ +\n\ +Sets the line color of the object \"name\" to the color \"color\". If \"name\"\n\ +is not given the currently selected item is used.\n\ +")); +/*! Set line color */ +PyObject *scribus_setlinecolor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinetrans__doc__, +QT_TR_NOOP("setLineTransparency(transparency, [\"name\"])\n\ +\n\ +Sets the line transparency of the object \"name\" to transparency\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set line transparency */ +PyObject *scribus_setlinetrans(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlineblend__doc__, +QT_TR_NOOP("setLineBlendmode(blendmode, [\"name\"])\n\ +\n\ +Sets the line blendmode of the object \"name\" to blendmode\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set line blendmode */ +PyObject *scribus_setlineblend(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinewidth__doc__, +QT_TR_NOOP("setLineWidth(width, [\"name\"])\n\ +\n\ +Sets line width of the object \"name\" to \"width\". \"width\" must be in the\n\ +range from 0.0 to 12.0 inclusive, and is measured in points. If \"name\" is not\n\ +given the currently selected item is used.\n\ +\n\ +May raise ValueError if the line width is out of bounds.\n\ +")); +/*! Set line width */ +PyObject *scribus_setlinewidth(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlineshade__doc__, +QT_TR_NOOP("setLineShade(shade, [\"name\"])\n\ +\n\ +Sets the shading of the line color of the object \"name\" to \"shade\".\n\ +\"shade\" must be an integer value in the range from 0 (lightest) to 100\n\ +(full color intensity). If \"name\" is not given the currently selected item\n\ +is used.\n\ +\n\ +May raise ValueError if the line shade is out of bounds.\n\ +")); +/*! Set line shade */ +PyObject *scribus_setlineshade(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinejoin__doc__, +QT_TR_NOOP("setLineJoin(join, [\"name\"])\n\ +\n\ +Sets the line join style of the object \"name\" to the style \"join\".\n\ +If \"name\" is not given the currently selected item is used. There are\n\ +predefined constants for join - JOIN_<type>.\n\ +")); +/*! Set line join */ +PyObject *scribus_setlinejoin(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinecap__doc__, +QT_TR_NOOP("setLineCap(endtype, [\"name\"])\n\ +\n\ +Sets the line cap style of the object \"name\" to the style \"cap\".\n\ +If \"name\" is not given the currently selected item is used. There are\n\ +predefined constants for \"cap\" - CAP_<type>.\n\ +")); +/*! Set line end */ +PyObject *scribus_setlinecap(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinestyle__doc__, +QT_TR_NOOP("setLineStyle(style, [\"name\"])\n\ +\n\ +Sets the line style of the object \"name\" to the style \"style\". If \"name\"\n\ +is not given the currently selected item is used. There are predefined\n\ +constants for \"style\" - LINE_<style>.\n\ +")); +/*! Set line end */ +PyObject *scribus_setlinestyle(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfillshade__doc__, +QT_TR_NOOP("setFillShade(shade, [\"name\"])\n\ +\n\ +Sets the shading of the fill color of the object \"name\" to \"shade\".\n\ +\"shade\" must be an integer value in the range from 0 (lightest) to 100\n\ +(full Color intensity). If \"name\" is not given the currently selected\n\ +Item is used.\n\ +\n\ +May raise ValueError if the fill shade is out of bounds.\n\ +")); +/*! Set fill shade */ +PyObject *scribus_setfillshade(PyObject * /*self*/, PyObject* args); + +/*! docstringscribus_setmultiline__doc__ */ +PyDoc_STRVAR(scribus_setcornerrad__doc__, +QT_TR_NOOP("setCornerRadius(radius, [\"name\"])\n\ +\n\ +Sets the corner radius of the object \"name\". The radius is expressed\n\ +in points. If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise ValueError if the corner radius is negative.\n\ +")); +/*! Set corner radius */ +PyObject *scribus_setcornerrad(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setmultiline__doc__, +QT_TR_NOOP("setMultiLine(\"namedStyle\", [\"name\"])\n\ +\n\ +Sets the line style of the object \"name\" to the named style \"namedStyle\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise NotFoundError if the line style doesn't exist.\n\ +")); +/*! Set multiline */ +PyObject *scribus_setmultiline(PyObject * /*self*/, PyObject* args); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdstyle.cpp b/scribus/plugins/scriptplugin/cmdstyle.cpp new file mode 100644 index 0000000..04c10a0 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdstyle.cpp @@ -0,0 +1,177 @@ +/* +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. +02.01.2008: Joachim Neu - joachim_neu@web.de - http://www.joachim-neu.de +*/ +#include "cmdstyle.h" +#include "cmdutil.h" + +#include "qbuffer.h" +#include "qpixmap.h" +//Added by qt3to4: +#include <QList> + +#include "scribuscore.h" +#include "styles/paragraphstyle.h" +#include "styles/charstyle.h" +#include "stylemanager.h" + +/*! 02.01.2007 - 05.01.2007 : Joachim Neu : Create a paragraph style. + Special thanks go to avox for helping me! */ +PyObject *scribus_createparagraphstyle(PyObject* /* self */, PyObject* args, PyObject* keywords) +{ + char* keywordargs[] = { + const_cast<char*>("name"), + const_cast<char*>("linespacingmode"), + const_cast<char*>("linespacing"), + const_cast<char*>("alignment"), + const_cast<char*>("leftmargin"), + const_cast<char*>("rightmargin"), + const_cast<char*>("gapbefore"), + const_cast<char*>("gapafter"), + const_cast<char*>("firstindent"), + const_cast<char*>("hasdropcap"), + const_cast<char*>("dropcaplines"), + const_cast<char*>("dropcapoffset"), + const_cast<char*>("charstyle"), + NULL}; + char *Name = const_cast<char*>(""), *CharStyle = const_cast<char*>(""); + int LineSpacingMode = 0, Alignment = 0, DropCapLines = 2, HasDropCap = 0; + double LineSpacing = 15.0, LeftMargin = 0.0, RightMargin = 0.0; + double GapBefore = 0.0, GapAfter = 0.0, FirstIndent = 0.0, DropCapOffset = 0; + if (!PyArg_ParseTupleAndKeywords(args, keywords, "es|ididddddiides", + keywordargs, "utf-8", &Name, &LineSpacingMode, &LineSpacing, &Alignment, + &LeftMargin, &RightMargin, &GapBefore, &GapAfter, &FirstIndent, + &HasDropCap, &DropCapLines, &DropCapOffset, "utf-8", &CharStyle)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty paragraph style name.","python error").toLocal8Bit().constData()); + return NULL; + } + + ParagraphStyle TmpParagraphStyle; + TmpParagraphStyle.setName(Name); + TmpParagraphStyle.setLineSpacingMode((ParagraphStyle::LineSpacingMode)LineSpacingMode); + TmpParagraphStyle.setLineSpacing(LineSpacing); + TmpParagraphStyle.setAlignment((ParagraphStyle::AlignmentType)Alignment); + TmpParagraphStyle.setLeftMargin(LeftMargin); + TmpParagraphStyle.setFirstIndent(FirstIndent); + TmpParagraphStyle.setRightMargin(RightMargin); + TmpParagraphStyle.setGapBefore(GapBefore); + TmpParagraphStyle.setGapAfter(GapAfter); + if(HasDropCap == 0) + TmpParagraphStyle.setHasDropCap(false); + else if(HasDropCap == 1) + TmpParagraphStyle.setHasDropCap(true); + else + { + PyErr_SetString(PyExc_ValueError, QObject::tr("hasdropcap has to be 0 or 1.","python error").toLocal8Bit().constData()); + return NULL; + } + TmpParagraphStyle.setDropCapLines(DropCapLines); + TmpParagraphStyle.setDropCapOffset(DropCapOffset); + TmpParagraphStyle.charStyle().setParent(CharStyle); + + StyleSet<ParagraphStyle> TmpStyleSet; + TmpStyleSet.create(TmpParagraphStyle); + ScCore->primaryMainWindow()->doc->redefineStyles(TmpStyleSet, false); + // PV - refresh the Style Manager window. + // I thought that this can work but it doesn't: + // ScCore->primaryMainWindow()->styleMgr()->reloadStyleView(); + // So the brute force setDoc is called... + ScCore->primaryMainWindow()->styleMgr()->setDoc(ScCore->primaryMainWindow()->doc); + + Py_RETURN_NONE; +} + +/*! 03.01.2007 - 05.01.2007 : Joachim Neu : Create a char style. + Special thanks go to avox for helping me! */ +PyObject *scribus_createcharstyle(PyObject* /* self */, PyObject* args, PyObject* keywords) +{ + char* keywordargs[] = { + const_cast<char*>("name"), + const_cast<char*>("font"), + const_cast<char*>("fontsize"), + const_cast<char*>("features"), + const_cast<char*>("fillcolor"), + const_cast<char*>("fillshade"), + const_cast<char*>("strokecolor"), + const_cast<char*>("strokeshade"), + const_cast<char*>("baselineoffset"), + const_cast<char*>("shadowxoffset"), + const_cast<char*>("shadowyoffset"), + const_cast<char*>("outlinewidth"), + const_cast<char*>("underlineoffset"), + const_cast<char*>("underlinewidth"), + const_cast<char*>("strikethruoffset"), + const_cast<char*>("strikethruwidth"), + const_cast<char*>("scaleh"), + const_cast<char*>("scalev"), + const_cast<char*>("tracking"), + const_cast<char*>("language"), + NULL}; + char *Name = const_cast<char*>(""), *Font = const_cast<char*>("Times"), *Features = const_cast<char*>("inherit"), *FillColor = const_cast<char*>("Black"), *StrokeColor = const_cast<char*>("Black"), *Language = const_cast<char*>(""); + double FontSize = 200, FillShade = 1, StrokeShade = 1, ScaleH = 1, ScaleV = 1, BaselineOffset = 0, ShadowXOffset = 0, ShadowYOffset = 0, OutlineWidth = 0, UnderlineOffset = 0, UnderlineWidth = 0, StrikethruOffset = 0, StrikethruWidth = 0, Tracking = 0; + if (!PyArg_ParseTupleAndKeywords(args, keywords, "es|esdesesdesddddddddddddes", keywordargs, + "utf-8", &Name, "utf-8", &Font, &FontSize, "utf-8", &Features, + "utf-8", &FillColor, &FillShade, "utf-8", &StrokeColor, &StrokeShade, &BaselineOffset, &ShadowXOffset, + &ShadowYOffset, &OutlineWidth, &UnderlineOffset, &UnderlineWidth, &StrikethruOffset, &StrikethruWidth, + &ScaleH, &ScaleV, &Tracking, "utf-8", &Language)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if(Name == EMPTY_STRING) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Cannot have an empty char style name.","python error").toLocal8Bit().constData()); + return NULL; + } + + QStringList FeaturesList = QString(Features).split(QString(",")); + + CharStyle TmpCharStyle; + TmpCharStyle.setName(Name); + TmpCharStyle.setFont((*ScCore->primaryMainWindow()->doc->AllFonts)[QString(Font)]); + TmpCharStyle.setFontSize(FontSize * 10); + TmpCharStyle.setFeatures(FeaturesList); + TmpCharStyle.setFillColor(QString(FillColor)); + TmpCharStyle.setFillShade(FillShade * 100); + TmpCharStyle.setStrokeColor(QString(StrokeColor)); + TmpCharStyle.setStrokeShade(StrokeShade * 100); + TmpCharStyle.setBaselineOffset(BaselineOffset); + TmpCharStyle.setShadowXOffset(ShadowXOffset); + TmpCharStyle.setShadowYOffset(ShadowYOffset); + TmpCharStyle.setOutlineWidth(OutlineWidth); + TmpCharStyle.setUnderlineOffset(UnderlineOffset); + TmpCharStyle.setUnderlineWidth(UnderlineWidth); + TmpCharStyle.setStrikethruOffset(StrikethruOffset); + TmpCharStyle.setStrikethruWidth(StrikethruWidth); + TmpCharStyle.setScaleH(ScaleH * 1000); + TmpCharStyle.setScaleV(ScaleV * 1000); + TmpCharStyle.setTracking(Tracking); + TmpCharStyle.setLanguage(QString(Language)); + + StyleSet<CharStyle> TmpStyleSet; + TmpStyleSet.create(TmpCharStyle); + ScCore->primaryMainWindow()->doc->redefineCharStyles(TmpStyleSet, false); + // PV - refresh the Style Manager window. + // I thought that this can work but it doesn't: + // ScCore->primaryMainWindow()->styleMgr()->reloadStyleView(); + // So the brute force setDoc is called... + ScCore->primaryMainWindow()->styleMgr()->setDoc(ScCore->primaryMainWindow()->doc); + + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdstyledocwarnings() +{ + QStringList s; + s << scribus_createparagraphstyle__doc__ << scribus_createcharstyle__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdstyle.h b/scribus/plugins/scriptplugin/cmdstyle.h new file mode 100644 index 0000000..1279884 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdstyle.h @@ -0,0 +1,86 @@ +/* +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. +02.01.2008: Joachim Neu - joachim_neu@web.de - http://www.joachim-neu.de +*/ +#ifndef CMDSTYLE_H +#define CMDSTYLE_H + +// Pulls in <Python.h> first +#include "cmdvar.h" +//Added by qt3to4: +#include <QPixmap> + +/** Style-related Commands */ + +/* PARAGRAPH STYLES */ + +/*! docstring */ +PyDoc_STRVAR(scribus_createparagraphstyle__doc__, +QT_TR_NOOP("createParagraphStyle(...)\n\n\ +Creates a paragraph style. This function takes the following keyword parameters:\n\n\ +\"name\" [required] -> specifies the name of the paragraphstyle to create\n\n\ +linespacingmode [optional] -> specifies the linespacing mode; possible modes are:\n\n\ +fixed linespacing: 0\n\n\ +automatic linespacing: 1\n\n\ +baseline grid linespacing: 2\n\n\ +linespacing [optional] -> specifies the linespacing if using fixed linespacing\n\n\ +alignment [optional] -> specifies the alignment of the paragraph\n\n\ +-> left: 0\n\n\ +-> center: 1\n\n\ +-> right: 2\n\n\ +-> justify: 3\n\n\ +-> extend: 4\n\n\ +leftmargin [optional], rightmargin [optional] -> specify the margin\n\n\ +gapbefore [optional], gapafter [optional] -> specify the gaps to the heading and following paragraphs\n\n\ +firstindent [optional] -> the indent of the first line\n\n\ +hasdropcap [optional] -> specifies if there are caps (1 = yes, 0 = no)\n\n\ +dropcaplines [optional] -> height (in lines) of the caps if used\n\n\ +dropcapoffset [optional] -> offset of the caps if used\n\n\ +\"charstyle\" [optional] -> char style to use\n\n\ +")); +/*! 02.01.2007 - 05.01.2007 : Joachim Neu : Create a paragraph style. + Special thanks go to avox for helping me! */ +PyObject *scribus_createparagraphstyle(PyObject * /* self */, PyObject* args, PyObject* keywords); + +/* CHAR STYLES */ + +/*! docstring */ +PyDoc_STRVAR(scribus_createcharstyle__doc__, +QT_TR_NOOP("createCharStyle(...)\n\n\ +Creates a character style. This function takes the following keyword parameters:\n\n\ +\"name\" [required] -> name of the char style to create\n\n\ +\"font\" [optional] -> name of the font to use\n\n\ +fontsize [optional] -> font size to set (double)\n\n\ +\"features\" [optional] -> nearer typographic details can be defined by a string that might contain the following phrases comma-seperated (without spaces!):\n\n\ +-> inherit\n\n\ +-> bold\n\n\ +-> italic\n\n\ +-> underline\n\n\ +-> underlinewords\n\n\ +-> strike\n\n\ +-> superscript\n\n\ +-> subscript\n\n\ +-> outline\n\n\ +-> shadowed\n\n\ +-> allcaps\n\n\ +-> smallcaps\n\n\ +\"fillcolor\" [optional], \"fillshade\" [optional] -> specify fill options\n\n\ +\"strokecolor\" [optional], \"strokeshade\" [optional] -> specify stroke options\n\n\ +baselineoffset [optional] -> offset of the baseline\n\n\ +shadowxoffset [optional], shadowyoffset [optional] -> offset of the shadow if used\n\n\ +outlinewidth [optional] -> width of the outline if used\n\n\ +underlineoffset [optional], underlinewidth [optional] -> underline options if used\n\n\ +strikethruoffset [optional], strikethruwidth [optional] -> strikethru options if used\n\n\ +scaleh [optional], scalev [optional] -> scale of the chars\n\n\ +tracking [optional] -> tracking of the text\n\n\ +\"language\" [optional] -> language code\n\n\ +")); +/*! 03.01.2007 - 05.01.2007 : Joachim Neu : Create a char style. + Special thanks go to avox for helping me! */ +PyObject *scribus_createcharstyle(PyObject * /* self */, PyObject* args, PyObject* keywords); + +#endif + diff --git a/scribus/plugins/scriptplugin/cmdtext.cpp b/scribus/plugins/scriptplugin/cmdtext.cpp new file mode 100644 index 0000000..fff491b --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdtext.cpp @@ -0,0 +1,1109 @@ +/* +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. +*/ +#include "cmdtext.h" +#include "cmdutil.h" +#include "pageitem_textframe.h" +#include "prefsmanager.h" +#include "selection.h" +#include "util.h" +#include "scribuscore.h" +#include "hyphenator.h" + +PyObject *scribus_getfontsize(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get font size of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (it->HasSel) + { + for (int b = 0; b < it->itemText.length(); b++) + if (it->itemText.selected(b)) + return PyFloat_FromDouble(static_cast<double>(it->itemText.charStyle(b).fontSize() / 10.0)); + return NULL; + } + else + return PyFloat_FromDouble(static_cast<long>(it->currentCharStyle().fontSize() / 10.0)); +} + +PyObject *scribus_getfont(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get font of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (it->HasSel) + { + for (int b = 0; b < it->itemText.length(); b++) + if (it->itemText.selected(b)) + return PyString_FromString(it->itemText.charStyle(b).font().scName().toUtf8()); + return NULL; + } + else + return PyString_FromString(it->currentCharStyle().font().scName().toUtf8()); +} + +PyObject *scribus_gettextsize(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!(i->asTextFrame()) && !(i->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text size of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i->itemText.length())); +} + +PyObject *scribus_gettextlines(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!(i->asTextFrame()) && !(i->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get number of lines of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i->itemText.lines())); +} + +PyObject *scribus_getcolumns(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column count of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyInt_FromLong(static_cast<long>(i->Cols)); +} + +PyObject *scribus_getlinespace(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get line space of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyFloat_FromDouble(static_cast<double>(i->currentStyle().lineSpacing())); +} + +PyObject *scribus_gettextdistances(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text distances of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return Py_BuildValue("(dddd)", + PointToValue(i->textToFrameDistLeft()), + PointToValue(i->textToFrameDistRight()), + PointToValue(i->textToFrameDistTop()), + PointToValue(i->textToFrameDistBottom())); +} + +PyObject *scribus_getcolumngap(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column gap of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + return PyFloat_FromDouble(PointToValue(static_cast<double>(i->ColGap))); +} + +PyObject *scribus_getframetext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + QString text = ""; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + for (int a = it->firstInFrame(); a <= it->lastInFrame(); ++a) + { + if (it->HasSel) + { + if (it->itemText.selected(a)) + text += it->itemText.text(a); + } + else + { + text += it->itemText.text(a); + } + } + return PyString_FromString(text.toUtf8()); +} + +PyObject *scribus_gettext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + QString text = ""; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get text of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + + // collect all chars from a storytext + for (int a = 0; a < it->itemText.length(); a++) + { + if (it->HasSel) + { + if (it->itemText.selected(a)) + text += it->itemText.text(a); + } + else + { + text += it->itemText.text(a); + } + } // for + return PyString_FromString(text.toUtf8()); +} + +PyObject *scribus_setboxtext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Text; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Text, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *currItem = GetUniqueItem(QString::fromUtf8(Name)); + if (currItem == NULL) + return NULL; + if (!(currItem->asTextFrame()) && !(currItem->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text of non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + QString Daten = QString::fromUtf8(Text); + Daten.replace("\r\n", SpecialChars::PARSEP); + Daten.replace(QChar('\n') , SpecialChars::PARSEP); + PyMem_Free(Text); + currItem->itemText.clear(); + for (int a = 0; a < ScCore->primaryMainWindow()->doc->FrameItems.count(); ++a) + { + ScCore->primaryMainWindow()->doc->FrameItems.at(a)->ItemNr = a; + } + currItem->itemText.insertChars(0, Daten); + currItem->invalidateLayout(); + currItem->Dirty = false; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_inserttext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Text; + int pos; + if (!PyArg_ParseTuple(args, "esi|es", "utf-8", &Text, &pos, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot insert text into non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + QString Daten = QString::fromUtf8(Text); + Daten.replace("\r\n", SpecialChars::PARSEP); + Daten.replace(QChar('\n') , SpecialChars::PARSEP); + PyMem_Free(Text); + if ((pos < -1) || (pos > static_cast<int>(it->itemText.length()))) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Insert index out of bounds.","python error").toLocal8Bit().constData()); + return NULL; + } + if (pos == -1) + pos = it->itemText.length(); + it->itemText.insertChars(pos, Daten); + it->Dirty = true; + if (ScCore->primaryMainWindow()->doc->DoDrawing) + { +// FIXME adapt to Qt-4 painting style +// it->paintObj(); + it->Dirty = false; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setalign(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int alignment; + if (!PyArg_ParseTuple(args, "i|es", &alignment, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((alignment > 4) || (alignment < 0)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Alignment out of range. Use one of the scribus.ALIGN* constants.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text alignment on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->setNewAlignment(alignment); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setfontsize(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double size; + if (!PyArg_ParseTuple(args, "d|es", &size, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((size > 512) || (size < 1)) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Font size out of bounds - must be 1 <= size <= 512.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font size on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->doc->itemSelection_SetFontSize(qRound(size * 10.0)); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setfont(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Font = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Font, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!(i->asTextFrame()) && !(i->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set font on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (PrefsManager::instance()->appPrefs.AvailFonts.contains(QString::fromUtf8(Font))) + { + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->SetNewFont(QString::fromUtf8(Font)); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); + } + else + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Font not found.","python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setlinespace(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double w; + if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (w < 0.1) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Line space out of bounds, must be >= 0.1.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set line spacing on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->doc->itemSelection_SetLineSpacing(w); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); + +// i->setLineSpacing(w); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_settextdistances(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double l,r,t,b; + if (!PyArg_ParseTuple(args, "dddd|es", &l, &r, &t, &b, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (l < 0.0 || r < 0.0 || t < 0.0 || b < 0.0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Text distances out of bounds, must be positive.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text distances on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + i->setTextToFrameDist(ValueToPoint(l), ValueToPoint(r), ValueToPoint(t), ValueToPoint(b)); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject *scribus_setcolumngap(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double w; + if (!PyArg_ParseTuple(args, "d|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (w < 0.0) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Column gap out of bounds, must be positive.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set column gap on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + i->ColGap = ValueToPoint(w); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_setcolumns(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (w < 1) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Column count out of bounds, must be > 1.","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set number of columns on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + i->Cols = w; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_selecttext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int start, selcount; + if (!PyArg_ParseTuple(args, "ii|es", &start, &selcount, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (selcount == -1) + { + // user wants to select all after the start point -- CR + selcount = it->itemText.length() - start; + if (selcount < 0) + // user passed start that's > text in the frame + selcount = 0; + } + // cr 2005-01-18 fixed off-by-one with end bound that made selecting the last char impossible + if ((start < 0) || ((start + selcount) > static_cast<int>(it->itemText.length()))) + { + PyErr_SetString(PyExc_IndexError, QObject::tr("Selection index out of bounds", "python error").toLocal8Bit().constData()); + return NULL; + } + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot select text in a non-text frame", "python error").toLocal8Bit().constData()); + return NULL; + } + /* FIXME: not sure if we should make this check or not + if (start > ende) + { + PyErr_SetString(PyExc_ValueError, QString("Selection start > selection end").toLocal8Bit().constData()); + return NULL; + } + */ + it->itemText.deselectAll(); + if (selcount == 0) + { + it->HasSel = false; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; + } + it->itemText.select(start, selcount, true); + it->HasSel = true; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_deletetext(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot delete text from a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (it->HasSel) + dynamic_cast<PageItem_TextFrame*>(it)->deleteSelectedTextFromFrame(); + else + { + it->itemText.clear(); + for (int a = 0; a < ScCore->primaryMainWindow()->doc->FrameItems.count(); ++a) + { + ScCore->primaryMainWindow()->doc->FrameItems.at(a)->ItemNr = a; + } + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_settextfill(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text fill on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + else + { + for (int b = 0; b < it->itemText.length(); b++) + { + //FIXME: doc method + if (it->HasSel) + { + if (it->itemText.selected(b)) + it->itemText.item(b)->setFillColor(QString::fromUtf8(Color)); + } + else + it->itemText.item(b)->setFillColor(QString::fromUtf8(Color)); + } +// it->TxtFill = QString::fromUtf8(Color); + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_settextstroke(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + char *Color; + if (!PyArg_ParseTuple(args, "es|es", "utf-8", &Color, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && (it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text stroke on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + else + { + for (int b = 0; b < it->itemText.length(); b++) + { + //FIXME:NLS use document method for this + if (it->HasSel) + { + if (it->itemText.selected(b)) + it->itemText.item(b)->setStrokeColor(QString::fromUtf8(Color)); + } + else + it->itemText.item(b)->setStrokeColor(QString::fromUtf8(Color)); + } +// it->TxtStroke = QString::fromUtf8(Color); + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + + +PyObject *scribus_settextscalingh(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double sc; + if (!PyArg_ParseTuple(args, "d|es", &sc, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (sc < 10) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Character scaling out of bounds, must be >= 10","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set character scaling on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->doc->itemSelection_SetScaleH(qRound(sc * 10)); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); + + Py_RETURN_NONE; +} + + +PyObject *scribus_settextscalingv(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + double sc; + if (!PyArg_ParseTuple(args, "d|es", &sc, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (sc < 10) + { + PyErr_SetString(PyExc_ValueError, QObject::tr("Character scaling out of bounds, must be >= 10","python error").toLocal8Bit().constData()); + return NULL; + } + PageItem *i = GetUniqueItem(QString::fromUtf8(Name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set character scaling on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + + int Apm = ScCore->primaryMainWindow()->doc->appMode; + ScCore->primaryMainWindow()->doc->m_Selection->clear(); + ScCore->primaryMainWindow()->doc->m_Selection->addItem(i); + if (i->HasSel) + ScCore->primaryMainWindow()->doc->appMode = modeEdit; + ScCore->primaryMainWindow()->doc->itemSelection_SetScaleV(qRound(sc * 10)); + ScCore->primaryMainWindow()->doc->appMode = Apm; + ScCore->primaryMainWindow()->view->Deselect(); + + Py_RETURN_NONE; +} + + +PyObject *scribus_settextshade(PyObject* /* self */, PyObject* args) +{ + char *Name = const_cast<char*>(""); + int w; + if (!PyArg_ParseTuple(args, "i|es", &w, "utf-8", &Name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if ((w < 0) || (w > 100)) + { +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; + } + PageItem *it = GetUniqueItem(QString::fromUtf8(Name)); + if (it == NULL) + return NULL; + if (!(it->asTextFrame()) && !(it->asPathText())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set text shade on a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + else + { + //FIXME:NLS use document method for that + for (int b = 0; b < it->itemText.length(); ++b) + { + if (it->HasSel) + { + if (it->itemText.selected(b)) + it->itemText.item(b)->setFillShade(w); + } + else + it->itemText.item(b)->setFillShade(w); + } +// it->ShTxtFill = w; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_linktextframes(PyObject* /* self */, PyObject* args) +{ + char *name1; + char *name2; + + if (!PyArg_ParseTuple(args, "eses", "utf-8", &name1, "utf-8", &name2)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *fromitem = GetUniqueItem(QString::fromUtf8(name1)); + if (fromitem == NULL) + return NULL; + PageItem *toitem = GetUniqueItem(QString::fromUtf8(name2)); + if (toitem == NULL) + return NULL; + if (!(fromitem->asTextFrame()) || !(toitem->asTextFrame())) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only link text frames.","python error").toLocal8Bit().constData()); + return NULL; + } +/* if (toitem->itemText.length() > 0) + { + PyErr_SetString(ScribusException, QObject::tr("Target frame must be empty.","python error").toLocal8Bit().constData()); + return NULL; + }*/ + if (toitem->nextInChain() != 0) + { + PyErr_SetString(ScribusException, QObject::tr("Target frame links to another frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (toitem->prevInChain() != 0) + { + PyErr_SetString(ScribusException, QObject::tr("Target frame is linked to by another frame.","python error").toLocal8Bit().constData()); + return NULL; + } + if (toitem == fromitem) + { + PyErr_SetString(ScribusException, QObject::tr("Source and target are the same object.","python error").toLocal8Bit().constData()); + return NULL; + } + // references to the others boxes + fromitem->link(toitem); + ScCore->primaryMainWindow()->view->DrawNew(); + // enable 'save icon' stuff + ScCore->primaryMainWindow()->slotDocCh(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_unlinktextframes(PyObject* /* self */, PyObject* args) +{ + char *name; + if (!PyArg_ParseTuple(args, "es", "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if (!item->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot unlink a non-text frame.","python error").toLocal8Bit().constData()); + return NULL; + } + // only linked + if (item->prevInChain() == 0) + { + PyErr_SetString(ScribusException, QObject::tr("Object is not a linked text frame, can't unlink.","python error").toLocal8Bit().constData()); + return NULL; + } +/* if (item->NextBox == 0) + { + PyErr_SetString(ScribusException, QObject::tr("Object the last frame in a series, can't unlink. Unlink the previous frame instead.","python error").toLocal8Bit().constData()); + return NULL; + } + */ +/* PageItem* nextbox = item->NextBox; + + while (nextbox != 0) + { + uint a = nextbox->itemText.count(); + for (uint s=0; s<a; ++s) + item->itemText.append(nextbox->itemText.take(0)); + nextbox = nextbox->NextBox; + } // while + uint a2 = item->itemText.count(); + for (uint s = 0; s < a2; ++s) + item->BackBox->itemText.append(item->itemText.take(0)); +*/ + item->prevInChain()->unlink(); + // enable 'save icon' stuff + ScCore->primaryMainWindow()->slotDocCh(); + ScCore->primaryMainWindow()->view->DrawNew(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/* + * Convert the selected text frame to outlines. + * + * 2004-09-07 (Craig Ringer) + * 2004-09-14 pv frame type, optional frame name param + */ +PyObject *scribus_tracetext(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if (!item->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot convert a non-text frame to outlines.","python error").toLocal8Bit().constData()); + return NULL; + } + if (item->invalid) + item->layout(); + ScCore->primaryMainWindow()->view->Deselect(true); + ScCore->primaryMainWindow()->view->SelectItemNr(item->ItemNr); + ScCore->primaryMainWindow()->view->TextToPath(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_istextoverflowing(PyObject * self, PyObject* args, PyObject* kw) +{ + char *name = const_cast<char*>(""); + bool nolinks = false; + char *kwargs[] = {const_cast<char*>("name"), const_cast<char*>("nolinks"), NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "|esi", kwargs, "utf-8", &name, &nolinks)) + return NULL; + if(!checkHaveDocument()) + return NULL; + PageItem *item = GetUniqueItem(QString::fromUtf8(name)); + if (item == NULL) + return NULL; + if (!item->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Only text frames can be checked for overflowing", "python error").toLocal8Bit().constData()); + return NULL; + } + /* original solution + if (item->itemText.count() > item->MaxChars) + return PyBool_FromLong(static_cast<long>(true)); + return PyBool_FromLong(static_cast<long>(false)); */ + /* + uint firstFrame = 0; + if (nolinks) + firstFrame = item->itemText.count(); + uint chars = item->itemText.count(); + uint maxchars = item->MaxChars; + while (item->NextBox != 0) { + item = item->NextBox; + chars += item->itemText.count(); + maxchars += item->MaxChars; + } + // no overrun + if (nolinks) + return PyInt_FromLong(maxchars - firstFrame); + + if (maxchars > chars) + return PyInt_FromLong(0); + // number of overrunning letters + return PyInt_FromLong(static_cast<long>(chars - maxchars)); + */ + // refresh overflow information + item->invalidateLayout(); + item->layout(); + return PyInt_FromLong(static_cast<long>(item->frameOverflows())); +} + +/* + * Does hyphenation on the given text frame. + * 08.12.2007: Joachim Neu + */ +PyObject *scribus_hyphenatetext(PyObject*, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if (!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only hyphenate text frame", "python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->docHyphenator->slotHyphenate(i); + return PyBool_FromLong(1); +} + +/* + * Does dehyphenation on the given text frame. + * 13.12.2007: Joachim Neu + */ +PyObject *scribus_dehyphenatetext(PyObject*, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if (!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Can only dehyphenate text frame", "python error").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->doc->docHyphenator->slotDeHyphenate(i); + return PyBool_FromLong(1); +} + +PyObject *scribus_setpdfbookmark(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + bool toggle; + if (!PyArg_ParseTuple(args, "b|es", &toggle, "utf-8", &name)) + return NULL; + if (!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Can't set bookmark on a non-text frame", "python error").toLocal8Bit().constData()); + return NULL; + } + if (i->isBookmark == toggle) + { +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; + } + if (toggle) + { + i->setIsAnnotation(false); + ScCore->primaryMainWindow()->AddBookMark(i); + } + else + ScCore->primaryMainWindow()->DelBookMark(i); + i->isBookmark = toggle; +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_ispdfbookmark(PyObject* /* self */, PyObject* args) +{ + char *name = const_cast<char*>(""); + if (!PyArg_ParseTuple(args, "|es", "utf-8", &name)) + return NULL; + if (!checkHaveDocument()) + return NULL; + PageItem *i = GetUniqueItem(QString::fromUtf8(name)); + if (i == NULL) + return NULL; + if (!i->asTextFrame()) + { + PyErr_SetString(WrongFrameTypeError, QObject::tr("Can't get info from a non-text frame", "python error").toLocal8Bit().constData()); + return NULL; + } + if (i->isBookmark) + return PyBool_FromLong(1); + return PyBool_FromLong(0); +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void cmdtextdocwarnings() +{ + QStringList s; + s << scribus_getfontsize__doc__ << scribus_getfont__doc__ + << scribus_gettextlines__doc__ << scribus_gettextsize__doc__ + << scribus_getframetext__doc__ << scribus_gettext__doc__ + << scribus_getlinespace__doc__ << scribus_getcolumngap__doc__ + << scribus_getcolumns__doc__ << scribus_setboxtext__doc__ + << scribus_inserttext__doc__ << scribus_setfont__doc__ + << scribus_setfontsize__doc__ << scribus_setlinespace__doc__ + << scribus_setcolumngap__doc__ << scribus_setcolumns__doc__ + << scribus_setalign__doc__ << scribus_selecttext__doc__ + << scribus_deletetext__doc__ << scribus_settextfill__doc__ + << scribus_settextstroke__doc__ << scribus_settextshade__doc__ + << scribus_linktextframes__doc__ << scribus_unlinktextframes__doc__ + << scribus_tracetext__doc__ << scribus_istextoverflowing__doc__ + << scribus_setpdfbookmark__doc__ << scribus_ispdfbookmark__doc__ + << scribus_hyphenatetext__doc__ << scribus_dehyphenatetext__doc__ + << scribus_gettextdistances__doc__ << scribus_settextdistances__doc__ + << scribus_settextscalingh__doc__ << scribus_settextscalingv__doc__; +} diff --git a/scribus/plugins/scriptplugin/cmdtext.h b/scribus/plugins/scriptplugin/cmdtext.h new file mode 100644 index 0000000..1a9a142 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdtext.h @@ -0,0 +1,430 @@ +/* +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. +*/ +#ifndef CMDTEXT_H +#define CMDTEXT_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +/*! Text frame handling */ + +/*! docstring */ +PyDoc_STRVAR(scribus_getfontsize__doc__, +QT_TR_NOOP("getFontSize([\"name\"]) -> float\n\ +\n\ +Returns the font size in points for the text frame \"name\". If this text\n\ +frame has some text selected the value assigned to the first character of\n\ +the selection is returned.\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Get font size */ +PyObject *scribus_getfontsize(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getfont__doc__, +QT_TR_NOOP("getFont([\"name\"]) -> string\n\ +\n\ +Returns the font name for the text frame \"name\". If this text frame\n\ +has some text selected the value assigned to the first character\n\ +of the selection is returned. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Get font */ +PyObject *scribus_getfont(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_gettextsize__doc__, +QT_TR_NOOP("getTextLength([\"name\"]) -> integer\n\ +\n\ +Returns the length of the text in the text frame \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Get text size */ +PyObject *scribus_gettextsize(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_gettextlines__doc__, +QT_TR_NOOP("getTextLines([\"name\"]) -> integer\n\ +\n\ +Returns the number of lines of the text in the text frame \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Get text lines */ +PyObject *scribus_gettextlines(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getframetext__doc__, +QT_TR_NOOP("getText([\"name\"]) -> string\n\ +\n\ +Returns the text of the text frame \"name\". If this text frame has some text\n\ +selected, the selected text is returned. All text in the frame, not just\n\ +currently visible text, is returned. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Get frame text */ +PyObject *scribus_getframetext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_gettext__doc__, +QT_TR_NOOP("getAllText([\"name\"]) -> string\n\ +\n\ +Returns the text of the text frame \"name\" and of all text frames which are\n\ +linked with this frame. If this textframe has some text selected, the selected\n\ +text is returned. If \"name\" is not given the currently selected item is\n\ +used.\n\ +")); +/*! Get all text */ +PyObject *scribus_gettext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getlinespace__doc__, +QT_TR_NOOP("getLineSpacing([\"name\"]) -> float\n\ +\n\ +Returns the line spacing (\"leading\") of the text frame \"name\" expressed in\n\ +points. If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Get line space */ +PyObject *scribus_getlinespace(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_gettextdistances__doc__, +QT_TR_NOOP("getTextDistances([\"name\"]) -> tuple\n\ +\n\ +Returns the text distances of the text frame \"name\" expressed in points. The\n\ +distances are returned as a tuple like (left, right, top, bottom). If \"name\"\n\ +is not given the currently selected item is used.\n\ +")); +/*! Get text distances */ +PyObject *scribus_gettextdistances(PyObject */*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getcolumngap__doc__, +QT_TR_NOOP("getColumnGap([\"name\"]) -> float\n\ +\n\ +Returns the column gap size of the text frame \"name\" expressed in points. If\n\ +\"name\" is not given the currently selected item is used.\n\ +")); +/*! Get column gap */ +PyObject *scribus_getcolumngap(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_getcolumns__doc__, +QT_TR_NOOP("getColumns([\"name\"]) -> integer\n\ +\n\ +Gets the number of columns of the text frame \"name\". If \"name\" is not\n\ +given the currently selected item is used.\n\ +")); +/*! Get columns */ +PyObject *scribus_getcolumns(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setboxtext__doc__, +QT_TR_NOOP("setText(\"text\", [\"name\"])\n\ +\n\ +Sets the text of the text frame \"name\" to the text of the string \"text\".\n\ +Text must be UTF8 encoded - use e.g. unicode(text, 'iso-8859-2'). See the FAQ\n\ +for more details. If \"name\" is not given the currently selected item is\n\ +used.\n\ +")); +/*! Set text */ +PyObject *scribus_setboxtext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_inserttext__doc__, +QT_TR_NOOP("insertText(\"text\", pos, [\"name\"])\n\ +\n\ +Inserts the text \"text\" at the position \"pos\" into the text frame \"name\".\n\ +Text must be UTF encoded (see setText() as reference) The first character has an\n\ +index of 0. Inserting text at position -1 appends it to the frame. If \"name\" is\n\ +not given the currently selected Item is used.\n\ +\n\ +May throw IndexError for an insertion out of bounds.\n\ +")); +/*! Insert text */ +PyObject *scribus_inserttext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfont__doc__, +QT_TR_NOOP("setFont(\"font\", [\"name\"])\n\ +\n\ +Sets the font of the text frame \"name\" to \"font\". If there is some text\n\ +selected only the selected text is changed. If \"name\" is not given the\n\ +currently selected item is used.\n\ +\n\ +May throw ValueError if the font cannot be found.\n\ +")); +/*! Set font */ +PyObject *scribus_setfont(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setfontsize__doc__, +QT_TR_NOOP("setFontSize(size, [\"name\"])\n\ +\n\ +Sets the font size of the text frame \"name\" to \"size\". \"size\" is treated\n\ +as a value in points. If there is some text selected only the selected text is\n\ +changed. \"size\" must be in the range 1 to 512. If \"name\" is not given the\n\ +currently selected item is used.\n\ +\n\ +May throw ValueError for a font size that's out of bounds.\n\ +")); +/*! Set font size */ +PyObject *scribus_setfontsize(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setlinespace__doc__, +QT_TR_NOOP("setLineSpacing(size, [\"name\"])\n\ +\n\ +Sets the line spacing (\"leading\") of the text frame \"name\" to \"size\".\n\ +\"size\" is a value in points. If \"name\" is not given the currently selected\n\ +item is used.\n\ +\n\ +May throw ValueError if the line spacing is out of bounds.\n\ +")); +/*! Set line space */ +PyObject *scribus_setlinespace(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextdistances__doc__, +QT_TR_NOOP("setTextDistances(left, right, top, bottom, [\"name\"])\n\ +\n\ +Sets the text distances of the text frame \"name\" to the values \"left\"\n\ +\"right\", \"top\" and \"bottom\". If \"name\" is not given the currently\n\ +selected item is used.\n\ +\n\ +May throw ValueError if any of the distances are out of bounds (must be positive).\n\ +")); +/*! Set text distances */ +PyObject *scribus_settextdistances(PyObject */*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setcolumngap__doc__, +QT_TR_NOOP("setColumnGap(size, [\"name\"])\n\ +\n\ +Sets the column gap of the text frame \"name\" to the value \"size\". If\n\ +\"name\" is not given the currently selected item is used.\n\ +\n\ +May throw ValueError if the column gap is out of bounds (must be positive).\n\ +")); +/*! Set column gap */ +PyObject *scribus_setcolumngap(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setcolumns__doc__, +QT_TR_NOOP("setColumns(nr, [\"name\"])\n\ +\n\ +Sets the number of columns of the text frame \"name\" to the integer \"nr\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May throw ValueError if number of columns is not at least one.\n\ +")); +/*! Set columns */ +PyObject *scribus_setcolumns(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setalign__doc__, +QT_TR_NOOP("setTextAlignment(align, [\"name\"])\n\ +\n\ +Sets the text alignment of the text frame \"name\" to the specified alignment.\n\ +If \"name\" is not given the currently selected item is used. \"align\" should\n\ +be one of the ALIGN_ constants defined in this module - see dir(scribus).\n\ +\n\ +May throw ValueError for an invalid alignment constant.\n\ +")); +/*! Set alignt */ +PyObject *scribus_setalign(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_selecttext__doc__, +QT_TR_NOOP("selectText(start, count, [\"name\"])\n\ +\n\ +Selects \"count\" characters of text in the text frame \"name\" starting from the\n\ +character \"start\". Character counting starts at 0. If \"count\" is zero, any\n\ +text selection will be cleared. If \"name\" is not given the currently\n\ +selected item is used.\n\ +\n\ +May throw IndexError if the selection is outside the bounds of the text.\n\ +")); +/*! Select text */ +PyObject *scribus_selecttext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_deletetext__doc__, +QT_TR_NOOP("deleteText([\"name\"])\n\ +\n\ +Deletes any text in the text frame \"name\". If there is some text selected,\n\ +only the selected text will be deleted. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Delete text */ +PyObject *scribus_deletetext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextfill__doc__, +QT_TR_NOOP("setTextColor(\"color\", [\"name\"])\n\ +\n\ +Sets the text color of the text frame \"name\" to the color \"color\". If there\n\ +is some text selected only the selected text is changed. If \"name\" is not\n\ +given the currently selected item is used.\n\ +")); +/*! Set text fill */ +PyObject *scribus_settextfill(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextstroke__doc__, +QT_TR_NOOP("setTextStroke(\"color\", [\"name\"])\n\ +\n\ +Set \"color\" of the text stroke. If \"name\" is not given the currently\n\ +selected item is used.\n\ +")); +/*! Set text stroke */ +PyObject *scribus_settextstroke(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextscalingv__doc__, +QT_TR_NOOP("setTextScalingV(scale, [\"name\"])\n\ +\n\ +Sets the vertical character scaling of the object \"name\" to \"scale\" in percent.\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set text shde */ +PyObject *scribus_settextscalingv(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextscalingh__doc__, +QT_TR_NOOP("setTextScalingH(scale, [\"name\"])\n\ +\n\ +Sets the horizontal character scaling of the object \"name\" to \"scale\" in percent.\n\ +If \"name\" is not given the currently selected item is used.\n\ +")); +/*! Set text shde */ +PyObject *scribus_settextscalingh(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_settextshade__doc__, +QT_TR_NOOP("setTextShade(shade, [\"name\"])\n\ +\n\ +Sets the shading of the text color of the object \"name\" to \"shade\". If\n\ +there is some text selected only the selected text is changed. \"shade\" must\n\ +be an integer value in the range from 0 (lightest) to 100 (full color\n\ +intensity). If \"name\" is not given the currently selected item is\n\ +used.\n\ +")); +/*! Set text shde */ +PyObject *scribus_settextshade(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_linktextframes__doc__, +QT_TR_NOOP("linkTextFrames(\"fromname\", \"toname\")\n\ +\n\ +Link two text frames. The frame named \"fromname\" is linked to the\n\ +frame named \"toname\". The target frame must be an empty text frame\n\ +and must not link to or be linked from any other frames already.\n\ +\n\ +May throw ScribusException if linking rules are violated.\n\ +")); +/** + Link text frames via Scripter. + 02/22/04 (petr vanek) + TODO: PDF bookmarks handling + */ +PyObject *scribus_linktextframes(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_unlinktextframes__doc__, +QT_TR_NOOP("unlinkTextFrames(\"name\")\n\ +\n\ +Remove the specified (named) object from the text frame flow/linkage. If the\n\ +frame was in the middle of a chain, the previous and next frames will be\n\ +connected, eg 'a->b->c' becomes 'a->c' when you unlinkTextFrames(b)'\n\ +\n\ +May throw ScribusException if linking rules are violated.\n\ +")); +/** + (Un)Link text frames via Scripter. + 02/22/04 (petr vanek) + TODO: PDF bookmarks handling + */ +PyObject *scribus_unlinktextframes(PyObject * self, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_tracetext__doc__, +QT_TR_NOOP("traceText([\"name\"])\n\ +\n\ +Convert the text frame \"name\" to outlines. If \"name\" is not given the\n\ +currently selected item is used.")); +/** + Trace text frames via Scripter. + 2004-09-07 (Craig Ringer) +*/ +PyObject *scribus_tracetext(PyObject * self, PyObject* args); + +PyDoc_STRVAR(scribus_istextoverflowing__doc__, +QT_TR_NOOP("textOverflows([\"name\", nolinks]) -> integer\n\ +\n\ +Returns the actual number of overflowing characters in text frame \"name\".\n\ +If is nolinks set to non zero value it takes only one frame - it doesn't\n\ +use text frame linking. Without this parameter it search all linking chain.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not an text frame\n")); +/** Check if is the text frame overflowind or not + 2005-02-04 petr vanek + */ +PyObject *scribus_istextoverflowing(PyObject * self, PyObject* args, PyObject* kw); + +PyDoc_STRVAR(scribus_hyphenatetext__doc__, +QT_TR_NOOP("hyphenateText([\"name\"]) -> bool\n\ +\n\ +Does hyphenation on text frame \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not a text frame\n\ +")); +/* + Does hyphenation on the given text frame + 08.12.2007: Joachim Neu +*/ +PyObject *scribus_hyphenatetext(PyObject *, PyObject* args); + +PyDoc_STRVAR(scribus_dehyphenatetext__doc__, +QT_TR_NOOP("dehyphenateText([\"name\"]) -> bool\n\ +\n\ +Does dehyphenation on text frame \"name\".\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not a text frame\n\ +")); +/* + Does dehyphenation on the given text frame + 13.12.2007: Joachim Neu +*/ +PyObject *scribus_dehyphenatetext(PyObject *, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setpdfbookmark__doc__, +QT_TR_NOOP("setPDFBookmark(\"toggle\", [\"name\"])\n\ +\n\ +Sets whether (toggle = 1) the text frame \"name\" is a bookmark nor not.\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not a text frame\n\ +")); +/*! Set PDF bookmark */ +PyObject *scribus_setpdfbookmark(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_ispdfbookmark__doc__, + QT_TR_NOOP("isPDFBookmark([\"name\"]) -> bool\n\ +\n\ +Returns true if the text frame \"name\" is a PDF bookmark.\n\ +If \"name\" is not given the currently selected item is used.\n\ +\n\ +May raise WrongFrameTypeError if the target frame is not a text frame\n\ +")); +/*! Is PDF bookmark? */ +PyObject *scribus_ispdfbookmark(PyObject * /*self*/, PyObject* args); + +#endif diff --git a/scribus/plugins/scriptplugin/cmdutil.cpp b/scribus/plugins/scriptplugin/cmdutil.cpp new file mode 100644 index 0000000..ce8cfa0 --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdutil.cpp @@ -0,0 +1,231 @@ +/* +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. +*/ +#include "cmdutil.h" +#include "units.h" +#include "page.h" +#include "scribuscore.h" +#include "selection.h" + +ScribusMainWindow* Carrier; +ScribusDoc* doc; + +/// Convert a value in points to a value in the current document units +double PointToValue(double Val) +{ + return pts2value(Val, ScCore->primaryMainWindow()->doc->unitIndex()); +} + +/// Convert a value in the current document units to a value in points +double ValueToPoint(double Val) +{ + return value2pts(Val, ScCore->primaryMainWindow()->doc->unitIndex()); +} + +/// Convert an X co-ordinate part in page units to a document co-ordinate +/// in system units. +double pageUnitXToDocX(double pageUnitX) +{ + return ValueToPoint(pageUnitX) + ScCore->primaryMainWindow()->doc->currentPage()->xOffset(); +} + +// Convert doc units to page units +double docUnitXToPageX(double pageUnitX) +{ + return PointToValue(pageUnitX - ScCore->primaryMainWindow()->doc->currentPage()->xOffset()); +} + +/// Convert a Y co-ordinate part in page units to a document co-ordinate +/// in system units. The document co-ordinates have their origin somewere +/// up and left of the first page, where page co-ordinates have their +/// origin on the top left of the current page. +double pageUnitYToDocY(double pageUnitY) +{ + return ValueToPoint(pageUnitY) + ScCore->primaryMainWindow()->doc->currentPage()->yOffset(); +} + +double docUnitYToPageY(double pageUnitY) +{ + return PointToValue(pageUnitY - ScCore->primaryMainWindow()->doc->currentPage()->yOffset()); +} + +int GetItem(QString Name) +{ + if (!Name.isEmpty()) + { + for (int a = 0; a < ScCore->primaryMainWindow()->doc->Items->count(); a++) + { + if (ScCore->primaryMainWindow()->doc->Items->at(a)->itemName() == Name) + return static_cast<int>(a); + } + } + else + { + if (ScCore->primaryMainWindow()->doc->m_Selection->count() != 0) + return ScCore->primaryMainWindow()->doc->m_Selection->itemAt(0)->ItemNr; + } + return -1; +} + +void ReplaceColor(QString col, QString rep) +{ + QColor tmpc; + for (int c = 0; c < ScCore->primaryMainWindow()->doc->Items->count(); c++) + { + PageItem *ite = ScCore->primaryMainWindow()->doc->Items->at(c); + if (ite->itemType() == PageItem::TextFrame) + { + for (int d = 0; d < ite->itemText.length(); d++) + { + //FIXME:NLS that should work on runs + if (col == ite->itemText.charStyle(d).fillColor()) + ite->itemText.item(d)->setFillColor(rep); + if (col == ite->itemText.charStyle(d).strokeColor()) + ite->itemText.item(d)->setStrokeColor(rep); + } + } + if (col == ite->fillColor()) + ite->setFillColor(rep); + if (col == ite->lineColor()) + ite->setLineColor(rep); + QList<VColorStop*> cstops = ite->fill_gradient.colorStops(); + for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst) + { + if (col == cstops.at(cst)->name) + { + ite->SetQColor(&tmpc, rep, cstops.at(cst)->shade); + cstops.at(cst)->color = tmpc; + cstops.at(cst)->name = rep; + } + } + } + for (int c = 0; c < ScCore->primaryMainWindow()->doc->MasterItems.count(); c++) + { + PageItem *ite = ScCore->primaryMainWindow()->doc->MasterItems.at(c); + if (ite->itemType() == PageItem::TextFrame) + { + for (int d = 0; d < ite->itemText.length(); d++) + { + //FIXME: NLS this should work on runs + if (col == ite->itemText.charStyle(d).fillColor()) + ite->itemText.item(d)->setFillColor(rep); + if (col == ite->itemText.charStyle(d).strokeColor()) + ite->itemText.item(d)->setStrokeColor(rep); + } + } + if (col == ite->fillColor()) + ite->setFillColor(rep); + if (col == ite->lineColor()) + ite->setLineColor(rep); + QList<VColorStop*> cstops = ite->fill_gradient.colorStops(); + for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst) + { + if (col == cstops.at(cst)->name) + { + ite->SetQColor(&tmpc, rep, cstops.at(cst)->shade); + cstops.at(cst)->color = tmpc; + cstops.at(cst)->name = rep; + } + } + } +} + +/* 04/07/10 returns selection if is not name specified pv */ +PageItem* GetUniqueItem(QString name) +{ + if (name.length()==0) + if (ScCore->primaryMainWindow()->doc->m_Selection->count() != 0) + return ScCore->primaryMainWindow()->doc->m_Selection->itemAt(0); + else + { + PyErr_SetString(NoValidObjectError, QString("Cannot use empty string for object name when there is no selection").toLocal8Bit().constData()); + return NULL; + } + else + return getPageItemByName(name); +} + +PageItem* getPageItemByName(QString name) +{ + if (name.length() == 0) + { + PyErr_SetString(PyExc_ValueError, QString("Cannot accept empty name for pageitem").toLocal8Bit().constData()); + return NULL; + } + for (int j = 0; j<ScCore->primaryMainWindow()->doc->Items->count(); j++) + { + if (name==ScCore->primaryMainWindow()->doc->Items->at(j)->itemName()) + return ScCore->primaryMainWindow()->doc->Items->at(j); + } // for items + PyErr_SetString(NoValidObjectError, QString("Object not found").toLocal8Bit().constData()); + return NULL; +} + + +/*! + * Checks to see if a pageItem named 'name' exists and return true + * if it does exist. Returns false if there is no such object, or + * if the empty string ("") is passed. + */ +bool ItemExists(QString name) +{ + if (name.length() == 0) + return false; + for (int j = 0; j<ScCore->primaryMainWindow()->doc->Items->count(); j++) + { + if (name==ScCore->primaryMainWindow()->doc->Items->at(j)->itemName()) + return true; + } // for items + return false; +} + +/*! + * Checks to see if there is a document open. + * If there is an open document, returns true. + * If there is no open document, sets a Python + * exception and returns false. + * 2004-10-27 Craig Ringer + */ +bool checkHaveDocument() +{ + if (ScCore->primaryMainWindow()->HaveDoc) + return true; + // Caller is required to check for false return from this function + // and return NULL. + PyErr_SetString(NoDocOpenError, QString("Command does not make sense without an open document").toLocal8Bit().constData()); + return false; +} + +QStringList getSelectedItemsByName() +{ + /* + QStringList names; + QPtrListIterator<PageItem> it(ScCore->primaryMainWindow()->view->SelItem); + for ( ; it.current() != 0 ; ++it) + names.append(it.current()->itemName()); + return names; + */ + return ScCore->primaryMainWindow()->doc->m_Selection->getSelectedItemsByName(); +} + +bool setSelectedItemsByName(QStringList& itemNames) +{ + ScCore->primaryMainWindow()->view->Deselect(); + // For each named item + for (QStringList::Iterator it = itemNames.begin() ; it != itemNames.end() ; it++) + { + // Search for the named item + PageItem* item = 0; + for (int j = 0; j < ScCore->primaryMainWindow()->doc->Items->count(); j++) + if (*it == ScCore->primaryMainWindow()->doc->Items->at(j)->itemName()) + item = ScCore->primaryMainWindow()->doc->Items->at(j); + if (!item) + return false; + // and select it + ScCore->primaryMainWindow()->view->SelectItemNr(item->ItemNr); + } + return true; +} diff --git a/scribus/plugins/scriptplugin/cmdutil.h b/scribus/plugins/scriptplugin/cmdutil.h new file mode 100644 index 0000000..f15072f --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdutil.h @@ -0,0 +1,71 @@ +/* +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. +*/ +#ifndef CMDUTIL_H +#define CMDUTIL_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +double PointToValue(double Val); +double ValueToPoint(double Val); + +/*! \brief Convert an X co-ordinate part in page units to a document co-ordinate in system units. +*/ +double pageUnitXToDocX(double pageUnitX); +/// \brief Doc units -> page-relative units +double docUnitXToPageX(double pageUnitX); + +/*! \brief Convert a Y co-ordinate part in page units to a document co-ordinate +in system units. The document co-ordinates have their origin somewere +up and left of the first page, where page co-ordinates have their +origin on the top left of the current page. */ +double pageUnitYToDocY(double pageUnitY); +/// \brief Doc units -> page-relative units +double docUnitYToPageY(double pageUnitY); + +int GetItem(QString Name); +void ReplaceColor(QString col, QString rep); +/*! + * @brief Returns named PageItem, or selection if name '', or exception and NULL if no item. + * + * Returns a pointer to a PageItem by looking it up by name - page independent. + * If `name' is empty, returns selected item. If the named item is not found, + * or `name' is empty and no item is selected, sets an exception and returns + * NULL. + * + * @author 03/10/2004 petr vanek + * @author 05/02/02 Craig Ringer + */ +PageItem* GetUniqueItem(QString name); + +/*! + * @brief Returns named PageItem, or exception and NULL if not found. + * + * @author 03/10/2004 Petr Vanek + * @author 05/02/02 Craig Ringer + */ +PageItem* getPageItemByName(QString name); + +// 2004-10-27 Craig Ringer see cmdutil.cpp for description +bool checkHaveDocument(); + +// 2004-11-12 Craig Ringer see cmdutil.cpp for description +bool ItemExists(QString name); + +/*! + * @brief Returns a list of the names of all selected PageItems + */ +QStringList getSelectedItemsByName(); +/*! + * @brief Replaces the current selection by selecting all the items named in the passed QStringList + * + * Returns false if one or more items can't be selected, true if all were selected. + * Selection state is undefined on failure. + */ +bool setSelectedItemsByName(QStringList& itemNames); + +#endif diff --git a/scribus/plugins/scriptplugin/cmdvar.h b/scribus/plugins/scriptplugin/cmdvar.h new file mode 100644 index 0000000..8f9a12d --- /dev/null +++ b/scribus/plugins/scriptplugin/cmdvar.h @@ -0,0 +1,81 @@ +/* +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. +*/ +#ifndef CMDVAR_H +#define CMDVAR_H + + +#include "scconfig.h" + +// PV - commented out - why it was here? +// #if defined(_XOPEN_SOURCE) +// #define SCRIBUS_XOPEN_SOURCE +// #undef _XOPEN_SOURCE +// #endif + +#if defined(HAVE_BOOST_PYTHON) +#include <boost/python.hpp> +#else +#include <Python.h> +#endif + +#ifndef Py_RETURN_NONE + #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#ifndef Py_RETURN_TRUE + #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif + +// PV - commented out - why it was here? +// #if defined(SCRIBUS_XOPEN_SOURCE) +// #define _XOPEN_SOURCE +// #undef SCRIBUS_XOPEN_SOURCE +// #endif + +#include <QString> + +#include "scribus.h" + + +class ScripterCore; + +// Globals for testing Qt properties and probably other more intresting future +// uses. +/** @brief A PyCObject containing a pointer to qApp */ +extern PyObject* wrappedQApp; +/** @brief A PyCObject containing a pointer to the main window ('Carrier') */ +extern PyObject* wrappedMainWindow; + +/** @brief A pointer to the ScripterCore instance */ +extern ScripterCore* scripterCore; + +/** @brief Initialize the 'scribus' Python module in the currently active interpreter */ +extern "C" void initscribus(ScribusMainWindow *pl); + +/* Exceptions */ +/*! Common scribus Exception */ +extern PyObject* ScribusException; +/*! Exception raised when no document opened - see checkHaveDocument() in cmdutil.cpp */ +extern PyObject* NoDocOpenError; +/*! Exception raised when an operation is performed on a frame type that doesn't support it.*/ +extern PyObject* WrongFrameTypeError; +/*! Exception raised by GetUniqueItem when it can't find a valid frame or a suitable selection to use. */ +extern PyObject* NoValidObjectError; +/*! A general exception for when objects such as colors and fonts cannot be found. */ +extern PyObject* NotFoundError; +/*! Exception raised when the user tries to create an object with the same name as one that already exists */ +extern PyObject* NameExistsError; + +/*! A helper variable for better string comparsions to reduce warnings: +"warning: comparison with string literal results in unspecified behaviour" +what is criticised by some linux distributors */ +#ifndef EMPTY_STRING +#define EMPTY_STRING const_cast<char*>("") +#endif + +#endif + diff --git a/scribus/plugins/scriptplugin/guiapp.cpp b/scribus/plugins/scriptplugin/guiapp.cpp new file mode 100644 index 0000000..518d122 --- /dev/null +++ b/scribus/plugins/scriptplugin/guiapp.cpp @@ -0,0 +1,141 @@ +/* +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. +*/ +#include "guiapp.h" +#include "cmdutil.h" +#include "scribuscore.h" +#include <QString> +#include <QCursor> + +PyObject *scribus_messagebartext(PyObject* /* self */, PyObject* args) +{ + char *aText; + if (!PyArg_ParseTuple(args, "es", "utf-8", &aText)) + return NULL; + ScCore->primaryMainWindow()->setStatusBarInfoText(QString::fromUtf8(aText)); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_progressreset(PyObject* /* self */) +{ + ScCore->primaryMainWindow()->mainWindowProgressBar->reset(); + qApp->processEvents(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_progresssettotalsteps(PyObject* /* self */, PyObject* args) +{ + int steps; + if (!PyArg_ParseTuple(args, "i", &steps)) + return NULL; + ScCore->primaryMainWindow()->mainWindowProgressBar->setMaximum(steps); + ScCore->primaryMainWindow()->mainWindowProgressBar->setValue(0); + qApp->processEvents(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_progresssetprogress(PyObject* /* self */, PyObject* args) +{ + int position; + if (!PyArg_ParseTuple(args, "i", &position)) + return NULL; + if (position > ScCore->primaryMainWindow()->mainWindowProgressBar->maximum()) + { + PyErr_SetString(PyExc_ValueError, QString("Tried to set progress > maximum progress").toLocal8Bit().constData()); + return NULL; + } + ScCore->primaryMainWindow()->mainWindowProgressBar->setValue(position); + qApp->processEvents(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + + +PyObject *scribus_setcursor(PyObject* /* self */, PyObject* args) +{ + char *aCursor; + qDebug("WARNING! SetCursor() is not stable!"); + if (!PyArg_ParseTuple(args, "es", "ascii", &aCursor)) + return NULL; + if (strcmp(aCursor, "wait") == 0) + qApp->changeOverrideCursor(Qt::WaitCursor); +// else +// qApp->restoreOverrideCursor(); +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_docchanged(PyObject* /* self */, PyObject* args) +{ + int aValue; + if (!PyArg_ParseTuple(args, "i", &aValue)) + return NULL; + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->slotDocCh(static_cast<bool>(aValue)); + /* + if (aValue>0) + ScCore->primaryMainWindow()->slotDocCh(true); + else + ScCore->primaryMainWindow()->slotDocCh(false);*/ +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_zoomdocument(PyObject* /* self */, PyObject* args) +{ + double zoomFactor; + if (!PyArg_ParseTuple(args, "d", &zoomFactor)) + return NULL; + if(!checkHaveDocument()) + return NULL; + if (zoomFactor > 0.0 || zoomFactor == -100.0) + ScCore->primaryMainWindow()->slotZoom(zoomFactor); + else + { + PyErr_SetString(PyExc_ValueError, QString("The zoom factor should be greater than 0.0 or equal to -100.0. See help(zoomFactor).").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/* + * Gives the possibility to scroll the document. + * 13.12.2007: Joachim Neu + */ +PyObject *scribus_scrolldocument(PyObject*,PyObject* args) +{ + int moveX = 0, moveY = 0; + if(!PyArg_ParseTuple(args, "ii", &moveX, &moveY)) + return NULL; + if(!checkHaveDocument()) + return NULL; + ScCore->primaryMainWindow()->view->scrollBy(moveX,moveY); + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void guiappdocwarnings() +{ + QStringList s; + s << scribus_messagebartext__doc__ << scribus_progressreset__doc__ + << scribus_progresssettotalsteps__doc__ << scribus_progresssetprogress__doc__ + << scribus_setcursor__doc__ << scribus_docchanged__doc__ + << scribus_zoomdocument__doc__ << scribus_scrolldocument__doc__; +} diff --git a/scribus/plugins/scriptplugin/guiapp.h b/scribus/plugins/scriptplugin/guiapp.h new file mode 100644 index 0000000..aa6acbb --- /dev/null +++ b/scribus/plugins/scriptplugin/guiapp.h @@ -0,0 +1,113 @@ +/* +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. +*/ +#ifndef GUIAPP_H +#define GUIAPP_H + +// Brings in <Python.h> first +#include "cmdvar.h" + +/*! Scribus GUI tool */ + +/*! docstring */ +PyDoc_STRVAR(scribus_messagebartext__doc__, +QT_TR_NOOP("messagebarText(\"string\")\n\ +\n\ +Writes the \"string\" into the Scribus message bar (status line). The text\n\ +must be UTF8 encoded or 'unicode' string(recommended).\n\ +")); +/** +Changes the status bar string. +(Petr Vanek 02/19/04) +*/ +PyObject *scribus_messagebartext(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_progressreset__doc__, +QT_TR_NOOP("progressReset()\n\ +\n\ +Cleans up the Scribus progress bar previous settings. It is called before the\n\ +new progress bar use. See progressSet.\n\ +")); +/* +Progressbar handling +(Petr Vanek 02/19/04) +*/ +PyObject *scribus_progressreset(PyObject * /*self*/); + +/*! docstring */ +PyDoc_STRVAR(scribus_progresssettotalsteps__doc__, +QT_TR_NOOP("progressTotal(max)\n\ +\n\ +Sets the progress bar's maximum steps value to the specified number.\n\ +See progressSet.\n\ +")); +PyObject *scribus_progresssettotalsteps(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_progresssetprogress__doc__, +QT_TR_NOOP("progressSet(nr)\n\ +\n\ +Set the progress bar position to \"nr\", a value relative to the previously set\n\ +progressTotal. The progress bar uses the concept of steps; you give it the\n\ +total number of steps and the number of steps completed so far and it will\n\ +display the percentage of steps that have been completed. You can specify the\n\ +total number of steps with progressTotal(). The current number of steps is set\n\ +with progressSet(). The progress bar can be rewound to the beginning with\n\ +progressReset(). [based on info taken from Trolltech's Qt docs]\n\ +")); +PyObject *scribus_progresssetprogress(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_setcursor__doc__, +QT_TR_NOOP("setCursor()\n\ +\n\ +[UNSUPPORTED!] This might break things, so steer clear for now.\n\ +")); +/** +Cursor handling +(Petr Vanek 02/19/04) +*/ +PyObject *scribus_setcursor(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_docchanged__doc__, +QT_TR_NOOP("docChanged(bool)\n\ +\n\ +Enable/disable save icon in the Scribus icon bar and the Save menu item. It's\n\ +useful to call this procedure when you're changing the document, because Scribus\n\ +won't automatically notice when you change the document using a script.\n\ +")); +/** +Enable/disable save icon +(Petr Vanek 02/20/04) +*/ +PyObject *scribus_docchanged(PyObject * /*self*/, PyObject* args); + +PyDoc_STRVAR(scribus_zoomdocument__doc__, +QT_TR_NOOP("zoomDocument(double)\n\ +\n\ +Zoom the document in main GUI window. Actions have whole number\n\ +values like 20.0, 100.0, etc. Zoom to Fit uses -100 as a marker.\n\ +")); +/** +Zooming the document +\author Petr Vanek <petr@yarpen.cz> +*/ +PyObject *scribus_zoomdocument(PyObject * /*self*/, PyObject* args); + +PyDoc_STRVAR(scribus_scrolldocument__doc__, +QT_TR_NOOP("scrollDocument(x,y)\n\ +\n\ +Scroll the document in main GUI window by x and y.\n\ +")); +/* + * Gives the possibility to scroll the document. + * 13.12.2007: Joachim Neu + */ +PyObject *scribus_scrolldocument(PyObject*, PyObject* args); + +#endif diff --git a/scribus/plugins/scriptplugin/objimageexport.cpp b/scribus/plugins/scriptplugin/objimageexport.cpp new file mode 100644 index 0000000..df34f7d --- /dev/null +++ b/scribus/plugins/scriptplugin/objimageexport.cpp @@ -0,0 +1,259 @@ +/* +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. +*/ +#include "objimageexport.h" +#include "cmdutil.h" +#include "page.h" + +#include <QImageWriter> +#include <structmember.h> +#include <QFileInfo> +#include <vector> +#include "scribuscore.h" + +typedef struct +{ + PyObject_HEAD + PyObject *name; // string - filename + PyObject *type; // string - image type (PNG, JPEG etc.) + PyObject *allTypes; // list - available types + int dpi; // DPI of the bitmap + int scale; // how is bitmap scaled 100 = 100% + int quality; // quality/compression <1; 100> +} ImageExport; + +static void ImageExport_dealloc(ImageExport* self) +{ + Py_XDECREF(self->name); + Py_XDECREF(self->type); + Py_XDECREF(self->allTypes); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * ImageExport_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) +{ + if(!checkHaveDocument()) + return NULL; + + ImageExport *self; + self = (ImageExport *)type->tp_alloc(type, 0); + if (self != NULL) { + self->name = PyString_FromString("ImageExport.png"); + self->type = PyString_FromString("PNG"); + self->allTypes = PyList_New(0); + self->dpi = 72; + self->scale = 100; + self->quality = 100; + } + return (PyObject *) self; +} + +static int ImageExport_init(ImageExport * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/) +{ + return 0; +} + +static PyMemberDef ImageExport_members[] = { + {const_cast<char*>("dpi"), T_INT, offsetof(ImageExport, dpi), 0, imgexp_dpi__doc__}, + {const_cast<char*>("scale"), T_INT, offsetof(ImageExport, scale), 0, imgexp_scale__doc__}, + {const_cast<char*>("quality"), T_INT, offsetof(ImageExport, quality), 0, imgexp_quality__doc__}, + {NULL, 0, 0, 0, NULL} // sentinel +}; + +static PyObject *ImageExport_getName(ImageExport *self, void * /*closure*/) +{ + Py_INCREF(self->name); + return self->name; +} + +static int ImageExport_setName(ImageExport *self, PyObject *value, void * /*closure*/) +{ + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, QObject::tr("The filename must be a string.", "python error").toLocal8Bit().constData()); + return -1; + } + if (PyString_Size(value) < 1) + { + PyErr_SetString(PyExc_TypeError, QObject::tr("The filename should not be empty string.", "python error").toLocal8Bit().constData()); + return -1; + } + Py_DECREF(self->name); + Py_INCREF(value); + self->name = value; + return 0; +} + +static PyObject *ImageExport_getType(ImageExport *self, void * /*closure*/) +{ + Py_INCREF(self->type); + return self->type; +} + +static int ImageExport_setType(ImageExport *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, QObject::tr("Cannot delete image type settings.", "python error").toLocal8Bit().constData()); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, QObject::tr("The image type must be a string.", "python error").toLocal8Bit().constData()); + return -1; + } + Py_DECREF(self->type); + Py_INCREF(value); + self->type = value; + return 0; +} + +static PyObject *ImageExport_getAllTypes(ImageExport * /*self*/, void * /*closure*/) +{ + PyObject *l; + int pos = 0; + QList<QByteArray> list = QImageWriter::supportedImageFormats(); + l = PyList_New(list.count()); + for (QList<QByteArray>::Iterator it = list.begin(); it != list.end(); ++it) + { + PyList_SetItem(l, pos, PyString_FromString(QString((*it)).toLatin1().constData())); + ++pos; + } + return l; +} + +static int ImageExport_setAllTypes(ImageExport * /*self*/, PyObject * /*value*/, void * /*closure*/) +{ + PyErr_SetString(PyExc_ValueError, QObject::tr("'allTypes' attribute is READ-ONLY", "python error").toLocal8Bit().constData()); + return -1; +} + +static PyGetSetDef ImageExport_getseters [] = { + {const_cast<char*>("name"), (getter)ImageExport_getName, (setter)ImageExport_setName, imgexp_filename__doc__, NULL}, + {const_cast<char*>("type"), (getter)ImageExport_getType, (setter)ImageExport_setType, imgexp_type__doc__, NULL}, + {const_cast<char*>("allTypes"), (getter)ImageExport_getAllTypes, (setter)ImageExport_setAllTypes, imgexp_alltypes__doc__, NULL}, + {NULL, NULL, NULL, NULL, NULL} // sentinel +}; + +static PyObject *ImageExport_save(ImageExport *self) +{ + if(!checkHaveDocument()) + return NULL; + + /* a little magic here - I need to compute the "maxGr" value... + * We need to know the right size of the page for landscape, + * portrait and user defined sizes. + */ + double pixmapSize; + (ScCore->primaryMainWindow()->doc->pageHeight > ScCore->primaryMainWindow()->doc->pageWidth) + ? pixmapSize = ScCore->primaryMainWindow()->doc->pageHeight + : pixmapSize = ScCore->primaryMainWindow()->doc->pageWidth; + QImage im = ScCore->primaryMainWindow()->view->PageToPixmap(ScCore->primaryMainWindow()->doc->currentPage()->pageNr(), qRound(pixmapSize * self->scale * (self->dpi / 72.0) / 100.0), false); + int dpi = qRound(100.0 / 2.54 * self->dpi); + im.setDotsPerMeterY(dpi); + im.setDotsPerMeterX(dpi); + if (!im.save(PyString_AsString(self->name), PyString_AsString(self->type))) + { + PyErr_SetString(ScribusException, QObject::tr("Failed to export image", "python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_True); // return True not None for backward compat + // return Py_True; +// Py_RETURN_TRUE; + return PyBool_FromLong(static_cast<long>(true)); +} + +static PyObject *ImageExport_saveAs(ImageExport *self, PyObject *args) +{ + char* value; + if(!checkHaveDocument()) + return NULL; + if (!PyArg_ParseTuple(args, const_cast<char*>("es"), "utf-8", &value)) + return NULL; + + /* a little magic here - I need to compute the "maxGr" value... + * We need to know the right size of the page for landscape, + * portrait and user defined sizes. + */ + double pixmapSize; + (ScCore->primaryMainWindow()->doc->pageHeight > ScCore->primaryMainWindow()->doc->pageWidth) + ? pixmapSize = ScCore->primaryMainWindow()->doc->pageHeight + : pixmapSize = ScCore->primaryMainWindow()->doc->pageWidth; + QImage im = ScCore->primaryMainWindow()->view->PageToPixmap(ScCore->primaryMainWindow()->doc->currentPage()->pageNr(), qRound(pixmapSize * self->scale * (self->dpi / 72.0) / 100.0), false); + int dpi = qRound(100.0 / 2.54 * self->dpi); + im.setDotsPerMeterY(dpi); + im.setDotsPerMeterX(dpi); + if (!im.save(value, PyString_AsString(self->type))) + { + PyErr_SetString(ScribusException, QObject::tr("Failed to export image", "python error").toLocal8Bit().constData()); + return NULL; + } +// Py_INCREF(Py_True); // return True not None for backward compat + // return Py_True; +// Py_RETURN_TRUE; + return PyBool_FromLong(static_cast<long>(true)); +} + +static PyMethodDef ImageExport_methods[] = { + {const_cast<char*>("save"), (PyCFunction)ImageExport_save, METH_NOARGS, imgexp_save__doc__}, + {const_cast<char*>("saveAs"), (PyCFunction)ImageExport_saveAs, METH_VARARGS, imgexp_saveas__doc__}, + {NULL, (PyCFunction)(0), 0, NULL} // sentinel +}; + +PyTypeObject ImageExport_Type = { + PyObject_HEAD_INIT(NULL) // PyObject_VAR_HEAD + 0, + const_cast<char*>("ImageExport"), // char *tp_name; /* For printing, in format "<module>.<name>" */ + sizeof(ImageExport), // int tp_basicsize, /* For allocation */ + 0, // int tp_itemsize; /* For allocation */ + (destructor) ImageExport_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + 0, // getattrfunc tp_getattr; + 0, // setattrfunc tp_setattr; + 0, // cmpfunc tp_compare; + 0, // reprfunc tp_repr; + 0, // PyNumberMethods *tp_as_number; + 0, // PySequenceMethods *tp_as_sequence; + 0, // PyMappingMethods *tp_as_mapping; + 0, // hashfunc tp_hash; + 0, // ternaryfunc tp_call; + 0, // reprfunc tp_str; + 0, // getattrofunc tp_getattro; + 0, // setattrofunc tp_setattro; + 0, // PyBufferProcs *tp_as_buffer; + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // long tp_flags; + imgexp__doc__, // char *tp_doc; /* Documentation string */ + 0, // traverseproc tp_traverse; + 0, // inquiry tp_clear; + 0, // richcmpfunc tp_richcompare; + 0, // long tp_weaklistoffset; + 0, // getiterfunc tp_iter; + 0, // iternextfunc tp_iternext; + ImageExport_methods, // struct PyMethodDef *tp_methods; + ImageExport_members, // struct PyMemberDef *tp_members; + ImageExport_getseters, // struct PyGetSetDef *tp_getset; + 0, // struct _typeobject *tp_base; + 0, // PyObject *tp_dict; + 0, // descrgetfunc tp_descr_get; + 0, // descrsetfunc tp_descr_set; + 0, // long tp_dictoffset; + (initproc)ImageExport_init, // initproc tp_init; + 0, // allocfunc tp_alloc; + ImageExport_new, // newfunc tp_new; + 0, // freefunc tp_free; /* Low-level free-memory routine */ + 0, // inquiry tp_is_gc; /* For PyObject_IS_GC */ + 0, // PyObject *tp_bases; + 0, // PyObject *tp_mro; /* method resolution order */ + 0, // PyObject *tp_cache; + 0, // PyObject *tp_subclasses; + 0, // PyObject *tp_weaklist; + 0, // destructor tp_del; + +#ifdef COUNT_ALLOCS + /* these must be last and never explicitly initialized */ + // int tp_allocs; + // int tp_frees; + // int tp_maxalloc; + // struct _typeobject *tp_next; +#endif +}; diff --git a/scribus/plugins/scriptplugin/objimageexport.h b/scribus/plugins/scriptplugin/objimageexport.h new file mode 100644 index 0000000..b056520 --- /dev/null +++ b/scribus/plugins/scriptplugin/objimageexport.h @@ -0,0 +1,46 @@ +/* +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. +*/ +#ifndef OBJIMGEXPORT_H +#define OBJIMGEXPORT_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +extern PyTypeObject ImageExport_Type; + +// docstrings +PyDoc_STRVAR(imgexp__doc__,"Image export\n\ +\n\ +Class ImageExport() provides the bitmap graphics exporting\n\ +for Python scripting as you know it from Export/Save as Image\n\ +menu. See related class PDFfile() and procedure savePageAsEPS().\n\ +Example:\n\ +i = ImageExport()\n\ +i.type = 'PNG' # select one from i.allTypes list\n\ +i.scale = 200 # I want to have 200%\n\ +i.name = '/home/subik/test.png'\n\ +i.save()\n\ +\n\ +two last lines should be replaced with:\n\ +i.saveAs('/home/subik/test.png')"); + +PyDoc_STRVAR(imgexp_dpi__doc__, "This value will be used for export as DPI. Read/write integer."); +PyDoc_STRVAR(imgexp_scale__doc__, "This is the scaling of the image. 100 = 100% etc. Read/write iteger."); +PyDoc_STRVAR(imgexp_quality__doc__, "Quality/compression: minimum 1 (poor), maximum 100 (qaulity). Read/write integer."); +PyDoc_STRVAR(imgexp_filename__doc__, "Filename of the image. With or without path. Read/write string."); +PyDoc_STRVAR(imgexp_type__doc__, "Bitmap type. See allTypes list for more info. Read/write string."); +PyDoc_STRVAR(imgexp_alltypes__doc__, "Available types. Read only list of strings."); + +PyDoc_STRVAR(imgexp_save__doc__, "save() -> boolean\n\nSaves image under previously set 'name'."); +PyDoc_STRVAR(imgexp_saveas__doc__, "saveAs('filename') -> boolean\n\nSaves image as 'filename'."); + +// Nest items are not needed but are here for me to exercise +// writing complete python objects + +#define ImageExport_Check(op) ((op)->ob_type == &ImageExport_Type) + +#endif /* OBJIMGEXPORT_H */ diff --git a/scribus/plugins/scriptplugin/objpdffile.cpp b/scribus/plugins/scriptplugin/objpdffile.cpp new file mode 100644 index 0000000..3268ed9 --- /dev/null +++ b/scribus/plugins/scriptplugin/objpdffile.cpp @@ -0,0 +1,1251 @@ +/* +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. +*/ +#include "objpdffile.h" +#include "cmdutil.h" +#include "colormgmt/sccolormgmtengine.h" +#include "bookmarkpalette.h" +#include "prefsmanager.h" +#include "scribusdoc.h" +#include "scribuscore.h" + +#include <structmember.h> +#include <QFileInfo> +#include <QList> +#include <QPixmap> +#include <vector> + +// these functions are located at utils.cpp +void SCRIBUS_API ReOrderText(ScribusDoc *doc, ScribusView *view); +// end of utils.cpp +//this is in file scribus.cpp + + +static int minmaxi(int val, int min, int max) +{ + if (val < min) + return min; + else if (val > max) + return max; + else return val; +} + +static double minmaxd(double val, double min, double max) +{ + if (val < min) + return min; + else if (val > max) + return max; + else return val; +} + +typedef struct +{ + PyObject_HEAD + PyObject *file; // string - file to save into + PyObject *fonts; // list of string - fonts to embed + PyObject *pages; // list of int - pages to print + int thumbnails; // bool - + int compress; // bool - + int compressmtd; // int - 0=automatic 1=jpeg 2=zip 3=none + int quality; // int - 0=Maximum 4=minimum + PyObject *resolution; // int - 35 - 4000 default=300 dpi + PyObject *downsample; // int - 35 - 4000 default=0 do not downsample ; other downsample to this resolution + int bookmarks; // bool - + int binding; // bool - 0 -left margin 1 -right margin + int presentation; // bool - + PyObject *effval; // list of list of 5 int - effect to apply to each page during presentation + int article; // bool - + int encrypt; // bool - + int uselpi; // bool - + int usespot; + int domulti; + PyObject *lpival; // list of elements which has structure [siii] + PyObject *owner; // string - owner's password + PyObject *user; // string - user's password + int aprint; // bool - allow printing + int achange; // bool - allow changing + int acopy; // bool - allow copying + int aanot; // bool - allow adding annotation and fields + int version; // int - version of pdf (12=1.2; 13=1.3; 14=1.4) + int outdst; // int - output destination 0 - screen, 1 - printer + + int profiles; // bool + int profilei; // bool + int intents; // int - 0 - 3 QString tmp_ip[] = { tr("Perceptual"), tr("Relative Colorimetric"), tr("Saturation"), tr("Absolute Colorimetric")}; + int intenti; // int - 0 - 3 QString tmp_ip[] = { tr("Perceptual"), tr("Relative Colorimetric"), tr("Saturation"), tr("Absolute Colorimetric")}; + int noembicc; // bool - "Don't use embedded ICC profiles" + PyObject *solidpr; // string + PyObject *imagepr; // string + PyObject *printprofc; // string + PyObject *info; // string + double bleedt; // double - 0 to hight of page + double bleedl; // double - 0 to width of page + double bleedr; // double - 0 to width of page + double bleedb; // double - 0 to hight of page + +} PDFfile; + +static void PDFfile_dealloc(PDFfile *self) +{ + Py_XDECREF(self->file); + Py_XDECREF(self->fonts); + Py_XDECREF(self->pages); + Py_XDECREF(self->resolution); + Py_XDECREF(self->downsample); + Py_XDECREF(self->effval); + Py_XDECREF(self->lpival); + Py_XDECREF(self->owner); + Py_XDECREF(self->user); + Py_XDECREF(self->solidpr); + Py_XDECREF(self->imagepr); + Py_XDECREF(self->printprofc); + Py_XDECREF(self->info); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * PDFfile_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) +{ +// do not create new object if there is no opened document + if (!ScCore->primaryMainWindow()->HaveDoc) { + PyErr_SetString(PyExc_SystemError, "Need to open document first"); + return NULL; + } + + PDFfile *self; + + self = (PDFfile *)type->tp_alloc(type, 0); + if (self) { +// set file attribute + self->file = PyString_FromString(""); + if (!self->file){ + Py_DECREF(self); + return NULL; + } +// set fonts attribute + self->fonts = PyList_New(0); + if (!self->fonts){ + Py_DECREF(self); + return NULL; + } +// set pages attribute + self->pages = PyList_New(0); + if (self->pages == NULL){ + Py_DECREF(self); + return NULL; + } +// set thumbnails attribute + self->thumbnails = 0; +// set compress attribute + self->compress = 0; +// set compressmtd attribute + self->compressmtd = 0; +// set quality attribute + self->quality = 0; +// set resolution attribute + self->resolution = PyInt_FromLong(300); + if (!self->resolution){ + Py_DECREF(self); + return NULL; + } +// set downsample attribute + self->downsample = PyInt_FromLong(0); + if (!self->downsample){ + Py_DECREF(self); + return NULL; + } +// set bookmarks attribute + self->bookmarks = 0; +// set binding attribute + self->binding = 0; +// set presentation attribute + self->presentation = 0; +// set effval attribute + self->effval = PyList_New(0); + if (!self->effval){ + Py_DECREF(self); + return NULL; + } +// set article attribute + self->article = 0; +// set encrypt attribute + self->encrypt = 0; +// set uselpi attribute + self->uselpi = 0; + self->usespot = 1; + self->domulti = 0; +// set lpival attribute + self->lpival = PyList_New(0); + if (!self->lpival){ + Py_DECREF(self); + return NULL; + } +// set owner attribute + self->owner = PyString_FromString(""); + if (!self->owner){ + Py_DECREF(self); + return NULL; + } +// set user attribute + self->user = PyString_FromString(""); + if (!self->user){ + Py_DECREF(self); + return NULL; + } +// set aprint attribute + self->aprint = 1; +// set achange attribute + self->achange = 1; +// set acopy attribute + self->acopy = 1; +// set aanot attribute + self->aanot = 1; +// set version attribute + self->version = 14; +// set output attribute + self->outdst = 0; + + + self->profiles = 0; // bool + self->profilei = 0; // bool + self->intents = 0; // int - 0 - ? + self->intenti = 0; // int - 0 - ? + self->noembicc = 0; // bool + self->solidpr = PyString_FromString(""); + if (!self->solidpr){ + Py_DECREF(self); + return NULL; + } + self->imagepr = PyString_FromString(""); + if (!self->imagepr){ + Py_DECREF(self); + return NULL; + } + self->printprofc = PyString_FromString(""); + if (!self->printprofc){ + Py_DECREF(self); + return NULL; + } + self->info = PyString_FromString(""); + if (!self->info){ + Py_DECREF(self); + return NULL; + } + self->bleedt = 0; // double - + self->bleedl = 0; // double - + self->bleedr = 0; // double - + self->bleedb = 0; // double - + } + return (PyObject *) self; +} + +static int PDFfile_init(PDFfile *self, PyObject * /*args*/, PyObject * /*kwds*/) +{ + int i; + if (!ScCore->primaryMainWindow()->HaveDoc) { + PyErr_SetString(PyExc_SystemError, "Must open doc first"); + return -1; + } +// defaut save into file + QString tf = ScCore->primaryMainWindow()->doc->PDF_Options.fileName; + if (tf.isEmpty()) { + QFileInfo fi = QFileInfo(ScCore->primaryMainWindow()->doc->DocName); + tf = fi.path()+"/"+fi.baseName()+".pdf"; + } + PyObject *file = NULL; + file = PyString_FromString(tf.toAscii()); + if (file){ + Py_DECREF(self->file); + self->file = file; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'file' attribute"); + return -1; + } +// embed all used fonts + PyObject *fonts = NULL; + fonts = PyList_New(0); + if (fonts){ + Py_DECREF(self->fonts); + self->fonts = fonts; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'fonts' attribute"); + return -1; + } + // get all used fonts + QMap<QString,int> ReallyUsed = ScCore->primaryMainWindow()->doc->UsedFonts; + // create list of all used fonts + QList<QString> tmpEm; + tmpEm = ReallyUsed.keys(); + QList<QString>::Iterator itef; + for (itef = tmpEm.begin(); itef != tmpEm.end(); ++itef) { +// AV: dunno what this is for, but it looks as if it's the only place where HasMetrics is used... +// if (PrefsManager::instance()->appPrefs.AvailFonts[(*itef).toAscii()]->HasMetrics) { + PyObject *tmp= NULL; + tmp = PyString_FromString((*itef).toAscii()); + if (tmp) { + PyList_Append(self->fonts, tmp); +// do i need Py_DECREF(tmp) here? +// Does PyList_Append increase reference or 'steal' one from provided argument +// If it 'steal' reference comment next line + Py_DECREF(tmp); + } + else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'fonts' attribute"); + return -1; + } +// } + } +// set to print all pages + PyObject *pages = NULL; + int num = 0; + // which one should I use ??? + // new = ScCore->primaryMainWindow()->view->Pages.count() + num = ScCore->primaryMainWindow()->doc->Pages->count(); + pages = PyList_New(num); + if (!pages){ + PyErr_SetString(PyExc_SystemError, "Can not initialize 'pages' attribute"); + return -1; + } + for (i = 0; i<num; ++i) { + PyObject *tmp; + tmp = PyInt_FromLong((long)i+1L); + if (tmp) + PyList_SetItem(pages, i, tmp); + else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'pages' attribute"); + return -1; + } + } + Py_DECREF(self->pages); + self->pages = pages; +// do not print thumbnails + self->thumbnails = ScCore->primaryMainWindow()->doc->PDF_Options.Thumbnails; +// set automatic compression + self->compress = ScCore->primaryMainWindow()->doc->PDF_Options.Compress; + self->compressmtd = ScCore->primaryMainWindow()->doc->PDF_Options.CompressMethod; +// use maximum image quality + self->quality = ScCore->primaryMainWindow()->doc->PDF_Options.Quality; +// default resolution + PyObject *resolution = NULL; + resolution = PyInt_FromLong(300); + if (resolution){ + Py_DECREF(self->resolution); + self->resolution = resolution; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'resolutin' attribute"); + return -1; + } +// do not downsample images + int down = ScCore->primaryMainWindow()->doc->PDF_Options.RecalcPic ? ScCore->primaryMainWindow()->doc->PDF_Options.PicRes : 0; + PyObject *downsample = NULL; + downsample = PyInt_FromLong(down); + if (downsample){ + Py_DECREF(self->downsample); + self->downsample = downsample; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'downsamle' attribute"); + return -1; + } + // no bookmarks + self->bookmarks = ScCore->primaryMainWindow()->doc->PDF_Options.Bookmarks; + // left margin binding + self->binding = ScCore->primaryMainWindow()->doc->PDF_Options.Binding; + // do not enable presentation effects + self->presentation = ScCore->primaryMainWindow()->doc->PDF_Options.PresentMode; + // set effects values for all pages + PyObject *effval = NULL; + num = 0; + // which one should I use ??? + // new = ScCore->primaryMainWindow()->view->Pages.count(); + num = ScCore->primaryMainWindow()->doc->Pages->count(); + effval = PyList_New(num); + if (!effval){ + PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute"); + return -1; + } + int num2 = ScCore->primaryMainWindow()->doc->PDF_Options.PresentVals.count(); + for (i = 0; i<num2; ++i) { + PyObject *tmp; + PDFPresentationData t = ScCore->primaryMainWindow()->doc->PDF_Options.PresentVals[i]; + tmp = Py_BuildValue(const_cast<char*>("[iiiiii]"), t.pageEffectDuration, t.pageViewDuration, t.effectType, t.Dm, t.M, t.Di ); + if (tmp) + PyList_SetItem(effval, i, tmp); + else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute"); + return -1; + } + for (; i<num; ++i) { + PyObject *tmp; + tmp = Py_BuildValue(const_cast<char*>("[iiiiii]"), 1, 1, 0, 0, 0, 0); + if (tmp) + PyList_SetItem(effval, i, tmp); + else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute"); + return -1; + } + } + } + Py_DECREF(self->effval); + self->effval = effval; +// do not save linked text frames as PDF article + self->article = ScCore->primaryMainWindow()->doc->PDF_Options.Articles; +// do not encrypt file + self->encrypt = ScCore->primaryMainWindow()->doc->PDF_Options.Encrypt; +// do not Use Custom Rendering Settings + self->uselpi = ScCore->primaryMainWindow()->doc->PDF_Options.UseLPI; + self->usespot = ScCore->primaryMainWindow()->doc->PDF_Options.UseSpotColors; + self->domulti = ScCore->primaryMainWindow()->doc->PDF_Options.doMultiFile; +// get default values for lpival + int n = ScCore->primaryMainWindow()->doc->PDF_Options.LPISettings.size(); + PyObject *lpival=PyList_New(n); + if (!lpival){ + PyErr_SetString(PyExc_SystemError, "Can not initialize 'lpival' attribute"); + return -1; + } + QMap<QString,LPIData>::Iterator it = ScCore->primaryMainWindow()->doc->PDF_Options.LPISettings.begin(); + while (it != ScCore->primaryMainWindow()->doc->PDF_Options.LPISettings.end()) { + PyObject *tmp; + tmp = Py_BuildValue(const_cast<char*>("[siii]"), it.key().toAscii().constData(), it.value().Frequency, it.value().Angle, it.value().SpotFunc); + if (!tmp) { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'lpival' attribute"); + return -1; + } + PyList_SetItem(lpival, --n, tmp); + ++it; + } + PyList_Reverse(lpival); + Py_DECREF(self->lpival); + self->lpival = lpival; +// set owner's password + PyObject *owner = NULL; + owner = PyString_FromString(ScCore->primaryMainWindow()->doc->PDF_Options.PassOwner.toAscii()); + if (owner){ + Py_DECREF(self->owner); + self->owner = owner; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'owner' attribute"); + return -1; + } +// set user'a password + PyObject *user = NULL; + user = PyString_FromString(ScCore->primaryMainWindow()->doc->PDF_Options.PassUser.toAscii()); + if (user){ + Py_DECREF(self->user); + self->user = user; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'user' attribute"); + return -1; + } +// allow printing document + self->aprint = ScCore->primaryMainWindow()->doc->PDF_Options.Permissions & 4; +// allow changing document + self->achange = ScCore->primaryMainWindow()->doc->PDF_Options.Permissions & 8; +// allow copying document + self->acopy = ScCore->primaryMainWindow()->doc->PDF_Options.Permissions & 16; +// allow adding annotation and fields + self->aanot = ScCore->primaryMainWindow()->doc->PDF_Options.Permissions & 32; +// use 1.4 pdf version *aka. Acrobat 5) + self->version = ScCore->primaryMainWindow()->doc->PDF_Options.Version; +// output destination is screen + self->outdst = ScCore->primaryMainWindow()->doc->PDF_Options.UseRGB ? 0 : 1; + + self->profiles = ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles; // bool + self->profilei = ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles2; // bool + self->noembicc = ScCore->primaryMainWindow()->doc->PDF_Options.EmbeddedI; // bool + self->intents = ScCore->primaryMainWindow()->doc->PDF_Options.Intent; // int - 0 - 3 + self->intenti = ScCore->primaryMainWindow()->doc->PDF_Options.Intent2; // int - 0 - 3 + QString tp = ScCore->primaryMainWindow()->doc->PDF_Options.SolidProf; + if (!ScCore->InputProfiles.contains(tp)) + tp = ScCore->primaryMainWindow()->view->Doc->CMSSettings.DefaultSolidColorRGBProfile; + PyObject *solidpr = NULL; + solidpr = PyString_FromString(tp.toAscii()); + if (solidpr){ + Py_DECREF(self->solidpr); + self->solidpr = solidpr; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'solidpr' attribute"); + return -1; + } + QString tp2 = ScCore->primaryMainWindow()->doc->PDF_Options.ImageProf; + if (!ScCore->InputProfiles.contains(tp2)) + tp2 = ScCore->primaryMainWindow()->view->Doc->CMSSettings.DefaultSolidColorRGBProfile; + PyObject *imagepr = NULL; + imagepr = PyString_FromString(tp2.toAscii()); + if (imagepr){ + Py_DECREF(self->imagepr); + self->imagepr = imagepr; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'imagepr' attribute"); + return -1; + } + QString tp3 = ScCore->primaryMainWindow()->doc->PDF_Options.PrintProf; + if (!ScCore->PDFXProfiles.contains(tp3)) + tp3 = ScCore->primaryMainWindow()->view->Doc->CMSSettings.DefaultPrinterProfile; + PyObject *printprofc = NULL; + printprofc = PyString_FromString(tp3.toAscii()); + if (printprofc){ + Py_DECREF(self->printprofc); + self->printprofc = printprofc; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'printprofc' attribute"); + return -1; + } + QString tinfo = ScCore->primaryMainWindow()->doc->PDF_Options.Info; + PyObject *info = NULL; + info = PyString_FromString(tinfo.toAscii()); + if (info){ + Py_DECREF(self->info); + self->info = info; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'info' attribute"); + return -1; + } + self->bleedt = ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Top*ScCore->primaryMainWindow()->doc->unitRatio(); // double - + self->bleedl = ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Left*ScCore->primaryMainWindow()->doc->unitRatio(); // double - + self->bleedr = ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Right*ScCore->primaryMainWindow()->doc->unitRatio(); // double - + self->bleedb = ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Bottom*ScCore->primaryMainWindow()->doc->unitRatio(); // double - + + return 0; +} + +static PyMemberDef PDFfile_members[] = { + {const_cast<char*>("thumbnails"), T_INT, offsetof(PDFfile, thumbnails), 0, const_cast<char*>("Generate thumbnails. Bool value.")}, + {const_cast<char*>("compress"), T_INT, offsetof(PDFfile, compress), 0, const_cast<char*>("Compression switch. Bool value.")}, + {const_cast<char*>("compressmtd"), T_INT, offsetof(PDFfile, compressmtd), 0, const_cast<char*>("Compression method.\n\t0 - Automatic\n\t1 - JPEG\n\t2 - zip\n\t3 - None.")}, + {const_cast<char*>("quality"), T_INT, offsetof(PDFfile, quality), 0, const_cast<char*>("Image quality\n\t0 - Maximum\n\t1 - High\n\t2 - Medium\n\t3 - Low\n\t4 - Minimum")}, + {const_cast<char*>("bookmarks"), T_INT, offsetof(PDFfile, bookmarks), 0, const_cast<char*>("Embed the bookmarks you created in your document.\nThese are useful for navigating long PDF documents.\nBool value")}, + {const_cast<char*>("binding"), T_INT, offsetof(PDFfile, binding), 0, const_cast<char*>("Choose binding.\n\t0 - Left binding\n\t1 - Right binding")}, + {const_cast<char*>("presentation"), T_INT, offsetof(PDFfile, presentation), 0, const_cast<char*>("Enable Presentation Effects.Bool value")}, + {const_cast<char*>("article"), T_INT, offsetof(PDFfile, article), 0, const_cast<char*>("Save Linked Text Frames as PDF Articles\n\tBool value")}, + {const_cast<char*>("encrypt"), T_INT, offsetof(PDFfile, encrypt), 0, const_cast<char*>("Use Encription. Bool value")}, + {const_cast<char*>("uselpi"), T_INT, offsetof(PDFfile, uselpi), 0, const_cast<char*>("Use Custom Rendering Settings. Bool value")}, + {const_cast<char*>("usespot"), T_INT, offsetof(PDFfile, usespot), 0, const_cast<char*>("Use Spot Colors. Bool value")}, + {const_cast<char*>("domulti"), T_INT, offsetof(PDFfile, domulti), 0, const_cast<char*>("Produce a PDF File for every Page. Bool value")}, + {const_cast<char*>("aprint"), T_INT, offsetof(PDFfile, aprint), 0, const_cast<char*>("Allow Printing the Document. Bool value")}, + {const_cast<char*>("achange"), T_INT, offsetof(PDFfile, achange), 0, const_cast<char*>("Allow Changing the Document. Bool value")}, + {const_cast<char*>("acopy"), T_INT, offsetof(PDFfile, acopy), 0, const_cast<char*>("Allow Copying Text and Graphics. Bool value")}, + {const_cast<char*>("aanot"), T_INT, offsetof(PDFfile, aanot), 0, const_cast<char*>("Allow Adding Annotations and Fields. Bool value")}, + {const_cast<char*>("version"), T_INT, offsetof(PDFfile, version), 0, const_cast<char*>("Choose PDF version to use:\n\t12 = PDF/X-3\n\t13 = PDF 1.3 (Acrobat 4)\n\t14 = PDF 1.4 (Acrobat 5)")}, + {const_cast<char*>("outdst"), T_INT, offsetof(PDFfile, outdst), 0, const_cast<char*>("Output destination.\n\t0 - screen\n\t1 - printer")}, + {const_cast<char*>("profiles"), T_INT, offsetof(PDFfile, profiles), 0, const_cast<char*>("Embed a color profile for solid colors. Bool value.")}, + {const_cast<char*>("profilei"), T_INT, offsetof(PDFfile, profilei), 0, const_cast<char*>("Embed a color profile for images. Bool value.")}, + {const_cast<char*>("intents"), T_INT, offsetof(PDFfile, intents), 0, const_cast<char*>("Rendering intent for solid colors\n\t0 - Perceptual\n\t1 - Relative Colorimetric\n\t2 - Saturation\n\t3 - Absolute Colorimetric")}, + {const_cast<char*>("intenti"), T_INT, offsetof(PDFfile, intenti), 0, const_cast<char*>("Rendering intent for images\n\t0 - Perceptual\n\t1 - Relative Colorimetric\n\t2 - Saturation\n\t3 - Absolute Colorimetric")}, + {const_cast<char*>("noembicc"), T_INT, offsetof(PDFfile, noembicc), 0, const_cast<char*>("Don't use embedded ICC profiles. Bool value")}, + {const_cast<char*>("bleedt"), T_DOUBLE, offsetof(PDFfile, bleedt), 0, const_cast<char*>("Bleed Top\n""Distance for bleed from the top of the physical page")}, + {const_cast<char*>("bleedl"), T_DOUBLE, offsetof(PDFfile, bleedl), 0, const_cast<char*>("Bleed Left\n""Distance for bleed from the left of the physical page")}, + {const_cast<char*>("bleedr"), T_DOUBLE, offsetof(PDFfile, bleedr), 0, const_cast<char*>("Bleed Right\n""Distance for bleed from the right of the physical page")}, + {const_cast<char*>("bleedb"), T_DOUBLE, offsetof(PDFfile, bleedb), 0, const_cast<char*>("Bleed Bottom\n""Distance for bleed from the bottom of the physical page")}, + {NULL, 0, 0, 0, NULL} // sentinel +}; + + +/* Here begins Getter & Setter functions */ + +static PyObject *PDFfile_getfile(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->file); + return self->file; +} + +static int PDFfile_setfile(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'file' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'file' attribute value must be string."); + return -1; + } + Py_DECREF(self->file); + Py_INCREF(value); + self->file = value; + return 0; +} + +static PyObject *PDFfile_getfonts(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->fonts); + return self->fonts; +} + +static int PDFfile_setfonts(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'fonts' attribute."); + return -1; + } + if (!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'fonts' attribute value must be list of strings."); + return -1; + } + int n; + n = PyList_Size(value); + for (int i=0; i<n; ++i) + if (!PyString_Check(PyList_GetItem(value, i))) { + PyErr_SetString(PyExc_TypeError, "The 'fonts' list must contain only strings."); + return -1; + } +// Do I need to check if supplied string is really +// name of available font??? +// this is not implemented yet + Py_DECREF(self->fonts); + Py_INCREF(value); + self->fonts = value; + PyList_Sort(self->fonts); + return 0; +} + +static PyObject *PDFfile_getpages(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->pages); + return self->pages; +} + +static int PDFfile_setpages(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'pages' attribute."); + return -1; + } + if (!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'pages' attribute value must be list of integers."); + return -1; + } + int len = PyList_Size(value); + for (int i = 0; i<len; i++){ + PyObject *tmp = PyList_GetItem(value, i); + // I did not check if tmp is NULL + // how can PyList_GetItem fail in this case (my guess: short of available memory?) + // Also do I need Py_INCREF or Py_DECREF here? + if (!PyInt_Check(tmp)){ + PyErr_SetString(PyExc_TypeError, "'pages' list must contain only integers."); + return -1; + } + if (PyInt_AsLong(tmp) > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count()) || PyInt_AsLong(tmp) < 1) { + PyErr_SetString(PyExc_ValueError, "'pages' value out of range."); + return -1; + } + } + Py_DECREF(self->pages); + Py_INCREF(value); + self->pages = value; + PyList_Sort(self->pages); + return 0; +} + + +static PyObject *PDFfile_getresolution(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->resolution); + return self->resolution; +} + +static int PDFfile_setresolution(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'resolution' attribute."); + return -1; + } + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'resolution' attribute value must be integer."); + return -1; + } + int n = PyInt_AsLong(value); + if (n<35 || n>4000) { + PyErr_SetString(PyExc_ValueError, "'compress' value must be in interval from 35 to 4000"); + return -1; + } + Py_DECREF(self->resolution); + Py_INCREF(value); + self->resolution = value; + return 0; +} + +static PyObject *PDFfile_getdownsample(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->downsample); + return self->downsample; +} + +static int PDFfile_setdownsample(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'downsample' attribute."); + return -1; + } + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'downsample' attribute value must be integer."); + return -1; + } + int n = PyInt_AsLong(value); + if (n!=0 && (n<35 || n>PyInt_AsLong(self->resolution))) { + PyErr_SetString(PyExc_TypeError, "'downsample' value must be 0 or in interval from 35 to value of 'resolutin'"); + return -1; + } + Py_DECREF(self->downsample); + Py_INCREF(value); + self->downsample = value; + return 0; +} + +static PyObject *PDFfile_geteffval(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->effval); + return self->effval; +} + +static int PDFfile_seteffval(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'effval' attribute."); + return -1; + } + if (!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'effval' must be list."); + return -1; + } + int n = PyList_Size(value); + for (int i=0; i<n; ++i) { + PyObject *tmp = PyList_GetItem(value, i); + if (!PyList_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, "elemets of 'effval' must be list of five integers."); + return -1; + } + int j = PyList_Size(tmp); + if (j != 6) { + PyErr_SetString(PyExc_TypeError, "elemets of 'effval' must have exactly six integers."); + return -1; + } + for ( --j; j > -1; --j) { + if (!PyInt_Check(PyList_GetItem(tmp, j))) { + PyErr_SetString(PyExc_TypeError, "innermost element of 'effval' must be integers."); + return -1; + } + } + } + Py_DECREF(self->effval); + Py_INCREF(value); + self->effval = value; + return 0; +} + +static PyObject *PDFfile_getlpival(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->lpival); + return self->lpival; +} + +static int PDFfile_setlpival(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'lpival' attribute."); + return -1; + } + if (!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'lpival' must be list."); + return -1; + } + // Do I need Py_INCREF or Py_DECREF here? + int n = PyList_Size(value); + for (int i=0; i<n; ++i) { + PyObject *tmp = PyList_GetItem(value, i); + if (!PyList_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, "elemets of 'lpival' must be list of five integers."); + return -1; + } + int j = PyList_Size(tmp); + if (j != 4) { + PyErr_SetString(PyExc_TypeError, "elemets of 'lpival' must have exactly four members."); + return -1; + } + for ( --j; j > 0; --j) { + if (!PyInt_Check(PyList_GetItem(tmp, j))) { + PyErr_SetString(PyExc_TypeError, "'lpival'elements must have structure [siii]"); + return -1; + } + } + if (!PyString_Check(PyList_GetItem(tmp, 0))) { + PyErr_SetString(PyExc_TypeError, "'lpival'elements must have structure [siii]"); + return -1; + } + } + Py_DECREF(self->lpival); + Py_INCREF(value); + self->lpival = value; + return 0; +} + +static PyObject *PDFfile_getowner(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->owner); + return self->owner; +} + +static int PDFfile_setowner(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'owner' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'owner' attribute value must be string."); + return -1; + } + Py_DECREF(self->owner); + Py_INCREF(value); + self->owner = value; + return 0; +} + +static PyObject *PDFfile_getuser(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->user); + return self->user; +} + +static int PDFfile_setuser(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'user' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'user' attribute value must be string."); + return -1; + } + Py_DECREF(self->user); + Py_INCREF(value); + self->user = value; + return 0; +} + +static PyObject *PDFfile_getsolidpr(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->solidpr); + return self->solidpr; +} + +static int PDFfile_setsolidpr(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'solidpr' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'solidpr' attribute value must be string."); + return -1; + } + Py_DECREF(self->solidpr); + Py_INCREF(value); + self->solidpr = value; + return 0; +} + +static PyObject *PDFfile_getimagepr(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->imagepr); + return self->imagepr; +} + +static int PDFfile_setimagepr(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'imagepr' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'imagepr' attribute value must be string."); + return -1; + } + Py_DECREF(self->imagepr); + Py_INCREF(value); + self->imagepr = value; + return 0; +} + +static PyObject *PDFfile_getprintprofc(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->printprofc); + return self->printprofc; +} + +static int PDFfile_setprintprofc(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'printprofc' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'printprofc' attribute value must be string."); + return -1; + } + Py_DECREF(self->printprofc); + Py_INCREF(value); + self->printprofc = value; + return 0; +} + +static PyObject *PDFfile_getinfo(PDFfile *self, void * /*closure*/) +{ + Py_INCREF(self->info); + return self->info; +} + +static int PDFfile_setinfo(PDFfile *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'info' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'info' attribute value must be string."); + return -1; + } + Py_DECREF(self->info); + Py_INCREF(value); + self->info = value; + return 0; +} + +static char *effval_doc = const_cast<char*>( +"List of effection values for each saved page.\n" +"It is list of list of six integers. Those int has followin meaning:\n\t" +"- Length of time the page is shown before the presentation\n\tstarts on the selected page. (1-3600)\n\t" +"- Length of time the effect runs. (1 - 3600)\n\t\tA shorter time will speed up the effect,\n\t\ta longer one will slow it down\n\t" +"- Type of the display effect\n\t\t0 - No Effect\n\t\t1 - Blinds\n\t\t2 - Box\n\t\t3 - Dissolve\n\t\t4 - Glitter\n\t\t5 - Split\n\t\t6 - Wipe\n\t" +"- Direction of the effect of moving lines\n\tfor the split and blind effects.\n\t\t0 - Horizontal\n\t\t1 - Vertical\n\t" +"- Starting position for the box and split effects.\n\t\t0 - Inside\n\t\t1 - Outside\n\t" +"- Direction of the glitter or wipe effects.\n\t\t0 - Left to Right\n\t\t1 - Top to Bottom\n\t\t2 - Bottom to Top\n\t\t3 - Right to Left\n\t\t4 - Top-left to Bottom-Right"); + +static char *lpival_doc = const_cast<char*>( +"Rendering Settings for individual colors.\n\n" +"This is list of values for each color\n" +"Color values have structure [siii] which stand for:\n\t" +"s - Color name ('Black', 'Cyan', 'Magenta', 'Yellow')\n\t" +"i - Frequency (10 to 1000)\n\t" +"i - Angle (-180 to 180)\n\t" +"i - Spot Function\n\t\t0 - Simple Dot\n\t\t1 - Line\n\t\t2 - Round\n\t\t3 - Ellipse\n" +"Be carefull when supplying these values as they\nare not checked for validity."); + +static PyGetSetDef PDFfile_getseters [] = { + {const_cast<char*>("file"), (getter)PDFfile_getfile, (setter)PDFfile_setfile, const_cast<char*>("Name of file to save into"), NULL}, + {const_cast<char*>("fonts"), (getter)PDFfile_getfonts, (setter)PDFfile_setfonts, const_cast<char*>("List of fonts to embed."), NULL}, + {const_cast<char*>("pages"), (getter)PDFfile_getpages, (setter)PDFfile_setpages, const_cast<char*>("List of pages to print"), NULL}, + {const_cast<char*>("resolution"), (getter)PDFfile_getresolution, (setter)PDFfile_setresolution, const_cast<char*>("Resolution of output file. Values from 35 to 4000."), NULL}, + {const_cast<char*>("downsample"), (getter)PDFfile_getdownsample, (setter)PDFfile_setdownsample, const_cast<char*>("Downsample image resolusion to this value. Values from 35 to 4000\nSet 0 for not to downsample"), NULL}, + {const_cast<char*>("effval"), (getter)PDFfile_geteffval, (setter)PDFfile_seteffval, effval_doc, NULL}, + {const_cast<char*>("lpival"), (getter)PDFfile_getlpival, (setter)PDFfile_setlpival, lpival_doc, NULL}, + {const_cast<char*>("owner"), (getter)PDFfile_getowner, (setter)PDFfile_setowner, const_cast<char*>("Owner's password"), NULL}, + {const_cast<char*>("user"), (getter)PDFfile_getuser, (setter)PDFfile_setuser, const_cast<char*>("User's password"), NULL}, + {const_cast<char*>("solidpr"), (getter)PDFfile_getsolidpr, (setter)PDFfile_setsolidpr, const_cast<char*>("Color profile for solid colors"), NULL}, + {const_cast<char*>("imagepr"), (getter)PDFfile_getimagepr, (setter)PDFfile_setimagepr, const_cast<char*>("Color profile for images"), NULL}, + {const_cast<char*>("printprofc"), (getter)PDFfile_getprintprofc, (setter)PDFfile_setprintprofc, const_cast<char*>("Output profile for printing. If possible, get some guidance from your printer on profile selection."), NULL}, + {const_cast<char*>("info"), (getter)PDFfile_getinfo, (setter)PDFfile_setinfo, const_cast<char*>("Mandatory string for PDF/X-3 or the PDF will fail\nPDF/X-3 conformance. We recommend you use the title of the document."), NULL}, + {NULL, NULL, NULL, NULL, NULL} // sentinel +}; + +static PyObject *PDFfile_save(PDFfile *self) +{ + if (!ScCore->primaryMainWindow()->HaveDoc) { + PyErr_SetString(PyExc_SystemError, "Need to open document first"); + return NULL; + }; + +// copied from file scribus.cpp +//void ScribusMainWindow::SaveAsPDF() + int Components = 3; + QString nam = ""; + if (ScCore->primaryMainWindow()->bookmarkPalette->BView->topLevelItemCount() == 0) + ScCore->primaryMainWindow()->doc->PDF_Options.Bookmarks = false; + +// apply fonts attribute + ScCore->primaryMainWindow()->doc->PDF_Options.EmbedList.clear(); + int n = PyList_Size(self->fonts); + for ( int i=0; i<n; ++i){ + QString tmpFon; + tmpFon = QString(PyString_AsString(PyList_GetItem(self->fonts, i))); + ScCore->primaryMainWindow()->doc->PDF_Options.EmbedList.append(tmpFon); + } +// apply file attribute + QString fn; + fn = QString(PyString_AsString(self->file)); + ScCore->primaryMainWindow()->doc->PDF_Options.fileName = fn; +// apply pages attribute + std::vector<int> pageNs; + int nn=PyList_Size(self->pages); + for (int i = 0; i < nn; ++i) { + pageNs.push_back((int)PyInt_AsLong(PyList_GetItem(self->pages, i))); + } +// apply thumbnails attribute + ScCore->primaryMainWindow()->doc->PDF_Options.Thumbnails = self->thumbnails; +// apply compress attribute + self->compressmtd = minmaxi(self->compressmtd, 0, 3); + ScCore->primaryMainWindow()->doc->PDF_Options.Compress = self->compress; + ScCore->primaryMainWindow()->doc->PDF_Options.CompressMethod = (PDFOptions::PDFCompression) self->compressmtd; +// apply quality attribute + self->quality = minmaxi(self->quality, 0, 4); + ScCore->primaryMainWindow()->doc->PDF_Options.Quality = self->quality; +// apply resolusion attribute + ScCore->primaryMainWindow()->doc->PDF_Options.Resolution = PyInt_AsLong(self->resolution); +// apply downsample attribute + ScCore->primaryMainWindow()->doc->PDF_Options.RecalcPic = PyInt_AsLong(self->downsample); + if (ScCore->primaryMainWindow()->doc->PDF_Options.RecalcPic) + ScCore->primaryMainWindow()->doc->PDF_Options.PicRes = PyInt_AsLong(self->downsample); + else + ScCore->primaryMainWindow()->doc->PDF_Options.PicRes = ScCore->primaryMainWindow()->doc->PDF_Options.Resolution; +// apply bookmarks attribute + ScCore->primaryMainWindow()->doc->PDF_Options.Bookmarks = self->bookmarks; +// apply binding attribute + ScCore->primaryMainWindow()->doc->PDF_Options.Binding = self->binding; +// apply presentation attribute + ScCore->primaryMainWindow()->doc->PDF_Options.PresentMode = self->presentation; + + QList<PDFPresentationData> PresentVals; + PresentVals.clear(); + int tmpnum; + tmpnum=PyList_Size(self->effval); + for (int i=0; i<tmpnum; ++i) { + PDFPresentationData t; +// How do I make this commented piece of code to work? +// I always get an error here + PyObject *ti = PyList_GetItem(self->effval, i); +// if (!PyArg_ParseTuple(ti , "[iiiiii]", +// &t.pageEffectDuration, &t.pageViewDuration, &t.effectType, &t.Dm, +// &t.M, &t.Di)) { +// PyErr_SetString(PyExc_SystemError, "while parsing 'effval'. WHY THIS HAPPENED????"); +// return NULL; +// } +// PresentVals.append(t); + // pv 10/03/2004 crashed when pt is null + if (ti) + { + // Do I Need to check if every PyInt_AsLong and PyList_GetItem funtion succeed??? + t.pageEffectDuration = PyInt_AsLong(PyList_GetItem(ti, 0)); + t.pageViewDuration = PyInt_AsLong(PyList_GetItem(ti, 1)); + t.effectType = PyInt_AsLong(PyList_GetItem(ti, 2)); + t.Dm = PyInt_AsLong(PyList_GetItem(ti, 3)); + t.M = PyInt_AsLong(PyList_GetItem(ti, 4)); + t.Di = PyInt_AsLong(PyList_GetItem(ti, 5)); + PresentVals.append(t); + } // if ti=NULL + + } + + ScCore->primaryMainWindow()->doc->PDF_Options.PresentVals = PresentVals; +// apply lpival + int n2 = PyList_Size(self->lpival); + for (int i=0; i<n2; ++i){ + LPIData lpi; + PyObject *t = PyList_GetItem(self->lpival, i); +// This code always raise exception - WHY??? +// char *s; +// if (!PyArg_ParseTuple(t, "[siii]", &s, &lpi.Frequency, +// &lpi.Angle, &lpi.SpotFunc)) { +// PyErr_SetString(PyExc_SystemError, "while parsing 'lpival'. WHY THIS HAPPENED????"); +// return NULL; +// } +// ScCore->primaryMainWindow()->doc->PDF_Options.LPISettings[QString(s)]=lpi; + QString st; + st = QString(PyString_AsString(PyList_GetItem(t,0))); + lpi.Frequency = PyInt_AsLong(PyList_GetItem(t, 1)); + lpi.Angle = PyInt_AsLong(PyList_GetItem(t, 2)); + lpi.SpotFunc = PyInt_AsLong(PyList_GetItem(t, 3)); + ScCore->primaryMainWindow()->doc->PDF_Options.LPISettings[st]=lpi; + } + + ScCore->primaryMainWindow()->doc->PDF_Options.Articles = self->article; + ScCore->primaryMainWindow()->doc->PDF_Options.Encrypt = self->encrypt; + ScCore->primaryMainWindow()->doc->PDF_Options.UseLPI = self->uselpi; + ScCore->primaryMainWindow()->doc->PDF_Options.UseSpotColors = self->usespot; + ScCore->primaryMainWindow()->doc->PDF_Options.doMultiFile = self->domulti; + self->version = minmaxi(self->version, 12, 14); + // FIXME: Sanity check version + ScCore->primaryMainWindow()->doc->PDF_Options.Version = (PDFOptions::PDFVersion)self->version; + if (self->encrypt) + { + int Perm = -64; + if (ScCore->primaryMainWindow()->doc->PDF_Options.Version == PDFOptions::PDFVersion_14) + Perm &= ~0x00240000; + if (self->aprint) + Perm += 4; + if (self->achange) + Perm += 8; + if (self->acopy) + Perm += 16; + if (self->aanot) + Perm += 32; + ScCore->primaryMainWindow()->doc->PDF_Options.Permissions = Perm; + ScCore->primaryMainWindow()->doc->PDF_Options.PassOwner = QString(PyString_AsString(self->owner)); + ScCore->primaryMainWindow()->doc->PDF_Options.PassUser = QString(PyString_AsString(self->user)); + } + if (self->outdst == 0) + { + ScCore->primaryMainWindow()->doc->PDF_Options.UseRGB = true; + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles = false; + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles2 = false; + } + else + { + ScCore->primaryMainWindow()->doc->PDF_Options.UseRGB = false; + if (ScCore->primaryMainWindow()->doc->HasCMS) + { + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles = self->profiles; + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles2 = self->profilei; + self->intents = minmaxi(self->intents, 0, 3); + ScCore->primaryMainWindow()->doc->PDF_Options.Intent = self->intents; + self->intenti = minmaxi(self->intenti, 0, 3); + ScCore->primaryMainWindow()->doc->PDF_Options.Intent2 = self->intenti; + ScCore->primaryMainWindow()->doc->PDF_Options.EmbeddedI = self->noembicc; + ScCore->primaryMainWindow()->doc->PDF_Options.SolidProf = PyString_AsString(self->solidpr); + ScCore->primaryMainWindow()->doc->PDF_Options.ImageProf = PyString_AsString(self->imagepr); + ScCore->primaryMainWindow()->doc->PDF_Options.PrintProf = PyString_AsString(self->printprofc); + if (ScCore->primaryMainWindow()->doc->PDF_Options.Version == PDFOptions::PDFVersion_X3) + { +// Where does compiler find cms function when I have not included header for it + ScColorProfile hIn; + hIn = ScColorMgmtEngine::openProfileFromFile(ScCore->PrinterProfiles[ScCore->primaryMainWindow()->doc->PDF_Options.PrintProf]); + nam = hIn.productDescription(); + if (hIn.colorSpace() == ColorSpace_Rgb) + Components = 3; + if (hIn.colorSpace() == ColorSpace_Cmyk) + Components = 4; + if (hIn.colorSpace() == ColorSpace_Gray) + Components = 3; + ScCore->primaryMainWindow()->doc->PDF_Options.Info = PyString_AsString(self->info); + self->bleedt = minmaxd(self->bleedt, 0, ScCore->primaryMainWindow()->view->Doc->pageHeight*ScCore->primaryMainWindow()->view->Doc->unitRatio()); + ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Top = self->bleedt/ScCore->primaryMainWindow()->view->Doc->unitRatio(); + self->bleedl = minmaxd(self->bleedl, 0, ScCore->primaryMainWindow()->view->Doc->pageWidth*ScCore->primaryMainWindow()->view->Doc->unitRatio()); + ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Left = self->bleedl/ScCore->primaryMainWindow()->view->Doc->unitRatio(); + self->bleedr = minmaxd(self->bleedr, 0, ScCore->primaryMainWindow()->view->Doc->pageWidth*ScCore->primaryMainWindow()->view->Doc->unitRatio()); + ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Right = self->bleedr/ScCore->primaryMainWindow()->view->Doc->unitRatio(); + self->bleedb = minmaxd(self->bleedb, 0, ScCore->primaryMainWindow()->view->Doc->pageHeight*ScCore->primaryMainWindow()->view->Doc->unitRatio()); + ScCore->primaryMainWindow()->doc->PDF_Options.bleeds.Bottom = self->bleedb/ScCore->primaryMainWindow()->view->Doc->unitRatio(); + ScCore->primaryMainWindow()->doc->PDF_Options.Encrypt = false; + ScCore->primaryMainWindow()->doc->PDF_Options.PresentMode = false; + } + } + else + { + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles = false; + ScCore->primaryMainWindow()->doc->PDF_Options.UseProfiles2 = false; + } + + } + QMap<int,QPixmap> thumbs; + for (uint ap = 0; ap < pageNs.size(); ++ap) + { + QPixmap pm(10,10); + if (ScCore->primaryMainWindow()->doc->PDF_Options.Thumbnails) + pm = QPixmap::fromImage(ScCore->primaryMainWindow()->view->PageToPixmap(pageNs[ap]-1, 100)); + thumbs.insert(pageNs[ap], pm); + } + ReOrderText(ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow()->view); + QString errorMessage; + if (!ScCore->primaryMainWindow()->getPDFDriver(fn, nam, Components, pageNs, thumbs, errorMessage)) { + fn = "Cannot write the File: " + fn; + if (!errorMessage.isEmpty()) + fn += QString("\n%1").arg(errorMessage); + PyErr_SetString(PyExc_SystemError, fn.toAscii()); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +static PyMethodDef PDFfile_methods[] = { + {const_cast<char*>("save"), (PyCFunction)PDFfile_save, METH_NOARGS, const_cast<char*>("Save selected pages to pdf file")}, + {NULL, (PyCFunction)(0), 0, NULL} // sentinel +}; + +PyTypeObject PDFfile_Type = { + PyObject_HEAD_INIT(NULL) // PyObject_VAR_HEAD + 0, // + const_cast<char*>("PDFfile"), // char *tp_name; /* For printing, in format "<module>.<name>" */ + sizeof(PDFfile), // int tp_basicsize, /* For allocation */ + 0, // int tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + (destructor) PDFfile_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + 0, // getattrfunc tp_getattr; + 0, // setattrfunc tp_setattr; + 0, // cmpfunc tp_compare; + 0, // reprfunc tp_repr; + + /* Method suites for standard classes */ + + 0, // PyNumberMethods *tp_as_number; + 0, // PySequenceMethods *tp_as_sequence; + 0, // PyMappingMethods *tp_as_mapping; + + /* More standard operations (here for binary compatibility) */ + + 0, // hashfunc tp_hash; + 0, // ternaryfunc tp_call; + 0, // reprfunc tp_str; + 0, // getattrofunc tp_getattro; + 0, // setattrofunc tp_setattro; + + /* Functions to access object as input/output buffer */ + 0, // PyBufferProcs *tp_as_buffer; + + /* Flags to define presence of optional/expanded features */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // long tp_flags; + + pdffile__doc__, // char *tp_doc; /* Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + 0, // traverseproc tp_traverse; + + /* delete references to contained objects */ + 0, // inquiry tp_clear; + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + 0, // richcmpfunc tp_richcompare; + + /* weak reference enabler */ + 0, // long tp_weaklistoffset; + + /* Added in release 2.2 */ + /* Iterators */ + 0, // getiterfunc tp_iter; + 0, // iternextfunc tp_iternext; + + /* Attribute descriptor and subclassing stuff */ + PDFfile_methods, // struct PyMethodDef *tp_methods; + PDFfile_members, // struct PyMemberDef *tp_members; + PDFfile_getseters, // struct PyGetSetDef *tp_getset; + 0, // struct _typeobject *tp_base; + 0, // PyObject *tp_dict; + 0, // descrgetfunc tp_descr_get; + 0, // descrsetfunc tp_descr_set; + 0, // long tp_dictoffset; + (initproc)PDFfile_init, // initproc tp_init; + 0, // allocfunc tp_alloc; + PDFfile_new, // newfunc tp_new; + 0, // freefunc tp_free; /* Low-level free-memory routine */ + 0, // inquiry tp_is_gc; /* For PyObject_IS_GC */ + 0, // PyObject *tp_bases; + 0, // PyObject *tp_mro; /* method resolution order */ + 0, // PyObject *tp_cache; + 0, // PyObject *tp_subclasses; + 0, // PyObject *tp_weaklist; + 0, // destructor tp_del; + +#ifdef COUNT_ALLOCS + /* these must be last and never explicitly initialized */ + // int tp_allocs; + // int tp_frees; + // int tp_maxalloc; + // struct _typeobject *tp_next; +#endif +}; diff --git a/scribus/plugins/scriptplugin/objpdffile.h b/scribus/plugins/scriptplugin/objpdffile.h new file mode 100644 index 0000000..d840798 --- /dev/null +++ b/scribus/plugins/scriptplugin/objpdffile.h @@ -0,0 +1,31 @@ +/* +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. +*/ +#ifndef OBJPDFFILE_H +#define OBJPDFFILE_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +extern PyTypeObject PDFfile_Type; + +// Nest items are not needed but are here for me to exercise +// writing complete python objects + +#define PDFfile_Check(op) ((op)->ob_type == &PDFfile_Type) + +PyDoc_STRVAR(pdffile__doc__,"Exporting PDF\n\ +\n\ +Class PDFfile() provides the PDF exporting\n\ +for Python scripting as you know it from Save as PDF\n\ +menu. \n\ +Example:\n\ +pdf = PDFfile()\n\ +pdf.thumbnails = 1 # generate thumbnails too\n\ +pdf.file = 'mypdf.pdf' \n\ +pdf.save()"); + +#endif /* OBJPDFFILE_H */ diff --git a/scribus/plugins/scriptplugin/objprinter.cpp b/scribus/plugins/scriptplugin/objprinter.cpp new file mode 100644 index 0000000..eb60f4f --- /dev/null +++ b/scribus/plugins/scriptplugin/objprinter.cpp @@ -0,0 +1,613 @@ +/* +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. +*/ +#include <vector> +#include <iostream> + +#include "objprinter.h" +#include "cmdutil.h" +#include "prefsmanager.h" + +#include <structmember.h> +#include <QFileInfo> +#include <QDir> + +#include "pslib.h" +#include "scpaths.h" +#include "scribuscore.h" +#include "util_file.h" +#include "util_ghostscript.h" +#include "util_printer.h" + +#ifdef HAVE_CUPS +#include <cups/cups.h> +#endif +// these functions are located at utils.cpp +bool SCRIBUS_API loadText(QString nam, QString *Buffer); +void SCRIBUS_API ReOrderText(ScribusDoc *doc, ScribusView *view); +// end of utils.cpp + +#if defined(_WIN32) +#include "scprintengine_gdi.h" +#endif + +typedef struct +{ + PyObject_HEAD + PyObject *allPrinters; // list of strings - names of installed printers + PyObject *printer; // string - selected printer + PyObject *file; // string - name of file to print into (eg. output.ps) + PyObject *cmd; // string - if "" use standard command else use this as command (eg. "kprinter", "xpp" ...) + PyObject *pages; // list of integers - pages to be printed + int copies; // numer of printed copies + PyObject *separation; // string - No; All; Cyan; Magenta; Yellow; Black + int color; // bool - do we print in color=1 or greyscale=0 + int useICC; // bool - do we use ICC Profiles 0 = No 1 = Yes + int pslevel; // integer - 1, 2 or 3 level of used postscript + int mph; // bool - mirror pages horizontally + int mpv; // bool - mirror pages vertically + int ucr; // bool - Under Color Removal +} Printer; + + +static void Printer_dealloc(Printer* self) +{ + Py_XDECREF(self->allPrinters); + Py_XDECREF(self->printer); + Py_XDECREF(self->file); + Py_XDECREF(self->cmd); + Py_XDECREF(self->pages); + Py_XDECREF(self->separation); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * Printer_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) +{ +// do not create new object if there is no opened document + if (!ScCore->primaryMainWindow()->HaveDoc) { + PyErr_SetString(PyExc_SystemError, "Need to open document first"); + return NULL; + } + + Printer *self; + self = (Printer *)type->tp_alloc(type, 0); + if (self != NULL) { +// set allPrinters attribute + self->allPrinters = PyList_New(0); + if (self->allPrinters == NULL){ + Py_DECREF(self); + return NULL; + } +// set printer attribute + self->printer = PyString_FromString(""); + if (self->printer == NULL){ + Py_DECREF(self); + return NULL; + } +// set file attribute + self->file = PyString_FromString(""); + if (self->file == NULL){ + Py_DECREF(self); + return NULL; + } +// set cmd attribute + self->cmd = PyString_FromString(""); + if (self->cmd == NULL){ + Py_DECREF(self); + return NULL; + } +// set pages attribute + self->pages = PyList_New(0); + if (self->pages == NULL){ + Py_DECREF(self); + return NULL; + } +// set separation attribute + self->separation = PyString_FromString("No"); + if (self->separation == NULL){ + Py_DECREF(self); + return NULL; + } +// set color attribute + self->color = 1; +// set useICC attribute + self->useICC = 0; +// set pslevel attribute + self->pslevel = 3; +// set mph attribute + self->mph = 0; +// set mpv attribute + self->mpv = 0; +// set ucr attribute + self->ucr = 1; +// set copies attribute + self->copies = 1; + } + return (PyObject *) self; +} + +static int Printer_init(Printer *self, PyObject * /*args*/, PyObject * /*kwds*/) +{ +// pool system for installed printers +// most code is stolen and little adopted from druck.cpp + PyObject *allPrinters = PyList_New(0); + if (allPrinters){ + Py_DECREF(self->allPrinters); + self->allPrinters = allPrinters; + } + QStringList printers = PrinterUtil::getPrinterNames(); + for (int i = 0; i < printers.count(); ++i) + { + QString prn = printers[i]; + if (prn.isEmpty()) + continue; + PyObject *tmppr = PyString_FromString(prn.toLocal8Bit().constData()); + if (tmppr){ + PyList_Append(self->allPrinters, tmppr); + Py_DECREF(tmppr); + } + } + PyObject *tmp2 = PyString_FromString("File"); + PyList_Append(self->allPrinters, tmp2); + Py_DECREF(tmp2); +// as defaut set to print into file + PyObject *printer = NULL; + printer = PyString_FromString("File"); + if (printer){ + Py_DECREF(self->printer); + self->printer = printer; + } +// set defaul name of file to print into + QString tf = ScCore->primaryMainWindow()->doc->PDF_Options.fileName; + if (tf.isEmpty()) { + QFileInfo fi = QFileInfo(ScCore->primaryMainWindow()->doc->DocName); + tf = fi.path()+"/"+fi.baseName()+".pdf"; + } + PyObject *file = NULL; + file = PyString_FromString(tf.toAscii()); + if (file){ + Py_DECREF(self->file); + self->file = file; + } else { + PyErr_SetString(PyExc_SystemError, "Can not initialize 'file' attribute"); + return -1; + } +// alternative printer commands default to "" + PyObject *cmd = NULL; + cmd = PyString_FromString(""); + if (cmd){ + Py_DECREF(self->cmd); + self->cmd = cmd; + } +// if document exist when created Printer instance +// set to print all pages + PyObject *pages = NULL; + int num = 0; + if (ScCore->primaryMainWindow()->HaveDoc) + // which one should I use ??? + // new = ScCore->primaryMainWindow()->view->Pages.count() + num = ScCore->primaryMainWindow()->doc->Pages->count(); + pages = PyList_New(num); + if (pages){ + Py_DECREF(self->pages); + self->pages = pages; + } + for (int i = 0; i<num; i++) { + PyObject *tmp=NULL; + tmp = PyInt_FromLong((long)i+1L); // instead of 1 put here first page number + if (tmp) + PyList_SetItem(self->pages, i, tmp); + } +// do not print separation + PyObject *separation = NULL; + separation = PyString_FromString("No"); + if (separation){ + Py_DECREF(self->separation); + self->separation = separation; + } +// print in color + self->color = 1; +// do not use ICC Profile + self->useICC = 0; +// use PostScrip level 3 + self->pslevel = 3; +// do not mirror pages + self->mph = 0; +// do not mirror pages + self->mpv = 0; +// apply Under Color Removal as default + self->ucr = 1; +// number of copies + self->copies = 1; + return 0; +} + +static PyMemberDef Printer_members[] = { + {const_cast<char*>("copies"), T_INT, offsetof(Printer, copies), 0, const_cast<char*>("Number of copies")}, + {const_cast<char*>("color"), T_INT, offsetof(Printer, color), 0, const_cast<char*>("Print in color.\n\t True - color -- Default\n\t False - greyscale")}, + {const_cast<char*>("useICC"), T_INT, offsetof(Printer, useICC), 0, const_cast<char*>("Use ICC Profile\n\tTrue\n\tFalse -- Default")}, + {const_cast<char*>("pslevel"), T_INT, offsetof(Printer, pslevel), 0, const_cast<char*>("PostScript Level\nCan be 1 or 2 or 3 -- Default is 3.")}, + {const_cast<char*>("mph"), T_INT, offsetof(Printer, mph), 0, const_cast<char*>("Mirror Pages Horizontal\n\tTrue\n\tFalse -- Default")}, + {const_cast<char*>("mpv"), T_INT, offsetof(Printer, mpv), 0, const_cast<char*>("Mirror Pages Vertical\n\t True\n\tFalse -- Default")}, + {const_cast<char*>("ucr"), T_INT, offsetof(Printer, ucr), 0, const_cast<char*>("Apply Under Color Removal\n\tTrue -- Default\n\tFalse")}, + {NULL, 0, 0, 0, NULL} // sentinel +}; + +/* Here begins Getter & Setter functions */ + +static PyObject *Printer_getallPrinters(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->allPrinters); + return self->allPrinters; +} + +static int Printer_setallPrinters(Printer * /*self*/, PyObject * /*value*/, void * /*closure*/) +{ + PyErr_SetString(PyExc_ValueError, "'allPrinters' attribute is READ-ONLY"); + return -1; +} + +static PyObject *Printer_getprinter(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->printer); + return self->printer; +} + +static int Printer_setprinter(Printer *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'printer' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'printer' attribute value must be string."); + return -1; + } + int n = PyList_Size(self->allPrinters); + bool same = 0; + for (int i = 0; i<n; i++) + if (PyObject_RichCompareBool(value, PyList_GetItem(self->allPrinters, i), Py_EQ) == 1) + same = true; + if (!same) { + PyErr_SetString(PyExc_ValueError, "'printer' value can be only one of string in 'allPrinters' attribute "); + return -1; + } + Py_DECREF(self->printer); + Py_INCREF(value); + self->printer = value; + return 0; +} + +static PyObject *Printer_getfile(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->file); + return self->file; +} + +static int Printer_setfile(Printer *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'file' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'file' attribute value must be string."); + return -1; + } + Py_DECREF(self->file); + Py_INCREF(value); + self->file = value; + return 0; +} + +static PyObject *Printer_getcmd(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->cmd); + return self->cmd; +} + +static int Printer_setcmd(Printer *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'cmd' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'cmd' attribute value must be string."); + return -1; + } + Py_DECREF(self->cmd); + Py_INCREF(value); + self->cmd = value; + return 0; +} + +static PyObject *Printer_getpages(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->pages); + return self->pages; +} + +static int Printer_setpages(Printer *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'pages' attribute."); + return -1; + } + if (!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, "'pages' attribute value must be list of integers."); + return -1; + } + int len = PyList_Size(value); + for (int i = 0; i<len; i++){ + PyObject *tmp = PyList_GetItem(value, i); + if (!PyInt_Check(tmp)){ + PyErr_SetString(PyExc_TypeError, "'pages' attribute must be list containing only integers."); + return -1; + } + if (PyInt_AsLong(tmp) > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count()) || PyInt_AsLong(tmp) < 1) { + PyErr_SetString(PyExc_ValueError, "'pages' value out of range."); + return -1; + } + } + Py_DECREF(self->pages); + Py_INCREF(value); + self->pages = value; + return 0; +} + +static PyObject *Printer_getseparation(Printer *self, void * /*closure*/) +{ + Py_INCREF(self->separation); + return self->separation; +} + +static int Printer_setseparation(Printer *self, PyObject *value, void * /*closure*/) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'separation' attribute."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'separation' attribute value must be string."); + return -1; + } + Py_DECREF(self->separation); + Py_INCREF(value); + self->separation = value; + return 0; +} + + +static PyGetSetDef Printer_getseters [] = { + {const_cast<char*>("allPrinters"), (getter)Printer_getallPrinters, (setter)Printer_setallPrinters, const_cast<char*>("List of installed printers -- read only"), NULL}, + {const_cast<char*>("printer"), (getter)Printer_getprinter, (setter)Printer_setprinter, const_cast<char*>("Name of printer to use.\nDefault is 'File' for printing into file"), NULL}, + {const_cast<char*>("file"), (getter)Printer_getfile, (setter)Printer_setfile, const_cast<char*>("Name of file to print into"), NULL}, + {const_cast<char*>("cmd"), (getter)Printer_getcmd, (setter)Printer_setcmd, const_cast<char*>("Alternative Printer Command"), NULL}, + {const_cast<char*>("pages"), (getter)Printer_getpages, (setter)Printer_setpages, const_cast<char*>("List of pages to be printed"), NULL}, + {const_cast<char*>("separation"), (getter)Printer_getseparation, (setter)Printer_setseparation, const_cast<char*>("Print separationl\n\t 'No' -- Default\n\t 'All'\n\t 'Cyan'\n\t 'Magenta'\n\t 'Yellow'\n\t 'Black'\nBeware of misspelling because check is not performed"), NULL}, + {NULL, NULL, NULL, NULL, NULL} // sentinel +}; + +// Here we actually print +static PyObject *Printer_print(Printer *self) +{ + if (!ScCore->primaryMainWindow()->HaveDoc) { + PyErr_SetString(PyExc_SystemError, "Need to open documetnt first"); + return NULL; + } +// copied from void ScribusMainWindow::slotFilePrint() in file scribus.cpp + QString fna, prn, cmd, scmd, cc, data, SepName; + QString printcomm; + bool fil, PSfile; + PSfile = false; + +// ReOrderText(ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow()->view); + prn = QString(PyString_AsString(self->printer)); + fna = QString(PyString_AsString(self->file)); + fil = (QString(PyString_AsString(self->printer)) == QString("File")) ? true : false; + std::vector<int> pageNs; + PrintOptions options; + for (int i = 0; i < PyList_Size(self->pages); ++i) { + options.pageNumbers.push_back((int)PyInt_AsLong(PyList_GetItem(self->pages, i))); + } + int Nr = (self->copies < 1) ? 1 : self->copies; + SepName = QString(PyString_AsString(self->separation)); + options.printer = prn; + options.prnEngine = (PrintEngine) self->pslevel; + options.toFile = fil; + options.separationName = SepName; + options.outputSeparations = (SepName == QString("No")) ? false : true; + options.useColor = self->color; + options.mirrorH = self->mph; + options.mirrorV = self->mpv; + options.useICC = self->useICC; + options.doGCR = self->ucr; + options.cropMarks = false; + options.bleedMarks = false; + options.registrationMarks = false; + options.colorMarks = false; + options.markOffset = 0.0; + options.bleeds.Top = 0.0; + options.bleeds.Left = 0.0; + options.bleeds.Right = 0.0; + options.bleeds.Bottom = 0.0; + if (!PrinterUtil::checkPrintEngineSupport(options.printer, options.prnEngine, options.toFile)) + options.prnEngine = PrinterUtil::getDefaultPrintEngine(options.printer, options.toFile); + printcomm = QString(PyString_AsString(self->cmd)); + QMap<QString, QMap<uint, FPointArray> > ReallyUsed; + ReallyUsed.clear(); + ScCore->primaryMainWindow()->doc->getUsedFonts(ReallyUsed); + PrefsManager *prefsManager=PrefsManager::instance(); + +#if defined(_WIN32) + if (!options.toFile) + { + QByteArray devMode; + bool printDone = false; + if ( PrinterUtil::getDefaultSettings(prn, options.devMode) ) + { + ScPrintEngine_GDI winPrint; + printDone = winPrint.print( *ScCore->primaryMainWindow()->doc, options ); + } + if (!printDone) + PyErr_SetString(PyExc_SystemError, "Printing failed"); + Py_RETURN_NONE; + } +#endif + + PSLib *dd = new PSLib(options, true, prefsManager->appPrefs.AvailFonts, ReallyUsed, ScCore->primaryMainWindow()->doc->PageColors, false, true); + if (dd != NULL) + { + if (!fil) + fna = QDir::toNativeSeparators(ScPaths::getTempFileDir()+"/tmp.ps"); + PSfile = dd->PS_set_file(fna); + fna = QDir::toNativeSeparators(fna); + if (PSfile) + { + options.setDevParam = false; + options.doClip = false; + dd->CreatePS(ScCore->primaryMainWindow()->doc, options); + if (options.prnEngine == PostScript1 || options.prnEngine == PostScript2) + { + if (ScCore->haveGS()) + { + QString tmp; + QStringList opts; + opts.append( QString("-dDEVICEWIDTHPOINTS=%1").arg(tmp.setNum(ScCore->primaryMainWindow()->doc->pageWidth)) ); + opts.append( QString("-dDEVICEHEIGHTPOINTS=%1").arg(tmp.setNum(ScCore->primaryMainWindow()->doc->pageHeight)) ); + convertPS2PS(fna, fna+".tmp", opts, options.prnEngine); + moveFile( fna + ".tmp", fna ); + } + else + { + PyErr_SetString(PyExc_SystemError, "Printing failed : GhostScript is needed to print to PostScript Level 1 or Level 2"); + Py_RETURN_NONE; + } + } + + if (!fil) + { + if (!printcomm.isEmpty()) + cmd = printcomm + " "+fna; + else + { + cmd = "lpr -P" + prn; + if (Nr > 1) + cmd += " -#" + cc.setNum(Nr); +#ifdef HAVE_CUPS +// This need yet to be implemented by object Printer +// cmd += printer->PrinterOpts; +#endif + cmd += " "+fna; + } + system(cmd.toLocal8Bit().constData()); + unlink(fna.toLocal8Bit().constData()); + } + } + else { + delete dd; + PyErr_SetString(PyExc_SystemError, "Printing failed"); + return NULL; + } + delete dd; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +static PyMethodDef Printer_methods[] = { + {const_cast<char*>("printNow"), (PyCFunction)Printer_print, METH_NOARGS, const_cast<char*>("Prints selected pages.")}, + {NULL, (PyCFunction)(0), 0, NULL} // sentinel +}; + +PyTypeObject Printer_Type = { + PyObject_HEAD_INIT(NULL) // PyObject_VAR_HEAD + 0, // + const_cast<char*>("Printer"), // char *tp_name; /* For printing, in format "<module>.<name>" */ + sizeof(Printer), // int tp_basicsize, /* For allocation */ + 0, // int tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + (destructor) Printer_dealloc, // destructor tp_dealloc; + 0, // printfunc tp_print; + 0, // getattrfunc tp_getattr; + 0, // setattrfunc tp_setattr; + 0, // cmpfunc tp_compare; + 0, // reprfunc tp_repr; + + /* Method suites for standard classes */ + + 0, // PyNumberMethods *tp_as_number; + 0, // PySequenceMethods *tp_as_sequence; + 0, // PyMappingMethods *tp_as_mapping; + + /* More standard operations (here for binary compatibility) */ + + 0, // hashfunc tp_hash; + 0, // ternaryfunc tp_call; + 0, // reprfunc tp_str; + 0, // getattrofunc tp_getattro; + 0, // setattrofunc tp_setattro; + + /* Functions to access object as input/output buffer */ + 0, // PyBufferProcs *tp_as_buffer; + + /* Flags to define presence of optional/expanded features */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // long tp_flags; + + printer__doc__, // char *tp_doc; /* Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + 0, // traverseproc tp_traverse; + + /* delete references to contained objects */ + 0, // inquiry tp_clear; + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + 0, // richcmpfunc tp_richcompare; + + /* weak reference enabler */ + 0, // long tp_weaklistoffset; + + /* Added in release 2.2 */ + /* Iterators */ + 0, // getiterfunc tp_iter; + 0, // iternextfunc tp_iternext; + + /* Attribute descriptor and subclassing stuff */ + Printer_methods, // struct PyMethodDef *tp_methods; + Printer_members, // struct PyMemberDef *tp_members; + Printer_getseters, // struct PyGetSetDef *tp_getset; + 0, // struct _typeobject *tp_base; + 0, // PyObject *tp_dict; + 0, // descrgetfunc tp_descr_get; + 0, // descrsetfunc tp_descr_set; + 0, // long tp_dictoffset; + (initproc)Printer_init, // initproc tp_init; + 0, // allocfunc tp_alloc; + Printer_new, // newfunc tp_new; + 0, // freefunc tp_free; /* Low-level free-memory routine */ + 0, // inquiry tp_is_gc; /* For PyObject_IS_GC */ + 0, // PyObject *tp_bases; + 0, // PyObject *tp_mro; /* method resolution order */ + 0, // PyObject *tp_cache; + 0, // PyObject *tp_subclasses; + 0, // PyObject *tp_weaklist; + 0, // destructor tp_del; + +#ifdef COUNT_ALLOCS + /* these must be last and never explicitly initialized */ + // int tp_allocs; + // int tp_frees; + // int tp_maxalloc; + // struct _typeobject *tp_next; +#endif +}; diff --git a/scribus/plugins/scriptplugin/objprinter.h b/scribus/plugins/scriptplugin/objprinter.h new file mode 100644 index 0000000..cf834a2 --- /dev/null +++ b/scribus/plugins/scriptplugin/objprinter.h @@ -0,0 +1,28 @@ +/* +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. +*/ +#ifndef OBJPRINTER_H +#define OBJPRINTER_H + +// Pulls in <Python.h> first +#include "cmdvar.h" + +extern PyTypeObject Printer_Type; + +// Nest items are not needed but are here for me to exercise +// writing complete python objects + +#define Printer_Check(op) ((op)->ob_type == &Printer_Type) + +PyDoc_STRVAR(printer__doc__,"Printing\n\ +\n\ +Class Printer() provides printing for Python scripting.\n\ +\n\ +Example:\n\ +p = Printer()\n\ +p.print()"); + +#endif /* OBJPRINTER_H */ diff --git a/scribus/plugins/scriptplugin/pconsole.cpp b/scribus/plugins/scriptplugin/pconsole.cpp new file mode 100644 index 0000000..a7331b1 --- /dev/null +++ b/scribus/plugins/scriptplugin/pconsole.cpp @@ -0,0 +1,397 @@ +/* +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. +*/ +/* +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +*/ + +#include "pconsole.h" + +#include <QFileDialog> +#include "scribus.h" +#include "prefsmanager.h" +#include "prefsfile.h" +#include "prefscontext.h" +#include "scmessagebox.h" +#include "commonstrings.h" +#include "util_icon.h" + + +PythonConsole::PythonConsole( QWidget* parent) + : QMainWindow( parent ) +{ + setupUi(this); + setWindowIcon(loadIcon("AppIcon.png")); + + changedLabel = new QLabel(this); + cursorTemplate = tr("Col: %1 Row: %2/%3"); + cursorLabel = new QLabel(this); + statusBar()->addPermanentWidget(changedLabel); + statusBar()->addPermanentWidget(cursorLabel); + + action_Open->setIcon(loadIcon("16/document-open.png")); + action_Save->setIcon(loadIcon("16/document-save.png")); + actionSave_As->setIcon(loadIcon("16/document-save-as.png")); + action_Exit->setIcon(loadIcon("exit.png")); + action_Run->setIcon(loadIcon("ok.png")); + + action_Open->setShortcut(tr("Ctrl+O")); + action_Save->setShortcut(tr("Ctrl+S")); + action_Run->setShortcut(Qt::Key_F9); + actionRun_As_Console->setShortcut(Qt::CTRL + Qt::Key_F9); + + commandEdit->setTabStopWidth(qRound(commandEdit->fontPointSize() * 4)); + + // install syntax highlighter. + new SyntaxHighlighter(commandEdit); + + languageChange(); + commandEdit_cursorPositionChanged(); + + // welcome note + QString welcomeText("\"\"\""); + welcomeText += tr("Scribus Python Console"); + welcomeText += "\n\n"; + welcomeText += tr( + "This is a standard Python console with some \n" + "known limitations. Please consult the Scribus \n" + "Scripter documentation for futher information. "); + welcomeText += "\"\"\"\n"; + commandEdit->setText(welcomeText); + commandEdit->selectAll(); + + connect(commandEdit, SIGNAL(cursorPositionChanged()), this, SLOT(commandEdit_cursorPositionChanged())); + connect(commandEdit->document(), SIGNAL(modificationChanged(bool)), this, SLOT(documentChanged(bool))); + + connect(action_Open, SIGNAL(triggered()), this, SLOT(slot_open())); + connect(action_Save, SIGNAL(triggered()), this, SLOT(slot_save())); + connect(actionSave_As, SIGNAL(triggered()), this, SLOT(slot_saveAs())); + connect(action_Exit, SIGNAL(triggered()), this, SLOT(slot_quit())); + connect(action_Run, SIGNAL(triggered()), this, SLOT(slot_runScript())); + connect(actionRun_As_Console, SIGNAL(triggered()), this, SLOT(slot_runScriptAsConsole())); + connect(action_Save_Output, SIGNAL(triggered()), this, SLOT(slot_saveOutput())); +} + +PythonConsole::~PythonConsole() +{ +} + +void PythonConsole::updateSyntaxHighlighter() +{ + new SyntaxHighlighter(commandEdit); +} + +void PythonConsole::setFonts() +{ + QFont font = QFont("Fixed"); + font.setStyleHint(QFont::TypeWriter); + font.setPointSize(PrefsManager::instance()->appPrefs.AppFontSize); + commandEdit->setFont(font); + outputEdit->setFont(font); +} + +void PythonConsole::closeEvent(QCloseEvent *) +{ + emit paletteShown(false); +} + +void PythonConsole::commandEdit_cursorPositionChanged() +{ + QTextCursor cur(commandEdit->textCursor()); + cursorLabel->setText(cursorTemplate.arg(cur.columnNumber()+1) + .arg(cur.blockNumber()+1) + .arg(commandEdit->document()->blockCount())); +} + +void PythonConsole::documentChanged(bool state) +{ + changedLabel->setText(state ? "*" : " "); +} + +void PythonConsole::languageChange() +{ + Ui::PythonConsole::retranslateUi(this); + //setWindowTitle( tr("Script Console")); + commandEdit->setToolTip( "<qt>" + tr("Write your commands here. A selection is processed as script") + "</qt>"); + outputEdit->setToolTip( "<qt>" + tr("Output of your script") + "</qt>"); +} + +void PythonConsole::slot_runScript() +{ + outputEdit->clear(); + parsePythonString(); + emit runCommand(); + commandEdit->textCursor().movePosition(QTextCursor::Start); +} + +void PythonConsole::slot_runScriptAsConsole() +{ + parsePythonString(); + commandEdit->clear(); + // content is destroyed. This is to prevent overwriting + filename = QString::null; + outputEdit->append("\n>>> " + m_command); + emit runCommand(); +} + +void PythonConsole::parsePythonString() +{ + if (commandEdit->textCursor().hasSelection()) + m_command = commandEdit->textCursor().selectedText(); + else + { + commandEdit->selectAll(); + m_command = commandEdit->textCursor().selectedText(); + } + // Per Qt doc, "If the selection obtained from an editor spans a line break, the text + // will contain a Unicode U+2029 paragraph separator character instead of a newline" + m_command.replace(QChar(0x2029), QChar('\n')); + // prevent user's wrong selection + m_command += '\n'; +} + +/* + * supplementary slots. Saving etc. + */ +void PythonConsole::slot_open() +{ + filename = QFileDialog::getOpenFileName(this, + tr("Open Python Script File"), + ".", + tr("Python Scripts (*.py *.PY)")); + if (filename.isNull()) + return; + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) + { + QTextStream stream(&file); + commandEdit->setPlainText(stream.readAll()); + file.close(); + } +} + +void PythonConsole::slot_save() +{ + if (filename.isNull()) + { + slot_saveAs(); + return; + } + QFile f(filename); + if (f.open(QIODevice::WriteOnly)) + { + QTextStream stream(&f); + stream << commandEdit->toPlainText(); + f.close(); + } +} + +void PythonConsole::slot_saveAs() +{ + QString oldFname = filename; + QString dirName = QDir::homePath(); + if (!filename.isEmpty()) + { + QFileInfo fInfo(filename); + QDir fileDir = fInfo.absoluteDir(); + if (fileDir.exists()) + dirName = fileDir.absolutePath(); + } + filename = QFileDialog::getSaveFileName(this, + tr("Save the Python Commands in File"), + dirName, + tr("Python Scripts (*.py *.PY)")); + if (filename.isEmpty()) + { + filename = oldFname; + return; + } + // #10070 : not needed QFileDialog::getSaveFileName() will ask overwrite confirmation by itself + /*if (QFile::exists(filename)) + { + QString fn = QDir::toNativeSeparators(filename); + if (ScMessageBox::warning(this, CommonStrings::trWarning, + "<qt>" + tr(QString("File %1 already exists. Do you want to replace it?").arg(fn).toLocal8Bit().constData()) + "</qt>", + QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) + { + filename = oldFname; + return; + } + }*/ + slot_save(); +} + +void PythonConsole::slot_saveOutput() +{ + QString dname = QDir::homePath(); + QString fname = QFileDialog::getSaveFileName(this, + tr("Save Current Output"), + dname, + tr("Text Files (*.txt)")); + if (fname.isEmpty()) + return; + QFile f(fname); + // #10070 : not needed QFileDialog::getSaveFileName() will ask overwrite confirmation by itself + /*if (f.exists()) + { + QString fn = QDir::toNativeSeparators(filename); + if (QMessageBox::warning(this, CommonStrings::trWarning, + "<qt>" + tr(QString("File %1 already exists. Do you want to replace it?").arg(fn).toLocal8Bit().constData()) + "</qt>", + QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) + return; + }*/ + // save + if (f.open(QIODevice::WriteOnly)) + { + QTextStream stream(&f); + stream << outputEdit->toPlainText(); + f.close(); + } +} + +void PythonConsole::slot_quit() +{ + emit paletteShown(false); +} + +/* + * Syntax highlighting + */ +SyntaxHighlighter::SyntaxHighlighter(QTextEdit *textEdit) : QSyntaxHighlighter(textEdit) +{ + // Reserved keywords in Python 2.4 + QStringList keywords; + HighlightingRule rule; + + keywords << "and" << "assert" << "break" << "class" << "continue" << "def" + << "del" << "elif" << "else" << "except" << "exec" << "finally" + << "for" << "from" << "global" << "if" << "import" << "in" + << "is" << "lambda" << "not" << "or" << "pass" << "print" << "raise" + << "return" << "try" << "while" << "yield"; + + keywordFormat.setForeground(colors.keywordColor); + keywordFormat.setFontWeight(QFont::Bold); + singleLineCommentFormat.setForeground(colors.commentColor); + singleLineCommentFormat.setFontItalic(true); + quotationFormat.setForeground(colors.stringColor); + numberFormat.setForeground(colors.numberColor); + operatorFormat.setForeground(colors.signColor); + + foreach (QString kw, keywords) + { + rule.pattern = QRegExp("\\b" + kw + "\\b", Qt::CaseInsensitive); + rule.format = keywordFormat; + highlightingRules.append(rule); + } + + rule.pattern = QRegExp("#[^\n]*"); + rule.format = singleLineCommentFormat; + highlightingRules.append(rule); + + rule.pattern = QRegExp("\'.*\'"); + rule.pattern.setMinimal(true); + rule.format = quotationFormat; + highlightingRules.append(rule); + + rule.pattern = QRegExp("\".*\""); + rule.pattern.setMinimal(true); + rule.format = quotationFormat; + highlightingRules.append(rule); + + rule.pattern = QRegExp("\\b\\d+\\b"); + rule.pattern.setMinimal(true); + rule.format = numberFormat; + highlightingRules.append(rule); + + rule.pattern = QRegExp("[\\\\|\\<|\\>|\\=|\\!|\\+|\\-|\\*|\\/|\\%]+"); + rule.pattern.setMinimal(true); + rule.format = operatorFormat; + highlightingRules.append(rule); +} + +void SyntaxHighlighter::highlightBlock(const QString &text) +{ + // Apply default text color + setFormat(0, text.length(), colors.textColor); + + foreach (HighlightingRule rule, highlightingRules) + { + QRegExp expression(rule.pattern); + int index = expression.indexIn(text); + while (index >= 0) + { + int length = expression.matchedLength(); + setFormat(index, length, rule.format); + index = expression.indexIn(text, index + length); + } + } + setCurrentBlockState(0); + + // multiline strings handling + int startIndex = 0; + if (previousBlockState() != 1) + startIndex = text.indexOf("\"\"\""); + + while (startIndex >= 0) + { + int endIndex = text.indexOf("\"\"\"", startIndex); + int commentLength; + + if (endIndex == -1) + { + setCurrentBlockState(1); + commentLength = text.length() - startIndex; + } + else + { + commentLength = endIndex - startIndex + 3;//commentEndExpression.matchedLength(); + } + setFormat(startIndex, commentLength, quotationFormat); + startIndex = text.indexOf("\"\"\"", startIndex + commentLength); + } +} + +SyntaxColors::SyntaxColors() +{ + PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin"); + errorColor.setNamedColor(prefs->get("syntaxerror", "#aa0000")); + commentColor.setNamedColor(prefs->get("syntaxcomment", "#A0A0A0")); + keywordColor.setNamedColor(prefs->get("syntaxkeyword", "#00007f")); + signColor.setNamedColor(prefs->get("syntaxsign", "#aa00ff")); + numberColor.setNamedColor(prefs->get("syntaxnumber", "#ffaa00")); + stringColor.setNamedColor(prefs->get("syntaxstring", "#005500")); + textColor.setNamedColor(prefs->get("syntaxtext", "#000000")); +} + +void SyntaxColors::saveToPrefs() +{ + PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin"); + if (prefs) + { + prefs->set("syntaxerror", qcolor2named(errorColor)); + prefs->set("syntaxcomment", qcolor2named(commentColor)); + prefs->set("syntaxkeyword", qcolor2named(keywordColor)); + prefs->set("syntaxsign", qcolor2named(signColor)); + prefs->set("syntaxnumber", qcolor2named(numberColor)); + prefs->set("syntaxstring", qcolor2named(stringColor)); + prefs->set("syntaxtext", qcolor2named(textColor)); + } +} + +QString SyntaxColors::qcolor2named(QColor color) +{ + int r, g, b; + QString retval("#"); + QString oct; + color.getRgb(&r, &g, &b); + retval += oct.setNum(r, 16).rightJustified(2, '0'); + retval += oct.setNum(g, 16).rightJustified(2, '0'); + retval += oct.setNum(b, 16).rightJustified(2, '0'); + return retval; +} diff --git a/scribus/plugins/scriptplugin/pconsole.h b/scribus/plugins/scriptplugin/pconsole.h new file mode 100644 index 0000000..9f614ac --- /dev/null +++ b/scribus/plugins/scriptplugin/pconsole.h @@ -0,0 +1,141 @@ +/* +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. +*/ +/* +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +*/ + +#ifndef PCONSOLE_H +#define PCONSOLE_H + +#include <QLabel> +#include <QMainWindow> +#include <QSyntaxHighlighter> +#include "ui_pconsole.h" + + +/*! \brief This is simple "IDE"/python console for interactive commands execution. +It's used e.g. like Tora (SQLnavigator) console. Sample: highlight some code, +press F9, then see the results. +\author Petr Vanek <petr@yarpen.cz> +*/ +class PythonConsole : public QMainWindow, public Ui::PythonConsole +{ + Q_OBJECT + + public: + PythonConsole( QWidget* parent = 0); + ~PythonConsole(); + + void setFonts(); + + /*! \brief The command string + \retval QString with prepared Python commands */ + QString command() { return m_command; }; + //! \brief File name for saving the contents + QString filename; + + //! \brief Close event for turning the action off + void closeEvent(QCloseEvent *); + + void updateSyntaxHighlighter(); + + public slots: + //! menu operations + virtual void slot_runScript(); + virtual void slot_runScriptAsConsole(); + virtual void slot_open(); + virtual void slot_save(); + virtual void slot_saveAs(); + virtual void slot_saveOutput(); + virtual void slot_quit(); + /*! \brief Slot processed after user change cursor postion in "programmer's editor". + */ + virtual void commandEdit_cursorPositionChanged(); + + signals: + //! \brief Menu indication trigger + void paletteShown(bool); + //! \brief Scripter Core launcher + void runCommand(); + + protected: + //! \brief prepare Python "script" from GUI widget + void parsePythonString(); + + //! \brief String with the script to run (part of the all text) + QString m_command; + + QLabel * changedLabel; + QLabel * cursorLabel; + QString cursorTemplate; + + protected slots: + virtual void languageChange(); + void documentChanged(bool state); + +}; + +/*! \brief Store colors for syntax highligter. +It provides defaults, loading and storing preferences. +\author Petr Vanek <petr@yarpen.cz> */ +class SyntaxColors +{ + public: + SyntaxColors(); + + QColor errorColor; + QColor commentColor; + QColor keywordColor; + QColor signColor; + QColor numberColor; + QColor stringColor; + QColor textColor; + + void saveToPrefs(); + + private: + /*! \brief Converts QColor into #rrggbb string. + \param color a QColor to convert. */ + QString qcolor2named(QColor color); +}; + +/*! \brief Simple syntax highlighting for Scripter (QTextEdit). +Based on the source of the Sqliteman and Qt4 examples. +but very simplifier. Improved too (of course). +TODO: colors of the higlited texts. User should set the colors in the + preferences. Waiting for the new plugin API. +\author Petr Vanek, <petr@yarpen.cz> +*/ +class SyntaxHighlighter : public QSyntaxHighlighter +{ + public: + SyntaxHighlighter(QTextEdit *textEdit); + + protected: + virtual void highlightBlock(const QString &text); + + struct HighlightingRule + { + QRegExp pattern; + QTextCharFormat format; + }; + QVector<HighlightingRule> highlightingRules; + + QTextCharFormat keywordFormat; + QTextCharFormat singleLineCommentFormat; + QTextCharFormat quotationFormat; + QTextCharFormat numberFormat; + QTextCharFormat operatorFormat; + + SyntaxColors colors; + +}; + +#endif diff --git a/scribus/plugins/scriptplugin/pconsole.ui b/scribus/plugins/scriptplugin/pconsole.ui new file mode 100644 index 0000000..f21c8ea --- /dev/null +++ b/scribus/plugins/scriptplugin/pconsole.ui @@ -0,0 +1,129 @@ +<ui version="4.0" > + <class>PythonConsole</class> + <widget class="QMainWindow" name="PythonConsole" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>535</width> + <height>471</height> + </rect> + </property> + <property name="windowTitle" > + <string>Script Console</string> + </property> + <widget class="QWidget" name="centralwidget" > + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <property name="horizontalSpacing" > + <number>6</number> + </property> + <property name="verticalSpacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QSplitter" name="splitter" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <widget class="QTextEdit" name="commandEdit" > + <property name="lineWrapMode" > + <enum>QTextEdit::NoWrap</enum> + </property> + </widget> + <widget class="QTextEdit" name="outputEdit" > + <property name="lineWrapMode" > + <enum>QTextEdit::NoWrap</enum> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + <property name="acceptRichText" > + <bool>false</bool> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>535</width> + <height>29</height> + </rect> + </property> + <widget class="QMenu" name="menu_File" > + <property name="title" > + <string>&File</string> + </property> + <addaction name="action_Open" /> + <addaction name="action_Save" /> + <addaction name="actionSave_As" /> + <addaction name="separator" /> + <addaction name="action_Exit" /> + </widget> + <widget class="QMenu" name="menu_Script" > + <property name="title" > + <string>&Script</string> + </property> + <addaction name="action_Run" /> + <addaction name="actionRun_As_Console" /> + <addaction name="action_Save_Output" /> + </widget> + <addaction name="menu_File" /> + <addaction name="menu_Script" /> + </widget> + <widget class="QStatusBar" name="statusbar" /> + <action name="action_Open" > + <property name="text" > + <string>&Open...</string> + </property> + </action> + <action name="action_Save" > + <property name="text" > + <string>&Save</string> + </property> + </action> + <action name="actionSave_As" > + <property name="text" > + <string>Save &As...</string> + </property> + </action> + <action name="action_Exit" > + <property name="text" > + <string>&Quit</string> + </property> + </action> + <action name="action_Run" > + <property name="text" > + <string>&Run</string> + </property> + </action> + <action name="actionRun_As_Console" > + <property name="text" > + <string>Run As &Console</string> + </property> + </action> + <action name="action_Save_Output" > + <property name="text" > + <string>&Save Output...</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> diff --git a/scribus/plugins/scriptplugin/runscriptdialog.cpp b/scribus/plugins/scriptplugin/runscriptdialog.cpp new file mode 100644 index 0000000..11d2ce8 --- /dev/null +++ b/scribus/plugins/scriptplugin/runscriptdialog.cpp @@ -0,0 +1,57 @@ +/* +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. +*/ +#include <QDir> +#include "runscriptdialog.h" +#include "prefsmanager.h" + +QString RunScriptDialog::m_lastScriptDir; + +RunScriptDialog::RunScriptDialog(QWidget* parent = 0, bool extEnable = false) : + QDialog(parent) +{ + setupUi(this); + + m_extEnable = extEnable; + PrefsManager *prefsManager = PrefsManager::instance(); + QString scriptDir = prefsManager->appPrefs.ScriptDir; + if (!m_lastScriptDir.isEmpty() && QDir(m_lastScriptDir).exists()) + fileWidget->setDirectory(m_lastScriptDir); + else if (!scriptDir.isEmpty() && QDir(scriptDir).exists()) + fileWidget->setDirectory(scriptDir); + else + fileWidget->setDirectory(QDir::current()); + fileWidget->setFilter( tr("Python Scripts (*.py *.PY);; All Files (*)")); + + if (!extEnable) + extChk->setVisible(false); + + connect(fileWidget, SIGNAL(accepted()), this, SLOT(accept())); + connect(fileWidget, SIGNAL(rejected()), this, SLOT(reject())); +} + +RunScriptDialog::~RunScriptDialog() +{ +} + +bool RunScriptDialog::extensionRequested() +{ + if (m_extEnable) + return extChk->isChecked(); + else + return false; +} + +QString RunScriptDialog::selectedFile() +{ + return fileWidget->selectedFile(); +} + +void RunScriptDialog:: accept() +{ + m_lastScriptDir = fileWidget->directory().path(); + QDialog::accept(); +} diff --git a/scribus/plugins/scriptplugin/runscriptdialog.h b/scribus/plugins/scriptplugin/runscriptdialog.h new file mode 100644 index 0000000..42bde94 --- /dev/null +++ b/scribus/plugins/scriptplugin/runscriptdialog.h @@ -0,0 +1,42 @@ +/* +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. +*/ +#ifndef _RUNSCRIPTDIALOG_H +#define _RUNSCRIPTDIALOG_H + +// Pulls in Python.h +// #include "cmdvar.h" +#include "ui_runscriptdialog.h" + + +/*! \brief Select a python script for execution. +\author Craig Ringer +\author Petr Vanek <petr@scribus.info> +*/ +class RunScriptDialog : public QDialog, public Ui::RunScriptDialog +{ + Q_OBJECT + + public: + RunScriptDialog(QWidget* parent, bool extEnable); + ~RunScriptDialog(); + + //! \brief Check if the user wanted the script run as an extension script + bool extensionRequested(); + //! \brief Return chosen filename + QString selectedFile(); + + protected: + // true id there is "scripter extensions" feature enabled + bool m_extEnable; + + static QString m_lastScriptDir; + + protected slots: + virtual void accept(); +}; + +#endif diff --git a/scribus/plugins/scriptplugin/runscriptdialog.ui b/scribus/plugins/scriptplugin/runscriptdialog.ui new file mode 100644 index 0000000..6bb413f --- /dev/null +++ b/scribus/plugins/scriptplugin/runscriptdialog.ui @@ -0,0 +1,81 @@ +<ui version="4.0" > + <class>RunScriptDialog</class> + <widget class="QDialog" name="RunScriptDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle" > + <string>Run Script</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="ScFileWidget" native="1" name="fileWidget" /> + </item> + <item row="1" column="0" > + <widget class="QCheckBox" name="extChk" > + <property name="text" > + <string>Run as Extension Script</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ScFileWidget</class> + <extends>QWidget</extends> + <header>scfilewidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>RunScriptDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>RunScriptDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/scribus/plugins/scriptplugin/samples/3columnA4.py b/scribus/plugins/scriptplugin/samples/3columnA4.py new file mode 100644 index 0000000..2609c72 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/3columnA4.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Creates 3 column layout on A4 paper and save it under 3columnA4.sla filename. This is a simple way to demonstrate creating a doc on the fly. """ + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +def main(argv): + """This is a simple way to demonstrate creating a doc on the fly. """ + + pass # <--- Delete this line +######################### +# YOUR IMPORTS GO HERE # +######################### + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +margins = (50, 50, 50, 50) +size = (612, 792) + +def main(): + if newDocument(PAPER_A4, margins, LANDSCAPE, 1, UNIT_POINTS, NOFACINGPAGES, FIRSTPAGELEFT,1): + a = createText(50, 50, 230, 495) + setTextAlignment(1,a) + setText("Column A", a) + setFontSize(12, a) + b = createText(280, 50, 230, 495) + setTextAlignment(1,b) + setText("Column B", b) + setFontSize(12, b) + c = createText(510, 50, 230, 495) + setTextAlignment(1,b) + setText("Column C", c) + setFontSize(12, c) + saveDocAs("3columnA4.sla") + + +if __name__ == '__main__': + main() diff --git a/scribus/plugins/scriptplugin/samples/3columnUSLTR.py b/scribus/plugins/scriptplugin/samples/3columnUSLTR.py new file mode 100644 index 0000000..0148bac --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/3columnUSLTR.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Creates 3 column layout on US Letter paper and save it under 3columnUSLTR.sla filename. This is a simple way to demonstrate creating a doc on the fly. """ + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +def main(argv): + """This is a simple way to demonstrate creating a doc on the fly. """ + + pass # <--- Delete this line + + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +margins = (50, 50, 50, 50) +size = (612, 792) + +def main(): + if newDocument(PAPER_LETTER, margins, LANDSCAPE, 1, UNIT_POINTS, NOFACINGPAGES, FIRSTPAGELEFT, 1): + a = createText(50, 50, 230, 512) + setTextAlignment(1,a) + setText("Column A", a) + setFontSize(12, a) + b = createText(280, 50, 230, 512) + setTextAlignment(1,b) + setText("Column B", b) + setFontSize(12, b) + c = createText(510, 50, 230, 512) + setTextAlignment(1,b) + setText("Column C", c) + setFontSize(12, c) + #saveDocAs("3columnUS.sla") + + +if __name__ == '__main__': + main() diff --git a/scribus/plugins/scriptplugin/samples/CMakeLists.txt b/scribus/plugins/scriptplugin/samples/CMakeLists.txt new file mode 100644 index 0000000..a7bf662 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/CMakeLists.txt @@ -0,0 +1,22 @@ +INCLUDE_DIRECTORIES( +"${CMAKE_SOURCE_DIR}/scribus" +) + +INSTALL(FILES +3columnUSLTR.py +3columnA4.py +boilerplate.py +Calender.py +ExtractText.py +golden-mean.py +legende.py +moins_10_pourcent_group.py +plus_10_pourcent_group.py +pochette_cd.py +quote.py +sample_db_usage.py +Sample1.py +trait_de_coupe.py +wordcount.py + DESTINATION ${SAMPLESDIR} +) diff --git a/scribus/plugins/scriptplugin/samples/Calender.py b/scribus/plugins/scriptplugin/samples/Calender.py new file mode 100644 index 0000000..2d80546 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/Calender.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" This Script creates a Calendar Sheet for the Current Month """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +import calendar +import time + +def main(): + Month = time.localtime()[1] + Year = time.localtime()[0] + Objects = [] + MonthList = ["January","February","March","April","May","June","July","August","September","October","November","December"] + DaysList = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"] + Xcoor = 10 + Ycoor = 30 + DayC = 0 + Calend = calendar.monthcalendar(Year, Month) + ob = createText(10, 10, 245, 20) + Title = MonthList[Month-1] + " " + str(Year) + setText(Title, ob) + Objects.append(ob) + for lx in range(45, 245, 35): + ob = createLine(lx, 30, lx, 20*len(Calend)+50) + Objects.append(ob) + for ly in range(50, 20*len(Calend)+50, 20): + ob = createLine(10, ly, 255, ly) + Objects.append(ob) + ob = createRect(10, 30, 245, 20*len(Calend)+20) + setFillColor("None", ob) + Objects.append(ob) + for day in range(7): + ob = createText(Xcoor, Ycoor, 35, 20) + setTextAlignment(ALIGN_CENTERED, ob) + setFontSize(12, ob) + if day == 6: + setTextColor("Red", ob) + setText(DaysList[day], ob) + Objects.append(ob) + Xcoor = Xcoor + 35 + Ycoor = Ycoor + 20 + for lines in Calend: + Xcoor = 10 + DayC = 0 + for rows in lines: + if rows != 0: + ob = createText(Xcoor, Ycoor, 35, 20) + setTextAlignment(ALIGN_CENTERED, ob) + if DayC == 6: + setTextColor("Red", ob) + setText(str(rows), ob) + Objects.append(ob) + Xcoor = Xcoor + 35 + DayC = DayC + 1 + Ycoor = Ycoor + 20 + groupObjects(Objects) + +if __name__ == '__main__': + if haveDoc(): + try: + setRedraw(False) + main() + finally: + setRedraw(True) + redrawAll() + else: + messageBox("Calendar Script", "Please run this script with a document open.", ICON_INFORMATION); diff --git a/scribus/plugins/scriptplugin/samples/ExtractText.py b/scribus/plugins/scriptplugin/samples/ExtractText.py new file mode 100644 index 0000000..506174f --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/ExtractText.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + +(C)2006.03.04 Gregory Pittman + +(C)2008.02.28 Petr Vanek - fileDialog replaces valueDialog + +this version 2008.02.28 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GPL, v2 (GNU General Public License as published by +the Free Software Foundation, version 2 of the License), or any later version. +See the Scribus Copyright page in the Help Browser for further informaton +about GPL, v2. + +SYNOPSIS + +This script takes the current document and extracts all the text from text frames, +and also gets the pathnames to all images. This is then saved to a file named +by the user. + +REQUIREMENTS + +You must run from Scribus and must have a file open. + +USAGE + +Start the script. A file dialog appears for the name of the file +to save to. The above information is saved to the file. + +""" +# Craig Bradney, Scribus Team +# 10/3/08: Added to Scribus 1.3.3.12svn distribution "as was" from Scribus wiki for bug #6826, script is GPLd + +import scribus + + +def exportText(textfile): + page = 1 + pagenum = scribus.pageCount() + T = [] + content = [] + while (page <= pagenum): + scribus.gotoPage(page) + d = scribus.getPageItems() + strpage = str(page) + T.append('Page '+ strpage + '\n\n') + for item in d: + if (item[1] == 4): + contents = scribus.getAllText(item[0]) + if (contents in content): + contents = 'Duplication, perhaps linked-to frame' + T.append(item[0]+': '+ contents + '\n\n') + content.append(contents) + elif (item[1] == 2): + imgname = scribus.getImageFile(item[0]) + T.append(item[0]+': ' + imgname + '\n') + page += 1 + T.append('\n') + output_file = open(textfile,'w') + output_file.writelines(T) + output_file.close() + endmessage = textfile + ' was created' + scribus.messageBox("Finished", endmessage,icon=0,button1=1) + + +if scribus.haveDoc(): + textfile = scribus.fileDialog('Enter name of file to save to', \ + filter='Text Files (*.txt);;All Files (*)') + try: + if textfile == '': + raise Exception + exportText(textfile) + except Exception, e: + print e + +else: + scribus.messageBox('Export Error', 'You need a Document open, and a frame selected.', \ + icon=0, button1=1) diff --git a/scribus/plugins/scriptplugin/samples/ReadMe b/scribus/plugins/scriptplugin/samples/ReadMe new file mode 100644 index 0000000..377258e --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/ReadMe @@ -0,0 +1,22 @@ +This folder contains some Example Scripts: + +3columnA4.py = Sample 3 column layout +3columnUSLTR.py = Sample 3 column layout +Calender.py = Creates a Calendar of the current Month in the current Document as a Group +ReadMe = this file +Sample1.py = Very simple Example, creates a Docmument with some Objects, saves the Document and closes it. +boilerplate.py = A template for your scripts +golden-mean.py = Creates a non printable marks in the Golden Mean of the page. +legende.py = Creates a legende for Image (filename) +moins_10_pourcent_group.py = Decrease size of the object by 10% +plus_10_pourcent_group.py = Increase size of the object by 10% +pochette_cd.py = Creates a CD/DVD pochette +quote.py = French quotation marks +sample_db_usage.py = Database HOWTO +trait_de_coupe.py +wordcount.py = Counts the count of the words :) + +Copy these Examples to any location you like and play with them. +Each script contains Docstring in the file header - this is a common Python +documentation text. You can see it by selecting Script->About Script... menu +entry. diff --git a/scribus/plugins/scriptplugin/samples/Sample1.py b/scribus/plugins/scriptplugin/samples/Sample1.py new file mode 100644 index 0000000..5205543 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/Sample1.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" A sample script """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +margins = (10, 10, 10, 30) + +def main(): + if newDocument(PAPER_A4, margins, PORTRAIT, 1, UNIT_POINTS, NOFACINGPAGES, FIRSTPAGERIGHT, 1): + a = createText(50, 50, 200, 80) + setText("A Test for Scribus", a) + setFontSize(20, a) + b = createEllipse(267, 391, 60, 60) + setFillColor("Red", b) + saveDocAs("Sample1.sla") + +if __name__ == '__main__': + main() diff --git a/scribus/plugins/scriptplugin/samples/boilerplate.py b/scribus/plugins/scriptplugin/samples/boilerplate.py new file mode 100644 index 0000000..85e3b5b --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/boilerplate.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +######################### +# YOUR IMPORTS GO HERE # +######################### + +def main(argv): + """This is a documentation string. Write a description of what your code + does here. You should generally put documentation strings ("docstrings") + on all your Python functions.""" + ######################### + # YOUR CODE GOES HERE # + ######################### + pass # <--- Delete this line + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + scribus.statusMessage("Running script...") + scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage("") + scribus.progressReset() + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) diff --git a/scribus/plugins/scriptplugin/samples/golden-mean.py b/scribus/plugins/scriptplugin/samples/golden-mean.py new file mode 100644 index 0000000..f180f94 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/golden-mean.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Golden Mean for Scribus. + +This script creates supplementary guides on the page to +help design the "right" layout in golden mean (golden +ratio). + +See scribus.net and CVS for fresh versions to come... + +REQUIREMENTS: +Scribus - CVS version later 02/24/2004 or later release 1.5 + +MORE INFO: +See e.g. +http://home.att.net/~vmueller/prop/theo.html +or Google for more theory :) + +CONTACT: +email : petr@yarpen.cz +Feature requests and bug reports welcomed + + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +from math import sqrt + + +def goldenMean(aSize=0): + """x = (?5-1)/2""" + return aSize * ((sqrt(5) - 1)/2) + + +def main(): + # remember user settings + unit = getUnit() + # set my environment - points needed + setUnit(0) + # Paper format + paper = pageDimension() + # set the guides. The get* functions are for "remembering" the old ones... + setVGuides(getVGuides() + [goldenMean(paper[0]), paper[0] - goldenMean(paper[0])]) + setHGuides(getHGuides() + [goldenMean(paper[1]), paper[1] - goldenMean(paper[1])]) + # restore user settings + setUnit(unit) + +if __name__ == '__main__': + if haveDoc(): + main() + else: + messageBox("Golden Mean.py", "Please run this script with a document already open", ICON_INFORMATION); diff --git a/scribus/plugins/scriptplugin/samples/legende.py b/scribus/plugins/scriptplugin/samples/legende.py new file mode 100644 index 0000000..933bc7b --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/legende.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" When you have an image selected this script creates small text legende +(caption) below the image. The new textframe contains name of the file. """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +import os + +def main(): + userUnit = getUnit() + setUnit(1) + sel_count = selectionCount() + + if sel_count == 0: + messageBox("legende.py", + "Please select the object to add a caption to before running this script.", + ICON_INFORMATION) + sys.exit(1) + + x,y = getPosition() + l,h = getSize() + texte = getImageFile() + image = os.path.basename(texte) + a = createText(x,y+h+2,l,8) + insertText(image,0,a) + setTextAlignment(2,a) + setFontSize(7,a) + setUnit(userUnit) + +if __name__ == '__main__': + main() diff --git a/scribus/plugins/scriptplugin/samples/moins_10_pourcent_group.py b/scribus/plugins/scriptplugin/samples/moins_10_pourcent_group.py new file mode 100644 index 0000000..c1ee6ef --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/moins_10_pourcent_group.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Make selected group smaller by 10% """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +if haveDoc() and selectionCount(): + scaleGroup(1/1.1) +else: + messageBox("moins_10_pourcent_group.py", "Please select an object to scale before running this script.", ICON_INFORMATION) diff --git a/scribus/plugins/scriptplugin/samples/plus_10_pourcent_group.py b/scribus/plugins/scriptplugin/samples/plus_10_pourcent_group.py new file mode 100644 index 0000000..36d174e --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/plus_10_pourcent_group.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Make selected group larger by 10% """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +if haveDoc() and selectionCount(): + scaleGroup(1.1) +else: + messageBox("plus_10_pourcent_group.py", "Please select an object to scale before running this script.", ICON_INFORMATION) diff --git a/scribus/plugins/scriptplugin/samples/pochette_cd.py b/scribus/plugins/scriptplugin/samples/pochette_cd.py new file mode 100644 index 0000000..0b8700c --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/pochette_cd.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" This script creates a CD Pochette - a paper pocket for CD/DVD disc """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +margins = (0, 0, 0, 0) +paper = (210, 297) + +def main(): + if newDocument(paper, margins, 1, 1, 1, NOFACINGPAGES, FIRSTPAGELEFT,1): + setUnit(1) + newPage(-1) + gotoPage(1) + createLayer("normal") + setActiveLayer("normal") + a = createText(98.5, 20, 100, 10) + setText("CD pochette - front page", a) + setFontSize(11, a) + setTextAlignment(1, a) + b = createText(28.5, 45, 120, 120) + setFillColor("None", b) + c = createText(148.5, 45, 120, 120) + setFillColor("None", c) + createLayer("bords_perdus") + setActiveLayer("bords_perdus") + img1 = createImage(24.35, 41.25 , 124.20, 127.95,) + img2 = createImage(148.55, 41.25 , 124.20, 127.95,) + createLayer("coupe") + setActiveLayer("coupe") + t1 = createLine(28.5, 38, 28.5, 43) + setLineWidth(0.1, t1) + t2 = createLine(148.5, 38, 148.5, 43) + setLineWidth(0.1, t2) + t3 = createLine(268.5, 38, 268.5, 43) + setLineWidth(0.1, t3) + t4 = createLine(28.5, 172, 28.5, 167) + setLineWidth(0.1, t4) + t5 = createLine(148.5, 172, 148.5, 167) + setLineWidth(0.1, t5) + t6 = createLine(268.5, 172, 268.5, 167) + setLineWidth(0.1, t6) + t7 = createLine(21.5, 45, 26.5, 45) + setLineWidth(0.1, t7) + t8 = createLine(21.5, 165, 26.5, 165) + setLineWidth(0.1, t8) + t9 = createLine(270.5, 45, 275.5, 45) + setLineWidth(0.1, t9) + t10 = createLine(270.5, 165, 275.5, 165) + setLineWidth(0.1, t10) + gotoPage(2) + setActiveLayer("normal") + a2 = createText(98.5, 20, 100, 10) + setText("CD pochette - back page", a2) + setFontSize(11, a2) + setTextAlignment(1, a2) + a2t = createText(204, 44, 78, 9) + setText("Mode d'emploi :", a2t) + setFontSize(13, a2t) + setTextAlignment(1, a2t) + a21 = createText(204, 54, 78, 87) + setText("Usage. TODO: tranlslate it from french", a21) + setFontSize(11, a21) + setTextAlignment(0, a21) + b2 = createText(28.5, 162.10, 117, 6) + setText("Texte sur la tranche", b2) + setFontSize(9, b2) + setTextAlignment(1, b2) + rotateObjectAbs(90, b2) + setFillColor("None", b2) + c2 = createText(34.5, 45, 137.5, 117) + setFillColor("None", c2) + d2 = createText(28.5, 162.10, 117, 6) + setText("Texte sur la tranche", d2) + setFontSize(9, d2) + setTextAlignment(1, d2) + rotateObjectAbs(90, d2) + setFillColor("None", d2) + moveObject(143.5, 0, d2) + setActiveLayer("bords_perdus") + img3 = createImage(24.35, 41.25 , 157.50, 126.50,) + setActiveLayer("coupe") + t21 = createLine(28.5, 38, 28.5, 43) + setLineWidth(0.1, t21) + t22 = createLine(34.5, 38, 34.5, 43) + setLineWidth(0.1, t22) + t23 = createLine(172, 38, 172, 43) + setLineWidth(0.1, t23) + t24 = createLine(178, 38, 178, 43) + setLineWidth(0.1, t24) + t25 = createLine(28.5, 164.5, 28.5, 169.5) + setLineWidth(0.1, t25) + t26 = createLine(34.5, 164, 34.5, 169.5) + setLineWidth(0.1, t26) + t27 = createLine(172, 164, 172, 169.5) + setLineWidth(0.1, t27) + t28 = createLine(178, 164, 178, 169.5) + setLineWidth(0.1, t28) + t29 = createLine(22.5, 45, 27.5, 45) + setLineWidth(0.1, t29) + t30 = createLine(22.5, 162, 27.5, 162) + setLineWidth(0.1, t30) + t31 = createLine(179.5, 45, 184.5, 45) + setLineWidth(0.1, t31) + t32 = createLine(179.5, 162, 184.5, 162) + setLineWidth(0.1, t32) + saveDocAs("pochette_CD.sla") + +if __name__ == '__main__': + main() diff --git a/scribus/plugins/scriptplugin/samples/quote.py b/scribus/plugins/scriptplugin/samples/quote.py new file mode 100644 index 0000000..aee0337 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/quote.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- + +""" This script changes quotation marks from " " to french style """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +import re + +TITLE = "Text quoting" + +# These need to be declared as unicode strings until some +# charset issues in the scripter are worked out. +QUOTE_START = u"" +QUOTE_END = u"" + +def quote(textobj): + quoted_re = re.compile('"[^"]*"') + try: + text = getText(textobj) + except WrongFrameTypeError: + messageBox("quote.py", "Cannot quote text in a non-text frame", ICON_INFORMATION); + sys.exit(1) + if len(text) == 0: + return 0 # We can't very well change anything in an empty frame + count = 0 + i = 0 + selectText(0, 0, textobj) + while i < len(text): + match = quoted_re.match(text[i:]) + if match: + end = match.end() + selectText(i, 1, textobj) + deleteText(textobj) + insertText(QUOTE_START, i, textobj) + selectText(i + end - 1, 1, textobj) + deleteText(textobj) + insertText(QUOTE_END, i + end - 1, textobj) + count += 1 + i = i + end + else: + i = i + 1 + return count + + +def main(): + changed = 0 + sel_count = selectionCount() + if sel_count: + for i in range(sel_count): + changed += quote(getSelectedObject(i)) + else: + for page in range(pageCount()): + gotoPage(page) + for obj in getAllObjects(): + changed += quote(obj) + messageBox(TITLE, "%s quotations changed" % changed, + ICON_INFORMATION, BUTTON_OK) + +if __name__ == '__main__': + if haveDoc(): + try: + setRedraw(False) + main() + finally: + setRedraw(True) + redrawAll() + else: + messageBox(TITLE, "No document open", ICON_WARNING, BUTTON_OK) diff --git a/scribus/plugins/scriptplugin/samples/sample_db_usage.py b/scribus/plugins/scriptplugin/samples/sample_db_usage.py new file mode 100644 index 0000000..2b8ef1e --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/sample_db_usage.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""OK. This is a sample Scribus database connection with Python HOWTO. + +DESCRIPTION: +I've got questions about DB and Scribus in my personal mailbox 3-4 +times in a month. So this is an common answer for asking people. + +Even through I'm an Oracle user/developer I choose MySQL for this +example, because of its presence in the Linux distributions and +hosting availability too. +But the DB server doesn't matter due the PEP 249 - standard DB interface +(http://www.python.org/peps/pep-0249.html). +There are various modules for database accessing: +http://www.python.org/topics/database/modules.html + +Anyway - this script provides connection to the database server by the +specified values in the hostname, dbname, username, and password variables. +Then it checks the system for table names in the specified databases +and it displays it in the new document finally. Easy and understandable. + + +CONTACT: +email : petr@yarpen.cz + + +LICENSE: +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" + +import sys + +# environment checking +try: + import scribus +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +try: + import MySQLdb +except ImportError: + print "You must have 'MySQLdb' installed." + sys.exit(1) + + +# connection parameters +hostname = 'server.foo.org' +dbname = 'name' +username = 'username' +password = 'password' + +# connection to the network wide server would be time consuming. So get the hint to the user. +scribus.statusMessage('Connecting to the ' + hostname + ' server. Be patient, please...') + +# Database related issues +try: + conn = MySQLdb.connect(passwd=password, db=dbname, host=hostname, user=username) +except: + scribus.messageBox('DB connection example', 'Connection error. You should specify your login in the script') + sys.exit(1) + +cur = conn.cursor() +# get the list of the databases +# it's like 'select * from dba_tables' in Oracle +count = cur.execute('show tables') +# formating the output +result = str(count) + ' table(s) in the ' + dbname + ' database.\n\n' +for i in cur.fetchall(): + result = result + i[0] + '\n' + +# Scribus presentation part +scribus.newDoc(scribus.PAPER_A5, (10, 10, 20, 20), scribus.PORTRAIT, 1, scribus.UNIT_POINTS, scribus.NOFACINGPAGES, scribus.FIRSTPAGERIGHT) +txtName = scribus.createText(10, 10, 200, 200) +scribus.setText(result, txtName) + +scribus.statusMessage('Script done.') diff --git a/scribus/plugins/scriptplugin/samples/trait_de_coupe.py b/scribus/plugins/scriptplugin/samples/trait_de_coupe.py new file mode 100644 index 0000000..12ad789 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/trait_de_coupe.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Draws a "crop marks" around selected object """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +def main(): + userUnit = getUnit() + setUnit(1) + x,y = getPosition() + l,h = getSize() + t1 = createLine(x, y-2, x, y-7) + setLineWidth(0.1, t1) + t2 = createLine(x+l, y-2, x+l, y-7) + setLineWidth(0.1, t2) + t3 = createLine(x, y+7+h, x, y+2+h) + setLineWidth(0.1, t3) + t4 = createLine(x+l, y+7+h, x+l, y+2+h) + setLineWidth(0.1, t4) + t5 = createLine(x-2, y, x-7, y) + setLineWidth(0.1, t5) + t6 = createLine(x-2, y+h, x-7, y+h) + setLineWidth(0.1, t6) + t7 = createLine(x+l+2, y+h, x+l+7, y+h) + setLineWidth(0.1, t7) + t7 = createLine(x+l+2, y, x+l+7, y) + setLineWidth(0.1, t7) + deselectAll() + setUnit(userUnit) + +if __name__ == '__main__': + if haveDoc() and selectionCount(): + main() + else: + messageBox("trait_de_coupe.py", "Please select an object to put crop marks around<i>before</i> running this script.", ICON_INFORMATION) diff --git a/scribus/plugins/scriptplugin/samples/wordcount.py b/scribus/plugins/scriptplugin/samples/wordcount.py new file mode 100644 index 0000000..de372d6 --- /dev/null +++ b/scribus/plugins/scriptplugin/samples/wordcount.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Counts the words in the whole document or in a textframe """ + +import sys + +try: + from scribus import * +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) + +import re + +TITLE = "Word count" + +def wordsplit(text): + word_pattern = "([A-Za-zäöüÄÖÜß]+)" + words = [] + for x in re.split(word_pattern, text): + if re.match(word_pattern, x): + words.append(x) + return words + + +def main(): + words = 0 + sel_count = selectionCount() + if sel_count: + source = "selected textframe" + if sel_count > 1: source += "s" #plural + for i in range(sel_count): + try: + text = getText(getSelectedObject(i)) + words += len(wordsplit(text)) + except WrongFrameTypeError: + if sel_count == 1: + # If there's only one object selected, display a message + messageBox(TITLE, "Can't count words in a non-text frame", ICON_INFORMATION); + sys.exit(1) + else: + # otherwise ignore + pass + else: + source = "whole document" + for page in range(1,pageCount() + 1): + gotoPage(page) + for obj in getAllObjects(): + try: + text = getText(obj) + words += len(wordsplit(text)) + except WrongFrameTypeError: + pass # ignore the error, it just wasn't a frame we can count + + if words == 0: words = "No" + messageBox(TITLE, "%s words counted in %s" % (words, source), + ICON_INFORMATION) + + +if __name__ == '__main__': + if haveDoc(): + main() + else: + messageBox(TITLE, "No document open", ICON_WARNING) diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_base.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_base.cpp new file mode 100644 index 0000000..e6f1100 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_base.cpp @@ -0,0 +1,85 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribusstructs.h" + +using namespace boost::python; + +// Declare the export functions from the implementation +extern void export_QString(); +extern void export_QObject(); +extern void export_QWidget(); +extern void export_QFrame(); +extern void export_QScrollView(); +extern void export_QMainWindow(); +extern void export_QApplication(); + +extern void export_ScribusStructs(); +extern void export_PageItem(); +extern void export_ScribusMainWindow(); +extern void export_ScribusQApp(); +extern void export_ScribusWin(); +extern void export_ScribusDoc(); +extern void export_ScribusView(); + +extern void export_styles(); + +/** + * @brief A simple test function to wrap with Boost::Python + */ +int add_five(int x) +{ + return x+5; +} + +/** + * @brief Define the scribus2 module + */ +BOOST_PYTHON_MODULE(scribus2) +{ + qDebug("Exporting scribus2"); + + // Export our basic testing function + def("add_five", add_five); + + // Export type converters + export_QString(); + + // And Qt classes + export_QObject(); + export_QApplication(); + export_QWidget(); + export_QFrame(); + export_QScrollView(); + export_QMainWindow(); + + // Export Scribus types + export_ScribusStructs(); + export_ScribusQApp(); + export_ScribusDoc(); + export_ScribusView(); + export_ScribusWin(); + export_ScribusMainWindow(); + export_PageItem(); + + // Export access functions and dirty hacks + export_styles(); + + qDebug("Done"); +} + +/** + * @brief Initialize the module, including calling initscribus2() + * + * This method should be a no-op if we've been built without support + * for Boost::Python + */ +void scripter2_init() +{ + initscribus2(); +} diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qapplication.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qapplication.cpp new file mode 100644 index 0000000..9a7d088 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qapplication.cpp @@ -0,0 +1,37 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QSpplication> + +//BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(QApplication_processEvents_overloads, QApplication::processEvents, 0, 1) + +void QApplication_processEvents(QApplication& app) +{ + app.processEvents(); +} + +void QApplication_processEventsT(QApplication& app, int maxtime) +{ + app.processEvents(maxtime); +} + +void export_QApplication() +{ + using namespace boost::python; + + class_<QApplication,boost::noncopyable>( + "QApplication", + "The base Qt application class", + no_init) + //.def("exec", &QApplication::exec); // BAD PLAN to expose this + //.def("processEvents", &QApplication::processEvents); + .def("processEvents", &QApplication_processEvents) + .def("processEventsT", &QApplication_processEventsT); + + scope().attr("qApp") = boost::ref(qApp); +} diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qframe.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qframe.cpp new file mode 100644 index 0000000..84ef8b7 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qframe.cpp @@ -0,0 +1,20 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QFrame> + +void export_QFrame() +{ + using namespace boost::python; + + class_<QFrame,bases<QWidget>,boost::noncopyable>( + "QFrame", + "A generic Qt frame widget"); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qmainwindow.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qmainwindow.cpp new file mode 100644 index 0000000..d6b6091 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qmainwindow.cpp @@ -0,0 +1,20 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QMainWindow> + +void export_QMainWindow() +{ + using namespace boost::python; + + class_<QMainWindow,bases<QWidget>,boost::noncopyable>( + "QMainWindow", + "A Qt main window widget"); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qobject.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qobject.cpp new file mode 100644 index 0000000..013fe51 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qobject.cpp @@ -0,0 +1,22 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QWidget> + + + +void export_QObject() +{ + using namespace boost::python; + + class_<QObject, boost::noncopyable>( + "QObject", + "A generic Qt object"); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qscrollview.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qscrollview.cpp new file mode 100644 index 0000000..e8ff1f8 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qscrollview.cpp @@ -0,0 +1,21 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QScrollView> +#include <QFrame> + +void export_QScrollView() +{ + using namespace boost::python; + + class_<QScrollView,bases<QFrame>,boost::noncopyable>( + "QScrollView", + "A generic Qt scroll view widget"); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qwidget.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qwidget.cpp new file mode 100644 index 0000000..4a25c89 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qtclass_qwidget.cpp @@ -0,0 +1,24 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QWidget> + + + +void export_QWidget() +{ + using namespace boost::python; + + class_<QWidget,bases<QObject>,boost::noncopyable>( + "QWidget", + "A generic Qt widget") + .def("show", &QWidget::show) + .def("hide", &QWidget::hide); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_qttype_qstring.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_qttype_qstring.cpp new file mode 100644 index 0000000..8672ddd --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_qttype_qstring.cpp @@ -0,0 +1,124 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include <QString> +#include <wchar.h> + + + +// Shamelessly cribbed from code in python-qt4 +// Originally by Eric Jardim <ericjardim@gmail.com> +// Rewritten by Craig Ringer <craig@postnewspapers.com.au> +// Ported to Scribus and Qt3 by Craig Ringer <craig@postnewspapers.com.au> + +using namespace boost::python; +/** + * @brief Boost::Python type converter for QString to Python `unicode' object + */ +struct QString_to_python_unicode +{ + static PyObject* + convert(QString const& s) + { + //FIXME: Done with Python/C API, needs Boost::Python-ifying + //FIXME: UCS-4 case can probably be done a lot more effciently. +#if defined(Py_UNICODE_WIDE) + //qDebug("Py_UNICODE_WIDE"); + int unichars = s.length(); + Py_UNICODE* buf = new Py_UNICODE[unichars]; + for (int i = 0; i < unichars; i++) + buf[i] = s.at(i).unicode(); + PyObject* tempObj = PyUnicode_FromUnicode(buf, unichars); + delete[] buf; + return tempObj; +#else + return PyUnicode_FromUnicode(s.utf16(), s.length()); +#endif + } +}; + + +/** + * @brief Boost::Python type converter for Python `unicode' or `str' to QString + */ +struct QString_from_python_str_or_unicode +{ + QString_from_python_str_or_unicode() + { + boost::python::converter::registry::push_back( &convertible, + &construct, + boost::python::type_id<QString>() ); + } + + static void* + convertible(PyObject* obj_ptr) + { + if (! (PyUnicode_Check(obj_ptr) || PyString_Check(obj_ptr)) ) + return 0; + return obj_ptr; + } + + static void + construct( PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + // First, convert the input to Python `unicode'. + PyObject* temp_obj_ptr; + if (PyString_Check(obj_ptr)) + { + // Coerce the `str' to `unicode' using sysdefaultencoding. UnicodeDecodeError + // is thrown if the string doesn't make sense in that encoding. + temp_obj_ptr = PyUnicode_FromObject(obj_ptr); // new reference + if (temp_obj_ptr == 0) + { + boost::python::throw_error_already_set(); + } + } + else + { + temp_obj_ptr = obj_ptr; + Py_INCREF(temp_obj_ptr); // to balance DECREF at end + } + + // FIXME: This implementation is probably rather inefficient + Py_UNICODE* value = PyUnicode_AsUnicode(temp_obj_ptr); + if (value == 0) + { + boost::python::throw_error_already_set(); + } + int unichars = PyUnicode_GET_SIZE(temp_obj_ptr); +#if defined(Py_UNICODE_WIDE) + + // Python is using a 4-byte unsigned buffer of UCS-4 + // FIXME: Qt doesn't give us any direct way to load UCS-4, so we're doing + // it a rather clunky way that can probably be improved. + // FIXME: Qt can't represent UCS-4 characters; we need to check for this + // and throw an exception. + QString tempString(""); + int i; + for (i = 0; i < unichars; i++) + tempString.append(QChar(value[i])); +#else + // Python is using a 2-byte unsigned buffer of UCS-2 with + // limited support for UTF-16 + QString tempString(QString::fromUtf16(value, unichars)); +#endif + Py_DECREF(temp_obj_ptr); + void* storage = ((boost::python::converter::rvalue_from_python_storage<QString>*) data)->storage.bytes; + new (storage) QString(tempString); + data->convertible = storage; + } +}; + +void export_QString() +{ + boost::python::to_python_converter<QString, QString_to_python_unicode>(); + QString_from_python_str_or_unicode(); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp new file mode 100644 index 0000000..4d0c1f2 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_pageitem.cpp @@ -0,0 +1,302 @@ +/* +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. +*/ +#include "cmdvar.h" + + + +#include "scribus.h" +#include "scribusdoc.h" +#include "pageitem.h" +#include <QList> + +using boost::python::list; +using boost::python::throw_error_already_set; + +PageItem & findItemByName(QList<PageItem*> & items, const QString name) +{ + for ( + QList<PageItem*>::iterator it(items.begin()) ; + it != items.end() ; + ++it) + { + if ( (*it)->itemName() == name) + return *(*it); + } + PyErr_SetString(PyExc_KeyError, "Item not found"); + throw_error_already_set(); +} + +PageItem & getItem(const QString name) +{ + return findItemByName(ScCore->primaryMainWindow()->doc->DocItems, name); +} + +list getItemNames() +{ + list l; + QList<PageItem*>& items( ScCore->primaryMainWindow()->doc->DocItems ); + for ( + QList<PageItem*>::iterator it(items.begin()) ; + it != items.end() ; + ++it) + { + l.append((*it)->itemName()); + } + return l; +} + +void export_PageItem() +{ + using namespace boost::python; + + def("getItemNames", getItemNames); + def("getItem", getItem, return_internal_reference<>()); + + { + scope p = class_<PageItem,boost::noncopyable>( + "PageItem", + "A Scribus canvas object", + no_init) + .def("clearContents", &PageItem::clearContents) + .def("AdjustPictScale", &PageItem::AdjustPictScale) + //TODO Needs: ObjAttrVector, Problem: pointer return + //.def("getObjectAttributes", &PageItem::getObjectAttributes, + //TODO Needs: ObjectAttribute + .def("getObjectAttribute", &PageItem::getObjectAttribute) + .def("setObjectAttributes", &PageItem::setObjectAttributes) + .def("SetFrameShape", &PageItem::SetFrameShape) + .def("SetRectFrame", &PageItem::SetRectFrame) + .def("SetOvalFrame", &PageItem::SetOvalFrame) + .def("SetFrameRound", &PageItem::SetFrameRound) + .def("SetPolyClip", &PageItem::SetPolyClip) + .def("getBoundingRect", &PageItem::getBoundingRect) + .def("pointWithinItem", &PageItem::pointWithinItem) + //.def("SetZeichAttr", &PageItem::SetZeichAttr) // WTF? + .def("SetFarbe", &PageItem::SetFarbe) + .def_readwrite("AspectRatio", &PageItem::AspectRatio) + .def_readwrite("AutoName", &PageItem::AutoName) + .def_readwrite("BottomLine", &PageItem::BottomLine) + .def_readwrite("ChangedMasterItem", &PageItem::ChangedMasterItem) + .def_readwrite("ClipEdited", &PageItem::ClipEdited) + .def_readwrite("Dirty", &PageItem::Dirty) + .def_readwrite("fillRule", &PageItem::fillRule) + .def_readwrite("Frame", &PageItem::Frame) + .def_readwrite("FrameOnly", &PageItem::FrameOnly) + .def_readwrite("HasSel", &PageItem::HasSel) + .def_readwrite("isAutoText", &PageItem::isAutoText) + .def_readwrite("isBookmark", &PageItem::isBookmark) + .def_readwrite("isEmbedded", &PageItem::isEmbedded) + .def_readwrite("isRaster", &PageItem::isRaster) + .def_readwrite("isSingleSel", &PageItem::isSingleSel) + .def_readwrite("isTableItem", &PageItem::isTableItem) + .def_readwrite("LeftLine", &PageItem::LeftLine) + .def_readwrite("PicArt", &PageItem::PicArt) + .def_readwrite("PictureIsAvailable", &PageItem::PictureIsAvailable) + .def_readwrite("PoShow", &PageItem::PoShow) + .def_readwrite("Redrawn", &PageItem::Redrawn) + .def_readwrite("RightLine", &PageItem::RightLine) + .def_readwrite("ScaleType", &PageItem::ScaleType) + .def_readwrite("Sizing", &PageItem::Sizing) + .def_readwrite("Tinput", &PageItem::Tinput) + .def_readwrite("toPixmap", &PageItem::toPixmap) + .def_readwrite("TopLine", &PageItem::TopLine) + .def_readwrite("UseEmbedded", &PageItem::UseEmbedded) + .def_readwrite("BaseOffs", &PageItem::BaseOffs) + .def_readwrite("BBoxH", &PageItem::BBoxH) + .def_readwrite("BBoxX", &PageItem::BBoxX) + .def_readwrite("BoundingH", &PageItem::BoundingH) + .def_readwrite("BoundingW", &PageItem::BoundingW) + .def_readwrite("BoundingX", &PageItem::BoundingX) + .def_readwrite("BoundingY", &PageItem::BoundingY) + .def_readwrite("ColGap", &PageItem::ColGap) + .def_readwrite("CurX", &PageItem::CurX) + .def_readwrite("CurY", &PageItem::CurY) + .def_readwrite("DashOffset", &PageItem::DashOffset) + .def_readwrite("gHeight", &PageItem::gHeight) + .def_readwrite("GrEndX", &PageItem::GrEndX) + .def_readwrite("GrEndY", &PageItem::GrEndY) + .def_readwrite("GrStartX", &PageItem::GrStartX) + .def_readwrite("GrStartY", &PageItem::GrStartY) + .def_readwrite("gWidth", &PageItem::gWidth) + .def_readwrite("gXpos", &PageItem::gXpos) + .def_readwrite("gYpos", &PageItem::gYpos) + .def_readwrite("LineSp", &PageItem::LineSp) + .def_readwrite("OldB", &PageItem::OldB) + .def_readwrite("OldB2", &PageItem::OldB2) + .def_readwrite("OldH", &PageItem::OldH) + .def_readwrite("OldH2", &PageItem::OldH2) + .def_readwrite("OldPwidth", &PageItem::OldPwidth) + .def_readwrite("Pwidth", &PageItem::Pwidth) + .def_readwrite("ContourLine", &PageItem::ContourLine) + .def_readwrite("imageClip", &PageItem::imageClip) + .def_readwrite("PoLine", &PageItem::PoLine) + .def_readwrite("BottomLinkID", &PageItem::BottomLinkID) + .def_readwrite("Cols", &PageItem::Cols) + .def_readwrite("CPos", &PageItem::CPos) + .def_readwrite("ExtraV", &PageItem::ExtraV) + .def_readwrite("FrameType", &PageItem::FrameType) + .def_readwrite("GrType", &PageItem::GrType) + .def_readwrite("IRender", &PageItem::IRender) + .def_readwrite("LayerNr", &PageItem::LayerNr) + .def_readwrite("LeftLinkID", &PageItem::LeftLinkID) + .def_readwrite("LineSpMode", &PageItem::LineSpMode) + .def_readwrite("NextIt", &PageItem::NextIt) + .def_readwrite("NextPg", &PageItem::NextPg) + .def_readwrite("oldOwnPage", &PageItem::oldOwnPage) + .def_readwrite("OrigH", &PageItem::OrigH) + .def_readwrite("OrigW", &PageItem::OrigW) + .def_readwrite("OwnPage", &PageItem::OwnPage) + .def_readwrite("RightLinkID", &PageItem::RightLinkID) + .def_readwrite("ShTxtFill", &PageItem::ShTxtFill) + .def_readwrite("ShTxtStroke", &PageItem::ShTxtStroke) + .def_readwrite("textAlignment", &PageItem::textAlignment) + .def_readwrite("TopLinkID", &PageItem::TopLinkID) + .def_readwrite("TxtBase", &PageItem::TxtBase) + .def_readwrite("TxtOutline", &PageItem::TxtOutline) + .def_readwrite("TxtScale", &PageItem::TxtScale) + .def_readwrite("TxtScaleV", &PageItem::TxtScaleV) + .def_readwrite("TxtShadowX", &PageItem::TxtShadowX) + .def_readwrite("TxtShadowY", &PageItem::TxtShadowY) + .def_readwrite("TxtStrikePos", &PageItem::TxtStrikePos) + .def_readwrite("TxtStrikeWidth", &PageItem::TxtStrikeWidth) + .def_readwrite("TxTStyle", &PageItem::TxTStyle) + .def_readwrite("TxtUnderPos", &PageItem::TxtUnderPos) + .def_readwrite("TxtUnderWidth", &PageItem::TxtUnderWidth) + .def_readwrite("*BackBox", &PageItem::BackBox) + .def_readwrite("BottomLink", &PageItem::BottomLink) + .def_readwrite("LeftLink", &PageItem::LeftLink) + .def_readwrite("*NextBox", &PageItem::NextBox) + .def_readwrite("RightLink", &PageItem::RightLink) + .def_readwrite("TopLink", &PageItem::TopLink) + .def_readwrite("PLineEnd", &PageItem::PLineEnd) + .def_readwrite("PLineJoin", &PageItem::PLineJoin) + .def_readwrite("PLineArt", &PageItem::PLineArt) + .def_readwrite("Clip", &PageItem::Clip) + .def_readwrite("itemText", &PageItem::itemText) + .def_readwrite("EmProfile", &PageItem::EmProfile) + .def_readwrite("IProfile", &PageItem::IProfile) + .def_readwrite("Language", &PageItem::Language) + .def_readwrite("NamedLStyle", &PageItem::NamedLStyle) + .def_readwrite("OnMasterPage", &PageItem::OnMasterPage) + .def_readwrite("Pfile", &PageItem::Pfile) + .def_readwrite("Pfile2", &PageItem::Pfile2) + .def_readwrite("Pfile3", &PageItem::Pfile3) + .def_readwrite("TxtFill", &PageItem::TxtFill) + .def_readwrite("TxtStroke", &PageItem::TxtStroke) + .def_readwrite("DashValues", &PageItem::DashValues) + .def_readwrite("effectsInUse", &PageItem::effectsInUse) + .def_readwrite("TabValues", &PageItem::TabValues) + .def_readwrite("Segments", &PageItem::Segments) + .def_readwrite("Groups", &PageItem::Groups) + .def_readwrite("pixm", &PageItem::pixm) + .def_readwrite("ItemNr", &PageItem::ItemNr) + .def_readwrite("MaxChars", &PageItem::MaxChars) + .def_readwrite("fill_gradient", &PageItem::fill_gradient) + .add_property("xPos", &PageItem::xPos, &PageItem::setXPos) + .add_property("yPos", &PageItem::yPos, &PageItem::setYPos) + .def("moveBy", &PageItem::moveBy) + .add_property("width", &PageItem::width, &PageItem::setWidth) + .add_property("height", &PageItem::height, &PageItem::setHeight) + .def("resizeBy", &PageItem::resizeBy) + // TODO: Weird error + //.def("rotation", &PageItem::rotation) + .def("setRotation", &PageItem::setRotation) + .def("rotateBy", &PageItem::rotateBy) + .add_property("selected", &PageItem::isSelected, &PageItem::setSelected) + .add_property("imageXscale", &PageItem::imageXScale, &PageItem::setImageXScale) + .add_property("imageYscale", &PageItem::imageYScale, &PageItem::setImageYScale) + .add_property("imageXOffset", &PageItem::imageXOffset, &PageItem::setImageXOffset) + .add_property("imageYOffset", &PageItem::imageYOffset, &PageItem::setImageYOffset) + .def("moveImageXYOffsetBy", &PageItem::moveImageXYOffsetBy) + .add_property("reversed", &PageItem::reversed, &PageItem::setReversed) + // TODO: Weird error + //.def("cornerRadius", &PageItem::cornerRadius) + .def("setCornerRadius", &PageItem::setCornerRadius) + .add_property("textToFrameDistLeft", &PageItem::textToFrameDistLeft, &PageItem::setTextToFrameDistLeft) + .add_property("textToFrameDistRight", &PageItem::textToFrameDistRight, &PageItem::setTextToFrameDistRight) + .add_property("textToFrameDistTop", &PageItem::textToFrameDistTop, &PageItem::setTextToFrameDistTop) + .add_property("textToFrameDistBottom", &PageItem::textToFrameDistBottom, &PageItem::setTextToFrameDistBottom) + .def("setTextToFrameDist", &PageItem::setTextToFrameDist) + .add_property("itemName", &PageItem::itemName, &PageItem::setItemName) + .add_property("fillColor", &PageItem::fillColor, &PageItem::setFillColor) + .add_property("fillShade", &PageItem::fillShade, &PageItem::setFillShade) + .add_property("fillTransparency", &PageItem::fillTransparency, &PageItem::setFillTransparency) + .add_property("lineColor", &PageItem::lineColor, &PageItem::setLineColor) + .add_property("lineShade", &PageItem::lineShade, &PageItem::setLineShade) + .add_property("lineTransparency", &PageItem::lineTransparency, &PageItem::setLineTransparency) + .add_property("setLineQColor", &PageItem::setLineQColor, &PageItem::setFillQColor) + .def("lineStyle", &PageItem::lineStyle) + // TODO: weird error + //.def("setLineStyle", &PageItem::setLineStyle) + // TODO: weird error + //.def("lineWidth", &PageItem::lineWidth) + .def("setLineWidth", &PageItem::setLineWidth) + .add_property("lineEnd", &PageItem::lineEnd, &PageItem::setLineEnd) + .add_property("lineJoin", &PageItem::lineJoin, &PageItem::setLineJoin) + .add_property("customLineStyle", &PageItem::customLineStyle, &PageItem::setCustomLineStyle) + .add_property("startArrowIndex", &PageItem::startArrowIndex, &PageItem::setStartArrowIndex) + .add_property("endArrowIndex", &PageItem::endArrowIndex, &PageItem::setEndArrowIndex) + .add_property("imageFlippedH", &PageItem::imageFlippedH, &PageItem::setImageFlippedH) + .def("flipImageH", &PageItem::flipImageH) + .add_property("imageFlippedV", &PageItem::imageFlippedV, &PageItem::setImageFlippedV) + .def("flipImageV", &PageItem::flipImageV) + .def("setImageScalingMode", &PageItem::setImageScalingMode) + .def("toggleLock", &PageItem::toggleLock) + .add_property("locked", &PageItem::locked, &PageItem::setLocked) + .def("toggleSizeLock", &PageItem::toggleSizeLock) + .add_property("sizeLocked", &PageItem::sizeLocked, &PageItem::setSizeLocked) + .add_property("font", &PageItem::font, &PageItem::setFont) + .add_property("fontSize", &PageItem::fontSize, &PageItem::setFontSize) + .add_property("fontHeight", &PageItem::fontHeight, &PageItem::setFontHeight) + .add_property("fontWidth", &PageItem::fontWidth, &PageItem::setFontWidth) + .add_property("fontFillColor", &PageItem::fontFillColor, &PageItem::setFontFillColor) + .add_property("fontFillShade", &PageItem::fontFillShade, &PageItem::setFontFillShade) + .add_property("fontStrokeColor", &PageItem::fontStrokeColor, &PageItem::setFontStrokeColor) + .add_property("fontStrokeShade", &PageItem::fontStrokeShade, &PageItem::setFontStrokeShade) + .add_property("fontEffects", &PageItem::fontEffects, &PageItem::setFontEffects) + .add_property("kerning", &PageItem::kerning, &PageItem::setKerning) + // TODO: weird error + //.def("lineSpacing", &PageItem::lineSpacing) + .def("setLineSpacing", &PageItem::setLineSpacing) + .add_property("language", &PageItem::language, &PageItem::setLanguage) + .add_property("textFlowMode", &PageItem::textFlowMode, &PageItem::setTextFlowMode) + .def("itemType", &PageItem::itemType) + .def("convertTo", &PageItem::convertTo) + .def("setLayer", &PageItem::setLayer) + .add_property("printable", &PageItem::printable, &PageItem::setPrintable) + .def("loadImage", &PageItem::loadImage) + .add_property("isAnnotation", &PageItem::isAnnotation, &PageItem::setIsAnnotation) + .def("annotation", &PageItem::annotation, return_internal_reference<>()); + + enum_<PageItem::ItemType>("ItemType") + .value("ImageFrame", PageItem::ImageFrame) + .value("ImageFrame", PageItem::ImageFrame) + .value("TextFrame", PageItem::TextFrame) + .value("Line", PageItem::Line) + .value("Polygon", PageItem::Polygon) + .value("PolyLine", PageItem::PolyLine) + .value("PathText", PageItem::PathText) + .export_values(); + + enum_<PageItem::ItemFrameType>("ItemFrameType") + .value("Unspecified", PageItem::Unspecified) + .value("Rectangle", PageItem::Rectangle) + .value("Ellipse", PageItem::Ellipse) + .value("Round", PageItem::Round) + .value("Other", PageItem::Other) + .export_values(); + + class_<PageItem::TabRecord>("TabRecord") + .def_readwrite("tabPosition", &PageItem::TabRecord::tabPosition) + .def_readwrite("tabType", &PageItem::TabRecord::tabType) + .add_property("tabFillChar", make_getter(&PageItem::TabRecord::tabFillChar, return_value_policy<return_by_value>()), + make_setter(&PageItem::TabRecord::tabFillChar, return_value_policy<return_by_value>())); + + } // end scope p +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusdoc.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusdoc.cpp new file mode 100644 index 0000000..0f41339 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusdoc.cpp @@ -0,0 +1,36 @@ +/* +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. +*/ +#include "cmdvar.h" + +using boost::python::list; +using boost::python::throw_error_already_set; + +/* +PageItemList getDocItems(ScribusDoc & doc) +{ + return PageItemList(doc.DocItems); +} + +PageItemList getMasterItems(ScribusDoc & doc) +{ + return PageItemList(doc.MasterItems); +} +*/ + +void export_ScribusDoc() +{ + using namespace boost::python; + + scope d = class_<ScribusDoc, bases<QObject>, boost::noncopyable>("ScribusDoc", + "A Scribus document", + no_init) + .add_property("isModified", &ScribusDoc::isModified, &ScribusDoc::setModified); + /* + .add_property("items", &getDocItems) + .add_property("masterPageItems", &getMasterItems); + */ +} diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusmainwin.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusmainwin.cpp new file mode 100644 index 0000000..d9c9d74 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusmainwin.cpp @@ -0,0 +1,29 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribus.h" +#include "scribuswin.h" +#include "scribusdoc.h" +#include "scribusview.h" + +void export_ScribusMainWindow() +{ + using namespace boost::python; + + class_<ScribusMainWindow, bases<QWidget>, boost::noncopyable>( + "ScribusMainWindow", + "The app's main window, which also provides much of its core functionality", + no_init) + .add_property("doc", make_getter(&ScribusMainWindow::doc, return_internal_reference<>())) + .add_property("view", make_getter(&ScribusMainWindow::view, return_internal_reference<>())) + .add_property("ActWin", make_getter(&ScribusMainWindow::ActWin, return_internal_reference<>())); + + scope().attr("ScMW") = boost::ref(ScMW); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusqapp.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusqapp.cpp new file mode 100644 index 0000000..2191492 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusqapp.cpp @@ -0,0 +1,29 @@ +/* +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. +*/ +#include "cmdvar.h" + + + +#include "scribusapp.h" + +extern ScribusQApp* ScQApp; + +void export_ScribusQApp() +{ + using namespace boost::python; + + class_<ScribusQApp, bases<QApplication>, boost::noncopyable>("ScribusQApp", + "The core application", + no_init) + .add_property("usingGUI", &ScribusQApp::usingGUI) + .add_property("isMacGUI", &ScribusQApp::isMacGUI) + .add_property("reverseDialogButtons", &ScribusQApp::reverseDialogButtons); + + scope().attr("ScQApp") = boost::ref(ScQApp); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusview.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusview.cpp new file mode 100644 index 0000000..8e53506 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribusview.cpp @@ -0,0 +1,20 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribusdoc.h" + +void export_ScribusView() +{ + using namespace boost::python; + + scope w = class_<ScribusView, bases<QScrollView>, boost::noncopyable>("ScribusView", + "The document display canvas", + no_init); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribuswin.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribuswin.cpp new file mode 100644 index 0000000..eee9171 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribus_scribuswin.cpp @@ -0,0 +1,18 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribuswin.h" + +void export_ScribusWin() +{ + using namespace boost::python; + + class_<ScribusWin, bases<QMainWindow>, boost::noncopyable>("ScribusWin", + "A Scribus document window", + no_init); +} diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_scribusstructs.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_scribusstructs.cpp new file mode 100644 index 0000000..eb2e6ef --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_scribusstructs.cpp @@ -0,0 +1,67 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribusstructs.h" + + +using namespace boost::python; + +/** + * @brief Wrap the ParagraphStyle class + */ +void export_ParagraphStyle() +{ + class_<ParagraphStyle>("ParagraphStyle") +// .def_readwrite("Vname", &ParagraphStyle::Vname) + .add_property("Vname", make_getter(&ParagraphStyle::Vname, return_value_policy<return_by_value>()), + make_setter(&ParagraphStyle::Vname, return_value_policy<return_by_value>())) + .def_readwrite("LineSpaMode", &ParagraphStyle::LineSpaMode) + .def_readwrite("LineSpa", &ParagraphStyle::LineSpa) + .def_readwrite("textAlignment", &ParagraphStyle::textAlignment) + .def_readwrite("Indent", &ParagraphStyle::Indent) + .def_readwrite("First", &ParagraphStyle::First) + .def_readwrite("gapBefore", &ParagraphStyle::gapBefore) + .def_readwrite("gapAfter", &ParagraphStyle::gapAfter) +// .def_readwrite("Font", &ParagraphStyle::Font) + .add_property("Font", make_getter(&ParagraphStyle::Font, return_value_policy<return_by_value>()), + make_setter(&ParagraphStyle::Font, return_value_policy<return_by_value>())) + .def_readwrite("FontSize", &ParagraphStyle::FontSize) + .def_readwrite("TabValues", &ParagraphStyle::TabValues) + .def_readwrite("Drop", &ParagraphStyle::Drop) + .def_readwrite("DropLin", &ParagraphStyle::DropLin) + .def_readwrite("DropDist", &ParagraphStyle::DropDist) + .def_readwrite("FontEffect", &ParagraphStyle::FontEffect) +// .def_readwrite("FColor", &ParagraphStyle::FColor) + .add_property("FColor", make_getter(&ParagraphStyle::FColor, return_value_policy<return_by_value>()), + make_setter(&ParagraphStyle::FColor, return_value_policy<return_by_value>())) + .def_readwrite("FShade", &ParagraphStyle::FShade) +// .def_readwrite("SColor", &ParagraphStyle::SColor) + .add_property("SColor", make_getter(&ParagraphStyle::SColor, return_value_policy<return_by_value>()), + make_setter(&ParagraphStyle::SColor, return_value_policy<return_by_value>())) + .def_readwrite("SShade", &ParagraphStyle::SShade) + .def_readwrite("BaseAdj", &ParagraphStyle::BaseAdj) + .def_readwrite("txtShadowX", &ParagraphStyle::txtShadowX) + .def_readwrite("txtShadowY", &ParagraphStyle::txtShadowY) + .def_readwrite("txtOutline", &ParagraphStyle::txtOutline) + .def_readwrite("txtUnderPos", &ParagraphStyle::txtUnderPos) + .def_readwrite("txtUnderWidth", &ParagraphStyle::txtUnderWidth) + .def_readwrite("txtStrikePos", &ParagraphStyle::txtStrikePos) + .def_readwrite("txtStrikeWidth", &ParagraphStyle::txtStrikeWidth) + .def_readwrite("scaleH", &ParagraphStyle::scaleH) + .def_readwrite("scaleV", &ParagraphStyle::scaleV) + .def_readwrite("baseOff", &ParagraphStyle::baseOff) + .def_readwrite("kernVal", &ParagraphStyle::kernVal) + ; +} + +void export_ScribusStructs() +{ + export_ParagraphStyle(); +} + + diff --git a/scribus/plugins/scriptplugin/scripter2/scripter2_styles.cpp b/scribus/plugins/scriptplugin/scripter2/scripter2_styles.cpp new file mode 100644 index 0000000..f5d6dda --- /dev/null +++ b/scribus/plugins/scriptplugin/scripter2/scripter2_styles.cpp @@ -0,0 +1,113 @@ +/* +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. +*/ +#include "cmdvar.h" + +#include "scribusstructs.h" +#include "scribusdoc.h" +#include "scribus.h" +#include <QList> + +// This file contains some basic methods for testing purposes, +// providing access to the docParagraphStyles member of the current +// ScribusDoc. It's a dirty hack that won't stay around. +// +// This will probably need to be replaced with a fake mapping class, since the +// styles are actually stored in a rather clumsy QValueList. + + + +using namespace boost::python; + +ParagraphStyle & getStyleRef(const QString & styleName) +{ + QList<ParagraphStyle>::iterator it(ScCore->primaryMainWindow()->doc->docParagraphStyles.begin()); + QList<ParagraphStyle>::iterator itEnd(ScCore->primaryMainWindow()->doc->docParagraphStyles.end()); + for ( ; it != itEnd; ++it) + { + if ((*it).Vname == styleName) + return *it; + } + throw "Style not found"; +} + +ParagraphStyle & getStyleRefi(int index) +{ + return ScCore->primaryMainWindow()->doc->docParagraphStyles[index]; +} + +ParagraphStyle getStyleVal(const QString & styleName) +{ + return getStyleRef(styleName); +} + +ParagraphStyle getStyleVali(int index) +{ + return getStyleRefi(index); +} + +void addStyle(const ParagraphStyle & style) +{ + QList<ParagraphStyle>::iterator it(ScCore->primaryMainWindow()->doc->docParagraphStyles.begin()); + QList<ParagraphStyle>::iterator itEnd(ScCore->primaryMainWindow()->doc->docParagraphStyles.end()); + for ( ; it != itEnd; ++it) + { + if ((*it).Vname == style.Vname) + throw "Style of same name already exists"; + } + ScCore->primaryMainWindow()->doc->docParagraphStyles.append(style); +} + +// This returns a COPY of the paragraph styles; modifications to this list do +// NOT affect the real paragraph style list. That'll have to happen much later, +// probably with a "fake mapping" class wrapper around the docParagraphStyles +// list, since we don't want Python users seeing the int-indexed list. +dict getStylesVal() +{ + dict d; + QList<ParagraphStyle>::iterator it(ScCore->primaryMainWindow()->doc->docParagraphStyles.begin()); + QList<ParagraphStyle>::iterator itEnd(ScCore->primaryMainWindow()->doc->docParagraphStyles.end()); + for ( ; it != itEnd; ++it) + d[(*it).Vname] = *it; + return d; +} + +dict getStylesRef() +{ + dict d; + QList<ParagraphStyle>::iterator it(ScCore->primaryMainWindow()->doc->docParagraphStyles.begin()); + QList<ParagraphStyle>::iterator itEnd(ScCore->primaryMainWindow()->doc->docParagraphStyles.end()); + for ( ; it != itEnd; ++it) + d[(*it).Vname] = boost::ref(*it); + return d; +} + +list getStyleNames() +{ + list l; + QList<ParagraphStyle>::iterator it(ScCore->primaryMainWindow()->doc->docParagraphStyles.begin()); + QList<ParagraphStyle>::iterator itEnd(ScCore->primaryMainWindow()->doc->docParagraphStyles.end()); + for ( ; it != itEnd; ++it) + l.append((*it).Vname); + return l; +} + +void nothing() { } + + +void export_styles() +{ + def("getStyleRef", getStyleRef, return_internal_reference<>()); + def("getStyleVal", getStyleVal); + def("getStyleRefi", getStyleRefi, return_internal_reference<>()); + def("getStyleVali", getStyleVali); + def("addStyle", addStyle); + def("getStylesVal", getStylesVal); + def("getStylesRef", getStylesRef); + def("getStyleNames", getStyleNames); +} + + diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp new file mode 100644 index 0000000..4bd8ba3 --- /dev/null +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -0,0 +1,627 @@ +/* +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. +*/ +#include "scriptercore.h" + +#include <QGlobalStatic> +#include <QWidget> +#include <QString> +#include <QApplication> +#include <QMessageBox> +#include <QTextCodec> +#include <QByteArray> +#include <QPixmap> +#include <cstdlib> + +#include "runscriptdialog.h" +#include "helpbrowser.h" +#include "propertiespalette.h" //TODO Move the calls to this to a signal +#include "pagepalette.h" //TODO Move the calls to this to a signal +#include "layers.h" //TODO Move the calls to this to a signal +#include "outlinepalette.h" //TODO Move the calls to this to a signal +#include "menumanager.h" +#include "pconsole.h" +#include "scraction.h" +#include "scribuscore.h" +#include "scpaths.h" +#include "selection.h" +#include "prefsfile.h" +#include "prefscontext.h" +#include "prefstable.h" +#include "prefsmanager.h" + +ScripterCore::ScripterCore(QWidget* parent) +{ + pcon = new PythonConsole(parent); + scrScripterActions.clear(); + scrRecentScriptActions.clear(); + returnString = "init"; + + scrScripterActions.insert("scripterExecuteScript", new ScrAction(QObject::tr("&Execute Script..."), QKeySequence(), this)); + scrScripterActions.insert("scripterShowConsole", new ScrAction(QObject::tr("Show &Console"), QKeySequence(), this)); + scrScripterActions.insert("scripterAboutScript", new ScrAction(QObject::tr("&About Script..."), QKeySequence(), this)); + + scrScripterActions["scripterExecuteScript"]->setMenuRole(QAction::NoRole); + scrScripterActions["scripterShowConsole"]->setMenuRole(QAction::NoRole); + scrScripterActions["scripterAboutScript"]->setMenuRole(QAction::NoRole); + + scrScripterActions["scripterShowConsole"]->setToggleAction(true); + scrScripterActions["scripterShowConsole"]->setChecked(false); + + QObject::connect( scrScripterActions["scripterExecuteScript"], SIGNAL(triggered()) , this, SLOT(runScriptDialog()) ); + QObject::connect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) ); + QObject::connect( scrScripterActions["scripterAboutScript"], SIGNAL(triggered()) , this, SLOT(aboutScript()) ); + + SavedRecentScripts.clear(); + ReadPlugPrefs(); + + QObject::connect(pcon, SIGNAL(runCommand()), this, SLOT(slotExecute())); + QObject::connect(pcon, SIGNAL(paletteShown(bool)), this, SLOT(slotInteractiveScript(bool))); +} + +ScripterCore::~ScripterCore() +{ + SavePlugPrefs(); + delete pcon; +} + +void ScripterCore::addToMainWindowMenu(ScribusMainWindow *mw) +{ + menuMgr = mw->scrMenuMgr; + menuMgr->createMenu("Scripter", QObject::tr("&Script")); + menuMgr->addMenuToMenuBarBefore("Scripter","Windows"); + menuMgr->createMenu("ScribusScripts", QObject::tr("&Scribus Scripts"), "Scripter"); + menuMgr->addMenuItem(scrScripterActions["scripterExecuteScript"], "Scripter"); + menuMgr->createMenu("RecentScripts", QObject::tr("&Recent Scripts"), "Scripter"); + menuMgr->addMenuSeparator("Scripter"); + menuMgr->addMenuItem(scrScripterActions["scripterShowConsole"], "Scripter"); + menuMgr->addMenuItem(scrScripterActions["scripterAboutScript"], "Scripter"); + buildScribusScriptsMenu(); + buildRecentScriptsMenu(); +} + + +void ScripterCore::buildScribusScriptsMenu() +{ + QString pfad = ScPaths::instance().scriptDir(); + QString pfad2; + pfad2 = QDir::toNativeSeparators(pfad); + QDir ds(pfad2, "*.py", QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks); + if ((ds.exists()) && (ds.count() != 0)) + { + for (uint dc = 0; dc < ds.count(); ++dc) + { + QFileInfo fs(ds[dc]); + QString strippedName=fs.baseName(); + scrScripterActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, strippedName, QKeySequence(), this)); + connect( scrScripterActions[strippedName], SIGNAL(triggeredData(QString)), this, SLOT(StdScript(QString)) ); + menuMgr->addMenuItem(scrScripterActions[strippedName], "ScribusScripts"); + } + } + + +} + +void ScripterCore::rebuildRecentScriptsMenu() +{ + for( QMap<QString, QPointer<ScrAction> >::Iterator it = scrRecentScriptActions.begin(); it!=scrRecentScriptActions.end(); ++it ) + menuMgr->removeMenuItem((*it), "RecentScripts"); + + scrRecentScriptActions.clear(); + uint max = qMin(PrefsManager::instance()->appPrefs.RecentDCount, RecentScripts.count()); + for (uint m = 0; m < max; ++m) + { + QString strippedName=RecentScripts[m]; + strippedName.remove(QDir::separator()); + scrRecentScriptActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, RecentScripts[m], QKeySequence(), this)); + connect( scrRecentScriptActions[strippedName], SIGNAL(triggeredData(QString)), this, SLOT(RecentScript(QString)) ); + menuMgr->addMenuItem(scrRecentScriptActions[strippedName], "RecentScripts"); + } +} + +void ScripterCore::buildRecentScriptsMenu() +{ + RecentScripts = SavedRecentScripts; + scrRecentScriptActions.clear(); + if (SavedRecentScripts.count() != 0) + { + uint max = qMin(PrefsManager::instance()->appPrefs.RecentDCount, SavedRecentScripts.count()); + for (uint m = 0; m < max; ++m) + { + QFileInfo fd(SavedRecentScripts[m]); + if (fd.exists()) + { + QString strippedName=SavedRecentScripts[m]; + strippedName.remove(QDir::separator()); + scrRecentScriptActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, SavedRecentScripts[m], QKeySequence(), this)); + connect( scrRecentScriptActions[strippedName], SIGNAL(triggeredData(QString)), this, SLOT(RecentScript(QString)) ); + menuMgr->addMenuItem(scrRecentScriptActions[strippedName], "RecentScripts"); + } + } + } +} + +void ScripterCore::FinishScriptRun() +{ + ScribusMainWindow* ScMW=ScCore->primaryMainWindow(); + if (ScMW->HaveDoc) + { + ScMW->propertiesPalette->setDoc(ScMW->doc); + ScMW->layerPalette->setDoc(ScMW->doc); + ScMW->outlinePalette->setDoc(ScMW->doc); + ScMW->outlinePalette->BuildTree(); + ScMW->pagePalette->setView(ScMW->view); + ScMW->pagePalette->Rebuild(); + ScMW->doc->RePos = true; +/* QImage pgPix(10, 10, QImage::Format_ARGB32); + QRect rd = QRect(0,0,9,9); + ScPainter *painter = new ScPainter(&pgPix, pgPix.width(), pgPix.height()); + for (int azz=0; azz<ScMW->doc->Items->count(); ++azz) + { + PageItem *ite = ScMW->doc->Items->at(azz); + if (ite->Groups.count() != 0) + ScMW->doc->GroupOnPage(ite); + else + ite->OwnPage = ScMW->doc->OnPage(ite); + ite->setRedrawBounding(); + if ((ite->itemType() == PageItem::TextFrame) || (ite->itemType() == PageItem::PathText)) // && (!ite->Redrawn)) + { + if (ite->itemType() == PageItem::PathText) + { + ite->Frame = false; + ite->updatePolyClip(); + ite->DrawObj(painter, rd); + } + else + { + if ((ite->prevInChain() != 0) || (ite->nextInChain() != 0)) + { + PageItem *nextItem = ite; + while (nextItem->prevInChain() != 0) + nextItem = nextItem->prevInChain(); + ite = nextItem; + ite->DrawObj(painter, rd); + } + else + ite->DrawObj(painter, rd); + } + } + } + delete painter; */ + ScMW->doc->RePos = false; + if (ScMW->doc->m_Selection->count() != 0) + { + ScMW->doc->m_Selection->itemAt(0)->emitAllToGUI(); + ScMW->HaveNewSel(ScMW->doc->m_Selection->itemAt(0)->itemType()); + } + else + ScMW->HaveNewSel(-1); + ScMW->view->DrawNew(); + //CB Really only need (want?) this for new docs, but we need it after a call to ScMW doFileNew. + //We don't want it in cmddoc calls as itll interact with the GUI before a script may be finished. + ScMW->HaveNewDoc(); + } +} + +void ScripterCore::runScriptDialog() +{ + QString fileName; + QString curDirPath = QDir::currentPath(); + RunScriptDialog dia( ScCore->primaryMainWindow(), m_enableExtPython ); + if (dia.exec()) + { + fileName = dia.selectedFile(); + slotRunScriptFile(fileName, dia.extensionRequested()); + + if (RecentScripts.indexOf(fileName) == -1) + RecentScripts.prepend(fileName); + else + { + RecentScripts.removeAll(fileName); + RecentScripts.prepend(fileName); + } + rebuildRecentScriptsMenu(); + } + QDir::setCurrent(curDirPath); + FinishScriptRun(); +} + +void ScripterCore::StdScript(QString basefilename) +{ + QString pfad = ScPaths::instance().scriptDir(); + QString pfad2; + pfad2 = QDir::toNativeSeparators(pfad); + QString fn = pfad2+basefilename+".py"; + QFileInfo fd(fn); + if (!fd.exists()) + return; + slotRunScriptFile(fn); + FinishScriptRun(); +} + +void ScripterCore::RecentScript(QString fn) +{ + QFileInfo fd(fn); + if (!fd.exists()) + { + RecentScripts.removeAll(fn); + rebuildRecentScriptsMenu(); + return; + } + slotRunScriptFile(fn); + FinishScriptRun(); +} + +void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) +{ + PyThreadState *state = NULL; + QFileInfo fi(fileName); + QByteArray na = fi.fileName().toLocal8Bit(); + // Set up a sub-interpreter if needed: + PyThreadState* global_state = NULL; + if (!inMainInterpreter) + { + ScCore->primaryMainWindow()->propertiesPalette->unsetDoc(); + ScCore->primaryMainWindow()->pagePalette->setView(NULL); + ScCore->primaryMainWindow()->setScriptRunning(true); + qApp->changeOverrideCursor(QCursor(Qt::WaitCursor)); + // Create the sub-interpreter + // FIXME: This calls abort() in a Python debug build. We're doing something wrong. + //stateo = PyEval_SaveThread(); + global_state = PyThreadState_Get(); + state = Py_NewInterpreter(); + // Chdir to the dir the script is in + QDir::setCurrent(fi.absolutePath()); + // Init the scripter module in the sub-interpreter + initscribus(ScCore->primaryMainWindow()); + } + // Make sure sys.argv[0] is the path to the script + char* comm[2]; + comm[0] = na.data(); + // and tell the script if it's running in the main intepreter or + // a subinterpreter using the second argument, ie sys.argv[1] + if (inMainInterpreter) + comm[1] = const_cast<char*>("ext"); + else + comm[1] = const_cast<char*>("sub"); + PySys_SetArgv(2, comm); + // call python script + PyObject* m = PyImport_AddModule((char*)"__main__"); + if (m == NULL) + qDebug("Failed to get __main__ - aborting script"); + else + { + // Path separators need to be escaped on Windows + QString escapedAbsPath = QDir::toNativeSeparators(fi.absolutePath()).replace("\\", "\\\\"); + QString escapedFileName = QDir::toNativeSeparators(fileName).replace("\\", "\\\\"); + // FIXME: If filename contains chars outside 7bit ascii, might be problems + PyObject* globals = PyModule_GetDict(m); + // Build the Python code to run the script + //QString cm = QString("from __future__ import division\n"); removed due #5252 PV + QString cm = QString("import sys\n"); + cm += QString("import cStringIO\n"); + /* Implementation of the help() in pydoc.py reads some OS variables + * for output settings. I use ugly hack to stop freezing calling help() + * in script. pv. */ + cm += QString("import os\nos.environ['PAGER'] = '/bin/false'\n"); // HACK + cm += QString("sys.path.insert(0, \"%1\")\n").arg(escapedAbsPath); + // Replace sys.stdin with a dummy StringIO that always returns + // "" for read + cm += QString("sys.stdin = cStringIO.StringIO()\n"); + cm += QString("try:\n"); + cm += QString(" execfile(\"%1\")\n").arg(escapedFileName); + cm += QString("except SystemExit:\n"); + cm += QString(" pass\n"); + // Capture the text of any other exception that's raised by the interpreter + // into a StringIO buffer for later extraction. + cm += QString("except:\n"); + cm += QString(" import traceback\n"); + cm += QString(" import scribus\n"); // we stash our working vars here + cm += QString(" scribus._f=cStringIO.StringIO()\n"); + cm += QString(" traceback.print_exc(file=scribus._f)\n"); + cm += QString(" _errorMsg = scribus._f.getvalue()\n"); + cm += QString(" del(scribus._f)\n"); + // We re-raise the exception so the return value of PyRun_StringFlags reflects + // the fact that an exception has ocurred. + cm += QString(" raise\n"); + // FIXME: if cmd contains chars outside 7bit ascii, might be problems + QByteArray cmd = cm.toUtf8(); + // Now run the script in the interpreter's global scope. It'll run in a + // sub-interpreter if we created and switched to one earlier, otherwise + // it'll run in the main interpreter. + PyObject* result = PyRun_String(cmd.data(), Py_file_input, globals, globals); + // NULL is returned if an exception is set. We don't care about any + // other return value (most likely None anyway) and can ignore it. + if (result == NULL) + { + // We've already saved the exception text, so clear the exception + PyErr_Clear(); + PyObject* errorMsgPyStr = PyMapping_GetItemString(globals, (char*)"_errorMsg"); + if (errorMsgPyStr == NULL) + { + // It's rather unlikely that this will ever be reached - to get here + // we'd have to fail to retrive the string we just created. + qDebug("Error retrieving error message content after script exception!"); + qDebug("Exception was:"); + PyErr_Print(); + } + else + { + QString errorMsg = PyString_AsString(errorMsgPyStr); + // Display a dialog to the user with the exception + QClipboard *cp = QApplication::clipboard(); + cp->setText(errorMsg); + ScCore->closeSplash(); + qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor)); + QMessageBox::warning(ScCore->primaryMainWindow(), + tr("Script error"), + "<qt><p>" + + tr("If you are running an official script report it at <a href=\"http://bugs.scribus.net\">bugs.scribus.net</a> please.") + + "</p><pre>" +errorMsg + "</pre><p>" + + tr("This message is in your clipboard too. Use Ctrl+V to paste it into bug tracker.") + + "</p></qt>"); + } + } // end if result == NULL + // Because 'result' may be NULL, not a PyObject*, we must call PyXDECREF not Py_DECREF + Py_XDECREF(result); + } // end if m == NULL + if (!inMainInterpreter) + { + Py_EndInterpreter(state); + PyThreadState_Swap(global_state); + //PyEval_RestoreThread(stateo); +// qApp->restoreOverrideCursor(); + ScCore->primaryMainWindow()->setScriptRunning(false); + } +} + +void ScripterCore::slotRunScript(const QString Script) +{ + ScCore->primaryMainWindow()->propertiesPalette->unsetDoc(); + ScCore->primaryMainWindow()->pagePalette->setView(NULL); + ScCore->primaryMainWindow()->setScriptRunning(true); + inValue = Script; + QString cm; + cm = "# -*- coding: utf8 -*- \n"; + if (PyThreadState_Get() != NULL) + { + initscribus(ScCore->primaryMainWindow()); + /* HACK: following loop handles all input line by line. + It *should* use I.C. because of docstrings etc. I.I. cannot + handle docstrings right. + Calling all code in one command: + ia = code.InteractiveInterpreter() ia.runsource(getval()) + works fine in plain Python. Not here. WTF? */ + cm += ( + "try:\n" + " import cStringIO\n" + " scribus._bu = cStringIO.StringIO()\n" + " sys.stdout = scribus._bu\n" + " sys.stderr = scribus._bu\n" + " sys.argv = ['scribus', 'ext']\n" // this is the PySys_SetArgv replacement + " for i in scribus.getval().splitlines():\n" + " scribus._ia.push(i)\n" + " scribus.retval(scribus._bu.getvalue())\n" + " sys.stdout = sys.__stdout__\n" + " sys.stderr = sys.__stderr__\n" + "except SystemExit:\n" + " print 'Catched SystemExit - it is not good for Scribus'\n" + "except KeyboardInterrupt:\n" + " print 'Catched KeyboardInterrupt - it is not good for Scribus'\n" + ); + } + // Set up sys.argv + /* PV - WARNING: THIS IS EVIL! This code summons a crash - see + bug #3510. I don't know why as the Python C API is a little + bit magic for me. It looks like it replaces the cm QString or what... + "In file tools/qgarray.cpp, line 147: Out of memory" + Anyway - sys.argv is set above + char* comm[1]; + comm[0] = const_cast<char*>("scribus"); + // the scripter console runs everything in the main interpreter + // tell the code it's running there. + comm[1] = const_cast<char*>("ext"); + PySys_SetArgv(2, comm); */ + // then run the code + PyObject* m = PyImport_AddModule((char*)"__main__"); + if (m == NULL) + qDebug("Failed to get __main__ - aborting script"); + else + { + PyObject* globals = PyModule_GetDict(m); + PyObject* result = PyRun_String(cm.toUtf8().data(), Py_file_input, globals, globals); + if (result == NULL) + { + PyErr_Print(); + QMessageBox::warning(ScCore->primaryMainWindow(), tr("Script error"), + "<qt>" + tr("There was an internal error while trying the " + "command you entered. Details were printed to " + "stderr. ") + "</qt>"); + } + else + // Because 'result' may be NULL, not a PyObject*, we must call PyXDECREF not Py_DECREF + Py_XDECREF(result); + } + ScCore->primaryMainWindow()->setScriptRunning(false); +} + +void ScripterCore::slotInteractiveScript(bool visible) +{ + QObject::disconnect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) ); + + scrScripterActions["scripterShowConsole"]->setChecked(visible); + pcon->setFonts(); + pcon->setShown(visible); + + QObject::connect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) ); +} + +void ScripterCore::slotExecute() +{ + slotRunScript(pcon->command()); + pcon->outputEdit->append(returnString); + pcon->commandEdit->ensureCursorVisible(); + FinishScriptRun(); +} + +void ScripterCore::ReadPlugPrefs() +{ + PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin"); + if (!prefs) + { + qDebug("scriptplugin: Unable to load prefs"); + return; + } + PrefsTable* prefRecentScripts = prefs->getTable("recentscripts"); + if (!prefRecentScripts) + { + qDebug("scriptplugin: Unable to get recent scripts"); + return; + } + // Load recent scripts from the prefs + for (int i = 0; i < prefRecentScripts->getRowCount(); i++) + SavedRecentScripts.append(prefRecentScripts->get(i,0)); + // then get more general preferences + m_enableExtPython = prefs->getBool("extensionscripts",false); + m_importAllNames = prefs->getBool("importall",true); + m_startupScript = prefs->get("startupscript", QString::null); + // and have the console window set up its position +} + +void ScripterCore::SavePlugPrefs() +{ + PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin"); + if (!prefs) + { + qDebug("scriptplugin: Unable to load prefs"); + return; + } + PrefsTable* prefRecentScripts = prefs->getTable("recentscripts"); + if (!prefRecentScripts) + { + qDebug("scriptplugin: Unable to get recent scripts"); + return; + } + for (int i = 0; i < RecentScripts.count(); i++) + prefRecentScripts->set(i, 0, RecentScripts[i]); + // then save more general preferences + prefs->set("extensionscripts", m_enableExtPython); + prefs->set("importall", m_importAllNames); + prefs->set("startupscript", m_startupScript); +} + +void ScripterCore::aboutScript() +{ + QString fname = ScCore->primaryMainWindow()->CFileDialog(".", tr("Examine Script"), tr("Python Scripts (*.py *.PY);;All Files (*)"), "", fdNone); + if (fname == QString::null) + return; + QString html("<html><body>"); + QFileInfo fi = QFileInfo(fname); + QFile input(fname); + if(!input.open(QIODevice::ReadOnly)) + return; + QTextStream intputstream(&input); + QString content = intputstream.readAll(); + QString docstring = content.section("\"\"\"", 1, 1); + if (!docstring.isEmpty()) + { + html += QString("<h1>%1 %2</h1>").arg( tr("Documentation for:")).arg(fi.fileName()); + html += QString("<p>%1</p>").arg(docstring.replace("\n\n", "<br><br>")); + } + else + { + html += QString("<p><b>%1 %2 %3</b></p>").arg( tr("Script")).arg(fi.fileName()).arg( tr(" doesn't contain any docstring!")); + html += QString("<pre>%4</pre>").arg(content); + } + html += "</body></html>"; + input.close(); + HelpBrowser *dia = new HelpBrowser(0, QObject::tr("About Script") + " " + fi.fileName(), "en"); + dia->setText(html); + dia->show(); +} + +void ScripterCore::initExtensionScripts() +{ + // Nothing to do currently +} + +void ScripterCore::runStartupScript() +{ + if ((m_enableExtPython) && (!m_startupScript.isNull())) + { + if (QFile::exists(this->m_startupScript)) + { + // run the script in the main interpreter. The user will be informed + // with a dialog if something has gone wrong. + this->slotRunScriptFile(this->m_startupScript, true); + } + else + qDebug("Startup script enabled, but couln't find script %s.", m_startupScript.toAscii().constData()); + } +} + +void ScripterCore::languageChange() +{ + scrScripterActions["scripterExecuteScript"]->setText(QObject::tr("&Execute Script...")); + scrScripterActions["scripterShowConsole"]->setText(QObject::tr("Show &Console")); + scrScripterActions["scripterAboutScript"]->setText(QObject::tr("&About Script...")); + + menuMgr->setText("Scripter", QObject::tr("&Script")); + menuMgr->setText("ScribusScripts", QObject::tr("&Scribus Scripts")); + menuMgr->setText("RecentScripts", QObject::tr("&Recent Scripts")); +} + +bool ScripterCore::setupMainInterpreter() +{ + QString cm = QString( + "# -*- coding: utf-8 -*-\n" + "import scribus\n" + "import sys\n" + "import code\n" + "sys.path[0] = \"%1\"\n" + "import cStringIO\n" + "sys.stdin = cStringIO.StringIO()\n" + "scribus._ia = code.InteractiveConsole(globals())\n" + ).arg(ScPaths::instance().scriptDir()); + if (m_importAllNames) + cm += "from scribus import *\n"; + QByteArray cmd = cm.toUtf8(); + if (PyRun_SimpleString(cmd.data())) + { + PyErr_Print(); + QMessageBox::warning(ScCore->primaryMainWindow(), tr("Script error"), + tr("Setting up the Python plugin failed. " + "Error details were printed to stderr. ")); + return false; + } + else + return true; +} + +void ScripterCore::setStartupScript(const QString& newScript) +{ + m_startupScript = newScript; +} + +void ScripterCore::setExtensionsEnabled(bool enable) +{ + m_enableExtPython = enable; +} + +void ScripterCore::updateSyntaxHighlighter() +{ + pcon->updateSyntaxHighlighter(); +} + +const QString & ScripterCore::startupScript() const +{ + return m_startupScript; +} + +bool ScripterCore::extensionsEnabled() const +{ + return m_enableExtPython; +} diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h new file mode 100644 index 0000000..1eaaf30 --- /dev/null +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -0,0 +1,89 @@ +/* +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. +*/ +#ifndef SCRIPTERCORE_H +#define SCRIPTERCORE_H + +#include "cmdvar.h" + +#include "qmap.h" +#include "qpointer.h" + +class ScrAction; +class ScribusMainWindow; +class MenuManager; +class PythonConsole; + +class ScripterCore : public QObject +{ + Q_OBJECT + +public: + ScripterCore(QWidget* parent); + ~ScripterCore(); + void addToMainWindowMenu(ScribusMainWindow *); + + /** @brief String representation of result returned by last python console command */ + QString returnString; + /** @brief String representation of line of code to be passed to the Python interactive interpreter */ + QString inValue; + +public slots: + void runScriptDialog(); + void StdScript(QString filebasename); + void RecentScript(QString fn); + void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScript(const QString Script); + void slotInteractiveScript(bool); + void slotExecute(); + /*! \brief Show docstring of the script to the user. + * I don't know how to get docstring via e.g. pydoc because of + * it needs to run script => error cannot find scribus module + */ + void aboutScript(); + /** \brief Does setup for the main interpreter, particularly the interactive console. True for success. */ + bool setupMainInterpreter(); + /** \brief Sets up the plugin for extension scripts, if enabled */ + void initExtensionScripts(); + /** \brief Runs the startup script, if enabled */ + void runStartupScript(); + void languageChange(); + + const QString & startupScript() const; + bool extensionsEnabled() const; + void setStartupScript(const QString& newScript); + void setExtensionsEnabled(bool enable); + void updateSyntaxHighlighter(); + +protected: + // Private helper functions + void FinishScriptRun(); + void ReadPlugPrefs(); + void SavePlugPrefs(); + void rebuildRecentScriptsMenu(); + void buildScribusScriptsMenu(); + void buildRecentScriptsMenu(); + void rebuildScribusScriptsMenu(); + + //Internal members + //! \brief Reference to the "IDE" widget + PythonConsole *pcon; + QStringList SavedRecentScripts; + QStringList RecentScripts; + MenuManager *menuMgr; + QMap<QString, QPointer<ScrAction> > scrScripterActions; + QMap<QString, QPointer<ScrAction> > scrRecentScriptActions; + + // Preferences + /** \brief pref: Enable access to main interpreter and 'extension scripts' */ + bool m_enableExtPython; + /** \brief pref: Run 'from scribus import *' at scripter startup */ + bool m_importAllNames; + /** \brief pref: Load this script on startup */ + QString m_startupScript; +}; + +#endif diff --git a/scribus/plugins/scriptplugin/scripterprefsgui.cpp b/scribus/plugins/scriptplugin/scripterprefsgui.cpp new file mode 100644 index 0000000..d2ae64a --- /dev/null +++ b/scribus/plugins/scriptplugin/scripterprefsgui.cpp @@ -0,0 +1,151 @@ +/* +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. +*/ + +// include the python header first because on OSX that uses the name "slots" +#include "cmdvar.h" + +#include <QColorDialog> +#include <QFileDialog> + +#include "scripterprefsgui.h" +#include "scriptercore.h" +#include "pconsole.h" + + +ScripterPrefsGui::ScripterPrefsGui(QWidget* parent ) + : PrefsPanel(parent) +{ + setupUi(this); + + // Create SyntaxColors with save to prefs + // disabled by defaults, only save when apply() + syntaxColors = new SyntaxColors(); + + languageChange(); + setupSyntaxColors(); + + // Set the state of the ext script enable checkbox + extensionScriptsChk->setChecked(scripterCore->extensionsEnabled()); + // The startup script box should be disabled if ext scripts are off + startupScriptEdit->setEnabled(extensionScriptsChk->isChecked()); + connect(extensionScriptsChk, SIGNAL(toggled(bool)), + startupScriptEdit, SLOT(setEnabled(bool))); + + // signals and slots connections + connect(extensionScriptsChk, SIGNAL(toggled(bool)), startupScriptEdit, SLOT(setEnabled(bool))); + // colors + connect(textButton , SIGNAL(clicked()), this, SLOT(setColor())); + connect(commentButton, SIGNAL(clicked()), this, SLOT(setColor())); + connect(keywordButton, SIGNAL(clicked()), this, SLOT(setColor())); + connect(errorButton , SIGNAL(clicked()), this, SLOT(setColor())); + connect(signButton , SIGNAL(clicked()), this, SLOT(setColor())); + connect(stringButton , SIGNAL(clicked()), this, SLOT(setColor())); + connect(numberButton , SIGNAL(clicked()), this, SLOT(setColor())); + connect(startupScriptChangeButton, SIGNAL(clicked()), this, SLOT(changeStartupScript())); +} + +/* + * Destroys the object and frees any allocated resources + */ +ScripterPrefsGui::~ScripterPrefsGui() +{ + delete syntaxColors; +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void ScripterPrefsGui::languageChange() +{ + setWindowTitle( tr("Scripter Preferences")); +/* extensionScriptsChk->setText( tr("Enable Extension Scripts")); + startupScriptEditLabel->setText( tr("Startup Script:")); + errorLabel->setText( tr("Errors:", "syntax highlighting")); + commentLabel->setText( tr("Comments:", "syntax highlighting")); + keywordLabel->setText( tr("Keywords:", "syntax highlighting")); + signLabel->setText( tr("Signs:", "syntax highlighting")); + numberLabel->setText( tr("Numbers:", "syntax highlighting")); + stringLabel->setText( tr("Strings:", "syntax highlighting")); + textLabel->setText( tr("Base Texts:", "syntax highlighting"));*/ +} + +// Apply changes to prefs. Auto connected. +void ScripterPrefsGui::apply() +{ + scripterCore->setExtensionsEnabled(extensionScriptsChk->isChecked()); + scripterCore->setStartupScript(startupScriptEdit->text()); + syntaxColors->saveToPrefs(); + + // Necessary to update console syntax highlighter + emit prefsChanged(); +} + +void ScripterPrefsGui::setColor() +{ + QPushButton* button = (QPushButton*) sender(); + + QColor oldColor; + if (button == textButton) oldColor = syntaxColors->textColor; + if (button == commentButton) oldColor = syntaxColors->commentColor; + if (button == keywordButton) oldColor = syntaxColors->keywordColor; + if (button == errorButton) oldColor = syntaxColors->errorColor; + if (button == signButton) oldColor = syntaxColors->signColor; + if (button == stringButton) oldColor = syntaxColors->stringColor; + if (button == numberButton) oldColor = syntaxColors->numberColor; + + QColor color = QColorDialog::getColor(oldColor, this); + if (color.isValid()) + { + setButtonIcon(button, color); + + if (button == textButton) syntaxColors->textColor = color; + if (button == commentButton) syntaxColors->commentColor = color; + if (button == keywordButton) syntaxColors->keywordColor = color; + if (button == errorButton) syntaxColors->errorColor = color; + if (button == signButton) syntaxColors->signColor = color; + if (button == stringButton) syntaxColors->stringColor = color; + if (button == numberButton) syntaxColors->numberColor = color; + } +} + +void ScripterPrefsGui::setButtonIcon(QPushButton* button, QColor color) +{ + QSize iconSize = button->iconSize(); + double iconWidth = qMax(iconSize.width() , button->width() / 3); + double iconHeight = qMin(iconSize.height(), button->height() / 3); + QSize newIconSize(iconWidth, iconHeight); + if (iconSize != newIconSize) + button->setIconSize(newIconSize); + QPixmap icon(button->iconSize()); + icon.fill(color); + button->setIcon(icon); +} + +void ScripterPrefsGui::setupSyntaxColors() +{ + SyntaxColors syntax; + setButtonIcon(textButton , syntax.textColor); + setButtonIcon(commentButton, syntax.commentColor); + setButtonIcon(keywordButton, syntax.keywordColor); + setButtonIcon(errorButton , syntax.errorColor); + setButtonIcon(signButton , syntax.signColor); + setButtonIcon(stringButton , syntax.stringColor); + setButtonIcon(numberButton , syntax.numberColor); +} + +void ScripterPrefsGui::changeStartupScript() +{ + QString currentScript=startupScriptEdit->text(); + QFileInfo fi(startupScriptEdit->text()); + if (!fi.exists()) + currentScript = QDir::homePath(); + + QString s = QFileDialog::getOpenFileName(this, tr("Locate Startup Script"), currentScript, "Python Scripts (*.py *.PY)"); + if (!s.isEmpty()) + startupScriptEdit->setText(s); +} diff --git a/scribus/plugins/scriptplugin/scripterprefsgui.h b/scribus/plugins/scriptplugin/scripterprefsgui.h new file mode 100644 index 0000000..4c4cc98 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripterprefsgui.h @@ -0,0 +1,47 @@ +/* +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. +*/ +#ifndef SCRIPTERPREFSGUI_H +#define SCRIPTERPREFSGUI_H + +#include "ui_scripterprefsgui.h" +#include "prefspanel.h" + +class SyntaxColors; + +/*! \brief Subclass of PrefsPanel that's supplied to the prefs +dialog for use when showing plugin preferences. */ +class ScripterPrefsGui : public PrefsPanel, public Ui::ScripterPrefsGui +{ + Q_OBJECT + + public: + ScripterPrefsGui(QWidget* parent); + ~ScripterPrefsGui(); + + public slots: + void apply(); + + protected: + void setupSyntaxColors(); + void setButtonIcon(QPushButton* button, QColor color); + + SyntaxColors* syntaxColors; + + protected slots: + void languageChange(); + /*! \brief All requests for color change are handled here. + \author Petr Vanek + \warning I'm trying to handle multiple signals via single slot here. sender() Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; otherwise the return value is undefined. This function will return something apparently correct in other cases as well. However, its value may change during any function call, depending on what signal-slot connections are activated during that call. In Qt 3.0 the value will change more often than in 2.x. This function violates the object-oriented principle of modularity. However, getting access to the sender might be useful when many signals are connected to a single slot. The sender is undefined if the slot is called as a normal C++ function. */ + void setColor(); + + void changeStartupScript(); + + signals: + void prefsChanged(); +}; + +#endif diff --git a/scribus/plugins/scriptplugin/scripterprefsgui.ui b/scribus/plugins/scriptplugin/scripterprefsgui.ui new file mode 100644 index 0000000..e1b65ae --- /dev/null +++ b/scribus/plugins/scriptplugin/scripterprefsgui.ui @@ -0,0 +1,259 @@ +<ui version="4.0" > + <class>ScripterPrefsGui</class> + <widget class="QWidget" name="ScripterPrefsGui" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>504</width> + <height>443</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0" > + <widget class="QTabWidget" name="tabWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="startupTab" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>478</width> + <height>285</height> + </rect> + </property> + <attribute name="title" > + <string>Extensions</string> + </attribute> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" colspan="2" > + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string>Startup Script:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="startupScriptEdit" /> + </item> + <item> + <widget class="QPushButton" name="startupScriptChangeButton" > + <property name="text" > + <string>Change...</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="0" > + <widget class="QCheckBox" name="extensionScriptsChk" > + <property name="text" > + <string>Enable Extension Scripts</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="consoleTab" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>478</width> + <height>285</height> + </rect> + </property> + <attribute name="title" > + <string>Console</string> + </attribute> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="7" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="5" column="1" > + <widget class="QPushButton" name="stringButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="6" column="1" > + <widget class="QPushButton" name="numberButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QPushButton" name="errorButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Comments:</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_4" > + <property name="text" > + <string>Keywords:</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_5" > + <property name="text" > + <string>Signs:</string> + </property> + </widget> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="label_7" > + <property name="text" > + <string>Strings:</string> + </property> + </widget> + </item> + <item row="6" column="0" > + <widget class="QLabel" name="label_8" > + <property name="text" > + <string>Numbers:</string> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="label_6" > + <property name="text" > + <string>Errors:</string> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Base Texts:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QPushButton" name="textButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="commentButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QPushButton" name="keywordButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QPushButton" name="signButton" > + <property name="text" > + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>extensionScriptsChk</tabstop> + <tabstop>startupScriptEdit</tabstop> + <tabstop>startupScriptChangeButton</tabstop> + <tabstop>textButton</tabstop> + <tabstop>commentButton</tabstop> + <tabstop>keywordButton</tabstop> + <tabstop>signButton</tabstop> + <tabstop>errorButton</tabstop> + <tabstop>stringButton</tabstop> + <tabstop>numberButton</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/scribus/plugins/scriptplugin/scriptplugin.cpp b/scribus/plugins/scriptplugin/scriptplugin.cpp new file mode 100644 index 0000000..c4233f5 --- /dev/null +++ b/scribus/plugins/scriptplugin/scriptplugin.cpp @@ -0,0 +1,828 @@ +/* +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. +*/ +/*************************************************************************** + scriptplugin.cpp - description + ------------------- + begin : Thu Oct 3 08:00:00 CEST 2002 + copyright : (C) 2002 by Franz Schmid + email : Franz.Schmid@altmuehlnet.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +// include cmdvar.h first, as it pulls in <Python.h> +#include "cmdvar.h" + +#include "cmdcolor.h" +#include "cmddialog.h" +#include "cmddoc.h" +#include "cmdgetprop.h" +#include "cmdgetsetprop.h" +#include "cmdmani.h" +#include "cmdmisc.h" +#include "cmdobj.h" +#include "cmdpage.h" +#include "cmdsetprop.h" +#include "cmdtext.h" +#include "cmdutil.h" +#include "cmdstyle.h" +#include "customfdialog.h" +#include "guiapp.h" +#include "helpbrowser.h" +#include "menumanager.h" +#include "objimageexport.h" +#include "objpdffile.h" +#include "objprinter.h" +#include "propertiespalette.h" +#include "scconfig.h" +#include "scpaths.h" +#include "scribuscore.h" +#include "scribusstructs.h" +#include "scriptercore.h" +#include "scripterprefsgui.h" +#include "scriptplugin.h" +#include "svgimport.h" +#include "units.h" +#include "util_icon.h" + +#include <QApplication> +#include <QMessageBox> +#include <QTextCodec> +#include <QRegExp> +#include <QPixmap> +#include <QWidget> +#include <QString> +//Added by qt3to4: +#include <QByteArray> +#include <cstdlib> +#include <iostream> + + +#ifdef HAVE_SCRIPTER2 +extern void scripter2_init(); +#endif + +// Exceptions; visible from cmdvar.h, set up in initscribus() +PyObject* ScribusException; +PyObject* NoDocOpenError; +PyObject* WrongFrameTypeError; +PyObject* NoValidObjectError; +PyObject* NotFoundError; +PyObject* NameExistsError; + +// Other extern variables defined in cmdvar.h +PyObject* wrappedMainWindow; +PyObject* wrappedQApp; +ScripterCore* scripterCore; + + +int scriptplugin_getPluginAPIVersion() +{ + return PLUGIN_API_VERSION; +} + +ScPlugin* scriptplugin_getPlugin() +{ + scripterCore=0; + ScriptPlugin* plug = new ScriptPlugin(); + Q_CHECK_PTR(plug); + return plug; +} + +void scriptplugin_freePlugin(ScPlugin* plugin) +{ + ScriptPlugin* plug = dynamic_cast<ScriptPlugin*>(plugin); + Q_ASSERT(plug); + delete plug; +} + +ScriptPlugin::ScriptPlugin() : ScPersistentPlugin() +{ + // Set action info in languageChange, so we only have to do + // it in one place. + languageChange(); +} + +ScriptPlugin::~ScriptPlugin() {}; + +void ScriptPlugin::languageChange() +{ + if (scripterCore) + scripterCore->languageChange(); +} + +void ScriptPlugin::addToMainWindowMenu(ScribusMainWindow* mw) +{ + if (scripterCore) + scripterCore->addToMainWindowMenu(mw); +} + +const QString ScriptPlugin::fullTrName() const +{ + return QObject::tr("Scripter"); +} + +const ScActionPlugin::AboutData* ScriptPlugin::getAboutData() const +{ + AboutData* about = new AboutData; + Q_CHECK_PTR(about); + about->authors = QString::fromUtf8( + "Petr Van\xc4\x9bk <petr@scribus.info>, " + "Franz Schmid <franz@scribus.info>, " + "Craig Ringer <craig@scribus.info>"); + about->shortDescription = tr("Embedded Python scripting support."); + // about->description = tr("Write me!") + // about->version + // about->releaseDate + // about->copyright + // about->license + return about; +} + +void ScriptPlugin::deleteAboutData(const AboutData* about) const +{ + Q_ASSERT(about); + delete about; +} + +bool ScriptPlugin::initPlugin() +{ + QString cm; + Py_Initialize(); + if (PyUnicode_SetDefaultEncoding("utf-8")) + { + qDebug("Failed to set default encoding to utf-8.\n"); + PyErr_Clear(); + } + + scripterCore = new ScripterCore(ScCore->primaryMainWindow()); + Q_CHECK_PTR(scripterCore); + initscribus(ScCore->primaryMainWindow()); +#ifdef HAVE_SCRIPTER2 + scripter2_init(); +#endif + scripterCore->setupMainInterpreter(); + scripterCore->initExtensionScripts(); + scripterCore->runStartupScript(); + return true; +} + +bool ScriptPlugin::cleanupPlugin() +{ + if (scripterCore) + { + delete scripterCore; + scripterCore = NULL; + } + Py_Finalize(); + return true; +} + +bool ScriptPlugin::newPrefsPanelWidget(QWidget* parent, + PrefsPanel*& panel, + QString& caption, + QPixmap& icon) +{ + panel = new ScripterPrefsGui(parent); + Q_CHECK_PTR(panel); + connect(panel, SIGNAL(prefsChanged()), scripterCore, SLOT(updateSyntaxHighlighter())); + caption = tr("Scripter"); + icon = loadIcon("python.png"); + return true; +} + +/* TEMPORARILY DISABLED +void run() +{ + QString pfad = ScPaths::instance().docDir(); + QString pfad2; + pfad2 = QDir::toNativeSeparators(pfad + "en/Scripter/index.html"); + HelpBrowser *dia = new HelpBrowser(0, QObject::tr("Online Reference"), ScCore->primaryMainWindow()->getGuiLanguage(), "scripter"); + dia->show(); +} +*/ + + +/****************************************************************************************/ +/* */ +/* Definitions of the Python commands */ +/* */ +/****************************************************************************************/ + +/*static */PyObject *scribus_retval(PyObject* /*self*/, PyObject* args) +{ + char *Name = NULL; + if (!PyArg_ParseTuple(args, (char*)"s", &Name)) + return NULL; + // Because sysdefaultencoding is not utf-8, Python is returning utf-8 encoded + // 8-bit char* strings. Make sure Qt understands that the input is utf-8 not + // the default local encoding (usually latin-1) by using QString::fromUtf8() + /*RetString = QString::fromUtf8(Name); + RetVal = retV;*/ + scripterCore->returnString = QString::fromUtf8(Name); + return PyInt_FromLong(0L); +} + +/*static */PyObject *scribus_getval(PyObject* /*self*/) +{ + return PyString_FromString(scripterCore->inValue.toUtf8().data()); +} + +/*! \brief Translate a docstring. Small helper function for use with the + * PyMethodDef struct. + */ +char* tr(const char* docstringConstant) +{ + // Alas, there's a lot of wasteful string copying going on + // here. + QString translated = QObject::tr(docstringConstant, "scripter docstring"); + // pv - hack for ugly formating in console removing + translated.replace("\n\n", "<P>"); + translated.replace('\n', " "); + translated.replace("<P>", "\n\n"); + /* + * Python doesn't support 'unicode' object docstrings in the PyMethodDef, + * and has no way to specify what encoding docstrings are in. The passed C + * strings passed are made into 'str' objects as-is. These are interpreted + * as being in the Python sysdefaultencoding, usually 'ascii', when used. + * We now set systemdefaultencoding to 'utf-8' ... so we're going to pass + * Python an 8-bit utf-8 encoded string in a char* . With + * sysdefaultencoding set correctly, Python will interpret it correctly and + * we'll have our unicode docstrings. It's not as ugly a hack as it sounds, + * you just have to remember that C and Python strings can both be + * considered 8-bit strings of binary data that can be later interpreted as + * a text string in a particular text encoding. + */ + //QCString utfTranslated = translated.utf8(); + QByteArray trch = translated.toUtf8(); + char* utfstr = strdup(trch.data()); + if (!utfstr) + // Complain, but then return NULL anyway. Python will treat NULL as + // "no value" so that's fine. + qDebug("scriptplugin.cpp:tr() - strdup() failure"); + return utfstr; +} + +/* Now we're using the more pythonic convention for names: + * class - ClassName + * procedure/function/method - procedureName + * etc. */ +PyMethodDef scribus_methods[] = { + // 2004/10/03 pv - aliases with common Python syntax - ClassName methodName + // 2004-11-06 cr - move aliasing to dynamically generated wrapper functions, sort methoddef + {const_cast<char*>("changeColor"), scribus_setcolor, METH_VARARGS, tr(scribus_setcolor__doc__)}, + {const_cast<char*>("closeDoc"), (PyCFunction)scribus_closedoc, METH_NOARGS, tr(scribus_closedoc__doc__)}, + {const_cast<char*>("closeMasterPage"), (PyCFunction)scribus_closemasterpage, METH_NOARGS, tr(scribus_closemasterpage__doc__)}, + {const_cast<char*>("createBezierLine"), scribus_bezierline, METH_VARARGS, tr(scribus_bezierline__doc__)}, + {const_cast<char*>("createEllipse"), scribus_newellipse, METH_VARARGS, tr(scribus_newellipse__doc__)}, + {const_cast<char*>("createImage"), scribus_newimage, METH_VARARGS, tr(scribus_newimage__doc__)}, + {const_cast<char*>("createLayer"), scribus_createlayer, METH_VARARGS, tr(scribus_createlayer__doc__)}, + {const_cast<char*>("createLine"), scribus_newline, METH_VARARGS, tr(scribus_newline__doc__)}, + {const_cast<char*>("createMasterPage"), scribus_createmasterpage, METH_VARARGS, tr(scribus_createmasterpage__doc__)}, + {const_cast<char*>("createPathText"), scribus_pathtext, METH_VARARGS, tr(scribus_pathtext__doc__)}, + {const_cast<char*>("createPolygon"), scribus_polygon, METH_VARARGS, tr(scribus_polygon__doc__)}, + {const_cast<char*>("createPolyLine"), scribus_polyline, METH_VARARGS, tr(scribus_polyline__doc__)}, + {const_cast<char*>("createRect"), scribus_newrect, METH_VARARGS, tr(scribus_newrect__doc__)}, + {const_cast<char*>("createText"), scribus_newtext, METH_VARARGS, tr(scribus_newtext__doc__)}, + {const_cast<char*>("createParagraphStyle"), (PyCFunction)scribus_createparagraphstyle, METH_KEYWORDS, tr(scribus_createparagraphstyle__doc__)}, + {const_cast<char*>("createCharStyle"), (PyCFunction)scribus_createcharstyle, METH_KEYWORDS, tr(scribus_createcharstyle__doc__)}, + {const_cast<char*>("currentPage"), (PyCFunction)scribus_actualpage, METH_NOARGS, tr(scribus_actualpage__doc__)}, + {const_cast<char*>("defineColor"), scribus_newcolor, METH_VARARGS, tr(scribus_newcolor__doc__)}, + {const_cast<char*>("deleteColor"), scribus_delcolor, METH_VARARGS, tr(scribus_delcolor__doc__)}, + {const_cast<char*>("deleteLayer"), scribus_removelayer, METH_VARARGS, tr(scribus_removelayer__doc__)}, + {const_cast<char*>("deleteMasterPage"), scribus_deletemasterpage, METH_VARARGS, tr(scribus_deletemasterpage__doc__)}, + {const_cast<char*>("deleteObject"), scribus_deleteobj, METH_VARARGS, tr(scribus_deleteobj__doc__)}, + {const_cast<char*>("deletePage"), scribus_deletepage, METH_VARARGS, tr(scribus_deletepage__doc__)}, + {const_cast<char*>("deleteText"), scribus_deletetext, METH_VARARGS, tr(scribus_deletetext__doc__)}, + {const_cast<char*>("deselectAll"), (PyCFunction)scribus_deselect, METH_NOARGS, tr(scribus_deselect__doc__)}, + {const_cast<char*>("docChanged"), scribus_docchanged, METH_VARARGS, tr(scribus_docchanged__doc__)}, + {const_cast<char*>("editMasterPage"), scribus_editmasterpage, METH_VARARGS, tr(scribus_editmasterpage__doc__)}, + {const_cast<char*>("fileDialog"), (PyCFunction)scribus_filedia, METH_VARARGS|METH_KEYWORDS, tr(scribus_filedia__doc__)}, + {const_cast<char*>("fileQuit"), scribus_filequit, METH_VARARGS, tr(scribus_filequit__doc__)}, + {const_cast<char*>("getActiveLayer"), (PyCFunction)scribus_getactlayer, METH_NOARGS, tr(scribus_getactlayer__doc__)}, + {const_cast<char*>("getAllObjects"), scribus_getallobj, METH_VARARGS, tr(scribus_getallobj__doc__)}, + {const_cast<char*>("getAllStyles"), (PyCFunction)scribus_getstylenames, METH_NOARGS, tr(scribus_getstylenames__doc__)}, + {const_cast<char*>("getAllText"), scribus_gettext, METH_VARARGS, tr(scribus_gettext__doc__)}, + {const_cast<char*>("getColorNames"), (PyCFunction)scribus_colornames, METH_NOARGS, tr(scribus_colornames__doc__)}, + {const_cast<char*>("getColor"), scribus_getcolor, METH_VARARGS, tr(scribus_getcolor__doc__)}, + {const_cast<char*>("getColorAsRGB"), scribus_getcolorasrgb, METH_VARARGS, tr(scribus_getcolorasrgb__doc__)}, + {const_cast<char*>("isSpotColor"), scribus_isspotcolor, METH_VARARGS, tr(scribus_isspotcolor__doc__)}, + {const_cast<char*>("setSpotColor"), scribus_setspotcolor, METH_VARARGS, tr(scribus_setspotcolor__doc__)}, + {const_cast<char*>("getTextDistances"), scribus_gettextdistances, METH_VARARGS, tr(scribus_gettextdistances__doc__)}, + {const_cast<char*>("getColumnGap"), scribus_getcolumngap, METH_VARARGS, tr(scribus_getcolumngap__doc__)}, + {const_cast<char*>("getColumns"), scribus_getcolumns, METH_VARARGS, tr(scribus_getcolumns__doc__)}, + {const_cast<char*>("getCornerRadius"), scribus_getcornerrad, METH_VARARGS, tr(scribus_getcornerrad__doc__)}, + {const_cast<char*>("getFillColor"), scribus_getfillcolor, METH_VARARGS, tr(scribus_getfillcolor__doc__)}, + {const_cast<char*>("getFillShade"), scribus_getfillshade, METH_VARARGS, tr(scribus_getfillshade__doc__)}, + {const_cast<char*>("getFillBlendmode"), scribus_getfillblend, METH_VARARGS, tr(scribus_getfillblend__doc__)}, + {const_cast<char*>("getFillTransparency"), scribus_getfilltrans, METH_VARARGS, tr(scribus_getfilltrans__doc__)}, + {const_cast<char*>("getFontNames"), (PyCFunction)scribus_fontnames, METH_NOARGS, tr(scribus_fontnames__doc__)}, + {const_cast<char*>("getFont"), scribus_getfont, METH_VARARGS, tr(scribus_getfont__doc__)}, + {const_cast<char*>("getFontSize"), scribus_getfontsize, METH_VARARGS, tr(scribus_getfontsize__doc__)}, + {const_cast<char*>("getGuiLanguage"), (PyCFunction)scribus_getlanguage, METH_NOARGS, tr(scribus_getlanguage__doc__)}, + {const_cast<char*>("getHGuides"), (PyCFunction)scribus_getHguides, METH_NOARGS, tr(scribus_getHguides__doc__)}, + {const_cast<char*>("getImageFile"), scribus_getimgname, METH_VARARGS, tr(scribus_getimgname__doc__)}, + {const_cast<char*>("getImageScale"), scribus_getimgscale, METH_VARARGS, tr(scribus_getimgscale__doc__)}, + {const_cast<char*>("getLayers"), (PyCFunction)scribus_getlayers, METH_NOARGS, tr(scribus_getlayers__doc__)}, + {const_cast<char*>("getLayerBlendmode"), scribus_glayerblend, METH_VARARGS, tr(scribus_glayerblend__doc__)}, + {const_cast<char*>("getLayerTransparency"), scribus_glayertrans, METH_VARARGS, tr(scribus_glayertrans__doc__)}, + {const_cast<char*>("getLineCap"), scribus_getlinecap, METH_VARARGS, tr(scribus_getlinecap__doc__)}, + {const_cast<char*>("getLineColor"), scribus_getlinecolor, METH_VARARGS, tr(scribus_getlinecolor__doc__)}, + {const_cast<char*>("getLineShade"), scribus_getlineshade, METH_VARARGS, tr(scribus_getlineshade__doc__)}, + {const_cast<char*>("getLineBlendmode"), scribus_getlineblend, METH_VARARGS, tr(scribus_getlineblend__doc__)}, + {const_cast<char*>("getLineTransparency"), scribus_getlinetrans, METH_VARARGS, tr(scribus_getlinetrans__doc__)}, + {const_cast<char*>("getLineJoin"), scribus_getlinejoin, METH_VARARGS, tr(scribus_getlinejoin__doc__)}, + {const_cast<char*>("getLineSpacing"), scribus_getlinespace, METH_VARARGS, tr(scribus_getlinespace__doc__)}, + {const_cast<char*>("getLineStyle"), scribus_getlinestyle, METH_VARARGS, tr(scribus_getlinestyle__doc__)}, + {const_cast<char*>("getLineWidth"), scribus_getlinewidth, METH_VARARGS, tr(scribus_getlinewidth__doc__)}, + {const_cast<char*>("getPageItems"), (PyCFunction)scribus_getpageitems, METH_NOARGS, tr(scribus_getpageitems__doc__)}, + {const_cast<char*>("getPageMargins"), (PyCFunction)scribus_getpagemargins, METH_NOARGS, tr(scribus_getpagemargins__doc__)}, + {const_cast<char*>("getPageType"), (PyCFunction)scribus_pageposition, METH_VARARGS, tr(scribus_pageposition__doc__)}, + {const_cast<char*>("getPageSize"), (PyCFunction)scribus_pagedimension, METH_NOARGS, tr(scribus_pagedimension__doc__)}, // just an alias to PageDimension() + {const_cast<char*>("getPageNSize"), scribus_pagensize, METH_VARARGS, tr(scribus_pagensize__doc__)}, + {const_cast<char*>("getPageNMargins"), scribus_pagenmargins, METH_VARARGS, tr(scribus_pagenmargins__doc__)}, + {const_cast<char*>("importPage"), scribus_importpage, METH_VARARGS, tr(scribus_importpage__doc__)}, + {const_cast<char*>("getPosition"), scribus_getposi, METH_VARARGS, tr(scribus_getposi__doc__)}, + {const_cast<char*>("getRotation"), scribus_getrotation, METH_VARARGS, tr(scribus_getrotation__doc__)}, + {const_cast<char*>("getObjectType"), scribus_getobjecttype, METH_VARARGS, tr(scribus_getobjecttype__doc__)}, + {const_cast<char*>("getSelectedObject"), scribus_getselobjnam, METH_VARARGS, tr(scribus_getselobjnam__doc__)}, + {const_cast<char*>("getSize"), scribus_getsize, METH_VARARGS, tr(scribus_getsize__doc__)}, + {const_cast<char*>("getTextColor"), scribus_getlinecolor, METH_VARARGS, tr(scribus_getlinecolor__doc__)}, + {const_cast<char*>("getTextLength"), scribus_gettextsize, METH_VARARGS, tr(scribus_gettextsize__doc__)}, + {const_cast<char*>("getTextLines"), scribus_gettextlines, METH_VARARGS, tr(scribus_gettextlines__doc__)}, + {const_cast<char*>("getText"), scribus_getframetext, METH_VARARGS, tr(scribus_getframetext__doc__)}, + {const_cast<char*>("getTextShade"), scribus_getlineshade, METH_VARARGS, tr(scribus_getlineshade__doc__)}, + {const_cast<char*>("getUnit"), (PyCFunction)scribus_getunit, METH_NOARGS, tr(scribus_getunit__doc__)}, + {const_cast<char*>("getVGuides"), (PyCFunction)scribus_getVguides, METH_NOARGS, tr(scribus_getVguides__doc__)}, + {const_cast<char*>("getXFontNames"), (PyCFunction)scribus_xfontnames, METH_NOARGS, tr(scribus_xfontnames__doc__)}, + {const_cast<char*>("gotoPage"), scribus_gotopage, METH_VARARGS, tr(scribus_gotopage__doc__)}, + {const_cast<char*>("groupObjects"), scribus_groupobj, METH_VARARGS, tr(scribus_groupobj__doc__)}, + {const_cast<char*>("haveDoc"), (PyCFunction)scribus_havedoc, METH_NOARGS, tr(scribus_havedoc__doc__)}, + {const_cast<char*>("placeSVG"), scribus_placesvg, METH_VARARGS, tr(scribus_placesvg__doc__)}, + {const_cast<char*>("placeEPS"), scribus_placeeps, METH_VARARGS, tr(scribus_placeeps__doc__)}, + {const_cast<char*>("placeSXD"), scribus_placesxd, METH_VARARGS, tr(scribus_placesxd__doc__)}, + {const_cast<char*>("placeODG"), scribus_placeodg, METH_VARARGS, tr(scribus_placeodg__doc__)}, + {const_cast<char*>("insertText"), scribus_inserttext, METH_VARARGS, tr(scribus_inserttext__doc__)}, + {const_cast<char*>("isLayerPrintable"), scribus_glayerprint, METH_VARARGS, tr(scribus_glayerprint__doc__)}, + {const_cast<char*>("isLayerVisible"), scribus_glayervisib, METH_VARARGS, tr(scribus_glayervisib__doc__)}, + {const_cast<char*>("isLayerLocked"), scribus_glayerlock, METH_VARARGS, tr(scribus_glayerlock__doc__)}, + {const_cast<char*>("isLayerOutlined"), scribus_glayeroutline, METH_VARARGS, tr(scribus_glayeroutline__doc__)}, + {const_cast<char*>("isLayerFlow"), scribus_glayerflow, METH_VARARGS, tr(scribus_glayerflow__doc__)}, + {const_cast<char*>("isLocked"), scribus_islocked, METH_VARARGS, tr(scribus_islocked__doc__)}, + {const_cast<char*>("linkTextFrames"), scribus_linktextframes, METH_VARARGS, tr(scribus_linktextframes__doc__)}, + {const_cast<char*>("loadImage"), scribus_loadimage, METH_VARARGS, tr(scribus_loadimage__doc__)}, + {const_cast<char*>("loadStylesFromFile"), scribus_loadstylesfromfile, METH_VARARGS, tr(scribus_loadstylesfromfile__doc__)}, + {const_cast<char*>("lockObject"), scribus_lockobject, METH_VARARGS, tr(scribus_lockobject__doc__)}, + {const_cast<char*>("masterPageNames"), (PyCFunction)scribus_masterpagenames, METH_NOARGS, tr(scribus_masterpagenames__doc__)}, + {const_cast<char*>("messagebarText"), scribus_messagebartext, METH_VARARGS, tr(scribus_messagebartext__doc__)}, + {const_cast<char*>("messageBox"), (PyCFunction)scribus_messdia, METH_VARARGS|METH_KEYWORDS, tr(scribus_messdia__doc__)}, + {const_cast<char*>("moveObjectAbs"), scribus_moveobjabs, METH_VARARGS, tr(scribus_moveobjabs__doc__)}, + {const_cast<char*>("moveObject"), scribus_moveobjrel, METH_VARARGS, tr(scribus_moveobjrel__doc__)}, + {const_cast<char*>("newDocDialog"), (PyCFunction)scribus_newdocdia, METH_NOARGS, tr(scribus_newdocdia__doc__)}, + {const_cast<char*>("newDoc"), scribus_newdoc, METH_VARARGS, tr(scribus_newdoc__doc__)}, + {const_cast<char*>("newDocument"), scribus_newdocument, METH_VARARGS, tr(scribus_newdocument__doc__)}, + {const_cast<char*>("newPage"), scribus_newpage, METH_VARARGS, tr(scribus_newpage__doc__)}, + {const_cast<char*>("newStyleDialog"), scribus_newstyledialog, METH_NOARGS, tr(scribus_newstyledialog__doc__)}, + {const_cast<char*>("objectExists"),scribus_objectexists, METH_VARARGS, tr(scribus_objectexists__doc__)}, + {const_cast<char*>("openDoc"), scribus_opendoc, METH_VARARGS, tr(scribus_opendoc__doc__)}, + {const_cast<char*>("pageCount"), (PyCFunction)scribus_pagecount, METH_NOARGS, tr(scribus_pagecount__doc__)}, + {const_cast<char*>("pageDimension"), (PyCFunction)scribus_pagedimension, METH_NOARGS, "Obsolete function. Don't use it."}, + {const_cast<char*>("progressReset"), (PyCFunction)scribus_progressreset, METH_NOARGS, tr(scribus_progressreset__doc__)}, + {const_cast<char*>("progressSet"), scribus_progresssetprogress, METH_VARARGS, tr(scribus_progresssetprogress__doc__)}, + {const_cast<char*>("progressTotal"), scribus_progresssettotalsteps, METH_VARARGS, tr(scribus_progresssettotalsteps__doc__)}, + {const_cast<char*>("redrawAll"), (PyCFunction)scribus_redraw, METH_NOARGS, tr(scribus_redraw__doc__)}, + {const_cast<char*>("renderFont"), (PyCFunction)scribus_renderfont, METH_KEYWORDS, tr(scribus_renderfont__doc__)}, + {const_cast<char*>("replaceColor"), scribus_replcolor, METH_VARARGS, tr(scribus_replcolor__doc__)}, + {const_cast<char*>("rotateObjectAbs"), scribus_rotobjabs, METH_VARARGS, tr(scribus_rotobjabs__doc__)}, + {const_cast<char*>("rotateObject"), scribus_rotobjrel, METH_VARARGS, tr(scribus_rotobjrel__doc__)}, + {const_cast<char*>("getDocName"), (PyCFunction)scribus_getdocname, METH_NOARGS, tr(scribus_getdocname__doc__)}, + {const_cast<char*>("saveDocAs"), scribus_savedocas, METH_VARARGS, tr(scribus_savedocas__doc__)}, + {const_cast<char*>("saveDoc"), (PyCFunction)scribus_savedoc, METH_NOARGS, tr(scribus_savedoc__doc__)}, + {const_cast<char*>("savePageAsEPS"), scribus_savepageeps, METH_VARARGS, tr(scribus_savepageeps__doc__)}, + {const_cast<char*>("scaleGroup"), scribus_scalegroup, METH_VARARGS, tr(scribus_scalegroup__doc__)}, + {const_cast<char*>("scaleImage"), scribus_scaleimage, METH_VARARGS, tr(scribus_scaleimage__doc__)}, + {const_cast<char*>("setImageScale"), scribus_setimagescale, METH_VARARGS, tr(scribus_setimagescale__doc__)}, + {const_cast<char*>("setImageOffset"), scribus_setimageoffset, METH_VARARGS, tr(scribus_setimageoffset__doc__)}, + {const_cast<char*>("selectionCount"), (PyCFunction)scribus_selcount, METH_NOARGS, tr(scribus_selcount__doc__)}, + {const_cast<char*>("selectObject"), scribus_selectobj, METH_VARARGS, tr(scribus_selectobj__doc__)}, + {const_cast<char*>("selectText"), scribus_selecttext, METH_VARARGS, tr(scribus_selecttext__doc__)}, + {const_cast<char*>("sentToLayer"), scribus_senttolayer, METH_VARARGS, tr(scribus_senttolayer__doc__)}, + {const_cast<char*>("setActiveLayer"), scribus_setactlayer, METH_VARARGS, tr(scribus_setactlayer__doc__)}, + {const_cast<char*>("setPDFBookmark"), scribus_setpdfbookmark, METH_VARARGS, tr(scribus_setpdfbookmark__doc__)}, + {const_cast<char*>("isPDFBookmark"), scribus_ispdfbookmark, METH_VARARGS, tr(scribus_ispdfbookmark__doc__)}, + {const_cast<char*>("setTextDistances"), scribus_settextdistances, METH_VARARGS, tr(scribus_settextdistances__doc__)}, + {const_cast<char*>("setColumnGap"), scribus_setcolumngap, METH_VARARGS, tr(scribus_setcolumngap__doc__)}, + {const_cast<char*>("setColumns"), scribus_setcolumns, METH_VARARGS, tr(scribus_setcolumns__doc__)}, + {const_cast<char*>("setCornerRadius"), scribus_setcornerrad, METH_VARARGS, tr(scribus_setcornerrad__doc__)}, + {const_cast<char*>("setCursor"), scribus_setcursor, METH_VARARGS, tr(scribus_setcursor__doc__)}, + {const_cast<char*>("setDocType"), scribus_setdoctype, METH_VARARGS, tr(scribus_setdoctype__doc__)}, + {const_cast<char*>("setFillColor"), scribus_setfillcolor, METH_VARARGS, tr(scribus_setfillcolor__doc__)}, + {const_cast<char*>("setFillTransparency"), scribus_setfilltrans, METH_VARARGS, tr(scribus_setfilltrans__doc__)}, + {const_cast<char*>("setFillBlendmode"), scribus_setfillblend, METH_VARARGS, tr(scribus_setfillblend__doc__)}, + {const_cast<char*>("setFillShade"), scribus_setfillshade, METH_VARARGS, tr(scribus_setfillshade__doc__)}, + {const_cast<char*>("setFont"), scribus_setfont, METH_VARARGS, tr(scribus_setfont__doc__)}, + {const_cast<char*>("setFontSize"), scribus_setfontsize, METH_VARARGS, tr(scribus_setfontsize__doc__)}, + {const_cast<char*>("setGradientFill"), scribus_setgradfill, METH_VARARGS, tr(scribus_setgradfill__doc__)}, + {const_cast<char*>("setGradientStop"), scribus_setgradstop, METH_VARARGS, tr(scribus_setgradstop__doc__)}, + {const_cast<char*>("setHGuides"), scribus_setHguides, METH_VARARGS, tr(scribus_setHguides__doc__)}, + {const_cast<char*>("setInfo"), scribus_setinfo, METH_VARARGS, tr(scribus_setinfo__doc__)}, + {const_cast<char*>("setLayerPrintable"), scribus_layerprint, METH_VARARGS, tr(scribus_layerprint__doc__)}, + {const_cast<char*>("setLayerVisible"), scribus_layervisible, METH_VARARGS, tr(scribus_layervisible__doc__)}, + {const_cast<char*>("setLayerLocked"), scribus_layerlock, METH_VARARGS, tr(scribus_layerlock__doc__)}, + {const_cast<char*>("setLayerOutlined"), scribus_layeroutline, METH_VARARGS, tr(scribus_layeroutline__doc__)}, + {const_cast<char*>("setLayerFlow"), scribus_layerflow, METH_VARARGS, tr(scribus_layerflow__doc__)}, + {const_cast<char*>("setLayerBlendmode"), scribus_layerblend, METH_VARARGS, tr(scribus_layerblend__doc__)}, + {const_cast<char*>("setLayerTransparency"), scribus_layertrans, METH_VARARGS, tr(scribus_layertrans__doc__)}, + {const_cast<char*>("setLineCap"), scribus_setlinecap, METH_VARARGS, tr(scribus_setlinecap__doc__)}, + {const_cast<char*>("setLineColor"), scribus_setlinecolor, METH_VARARGS, tr(scribus_setlinecolor__doc__)}, + {const_cast<char*>("setLineTransparency"), scribus_setlinetrans, METH_VARARGS, tr(scribus_setlinetrans__doc__)}, + {const_cast<char*>("setLineBlendmode"), scribus_setlineblend, METH_VARARGS, tr(scribus_setlineblend__doc__)}, + {const_cast<char*>("setLineJoin"), scribus_setlinejoin, METH_VARARGS, tr(scribus_setlinejoin__doc__)}, + {const_cast<char*>("setLineShade"), scribus_setlineshade, METH_VARARGS, tr(scribus_setlineshade__doc__)}, + {const_cast<char*>("setLineSpacing"), scribus_setlinespace, METH_VARARGS, tr(scribus_setlinespace__doc__)}, + {const_cast<char*>("setLineStyle"), scribus_setlinestyle, METH_VARARGS, tr(scribus_setlinestyle__doc__)}, + {const_cast<char*>("setLineWidth"), scribus_setlinewidth, METH_VARARGS, tr(scribus_setlinewidth__doc__)}, + {const_cast<char*>("setMargins"), scribus_setmargins, METH_VARARGS, tr(scribus_setmargins__doc__)}, + {const_cast<char*>("setMultiLine"), scribus_setmultiline, METH_VARARGS, tr(scribus_setmultiline__doc__)}, + // duplicity? {"setMultiLine", scribus_setmultiline, METH_VARARGS, "TODO: docstring"}, + {const_cast<char*>("setRedraw"), scribus_setredraw, METH_VARARGS, tr(scribus_setredraw__doc__)}, + // missing? {"setSelectedObject", scribus_setselobjnam, METH_VARARGS, "Returns the Name of the selecteted Object. \"nr\" if given indicates the Number of the selected Object, e.g. 0 means the first selected Object, 1 means the second selected Object and so on."}, + {const_cast<char*>("hyphenateText"), scribus_hyphenatetext, METH_VARARGS, tr(scribus_hyphenatetext__doc__)}, + {const_cast<char*>("dehyphenateText"), scribus_dehyphenatetext, METH_VARARGS, tr(scribus_dehyphenatetext__doc__)}, + {const_cast<char*>("setScaleImageToFrame"), (PyCFunction)scribus_setscaleimagetoframe, METH_KEYWORDS, tr(scribus_setscaleimagetoframe__doc__)}, + {const_cast<char*>("setStyle"), scribus_setstyle, METH_VARARGS, tr(scribus_setstyle__doc__)}, + {const_cast<char*>("setTextAlignment"), scribus_setalign, METH_VARARGS, tr(scribus_setalign__doc__)}, + {const_cast<char*>("setTextColor"), scribus_settextfill, METH_VARARGS, tr(scribus_settextfill__doc__)}, + {const_cast<char*>("setText"), scribus_setboxtext, METH_VARARGS, tr(scribus_setboxtext__doc__)}, + {const_cast<char*>("setTextScalingH"), scribus_settextscalingh, METH_VARARGS, tr(scribus_settextscalingh__doc__)}, + {const_cast<char*>("setTextScalingV"), scribus_settextscalingv, METH_VARARGS, tr(scribus_settextscalingv__doc__)}, + {const_cast<char*>("setTextShade"), scribus_settextshade, METH_VARARGS, tr(scribus_settextshade__doc__)}, + {const_cast<char*>("setTextStroke"), scribus_settextstroke, METH_VARARGS, tr(scribus_settextstroke__doc__)}, + {const_cast<char*>("setUnit"), scribus_setunit, METH_VARARGS, tr(scribus_setunit__doc__)}, + {const_cast<char*>("setVGuides"), scribus_setVguides, METH_VARARGS, tr(scribus_setVguides__doc__)}, + {const_cast<char*>("sizeObject"), scribus_sizeobjabs, METH_VARARGS, tr(scribus_sizeobjabs__doc__)}, + {const_cast<char*>("statusMessage"), scribus_messagebartext, METH_VARARGS, tr(scribus_messagebartext__doc__)}, + {const_cast<char*>("textFlowMode"), scribus_textflow, METH_VARARGS, tr(scribus_textflow__doc__)}, + {const_cast<char*>("traceText"), scribus_tracetext, METH_VARARGS, tr(scribus_tracetext__doc__)}, + {const_cast<char*>("unGroupObject"), scribus_ungroupobj, METH_VARARGS, tr(scribus_ungroupobj__doc__)}, + {const_cast<char*>("unlinkTextFrames"), scribus_unlinktextframes, METH_VARARGS, tr(scribus_unlinktextframes__doc__)}, + {const_cast<char*>("valueDialog"), scribus_valdialog, METH_VARARGS, tr(scribus_valdialog__doc__)}, + {const_cast<char*>("textOverflows"), (PyCFunction)scribus_istextoverflowing, METH_KEYWORDS, tr(scribus_istextoverflowing__doc__)}, + {const_cast<char*>("zoomDocument"), scribus_zoomdocument, METH_VARARGS, tr(scribus_zoomdocument__doc__)}, + {const_cast<char*>("scrollDocument"), scribus_scrolldocument, METH_VARARGS, tr(scribus_scrolldocument__doc__)}, + {const_cast<char*>("moveSelectionToBack"), (PyCFunction)scribus_moveselectiontoback, METH_NOARGS, tr(scribus_moveselectiontoback__doc__)}, + {const_cast<char*>("moveSelectionToFront"), (PyCFunction)scribus_moveselectiontofront, METH_NOARGS, tr(scribus_moveselectiontofront__doc__)}, + // Property magic + {const_cast<char*>("getPropertyCType"), (PyCFunction)scribus_propertyctype, METH_KEYWORDS, tr(scribus_propertyctype__doc__)}, + {const_cast<char*>("getPropertyNames"), (PyCFunction)scribus_getpropertynames, METH_KEYWORDS, tr(scribus_getpropertynames__doc__)}, + {const_cast<char*>("getProperty"), (PyCFunction)scribus_getproperty, METH_KEYWORDS, tr(scribus_getproperty__doc__)}, + {const_cast<char*>("setProperty"), (PyCFunction)scribus_setproperty, METH_KEYWORDS, tr(scribus_setproperty__doc__)}, +// {const_cast<char*>("getChildren"), (PyCFunction)scribus_getchildren, METH_KEYWORDS, tr(scribus_getchildren__doc__)}, +// {const_cast<char*>("getChild"), (PyCFunction)scribus_getchild, METH_KEYWORDS, tr(scribus_getchild__doc__)}, + // by Christian Hausknecht + {const_cast<char*>("duplicateObject"), scribus_duplicateobject, METH_VARARGS, tr(scribus_duplicateobject__doc__)}, + // Internal methods - Not for public use + {const_cast<char*>("retval"), (PyCFunction)scribus_retval, METH_VARARGS, const_cast<char*>("Scribus internal.")}, + {const_cast<char*>("getval"), (PyCFunction)scribus_getval, METH_NOARGS, const_cast<char*>("Scribus internal.")}, + {NULL, (PyCFunction)(0), 0, NULL} /* sentinel */ +}; + +void initscribus_failed(const char* fileName, int lineNo) +{ + qDebug("Scripter setup failed (%s:%i)", fileName, lineNo); + if (PyErr_Occurred()) + PyErr_Print(); + return; +} + +void initscribus(ScribusMainWindow *pl) +{ + if (!scripterCore) + { + qWarning("scriptplugin: Tried to init scribus module, but no scripter core. Aborting."); + return; + } + PyObject *m, *d; + PyImport_AddModule((char*)"scribus"); + + PyType_Ready(&Printer_Type); + PyType_Ready(&PDFfile_Type); + PyType_Ready(&ImageExport_Type); + m = Py_InitModule((char*)"scribus", scribus_methods); + Py_INCREF(&Printer_Type); + PyModule_AddObject(m, (char*)"Printer", (PyObject *) &Printer_Type); + Py_INCREF(&PDFfile_Type); + PyModule_AddObject(m, (char*)"PDFfile", (PyObject *) &PDFfile_Type); + Py_INCREF(&ImageExport_Type); + PyModule_AddObject(m, (char*)"ImageExport", (PyObject *) &ImageExport_Type); + d = PyModule_GetDict(m); + + // Set up the module exceptions + // common exc. + ScribusException = PyErr_NewException((char*)"scribus.ScribusException", NULL, NULL); + Py_INCREF(ScribusException); + PyModule_AddObject(m, (char*)"ScribusException", ScribusException); + // no doc open + NoDocOpenError = PyErr_NewException((char*)"scribus.NoDocOpenError", ScribusException, NULL); + Py_INCREF(NoDocOpenError); + PyModule_AddObject(m, (char*)"NoDocOpenError", NoDocOpenError); + // wrong type of frame for operation + WrongFrameTypeError = PyErr_NewException((char*)"scribus.WrongFrameTypeError", ScribusException, NULL); + Py_INCREF(WrongFrameTypeError); + PyModule_AddObject(m, (char*)"WrongFrameTypeError", WrongFrameTypeError); + // Couldn't find named object, or no named object and no selection + NoValidObjectError = PyErr_NewException((char*)"scribus.NoValidObjectError", ScribusException, NULL); + Py_INCREF(NoValidObjectError); + PyModule_AddObject(m, (char*)"NoValidObjectError", NoValidObjectError); + // Couldn't find the specified resource - font, color, etc. + NotFoundError = PyErr_NewException((char*)"scribus.NotFoundError", ScribusException, NULL); + Py_INCREF(NotFoundError); + PyModule_AddObject(m, (char*)"NotFoundError", NotFoundError); + // Tried to create an object with the same name as one that already exists + NameExistsError = PyErr_NewException((char*)"scribus.NameExistsError", ScribusException, NULL); + Py_INCREF(NameExistsError); + PyModule_AddObject(m, (char*)"NameExistsError", NameExistsError); + // Done with exception setup + + // CONSTANTS + PyDict_SetItemString(d, const_cast<char*>("UNIT_POINTS"), PyInt_FromLong(unitIndexFromString("pt"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_MILLIMETERS"), PyInt_FromLong(unitIndexFromString("mm"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_INCHES"), PyInt_FromLong(unitIndexFromString("in"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_PICAS"), PyInt_FromLong(unitIndexFromString("p"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_CENTIMETRES"), PyInt_FromLong(unitIndexFromString("cm"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_CICERO"), PyInt_FromLong(unitIndexFromString("c"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_PT"), PyInt_FromLong(unitIndexFromString("pt"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_MM"), PyInt_FromLong(unitIndexFromString("mm"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_IN"), PyInt_FromLong(unitIndexFromString("in"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_P"), PyInt_FromLong(unitIndexFromString("p"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_CM"), PyInt_FromLong(unitIndexFromString("cm"))); + PyDict_SetItemString(d, const_cast<char*>("UNIT_C"), PyInt_FromLong(unitIndexFromString("c"))); + PyDict_SetItemString(d, const_cast<char*>("PORTRAIT"), Py_BuildValue(const_cast<char*>("i"), portraitPage)); + PyDict_SetItemString(d, const_cast<char*>("LANDSCAPE"), Py_BuildValue(const_cast<char*>("i"), landscapePage)); + PyDict_SetItemString(d, const_cast<char*>("NOFACINGPAGES"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("FACINGPAGES"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("FIRSTPAGERIGHT"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("FIRSTPAGELEFT"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("ALIGN_LEFT"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("ALIGN_RIGHT"), Py_BuildValue(const_cast<char*>("i"), 2)); + PyDict_SetItemString(d, const_cast<char*>("ALIGN_CENTERED"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("ALIGN_BLOCK"), Py_BuildValue(const_cast<char*>("i"), 4)); + PyDict_SetItemString(d, const_cast<char*>("ALIGN_FORCED"), Py_BuildValue(const_cast<char*>("i"), 4)); + PyDict_SetItemString(d, const_cast<char*>("FILL_NOG"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("FILL_HORIZONTALG"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("FILL_VERTICALG"), Py_BuildValue(const_cast<char*>("i"), 2)); + PyDict_SetItemString(d, const_cast<char*>("FILL_DIAGONALG"), Py_BuildValue(const_cast<char*>("i"), 3)); + PyDict_SetItemString(d, const_cast<char*>("FILL_CROSSDIAGONALG"), Py_BuildValue(const_cast<char*>("i"), 4)); + PyDict_SetItemString(d, const_cast<char*>("FILL_RADIALG"), Py_BuildValue(const_cast<char*>("i"), 5)); + PyDict_SetItemString(d, const_cast<char*>("LINE_SOLID"), Py_BuildValue(const_cast<char*>("i"), Qt::SolidLine)); + PyDict_SetItemString(d, const_cast<char*>("LINE_DASH"), Py_BuildValue(const_cast<char*>("i"), Qt::DashLine)); + PyDict_SetItemString(d, const_cast<char*>("LINE_DOT"), Py_BuildValue(const_cast<char*>("i"), Qt::DotLine)); + PyDict_SetItemString(d, const_cast<char*>("LINE_DASHDOT"), Py_BuildValue(const_cast<char*>("i"), Qt::DashDotLine)); + PyDict_SetItemString(d, const_cast<char*>("LINE_DASHDOTDOT"), Py_BuildValue(const_cast<char*>("i"), Qt::DashDotDotLine)); + PyDict_SetItemString(d, const_cast<char*>("JOIN_MITTER"), Py_BuildValue(const_cast<char*>("i"), Qt::MiterJoin)); + PyDict_SetItemString(d, const_cast<char*>("JOIN_BEVEL"), Py_BuildValue(const_cast<char*>("i"), Qt::BevelJoin)); + PyDict_SetItemString(d, const_cast<char*>("JOIN_ROUND"), Py_BuildValue(const_cast<char*>("i"), Qt::RoundJoin)); + PyDict_SetItemString(d, const_cast<char*>("CAP_FLAT"), Py_BuildValue(const_cast<char*>("i"), Qt::FlatCap)); + PyDict_SetItemString(d, const_cast<char*>("CAP_SQUARE"), Py_BuildValue(const_cast<char*>("i"), Qt::SquareCap)); + PyDict_SetItemString(d, const_cast<char*>("CAP_ROUND"), Py_BuildValue(const_cast<char*>("i"), Qt::RoundCap)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_NONE"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::NoButton)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_OK"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Ok)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_CANCEL"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Cancel)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_YES"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Yes)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_NO"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::No)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_ABORT"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Abort)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_RETRY"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Retry)); + PyDict_SetItemString(d, const_cast<char*>("BUTTON_IGNORE"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Ignore)); + PyDict_SetItemString(d, const_cast<char*>("ICON_NONE"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::NoIcon)); + PyDict_SetItemString(d, const_cast<char*>("ICON_INFORMATION"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Information)); + PyDict_SetItemString(d, const_cast<char*>("ICON_WARNING"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Warning)); + PyDict_SetItemString(d, const_cast<char*>("ICON_CRITICAL"), Py_BuildValue(const_cast<char*>("i"), QMessageBox::Critical)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A0"), Py_BuildValue(const_cast<char*>("(ff)"), 2380.0, 3368.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A1"), Py_BuildValue(const_cast<char*>("(ff)"), 1684.0, 2380.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A2"), Py_BuildValue(const_cast<char*>("(ff)"), 1190.0, 1684.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A3"), Py_BuildValue(const_cast<char*>("(ff)"), 842.0, 1190.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A4"), Py_BuildValue(const_cast<char*>("(ff)"), 595.0, 842.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A5"), Py_BuildValue(const_cast<char*>("(ff)"), 421.0, 595.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A6"), Py_BuildValue(const_cast<char*>("(ff)"), 297.0, 421.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A7"), Py_BuildValue(const_cast<char*>("(ff)"), 210.0, 297.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A8"), Py_BuildValue(const_cast<char*>("(ff)"), 148.0, 210.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_A9"), Py_BuildValue(const_cast<char*>("(ff)"), 105.0, 148.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B0"), Py_BuildValue(const_cast<char*>("(ff)"), 2836.0, 4008.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B1"), Py_BuildValue(const_cast<char*>("(ff)"), 2004.0, 2836.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B2"), Py_BuildValue(const_cast<char*>("(ff)"), 1418.0, 2004.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B3"), Py_BuildValue(const_cast<char*>("(ff)"), 1002.0, 1418.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B4"), Py_BuildValue(const_cast<char*>("(ff)"), 709.0, 1002.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B5"), Py_BuildValue(const_cast<char*>("(ff)"), 501.0, 709.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B6"), Py_BuildValue(const_cast<char*>("(ff)"), 355.0, 501.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B7"), Py_BuildValue(const_cast<char*>("(ff)"), 250.0, 355.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B8"), Py_BuildValue(const_cast<char*>("(ff)"), 178.0, 250.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B9"), Py_BuildValue(const_cast<char*>("(ff)"), 125.0, 178.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_B10"), Py_BuildValue(const_cast<char*>("(ff)"), 89.0, 125.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_C5E"), Py_BuildValue(const_cast<char*>("(ff)"), 462.0, 649.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_COMM10E"), Py_BuildValue(const_cast<char*>("(ff)"), 298.0, 683.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_DLE"), Py_BuildValue(const_cast<char*>("(ff)"), 312.0, 624.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_EXECUTIVE"), Py_BuildValue(const_cast<char*>("(ff)"), 542.0, 720.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_FOLIO"), Py_BuildValue(const_cast<char*>("(ff)"), 595.0, 935.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_LEDGER"), Py_BuildValue(const_cast<char*>("(ff)"), 1224.0, 792.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_LEGAL"), Py_BuildValue(const_cast<char*>("(ff)"), 612.0, 1008.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_LETTER"), Py_BuildValue(const_cast<char*>("(ff)"), 612.0, 792.0)); + PyDict_SetItemString(d, const_cast<char*>("PAPER_TABLOID"), Py_BuildValue(const_cast<char*>("(ff)"), 792.0, 1224.0)); + PyDict_SetItemString(d, const_cast<char*>("NORMAL"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("DARKEN"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("LIGHTEN"), Py_BuildValue(const_cast<char*>("i"), 2)); + PyDict_SetItemString(d, const_cast<char*>("MULTIPLY"), Py_BuildValue(const_cast<char*>("i"), 3)); + PyDict_SetItemString(d, const_cast<char*>("SCREEN"), Py_BuildValue(const_cast<char*>("i"), 4)); + PyDict_SetItemString(d, const_cast<char*>("OVERLAY"), Py_BuildValue(const_cast<char*>("i"), 5)); + PyDict_SetItemString(d, const_cast<char*>("HARD_LIGHT"), Py_BuildValue(const_cast<char*>("i"), 6)); + PyDict_SetItemString(d, const_cast<char*>("SOFT_LIGHT"), Py_BuildValue(const_cast<char*>("i"), 7)); + PyDict_SetItemString(d, const_cast<char*>("DIFFERENCE"), Py_BuildValue(const_cast<char*>("i"), 8)); + PyDict_SetItemString(d, const_cast<char*>("EXCLUSION"), Py_BuildValue(const_cast<char*>("i"), 9)); + PyDict_SetItemString(d, const_cast<char*>("COLOR_DODGE"), Py_BuildValue(const_cast<char*>("i"), 10)); + PyDict_SetItemString(d, const_cast<char*>("COLOR_BURN"), Py_BuildValue(const_cast<char*>("i"), 11)); + PyDict_SetItemString(d, const_cast<char*>("HUE"), Py_BuildValue(const_cast<char*>("i"), 12)); + PyDict_SetItemString(d, const_cast<char*>("SATURATION"), Py_BuildValue(const_cast<char*>("i"), 13)); + PyDict_SetItemString(d, const_cast<char*>("COLOR"), Py_BuildValue(const_cast<char*>("i"), 14)); + PyDict_SetItemString(d, const_cast<char*>("LUMINOSITY"), Py_BuildValue(const_cast<char*>("i"), 15)); + // preset page layouts + PyDict_SetItemString(d, const_cast<char*>("PAGE_1"), Py_BuildValue(const_cast<char*>("i"), 0)); + PyDict_SetItemString(d, const_cast<char*>("PAGE_2"), Py_BuildValue(const_cast<char*>("i"), 1)); + PyDict_SetItemString(d, const_cast<char*>("PAGE_3"), Py_BuildValue(const_cast<char*>("i"), 2)); + PyDict_SetItemString(d, const_cast<char*>("PAGE_4"), Py_BuildValue(const_cast<char*>("i"), 3)); + + // Measurement units understood by Scribus's units.cpp functions are exported as constant conversion + // factors to be used from Python. + for (int i = 0; i <= unitGetMaxIndex(); ++i) + { + PyObject* value = PyFloat_FromDouble(unitGetRatioFromIndex(i)); + if (!value) + { + initscribus_failed(__FILE__, __LINE__); + return; + } + // `in' is a reserved word in Python so we must replace it + PyObject* name; + if (unitGetStrFromIndex(i) == "in") + name = PyString_FromString("inch"); + else + name = PyString_FromString(unitGetStrFromIndex(i).toAscii().constData()); + if (!name) + { + initscribus_failed(__FILE__, __LINE__); + return; + } + if (PyDict_SetItem(d, name, value)) + { + initscribus_failed(__FILE__, __LINE__); + return; + } + } + + // Export the Scribus version into the module namespace so scripts know what they're running in + PyDict_SetItemString(d, const_cast<char*>("scribus_version"), PyString_FromString(const_cast<char*>(VERSION))); + // Now build a version tuple like that provided by Python in sys.version_info + // The tuple is of the form (major, minor, patchlevel, extraversion, reserved) + QRegExp version_re("(\\d+)\\.(\\d+)\\.(\\d+)(.*)"); + int pos = version_re.indexIn(QString(VERSION)); + // We ignore errors, causing the scribus_version_info attribute to simply not be created. + // This will make acceses raise AttrbuteError. + if (pos > -1) + { + int majorVersion = version_re.cap(1).toInt(); + int minorVersion = version_re.cap(2).toInt(); + int patchVersion = version_re.cap(3).toInt(); + QString extraVersion = version_re.cap(4); + PyObject* versionTuple = Py_BuildValue(const_cast<char*>("(iiisi)"),\ + majorVersion, minorVersion, patchVersion, (const char*)extraVersion.toUtf8(), 0); + if (versionTuple != NULL) + PyDict_SetItemString(d, const_cast<char*>("scribus_version_info"), versionTuple); + else + qDebug("Failed to build version tuple for version string '%s' in scripter", VERSION); + } + else + qDebug("Couldn't parse version string '%s' in scripter", VERSION); + +// ScMW = pl; + // Function aliases for compatibility + // We need to import the __builtins__, warnings and exceptions modules to be able to run + // the generated Python functions from inside the `scribus' module's context. + // This code makes it possible to extend the `scribus' module by running Python code + // from C in other ways too. + PyObject* builtinModule = PyImport_ImportModuleEx(const_cast<char*>("__builtin__"), + d, d, Py_BuildValue(const_cast<char*>("[]"))); + if (builtinModule == NULL) + { + qDebug("Failed to import __builtin__ module. Something is probably broken with your Python."); + return; + } + PyDict_SetItemString(d, const_cast<char*>("__builtin__"), builtinModule); + PyObject* exceptionsModule = PyImport_ImportModuleEx(const_cast<char*>("exceptions"), + d, d, Py_BuildValue(const_cast<char*>("[]"))); + if (exceptionsModule == NULL) + { + qDebug("Failed to import exceptions module. Something is probably broken with your Python."); + return; + } + PyDict_SetItemString(d, const_cast<char*>("exceptions"), exceptionsModule); + PyObject* warningsModule = PyImport_ImportModuleEx(const_cast<char*>("warnings"), + d, d, Py_BuildValue(const_cast<char*>("[]"))); + if (warningsModule == NULL) + { + qDebug("Failed to import warnings module. Something is probably broken with your Python."); + return; + } + PyDict_SetItemString(d, const_cast<char*>("warnings"), warningsModule); + // Create the module-level docstring. This can be a proper unicode string, unlike + // the others, because we can just create a Unicode object and insert it in our + // module dictionary. + QString docstring = QObject::tr("Scribus Python interface module\n\ +\n\ +This module is the Python interface for Scribus. It provides functions\n\ +to control scribus and to manipulate objects on the canvas. Each\n\ +function is documented individually below.\n\ +\n\ +A few things are common across most of the interface.\n\ +\n\ +Most functions operate on frames. Frames are identified by their name,\n\ +a string - they are not real Python objects. Many functions take an\n\ +optional (non-keyword) parameter, a frame name.\n\ +Many exceptions are also common across most functions. These are\n\ +not currently documented in the docstring for each function.\n\ +- Many functions will raise a NoDocOpenError if you try to use them\n\ +without a document to operate on.\n\ +- If you do not pass a frame name to a function that requires one,\n\ +the function will use the currently selected frame, if any, or\n\ +raise a NoValidObjectError if it can't find anything to operate\n\ +on.\n\ +- Many functions will raise WrongFrameTypeError if you try to use them\n\ +on a frame type that they do not make sense with. For example, setting\n\ +the text color on a graphics frame doesn't make sense, and will result\n\ +in this exception being raised.\n\ +- Errors resulting from calls to the underlying Python API will be\n\ +passed through unaltered. As such, the list of exceptions thrown by\n\ +any function as provided here and in its docstring is incomplete.\n\ +\n\ +Details of what exceptions each function may throw are provided on the\n\ +function's documentation, though as with most Python code this list\n\ +is not exhaustive due to exceptions from called functions.\n\ +"); + + PyObject* docStr = PyString_FromString(docstring.toUtf8().data()); + if (!docStr) + qDebug("Failed to create module-level docstring (couldn't make str)"); + else + { + PyObject* uniDocStr = PyUnicode_FromEncodedObject(docStr, "utf-8", NULL); + Py_DECREF(docStr); + docStr = NULL; + if (!uniDocStr) + qDebug("Failed to create module-level docstring object (couldn't make unicode)"); + else + PyDict_SetItemString(d, const_cast<char*>("__doc__"), uniDocStr); + Py_DECREF(uniDocStr); + uniDocStr = NULL; + } + + // Wrap up pointers to the the QApp and main window and push them out + // to Python. + wrappedQApp = wrapQObject(qApp); + if (!wrappedQApp) + { + qDebug("Failed to wrap up QApp"); + PyErr_Print(); + } + // Push it into the module dict, stealing a ref in the process + PyDict_SetItemString(d, const_cast<char*>("qApp"), wrappedQApp); + Py_DECREF(wrappedQApp); + wrappedQApp = NULL; + + wrappedMainWindow = wrapQObject(pl); + if (!wrappedMainWindow) + { + qDebug("Failed to wrap up ScMW"); + PyErr_Print(); + } + // Push it into the module dict, stealing a ref in the process + PyDict_SetItemString(d, const_cast<char*>("mainWindow"), wrappedMainWindow); + Py_DECREF(wrappedMainWindow); + wrappedMainWindow = NULL; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void scriptplugindocwarnings() +{ + QStringList s; + s <<printer__doc__<<pdffile__doc__<<imgexp__doc__<<imgexp_dpi__doc__<<imgexp_scale__doc__ <<imgexp_quality__doc__<<imgexp_filename__doc__<<imgexp_type__doc__<<imgexp_alltypes__doc__ << imgexp_save__doc__ << imgexp_saveas__doc__; +} diff --git a/scribus/plugins/scriptplugin/scriptplugin.h b/scribus/plugins/scriptplugin/scriptplugin.h new file mode 100644 index 0000000..0b136b2 --- /dev/null +++ b/scribus/plugins/scriptplugin/scriptplugin.h @@ -0,0 +1,50 @@ +/* +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. +*/ +#ifndef SCRIPTPLUG_H +#define SCRIPTPLUG_H + +#include "cmdvar.h" +#include "scplugin.h" +#include "pluginapi.h" +//Added by qt3to4: +#include <QPixmap> + +class QString; +class QPixmap; +class QWidget; +class PrefsPanel; + +class PLUGIN_API ScriptPlugin : public ScPersistentPlugin +{ + Q_OBJECT + + public: + // Standard plugin implementation + ScriptPlugin(); + virtual ~ScriptPlugin(); + virtual bool initPlugin(); + virtual bool cleanupPlugin(); + virtual const QString fullTrName() const; + virtual const AboutData* getAboutData() const; + virtual void deleteAboutData(const AboutData* about) const; + virtual void languageChange(); + virtual bool newPrefsPanelWidget(QWidget* parent, PrefsPanel*& panel, + QString& caption, QPixmap& icon); + virtual void addToMainWindowMenu(ScribusMainWindow *); + + // Special features (none) +}; + +extern "C" PLUGIN_API int scriptplugin_getPluginAPIVersion(); +extern "C" PLUGIN_API ScPlugin* scriptplugin_getPlugin(); +extern "C" PLUGIN_API void scriptplugin_freePlugin(ScPlugin* plugin); + +/** Some useful Subroutines */ +/*static */PyObject *scribus_retval(PyObject *self, PyObject* args); +/*static */PyObject *scribus_getval(PyObject *self); + +#endif // CMSPLUG_H diff --git a/scribus/plugins/scriptplugin/scripts/Autoquote.py b/scribus/plugins/scriptplugin/scripts/Autoquote.py new file mode 100644 index 0000000..daa58f9 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/Autoquote.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# File: quotes.py - changes typewriter quotes to typographic quotes +# © 2010.08.28 Gregory Pittman +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +""" +USAGE + +You must have a document open, and a text frame selected. +There will be a valueDialog asking for your language for the quotes, +the default is 'en', but change the default to suit your needs. +Detected errors shut down the script with an appropriate message. + +""" +import scribus + +if scribus.haveDoc(): + c = 0 + lang = scribus.valueDialog("Choose by language or country", 'Language: af, be, ch, cs, de, en, es, et, fi, fr,\n hu, is, lt, mk, nl, pl, ru, se, sk, sl, sq and uk\n are current choices','en') + if (lang == 'en'): + lead_double = u"\u201c" + follow_double = u"\u201d" + lead_single = u"\u2018" + follow_single = u"\u2019" + elif (lang == 'de'): + lead_double = u"\u201e" + follow_double = u"\u201c" + lead_single = u"\u2019" + follow_single = u"\u201a" + elif (lang == 'fr'): + lead_double = u"\u00ab" + follow_double = u"\u00bb" + lead_single = u"\u2018" + follow_single = u"\u2019" # am hoping this will cover contractions like je t'aime + elif (lang == 'pl'): + lead_double = u"\u201e" + follow_double = u"\u201d" + lead_single = u"\u201a" + follow_single = u"\u2019" + elif ((lang == 'se') or (lang == 'fi')): + lead_double = u"\u201d" + follow_double = u"\u201d" + lead_single = u"\u2019" + follow_single = u"\u2019" + elif (lang == 'af'): + lead_double = u"\u201c" + follow_double = u"\u201d" + lead_single = u"\u2018" + follow_single = u"\u2019" + elif (lang == 'sq'): + lead_double = u"\u201e" + follow_double = u"\u201c" + lead_single = u"\u2018" + follow_single = u"\u2019" + elif ((lang == 'be') or (lang == 'ch') or (lang == 'uk') or (lang == 'ru')): + lead_double = u"\u00ab" + follow_double = u"\u00bb" + lead_single = u"\u2039" + follow_single = u"\u203a" + elif (lang == 'uk'): + lead_double = u"\u00ab" + follow_double = u"\u00bb" + lead_single = u"\u2039" + follow_single = u"\u203a" + elif (lang == 'es'): + lead_double = u"\u00ab" + follow_double = u"\u00bb" + follow_double = u"\u201d" + lead_single = u"\u2018" + elif ((lang == 'lt') or (lang == 'mk') or (lang == 'is') or (lang == 'sk') or (lang == 'sl') or (lang == 'cs') or (lang == 'et')): + lead_double = u"\u201e" + follow_double = u"\u201c" + lead_single = u"\u2019" + follow_single = u"\u201a" + elif ((lang == 'hu') or (lang == 'nl')): + lead_double = u"\u201e" + follow_double = u"\u201d" + lead_single = u"\u00bb" + follow_single = u"\u00ab" + else: + scribus.messageBox('Language Error', 'You need to choose an available language', icon=0, button1=1) + sys.exit(2) + +else: + scribus.messageBox('Usage Error', 'You need a Document open', icon=0, button1=1) + sys.exit(2) + +if scribus.selectionCount() == 0: + scribus.messageBox('Scribus - Usage Error', + "There is no object selected.\nPlease select a text frame and try again.", + scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) +if scribus.selectionCount() > 1: + scribus.messageBox('Scribus - Usage Error', + "You have more than one object selected.\nPlease select one text frame and try again.", scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) +textbox = scribus.getSelectedObject() +pageitems = scribus.getPageItems() +boxcount = 1 +for item in pageitems: + if (item[0] == textbox): + if (item[1] != 4): + scribus.messageBox('Scribus - Usage Error', "This is not a textframe. Try again.", scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) +contents = scribus.getTextLength(textbox) +while c <= (contents -1): + if ((c + 1) > contents - 1): + nextchar = ' ' + else: + scribus.selectText(c+1, 1, textbox) + nextchar = scribus.getText(textbox) + scribus.selectText(c, 1, textbox) + char = scribus.getText(textbox) + if (len(char) != 1): + c += 1 + continue + if ((ord(char) == 34) and (c == 0)): + scribus.deleteText(textbox) + scribus.insertText(lead_double, c, textbox) + elif (ord(char) == 34): + if ((prevchar == '.') or (prevchar == ',') or (prevchar == '?') or (prevchar == '!')): + scribus.deleteText(textbox) + scribus.insertText(follow_double, c, textbox) + elif ((ord(prevchar) == 39) and ((nextchar != ' ') and (nextchar != ',') and (nextchar != '.'))): + scribus.deleteText(textbox) + scribus.insertText(lead_double, c, textbox) + elif ((nextchar == '.') or (nextchar == ',')): + scribus.deleteText(textbox) + scribus.insertText(follow_double, c, textbox) + + elif ((prevchar == ' ') or ((nextchar != ' ') and (ord(nextchar) != 39))): + scribus.deleteText(textbox) + scribus.insertText(lead_double, c, textbox) + else: + scribus.deleteText(textbox) + scribus.insertText(follow_double, c, textbox) + + if ((ord(char) == 39) and (c == 0)): + scribus.deleteText(textbox) + scribus.insertText(lead_single, c, textbox) + elif (ord(char) == 39): + if ((prevchar == '.') or (prevchar == ',') or (prevchar == '?') or (prevchar == '!')): + scribus.deleteText(textbox) + scribus.insertText(follow_single, c, textbox) + elif ((ord(prevchar) == 34) and ((nextchar != ' ') and (nextchar != ',') and (nextchar != '.'))): + scribus.deleteText(textbox) + scribus.insertText(lead_single, c, textbox) + elif ((prevchar != ' ') and (ord(prevchar) != 34) and (nextchar != ' ')): + scribus.deleteText(textbox) + scribus.insertText(follow_single, c, textbox) + elif ((prevchar == ' ') or ((nextchar != ' ') and (ord(nextchar) != 34))): + scribus.deleteText(textbox) + scribus.insertText(lead_single, c, textbox) + else: + scribus.deleteText(textbox) + scribus.insertText(follow_single, c, textbox) + + c += 1 + prevchar = char + +scribus.setRedraw(1) +scribus.docChanged(1) +endmessage = 'Successfully ran script\n Last character read was '+str(char) # Change this message to your liking +scribus.messageBox("Finished", endmessage,icon=0,button1=1)
\ No newline at end of file diff --git a/scribus/plugins/scriptplugin/scripts/CMakeLists.txt b/scribus/plugins/scriptplugin/scripts/CMakeLists.txt new file mode 100644 index 0000000..814d191 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/CMakeLists.txt @@ -0,0 +1,20 @@ +INCLUDE_DIRECTORIES( +"${CMAKE_SOURCE_DIR}/scribus" +) + +INSTALL(FILES +Autoquote.py +CalendarWizard.py +ColorChart.py +DirectImageImport.py +FontSample.py +InfoBox.py +ChangeLog +NEWS +ReadMe +TODO +color2csv.py +csv2color.py +importcsv2table.py + DESTINATION ${SCRIPTSDIR} +) diff --git a/scribus/plugins/scriptplugin/scripts/CalendarWizard.py b/scribus/plugins/scriptplugin/scripts/CalendarWizard.py new file mode 100644 index 0000000..8b46eba --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/CalendarWizard.py @@ -0,0 +1,670 @@ +# -*- coding: utf-8 -*- + +""" This is a simple 'Calendar creation wizard' for Scribus. It's a fully +rewritten Calender.py from Scribus examples. Enjoy. + +DESCRIPTION & USAGE: +This script needs Tkinter. It will create a GUI with available options +for easy calendar page creation. You'll get new pages with calendar +tables into a new document you are asked for. Position of the +objects in page is calculated with the "golden-ratio" aspect from the +page margins. + +Steps to create: + 1) Fill requested values in the Calendar dialog + 2) You will be prompted for new document + 3) You will be prompted for new paragraph style which will be used + in calendar text frames. It could be changed later. + +There are 2 types of calendar supported: + 1) Classic calendar with one month matrix per page. I suggest + here PORTRAIT orientation. + 2) Horizontal event calendar with one week per page with huge place + for human inputs. There should be LANDSCAPE imho. + 3) Horizontal event calendar with one week per page with huge place + for human inputs. There should be LANDSCAPE imho. + +But everything works with both orientations well of course too. + +AUTHORS: + Petr Vanek <petr@scribus.info> + Bernhard Reiter <ockham@raz.or.at> + +LICENSE: +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + +import sys +import calendar +import datetime + +try: + from scribus import * +except ImportError: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +try: + # I wish PyQt installed everywhere :-/ + from Tkinter import * + from tkFont import Font +except ImportError: + print "This script requires Python's Tkinter properly installed." + messageBox('Script failed', + 'This script requires Python\'s Tkinter properly installed.', + ICON_CRITICAL) + sys.exit(1) + + +localization = { +'Catalan' : + [['Gener', 'Febrer', 'Març', 'Abril', 'Maig', + 'Juny', 'Juliol', 'Agost', 'Setembre', + 'Octubre', 'Novembre', 'Desembre'], + ['Dilluns', 'Dimarts', 'Dimecres', 'Dijous', 'Divendres', 'Dissabte', 'Diumenge']], +'Catalan-short' : + [['Gener', 'Febrer', 'Març', 'Abril', 'Maig', + 'Juny', 'Juliol', 'Agost', 'Setembre', + 'Octubre', 'Novembre', 'Desembre'], + ['Dl', 'Dm', 'Dc', 'Dj', 'Dv', 'Ds', 'Dg']], +# Catalan by "Cesc Morata" <atarom@gmail.com> +'Czech' : + [['Leden', 'Únor', 'Březen', 'Duben', 'Květen', + 'Červen', 'Červenec', 'Srpen', 'Září', + 'Říjen', 'Listopad', 'Prosinec'], + ['Pondělí','Úterý','Středa','Čtvrtek','Pátek','Sobota', 'Neděle']], +'Czech-short' : + [['Leden', 'Únor', 'Březen', 'Duben', 'Květen', + 'Červen', 'Červenec', 'Srpen', 'Září', + 'Říjen', 'Listopad', 'Prosinec'], + ['Po', 'Út', 'St', 'Čt', 'Pá', 'So', 'Ne']], +# Croatian by daweed +'Croatian' : + [['Siječanj', 'Veljača', 'Ožujak', 'Travanj', 'Svibanj', + 'Lipanj', 'Srpanj', 'Kolovoz', 'Rujan', + 'Listopad', 'Studeni', 'Prosinac'], + ['Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota', 'Nedjelja']], + +'Dutch' : + [['Januari', 'Februari', 'Maart', 'April', + 'Mei', 'Juni', 'Juli', 'Augustus', 'September', + 'Oktober', 'November', 'December'], + ['Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag', 'Zondag']], +# Dutch by "Christoph Schäfer" <christoph-schaefer@gmx.de> +'English' : + [['January', 'February', 'March', 'April', + 'May', 'June', 'July', 'August', 'September', + 'October', 'November', 'December'], + ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday', 'Sunday']], +'English-short' : + [['January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', 'October', + 'November', 'December'], + ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']], +'Finnish' : + [['Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', + 'Toukokuu', 'Kesäkuu', 'Heinäkuu', 'Elokuu', 'Syyskuu', + 'Lokakuu', 'Marraskuu', 'Joulukuu'], + ['ma','ti','ke','to','pe','la', 'su']], +'French': + [['Janvier', u'F\xe9vrier', 'Mars', 'Avril', + 'Mai', 'Juin', 'Juillet', u'Ao\xfbt', 'Septembre', + 'Octobre', 'Novembre', u'D\xe9cembre'], + ['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche']], +'German' : + [['Januar', 'Februar', u'M\xe4rz', 'April', + 'Mai', 'Juni', 'Juli', 'August', 'September', + 'Oktober', 'November', 'Dezember'], + ['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag']], +'German (Austrian)' : + [[u'J\xe4nner', 'Feber', u'M\xe4rz', 'April', + 'Mai', 'Juni', 'Juli', 'August', 'September', + 'Oktober', 'November', 'Dezember'], + ['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag']], +# Hungarian by Gergely Szalay szalayg@gmail.com +'Hungarian' : + [['Január', 'Február', 'Március', 'Április', + 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', + 'Október', 'November', 'December'], + ['Hétfő','Kedd','Szerda','Csütörtök','Péntek','Szombat','Vasárnap']], +'Italian' : + [['Gennaio', 'Febbraio', 'Marzo', 'Aprile', + 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', + 'Ottobre', 'Novembre', 'Dicembre'], + [u'Luned\xec', u'Marted\xec', u'Mercoled\xec', u'Gioved\xec', u'Venerd\xec', 'Sabato', 'Domenica']], +# Norwegian by Joacim Thomassen joacim@net.homelinux.org +'Norwegian' : + [['Januar', 'Februar','Mars', 'April','Mai', 'Juni','Juli', 'August','September', 'Oktober', 'November', 'Desember'], + ['Mandag', 'Tirsdag','Onsdag', 'Torsdag','Fredag', 'Lørdag','Søndag']], +# Polish by "Łukasz [DeeJay1] Jernaś" <deejay1@nsj.srem.pl> +'Polish' : + [['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', + 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', + 'Październik', 'Listopad', 'Grudzień'], + ['Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela']], +'Portuguese' : + [['Janeiro', 'Fevereiro', u'Mar\xe7o', 'Abril', + 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', + 'Outubro', 'Novembro', 'Dezembro'], + ['Segunda-feira', u'Ter\xe7a-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', u'S\xe1bado', 'Domingo']], +# Romanian by Costin Stroie <costinstroie@eridu.eu.org> +'Romanian' : + [['Ianuarie', 'Februarie', 'Martie', 'Aprilie', + 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', + 'Octombrie', 'Noiembrie', 'Decembrie'], + ['Luni','Mar\xc8\x9bi','Miercuri','Joi','Vineri','S\xc3\xa2mb\xc4\x83t\xc4\x83', 'Duminic\xc4\x83']], +'Russian' : + [['Январь', 'Февраль', 'Март', 'Апрель', + 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', + 'Октябрь', 'Ноябрь', 'Декабрь'], + ['Понедельник','Вторник','Среда','Четверг','Пятница','Суббота', 'Воскресенье']], +'Slovak' : + [['Január', 'Február', 'Marec', 'Apríl', + 'Máj', 'Jún', 'Júl', 'August', 'September', + 'Október', 'November', 'December'], + ['Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota', 'Nedeľa']], +'Slovak-short' : + [['Január', 'Február', 'Marec', 'Apríl', + 'Máj', 'Jún', 'Júl', 'August', 'September', + 'Október', 'November', 'December'], + ['Po','Ut','St','Št','Pi','So', 'Ne']], +'Spanish' : + [['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', + 'Junio', 'Julio', 'Agosto', 'Septiembre', + 'Octubre', 'Noviembre', 'Diciembre'], + ['Lunes', 'Martes', u'Mi\xe9rcoles', 'Jueves', 'Viernes', u'S\xe1bado', 'Domingo']], +'Swedish' : + [['Januari', 'Februari','Mars', 'April','Maj', 'Juni','Juli', 'Augusti','September', 'Oktober', 'November', 'December'], + ['Måndag', 'Tisdag','Onsdag', 'Torsdag','Fredag', 'Lördag','Söndag']] +} + + +from math import sqrt + +class ScCalendar: + """ Parent class for all calendar types """ + + def __init__(self, year, months=[], firstDay=calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + """ Setup basic things """ + # params + self.drawSauce = drawSauce # draw supplementary image? + self.year = year + self.months = months + self.lang = lang + # day order + self.dayOrder = localization[self.lang][1] + if firstDay == calendar.SUNDAY: + dl = self.dayOrder[:6] + dl.insert(0, self.dayOrder[6]) + self.dayOrder = dl + self.mycal = calendar.Calendar(firstDay) + self.layerImg = 'Calendar image' + self.layerCal = 'Calendar' + self.pStyleDate = "Date" # paragraph styles + self.pStyleWeekday = "Weekday" + self.pStyleMonth = "Month" + self.pStyleWeekNo = "WeekNo" + self.masterPage = "Weekdays" + self.sepMonths = sepMonths + # settings + self.firstPage = True # create only 2nd 3rd ... pages. No 1st one. + calendar.setfirstweekday(firstDay) + progressTotal(len(months)) + + def setupDocVariables(self): + """ Compute base metrics here. Page layout is bordered by margins and + virtually divided by golden mean 'cut' in the bottom. The calendar is + in the bottom part - top is occupied with empty image frame. """ + page = getPageSize() + self.pagex = page[0] + self.pagey = page[1] + marg = getPageMargins() + # See http://docs.scribus.net/index.php?lang=en&page=scripterapi-page#-getPageMargins + self.margint = marg[0] + self.marginl = marg[1] + self.marginr = marg[2] + self.marginb = marg[3] + self.width = self.pagex - self.marginl - self.marginr + self.height = self.pagey - self.margint - self.marginb + + def goldenMean(self, aSize): + """ Taken from samples/golden-mean.py.""" + return aSize * ((sqrt(5) - 1)/2) + + def applyTextToFrame(self, aText, aFrame): + """ Insert the text with style. """ + setText(aText, aFrame) + setStyle(self.pStyleDate, aFrame) + + def createCalendar(self): + """ Walk through months dict and call monthly sheet """ + if not newDocDialog(): + return 'Create a new document first, please' + createParagraphStyle(name=self.pStyleDate, alignment=ALIGN_RIGHT) + createParagraphStyle(name=self.pStyleWeekday, alignment=ALIGN_RIGHT) + createParagraphStyle(name=self.pStyleMonth) + createParagraphStyle(name=self.pStyleWeekNo, alignment=ALIGN_RIGHT) + originalUnit = getUnit() + setUnit(UNIT_POINTS) + self.setupDocVariables() + if self.drawSauce: + createLayer(self.layerImg) + createLayer(self.layerCal) + self.setupMasterPage() + run = 0 + for i in self.months: + run += 1 + progressSet(run) + cal = self.mycal.monthdatescalendar(self.year, i + 1) + self.createMonthCalendar(i, cal) + setUnit(originalUnit) + return None + + def createLayout(self): + """ Create the page and optional bells and whistles around """ + self.createPage() + if self.drawSauce: + setActiveLayer(self.layerImg) + self.createImage() + setActiveLayer(self.layerCal) + + def createPage(self): + """ Wrapper to the new page with layers """ + if self.firstPage: + self.firstPage = False + newPage(-1, self.masterPage) # create a new page using the masterPage + deletePage(1) # now it's safe to delete the first page + gotoPage(1) + return + newPage(-1, self.masterPage) + +class ScEventCalendar(ScCalendar): + """ Parent class for event + (horizontal event, vertical event) calendar types """ + + def __init__(self, year, months = [], firstDay = calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + ScCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + + def printMonth(self, cal, month, week): + """ Print the month name(s) """ + if week[6].day < 7: + if (week == cal[len(cal)-1]): + self.createHeader(localization[self.lang][0][month] + self.sepMonths + localization[self.lang][0][(month+1)%12]) + elif ((month-1) not in self.months): + self.createHeader(localization[self.lang][0][(month-1)%12] + self.sepMonths + localization[self.lang][0][month]) + else: + self.createHeader(localization[self.lang][0][month]) + + def createMonthCalendar(self, month, cal): + """ Draw one week calendar per page """ + for week in cal: + # Avoid duplicate week around the turn of the months: + # Only include week: + # * If it's not the first week in a month, or, if it is: + # * If it starts on the first weekday + # * If the month before it isn't included + if (week != cal[0]) or (week[0].day == 1) or ((month-1) not in self.months): + self.createLayout() + self.printMonth(cal, month, week) + self.printWeekNo(week) + + for day in week: + self.printDay(day) + +class ScHorizontalEventCalendar(ScEventCalendar): + """ One day = one row calendar. I suggest LANDSCAPE orientation.\ + One week per page.""" + + def __init__(self, year, months = [], firstDay = calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + ScEventCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + + def setupDocVariables(self): + """ Compute base metrics here. Page layout is bordered by margins and + virtually divided by golden mean 'cut' in the bottom. The calendar is + in the bottom part - top is occupied with empty image frame. """ + # golden mean + ScCalendar.setupDocVariables(self) + self.gmean = self.width - self.goldenMean(self.width) + self.marginl + # calendar size = gmean + # rows and cols + self.rowSize = self.height / 8 + + def printWeekNo(self, week): + """ Dummy for now + (for this type of calendar - see ScVerticalEventCalendar) """ + return + + def printDay(self, j): + """ Print a given day """ + cel = createText(self.gmean + self.marginl, + self.margint + (1 + (j.weekday()-calendar.firstweekday())%7) * self.rowSize, + self.width - self.gmean, self.rowSize) + setText(str(j.day), cel) + setStyle(self.pStyleDate, cel) + + def createHeader(self, monthName): + """ Draw calendar header: Month name """ + cel = createText(self.gmean + self.marginl, self.margint, + self.width - self.gmean, self.rowSize) + setText(monthName, cel) + setStyle(self.pStyleMonth, cel) + + def createImage(self): + """ Wrapper for everytime-the-same image frame. """ + if self.drawSauce: + createImage(self.marginl, self.margint, self.gmean, self.height) + + def setupMasterPage(self): + """ Create a master page (not used for this type of calendar """ + createMasterPage(self.masterPage) + closeMasterPage() + +class ScVerticalCalendar(ScCalendar): + """ Parent class for vertical + (classic, vertical event) calendar types """ + + def __init__(self, year, months = [], firstDay = calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + ScCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + + def setupDocVariables(self): + """ Compute base metrics here. Page layout is bordered by margins and + virtually divided by golden mean 'cut' in the bottom. The calendar is + in the bottom part - top is occupied with empty image frame. """ + # gloden mean + ScCalendar.setupDocVariables(self) + self.gmean = self.height - self.goldenMean(self.height) + self.margint + # calendar size + self.calHeight = self.height - self.gmean + self.margint + # rows and cols + self.rowSize = self.gmean / 8 + self.colSize = self.width / 7 + + def setupMasterPage(self): + """ Draw invariant calendar header: Days of the week """ + createMasterPage(self.masterPage) + editMasterPage(self.masterPage) + setActiveLayer(self.layerCal) + rowCnt = 0 + for j in self.dayOrder: # days + cel = createText(self.marginl + rowCnt*self.colSize, + self.calHeight + self.rowSize, + self.colSize, self.rowSize) + setText(j, cel) + setStyle(self.pStyleWeekday, cel) + rowCnt+=1 + closeMasterPage() + + def createHeader(self, monthName): + """ Draw calendar header: Month name """ + header = createText(self.marginl, self.calHeight, self.width, self.rowSize) + setText(monthName, header) + setStyle(self.pStyleMonth, header) + + def createImage(self): + """ Wrapper for everytime-the-same image frame. """ + if self.drawSauce: + createImage(self.marginl, self.margint, + self.width, self.calHeight - self.margint) + +class ScClassicCalendar(ScVerticalCalendar): + """ Calendar matrix creator itself. I suggest PORTRAIT orientation. + One month per page.""" + + def __init__(self, year, months = [], firstDay = calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + ScVerticalCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + + def createMonthCalendar(self, month, cal): + """ Create a page and draw one month calendar on it """ + self.createLayout() + self.createHeader(localization[self.lang][0][month]) + rowCnt = 2 + for week in cal: + colCnt = 0 + for day in week: + cel = createText(self.marginl + colCnt * self.colSize, + self.calHeight + rowCnt * self.rowSize, + self.colSize, self.rowSize) + colCnt += 1 + if day.month == month + 1: + setText(str(day.day), cel) + setStyle(self.pStyleDate, cel) + rowCnt += 1 + +class ScVerticalEventCalendar(ScVerticalCalendar, ScEventCalendar): + """ One day = one column calendar. I suggest LANDSCAPE orientation.\ + One week per page.""" + + def __init__(self, year, months = [], firstDay = calendar.SUNDAY, drawSauce=True, sepMonths='/', lang='English'): + ScVerticalCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + ScEventCalendar.__init__(self, year, months, firstDay, drawSauce, sepMonths, lang) + + def printDay(self, j): + """ Print a given day """ + cel = createText(self.marginl + ((j.weekday()-calendar.firstweekday())%7)*self.colSize, + self.calHeight + self.rowSize, + self.colSize/5, self.rowSize) + setText(str(j.day), cel) + setStyle(self.pStyleDate, cel) + + def printWeekNo(self, week): + """ Print the week number for the given week""" + weekCel = createText(self.marginl, self.calHeight, self.width, self.rowSize) + # Week number: of this week's Thursday. + # See http://docs.python.org/library/datetime.html#datetime.date.isocalendar + # Note that week calculation isn't perfectly universal yet: + # http://en.wikipedia.org/wiki/Week_number#Week_number + setText(str(week[(calendar.THURSDAY-calendar.firstweekday())%7].isocalendar()[1]), weekCel) + setStyle(self.pStyleWeekNo, weekCel) + +class TkCalendar(Frame): + """ GUI interface for Scribus calendar wizard. + It's ugly and very simple. I can say I hate Tkinter :-/""" + + def __init__(self, master=None): + """ Setup the dialog """ + # reference to the localization dictionary + self.key = 'English' + Frame.__init__(self, master) + self.grid() + self.master.resizable(0, 0) + self.master.title('Scribus Calendar Wizard') + #define widgets + self.statusVar = StringVar() + self.statusLabel = Label(self, textvariable=self.statusVar) + self.statusVar.set('Select Options and Values') + # langs + # change the height = to match number of langs. + self.langLabel = Label(self, text='Select language:') + + self.langFrame = Frame(self) + self.langFrame.pack() + self.langScrollbar = Scrollbar(self.langFrame) + self.langScrollbar.pack(fill=Y, side=RIGHT) + self.langListbox = Listbox(self.langFrame, selectmode=SINGLE, height=10, yscrollcommand=self.langScrollbar.set) + self.langListbox.pack(fill=X,side=LEFT) + self.langScrollbar.config(command=self.langListbox.yview) + + keys = localization.keys() + keys.sort() + for i in keys: + self.langListbox.insert(END, i) + self.langButton = Button(self, text='Change language', command=self.languageChange) + # calendar type + self.typeLabel = Label(self, text='Calendar type') + self.typeVar = IntVar() + self.typeClRadio = Radiobutton(self, text='Classic', variable=self.typeVar, value=0) + self.typeEvRadio = Radiobutton(self, text='Event (Horizontal)', variable=self.typeVar, value=1) + self.typeVERadio = Radiobutton(self, text='Event (Vertical)', variable=self.typeVar, value=2) + # start of week + self.weekStartsLabel = Label(self, text='Week begins with:') + self.weekVar = IntVar() + self.weekMondayRadio = Radiobutton(self, text='Mon', variable=self.weekVar, value=calendar.MONDAY) + self.weekSundayRadio = Radiobutton(self, text='Sun', variable=self.weekVar, value=calendar.SUNDAY) + # year + self.yearLabel = Label(self, text='Year:') + self.yearVar = StringVar() + self.yearEntry = Entry(self, textvariable=self.yearVar, width=4) + self.wholeYearLabel = Label(self, text='Whole year:') + self.wholeYear = IntVar() + self.wholeYearCheck = Checkbutton(self, command=self.setWholeYear, variable=self.wholeYear) + # months + self.monthLabel = Label(self, text='Months:') + self.monthListbox = Listbox(self, selectmode=MULTIPLE, height=12) + # layout stuff + self.imageLabel = Label(self, text='Draw Image Frame:') + self.imageVar = IntVar() + self.imageCheck = Checkbutton(self, variable=self.imageVar) + # Months separator + self.sepMonthsLabel = Label(self, text='Months separator:') + self.sepMonthsVar = StringVar() + self.sepMonthsEntry = Entry(self, textvariable=self.sepMonthsVar, width=4) + # closing/running + self.okButton = Button(self, text="OK", width=6, command=self.okButonn_pressed) + self.cancelButton = Button(self, text="Cancel", command=self.quit) + # setup values + self.weekMondayRadio.select() + self.typeClRadio.select() + self.yearVar.set(str(datetime.date(1, 1, 1).today().year)) + self.sepMonthsVar.set('/') + self.imageCheck.select() + # make layout + self.columnconfigure(0, pad=6) + currRow = 0 + self.statusLabel.grid(column=0, row=currRow, columnspan=4) + currRow += 1 + self.langLabel.grid(column=0, row=currRow, sticky=W) + self.monthLabel.grid(column=3, row=currRow, sticky=W) + currRow += 1 + self.langFrame.grid(column=0, row=currRow, rowspan=6, sticky=N) + self.typeLabel.grid(column=1, row=currRow, sticky=E) + self.typeClRadio.grid(column=2, row=currRow, sticky=W) + self.monthListbox.grid(column=3, row=currRow, rowspan=8) + currRow += 1 + self.typeEvRadio.grid(column=2, row=currRow, sticky=W) + currRow += 1 + self.typeVERadio.grid(column=2, row=currRow, sticky=W) + currRow += 1 + self.weekStartsLabel.grid(column=1, row=currRow, sticky=N+E) + self.weekMondayRadio.grid(column=2, row=currRow, sticky=N+W) + currRow += 1 + self.weekSundayRadio.grid(column=2, row=currRow, sticky=N+W) + currRow += 1 + self.yearLabel.grid(column=1, row=currRow, sticky=N+E) + self.yearEntry.grid(column=2, row=currRow, sticky=N+W) + currRow += 1 + self.wholeYearLabel.grid(column=1, row=currRow, sticky=N+E) + self.wholeYearCheck.grid(column=2, row=currRow, sticky=N+W) + currRow += 1 + self.imageLabel.grid(column=1, row=currRow, sticky=N+E) + self.imageCheck.grid(column=2, row=currRow, sticky=N+W) + self.langButton.grid(column=0, row=currRow) + currRow += 1 + self.sepMonthsLabel.grid(column=1, row=currRow, sticky=N+E) + self.sepMonthsEntry.grid(column=2, row=currRow, sticky=N+W) + currRow += 3 + self.rowconfigure(currRow, pad=6) + self.okButton.grid(column=1, row=currRow, sticky=E) + self.cancelButton.grid(column=2, row=currRow, sticky=W) + # fill the values + self.realLangChange() + + def languageChange(self, lang='English'): + """ Called by Change button. Get language list value and + call real re-filling. """ + ix = self.langListbox.curselection() + if len(ix)==0: + self.statusVar.set('Select a language, please') + return + self.realLangChange(lang=self.langListbox.get(ix[0])) + + def realLangChange(self, lang='English'): + """ Real widget setup. Ot takes values from localization dictionary. + [0] = months, [1] Days """ + self.key = lang + self.monthListbox.delete(0, END) + self.wholeYear.set(0) + for i in localization[lang][0]: + self.monthListbox.insert(END, i) + + def setWholeYear(self): + """ All/none months selection. It's called after "Whole year" check button + click. """ + if self.wholeYear.get() == 1: + self.monthListbox.selection_set(0, END) + else: + self.monthListbox.selection_clear(0, END) + + def okButonn_pressed(self): + """ User variables testing and preparing """ + # year + try: + year = self.yearVar.get().strip() + if len(year) != 4: + raise ValueError + year = int(year, 10) + except ValueError: + self.statusVar.set('Year must be in the "YYYY" format e.g. 2005.') + return + # months + selMonths = self.monthListbox.curselection() + if len(selMonths) == 0: + self.statusVar.set('At least one month must be selected.') + return + months = [] + for i in selMonths: + months.append(int(i)) + # draw images etc. + if self.imageVar.get() == 0: + draw = False + else: + draw = True + # create calendar (finally) + if self.typeVar.get() == 0: + cal = ScClassicCalendar(year, months, self.weekVar.get(), draw, self.sepMonthsVar.get(), self.key) + elif self.typeVar.get() == 1: + cal = ScHorizontalEventCalendar(year, months, self.weekVar.get(), draw, self.sepMonthsVar.get(), self.key) + else: + cal = ScVerticalEventCalendar(year, months, self.weekVar.get(), draw, self.sepMonthsVar.get(), self.key) + self.master.withdraw() + err = cal.createCalendar() + if err != None: + self.master.deiconify() + self.statusVar.set(err) + else: + self.quit() + + def quit(self): + self.master.destroy() + + +def main(): + """ Application/Dialog loop with Scribus sauce around """ + try: + statusMessage('Running script...') + progressReset() + root = Tk() + app = TkCalendar(root) + root.mainloop() + finally: + if haveDoc(): + redrawAll() + statusMessage('Done.') + progressReset() + +if __name__ == '__main__': + main() + diff --git a/scribus/plugins/scriptplugin/scripts/ChangeLog b/scribus/plugins/scriptplugin/scripts/ChangeLog new file mode 100644 index 0000000..c3f8e0f --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/ChangeLog @@ -0,0 +1,181 @@ +20061016 v 0.8.2tk + A one liner change by Jean Ghali to line #734 to add the extra parameter missing. +20051124 v0.8tk final: + Cleaned up the checkbox labels and layout. + +20051121 v0.8tk preview 3: + Calls the new Scribus zoomDocument() function to make the completed font + sample document fit in Scribus window. + + Grey out "Start page number count from first page" when "Print TOC" is + not checked as without a table of contents the first page would always + start on the same page number making this option irrelevant. + +20051120 v0.8tk preview 2: + Replaced the newDoc() with newDocument(). Have not put any fallback code + for use with earlier Scribus versions. + + When using double sided option we now make use of Scribus ability to display + pages side by side as default. You may need to zoom out to view the + complete document width. This is because currently there is no way of setting + "Fit To Page" from the Scripter. + +20050902 v0.8tk preview 1: + Rearanged the initialisation. If no fonts are found for the Table of + Contents, page numbers and font sample labels, the script shows a + message box listing the problem and a possible solution as well as a message + to the console. + + A Scribus messagebox alerts the user if Tkinter is not found. Previously + this message was only printed to the console. + + Now able to do a dummy run to calculate and report the amount of samples + that will fit on a page. This enables the script to correctly calculate + how many sheets will be required. Previously it was always assumed that + there would be 3 sample blocks on a sheet. This is now not always the case. + + Added menu. Also added "about" and "settings" dialogs. + + Sample rows can be selected or unselected to save on paper. The settings are + automatically saved when changed and can be set as user defaults. + + User can choose to have page numbers count from first page of the toc instead + of the first page of samples. This can be helpful if wanting to quickly look + up a font in the toc and then using the Scribus page navigator dialog to go to + the actual page on the screen to view it without printing it out. + + Added initial support for a sample paragraph. The sample paragraph defaults + to "off" due to the amount of space it uses on the page. + + Some widgets read their defaults from a config dictionary. + + Many code cleanups. Classes used for settings storage have been replaced with + dictionaries to make it easier for users to customise. + +################################################### + +20050930 v0.7.5tk + Fixed bug in table of contents. TOC rows value was not being honoured. + Would create an unrequired blank headed toc page when the TOC rows count setting + matched the amount of samples selected. + +20050814 v0.7.4tk + Now updates the Scribus Progress Bar (one increment for each font drawn). + +20050813 v0.7.3tk + Fix typo in exception code. + Modified case of some script variables to make compatible with changes + in Scribus 1.3 scriptor. + Removed the reduntant "self.master.maxsize(1, 1)" from the application class. + +20050104 v0.7.2tk + More cleanups in font preview code. If a font cannot be displayed + then the preview panel is cleared. Removed many error messages returned + to the console. + +20050103 v0.7.1tk + Removed discontinued email address + +20041230 v0.7tk + Added a preview panel so user can see a sample of what a font may look like + before selecting it to use. + Detects failure of Python Imaging Library module to load and tests for the ability to + write to .scribus folder then disables preview if necessary. + Incorporated Craig Ringers boilerplate and Scribus function case changes. + Put labels on the left and right listboxes describing what they do. + Listboxes now get focus when selected with the mouse. This allows Up Down + keys to be used to scroll through font names. + When selecting a single item in a listbox, the font highlighted will be + displayed in a panel. + Some function names have changed and some docstrings added. + The main window should no longer be expandable. + +20040224 v0.6.1 + A bug fix was introduced to Scribus CVS on 20040223 that affected the text + frames. This version has an adjusted height and position of some text frames + to make the samples correctly fit inside them again. + +20040212 v0.6 final + Fixed bug that stopped multiple selection move from working properly. + More code cleanups. + Adjusted the button positions. + Added logic to gray out "item up" and "item down" buttons when not appropriate. + Enhanced the "move left" and "move right" button gray out code. + Fixed a problem when double clicking on a multiple selection of rows. + Small adjustments and fixes to the layouts. + +20030130 v0.6 preview 5 + Now contains a list of acceptable proportional and fixed width fonts that are needed for + the TOC and font sample labels. If a match is not found with the installed font list available to Scribus + then an error message is dumped to the console with a list of the required fonts for the user to get. The + script will continue to run with whatever font happens be be set as default in Scribus. + Fixed broken horizontal line drawing code. + Various size adjustments to text frames that were drawing outside of margin area. + +20030129 v0.6 preview 4 + Rewritten useSelection function. Now measures the available space left on page before placing the + sample block. It is now possible to select the sample lines to print by commenting out rows in + the drawSampleBlock() function and if there is space then more samples will be placed on the page. + Renamed some functions. + Made some small adjustments to the text frame dimensions. + +20040126 v0.6 preview 3 + Added double sided paper handling. + Added binding offsets. + Left hand pane allows multiple selection again. Shift and mouse drag will select a block, + hold Control plus click to highlight single items. Press '>' button to move the seelcted group to the + right hand pane. + More code cleanups. + removed pound sign from sample string. It was causing errors with Python V2.3 thanks MrB + Changed default sans font to "Nimbus Sans L Regular" instead of "Arial" + +20040123 v0.6 preview 2 + fixed the extra page bug introduced in v0.6 preview 1 + Changed the 36 point font to 32 point. this improves the layout of the samples. + +20040120 v0.6 preview 1 + Start adding optional page numbers. + Start adding optional table of contents. + Improve paper size variables format. + More code cleanups. + If a second (or more) font list was created with the script then it would be impossible to + view anything other than the most recent document in Scribus - fixed + +20040121 v0.5a + Small change to fix non display of earlier font sample documents still open in Scribus + if the script is run again. + +20040112 v0.5 + Added SetRedraw to speed up page generation. + Added status bar to display the quantity of fonts available, how many are selected + and how many pages will be needed. + Added a paper size selector. + +20040107 v0.4 + More cleanups in the main page generator loop + Added 6 point sample + Left list box now sorts correctly when moving individual items back to it + More adjustments to text layouts + +20040106 v0.3a + fixed page creep bug + +20040106 v0.3 + Put each text string into its own text frame and put in separator lines + Prints the font size as part of the test string + Can crudely set A4 or US Letter size paper by uncommenting the appropriate + 2 lines in useselection() + changing this just adjusts the position of the samples on the page for the change + in paper length. + Some code clean ups. + +20040105 v0.2 + Rearranged the buttons. Put in Franz's fix. Thanks Franz. + Put in some more sample lines including the standard alphabet characters. + +20040105 v0.1a + Added a double click to select font in font selector. + Fixes to some button logic. Gray out as required. + +20040104 v0.1 + First release diff --git a/scribus/plugins/scriptplugin/scripts/ColorChart.py b/scribus/plugins/scriptplugin/scripts/ColorChart.py new file mode 100644 index 0000000..46946d3 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/ColorChart.py @@ -0,0 +1,350 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +ABOUT THIS SCRIPT: + +ColorChart.py allows a user to create color charts with all +the colors of a given scribus document. +It generates a color field for each color and a description +of the color, containing the color name, the CMYK values and +the RGB values. + +If there is a document opened in scribus, ColorChart uses this +document as color source and creates a new document with the +color chart. +If there is no document opened in scribus, ColorChart displays +a file open dialog to allow the user to chose a scribus file +to generate a colorchart of. +You will be asked to give a name for the color chart. This name +will be displayed in the pages headlines. +############################ + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Author: Sebastian Stetter +please report bugs to: scribusscript@sebastianstetter.de +""" +from __future__ import division +import sys +__version__=1.1 +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +#################### +# IMPORTS GO HERE # +#################### + +COLOR_FIELD_HEIGHT=25 +#space between colorfields +HSPACE=5 +VSPACE=4 +#space for header and footer +HEADERSIZE = 10 +FOOTERSIZE = 5 +TEXT_BOX_WIDTH = 50 +global pageTitle +pageTitle="COLOR CHART" + +def drawHeaderFooter(pagetitle): + """draw some info on the pages""" + # get page size + pageSize=scribus.getPageSize() + pageWidth=pageSize[0] + pageHeight=pageSize[1] + #pageMargins + pageMargins=scribus.getPageMargins() + topMargin=pageMargins[0] + leftMargin=pageMargins[1] + rightMargin=pageMargins[2] + bottomMargin=pageMargins[3] + + #create textbox and insert text for header + textbox=scribus.createText(leftMargin, topMargin, pageWidth-leftMargin-rightMargin, HEADERSIZE) + #set proper font size and alignment + scribus.setFontSize(18, textbox) + scribus.setTextAlignment(scribus.ALIGN_CENTERED, textbox) + #load the string into the textbox + headerstring=pagetitle + scribus.insertText(headerstring, 0, textbox) + + #create textbox and insert text for footer + textbox=scribus.createText(leftMargin, pageHeight-bottomMargin-FOOTERSIZE, pageWidth-leftMargin-rightMargin, FOOTERSIZE) + #set proper font size and alignment + scribus.setFontSize(9, textbox) + scribus.setTextAlignment(scribus.ALIGN_LEFT, textbox) + #load the string into the textbox + footerstring="Created using ColorChart.py V %s script for Scribus by Sebastian Stetter - http://www.sebastianstetter.de" % str(__version__) + scribus.insertText(footerstring, 0, textbox) + + +def getSpotColors(): + """ Get spot colors from an original document. + Must be called after getColorsFromDocument(). + """ + ret = {} + for color in scribus.getColorNames(): + ret[color] = scribus.isSpotColor(color) + return ret + + +def getColorsFromDocument(): + """gets colors from opend document. if there is no document, display dialog to chose a file. returns a list[name,c,m,y,k]""" + def getColors(): + """gets the colors and returns a list[name,c,m,y,k]""" + colorNames=scribus.getColorNames() + list=[] + scribus.statusMessage("Reading Colors...") + stepsTotal=len(colorNames) + scribus.progressTotal(stepsTotal) + steps=0 + for name in colorNames: + color=scribus.getColor(name) + listitem=[name, color[0], color[1], color[2], color[3]] + list.append(listitem) + #update progress bar + steps=steps+1 + scribus.progressSet(steps) + return list + + #check if we have a document - otherwise display open file dialog + if scribus.haveDoc() == 1: + pass + list=getColors() + return list + else: + pass + #display file open dialog + file=scribus.fileDialog("ColorChart by Sebastian Stetter", 'Scribus files(*.sla *.SLA *.sla.gz *.SLA.GZ)') + #open file + try: + scribus.openDoc(file) + except: + scribus.messageBox("ColorChart by Sebastian Stetter", "could not open file") + sys.exit() + list=getColors() + return list + +def prepareDocument(): + """creates the new document, sets up colors """ + colorList = getColorsFromDocument() + spotDict = getSpotColors() + scribus.statusMessage("Preparing new document...") + scribus.newDocument(scribus.PAPER_A4, (15,15, 20, 20), scribus.PORTRAIT, 1, scribus.UNIT_POINTS, scribus.PAGE_1, 0, 1) + scribus.setUnit(scribus.UNIT_MILLIMETERS) + #delete existing colors + cols = scribus.getColorNames() + for col in cols: + scribus.deleteColor(col, "None") + + #create our new colors + for color in colorList: + cname=color[0] + c = int(color[1]) + m = int(color[2]) + y = int(color[3]) + k = int(color[4]) + scribus.defineColor(cname, c, m, y, k ) + if spotDict.has_key(cname): + scribus.setSpotColor(cname, spotDict[cname]) + + #get the pageTitle form user and store it in PageTitle + global pageTitle + pageTitle=scribus.valueDialog("ColorChart by Sebastian Stetter", "Please enter document title", "Scribus COLOR CHART") + drawHeaderFooter(pageTitle) + +def createPage(): + """appends a new page""" + scribus.newPage(-1) #append new page + #new page - new header and footer + drawHeaderFooter(pageTitle) + + +def rgbhex(r,g,b): + '''convert rgb values in 0-255 style to hex string in #000000 to #ffffff style''' + hr=hex(r) + hr = hr.replace("0x", "") + if len(hr)== 0: + hr = "00" + elif len(hr)==1: + hr = "0"+hr + else: + pass + hg=hex(g) + hg = hg.replace("0x", "") + if len(hg)== 0: + hg = "00" + elif len(hg)==1: + hg = "0"+hg + else: + pass + hb=hex(b) + hb = hb.replace("0x", "") + if len(hb)== 0: + hb = "00" + elif len(hb)==1: + hb = "0"+hb + else: + pass + rgbstring="#"+hr+hg+hb + rgbstring=rgbstring.upper() + return rgbstring + + +def drawColor(colorname, h, v, width, height): #h horizontal position, v vertical position + """draws a color chart field with its caption for the given colorname at the h and v position + """ + #get cmyk values and convert them to 0 - 255 values + color = scribus.getColor(colorname) + c= int(round(color[0]/2.55)) + m=int(round(color[1]/2.55)) + y=int(round(color[2]/2.55)) + k=int(round(color[3]/2.55)) + #get rgb color + rgbcolor=scribus.getColorAsRGB(colorname) + r=rgbcolor[0] + g=rgbcolor[1] + b=rgbcolor[2] + #get webcolor + webcolor=rgbhex(r, g, b) + #but String for Textbox together + colorDisplay = colorname + if scribus.isSpotColor(colorname): + colorDisplay += " (Spot Color)" + colorstring="%s\nC %i, M %i, Y %i, K %i, \nR %i, G %i, B %i \nRGB: %s" %(colorDisplay, c, m, y, k, r, g, b, webcolor) + + #draw rectangle and set colors + rect=scribus.createRect(h, v, width, height) + scribus.setFillColor(colorname, rect) + #if total amount of color is < 20 draw outline in Black for rectangle, else in same color + if c +m+y+k < 20: + scribus.setLineColor("Black", rect) + else: + scribus.setLineColor(colorname, rect) + #create textbox and insert text + textbox=scribus.createText(h+width+5, v, 50, height) + #set proper font size + scribus.setFontSize(11, textbox) + scribus.setTextAlignment(scribus.ALIGN_LEFT, textbox) + #load the string into the textbox + scribus.insertText(colorstring, 0, textbox) + + +def createChart(): + """actually handles the whole chart creation process""" + prepareDocument() + # get page size + pageSize=scribus.getPageSize() + pageWidth=pageSize[0] + pageHeight=pageSize[1] + #pageMargins + pageMargins=scribus.getPageMargins() + topMargin=pageMargins[0] + leftMargin=pageMargins[1] + rightMargin=pageMargins[2] + bottomMargin=pageMargins[3] + + #color field dimensions + colorFieldWidth= pageWidth - leftMargin - rightMargin - (TEXT_BOX_WIDTH+HSPACE) #50+5 is the with of the textbox plus the space between textbox and colorfield + + #how much space does one field use? + vSpaceUsedByField = COLOR_FIELD_HEIGHT+VSPACE + + #how much space is available per row? + vSpaceAvailable=pageHeight-topMargin-bottomMargin-HEADERSIZE-FOOTERSIZE + + #counts the colorFields created for a page. reset this variable after creation of new page + colorFieldCounter=0 + + #get list of all colors in document + colorList = scribus.getColorNames() + #prepare the progressbar + colorNumber=len(colorList) + scribus.progressTotal(colorNumber) + #@TODO: implement possibility to abort script (button2=scribus.BUTTON_CANCEL) buttons should return int 1 or 2 + #scribus.messageBox("ColorChart Script by Sebastian Stetter", "...going to create a chart of "+str(colorNumber)+" colors.\n This may take a while.", button1 = scribus.BUTTON_OK) + scribus.statusMessage("Drawing color fields...") + stepCompleted=0 + #disable redrawing for better performance + scribus.setRedraw(False) + for color in colorList: + if (vSpaceUsedByField * (colorFieldCounter+1)) <= vSpaceAvailable: + # when there is enought space left draw a color field... + + #calculate Position for new colorField + h=leftMargin + v=topMargin + (vSpaceUsedByField * colorFieldCounter)+HEADERSIZE + #draw the colorField + drawColor(color, h, v, colorFieldWidth, COLOR_FIELD_HEIGHT) + colorFieldCounter = colorFieldCounter+1 + #update progressbar + stepCompleted = stepCompleted+1 + scribus.progressSet(stepCompleted) + else: + #not enough space? create a new page! + createPage() + #reset the colorFieldCounter to '0' since we created a new page + colorFieldCounter = 0 + h=leftMargin + v=topMargin + (vSpaceUsedByField * colorFieldCounter)+HEADERSIZE + drawColor(color, h, v, colorFieldWidth, COLOR_FIELD_HEIGHT) + colorFieldCounter = colorFieldCounter+1 + + #update progressbar + stepCompleted = stepCompleted+1 + scribus.progressSet(stepCompleted) + + #make shure pages are redrawn + scribus.setRedraw(True) + + +def main(argv): + """just invokes createChart() and displays a message after the chart is finished.""" + createChart() + scribus.messageBox("ColorChart Script by Sebastian Stetter", "Your chart has been created, but not saved, yet!\nThanks for using ColorChart and Scribus!") + + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + scribus.statusMessage("Creating color chart...") + scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage("") + scribus.progressReset() + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) diff --git a/scribus/plugins/scriptplugin/scripts/DirectImageImport.py b/scribus/plugins/scriptplugin/scripts/DirectImageImport.py new file mode 100644 index 0000000..369a7ad --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/DirectImageImport.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + +Diese Skript importiert ein Bild und setzt es auf die akutelle Seite. +Der Bildrahmen wird dem Bild angepasst und in den nicht-proportionalen Modus +gesetzt, das heisst, beliebige Verzerrungen sind moeglich. + +Um das Bild proportional zu vergroessern, die STRG-Taste beim Bearbeiten druecken. + +Tested with scribus 1.3.3.3 + +Author: Konrad Stania + +some modifications 2009 by Gregory Pittman, tested on Scribus 1.3.3.13svn + +This newer version uses the Python Imaging Library to get the dimensions of the +image to be imported, and adjusts the frame accordingly. Initially the frame will +be created centered, at 80% of the page's width or height, whichever is smaller. +There is an adjustment to 80% of the height of the page in case this is exceeded +by the initial calculation. + +USAGE: + +You must have a document open. Run the script, a dialog asks you to choose an +image to load. A proportional frame is automatically created and image loaded, +then adjusted to frame size. + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +name +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" + +# Craig Bradney, Scribus Team +# 10/3/08: Added to Scribus 1.3.3.12svn distribution "as was" from Scribus wiki for bug #6826, script is GPLd + +import sys + + +try: + from scribus import * + +except ImportError: + print "This script only runs from within Scribus." + sys.exit(1) +try: + from PIL import Image +except ImportError: + print "Unable to import the Python Imaging Library module." + sys.exit(1) + +def main(): + + pageX,pageY = getPageSize() + ImageFileName = fileDialog("Image Import", "*","" ,True, False) + im = Image.open(ImageFileName) + xsize, ysize = im.size + + if (pageX < pageY): + Breite = pageX * 0.8 + else: + Breite = pageY * 0.8 + Hoehe = Breite * ysize/xsize + +# for images taller than they are wide we want to limit height of frame to 80% of page height + if (Hoehe > pageY * 0.8): + Hoehe = pageY * 0.8 + Breite = Hoehe * xsize/ysize + + ImageFrame = createImage(pageX/2 - Breite/2, pageY/2 - Hoehe/2, Breite, Hoehe) + loadImage(ImageFileName, ImageFrame) + setScaleImageToFrame(True, False,ImageFrame) + setFillColor("None", ImageFrame) + setLineColor("None", ImageFrame) + + +if __name__ == '__main__': + if haveDoc(): + main() + else: + messageBox("Image Import", "You need to have a document open <i>before</i> you can run this script succesfully.", ICON_INFORMATION)
\ No newline at end of file diff --git a/scribus/plugins/scriptplugin/scripts/FontSample.py b/scribus/plugins/scriptplugin/scripts/FontSample.py new file mode 100644 index 0000000..62bdcfc --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/FontSample.py @@ -0,0 +1,1578 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# **************************************************************************** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# **************************************************************************** + +""" +****************************************************************************** + +DESCRIPTION & USAGE: +This script needs Tkinter. It will create a GUI with an alphabetical list +of fonts using the names as they will be shown in Scribus. User can select +one or more fonts and create an example sheet(s) to print or create a PDF +from. It is heavily commented to make it easier for the user to adjust it +for his / her own needs. + +Note: this version needs read/write access to .scribus directory in users +home. You will also need Python Imaging Library (PIL) installed. +If your system does not meet these requirements then change showPreviewPanel +to a value of 0. This will disable the new preview features. + +****************************************************************************** + +First release : 30/12/2003 +This release : v0.8.1tk (released 4th Dec 2005) +Copyright : (C) 2003 - 2005 Steve Callcott +Latest releases +and support : www.firstwish.co.uk/sjc/scribus/index.php +Maintainer : Steve Callcott 2003 - 2005 +Email : stotte@firstwish.co.uk + +For revision history see the ChangeLog file. +Bugs and future plans are listed in the TODO file. +See NEWS for new features since last version. + +WHATS NEW v0.8.2tk: +A one liner change by Jean Ghali to line #734 to add the extra parameter missing. +See: http://bugs.scribus.net/view.php?id=4377 + +WHATS NEW v0.8.1tk: +After reloading users saved preferences the status bar was not showing +correct calculations. +Changed text in settings menu. + +WHATS NEW v0.8tk Final: +Cleaned up the checkbox labels and layout. + +WHATS NEW v0.8tk Preview 3: +Calls the new Scribus zoomDocument() function to make the completed font +sample document fit in Scribus window. + +Grey out "Start page number count from first page" when "Print TOC" is +not checked as without a table of contents the first page would always +start on the same page number making this option irrelevant. + +WHATS NEW v0.8tk Preview 2: +Replaced the newDoc() with newDocument(). Have not put any fallback code +for use with earlier Scribus versions. + +When using double sided option we now make use of Scribus ability to display +pages side by side as default. You may need to zoom out to view the +complete document width. + +WHATS NEW v0.8tk Preview 1: +Rearanged the initialisation. If no fonts are found for the Table of +Contents, page numbers and font sample labels, the script shows a +message box listing the problem and a possible solution as well as a message +to the console. + +A Scribus messagebox alerts the user if Tkinter is not found. Previously +this message was only printed to the console. + +Now able to do a dummy run to calculate and report the amount of samples +that will fit on a page. This enables the script to correctly calculate +how many sheets will be required. Previously it was always assumed that +there would be 3 sample blocks on a sheet. This is now not always the case. + +Added menu. Also added "about" and "settings" dialogs. + +Sample rows can be selected or unselected to save on paper. The settings are +automatically saved when changed and can be set as user defaults. + +User can choose to have page numbers count from first page of the toc instead +of the first page of samples. This can be helpful if wanting to quickly look +up a font in the toc and then using the Scribus page navigator dialog to go to +the actual page on the screen to view it without printing it out. + +Added initial support for a sample paragraph. The sample paragraph defaults +to "off" due to the amount of space it uses on the page. + +Some widgets read their defaults from a config dictionary. + +Many code cleanups. Classes used for settings storage have been replaced with +dictionaries to make it easier for users to customise. + +****************************************************************************** +""" + +import sys +import os +import cPickle + + +showPreviewPanel = 1 # change to 0 to permanently hide the preview +TEMP_PATH = os.path.join(os.path.expanduser('~'), '.scribus') +CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.scribus/fontsampler') + + +try: + import scribus +except ImportError,err: + print 'This Python script is written for the Scribus scripting interface.' + print 'It can only be run from within Scribus.' + sys.exit(1) + + +try: + from Tkinter import * +except ImportError,err: + print 'This script will not work without Tkinter' + scribus.messageBox('Error','This script will not work without Tkinter\nPlease install and try again', + scribus.ICON_WARNING) + sys.exit(1) + + +if not os.path.exists(CONFIG_PATH): + try: + print 'Attempting to creating configuration file directory...' + os.mkdir(CONFIG_PATH) + print 'Success, now testing for write access of new directory...' + if os.access(CONFIG_PATH, os.W_OK): + print 'Write access ok.' + else: + print 'Error, unable to write to .scribus/fontsampler directory.' + except: + CONFIG_PATH = '' + print 'Failed to make configuration file directory,' + print 'do you have a .scribus directory in your home directory?' + print 'font sampler will not be able to save your preferences' + + +try: + import Image +except ImportError,err: + print 'You need to install Python Imaging Library (PIL).' + print 'If using gentoo then you need to emerge /dev-python/imaging' + print 'If using an RPM based linux distribution then you add python-imaging or similar.' + print 'Script will continue without the font preview panel.' + showPreviewPanel = 0 + + +try: + import ImageTk +except ImportError,err: + print 'Module ImageTk not found, font preview disabled' + showPreviewPanel = 0 + + +if showPreviewPanel: + if not os.path.exists(TEMP_PATH): + print '.scribus folder not found, disabling font preview panel' + showPreviewPanel = 0 + if not os.access(TEMP_PATH, os.W_OK): + print 'Unable to write to .scribus folder, disabling font preview panel' + showPreviewPanel = 0 + + +# A few globals for use later... +gSamplePic = None +gPreviewId = None + +#************************************************************************* + +WINDOW_TITLE = 'Font Sampler v0.8.1tk - Steve Callcott' +SUPPORT_PAGE = 'www.firstwish.co.uk/sjc/scribus/index.php' + +fontsListFixed = ( + 'Luxi Mono Regular', + 'Nimbus Mono L Regular', + 'Courier 10 Pitch Regular', + 'Courier New Regular', + 'Courier Regular', + 'Andale Mono Regular', + 'Larabiefont Regular' +) + +fontsListProportional = ( + 'Nimbus Sans L Regular', + 'Luxi Sans Regular', + 'Bitstream Vera Sans', + 'Helvetica', + 'Arial Regular' +) + +defaultPrefs = { + 'wantDoubleSided': 0, + 'paperSize':'A4', # currently PAPER_LETTER or PAPER_A4 + 'wantTOC': 1, + 'wantBindingOffset': 0, + 'wantPageNumbers': 1, + 'wantPageOneOnFirst': 0, + 'wantAlphabet' : 1, + 'want6Point' : 1, + 'want8Point' : 1, + 'want10Point' : 1, + 'want12Point' : 1, + 'want16Point' : 1, + 'want20Point' : 1, + 'want32Point' : 1, + 'wantParagraph' : 0 # Uses a lot of space so default is off +} + +userPrefs = {} + +geometriesList = [ + { + 'paperName' : 'A4', + 'paperSize' : scribus.PAPER_A4, + 'paperWidth' : 595, + 'paperHeight' : 842, + 'paperTopMargin' : 60, + 'paperBottomMargin' : 50, + 'paperLeftMargin' : 50, + 'paperRightMargin' : 50, + 'paperBinding' : 16, + 'tocRowsPerPage' : 57, + 'paperPageNumVertOffset' : 16 + }, + { + 'paperName' : 'US Letter', + 'paperSize' : scribus.PAPER_LETTER, + 'paperWidth' : 612, + 'paperHeight' : 792, + 'paperTopMargin' : 27, + 'paperBottomMargin' : 45, + 'paperLeftMargin' : 50, + 'paperRightMargin' : 50, + 'paperBinding' : 18, + 'tocRowsPerPage' : 56, + 'paperPageNumVertOffset' : 16 + } +] + +# define our data dictionary and some of the data... +dD = { + 'tocHeaderTitle' : 'Table of Contents', + 'tocCharsInRow' : 75, + 'previewpanelFontHeight' : 28, + 'previewpanelSampleText' : 'Woven silk pyjamas exchanged for blue quartz' +} + +samplesHeader = { + 'fontSize' : 16, + 'lineSpace' : 15, + 'textHeight' : 23 +} + +# Use \xBC etc to insert Hex ascii chars into the sample strings below. +sampleAlphabet = { + 'fontSize' : 10.5, + 'lineSpace' : 12, + 'textString' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#?$*&', + 'textHeight' : 18 +} + +sample6Point = { + 'fontSize' : 6, + 'lineSpace' : 6, + 'textString' : 'This line is in 6 point', + 'textHeight' : 13 +} + +sample8Point = { + 'fontSize' : 8, + 'lineSpace' : 8, + 'textString' : 'This line is in 8 point', + 'textHeight' : 16 +} + +sample10Point = { + 'fontSize' : 10, + 'lineSpace' : 11, + 'textString' : 'This line is in 10 point', + 'textHeight' : 19 +} + +sample12Point = { + 'fontSize' : 12, + 'lineSpace' : 11, + 'textString' : 'This line is in 12 point', + 'textHeight' : 21 +} + +sample16Point = { + 'fontSize' : 16, + 'lineSpace' : 13, + 'textString' : 'This line is in 16 point', + 'textHeight' : 26 +} + +sample20Point = { + 'fontSize' : 20, + 'lineSpace' : 16, + 'textString' : 'This line is in 20 point', + 'textHeight' : 31 +} + +sample32Point = { + 'fontSize' : 32, + 'lineSpace' : 29, + 'textString' : 'This line is in 32 point', + 'textHeight' : 49 +} + +sampleParagraph = { + 'fontSize' : 9, + 'lineSpace' : 10.8, + 'textHeight' : 175 +} + +sampleParagraphText = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. \ +Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. \ +Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero \ +nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, \ +placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, \ +mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis \ +ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. \ +Nulla placerat porta justo. Nulla vitae turpis.\n\nPraesent lacus.Lorem ipsum dolor sit \ +amet, consectetuer adipiscing elit. Pellentesque habitant morbi tristique senectus \ +et netus et malesuada fames ac turpis egestas. Quisque vel erat eget diam \ +consectetuer iaculis. Cras ante velit, suscipit et, porta tempus, dignissim quis, \ +magna. Vivamus viverra, turpis nec rhoncus ultricies, diam turpis eleifend nisl, a \ +eleifend ante felis ac sapien. Integer bibendum. Suspendisse in mi non neque \ +bibendum convallis. Suspendisse potenti. Sed sit amet purus at felis adipiscing \ +aliquam. Vivamus et nisl sit amet mauris aliquet molestie. Integer tortor massa, \ +aliquam a, lacinia nonummy, sagittis nec, eros.' + +#************************************************************************* + +def set_font_fixed(fontList): + """Find a matching font for the Table of Contents.""" + availableFonts = scribus.getFontNames() + found = 0 + for f in fontList: + if found: + break + for i in availableFonts: + if not found: + if f == i: + return f + found = 1 + break + if not found: + errorList = '' + for j in fontList: + errorList = errorList + j + '\n' + errorMessage ='No suitable fixed width font found.\nPlease install at least one of these fixed width fonts:\n'+errorList + print errorMessage + raise Exception(errorMessage) + + +def set_font_proportional(fontList): + """Find a matching font for the page numbers and font names above samples.""" + availableFonts = scribus.getFontNames() + found = 0 + for p in fontList: + if found: + break + for i in availableFonts: + if not found: + if p == i: + return p + found = 1 + break + if not found: + errorList = '' + for j in fontList: + errorList = errorList + j + '\n' + errorMessage = 'No suitable proportional font found.\nPlease install at least one of these proportional fonts:\n'+errorList + print errorMessage + raise Exception(errorMessage) + + +def save_user_conf(path): + """Save the data to the save file on the path specified by CONFIG_PATH. + + Note initialisation unsets the CONFIG_PATH if it failed to verify or create""" + if not path == '': + try: + file = open(os.path.join(path,'fontsampler.conf'), 'w') + data = { + 'a' : defaultPrefs, + 'b' : userPrefs + } + cPickle.dump(data, file) + file.close() + except: + print 'failed to save data' + + +def restore_user_conf(path): + """Restore the data from the save file on the path specified by CONFIG_PATH.""" + try: + file = open(os.path.join(path,'fontsampler.conf'), 'r') + data = cPickle.load(file) + file.close() + defaultPrefs.update(data['a']) + userPrefs.update(data['b']) + except: + userPrefs.update(defaultPrefs) + print 'failed to load saved data so using default values defined in the script' + + +def set_page_geometry(dD, geometriesList, paperSize, wantBindingOffset): + """This is the experimental replacement paper size setting function. + + Each paper size and other associated data are stored in a dictionary. + The dictionaries are stored in a list. We copy appropriate dictionary + and custom calculations into a work dictionary for use. + The advantage of this is its easier to add new paper definitions. + Returns a new dictionary, use .update to merge in new values into dD. + """ + try: + result={} + for i in geometriesList: + if i['paperName'] == paperSize: + dD.update(i) + + result['paperLeftMarginOdd'] = dD['paperLeftMargin'] + \ + dD['paperBinding'] + result['paperRightMarginEven'] = dD['paperRightMargin'] + \ + dD['paperBinding'] + result['paperTextHeight'] = dD['paperHeight'] - \ + dD['paperTopMargin'] - \ + dD['paperBottomMargin'] + result['paperMargins'] = dD['paperLeftMargin'],dD['paperRightMargin'],dD['paperTopMargin'],dD['paperBottomMargin'] + + # if we are adding a binding offset to the margins then we will have less width for our text... + if wantBindingOffset: + result['paperTextWidth'] = dD['paperWidth'] - \ + dD['paperLeftMargin'] - \ + dD['paperRightMargin'] - \ + dD['paperBinding'] - \ + 2 + else: + result['paperTextWidth'] = dD['paperWidth'] - \ + dD['paperLeftMargin'] - \ + dD['paperRightMargin'] - \ + 2 + return result + except: + errorMessage = 'set_page_geometry() failure: %s' % sys.exc_info()[1] + print errorMessage + + +def set_odd_even(pageNum): + """ Sets the left margin position. + + Checks the number passed to it and sets left margin accordingly. + Call once after each new page is created. + Returns 1 if even and 0 if odd page. + """ + if pageNum % 2 == 0: + isEvenPage = 1 # Even side + else: + isEvenPage = 0 # Odd side + + if userPrefs['wantBindingOffset']: + if isEvenPage and userPrefs['wantDoubleSided']: # Even (when double sided) + dD['paperLeftSide'] = dD['paperLeftMargin'] + 1 + else: # Odd side + dD['paperLeftSide'] = dD['paperLeftMarginOdd'] + 1 + else: # No binding + dD['paperLeftSide'] = dD['paperLeftMargin'] + 1 + return isEvenPage + + +def draw_sample_row(font, fontSize, lineSpace, textString, x, y, w, h, getSizeOnly): + """Creates one row of samples or a header for the top of the block. + + Called once by draw_sample_block() to create a block label then as many times + as required to create each actual sample found in the list of dictionaries + containing each samples definition. + """ + if not getSizeOnly: + f = scribus.createText(x, y, w, h) + scribus.insertText(textString, 0, f) + scribus.setFont(font, f) + scribus.setFontSize(fontSize, f) + scribus.setLineSpacing(lineSpace, f) + scribus.setTextAlignment(0, f) + return y + h + 1 + + +def draw_sample_block(fontName, x, y, w, getSizeOnly): + """Drawing of a complete sample block starts from here. + + Iterates through each sample declared in the "samples" tuple. Places one + complete block using the font specified in fontname. + Note top line on page is drawn outside of this function. This ensures ease + of returning same height of every sample block. Line could have been drawn + at top inside this function and page finalised with line at bottom instead. + If getSizeOnly is true then returns the overall height of the entire text + block but without actually placing it. + """ + startPos = y + # Note there are 2 points of space before horizontal line at bottom of block. + # This 2 points will not appear at top of page so need to add it. + + # set space below horizontal line to the top of the text block + y = y + 4 + + # (note there is one extra point inserted by addSampleRow() for each row generated)... + + # first need a header... + y = draw_sample_row(dD['bookstylePropFont'], samplesHeader['fontSize'], samplesHeader['lineSpace'], fontName, x, y, w, samplesHeader['textHeight'], getSizeOnly) + + if userPrefs['wantAlphabet']: + y = draw_sample_row(fontName, sampleAlphabet['fontSize'], sampleAlphabet['lineSpace'], sampleAlphabet['textString'], x, y, w, sampleAlphabet['textHeight'], getSizeOnly) + + if userPrefs['want6Point']: + y = draw_sample_row(fontName, sample6Point['fontSize'], sample6Point['lineSpace'], sample6Point['textString'], x, y, w, sample6Point['textHeight'], getSizeOnly) + + if userPrefs['want8Point']: + y = draw_sample_row(fontName, sample8Point['fontSize'], sample8Point['lineSpace'], sample8Point['textString'], x, y, w, sample8Point['textHeight'], getSizeOnly) + + if userPrefs['want10Point']: + y = draw_sample_row(fontName, sample10Point['fontSize'], sample10Point['lineSpace'], sample10Point['textString'], x, y, w, sample10Point['textHeight'], getSizeOnly) + + if userPrefs['want12Point']: + y = draw_sample_row(fontName, sample12Point['fontSize'], sample12Point['lineSpace'], sample12Point['textString'], x, y, w, sample12Point['textHeight'], getSizeOnly) + + if userPrefs['want16Point']: + y = draw_sample_row(fontName, sample16Point['fontSize'], sample16Point['lineSpace'], sample16Point['textString'], x, y, w, sample16Point['textHeight'], getSizeOnly) + + if userPrefs['want20Point']: + y = draw_sample_row(fontName, sample20Point['fontSize'], sample20Point['lineSpace'], sample20Point['textString'], x, y, w, sample20Point['textHeight'], getSizeOnly) + + if userPrefs['want32Point']: + y = draw_sample_row(fontName, sample32Point['fontSize'], sample32Point['lineSpace'], sample32Point['textString'], x, y, w, sample32Point['textHeight'], getSizeOnly) + + if userPrefs['wantParagraph']: + y = draw_sample_row(fontName, sampleParagraph['fontSize'], sampleParagraph['lineSpace'], sampleParagraphText, x, y, w, sampleParagraph['textHeight'], getSizeOnly) + + y = y + 1 # one extra point of space above bottom Horiz. line + + lineHeight = draw_horiz_line(y, x, w + x, getSizeOnly) + y = y + lineHeight + + return y - startPos + + +def insert_toc_row(fontName, pageNum, yPos, frame): + """Called once for each content line to be drawn in the text frame.""" + dotLine = "" + dotQuant = dD['tocCharsInRow'] - len(fontName) - len(str(pageNum)) + 1 + for i in range(dotQuant): + dotLine = dotLine + '.' + oneLine = fontName + dotLine + str(pageNum) + "\n" + scribus.insertText(oneLine, yPos, frame) + yPos = yPos + len(oneLine) + 0 + return yPos + + +def build_toc_page_template(): + """Inserts empty toc template into the currently selected page.""" + # first put a header on the empty page... + textstring = dD['tocHeaderTitle'] + yPos = dD['paperTopMargin'] + 1 + header = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 35) + scribus.insertText(textstring, 0, header) + scribus.setFont(dD['bookstylePropFont'], header) + scribus.setFontSize(24, header) + scribus.setTextAlignment(1, header) + # now create a text frame for the table of contents... + yPos = yPos + 36 + body = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], dD['paperHeight'] - yPos - dD['paperBottomMargin'] - 1) + scribus.setFont(dD['bookstyleFixedFont'], body) + scribus.setFontSize(10, body) + scribus.setLineSpacing(12, body) + return body + + +def build_toc(tocList): + """Creates all the Table of Contents pages. + + Calls tocPageFramesBuild() to write the header and empty frame for the + toc rows each time a new page is added. + Then calls tocRowAdd() to add each line to the toc frame. Creates new page + each time it completes last row on page. + """ + rowCount = 0 + yPos = 0 + tocPageNum = 1 + tocPageCount = 1 + + scribus.newPage(tocPageNum) + isEvenPage = set_odd_even(tocPageNum) + body = build_toc_page_template() # create frames for new empty page + if isEvenPage == 0: + scribus.setTextAlignment(2, body) + else: + scribus.setTextAlignment(0, body) + for i in tocList: + if rowCount == dD['tocRowsPerPage']: # Need to build a new TOC page (count is from zero, not one) + tocPageNum = tocPageNum + 1 + scribus.newPage(tocPageNum) + isEvenPage = set_odd_even(tocPageNum) + body = build_toc_page_template() + if not isEvenPage: + scribus.setTextAlignment(2, body) + else: + scribus.setTextAlignment(0, body) + rowCount = 0 + yPos = 0 + tocPageCount = tocPageCount + 1 + yPos = insert_toc_row(i[0], i[1], yPos, body) + rowCount = rowCount + 1 + if userPrefs['wantDoubleSided']: + if tocPageCount % 2 != 0: # Odd page + tocPageNum = tocPageNum + 1 + scribus.newPage(tocPageNum) # Add an extra page if odd number + + +def add_page_num(pageNum): + yPos = dD['paperHeight'] - \ + dD['paperBottomMargin'] - \ + dD['paperPageNumVertOffset'] + footer = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 15) + scribus.insertText('%s' % pageNum, 0, footer) + scribus.setFont(dD['bookstylePropFont'], footer) + scribus.setFontSize(9, footer) + scribus.setTextAlignment(1, footer) + scribus.setLineSpacing(10, footer) + + +def create_empty_samplepage(pageNum, getSizeOnly): + """Creates a new page and increments page number by one. + + Note getSizeOnly is now evaluated. Will still generate page number increment + but will not actually create the new page or place the number on the page.""" + if not getSizeOnly: + scribus.newPage(-1) + pageNum = pageNum + 1 + set_odd_even(pageNum) + if not getSizeOnly: + if userPrefs['wantPageNumbers']: + add_page_num(pageNum) + return pageNum + + +def draw_horiz_line(yPos, xStart, xEnd, getSizeOnly): + """Draws a line and returns the height. + + If getSizeOnly is set then returns the height it would have + used but without actually creating a line. + """ + lineWidth = 1 + if not getSizeOnly: + newLine = scribus.createLine(xStart, yPos, xEnd, yPos) + scribus.setLineWidth(lineWidth, newLine) + return lineWidth + + +def draw_selection(fontList, getSizeOnly): + """Draws the sample blocks onto the Scribus canvas. + + Measure one font sample block including any horizontal lines and extra + vertical spaces. + Get the amount of vertical space available for the text area between the + top line and top of page number area. + Use these two values to calculate how many complete sample blocks will fit + in the space available. This is the "pageBlocks" + Note we always draw the top horizontal line before placing the blocks. This + is taken into account when calculating the available text area. + Next, if "getSizeOnly" is false we create a page then create the sample + blocks while incrementing a counter until it matches the "pageBlocks". + Reset the counter and create new page. We keep going until we have processed + all the fonts in the selection list. + We update the Scribus progress bar as we create each font sample block. + The returned result is used to update some values in the status bar. + """ + progress = 1 + scribus.progressReset() + scribus.progressTotal(len(fontList)) + tocList = [] + pageNum = 1 + blockCounter = 0 + counter = 0 + facingPages = scribus.NOFACINGPAGES + + # Just get blocks per page value... + set_odd_even(pageNum) + lineHeight = 1 # include the one point of space below top margin + lineHeight = lineHeight + draw_horiz_line(0, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], 1) + usuableArea = dD['paperHeight'] - \ + dD['paperTopMargin'] - \ + lineHeight - \ + dD['paperBottomMargin'] - \ + dD['paperPageNumVertOffset'] + + blockHeight = draw_sample_block(fontList[0], dD['paperLeftSide'], 0, dD['paperTextWidth'], 1) + pageBlocks = int(usuableArea / blockHeight) + #print blockHeight + #print "Usuable area %s points high" % usuableArea + #print "Used space on page is %s points high" % (blockHeight * pageBlocks) + + if not getSizeOnly: + # not a dummy run so start by setting up page numbering... + if userPrefs['wantPageOneOnFirst'] and userPrefs['wantTOC']: + tocPageCount = divmod(len(fontList), dD['tocRowsPerPage']) + pageNum = pageNum + tocPageCount[0] + if tocPageCount[1] != 0: + # (adding more to page number as not whole number) + pageNum = pageNum + 1 + if userPrefs['wantDoubleSided']: + oddEvenTest = divmod(pageNum, 2) + if oddEvenTest[1] == 0: + # (adding extra one to start number as odd amount) + pageNum = pageNum + 1 + if userPrefs['wantDoubleSided']: + facingPages = scribus.FACINGPAGES + # now create a new document with empty page and start building... + scribus.newDocument(dD['paperSize'], dD['paperMargins'], scribus.PORTRAIT, 1, scribus.UNIT_POINTS, facingPages, scribus.FIRSTPAGERIGHT, 1) + scribus.zoomDocument(-100) + # A new doc gives us a new page by default so set it up first... + set_odd_even(pageNum) + yPos = dD['paperTopMargin'] + 1 + lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly) + yPos = yPos + lineHeight + if userPrefs['wantPageNumbers']: + add_page_num(pageNum) + for i in fontList: + # Now place the actual sample block but create a new page if needed... + if counter == pageBlocks: + pageNum = create_empty_samplepage(pageNum, getSizeOnly) + yPos = dD['paperTopMargin'] + 1 + lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly) + yPos = yPos + lineHeight + counter = 0 + blockHeight = draw_sample_block(i, dD['paperLeftSide'], yPos, dD['paperTextWidth'], getSizeOnly) + yPos = yPos + blockHeight + # and also increment the Scribus progress bar... + scribus.progressSet(progress) + progress = progress + 1 + # Add current font to TOC... + tocList.append([i, pageNum]) + counter = counter + 1 + if userPrefs['wantTOC']: + # Insert table of contents - (before page numbering)... + build_toc(tocList) + scribus.gotoPage(1) + return pageBlocks + + +def preview_font(app, fontName): + """Gets the named font and puts a sample in the preview panel. + + Pick up the temp sample qpixmap file and display it in a canvas object + The temp file is put in the users ".scribus" folder and cleaned up on exit. + We create samplePic as a global as a workaround because the reference count + does not increase when we add the image to the canvas. Therefore python + garbage collection removes our image before we have even displayed it. + Note app.previewPanel is the actual canvas. + """ + global gSamplePic + global gPreviewId + scribus.renderFont(fontName, os.path.join(TEMP_PATH,'temp079r.bmp'),dD['previewpanelSampleText'],dD['previewpanelFontHeight']) + try: + tempPic = Image.open(os.path.join(TEMP_PATH,'temp079r.bmp')) + tempPic.save(os.path.join(TEMP_PATH,'temp079r.jpeg'),format='JPEG') + tempImage = Image.open(os.path.join(TEMP_PATH,'temp079r.jpeg')) + imgDimen = tempPic.getbbox() + gSamplePic = ImageTk.PhotoImage(tempImage) + # To center the image use "Half display height minus half the image height" + # preview panel is allegedly 56 (60 less a 2 pixel border top and bottom) + # need to be lower than that to look correct visually... + topEdge = (32 - (imgDimen[3] / 2)) + gPreviewId = app.previewPanel.create_image(5, topEdge, anchor=NW, image=gSamplePic) + os.remove(os.path.join(TEMP_PATH,'temp079r.bmp')) + os.remove(os.path.join(TEMP_PATH,'temp079r.jpeg')) + except IOError: + gSamplePic = None + gPreviewId = app.previewPanel.create_image(0, 0, anchor=NW, image=gSamplePic) + return + + +class AboutDialog(Toplevel): + + def __init__(self, parent): + Toplevel.__init__(self, parent) + self.transient(parent) + self.title('About') + self.parent = parent + self.result = None + self.resizable(0, 0) + + infoLabel = Label(self, text=WINDOW_TITLE+'\nSupport page at %s' % SUPPORT_PAGE) + infoLabel.pack(padx=5, pady=5) + # now the frame for contents... + contentFrame = Frame(self) + self.btnOk = Button(contentFrame, text='OK', command=self.ok, default=ACTIVE) + self.btnOk.pack(side=LEFT, padx=5, pady=5) + contentFrame.pack() + self.bind('<Return>', self.ok) + self.grab_set() + self.protocol('WM_DELETE_WINDOW', self.ok) + self.initial_focus = self.btnOk + self.wait_window(self) + + def ok(self, event=None): + self.withdraw() + self.update_idletasks() + self.parent.focus_set() + self.destroy() + + +class ConfigurationDialog(Toplevel): + + def __init__(self, parent): + Toplevel.__init__(self, parent) + self.transient(parent) + self.title('Configuration') + self.parent = parent + self.result = None + self.resizable(0, 0) + + # Create outer frame... + self.topFrame = Frame(self, bd=1, relief=FLAT) + self.topFrame.grid(row=0, column=0, padx=5, pady=5) + + self.paperSizeLabel = Label(self.topFrame, text='Sample Rows:') + self.paperSizeLabel.grid(row=0, column=0, sticky=W) + + # This frame holds each sample selector... + self.sampleSelectFrame = Frame(self.topFrame, bd=1, relief=RIDGE) + self.sampleSelectFrame.grid(row=1, column=0, padx=0, pady=2) + + # now create the sample selector widgets for the frame... + self.__wantAlphabet = IntVar() + self.btnWantAlphabet = Checkbutton(self.sampleSelectFrame, text='want alphabet row', variable=self.__wantAlphabet, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWantAlphabet.grid(row=0, column=0, padx=10, pady=0, sticky=W) + if userPrefs['wantAlphabet']: + self.btnWantAlphabet.select() + + self.__want6Point = IntVar() + self.btnWant6Point = Checkbutton(self.sampleSelectFrame, text='want 6 point row', variable=self.__want6Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant6Point.grid(row=1, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want6Point']: + self.btnWant6Point.select() + + self.__want8Point = IntVar() + self.btnWant8Point = Checkbutton(self.sampleSelectFrame, text='want 8 point row', variable=self.__want8Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant8Point.grid(row=2, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want8Point']: + self.btnWant8Point.select() + + self.__want10Point = IntVar() + self.btnWant10Point = Checkbutton(self.sampleSelectFrame, text='want 10 point row', variable=self.__want10Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant10Point.grid(row=3, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want10Point']: + self.btnWant10Point.select() + + self.__want12Point = IntVar() + self.btnWant12Point = Checkbutton(self.sampleSelectFrame, text='want 12 point row', variable=self.__want12Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant12Point.grid(row=4, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want12Point']: + self.btnWant12Point.select() + + self.__want16Point = IntVar() + self.btnWant16Point = Checkbutton(self.sampleSelectFrame, text='want 16 point row', variable=self.__want16Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant16Point.grid(row=5, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want16Point']: + self.btnWant16Point.select() + + self.__want20Point = IntVar() + self.btnWant20Point = Checkbutton(self.sampleSelectFrame, text='want 20 point row', variable=self.__want20Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant20Point.grid(row=6, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want20Point']: + self.btnWant20Point.select() + + self.__want32Point = IntVar() + self.btnWant32Point = Checkbutton(self.sampleSelectFrame, text='want 32 point row', variable=self.__want32Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnWant32Point.grid(row=7, column=0, padx=10, pady=0, sticky=W) + if userPrefs['want32Point']: + self.btnWant32Point.select() + + self.__wantParagraph = IntVar() + self.btnParagraphSelect = Checkbutton(self.sampleSelectFrame, text='want sample paragraph', variable=self.__wantParagraph, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) + self.btnParagraphSelect.grid(row=8, column=0, padx=10, pady=0, sticky=W) + if userPrefs['wantParagraph']: + self.btnParagraphSelect.select() + + self.paperSizeLabel = Label(self.topFrame, text='Paper Sizes:') + self.paperSizeLabel.grid(row=2, column=0, sticky=W) + + self.paperSizeFrame = Frame(self.topFrame, bd=1, relief=RIDGE) + self.paperSizeFrame.grid(row=3, column=0, padx=0, pady=2, sticky=W) + + self.__paper = StringVar() + self.a4papersizeSelect = Radiobutton(self.paperSizeFrame, text='A4', variable=self.__paper, value='A4', command=self.__paperSelectionClick) + self.a4papersizeSelect.grid(row=1, column=0, padx=10, sticky=W) + self.uspapersizeSelect = Radiobutton(self.paperSizeFrame, text='US Letter', variable=self.__paper, value='US Letter', command=self.__paperSelectionClick) + self.uspapersizeSelect.grid(row=2, column=0, padx=10, sticky=W) + + # set to match prefs... + if userPrefs['paperSize'] == 'US Letter': + self.uspapersizeSelect.select() + if userPrefs['paperSize'] == 'A4': + self.a4papersizeSelect.select() + + self.btnFrame = Frame(self.topFrame) + self.btnFrame.grid(row=4, column=0, padx=10, pady=2) + self.btnOk = Button(self.btnFrame, text='OK', command=self.ok) + self.btnOk.grid(row=2, column=0, pady=5) + self.bind('<Return>', self.ok) + self.grab_set() + self.initial_focus = self.btnOk + self.wait_window(self) + + + def __sampleSelectionClick(self): + """Get and store all the selections. + + Just assigns the lot at once. Not worth being picky and only + assigning values that have changed since last time. + """ + userPrefs['wantAlphabet'] = self.__wantAlphabet.get() + userPrefs['want6Point'] = self.__want6Point.get() + userPrefs['want8Point'] = self.__want8Point.get() + userPrefs['want10Point'] = self.__want10Point.get() + userPrefs['want12Point'] = self.__want12Point.get() + userPrefs['want16Point'] = self.__want16Point.get() + userPrefs['want20Point'] = self.__want20Point.get() + userPrefs['want32Point'] = self.__want32Point.get() + userPrefs['wantParagraph'] = self.__wantParagraph.get() + self.parent.statusbarUpdate() + + def __paperSelectionClick(self): + userPrefs['paperSize'] = self.__paper.get() + self.parent.statusbarUpdate() + + def ok(self, event=None): + dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) + self.withdraw() + self.update_idletasks() + self.parent.focus_set() + self.destroy() + + +class Application(Frame): + + def __init__(self, master = None): + Frame.__init__(self, master) + + self.grid() + + # Remove maximise button and resize. Not good to allow resizable window + # because the listboxes are fixed width... + self.master.resizable(0, 0) + + # build the menu... + menubar = Menu(self) + settingsmenu = Menu(menubar, tearoff=0) + settingsmenu.add_command(label='Configuration', command=self.__configurationDlgShow) + settingsmenu.add_separator() + settingsmenu.add_command(label='Save current settings', command=self.__saveCurrentSettingsAsDefaults) + settingsmenu.add_command(label='Load saved settings', command=self.__restoreCurrentSettingsFromDefault) + + menubar.add_cascade(label='Settings', menu=settingsmenu) + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About', command=self.__aboutDlgShow) + menubar.add_cascade(label='Help', menu=helpmenu) + # display menu... + self.master.config(menu=menubar) + + # now start adding our widgets starting with the top frame... + self.listbox_frame = Frame(self) + self.listbox_frame.grid(row=0, column=0, sticky=EW) + + # left hand listbox assembly + self.leftListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN) + self.leftListbox_frame.grid(row=1, column=0) + + self.leftLabel = Label(self.listbox_frame, text='Available Fonts') + self.leftLabel.grid(row=0, column=0, sticky=NS) + + self.yScroll1 = Scrollbar(self.leftListbox_frame, orient=VERTICAL) + self.yScroll1.grid(row=0, column=1, sticky=NS) + self.xScroll1 = Scrollbar(self.leftListbox_frame, orient=HORIZONTAL) + self.xScroll1.grid(row=1, column=0, sticky=EW) + + self.listbox1 = Listbox(self.leftListbox_frame, + xscrollcommand=self.xScroll1.set, + yscrollcommand=self.yScroll1.set, + selectmode=EXTENDED, + height=20, width=40) + self.listbox1.grid(row=0, column=0, sticky=NSEW) + self.xScroll1['command'] = self.listbox1.xview + self.yScroll1['command'] = self.listbox1.yview + + def __listbox1KeyRelease(event): + """Check if an Up or Down key has been pressed and released and + if so the preview panel is refreshed. If the keys are held down + the file system slows the scroll. Need a timer here to delay + updates.""" + if (event.keysym == 'Down' or event.keysym == 'Up'): + __listbox1DoLogicCallback(self) + + def __listbox1SingleClick(event): + """Call this first when listbox1 is clicked with mouse to put focus + into the listbox. Note we call when mouse click is released, not pressed, + due to the fact that the listbox does not change the selection until the button + is released.""" + self.listbox1.focus_set() + __listbox1DoLogicCallback(self) + self.listbox1.bind('<ButtonRelease-1>', __listbox1SingleClick) + + def __listbox1DoLogicCallback(event): + """Decides if current selection should be previewed. + + Start by counting items in selection list and if equal to one then + show selected font, ignoring if more or less than one. Then also + set up buttons logic depending on selection. We bind the FocusIn + to this too so button logic and preview gets updated when focus + enters the listbox. + """ + # note we are not making use of "self.listbox1.get(ACTIVE)" due to + # it not getting the real active name. Always one selection behind + # even though we are doing all this in the ButtonRelease event. + # Have made a change here. If more than one font name is selected + # then we just empty the preview. + names = self.listbox1.curselection() + if len(names) == 1: + selectedFont = self.listbox1.get(names[0]) + self.__curSelectedItem(selectedFont) + else: + try: + app.previewPanel.delete(previewId) + except: + pass + #else: + #selectedFont = self.listbox1.get(ACTIVE) + #print selectedFont # for testing + #if selectedFont != "": + #self.__curSelectedItem(selectedFont) + + # Now do the button logic... + self.listbox2.selection_clear(0,END) + self.__setUpDownActive(0, 0) # Force a disable if in other box + if self.listbox1.size() > 0: + self.__setSelButtonsActive(0, 1) + else: + self.__setSelButtonsActive(0, 0) + + self.listbox1.bind('<FocusIn>', __listbox1DoLogicCallback) + self.listbox1.bind('<Any-KeyRelease>', __listbox1KeyRelease) + + def __listbox1DoubleClickCallback(event): + """The single click event will fire also when left listbox + is double clicked but we are detecting the single click button up event.""" + self.__listSelectionToRight() + + self.listbox1.bind('<Double-Button-1>', __listbox1DoubleClickCallback) + + # middle button frame assembly + self.midbutton_frame = Frame(self.listbox_frame) + self.midbutton_frame.grid(row=0, rowspan=2, column=1, sticky=NSEW) + + self.rsingleButton = Button(self.midbutton_frame, state='disabled', text='>', command=self.__rsingleButtonClick) + self.rsingleButton.grid(row=0, column=0, padx=5, pady=5, sticky=EW) + self.rdoubleButton = Button(self.midbutton_frame, text='>>', command=self.__rdoubleButtonClick) + self.rdoubleButton.grid(row=1, column=0, padx=5, pady=5, sticky=EW) + + self.itemupButton = Button(self.midbutton_frame, state='disabled', text='Up', command=self.__itemupButtonClick) + self.itemupButton.grid(row=2, column=0, padx=5, pady=5, sticky=EW) + self.itemdownButton = Button(self.midbutton_frame, state='disabled', text='Down', command=self.__itemdownButtonClick) + self.itemdownButton.grid(row=3, column=0, padx=5, pady=5, sticky=EW) + + self.lsingleButton = Button(self.midbutton_frame, state='disabled', text='<', command=self.__lsingleButtonClick) + self.lsingleButton.grid(row=4, column=0, padx=5, pady=5, sticky=EW) + self.ldoubleButton = Button(self.midbutton_frame, state='disabled', text='<<', command=self.__ldoubleButtonClick) + self.ldoubleButton.grid(row=5, column=0, padx=5, pady=5, sticky=EW) + + # Right hand listbox assembly + self.rightListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN) + self.rightListbox_frame.grid(row=1, column=2) + + self.rightLabel = Label(self.listbox_frame, text='Selected Fonts') + self.rightLabel.grid(row=0, column=2, sticky=NS) + + self.yScroll2 = Scrollbar(self.rightListbox_frame, orient=VERTICAL) + self.yScroll2.grid(row=0, column=1, sticky=NS) + self.xScroll2 = Scrollbar(self.rightListbox_frame, orient=HORIZONTAL) + self.xScroll2.grid(row=1, column=0, sticky=EW) + + self.listbox2 = Listbox(self.rightListbox_frame, + xscrollcommand=self.xScroll2.set, + yscrollcommand=self.yScroll2.set, + selectmode=EXTENDED, + height=20, width=40) + self.listbox2.grid(row=0, column=0, sticky=NSEW) + self.xScroll2['command'] = self.listbox2.xview + self.yScroll2['command'] = self.listbox2.yview + + def __listbox2SingleClick(event): + """Similar to __listbox1SingleClick().""" + self.listbox2.focus_set() + __listbox2DoLogicCallback(self) + self.listbox2.bind('<ButtonRelease-1>', __listbox2SingleClick) + + def __listbox2KeyRelease(event): + if (event.keysym == 'Down' or event.keysym == 'Up'): + __listbox2DoLogicCallback(self) + + def __listbox2DoLogicCallback(event): + """Similar to __listbox1DoLogicCallback().""" + names = self.listbox2.curselection() + if len(names) == 1: + selectedFont = self.listbox2.get(names[0]) + self.__curSelectedItem(selectedFont) + else: + try: + app.previewPanel.delete(previewId) + except: + pass + + # Now do the button logic... + self.listbox1.selection_clear(0,END) + self.__testUpDownState() + if self.listbox2.size() > 0: + self.__setSelButtonsActive(1, 0) + else: + self.__setSelButtonsActive(0, 0) + self.listbox2.bind('<FocusIn>', __listbox2DoLogicCallback) + self.listbox2.bind('<Any-KeyRelease>', __listbox2KeyRelease) + + def __listbox2DoubleClickCallback(event): + """Similar to __listbox1DoubleClickCallback().""" + self.__listSelectionToLeft() + self.listbox2.bind('<Double-Button-1>', __listbox2DoubleClickCallback) + + # now draw the bottom font preview frame if required... + if showPreviewPanel: + self.preview_frame = Frame(self) + self.preview_frame.grid(row=1, column=0, sticky=EW) + self.previewPanel = Canvas(self.preview_frame, height=60, bg='white', bd=2, relief=SUNKEN) + self.previewPanel.pack(fill=X) + + # now draw the bottom controls frame... + self.controls_frame = Frame(self) + self.controls_frame.grid(row=2, column=0, sticky=EW) + + # create a container... + self.button_frame1 = Frame(self.controls_frame, bd=1, relief=RIDGE) + self.button_frame1.grid(row=0, column=0, padx=10, pady=2) + # create and add page number selection button... + self.__wantPageNum = IntVar() + self.pagenumSelect = Checkbutton(self.button_frame1, text='Print page numbers', variable=self.__wantPageNum, offvalue=0, onvalue=1, command=self.__pageNumberSelectButtonClick) + self.pagenumSelect.grid(row=0, column=0, padx=0, sticky=W) + + # create a container... + self.button_frame2 = Frame(self.controls_frame, bd=1, relief=RIDGE) + self.button_frame2.grid(row=0, column=1, padx=10, pady=2) + # create and add the TOC selector... + self.__wantToc = IntVar() + self.tocSelect = Checkbutton(self.button_frame2, text='Print table of contents', variable=self.__wantToc, offvalue=0, onvalue=1, command=self.__tocSelectButtonClick) + self.tocSelect.grid(row=0, column=0, padx=0, sticky=W) + # create and add page one on first selector... + self.__wantPageOneOnFirst = IntVar() + self.btnPageOneOnFirst = Checkbutton(self.button_frame2, text='Page count includes TOC', variable=self.__wantPageOneOnFirst, offvalue=0, onvalue=1, command=self.__wantPageOneOnFirstClick) + self.btnPageOneOnFirst.grid(row=1, column=0, padx=0, sticky=W) + + # create a container... + self.button_frame3 = Frame(self.controls_frame, bd=1, relief=RIDGE) + self.button_frame3.grid(row=0, column=2, padx=10, pady=2) + # create and add the binding offset... + self.__wantBindingOffset = IntVar() + self.bindingoffsetSelect = Checkbutton(self.button_frame3, text='Extra offset for binding', variable=self.__wantBindingOffset, offvalue=0, onvalue=1, command=self.__bindingoffsetSelectButtonClick) + self.bindingoffsetSelect.grid(row=0, column=0, sticky=W) + # create and add the double sided selection buttons... + self.__wantDoubleSided = IntVar() + self.doublesidedSelect = Checkbutton(self.button_frame3, text='Double sided pages', variable=self.__wantDoubleSided, offvalue=0, onvalue=1, command=self.__doubleSidedSelectButtonClick) + self.doublesidedSelect.grid(row=1, column=0, rowspan=2, sticky=W) + + # now the ok and cancel buttons... + self.cancelButton = Button(self.controls_frame, text='Cancel', command=self.__cancelButtonClick) + self.cancelButton.grid(row=0, column=3, padx=5) + self.okButton = Button(self.controls_frame, text='OK', state='disabled', command=self.__okButtonClick) + self.okButton.grid(row=0, column=4, padx=5) + + # now create the bottom status bar frame and contents... + self.status_frame = Frame(self) + self.status_frame.grid(row=3, column=0, sticky=E+W) + self.status0 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) + self.status0.pack(side=LEFT) + self.status1 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) + self.status1.pack(side=LEFT) + self.status2 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) + self.status2.pack(side=LEFT) + self.status3 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) + self.status3.pack(side=LEFT) + self.statusPaperSize = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) + self.statusPaperSize.pack(fill=X) + + def statusbarUpdate(self): + """Draws the status bar contents. + + Note "draw_selection()" does a dummy run to count the amount of sample + blocks on a sheet. + TODO: Statusbar setting and recalculation should be separated. Just recalc + and refresh panels as required instead of all of them each time. + """ + available = self.listbox1.size() + selected = self.listbox2.size() + size = FloatType(selected) + blocksPerSheet = draw_selection(scribus.getFontNames(), 1) + value = size / blocksPerSheet + pages = IntType(value) # Get whole part of number + value = value - pages # Remove whole number part + if value > 0: # Test remainder + pages = pages + 1 # Had remainder so add a page + self.status0['text'] = 'Fonts available: %s ' % (available + selected) + self.status1['text'] = 'Fonts selected: %s ' % selected + self.status2['text'] = 'Sheets required: %s ' % pages + self.status3['text'] = 'Fonts per sheet: %s ' % blocksPerSheet + self.statusPaperSize['text'] = 'Paper size: %s ' % userPrefs['paperSize'] + + def __listSelectionToRight(self): + toMoveRight = ListType(self.listbox1.curselection()) + self.listbox1.selection_clear(0,END) + toMoveRight.reverse() # reverse list so we delete from bottom of listbox first + tempList = [] + for i in toMoveRight: + tempList.insert(0,self.listbox1.get(i)) # gets the actual strings (reverse again) + self.listbox1.delete(i) + for j in tempList: + self.listbox2.insert(END, j) + self.__setButtonsState() + self.__setSelButtonsActive(0, 0) + self.statusbarUpdate() + + def __listSelectionToLeft(self): + toMoveLeft = ListType(self.listbox2.curselection()) + toMoveLeft.reverse() + self.listbox2.selection_clear(0,END) + for i in toMoveLeft: + self.listbox1.insert(END, self.listbox2.get(i)) # Insert it at the end + self.listbox2.delete(i) + fontList = ListType(self.listbox1.get(0, END)) # Copy contents to a list type + self.listbox1.delete(0, END) # Remove all contents + fontList.sort() # Use sort method of list + for j in fontList: + self.listbox1.insert(END, j) # Replace with sorted version + self.__setButtonsState() + self.__setSelButtonsActive(0, 0) + self.statusbarUpdate() + + def __listAllToRight(self): + fontList = self.listbox1.get(0, END) # Get each font name into a list + for i in fontList: + self.listbox2.insert(END, i) # Copy each one + self.listbox1.delete(0, END) # All done so empty the left listbox + self.__setButtonsState() + self.__setSelButtonsActive(0, 0) + self.statusbarUpdate() + + def __listAllToLeft(self): + """Moves all selected fonts back to the left hand pane. + + Note we just clear both panes then reload the left listbox in correct + order from scratch as this is probably quicker than moving each + item individually. + """ + self.listbox1.delete(0, END) + fontList = scribus.getFontNames() + fontList.sort() + for i in fontList: + self.listbox1.insert(END, i) + self.listbox2.delete(0, END) + self.__setButtonsState() + self.__setSelButtonsActive(0, 0) + self.statusbarUpdate() + + def __setSelButtonsActive(self, selToRight, selToLeft): + # The "selection" buttons are the ones with ">" and "<" on them + if selToRight == 1: + self.lsingleButton['state'] = NORMAL + else: + self.lsingleButton['state'] = DISABLED + if selToLeft == 1: + self.rsingleButton['state'] = NORMAL + else: + self.rsingleButton['state'] = DISABLED + + def __setAllButtonsActive(self, allToRight, allToLeft): + # The "all" buttons are the ones with ">>" and "<<" on them + if allToRight == 1: + self.rdoubleButton['state'] = NORMAL + else: + self.rdoubleButton['state'] = DISABLED + if allToLeft == 1: + self.ldoubleButton['state'] = NORMAL + else: + self.ldoubleButton['state'] = DISABLED + + def __setButtonsState(self): + if self.listbox2.size() > 0 and self.listbox1.size() > 0: + self.__setAllButtonsActive(1, 1) + self.okButton['state'] = NORMAL + elif self.listbox2.size() == 0: + self.__setAllButtonsActive(1, 0) + self.okButton['state'] = DISABLED + elif self.listbox1.size() == 0: + self.__setAllButtonsActive(0, 1) + self.okButton['state'] = NORMAL + + def __itemUp(self): + """Test if one item is selected then move it up one position.""" + selection = self.listbox2.curselection() + if len(selection) == 1: + indexId = IntType(selection[0]) # Get the first (only) item as integer type + if indexId > 0: + fontString = self.listbox2.get(indexId) + self.listbox2.delete(indexId) + newPos = indexId - 1 + self.listbox2.selection_clear(0, END) + self.listbox2.insert(newPos, fontString) + self.listbox2.see(newPos - 10) # Scrolls listbox automatically into view if req. + self.listbox2.selection_set(newPos) + self.listbox2.activate(newPos) # make focus follow selection + self.__testUpDownState() # note tests only after an item has been moved + + def __itemDown(self): + """Test if one item is selected then move it down one position.""" + limit = self.listbox2.size() + selection = self.listbox2.curselection() + if len(selection) == 1: + indexId = IntType(selection[0]) + if indexId < limit - 1: + fontString = self.listbox2.get(indexId) + self.listbox2.delete(indexId) + newPos = indexId + 1 + self.listbox2.selection_clear(0, END) + self.listbox2.insert(newPos, fontString) + self.listbox2.see(newPos + 10) + self.listbox2.selection_set(newPos) + self.listbox2.activate(newPos) # make focus follow selection + self.__testUpDownState() + + def __setUpDownActive(self, up, down): + """Just sets the buttons active or inactive. + + See testUpDown() for the actual evaluation + """ + if up == 1: + self.itemupButton['state'] = NORMAL + else: + self.itemupButton['state'] = DISABLED + if down == 1: + self.itemdownButton['state'] = NORMAL + else: + self.itemdownButton['state'] = DISABLED + + def __testUpDownState(self): + """Only enable the up and down buttons when just a single item is selected. + + Enable should be applied to up, down or both depending on its + position in the listbox. At all other times disable both. + """ + # Get a count of how many items are currently selected... + selection = list(self.listbox2.curselection()) + tcount = 0 + for sel in selection: + tcount = tcount + 1 + + position = 0 + if tcount == 1: + position = IntType(selection[0]) + + # If one selected and there is more than one item in the listbox then ok... + if tcount == 1 and self.listbox2.size() > 1: + # Now test the position of the selected line... + if position > 0 and position < self.listbox2.size() - 1: # Both + self.__setUpDownActive(1, 1) + # If not one less or lesser from the bottom (listbox.count-1?) then gray the down button. + elif position == self.listbox2.size() - 1: # Up only + self.__setUpDownActive(1, 0) + # If not one or more from the top then gray up button. + elif position == 0: # Down only + self.__setUpDownActive(0, 1) + else: + self.__setUpDownActive(0, 0) + + def __curSelectedItem(self, selectedFont): + """Send the selected font to the preview function if preview available.""" + if showPreviewPanel: + preview_font(self, selectedFont) + + # create the button events... + def __rsingleButtonClick(self): + self.__listSelectionToRight() + + def __rdoubleButtonClick(self): + self.__listAllToRight() + + def __lsingleButtonClick(self): + self.__listSelectionToLeft() + self.__testUpDownState() + + def __ldoubleButtonClick(self): + self.__listAllToLeft() + self.__testUpDownState() + + def __itemupButtonClick(self): + self.__itemUp() + + def __itemdownButtonClick(self): + self.__itemDown() + + def __tocSelectButtonClick(self): + userPrefs['wantTOC'] = self.__wantToc.get() + if userPrefs['wantTOC']: + self.btnPageOneOnFirst['state'] = NORMAL + else: + self.btnPageOneOnFirst['state'] = DISABLED + + def __pageNumberSelectButtonClick(self): + userPrefs['wantPageNumbers'] = self.__wantPageNum.get() + + def __bindingoffsetSelectButtonClick(self): + userPrefs['wantBindingOffset'] = self.__wantBindingOffset.get() + dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) + + def __doubleSidedSelectButtonClick(self): + userPrefs['wantDoubleSided'] = self.__wantDoubleSided.get() + + def __wantPageOneOnFirstClick(self): + userPrefs['wantPageOneOnFirst'] = self.__wantPageOneOnFirst.get() + + def __cancelButtonClick(self): + """We exit the app here if user presses cancel.""" + self.master.destroy() + + def __okButtonClick(self): + """User presses ok, so lets create the pages.""" + save_user_conf(CONFIG_PATH) + draw_selection(self.listbox2.get(0, END), 0) + self.master.destroy() + + def __configurationDlgShow(self): + """Opens the configuration dialog where user can set up the options""" + configs = ConfigurationDialog(self) + self.statusbarUpdate() + + def __saveCurrentSettingsAsDefaults(self): + """Stores current settings as defaults.""" + defaultPrefs.update(userPrefs) + save_user_conf(CONFIG_PATH) + + def __restoreCurrentSettingsFromDefault(self): + """Restores current settings from defaults.""" + userPrefs.update(defaultPrefs) + self.initialiseWidgets() + self.statusbarUpdate() + + def initialiseWidgets(self): + if userPrefs['wantPageNumbers']: + self.pagenumSelect.select() + else: + self.pagenumSelect.deselect() + if userPrefs['wantTOC']: + self.tocSelect.select() + self.btnPageOneOnFirst['state'] = NORMAL + else: + self.tocSelect.deselect() + self.btnPageOneOnFirst['state'] = DISABLED + if userPrefs['wantBindingOffset']: + self.bindingoffsetSelect.select() + else: + self.bindingoffsetSelect.deselect() + if userPrefs['wantDoubleSided']: + self.doublesidedSelect.select() + else: + self.doublesidedSelect.deselect() + if userPrefs['wantPageOneOnFirst']: + self.btnPageOneOnFirst.select() + else: + self.btnPageOneOnFirst.deselect() + + def __aboutDlgShow(self): + """Brings up a dialog with support url etc.""" + about = AboutDialog(self) + + +def setup_tk(): + """Create and setup the Tkinter app.""" + root = Tk() + app = Application(root) + app.master.title(WINDOW_TITLE) + + # now get a list of all the fonts Scribus knows about... + fontList = scribus.getFontNames() + fontList.sort() + # and load the list into the GUI listbox... + for i in fontList: + app.listbox1.insert(END, i) + app.sampleBlocksPerPage = draw_selection(scribus.getFontNames(), 1) + # now set the status bar message... + app.statusbarUpdate() + # set up widgets using data from userPrefs... + app.initialiseWidgets() + return app + +def initialisation(): + """Test for suitable fonts and on success creates tkinter app.""" + try: + dD['bookstyleFixedFont'] = set_font_fixed(fontsListFixed) + dD['bookstylePropFont'] = set_font_proportional(fontsListProportional) + except: + scribus.messageBox('Font problem', + '%s' % sys.exc_info()[1], + scribus.ICON_WARNING) + sys.exit(1) + # load users saved defaults... + restore_user_conf(CONFIG_PATH) + # get and set the initial paper size to match default radiobutton selection... + dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) + # Made it this far so its time to create our Tkinter app... + app = setup_tk() + # now show the main window and wait for user to do something... + app.mainloop() + + +def main(argv): + """Application initialization, font checks and initial setup.""" + initialisation() + + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + scribus.statusMessage('Running script...') + scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage('') + scribus.progressReset() + + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) + diff --git a/scribus/plugins/scriptplugin/scripts/InfoBox.py b/scribus/plugins/scriptplugin/scripts/InfoBox.py new file mode 100644 index 0000000..f1050e1 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/InfoBox.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# **************************************************************************** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# **************************************************************************** + + +""" +(C) 2005 by Thomas R. Koll, <tomk32@gmx.de>, http://verlag.tomk32.de + +(c) 2008, 2010 modifications, additional features, and some repair + by Gregory Pittman + +A simple script for exact placement of a frame (infobox) +over the current textbox, asking the user for the width +of the infobox and in which column to place it. + +Some enhancements: + +* You can now create a text frame or an image frame, and also load +an image. + +* More than one infobox can be added to a text frame by repeatedly running + the script (ie, no name conflicts occur). + +* Height and Y-Pos of top of infobox can be specified. + +* Works with any page unit - pts, mm, in, and picas, cm, and even ciceros. + +* Infobox has Text Flows Around Frame activated, also + Scale Image to Frame for images. + +USAGE + +Select a textframe, start the script and have phun +Default name for the infobox is 'infobox' + name_of_selected_frame, +but this can be changed. + + +""" + +try: + import scribus +except ImportError: + print "Unable to import the 'scribus' module. This script will only run within" + print "the Python interpreter embedded in Scribus. Try Script->Execute Script." + sys.exit(1) + +def main(argv): + unit = scribus.getUnit() + units = [' pts','mm',' inches',' picas','cm',' ciceros'] + unitlabel = units[unit] + if scribus.selectionCount() == 0: + scribus.messageBox('Scribus - Script Error', + "There is no object selected.\nPlease select a text frame and try again.", + scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) + if scribus.selectionCount() > 1: + scribus.messageBox('Scribus - Script Error', + "You have more than one object selected.\nPlease select one text frame and try again.", + scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) + textbox = scribus.getSelectedObject() + pageitems = scribus.getPageItems() + boxcount = 1 + for item in pageitems: + if (item[0] == textbox): + if (item[1] != 4): + scribus.messageBox('Scribus - Script Error', + "This is not a textframe. Try again.", scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(2) + +# While we're finding out what kind of frame is selected, we'll also make sure we +# will come up with a unique name for our infobox frame - it's possible we may want +# more than one for a multicolumn frame. + if (item[0] == ("infobox" + str(boxcount) + textbox)): + boxcount += 1 + left, top = scribus.getPosition(textbox) + o_width, o_height = scribus.getSize(textbox) + o_cols = int(scribus.getColumns(textbox)) + o_gap = scribus.getColumnGap(textbox) + + columns_width = 0 + column_pos = 0 + o_colwidth = (o_width - ((o_cols - 1) * o_gap)) / o_cols + if (o_cols > 1): + while (columns_width > o_cols or columns_width < 1): + columns_width = scribus.valueDialog('Width', + 'How many columns width shall the '+ + 'box be (max ' + str(o_cols) + ')?','1') + columns_width = int(columns_width) + if (columns_width < o_cols): + max = o_cols - columns_width + while (column_pos <= max and column_pos <= 1): + column_pos = scribus.valueDialog('Placement', + 'In which column do you want ' + 'to place the box (1 to ' + + str(o_cols) + ')?','1') + column_pos = int(column_pos) - 1 + if (o_cols == 1): + columns_width = 1 + new_height = 0 + while (new_height == 0): + new_height = scribus.valueDialog('Height','Your frame height is '+ str(o_height) + + unitlabel +'. How tall\n do you want your ' + + 'infobox to be in '+ unitlabel +'?\n If you load an image, height will be\n calculated, so the value here does not\n matter.', str(o_height)) + new_top = -1 + while (new_top < 0): + new_top = scribus.valueDialog('Y-Pos','The top of your infobox is currently\n'+ str(top) + + unitlabel +'. Where do you want \n' + + 'the top to be in '+ unitlabel +'?', str(top)) + framename = scribus.valueDialog('Name of Frame','Name your frame or use this default name',"infobox" + str(boxcount) + textbox) + frametype = 'text' + frametype = scribus.valueDialog('Frame Type','Change to anything other\n than "text" for image frame.\nEnter "imageL" to also load an image',frametype) + new_width = columns_width * o_colwidth + (columns_width-1) * o_gap + new_left = left + ((column_pos) * o_colwidth) + ((column_pos) * o_gap) + if (frametype == 'text'): + new_textbox = scribus.createText(new_left, float(new_top), new_width, float(new_height),framename) + scribus.setColumnGap(0, new_textbox) + scribus.setColumns(1, new_textbox) + scribus.textFlowMode(new_textbox, 1) + else: + if (frametype == 'imageL'): + imageload = scribus.fileDialog('Load image','Images(*.jpg *.png *.tif *.JPG *.PNG *.jpeg *.JPEG *.TIF)',haspreview=1) + new_image = scribus.createImage(new_left, float(new_top), new_width, float(new_height),framename) + scribus.loadImage(imageload, new_image) + scribus.messageBox('Please Note',"Your frame will be created once you click OK.\n\nUse the Context Menu to Adjust Frame to Image.\n\nIf your image does not fill the width completely,\nstretch the frame vertically first.",scribus.BUTTON_OK) + else: + new_image = scribus.createImage(new_left, float(new_top), new_width, float(new_height),framename) + scribus.textFlowMode(new_image, 1) + scribus.setScaleImageToFrame(scaletoframe=1, proportional=1, name=new_image) +if __name__ == '__main__': + # This script makes no sense without a document open + if not scribus.haveDoc(): + scribus.messageBox('Scribus - Script Error', "No document open", scribus.ICON_WARNING, scribus.BUTTON_OK) + sys.exit(1) + # Disable redraws + scribus.setRedraw(False) + # Run the main script, ensuring redraws are re-enabled even if the + # script aborts with an exception, and don't fail with an exception + # even if the document is closed while the script runs. + try: + main(sys.argv) + finally: + try: + scribus.setRedraw(True) + except: + pass + diff --git a/scribus/plugins/scriptplugin/scripts/NEWS b/scribus/plugins/scriptplugin/scripts/NEWS new file mode 100644 index 0000000..f81f813 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/NEWS @@ -0,0 +1,40 @@ +New since 0.7 series: + + Now able to do a dummy run to calculate and report the amount of samples + that will fit on a page. This enables the script to correctly calculate + how many sheets will be required. Previously it was always assumed that + there would be 3 sample blocks on a sheet. This is now not always the case. + + Sample rows can be selected or unselected to save on paper. The settings are + automatically saved when changed and can be set as user defaults. + + User can choose to have page numbers count from first page of the toc instead + of the first page of samples. This can be helpful if wanting to quickly look + up a font in the toc and then using the Scribus page navigator dialog to go to + the actual page on the screen to view it without printing it out. + + Added initial support for a sample paragraph. The sample paragraph defaults + to "off" due to the amount of space it uses on the page. + +New since v0.6.1: + + Added a font sample preview panel. This will only be displayed if certain system + requirements are met. Otherwise the panel will be hidden. + Changed version numbers to accomodate parallel releases using other widget sets. + Tkinter versions will now have the letters "tk" appended after the version number, a + qt version would be "qt". Note that a qt version will not be appearing until issues will PyQt + can be resolved. + +New since V0.5a: + + Optional Page Numbers. + Optional Table of Contents creation. + Added an optional binding offset. Leaves extra space for the binding edge. + Added Double sided paper facility. Inserts a blank page after table of contents + if required, to force the main sample pages to always start on an odd page + number. This also flips the binding offset to the other side when printing the + even numbered side. + Better layouts. + Has more built in default font options for headers, table of contents and + sample labels. + Users can now select more than one font at a time in the list boxes. diff --git a/scribus/plugins/scriptplugin/scripts/ReadMe b/scribus/plugins/scriptplugin/scripts/ReadMe new file mode 100644 index 0000000..df8aa61 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/ReadMe @@ -0,0 +1 @@ +This folder contains the official Scripts for Scribus diff --git a/scribus/plugins/scriptplugin/scripts/TODO b/scribus/plugins/scriptplugin/scripts/TODO new file mode 100644 index 0000000..ec172b1 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/TODO @@ -0,0 +1,13 @@ +TODO: + +Make a PDF sample page for the web site using three example fonts such as... +Utopia, Bitstream Charter Luxi, Helvetica or any of the Web fonts + - Trebuchet, Times *New * Roman, Georgia + +Need improvments to the clean up code to insure that temp images are removed +from .scribus folder. + +Improve the Listbox events coding. + +Continual holding of Up or Down keys causes preview to be redrawn rapidly. This causes +a number of problems. Needs a timer to delay redraws when scrolling. diff --git a/scribus/plugins/scriptplugin/scripts/color2csv.py b/scribus/plugins/scriptplugin/scripts/color2csv.py new file mode 100644 index 0000000..d4bf10f --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/color2csv.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +ABOUT THIS SCRIPT: + +Export Scribus Colors to CSV + +color2csv.py allows a user to export the colors of a given scribus document in a csv file. The file will be a text file with comma seperated values in the following format: +"colorname", c,m,y,k + +If there is a document opened in scribus, color2csv uses this document as color source. +If there is no document opened in scribus, color2csv displays a file open dialog to allow the user to chose a scribus file to get the colors from. + +Use csv2color to import the colors into a scribus document from a csv file. + +############################ + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Author: Sebastian Stetter + +please report bugs to: scribusscript@sebastianstetter.de +""" +from __future__ import division +import sys + +__version__=1.0 + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +######################### +# YOUR IMPORTS GO HERE # +######################### +import csv +import os +#define some variables + +def getColorsFromDoc(): + """returns a list ("name", c,y,m,k) + get all the colors of that doc. """ + #get a list of al the colornames + scribus.statusMessage("Reading Colors...") + + try: + colorlist = scribus.getColorNames() + scribus.progressTotal(len(colorlist)) + i=0 + colordata=[] + for color in colorlist: + colorvalues=scribus.getColor(color) + c=int(colorvalues[0]/2.55) #convert values from 0-255 to 0-100 + m=int(colorvalues[1]/2.55) + y=int(colorvalues[2]/2.55) + k=int(colorvalues[3]/2.55) + name=color.strip() #eliminate leading and tailing whitespace + cd = [name,c ,m,y,k] + colordata.append(cd) + i=i+1 + scribus.progressSet(i) + + return colordata + except: + scribus.messageBox("color2csv", "Can not retrieve colors - There is no Document", icon=scribus.ICON_WARNING) + sys.exit() + + +def writeColorCsvFile(filename, colorlist): + """writes all the colors to a csv file""" + scribus.statusMessage("Writing colors to csv file...") + scribus.progressTotal(len(colorlist)) + i=0 + try: + csvwriter=csv.writer(file(filename, "w"), quoting=csv.QUOTE_NONNUMERIC) + for line in colorlist: + csvwriter.writerow(line) + i=i+1 + scribus.progressSet(i) + except: + scribus.messageBox("color2csv", "Could not write file!", icon=scribus.ICON_WARNING) + sys.exit() + +def main(argv): + """Main method - here we check if we have a doc - else we open one. we get all the colors and write them to a csv file.""" + if scribus.haveDoc(): #DOC OPEN + #get colors, get filename, write stuff + cols = getColorsFromDoc() + filename = scribus.fileDialog("color2csv: Save csv color file", defaultname="colors.csv", issave=True , haspreview=False) + + #@TODO: optimize path checking + if filename !="": + if os.path.exists(filename): #make shure we don't accidentaly overwrite existing files + answer= scribus.messageBox("color2csv", "File already exists! \n do you want to overwrite it?", icon=scribus.ICON_WARNING, button1=scribus.BUTTON_YES, button2=scribus.BUTTON_ABORT) + if answer == scribus.BUTTON_YES: + writeColorCsvFile(filename, cols) + else: + sys.exit() + else: + writeColorCsvFile(filename, cols) + else: + sys.exit() + else: # NO DOC OPEN - open one! + scribusfile = scribus.fileDialog("color2csv: Open scribus file", "Scribus files(*.sla *.SLA *.sla.gz *.SLA.GZ)") + if scribusfile !="": + try: + scribus.openDoc(scribusfile) + except: + scribus.messageBox("color2csv", "Could not open file!") + sys.exit() + #get colors, get filename, write stuff + cols = getColorsFromDoc() + filename = scribus.fileDialog("color2csv: Save csv color file", defaultname="colors.csv", issave=True ) + writeColorCsvFile(filename, cols) + else: + sys.exit() + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + #scribus.statusMessage("Running script...") + #scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage("") + scribus.progressReset() + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) diff --git a/scribus/plugins/scriptplugin/scripts/csv2color.py b/scribus/plugins/scriptplugin/scripts/csv2color.py new file mode 100644 index 0000000..0c4011d --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/csv2color.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +ABOUT THIS SCRIPT: + +Import Colors from a CSV file to Scribus + +csv2color.py allows a user to import colors from a given csv file into a scribus document. +The file must be a text file with comma seperated values in the following format: + +"colorname", c,m,y,k + +There must be a document opend in scribus where the colors can be defined in. +If the csv contanins one or more color names that already exist in the document, the colors will be imported with a `*` as prefix. + +This script is especially helpfull if you want to use CMYK color representations of color systems like HKS, Pantone or RAL in Scribus. Lots of such CMYK translation tables can be found on the Web. +One can easily copy such a table into a text file, save it in the obove described format and import it into a scribus document. + +Use color2csv to export the colors from a scribus document into a csv file. + +############################ + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Author: Sebastian Stetter + +please report bugs to: scribusscript@sebastianstetter.de +""" +from __future__ import division +import sys + +__version__=1.1 + + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +######################### +# YOUR IMPORTS GO HERE # +######################### +import csv +import os + +PREFIX="*" + +def checkValue(c, m, y, k): + """returns true if the cmyk values are between 0 and 255""" + MINVAL=0 + MAXVAL=255 + valueOk=True + for val in c, m, y, k: + if val >=MINVAL and val <=255: + pass + else: + valueOk=False + + return valueOk + +def getColorsFromCsv(filename): + """get colors from csv file and return a list with name and cmyk 255 values""" + csvreader=csv.reader(file(filename)) + + csvcolors=[] + i=0 + for row in csvreader: + name=row[0] + name=name.strip() + c=int(row[1] )* 2.55 + c=int(c) + m=int(row[2] )* 2.55 + m=int(m) + y=int(row[3] )* 2.55 + y=int(y) + k=int(row[4] )* 2.55 + k=int(k) + if checkValue(c, m, y, k) ==False: + scribus.messageBox("csv2color", "At least one CMYK value in your csv file is not correct \n(must be between 0 and 100)\nAborting script - nothing imported.", icon=scribus.ICON_WARNING) + sys.exit() + else: + pass + color=(name, c, m, y, k) + csvcolors.append(color) + i=i+1 + return csvcolors + +def getColorDict(): + """get the colors that already exist from the opened Document and return a dictionary""" + scribus.statusMessage("Reading existing colors...") + colornames = scribus.getColorNames() + scribus.progressTotal(len(colornames)) + i=0 + colordict={} + for name in colornames: + colordict[name]=None + i=i+1 + scribus.progressSet(i) + return colordict #we can ask this dict if the color already exists + +def importColors(colorlist): + """check if colors exists an import""" + colordict=getColorDict() + scribus.statusMessage("Defining new colors...") + scribus.progressTotal(len(colorlist)) + i=0 + for color in colorlist: + name=color[0] + c=color[1] + m=color[2] + y=color[3] + k=color[4] + while colordict.has_key(name):# check if color already exists - then add PREFIX to name + name = PREFIX+name + + scribus.defineColor(name, c, m, y, k) + i=i+1 + scribus.progressSet(i) + +def main(argv): + """Main method for importing colors.""" + if not scribus.haveDoc(): #do we have a doc? + scribus.messageBox("csv2color", "No document to import colors \n Please open one, first.") + sys.exit() + else: + filename=scribus.fileDialog("csv2color", "CSV files(*.csv *.CSV *.txt *.TXT)") + while os.path.isdir(filename): + filename=scribus.fileDialog("csv2color", "CSV files(*.csv *.CSV *.txt *.TXT)") #proper filename? + else: + try: + colorlist=getColorsFromCsv(filename) + messagestring = "You are going to import %i colors \n This may take a while" % len(colorlist) + answer = scribus.messageBox("csv2color", messagestring, button1=scribus.BUTTON_OK, button2=scribus.BUTTON_CANCEL) + if answer != scribus.BUTTON_OK: + sys.exit() + else: + importColors(colorlist) + scribus.docChanged(True) + scribus.messageBox("csv2color", "Colors imported! \n Thank you for using csv2color and Scribus!") + except: + scribus.messageBox("csv2color", "Could not import file!", icon=scribus.ICON_WARNING) + sys.exit() + + + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + #scribus.statusMessage("Running script...") + scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage("") + scribus.progressReset() + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) diff --git a/scribus/plugins/scriptplugin/scripts/importcsv2table.py b/scribus/plugins/scriptplugin/scripts/importcsv2table.py new file mode 100644 index 0000000..5c628b1 --- /dev/null +++ b/scribus/plugins/scriptplugin/scripts/importcsv2table.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +ABOUT THIS SCRIPT: + +Import CSV data files as tables into Scribus + +1. Create any frame of any size on your page but positioned +where you want the table to be located (upper left corner) + +2. Make sure it is selected + +3. Execute this script: + +You will be prompted first for the width of the left column in mm, +then the right column in mm, then height of all cells, and finally +for a csv filename + +4. The data from the csv file will be imported and a table of +textboxes will be drawn on the page. + +LIMITATIONS: + +1. You are limited to two-column CSV data in your file. + +2. In Scribus versions 1.3.5svn, when the script ends, you cannot +adjust text, colors, and line features for a group, whereas in 1.3.3.x, +all of these can be done without ungrouping. + +HINTS: + +Postgresql: +You can easily create a CSV file with a Postgresql database. From Postgresql, +toggle unaligned output with the '\a' switch, then activate a comma as +a separator with '\f ,' (without apostrophes). Send output to a file +with '\o myfile.csv', then query your database. + +Sqlite3: +You can use "sqlite3 -csv" in the command line or ".mode csv" in sqlite's +interactive shell. + +############################ + +LICENSE: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Author: Sebastian Stetter + +Modifications: Gregory Pittman + +please report bugs to: scribusscript@sebastianstetter.de +""" + +from __future__ import division +import sys + +try: + # Please do not use 'from scribus import *' . If you must use a 'from import', + # Do so _after_ the 'import scribus' and only import the names you need, such + # as commonly used constants. + import scribus +except ImportError,err: + print "This Python script is written for the Scribus scripting interface." + print "It can only be run from within Scribus." + sys.exit(1) + +######################### +# YOUR IMPORTS GO HERE # +######################### +import csv + +#get information about the area where the bale should be drawed +def getPosition(): + if scribus.selectionCount() == 1: + areaname = scribus.getSelectedObject() + position= scribus.getPosition(areaname) + vpos = position[1] + hpos = position[0] + scribus.deleteObject(areaname) + return vpos, hpos + + else: + scribus.messageBox("csv2table", "please select ONE Object to mark the drawing area for the table") + sys.exit() + +#get the cvs data +def getCSVdata(): + """opens a csv file, reads it in and returns a 2 dimensional list with the data""" + csvfile = scribus.fileDialog("csv2table :: open file", "*.csv") + if csvfile != "": + try: + reader = csv.reader(file(csvfile)) + datalist=[] + for row in reader: + rowlist=[] + for col in row: + rowlist.append(col) + datalist.append(rowlist) + return datalist + except Exception, e: + scribus.messageBox("csv2table", "Could not open file %s"%e) + else: + sys.exit + +def getDataInformation(list): + """takes a 2 dimensional list object and returns the numbers of rows and cols""" + datainfo = dict() + datainfo["rowcount"]=len(list) + datainfo["colcount"]= len(list[0]) + return datainfo + +def cellsize(areainfo, datainfo): + """"takes the area and data info and calculates the prper cell size""" + csize=dict() + csize["v"]= areainfo["vsize"] / datainfo["rowcount"] + csize["h"]= areainfo["hsize"] / datainfo["colcount"] + return csize + +def main(argv): + """This is a documentation string. Write a description of what your code + does here. You should generally put documentation strings ("docstrings") + on all your Python functions.""" + ######################### + # YOUR CODE GOES HERE # + ######################### + userdim=scribus.getUnit() #get unit and change it to mm + scribus.setUnit(scribus.UNIT_MILLIMETERS) + cellwidthleft = 0 + cellwidthright = 0 + cellHeight = 0 + pos = getPosition() + while cellwidthleft <= 0: + cellwidthL = scribus.valueDialog('Left Cell Width','How wide (mm) do you wish left cells to be?','30.0') + cellwidthleft = float(cellwidthL) + while cellwidthright <= 0: + cellwidthR = scribus.valueDialog('Right Cell Width','How wide (mm) do you wish right cells to be?','30.0') + cellwidthright = float(cellwidthR) + while cellHeight <= 0: + cellheight = scribus.valueDialog('Cell Height','How tall (mm) do you wish cells to be?','10.0') + cellHeight = float(cellheight) + data = getCSVdata() + di= getDataInformation(data) + hposition=pos[1] + vposition=pos[0] + + objectlist=[] # here we keep a record of all the created textboxes so we can group them later + i=0 + scribus.progressTotal(len(data)) + scribus.setRedraw(False) + for row in data: + c=0 + for cell in row: + cell = cell.strip() + cellsize=cellwidthleft + if c == 1: cellsize=cellwidthright + textbox=scribus.createText(hposition, vposition, cellsize, cellHeight) #create a textbox + objectlist.append(textbox) + scribus.insertText(cell,0, textbox)#insert the text into the textbox + hposition=hposition+cellwidthleft #move the position for the next cell + c=1 + vposition=vposition+cellHeight #set vertical position for next row + hposition=pos[1] #reset vertical position for next row + i=i+1 + scribus.progressSet(i) + + scribus.groupObjects(objectlist) + scribus.progressReset() + scribus.setUnit(userdim) # reset unit to previous value + scribus.docChanged(True) + scribus.statusMessage("Done") + scribus.setRedraw(True) + +def main_wrapper(argv): + """The main_wrapper() function disables redrawing, sets a sensible generic + status bar message, and optionally sets up the progress bar. It then runs + the main() function. Once everything finishes it cleans up after the main() + function, making sure everything is sane before the script terminates.""" + try: + scribus.statusMessage("Importing .csv table...") + scribus.progressReset() + main(argv) + finally: + # Exit neatly even if the script terminated with an exception, + # so we leave the progress bar and status bar blank and make sure + # drawing is enabled. + if scribus.haveDoc(): + scribus.setRedraw(True) + scribus.statusMessage("") + scribus.progressReset() + +# This code detects if the script is being run as a script, or imported as a module. +# It only runs main() if being run as a script. This permits you to import your script +# and control it manually for debugging. +if __name__ == '__main__': + main_wrapper(sys.argv) diff --git a/scribus/plugins/scriptplugin/svgimport.cpp b/scribus/plugins/scriptplugin/svgimport.cpp new file mode 100644 index 0000000..4c5b3d1 --- /dev/null +++ b/scribus/plugins/scriptplugin/svgimport.cpp @@ -0,0 +1,172 @@ +/* +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. +*/ +#include "svgimport.h" +#include "cmdvar.h" +#include "cmdutil.h" + +// We need svgpluginid.h for the SVG format ID, and +// loadsaveplugin.h for the FileFormat interface. +#include "../formatidlist.h" +#include "loadsaveplugin.h" +#include "scribuscore.h" +#include "selection.h" +#include "propertiespalette.h" + +#include <QString> + +PyObject *scribus_placesvg(PyObject* /* self */, PyObject* args) +{ + char *Image; + double x = 0.0; + double y = 0.0; + if (!PyArg_ParseTuple(args, "es|dd", "utf-8", &Image, &x, &y)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const FileFormat * fmt = LoadSavePlugin::getFormatById(FORMATID_SVGIMPORT); + if( fmt ) + { + fmt->loadFile(QString::fromUtf8(Image), LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfScripted); + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + double x2, y2, w, h; + ScCore->primaryMainWindow()->doc->m_Selection->getGroupRect(&x2, &y2, &w, &h); + ScCore->primaryMainWindow()->view->startGroupTransaction(); + ScCore->primaryMainWindow()->doc->moveGroup(pageUnitXToDocX(x) - x2, pageUnitYToDocY(y) - y2); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + ScCore->primaryMainWindow()->propertiesPalette->updateColorList(); + ScCore->primaryMainWindow()->propertiesPalette->paraStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->charStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->SetLineFormats(ScCore->primaryMainWindow()->doc); + } + } + else + { + PyErr_SetString(PyExc_Exception, "SVG Import plugin not available"); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_placeeps(PyObject* /* self */, PyObject* args) +{ + char *Image; + double x = 0.0; + double y = 0.0; + if (!PyArg_ParseTuple(args, "es|dd", "utf-8", &Image, &x, &y)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const FileFormat * fmt = LoadSavePlugin::getFormatById(FORMATID_PSIMPORT); + if( fmt ) + { + fmt->loadFile(QString::fromUtf8(Image), LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfScripted); + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + double x2, y2, w, h; + ScCore->primaryMainWindow()->doc->m_Selection->getGroupRect(&x2, &y2, &w, &h); + ScCore->primaryMainWindow()->view->startGroupTransaction(); + ScCore->primaryMainWindow()->doc->moveGroup(pageUnitXToDocX(x) - x2, pageUnitYToDocY(y) - y2); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + ScCore->primaryMainWindow()->propertiesPalette->updateColorList(); + ScCore->primaryMainWindow()->propertiesPalette->paraStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->charStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->SetLineFormats(ScCore->primaryMainWindow()->doc); + } + } + else + { + PyErr_SetString(PyExc_Exception, "EPS Import plugin not available"); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_placesxd(PyObject* /* self */, PyObject* args) +{ + char *Image; + double x = 0.0; + double y = 0.0; + if (!PyArg_ParseTuple(args, "es|dd", "utf-8", &Image, &x, &y)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const FileFormat * fmt = LoadSavePlugin::getFormatById(FORMATID_SXDIMPORT); + if( fmt ) + { + fmt->loadFile(QString::fromUtf8(Image), LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfScripted); + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + double x2, y2, w, h; + ScCore->primaryMainWindow()->doc->m_Selection->getGroupRect(&x2, &y2, &w, &h); + ScCore->primaryMainWindow()->view->startGroupTransaction(); + ScCore->primaryMainWindow()->doc->moveGroup(pageUnitXToDocX(x) - x2, pageUnitYToDocY(y) - y2); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + ScCore->primaryMainWindow()->propertiesPalette->updateColorList(); + ScCore->primaryMainWindow()->propertiesPalette->paraStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->charStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->SetLineFormats(ScCore->primaryMainWindow()->doc); + } + } + else + { + PyErr_SetString(PyExc_Exception, "OpenOffice Import plugin not available"); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +PyObject *scribus_placeodg(PyObject* /* self */, PyObject* args) +{ + char *Image; + double x = 0.0; + double y = 0.0; + if (!PyArg_ParseTuple(args, "es|dd", "utf-8", &Image, &x, &y)) + return NULL; + if(!checkHaveDocument()) + return NULL; + const FileFormat * fmt = LoadSavePlugin::getFormatById(FORMATID_ODGIMPORT); + if( fmt ) + { + fmt->loadFile(QString::fromUtf8(Image), LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfScripted); + if (ScCore->primaryMainWindow()->doc->m_Selection->count() > 1) + { + double x2, y2, w, h; + ScCore->primaryMainWindow()->doc->m_Selection->getGroupRect(&x2, &y2, &w, &h); + ScCore->primaryMainWindow()->view->startGroupTransaction(); + ScCore->primaryMainWindow()->doc->moveGroup(pageUnitXToDocX(x) - x2, pageUnitYToDocY(y) - y2); + ScCore->primaryMainWindow()->view->endGroupTransaction(); + ScCore->primaryMainWindow()->propertiesPalette->updateColorList(); + ScCore->primaryMainWindow()->propertiesPalette->paraStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->charStyleCombo->updateFormatList(); + ScCore->primaryMainWindow()->propertiesPalette->SetLineFormats(ScCore->primaryMainWindow()->doc); + } + } + else + { + PyErr_SetString(PyExc_Exception, "OpenOffice Import plugin not available"); + return NULL; + } +// Py_INCREF(Py_None); +// return Py_None; + Py_RETURN_NONE; +} + +/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings +with header files structure untouched (docstrings are kept near declarations) +PV */ +void svgimportdocwarnings() +{ + QStringList s; + s << scribus_placesvg__doc__ << scribus_placeeps__doc__ << scribus_placesxd__doc__ << scribus_placeodg__doc__; +} diff --git a/scribus/plugins/scriptplugin/svgimport.h b/scribus/plugins/scriptplugin/svgimport.h new file mode 100644 index 0000000..5446761 --- /dev/null +++ b/scribus/plugins/scriptplugin/svgimport.h @@ -0,0 +1,61 @@ +/* +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. +*/ +#ifndef IMPORTSVG_H +#define IMPORTSVG_H + +// Brings in <Python.h> first +#include "cmdvar.h" + +/*! docstring */ +PyDoc_STRVAR(scribus_placesvg__doc__, +QT_TR_NOOP("placeSVG(\"filename\", x, y)\n\ +\n\ +Places the SVG \"filename\" onto the current page,\n\ +x and y specify the coordinate of the topleft corner of the SVG placed on the page\n\ +\n\ +If loading was successful, the selection contains the imported SVG\n\ +")); +/*! Places an SVG file. */ +PyObject *scribus_placesvg(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_placeeps__doc__, +QT_TR_NOOP("placeEPS(\"filename\", x, y)\n\ +\n\ +Places the EPS \"filename\" onto the current page,\n\ +x and y specify the coordinate of the topleft corner of the EPS placed on the page\n\ +\n\ +If loading was successful, the selection contains the imported EPS\n\ +")); +/*! Places an EPS file. */ +PyObject *scribus_placeeps(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_placesxd__doc__, +QT_TR_NOOP("placeSXD(\"filename\", x, y)\n\ +\n\ +Places the SXD \"filename\" onto the current page,\n\ +x and y specify the coordinate of the topleft corner of the SXD placed on the page\n\ +\n\ +If loading was successful, the selection contains the imported SXD\n\ +")); +/*! Places an SXD file. */ +PyObject *scribus_placesxd(PyObject * /*self*/, PyObject* args); + +/*! docstring */ +PyDoc_STRVAR(scribus_placeodg__doc__, +QT_TR_NOOP("placeODG(\"filename\", x, y)\n\ +\n\ +Places the ODG \"filename\" onto the current page,\n\ +x and y specify the coordinate of the topleft corner of the ODG placed on the page\n\ +\n\ +If loading was successful, the selection contains the imported ODG\n\ +")); +/*! Places an ODG file. */ +PyObject *scribus_placeodg(PyObject * /*self*/, PyObject* args); + +#endif |
