Donnerstag, 14. August 2008

Introduction video

I will try to add some comments later. Here you can see a recorded sessions with ScripterNG in action.

It includes
  • the object explorer
  • the script editor with interactive console
  • the error handler
  • the source checker
  • and an example script which shows to main window in full-screen mode

Sonntag, 10. August 2008

How to add functions to the scripting interface

First a little bit about good API-design. The (mostly) property-based object model in InDesign is a great example how to create a well-designed easy API. Take a look at this guide (PDF, 3.2 MB).

You start with a scaffolding-like script:

Go to the scripterng plug-in directory and call
./new_api.py test
This will generate two files:
  • api_test.h
  • api_test.cpp
from api_example.{h,cpp} as a template.

The files are added to CMakeLists.txt and the header file is included in scripterngimpl.h

Inside these files there is a class TestAPI defined. By default the class is a child of ScriperNGImpl and has the object-name Test. So the class will be automatically available under the name ScriperNG.Test from Python or QtScript.

The class is created at start-up in scriperngimpl.cpp but you might want to change that. Look for the activeDocument Q_PROPERTY in scripterngimpl to see how to create an object on demand.

To write a function which is available for scripting you have to write a public slot method. Allowed as parameters and as return types are basic types (int, bool, ..) and Qt objects. Pointers to pointers and complicated stuff like that does not work - but would not make any sense anyway...
One caveat: If you want to return instances of QObject or QWidget you have to declare the base class QObject or QWidget as return type. The correct typecasting is done later at runtime via the Qt Meta-Object system.

That's all. You do not have to know anything about the scripting language or about any binding api to do parameter conversation and validation. This is done by ScripterNG.

Samstag, 9. August 2008

Script Descriptor Files

These files describe a script. Its extension is .scs and you can write them easily by hand. Here are the possible options and their defaults:

name =
title =
description =
icon =
menu = ScripterNG
shortcut = # A valid QKeySequence as a string, see Qt4-docs
filename = # name of script file
subroutine = # additional entry point?
author =
contact =
homepage =
version =
copyright = # GPL2
scribus_version =
redraw = True
mode = interactive # allowed: batch, interactive, extension
language = python # allowed: python, qtscript
separator_before = False # in menu
separator_after = False # in menu
background_mode = False # threaded execution only for non-gui scripts

More options are already planned and will come with a later release. Feedback on needed features is always welcome.

If you put a script descriptor file inside the scripterng/autoload or ~/.scribus/scripterng/autoload folder it will be loaded at startup, added to the menu bar, etc.
Every entry you see in the ScriperNG menu is already a separate script in autoload.

You can also put the script descriptor inside a source file at the top in double comments. Python files have to be called .spy and look like this:

# -*- coding: utf-8 -*-
## name = about
## title = About ScripterNG
## shortcut = Esc,a
# ScripterNG is a builtin and does not need to be imported
ScripterNG.aboutScripterNG()


With QtScript (extension is .sqts) the same is possible:

/// name = aboutqts
/// title = About ScripterNG from QtScript
ScripterNG.aboutScripter();

Support for .zip-packaged scripts is on the TODO.

Freitag, 18. Juli 2008

Dockable dialogs - manipulate the GUI with PyQt and ScripterNG

With ScripterNG and PyQt you have access to the GUI and you can test new stuff easily.

Here is an example with dockwidgets, which are curently not used inside Scribus:

If you look in the lower left you can see that overlapping dockwidgets get tabbed. This is a new feature in Qt4.


This is done by the following code:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class DockDialog(QDockWidget):

def __init__(self, dlg, area=Qt.RightDockWidgetArea):
QDockWidget.__init__(self, dlg.windowTitle())
self.setObjectName(dlg.objectName() or i18n(dlg.windowTitle()))
self.resize(dlg.size())
dlg.parent().addDockWidget(area, self)
dlg.setParent(self)
dlg.move(0, 0)
self.setWidget(dlg)
self.show()
dlg.installEventFilter(self)

def eventFilter(self, obj, event):
return False
if isinstance(event, QCloseEvent) or isinstance(event, QHideEvent):
obj.hide()
self.hide()
return True
elif isinstance(event, QShowEvent):
self.show()
return QDockWidget.eventFilter(self, obj, event)


dockables = ["Properties", "Outline", "Layers", "Arrange Pages",
"Scrapbook", "Bookmarks", "Align and Distribute"]
docks = qApp.docks = {}

for tlw in qApp.topLevelWidgets():
if isinstance(tlw, QDialog):
title = str(tlw.windowTitle())
if i18n(title) in dockables:
docks[title] = DockDialog(tlw)


This is more a proof of concept and the code should not be used in production, of course. But you can see what is possible with a few lines. And it might be an inspiration how to improve the GUI of Scribus.

Samstag, 28. Juni 2008

Sorry no updates right now

I am busy with doing stuff for University but I hope I will find some time the next days to complete the core. Therefore I have to add support for the new script descriptor files. More on that later in a separate post.

Donnerstag, 19. Juni 2008

ScripterNG plug-in documentation

In progress documentation is now available at http://docs.google.com/Doc?id=ddggcjfj_205f5wsvf2

There is also a document about my previous evaluation at http://docs.google.com/Doc?id=ddggcjfj_16ccjdxrcp

ChangeLog, part 2

2008-06-19 22:55 henning

* src/scripterng_plugin/scripterngimpl.cpp: forgot to raise error
if openDocument fails

2008-06-19 22:55 henning

* src/scripterng_plugin/python/init_scripterng.py: make mikro.Error
class available as ScripterNG.Error

2008-06-19 22:06 henning

* src/scripterng_plugin/api_prefs.cpp,
src/scripterng_plugin/scripterng.cpp,
src/scripterng_plugin/scripterngimpl.cpp,
src/scripterng_plugin/scripterngimpl.h: added checkDocument,
haveDocument, closeDocument, openDocument and setModified

2008-06-19 21:52 henning

* src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/python/sceditor/__init__.py,
src/scripterng_plugin/python/sceditor/mainwindow.py: menu and
mainwindow are now attributes of ScripterNG. EditorMainWindow is
now a child of ScribusMainWindow

2008-06-19 21:50 henning

* src/scripterng_plugin/python/mikro.py: added exception support.
Use RAISE from scripterimpl.h

2008-06-19 02:05 henning

* playground/ElementPath.py, playground/ElementTree.py,
playground/scxml.py: further work on xml support
(now needs newest version of elementtree)

2008-06-19 00:46 henning

* src/scripterng_plugin/python/sceditor/console.py,
src/scripterng_plugin/python/sceditor/highlighter.py,
src/scripterng_plugin/python/sceditor/widget.py: Ported source
editor from QTextEdit to QPlainTextEdit which is faster.
Disabled empty_format in highlighter.

2008-06-17 02:04 henning

* playground/full_issue_draft_1.sla, playground/scxml.py: Scirbus
XML file-format support module

2008-06-17 02:02 henning

* playground/compat.py: compat module stub

2008-06-16 23:05 henning

* src/scripterng_plugin/python/mikro.py: improved speed of child
object access

2008-06-16 01:43 henning

* src/scripterng_plugin/api_prefs.cpp,
src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/scripterngimpl.cpp: ScripterNG(impl) is now
top-level object (from the scripting point of view),
changed parent for ApiPrefs.
Removed not working reload menu item and added a run script menu
item

2008-06-14 23:41 henning

* src/scripterng_plugin/python/excepthook.py,
src/scripterng_plugin/python/excepthook.ui,
src/scripterng_plugin/python/excepthook_ui.py,
src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/scripterngimpl.cpp: Added a nice looking
error handler if a script raises an exception

2008-06-14 05:11 henning

* src/scripterng_plugin/CMakeLists.txt,
src/scripterng_plugin/python/sandbox.py,
src/scripterng_plugin/python/sceditor,
src/scripterng_plugin/python/sceditor/__init__.py,
src/scripterng_plugin/python/sceditor/assist.py,
src/scripterng_plugin/python/sceditor/console.py,
src/scripterng_plugin/python/sceditor/highlighter.py,
src/scripterng_plugin/python/sceditor/indenter.py,
src/scripterng_plugin/python/sceditor/mainwindow.py,
src/scripterng_plugin/python/sceditor/mainwindow.ui,
src/scripterng_plugin/python/sceditor/mainwindow_ui.py,
src/scripterng_plugin/python/sceditor/rope.zip,
src/scripterng_plugin/python/sceditor/widget.py: Removed sandbox.
Added a small editor/console for Python and (partly) QtScript

2008-06-14 05:08 henning

* src/scripterng_plugin/scripterngimpl.cpp: removed a warning

2008-06-14 05:08 henning

* src/scripterng_plugin/python/init_scripterng.py: cleaner init

2008-06-14 05:07 henning

* src/scripterng_plugin/python/mikro.py, tests/test_mikro.py:
Better introspection support for ScripterNG object (via
__members__)

The benefits of dynamic binding using the Qt meta object system

Here you can see the old way to write a function which can be used from Python:

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(true));
}



And now the new way:

bool ScripterNGImpl::openDocument(const QString & filename)
{
bool ret = ScCore->primaryMainWindow()->loadDoc(filename);
if (!ret)
{
RAISE("Cannot open " + filename);
return NULL;
}
return ret;
}


That's all :-)

You only have to make sure the method is defined as a slot or as invokeable. Parsing, checking and converting parameters is not needed anymore. For a more complex method you will save a lot of overhead.


Less code is easier to understand and to modify.
So I hope this will motivate others to contribute to this plug-in.

Real screenshots

These are actual screenshots and no mockups like before.

I hope you won't see this window that often. It pops up if an error occures.


Here you can see the script editor which is available via the ScripterNG menu.

QtScript is already enabled.

Donnerstag, 12. Juni 2008

ChangeLog

I removed this feed from planet-soc.com because I don't think there are many interested in this blog and I don't want to bore the rest ;)

But here you are on my blog, so I guess you are interested in some progress. I am currently in the stage where I complete the core. With core I mean the technical base which will enable me to add new API functions easily bit by bit.

The current plug-in code compiles and is available on the SourceForge SVN server. But you won't see much because most stuff is under the hood currently.

Here is a complete changelog so far:

2008-06-12 15:17 henning

* src/scripterng_plugin/python/mikro.py, tests/test_mikro.py: Moved
mikro test code into separate file

2008-06-12 02:16 henning

* src/scripterng_plugin/python/mikro.py: Fixed connect and added
disconnect

2008-06-12 02:15 henning

* src/scripterng_plugin/python/init_scripterng.py: Check for PyQt4
and report problems on console

2008-06-12 01:52 henning

* src/scripterng_plugin/python/mikro.py: Named child objects are
now available as attributes

2008-06-12 00:56 henning

* src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/python/mikro.py: First use of PyQt 4.4
features.
C++ methods can now be called from Python scripts inside
ScripterNG.
This is an important step to make Scribus functionality available
to
Python.
It's not that much code but it required heavy thinking about a
efficient implementation.

2008-06-10 22:58 henning

* src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/python/sandbox.py,
src/scripterng_plugin/python/scripterng_hooks.py,
src/scripterng_plugin/scripterngimpl.cpp, tests,
tests/mainwinstub.py, tests/mainwinstub.ui, tests/test_menus.py:
Now the plug-in can hook into menus and a menu entry in the
ScripterNG
menu with an example editor/shell was added.

2008-06-10 00:13 henning

* src/scripterng_plugin/README,
src/scripterng_plugin/scripterngimpl.cpp: added README document
and unified some indentions

2008-06-09 22:21 henning

* src/scripterng_plugin, src/scripterng_plugin/CMakeLists.txt,
src/scripterng_plugin/INSTALL,
src/scripterng_plugin/api_prefs.cpp,
src/scripterng_plugin/api_prefs.h, src/scripterng_plugin/python,
src/scripterng_plugin/python/cleanup_scripterng.py,
src/scripterng_plugin/python/init_scripterng.py,
src/scripterng_plugin/python/mikro.py,
src/scripterng_plugin/python/pyqtscript.py,
src/scripterng_plugin/pythonize.cpp,
src/scripterng_plugin/pythonize.h,
src/scripterng_plugin/scripterng.cpp,
src/scripterng_plugin/scripterng.h,
src/scripterng_plugin/scripterngimpl.cpp,
src/scripterng_plugin/scripterngimpl.h: first updated version in
new repository

2008-06-05 18:18 henning

* src/repository_webapp, src/repository_webapp/__init__.py,
src/repository_webapp/apps,
src/repository_webapp/apps/repository,
src/repository_webapp/apps/repository/__init__.py,
src/repository_webapp/apps/repository/models.py,
src/repository_webapp/apps/repository/urls.py,
src/repository_webapp/apps/repository/views.py,
src/repository_webapp/apps/tagging,
src/repository_webapp/apps/tagging/__init__.py,
src/repository_webapp/apps/tagging/fields.py,
src/repository_webapp/apps/tagging/forms.py,
src/repository_webapp/apps/tagging/generic.py,
src/repository_webapp/apps/tagging/managers.py,
src/repository_webapp/apps/tagging/models.py,
src/repository_webapp/apps/tagging/settings.py,
src/repository_webapp/apps/tagging/tagging_trunk,
src/repository_webapp/apps/tagging/tagging_trunk/CHANGELOG.txt,
src/repository_webapp/apps/tagging/tagging_trunk/INSTALL.txt,
src/repository_webapp/apps/tagging/tagging_trunk/LICENSE.txt,
src/repository_webapp/apps/tagging/tagging_trunk/MANIFEST.in,
src/repository_webapp/apps/tagging/tagging_trunk/README.txt,
src/repository_webapp/apps/tagging/tagging_trunk/docs,
src/repository_webapp/apps/tagging/tagging_trunk/docs/overview.txt,
src/repository_webapp/apps/tagging/tagging_trunk/setup.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/__init__.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/fields.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/forms.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/generic.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/managers.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/models.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/settings.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/templatetags,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/templatetags/__init__.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/templatetags/tagging_tags.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests/__init__.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests/models.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests/settings.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests/tags.txt,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/tests/tests.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/utils.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/validators.py,
src/repository_webapp/apps/tagging/tagging_trunk/tagging/views.py,
src/repository_webapp/apps/tagging/templatetags,
src/repository_webapp/apps/tagging/templatetags/__init__.py,
src/repository_webapp/apps/tagging/templatetags/tagging_tags.py,
src/repository_webapp/apps/tagging/tests,
src/repository_webapp/apps/tagging/tests/__init__.py,
src/repository_webapp/apps/tagging/tests/models.py,
src/repository_webapp/apps/tagging/tests/settings.py,
src/repository_webapp/apps/tagging/tests/tags.txt,
src/repository_webapp/apps/tagging/tests/tests.py,
src/repository_webapp/apps/tagging/utils.py,
src/repository_webapp/apps/tagging/validators.py,
src/repository_webapp/apps/tagging/views.py,
src/repository_webapp/create_database.sh,
src/repository_webapp/manage.py, src/repository_webapp/media,
src/repository_webapp/media/media,
src/repository_webapp/media/media/upload,
src/repository_webapp/media/upload,
src/repository_webapp/media/upload/releases,
src/repository_webapp/middleware,
src/repository_webapp/middleware/__init__.py,
src/repository_webapp/middleware/threadlocaluser.py,
src/repository_webapp/run_testserver.sh,
src/repository_webapp/settings.py,
src/repository_webapp/templates, src/repository_webapp/urls.py:
skeleton for web-based repository

2008-05-01 16:39 henning

* doc, playground, src: initial directory structure (and test if
committing works)

2008-04-25 00:21 oleksa

* .: Project branch for Henning's scripter-ng project

Donnerstag, 22. Mai 2008

Mockups

After my first post, my new blog about Scripter got deactivated because it was classified as a spam blog by some automatic software on blogger.com. Luckyly this issue has been resolved.

So here are now some screenshots of some widgets I was working on in the past and which I would like to integrate into ScripterNG.

Inform the user about possible security problems.

Heavily inspired by Firefox...

Currently uses QTextBrowser for HTML rendering but will probably switch to QtWebKit later

The interactive console will also work for QtScript when finished.


I do not plan to replace Emacs but I think a nice editor can be very helpful.
This will be available as an extension to keep the plug-in core small.

Book
Google sent every summer of code student a very nice book. I already enjoyed reading some articles in this book. It is called Beautiful Code.

Sonntag, 18. Mai 2008

Summary so far

Hi this is my first post regarding my summer of code project.

LGM
Last week I was attending the Libre Graphics Meeting in Wroclaw, Poland. It was a great experience meeting all the people in person I already know from IRC and talking to new people involved in free graphics software as well as talking to random people in my hostel (BTW the Avantgarade hostel is really nice and friendly but the kitchen is a little bit small unfortunately).
Ten years ago I once was in Wroclaw and now it was nice to see the improvements all over the place. Nevertheless there is still a lot to do and I hope that Poland will further profit from its membership in the EU.
While discussing with the Scribus developers I got a clear impression that they are looking forward to my project. I described my ideas and got positive feedback. So the real planing and coding can start :-)


PyQt
PyQt are the Python bindings for Qt. These bindings will be used extensively in my project and will be a runtime dependency. So people creating scripts for ScripterNG can rely on the fact that this powerful framework is available (you can say goodbye to Tkinter :-) ). One main benefit is better integration. Additionally it will be possible to reduce the C++ code to its minimum while doing everything else in Python.
I worked with the author of PyQt to make sure that some missing features were added which are very usefull for PyQt inside a C++ application.
A few days ago there was a new release where about 50% of its new features are related to interaction with C++ objects.

Feedback
While I have already concrete ideas and plans I would appreciate any feedback, especially about the document object model (InDesign seems to provide an interesting object model for JavaScript [PDF]).