diff --git a/src/Xournalpp.cpp b/src/Xournalpp.cpp index 1d2a305c..d4a2a9c1 100644 --- a/src/Xournalpp.cpp +++ b/src/Xournalpp.cpp @@ -13,9 +13,6 @@ #include "util/CrashHandler.h" #include "util/Stacktrace.h" -// TODO: debug -#include "model/eraser/EraseableStrokePart.h" - int main(int argc, char * argv[]) { // init crash handler installCrashHandlers(); diff --git a/src/control/Control.cpp b/src/control/Control.cpp index 18c82a35..a231ca80 100644 --- a/src/control/Control.cpp +++ b/src/control/Control.cpp @@ -119,6 +119,13 @@ Control::~Control() { this->scheduler->stop(); + for (GList * l = this->changedPages; l != NULL; l = l->next) { + XojPage * page = (XojPage *) l->data; + page->unreference(); + } + g_list_free(this->changedPages); + this->changedPages = NULL; + delete this->clipboardHandler; this->clipboardHandler = NULL; delete this->recent; @@ -168,10 +175,13 @@ bool Control::checkChangedDocument(Control * control) { return true; } for (GList * l = control->changedPages; l != NULL; l = l->next) { - int p = control->doc->indexOf((XojPage *) l->data); + XojPage * page = (XojPage *) l->data; + int p = control->doc->indexOf(page); if (p != -1) { control->firePageChanged(p); } + + page->unreference(); } g_list_free(control->changedPages); control->changedPages = NULL; @@ -1489,8 +1499,9 @@ void Control::undoRedoPageChanged(PageRef page) { } } - // TODO: reference / unrefrerence!! - this->changedPages = g_list_append(this->changedPages, (XojPage *)page); + XojPage * p = (XojPage *)page; + this->changedPages = g_list_append(this->changedPages, p); + p->reference(); } void Control::selectTool(ToolType type) { diff --git a/src/control/XournalMain.cpp b/src/control/XournalMain.cpp index 898abae1..4d3248d4 100644 --- a/src/control/XournalMain.cpp +++ b/src/control/XournalMain.cpp @@ -79,6 +79,7 @@ int XournalMain::run(int argc, char * argv[]) { gchar * pdfFilename = NULL; #ifdef ENABLE_PYTHON gchar * scriptFilename = NULL; + gchar * scriptArg = NULL; #endif int openAtPageNumber = -1; @@ -89,7 +90,8 @@ int XournalMain::run(int argc, char * argv[]) { { "page", 'n', 0, G_OPTION_ARG_INT, &openAtPageNumber, "Jump to Page (first Page: 1)", "N" }, #ifdef ENABLE_PYTHON - { "script", 'n', 0, G_OPTION_ARG_FILENAME, &scriptFilename, "Runs a Python script as plugin", NULL }, + { "script", 0, 0, G_OPTION_ARG_STRING, &scriptFilename, "Runs a Python script as plugin", NULL }, + { "script-arg", 0, 0, G_OPTION_ARG_STRING, &scriptArg, "Python script parameter", NULL }, #endif { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &optFilename, "", NULL }, { NULL } @@ -187,11 +189,10 @@ int XournalMain::run(int argc, char * argv[]) { } #ifdef ENABLE_PYTHON - PythonRunner * runner = NULL; + PythonRunner::initPythonRunner(control); if(scriptFilename) { - runner = new PythonRunner(control); - runner->runScript(scriptFilename, "xournalTest"); + PythonRunner::runScript(scriptFilename, "xournalTest", scriptArg); } #endif @@ -202,7 +203,7 @@ int XournalMain::run(int argc, char * argv[]) { win->getXournal()->clearSelection(); #ifdef ENABLE_PYTHON - delete runner; + PythonRunner::releasePythonRunner(); #endif delete win; diff --git a/src/gui/XournalView.cpp b/src/gui/XournalView.cpp index d9c7115d..11fc36a3 100644 --- a/src/gui/XournalView.cpp +++ b/src/gui/XournalView.cpp @@ -219,7 +219,7 @@ RepaintHandler * XournalView::getRepaintHandler() { return this->repaintHandler; } -bool XournalView::onKeyReleaseEvent(GdkEventKey *event) { +bool XournalView::onKeyReleaseEvent(GdkEventKey * event) { XOJ_CHECK_TYPE(XournalView); int p = getCurrentPage(); diff --git a/src/plugin/python/PythonRunner.cpp b/src/plugin/python/PythonRunner.cpp index 46b1ad96..46ddd3e2 100644 --- a/src/plugin/python/PythonRunner.cpp +++ b/src/plugin/python/PythonRunner.cpp @@ -3,23 +3,116 @@ #include "bindings/PyXournal.h" +class ScriptData { +public: + ScriptData(String name, String function, String parameter) { + this->name = name; + this->function = function; + this->parameter = parameter; + } + +public: + String name; + String function; + String parameter; +}; + +PythonRunner * PythonRunner::instance = NULL; + PythonRunner::PythonRunner(Control * control) { XOJ_INIT_TYPE(PythonRunner); this->control = control; this->pythonInitialized = false; + + this->callbackId = 0; + + this->mutex = g_mutex_new(); + this->scripts = NULL; } PythonRunner::~PythonRunner() { XOJ_CHECK_TYPE(PythonRunner); - if(this->pythonInitialized) { + if (this->callbackId) { + g_source_remove(this->callbackId); + this->callbackId = 0; + } + + if (this->pythonInitialized) { Py_Finalize(); } + g_mutex_free(this->mutex); + this->mutex = NULL; + + for (GList * l = this->scripts; l != NULL; l = l->next) { + ScriptData * s = (ScriptData *) l->data; + delete s; + } + g_list_free(this->scripts); + this->scripts = NULL; + XOJ_RELEASE_TYPE(PythonRunner); } +void PythonRunner::initPythonRunner(Control * control) { + if (instance) { + g_warning("PythonRunner already initialized!"); + return; + } + + instance = new PythonRunner(control); +} + +void PythonRunner::releasePythonRunner() { + if (instance) { + delete instance; + instance = NULL; + } +} + +void PythonRunner::runScript(String name, String function, String parameter) { + if (instance == NULL) { + g_warning("PythonRunner not initialized!"); + return; + } + + g_mutex_lock(instance->mutex); + + if (instance->callbackId == 0) { + instance->callbackId = g_idle_add((GSourceFunc) scriptRunner, instance); + } + + instance->scripts = g_list_append(instance->scripts, new ScriptData(name, function, parameter)); + + g_mutex_unlock(instance->mutex); +} + +bool PythonRunner::scriptRunner(PythonRunner * runner) { + g_mutex_lock(runner->mutex); + GList * first = g_list_first(runner->scripts); + ScriptData * data = (ScriptData *) first->data; + runner->scripts = g_list_delete_link(runner->scripts, first); + g_mutex_unlock(runner->mutex); + + runner->runScriptInt(data->name, data->function, data->parameter); + + delete data; + + bool callAgain = false; + g_mutex_lock(runner->mutex); + if (runner->scripts) { + callAgain = true; + } else { + callAgain = false; + runner->callbackId = 0; + } + g_mutex_unlock(runner->mutex); + + return callAgain; +} + void PythonRunner::addPath(String path, String & cmd) { XOJ_CHECK_TYPE(PythonRunner); @@ -32,18 +125,20 @@ void PythonRunner::addPath(String path, String & cmd) { void PythonRunner::initPython() { XOJ_CHECK_TYPE(PythonRunner); - if(this->pythonInitialized) { + if (this->pythonInitialized) { return; } - Py_SetProgramName("Xournal"); + Py_SetProgramName("Xournal"); - Py_Initialize(); + Py_Initialize(); PyXournal_initPython(this->control); char buffer[512] = { 0 }; const char * path = getcwd(buffer, sizeof(buffer)); + //TODO: PYTHONPATH + String cmd = "import sys\n"; if (path != NULL) { @@ -59,7 +154,7 @@ void PythonRunner::initPython() { PyRun_SimpleString(cmd.c_str()); } -void PythonRunner::runScript(String path, String function) { +void PythonRunner::runScriptInt(String path, String function, String parameter) { XOJ_CHECK_TYPE(PythonRunner); initPython(); @@ -75,7 +170,14 @@ void PythonRunner::runScript(String path, String function) { /* pFunc is a new reference */ if (pFunc && PyCallable_Check(pFunc)) { - PyObject * pArgs = PyTuple_New(0); + PyObject * pArgs = NULL; + + if (parameter.c_str() == NULL) { + pArgs = PyTuple_New(0); + } else { + pArgs = PyTuple_New(1); + PyTuple_SetItem(pArgs, 0, PyString_FromString(parameter.c_str())); + } PyObject * pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); diff --git a/src/plugin/python/PythonRunner.h b/src/plugin/python/PythonRunner.h index 773203a7..2dff84e2 100644 --- a/src/plugin/python/PythonRunner.h +++ b/src/plugin/python/PythonRunner.h @@ -19,14 +19,21 @@ class Control; class PythonRunner { -public: +private: PythonRunner(Control * control); virtual ~PythonRunner(); public: - void runScript(String path, String function); + static void initPythonRunner(Control * control); + static void releasePythonRunner(); + + static void runScript(String name, String function, String parameter = NULL); + +private: + static bool scriptRunner(PythonRunner * runner); private: + void runScriptInt(String path, String function, String parameter); void addPath(String path, String & cmd); void initPython(); @@ -34,8 +41,16 @@ private: private: XOJ_TYPE_ATTRIB; + static PythonRunner * instance; + + GMutex * mutex; + + GList * scripts; + bool pythonInitialized; Control * control; + + int callbackId; }; #endif /* __PYTHONRUNNER_H__ */ diff --git a/src/plugin/python/bindings/PyXournal.cpp b/src/plugin/python/bindings/PyXournal.cpp index 36e7230e..1bde0c5a 100644 --- a/src/plugin/python/bindings/PyXournal.cpp +++ b/src/plugin/python/bindings/PyXournal.cpp @@ -1,5 +1,7 @@ #include "PyXournal.h" #include "../../../control/Control.h" +#include "../../../gui/XournalView.h" +#include "../../../gui/widgets/XournalWidget.h" #include #include "structmember.h" @@ -17,6 +19,7 @@ typedef struct { PyObject_HEAD Control * control; PyObject * undoRedoHandler; + PyObject * document; } PyXournal; static Control * PyXournal_control = NULL; @@ -29,30 +32,29 @@ void PyXournal_initPython(Control * control) { initxournal(); } -static void PyXournal_dealloc(PyXournal* self) { - self->ob_type->tp_free((PyObject*) self); +static void PyXournal_dealloc(PyXournal * self) { + self->ob_type->tp_free((PyObject *) self); } static PyObject * -PyXournal_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { +PyXournal_new(PyTypeObject * type, PyObject * args, PyObject * kwds) { PyXournal *self; self = (PyXournal *) type->tp_alloc(type, 0); if (self != NULL) { self->control = PyXournal_control; self->undoRedoHandler = PyLong_FromLong(5); + self->document = PyLong_FromLong(20); } return (PyObject *) self; } -static int PyXournal_init(PyXournal *self, PyObject *args, PyObject *kwds) { +static int PyXournal_init(PyXournal * self, PyObject * args, PyObject * kwds) { return 0; } static PyMemberDef PyXournal_members[] = { - { "undoRedoHandler", T_OBJECT, offsetof(PyXournal, undoRedoHandler), 0, "Undo- / Redohandler" }, - { NULL } /* Sentinel */ }; @@ -135,7 +137,7 @@ PyXournal_setSelectedTool(PyXournal * self, PyObject * args) { } static PyObject * -PyXournal_getSelectedTool(PyXournal* self) { +PyXournal_getSelectedTool(PyXournal * self) { ToolType tt = self->control->getToolHandler()->getToolType(); return PyLong_FromLong(tt); @@ -151,8 +153,33 @@ PyXournal_mousePressed(PyXournal * self, PyObject * args) { return NULL; } - // TODO: implememnt - g_warning("NOT IMPLEMENTED!\n"); + MainWindow * win = self->control->getWindow(); + if(!win) { + PyErr_SetString(PyExc_AttributeError, "Window not yet initialized!"); + return NULL; + } + + int pageNo = self->control->getCurrentPageNo(); + XournalView * xournal = win->getXournal(); + double zoom = xournal->getZoom(); + PageView * v = xournal->getViewFor(pageNo); + + GdkEventButton event; + memset(&event, 0, sizeof(GdkEventButton)); + event.type = GDK_BUTTON_PRESS; + event.window = (GdkWindow *)*win; + event.send_event = true; + event.time = 0; + event.x = x * zoom + v->getX(); + event.y = y * zoom + v->getY(); + event.axes = NULL; + event.state = GDK_MOD2_MASK; + event.button = 1; + event.device = gdk_device_get_core_pointer(); + event.x_root = 0; + event.y_root = 0; + + gtk_widget_event(xournal->getWidget(), (GdkEvent *)&event); Py_RETURN_NONE; } @@ -167,26 +194,69 @@ PyXournal_mouseMoved(PyXournal * self, PyObject * args) { return NULL; } - // TODO: implememnt - g_warning("NOT IMPLEMENTED!\n"); + MainWindow * win = self->control->getWindow(); + if(!win) { + PyErr_SetString(PyExc_AttributeError, "Window not yet initialized!"); + return NULL; + } + + int pageNo = self->control->getCurrentPageNo(); + XournalView * xournal = win->getXournal(); + double zoom = xournal->getZoom(); + PageView * v = xournal->getViewFor(pageNo); + + GdkEventMotion event; + memset(&event, 0, sizeof(GdkEventMotion)); + event.type = GDK_MOTION_NOTIFY; + event.window = (GdkWindow *)*win; + event.send_event = true; + event.time = 0; + event.x = x * zoom + v->getX(); + event.y = y * zoom + v->getY(); + event.axes = NULL; + event.state = GDK_MOD2_MASK; + event.is_hint = 0; + event.device = gdk_device_get_core_pointer(); + event.x_root = 0; + event.y_root = 0; + + gtk_widget_event(xournal->getWidget(), (GdkEvent *)&event); Py_RETURN_NONE; } static PyObject * PyXournal_mouseReleased(PyXournal * self) { - // TODO: implememnt - g_warning("NOT IMPLEMENTED!\n"); + MainWindow * win = self->control->getWindow(); + if(!win) { + PyErr_SetString(PyExc_AttributeError, "Window not yet initialized!"); + return NULL; + } + + GdkEventButton event; + memset(&event, 0, sizeof(GdkEventButton)); + event.type = GDK_BUTTON_RELEASE; + event.window = (GdkWindow *)*win; + event.send_event = true; + event.time = 0; + event.x = 0; + event.y = 0; + event.axes = NULL; + event.state = GDK_MOD2_MASK; + event.button = 1; + event.device = gdk_device_get_core_pointer(); + event.x_root = 0; + event.y_root = 0; + + gtk_widget_event(win->getXournal()->getWidget(), (GdkEvent *)&event); Py_RETURN_NONE; } static PyObject * PyXournal_getUndoRedoHandler(PyXournal * self) { - // TODO: implememnt - g_warning("NOT IMPLEMENTED!\n"); - - Py_RETURN_NONE; + Py_INCREF(self->undoRedoHandler); + return self->undoRedoHandler; } static PyObject * @@ -198,10 +268,8 @@ PyXournal_getSelectedPage(PyXournal * self) { static PyObject * PyXournal_getDocument(PyXournal * self) { - // TODO: implememnt - g_warning("NOT IMPLEMENTED!\n"); - - Py_RETURN_NONE; + Py_INCREF(self->document); + return self->document; } static PyObject * @@ -304,8 +372,9 @@ void initxournal() { m = Py_InitModule3("xournal", module_methods, "Xournal api modul"); - if (m == NULL) + if (m == NULL) { return; + } Py_INCREF(&XournalType); PyModule_AddObject(m, "Xournal", (PyObject *) &XournalType); diff --git a/testing/Test.py b/testing/Test.py index 6f772302..6adfc828 100644 --- a/testing/Test.py +++ b/testing/Test.py @@ -1,9 +1,43 @@ import xournal +import undo.UndoRedoTest +import os -def xournalTest(): - print 'Testmethode' +def xournalTest(args = ''): + print 'Xournal testsuit started...' xoj = xournal.Xournal() + + xournalRunTestInSubfolder(xoj, 'tools'); + xournalRunTestInSubfolder(xoj, 'undo'); + + +def xournalRunTestInSubfolder(xoj, subfolder): + path = os.path.realpath(__file__) + path = os.path.dirname(path) + folder = os.path.join(path, subfolder) + + print 'Running scripts in %s' % folder + + for name in os.listdir(folder): + dirfile = os.path.join(folder, name) + + if os.path.isdir(dirfile) and not name.startswith('.') and os.path.exists(os.path.join(dirfile, 'Test.py')): + print 'Run test in %s' % dirfile + print 'Debug: import %s from %s' % (name, subfolder + '.' + name + '.Test') + __import__(subfolder + '.' + name + '.Test', fromlist = name) + cls = globals()[name] + inst = cls() + inst. + + + +# print xoj.openFile('/home/andreas/tmp/Notiz-10-03-2011-16-57.xoj') + +""" xoj.mousePressed(10, 10) + xoj.mouseMoved(20, 20) + xoj.mouseReleased() + + ud = ColorUndoAction() +""" - print xoj.openFile('/home/andreas/tmp/Notiz-10-03-2011-16-57.xoj') diff --git a/testing/undo/ColorUndoAction/Test.py b/testing/undo/ColorUndoAction/Test.py new file mode 100644 index 00000000..be9216d9 --- /dev/null +++ b/testing/undo/ColorUndoAction/Test.py @@ -0,0 +1,16 @@ +# Xournal++ +# +# Testclass for Undo / Redohandler +# +# @author Xournal Team +# http://xournal.sf.net +# +# @license GPL + +from undo.UndoRedoTest import UndoRedoTest + +class ColorUndoAction(UndoRedoTest): + def __init__(self): + UndoRedoTest.__init__(self) + print 'ColorUndoAction' + diff --git a/testing/undo/ColorUndoAction/Test.pyc b/testing/undo/ColorUndoAction/Test.pyc new file mode 100644 index 00000000..cee0add7 Binary files /dev/null and b/testing/undo/ColorUndoAction/Test.pyc differ diff --git a/testing/undo/ColorUndoAction/__init__.py b/testing/undo/ColorUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/ColorUndoAction/__init__.pyc b/testing/undo/ColorUndoAction/__init__.pyc new file mode 100644 index 00000000..1754fee0 Binary files /dev/null and b/testing/undo/ColorUndoAction/__init__.pyc differ diff --git a/testing/undo/DeleteUndoAction/__init__.py b/testing/undo/DeleteUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/EraseUndoAction/__init__.py b/testing/undo/EraseUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/FontUndoAction/__init__.py b/testing/undo/FontUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/InsertDeletePageUndoAction/__init__.py b/testing/undo/InsertDeletePageUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/InsertLayerUndoAction/__init__.py b/testing/undo/InsertLayerUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/InsertUndoAction/__init__.py b/testing/undo/InsertUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/MoveUndoAction/__init__.py b/testing/undo/MoveUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/PageBackgroundChangedUndoAction/__init__.py b/testing/undo/PageBackgroundChangedUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/PageLayerPosEntry/__init__.py b/testing/undo/PageLayerPosEntry/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/RecognizerUndoAction/__init__.py b/testing/undo/RecognizerUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/RemoveLayerUndoAction/__init__.py b/testing/undo/RemoveLayerUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/ScaleUndoAction/__init__.py b/testing/undo/ScaleUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/SizeUndoAction/__init__.py b/testing/undo/SizeUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/TextUndoAction/__init__.py b/testing/undo/TextUndoAction/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/UndoRedoTest.py b/testing/undo/UndoRedoTest.py new file mode 100644 index 00000000..6a07d3d8 --- /dev/null +++ b/testing/undo/UndoRedoTest.py @@ -0,0 +1,17 @@ +# Xournal++ +# +# Textclass for Undo / Redohandler +# +# @author Xournal Team +# http://xournal.sf.net +# +# @license GPL + + +class UndoRedoTest: + def __init__(self): + print 'UndoRedoTest\n' + + def runTest(self): + print 'run test called!\n' + diff --git a/testing/undo/UndoRedoTest.pyc b/testing/undo/UndoRedoTest.pyc new file mode 100644 index 00000000..28be8346 Binary files /dev/null and b/testing/undo/UndoRedoTest.pyc differ diff --git a/testing/undo/__init__.py b/testing/undo/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testing/undo/__init__.pyc b/testing/undo/__init__.pyc new file mode 100644 index 00000000..6ea628a2 Binary files /dev/null and b/testing/undo/__init__.pyc differ