##// END OF EJS Templates
updated old license information and current date...
florianlink -
r133:26c5443b8486
parent child
Show More
@@ -1,43 +1,43
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file CustomObjects.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-4
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "CustomObjects.h"
43 43
@@ -1,149 +1,149
1 1 #ifndef _PYCUSTOMOBJECTS_H
2 2 #define _PYCUSTOMOBJECTS_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file CustomObjects.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-4
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtCppWrapperFactory.h"
47 47 #include <QObject>
48 48
49 49
50 50 // declare our own custom object
51 51 class CustomObject {
52 52 public:
53 53 CustomObject() {}
54 54 CustomObject(const QString& first, const QString& last) { _firstName = first; _lastName = last; }
55 55
56 56 QString _firstName;
57 57 QString _lastName;
58 58
59 59 };
60 60
61 61
62 62 // add a decorator that allows to access the CustomObject from PythonQt
63 63 class CustomObjectWrapper : public QObject {
64 64
65 65 Q_OBJECT
66 66
67 67 public slots:
68 68 // add a constructor
69 69 CustomObject* new_CustomObject(const QString& first, const QString& last) { return new CustomObject(first, last); }
70 70
71 71 // add a destructor
72 72 void delete_CustomObject(CustomObject* o) { delete o; }
73 73
74 74 // add access methods
75 75 QString firstName(CustomObject* o) { return o->_firstName; }
76 76
77 77 QString lastName(CustomObject* o) { return o->_lastName; }
78 78
79 79 void setFirstName(CustomObject* o, const QString& name) { o->_firstName = name; }
80 80
81 81 void setLastName(CustomObject* o, const QString& name) { o->_lastName = name; }
82 82
83 83 };
84 84
85 85
86 86 //------------------------------------------------------------------------------------------------
87 87 // alternative: we create a wrapper factory, which creates a wrapper object for each CPP instance:
88 88 //------------------------------------------------------------------------------------------------
89 89
90 90 // declare our own custom object
91 91 class CustomObject2 {
92 92 public:
93 93 CustomObject2() {}
94 94 CustomObject2(const QString& first, const QString& last) { _firstName = first; _lastName = last; }
95 95
96 96 QString _firstName;
97 97 QString _lastName;
98 98
99 99 };
100 100
101 101
102 102 // add a decorator that allows to access the CustomObject from PythonQt
103 103 class CustomObject2Wrapper : public QObject {
104 104
105 105 Q_OBJECT
106 106
107 107 public:
108 108 CustomObject2Wrapper(CustomObject2* obj) { _ptr = obj; }
109 109
110 110 public slots:
111 111 // add access methods
112 112 QString firstName() { return _ptr->_firstName; }
113 113
114 114 QString lastName() { return _ptr->_lastName; }
115 115
116 116 void setFirstName(const QString& name) { _ptr->_firstName = name; }
117 117
118 118 void setLastName(const QString& name) { _ptr->_lastName = name; }
119 119
120 120 private:
121 121 CustomObject2* _ptr;
122 122 };
123 123
124 124 // additional constructor/destructor for CustomObject2 (optional)
125 125 class CustomObject2Constructor : public QObject {
126 126
127 127 Q_OBJECT
128 128
129 129 public slots:
130 130 // add a constructor
131 131 CustomObject2* new_CustomObject2(const QString& first, const QString& last) { return new CustomObject2(first, last); }
132 132
133 133 // add a destructor
134 134 void delete_CustomObject2(CustomObject2* o) { delete o; }
135 135 };
136 136
137 137 // a factory that can create wrappers for CustomObject2
138 138 class CustomFactory : public PythonQtCppWrapperFactory
139 139 {
140 140 public:
141 141 virtual QObject* create(const QByteArray& name, void *ptr) {
142 142 if (name == "CustomObject2") {
143 143 return new CustomObject2Wrapper((CustomObject2*)ptr);
144 144 }
145 145 return NULL;
146 146 }
147 147 };
148 148
149 149 #endif
@@ -1,84 +1,84
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyGuiExample.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "gui/PythonQtScriptingConsole.h"
44 44 #include "CustomObjects.h"
45 45
46 46 #include <QApplication>
47 47
48 48 int main( int argc, char **argv )
49 49 {
50 50 QApplication qapp(argc, argv);
51 51
52 52 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
53 53
54 54 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
55 55 PythonQtScriptingConsole console(NULL, mainContext);
56 56
57 57 // -----------------------------------------------------------------
58 58 // Alternative 1: make CustomObject known and use decorators for wrapping:
59 59 // -----------------------------------------------------------------
60 60
61 61 // register the new object as a known classname and add it's wrapper object
62 62 PythonQt::self()->registerCPPClass("CustomObject", "","", PythonQtCreateObject<CustomObjectWrapper>);
63 63
64 64 // -----------------------------------------------------------------
65 65 // Alternative 2: make CustomObject2 known and use a wrapper factory for wrapping:
66 66 // -----------------------------------------------------------------
67 67
68 68 // add a factory that can handle pointers to CustomObject2
69 69 PythonQt::self()->addWrapperFactory(new CustomFactory());
70 70
71 71 // the following is optional and only needed if you want a constructor:
72 72 // register the new object as a known classname
73 73 PythonQt::self()->registerCPPClass("CustomObject2");
74 74 // add a constructor for CustomObject2
75 75 PythonQt::self()->addClassDecorators(new CustomObject2Constructor());
76 76
77 77 mainContext.evalFile(":example.py");
78 78
79 79 console.appendCommandPrompt();
80 80 console.show();
81 81
82 82 return qapp.exec();
83 83 }
84 84
@@ -1,43 +1,43
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file CustomObject.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-4
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "CustomObject.h"
43 43
@@ -1,85 +1,85
1 1 #ifndef _PYCUSTOMOBJECT_H
2 2 #define _PYCUSTOMOBJECT_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file CustomObject.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-4
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include <QObject>
47 47
48 48
49 49 // declare our own copyable custom object
50 50 class CustomObject {
51 51 public:
52 52 CustomObject() {}
53 53 CustomObject(const QString& first, const QString& last) { _firstName = first; _lastName = last; }
54 54
55 55 QString _firstName;
56 56 QString _lastName;
57 57
58 58 };
59 59
60 60 // register it to the meta type system
61 61 Q_DECLARE_METATYPE(CustomObject)
62 62
63 63 // add a wrapper that allows to access the CustomObject from PythonQt
64 64 class CustomObjectWrapper : public QObject {
65 65
66 66 Q_OBJECT
67 67
68 68 public slots:
69 69 // add a constructor
70 70 CustomObject* new_CustomObject(const QString& first, const QString& last) { return new CustomObject(first, last); }
71 71
72 72 // add access methods
73 73
74 74 QString firstName(CustomObject* o) { return o->_firstName; }
75 75
76 76 QString lastName(CustomObject* o) { return o->_lastName; }
77 77
78 78 void setFirstName(CustomObject* o, const QString& name) { o->_firstName = name; }
79 79
80 80 void setLastName(CustomObject* o, const QString& name) { o->_lastName = name; }
81 81
82 82 };
83 83
84 84
85 85 #endif
@@ -1,69 +1,69
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyGuiExample.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "gui/PythonQtScriptingConsole.h"
44 44 #include "CustomObject.h"
45 45
46 46 #include <QApplication>
47 47
48 48 int main( int argc, char **argv )
49 49 {
50 50 QApplication qapp(argc, argv);
51 51
52 52 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
53 53
54 54 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
55 55 PythonQtScriptingConsole console(NULL, mainContext);
56 56
57 57 // register the type with QMetaType
58 58 qRegisterMetaType<CustomObject>("CustomObject");
59 59 // add a wrapper object for the new variant type
60 60 PythonQt::self()->registerCPPClass("CustomObject","","", PythonQtCreateObject<CustomObjectWrapper>);
61 61
62 62 mainContext.evalFile(":example.py");
63 63
64 64 console.appendCommandPrompt();
65 65 console.show();
66 66
67 67 return qapp.exec();
68 68 }
69 69
@@ -1,43 +1,43
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyExampleObject.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-10
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PyExampleDecorators.h"
43 43
@@ -1,95 +1,95
1 1 #ifndef _PYEXAMPLEDECORATORS_H
2 2 #define _PYEXAMPLEDECORATORS_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PyExampleDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-4
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include <QDebug>
47 47 #include <QObject>
48 48 #include <QPushButton>
49 49
50 50 // an example CPP object
51 51 class YourCPPObject {
52 52 public:
53 53 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
54 54
55 55 float doSomething(int arg1) { return arg1*a*b; };
56 56
57 57 private:
58 58
59 59 int a;
60 60 float b;
61 61 };
62 62
63 63 // an example decorator
64 64 class PyExampleDecorators : public QObject
65 65 {
66 66 Q_OBJECT
67 67
68 68 public slots:
69 69 // add a constructor to QSize variant that takes a QPoint
70 70 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
71 71
72 72 // add a constructor for QPushButton that takes a text and a parent widget
73 73 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
74 74
75 75 // add a constructor for a CPP object
76 76 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
77 77
78 78 // add a destructor for a CPP object
79 79 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
80 80
81 81 // add a static method to QWidget
82 82 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
83 83
84 84 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
85 85 void move(QWidget* w, const QPoint& p) { w->move(p); }
86 86
87 87 // add an additional slot to QWidget, overloading the above move method
88 88 void move(QWidget* w, int x, int y) { w->move(x,y); }
89 89
90 90 // add a method to your own CPP object
91 91 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
92 92 };
93 93
94 94
95 95 #endif
@@ -1,68 +1,68
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyGuiExample.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "gui/PythonQtScriptingConsole.h"
44 44 #include "PyExampleDecorators.h"
45 45
46 46 #include <QApplication>
47 47
48 48 int main( int argc, char **argv )
49 49 {
50 50 QApplication qapp(argc, argv);
51 51
52 52 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
53 53
54 54 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
55 55 PythonQtScriptingConsole console(NULL, mainContext);
56 56
57 57 PythonQt::self()->addDecorators(new PyExampleDecorators());
58 58 PythonQt::self()->registerClass(&QPushButton::staticMetaObject);
59 59 PythonQt::self()->registerCPPClass("YourCPPObject");
60 60
61 61 mainContext.evalFile(":example.py");
62 62
63 63 console.appendCommandPrompt();
64 64 console.show();
65 65
66 66 return qapp.exec();
67 67 }
68 68
@@ -1,101 +1,101
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtTests.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include <QApplication>
44 44 #include <QTextBrowser>
45 45 #include <QLayout>
46 46 #include <QGroupBox>
47 47 #include <QPushButton>
48 48 #include <QLineEdit>
49 49
50 50 int main( int argc, char **argv )
51 51 {
52 52 QApplication qapp(argc, argv);
53 53
54 54 // init PythonQt and Python
55 55 PythonQt::init();
56 56
57 57 // get the __main__ python module
58 58 PythonQtObjectPtr mainModule = PythonQt::self()->getMainModule();
59 59
60 60 // evaluate a simple python script and receive the result a qvariant:
61 61 QVariant result = mainModule.evalScript("19*2+4", Py_eval_input);
62 62
63 63 // Create object from python, hold onto reference in C++:
64 64 PythonQtObjectPtr tag = mainModule.evalScript("EyeD3Tagger()\n", Py_eval_input);
65 65 Q_ASSERT(!tag.isNull());
66 66
67 67 // call python methods from C++
68 68 tag.call("setFileName", QVariantList() << "t.mp3");
69 69 QVariant fn = tag.call("fileName", QVariantList());
70 70 Q_ASSERT(fn.toString() == QString("t.mp3"));
71 71
72 72 // create a small Qt GUI
73 73 QVBoxLayout* vbox = new QVBoxLayout;
74 74 QGroupBox* box = new QGroupBox;
75 75 QTextBrowser* browser = new QTextBrowser(box);
76 76 QLineEdit* edit = new QLineEdit(box);
77 77 QPushButton* button = new QPushButton(box);
78 78 button->setObjectName("button1");
79 79 edit->setObjectName("edit");
80 80 browser->setObjectName("browser");
81 81 vbox->addWidget(browser);
82 82 vbox->addWidget(edit);
83 83 vbox->addWidget(button);
84 84 box->setLayout(vbox);
85 85
86 86 // make the groupbox to the python under the name "box"
87 87 mainModule.addObject("box", box);
88 88
89 89 // evaluate the python script which is defined in the resources
90 90 mainModule.evalFile(":GettingStarted.py");
91 91
92 92 // define a python method that appends the passed text to the browser
93 93 mainModule.evalScript("def appendText(text):\n box.browser.append(text)");
94 94 // shows how to call the method with a text that will be append to the browser
95 95 mainModule.call("appendText", QVariantList() << "The ultimate answer is ");
96 96
97 97
98 98
99 99 return qapp.exec();
100 100 }
101 101
@@ -1,68 +1,68
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyGuiExample.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQt_QtAll.h"
44 44 #include "gui/PythonQtScriptingConsole.h"
45 45
46 46 #include <QApplication>
47 47 #include <QWidget>
48 48 #include <QMainWindow>
49 49 #include <QPushButton>
50 50 #include <QLayout>
51 51
52 52
53 53 int main( int argc, char **argv )
54 54 {
55 55 QApplication qapp(argc, argv);
56 56
57 57 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
58 58 PythonQt_QtAll::init();
59 59
60 60 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
61 61 PythonQtScriptingConsole console(NULL, mainContext);
62 62
63 63 mainContext.evalFile(":example.py");
64 64
65 65 console.show();
66 66 return qapp.exec();
67 67 }
68 68
@@ -1,90 +1,90
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyGuiExample.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQt_QtAll.h"
44 44 #include "gui/PythonQtScriptingConsole.h"
45 45
46 46 #include <QApplication>
47 47 #include <QDir>
48 48 #include <QMessageBox>
49 49
50 50
51 51 int main( int argc, char **argv )
52 52 {
53 53 QApplication qapp(argc, argv);
54 54
55 55 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
56 56 PythonQt_QtAll::init();
57 57
58 58 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
59 59
60 60 bool showConsole = false;
61 61 QStringList files;
62 62 for (int i = 1; i < argc; i++) {
63 63 QString arg = argv[i];
64 64 QString argLower = arg.toLower();
65 65 if (argLower == "-console" || argLower == "-c") {
66 66 showConsole = true;
67 67 } else {
68 68 QString file = arg;
69 69 QFileInfo info(file);
70 70 if (info.exists()) {
71 71 files << info.absoluteFilePath();
72 72 // add the file's absolute path for local importing
73 73 PythonQt::self()->addSysPath(info.absolutePath());
74 74 } else {
75 75 QMessageBox::warning(NULL, "PyLauncher", QString("File does not exist: %1").arg(file));
76 76 }
77 77 }
78 78 }
79 79 PythonQtScriptingConsole console(NULL, mainContext);
80 80
81 81 foreach(QString file, files) {
82 82 mainContext.evalFile(file);
83 83 }
84 84 if (showConsole || console.hadError()) {
85 85 console.show();
86 86 }
87 87
88 88 return qapp.exec();
89 89 }
90 90
@@ -1,87 +1,87
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PyExampleObject.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-10
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PyExampleObject.h"
43 43 #include <QMessageBox>
44 44 #include <QDir>
45 45
46 46 PyExampleObject::PyExampleObject():QObject(NULL)
47 47 {
48 48 }
49 49
50 50 PyObject* PyExampleObject::getMainModule() {
51 51 return PythonQt::self()->getMainModule();
52 52 }
53 53
54 54 void PyExampleObject::showInformation(const QString& str)
55 55 {
56 56 QMessageBox::information ( NULL, "Test", str);
57 57 }
58 58
59 59 QStringList PyExampleObject::readDirectory(const QString& dir)
60 60 {
61 61 QDir d(dir);
62 62 return d.entryList();
63 63 }
64 64
65 65 QMainWindow* PyExampleObject::createWindow()
66 66 {
67 67 QMainWindow* m = new QMainWindow();
68 68 QPushButton* b = new QPushButton(m);
69 69 b->setObjectName("button1");
70 70
71 71 m->show();
72 72 return m;
73 73 }
74 74
75 75 QObject* PyExampleObject::findChild(QObject* o, const QString& name)
76 76 {
77 77 return qFindChild<QObject*>(o, name);
78 78 }
79 79
80 80 QVariantMap PyExampleObject::testMap()
81 81 {
82 82 QVariantMap m;
83 83 m.insert("a", QStringList() << "test1" << "test2");
84 84 m.insert("b", 12);
85 85 m.insert("c", 12.);
86 86 return m;
87 87 }
@@ -1,79 +1,79
1 1 #ifndef _PYEXAMPLEOBJECT_H
2 2 #define _PYEXAMPLEOBJECT_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PyExampleObject.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46
47 47 #include <QObject>
48 48 #include <QStringList>
49 49 #include <QMainWindow>
50 50 #include <QPushButton>
51 51 #include <QVariant>
52 52 #include <QLayout>
53 53
54 54
55 55 class PyExampleObject : public QObject {
56 56
57 57 Q_OBJECT
58 58
59 59 public:
60 60 PyExampleObject();
61 61
62 62 public slots:
63 63
64 64 //! example for passing a PyObject directly from Qt to Python (without extra mashalling)
65 65 PyObject* getMainModule();
66 66
67 67 void showInformation(const QString& str);
68 68
69 69 QStringList readDirectory(const QString& dir);
70 70
71 71 QMainWindow* createWindow();
72 72
73 73 QObject* findChild(QObject* o, const QString& name);
74 74
75 75 QVariantMap testMap();
76 76
77 77 };
78 78
79 79 #endif
@@ -1,74 +1,74
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtTests.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQt_QtAll.h"
44 44
45 45 #include "PyExampleObject.h"
46 46 #include "gui/PythonQtScriptingConsole.h"
47 47
48 48 #include <QApplication>
49 49 #include <QWidget>
50 50 #include <QMainWindow>
51 51 #include <QPushButton>
52 52 #include <QLayout>
53 53
54 54
55 55 int main( int argc, char **argv )
56 56 {
57 57 QApplication qapp(argc, argv);
58 58
59 59 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
60 60 PythonQt_QtAll::init();
61 61
62 62 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
63 63 PythonQtScriptingConsole console(NULL, mainContext);
64 64
65 65 // add a QObject to the namespace of the main python context
66 66 PyExampleObject example;
67 67 mainContext.addObject("example", &example);
68 68
69 69 mainContext.evalFile(":example.py");
70 70
71 71 console.show();
72 72 return qapp.exec();
73 73 }
74 74
@@ -1,67 +1,67
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 #include "PythonQt_QtAll.h"
34 34
35 35 #include "PythonQt.h"
36 36
37 37 void PythonQt_init_QtGui(PyObject*);
38 38 void PythonQt_init_QtSvg(PyObject*);
39 39 void PythonQt_init_QtSql(PyObject*);
40 40 void PythonQt_init_QtNetwork(PyObject*);
41 41 void PythonQt_init_QtCore(PyObject*);
42 42 void PythonQt_init_QtWebKit(PyObject*);
43 43 void PythonQt_init_QtOpenGL(PyObject*);
44 44 void PythonQt_init_QtXml(PyObject*);
45 45 void PythonQt_init_QtXmlPatterns(PyObject*);
46 46 void PythonQt_init_QtUiTools(PyObject*);
47 47 void PythonQt_init_QtPhonon(PyObject*);
48 48
49 49 namespace PythonQt_QtAll
50 50 {
51 51 PYTHONQT_QTALL_EXPORT void init() {
52 52 PythonQt_init_QtCore(0);
53 53 PythonQt_init_QtNetwork(0);
54 54 PythonQt_init_QtGui(0);
55 55 PythonQt_init_QtXml(0);
56 56 PythonQt_init_QtSvg(0);
57 57 PythonQt_init_QtSql(0);
58 58 PythonQt_init_QtWebKit(0);
59 59 PythonQt_init_QtOpenGL(0);
60 60 PythonQt_init_QtUiTools(0);
61 61 // Does not compile yet:
62 62 // PythonQt_init_QtXmlPatterns(0);
63 63 // PythonQt_init_QtPhonon(0);
64 64 };
65 65 };
66 66
67 67
@@ -1,52 +1,52
1 1 #ifndef _PYTHONQT_QTALL_H
2 2 #define _PYTHONQT_QTALL_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #ifdef WIN32
37 37 #ifdef PYTHONQT_QTALL_EXPORTS
38 38 #define PYTHONQT_QTALL_EXPORT __declspec(dllexport)
39 39 #else
40 40 #define PYTHONQT_QTALL_EXPORT __declspec(dllimport)
41 41 #endif
42 42 #else
43 43 #define PYTHONQT_QTALL_EXPORT
44 44 #endif
45 45
46 46 namespace PythonQt_QtAll
47 47 {
48 48 //! initialize the Qt binding
49 49 PYTHONQT_QTALL_EXPORT void init();
50 50 };
51 51
52 52 #endif
@@ -1,1220 +1,1220
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt_init_QtGuiBuiltin(PyObject*);
60 60 void PythonQt_init_QtCoreBuiltin(PyObject*);
61 61
62 62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
63 63 {
64 64 if (!_self) {
65 65 _self = new PythonQt(flags, pythonQtModuleName);
66 66
67 67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
68 68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
69 69
70 70 PythonQtRegisterToolClassesTemplateConverter(int);
71 71 PythonQtRegisterToolClassesTemplateConverter(float);
72 72 PythonQtRegisterToolClassesTemplateConverter(double);
73 73 PythonQtRegisterToolClassesTemplateConverter(qint32);
74 74 PythonQtRegisterToolClassesTemplateConverter(quint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(qint64);
76 76 PythonQtRegisterToolClassesTemplateConverter(quint64);
77 77 // TODO: which other POD types should be available for QList etc.
78 78
79 79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
80 80
81 81 PythonQt_init_QtCoreBuiltin(NULL);
82 82 PythonQt_init_QtGuiBuiltin(NULL);
83 83
84 84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
85 85 PythonQtRegisterToolClassesTemplateConverter(QDate);
86 86 PythonQtRegisterToolClassesTemplateConverter(QTime);
87 87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
88 88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
89 89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
90 90 PythonQtRegisterToolClassesTemplateConverter(QRect);
91 91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
92 92 PythonQtRegisterToolClassesTemplateConverter(QSize);
93 93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
94 94 PythonQtRegisterToolClassesTemplateConverter(QLine);
95 95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
96 96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
97 97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
99 99
100 100 PythonQtRegisterToolClassesTemplateConverter(QFont);
101 101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
102 102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
103 103 PythonQtRegisterToolClassesTemplateConverter(QColor);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
105 105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
106 106 PythonQtRegisterToolClassesTemplateConverter(QImage);
107 107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
108 108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
109 109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
110 110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
111 111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
112 112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
113 113 PythonQtRegisterToolClassesTemplateConverter(QPen);
114 114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
115 115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
116 116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
117 117
118 118
119 119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
120 120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
121 121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
122 122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
123 123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
124 124 for (unsigned int i = 0;i<16; i++) {
125 125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
126 126 if (obj) {
127 127 PyModule_AddObject(pack, names[i], obj);
128 128 Py_INCREF(obj);
129 129 PyModule_AddObject(pack2, names[i], obj);
130 130 } else {
131 131 std::cerr << "method not found " << names[i];
132 132 }
133 133 }
134 134 }
135 135 }
136 136
137 137 void PythonQt::cleanup()
138 138 {
139 139 if (_self) {
140 140 delete _self;
141 141 _self = NULL;
142 142 }
143 143 }
144 144
145 145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
146 146 {
147 147 _p = new PythonQtPrivate;
148 148 _p->_initFlags = flags;
149 149
150 150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
151 151
152 152 Py_SetProgramName("PythonQt");
153 153 if (flags & IgnoreSiteModule) {
154 154 // this prevents the automatic importing of Python site files
155 155 Py_NoSiteFlag = 1;
156 156 }
157 157 Py_Initialize();
158 158
159 159 // add our own python object types for qt object slots
160 160 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
161 161 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
162 162 }
163 163 Py_INCREF(&PythonQtSlotFunction_Type);
164 164
165 165 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
166 166 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
167 167 // add our own python object types for classes
168 168 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtClassWrapper_Type);
172 172
173 173 // add our own python object types for CPP instances
174 174 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
175 175 PythonQt::handleError();
176 176 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
177 177 }
178 178 Py_INCREF(&PythonQtInstanceWrapper_Type);
179 179
180 180 // add our own python object types for redirection of stdout
181 181 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
182 182 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
183 183 }
184 184 Py_INCREF(&PythonQtStdOutRedirectType);
185 185
186 186 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
187 187
188 188 _p->setupSharedLibrarySuffixes();
189 189
190 190 }
191 191
192 192 PythonQt::~PythonQt() {
193 193 delete _p;
194 194 _p = NULL;
195 195 }
196 196
197 197 PythonQtPrivate::~PythonQtPrivate() {
198 198 delete _defaultImporter;
199 199 _defaultImporter = NULL;
200 200
201 201 {
202 202 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
203 203 while (i.hasNext()) {
204 204 delete i.next().value();
205 205 }
206 206 }
207 207 PythonQtConv::global_valueStorage.clear();
208 208 PythonQtConv::global_ptrStorage.clear();
209 209 PythonQtConv::global_variantStorage.clear();
210 210
211 211 PythonQtMethodInfo::cleanupCachedMethodInfos();
212 212 }
213 213
214 214 PythonQtImportFileInterface* PythonQt::importInterface()
215 215 {
216 216 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
217 217 }
218 218
219 219 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
220 220 {
221 221 if (_self->_p->_noLongerWrappedCB) {
222 222 (*_self->_p->_noLongerWrappedCB)(o);
223 223 };
224 224 }
225 225
226 226 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
227 227 {
228 228 _p->registerClass(metaobject, package, wrapperCreator, shell);
229 229 }
230 230
231 231 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
232 232 {
233 233 // we register all classes in the hierarchy
234 234 const QMetaObject* m = metaobject;
235 235 bool first = true;
236 236 while (m) {
237 237 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
238 238 if (!info->pythonQtClassWrapper()) {
239 239 info->setTypeSlots(typeSlots);
240 240 info->setupQObject(m);
241 241 createPythonQtClassWrapper(info, package, module);
242 242 if (m->superClass()) {
243 243 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
244 244 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
245 245 }
246 246 }
247 247 if (first) {
248 248 first = false;
249 249 if (wrapperCreator) {
250 250 info->setDecoratorProvider(wrapperCreator);
251 251 }
252 252 if (shell) {
253 253 info->setShellSetInstanceWrapperCB(shell);
254 254 }
255 255 }
256 256 m = m->superClass();
257 257 }
258 258 }
259 259
260 260 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
261 261 {
262 262 PyObject* pack = module?module:packageByName(package);
263 263 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
264 264 PyModule_AddObject(pack, info->className(), pyobj);
265 265 if (!module && package && strncmp(package,"Qt",2)==0) {
266 266 // since PyModule_AddObject steals the reference, we need a incref once more...
267 267 Py_INCREF(pyobj);
268 268 // put all qt objects into Qt as well
269 269 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
270 270 }
271 271 info->setPythonQtClassWrapper(pyobj);
272 272 }
273 273
274 274 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
275 275 {
276 276 if (!obj) {
277 277 Py_INCREF(Py_None);
278 278 return Py_None;
279 279 }
280 280 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
281 281 if (!wrap) {
282 282 // smuggling it in...
283 283 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
284 284 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
285 285 registerClass(obj->metaObject());
286 286 classInfo = _knownClassInfos.value(obj->metaObject()->className());
287 287 }
288 288 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
289 289 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
290 290 } else {
291 291 Py_INCREF(wrap);
292 292 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
293 293 }
294 294 return (PyObject*)wrap;
295 295 }
296 296
297 297 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
298 298 {
299 299 if (!ptr) {
300 300 Py_INCREF(Py_None);
301 301 return Py_None;
302 302 }
303 303
304 304 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
305 305 if (!wrap) {
306 306 PythonQtClassInfo* info = _knownClassInfos.value(name);
307 307 if (!info) {
308 308 // maybe it is a PyObject, which we can return directly
309 309 if (name == "PyObject") {
310 310 PyObject* p = (PyObject*)ptr;
311 311 Py_INCREF(p);
312 312 return p;
313 313 }
314 314
315 315 // we do not know the metaobject yet, but we might know it by it's name:
316 316 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
317 317 // yes, we know it, so we can convert to QObject
318 318 QObject* qptr = (QObject*)ptr;
319 319 registerClass(qptr->metaObject());
320 320 info = _knownClassInfos.value(qptr->metaObject()->className());
321 321 }
322 322 }
323 323 if (info && info->isQObject()) {
324 324 QObject* qptr = (QObject*)ptr;
325 325 // if the object is a derived object, we want to switch the class info to the one of the derived class:
326 326 if (name!=(qptr->metaObject()->className())) {
327 327 registerClass(qptr->metaObject());
328 328 info = _knownClassInfos.value(qptr->metaObject()->className());
329 329 }
330 330 wrap = createNewPythonQtInstanceWrapper(qptr, info);
331 331 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
332 332 return (PyObject*)wrap;
333 333 }
334 334
335 335 // not a known QObject, so try our wrapper factory:
336 336 QObject* wrapper = NULL;
337 337 for (int i=0; i<_cppWrapperFactories.size(); i++) {
338 338 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
339 339 if (wrapper) {
340 340 break;
341 341 }
342 342 }
343 343
344 344 if (info) {
345 345 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
346 346 ptr = info->castDownIfPossible(ptr, &info);
347 347 }
348 348
349 349 if (!info || info->pythonQtClassWrapper()==NULL) {
350 350 // still unknown, register as CPP class
351 351 registerCPPClass(name.constData());
352 352 info = _knownClassInfos.value(name);
353 353 }
354 354 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
355 355 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
356 356 info->setMetaObject(wrapper->metaObject());
357 357 }
358 358 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
359 359 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
360 360 } else {
361 361 Py_INCREF(wrap);
362 362 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
363 363 }
364 364 return (PyObject*)wrap;
365 365 }
366 366
367 367 PyObject* PythonQtPrivate::dummyTuple() {
368 368 static PyObject* dummyTuple = NULL;
369 369 if (dummyTuple==NULL) {
370 370 dummyTuple = PyTuple_New(1);
371 371 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
372 372 }
373 373 return dummyTuple;
374 374 }
375 375
376 376
377 377 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
378 378 // call the associated class type to create a new instance...
379 379 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
380 380
381 381 result->setQObject(obj);
382 382 result->_wrappedPtr = wrappedPtr;
383 383 result->_ownedByPythonQt = false;
384 384 result->_useQMetaTypeDestroy = false;
385 385
386 386 if (wrappedPtr) {
387 387 _wrappedObjects.insert(wrappedPtr, result);
388 388 } else {
389 389 _wrappedObjects.insert(obj, result);
390 390 if (obj->parent()== NULL && _wrappedCB) {
391 391 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
392 392 (*_wrappedCB)(obj);
393 393 }
394 394 }
395 395 return result;
396 396 }
397 397
398 398 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
399 399 PythonQtClassWrapper* result;
400 400
401 401 PyObject* className = PyString_FromString(info->className());
402 402
403 403 PyObject* baseClasses = PyTuple_New(1);
404 404 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
405 405
406 406 PyObject* typeDict = PyDict_New();
407 407 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
408 408 PyDict_SetItemString(typeDict, "__module__", moduleName);
409 409
410 410 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
411 411
412 412 // set the class info so that PythonQtClassWrapper_new can read it
413 413 _currentClassInfoForClassWrapperCreation = info;
414 414 // create the new type object by calling the type
415 415 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
416 416
417 417 Py_DECREF(baseClasses);
418 418 Py_DECREF(typeDict);
419 419 Py_DECREF(args);
420 420 Py_DECREF(className);
421 421
422 422 return result;
423 423 }
424 424
425 425 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
426 426 {
427 427 PyObject* args = Py_BuildValue("(i)", enumValue);
428 428 PyObject* result = PyObject_Call(enumType, args, NULL);
429 429 Py_DECREF(args);
430 430 return result;
431 431 }
432 432
433 433 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
434 434 PyObject* result;
435 435
436 436 PyObject* className = PyString_FromString(enumName);
437 437
438 438 PyObject* baseClasses = PyTuple_New(1);
439 439 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
440 440
441 441 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
442 442 PyObject* typeDict = PyDict_New();
443 443 PyDict_SetItemString(typeDict, "__module__", module);
444 444
445 445 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
446 446
447 447 // create the new int derived type object by calling the core type
448 448 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
449 449
450 450 Py_DECREF(baseClasses);
451 451 Py_DECREF(typeDict);
452 452 Py_DECREF(args);
453 453 Py_DECREF(className);
454 454
455 455 return result;
456 456 }
457 457
458 458 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
459 459 {
460 460 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
461 461 if (!r) {
462 462 r = new PythonQtSignalReceiver(obj);
463 463 _p->_signalReceivers.insert(obj, r);
464 464 }
465 465 return r;
466 466 }
467 467
468 468 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
469 469 {
470 470 bool flag = false;
471 471 PythonQtObjectPtr callable = lookupCallable(module, objectname);
472 472 if (callable) {
473 473 PythonQtSignalReceiver* r = getSignalReceiver(obj);
474 474 flag = r->addSignalHandler(signal, callable);
475 475 if (!flag) {
476 476 // signal not found
477 477 }
478 478 } else {
479 479 // callable not found
480 480 }
481 481 return flag;
482 482 }
483 483
484 484 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
485 485 {
486 486 bool flag = false;
487 487 PythonQtSignalReceiver* r = getSignalReceiver(obj);
488 488 if (r) {
489 489 flag = r->addSignalHandler(signal, receiver);
490 490 }
491 491 return flag;
492 492 }
493 493
494 494 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
495 495 {
496 496 bool flag = false;
497 497 PythonQtObjectPtr callable = lookupCallable(module, objectname);
498 498 if (callable) {
499 499 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
500 500 if (r) {
501 501 flag = r->removeSignalHandler(signal, callable);
502 502 }
503 503 } else {
504 504 // callable not found
505 505 }
506 506 return flag;
507 507 }
508 508
509 509 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
510 510 {
511 511 bool flag = false;
512 512 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
513 513 if (r) {
514 514 flag = r->removeSignalHandler(signal, receiver);
515 515 }
516 516 return flag;
517 517 }
518 518
519 519 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
520 520 {
521 521 PythonQtObjectPtr p = lookupObject(module, name);
522 522 if (p) {
523 523 if (PyCallable_Check(p)) {
524 524 return p;
525 525 }
526 526 }
527 527 PyErr_Clear();
528 528 return NULL;
529 529 }
530 530
531 531 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
532 532 {
533 533 QStringList l = name.split('.');
534 534 PythonQtObjectPtr p = module;
535 535 PythonQtObjectPtr prev;
536 536 QString s;
537 537 QByteArray b;
538 538 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
539 539 prev = p;
540 540 b = (*i).toLatin1();
541 541 if (PyDict_Check(p)) {
542 542 p = PyDict_GetItemString(p, b.data());
543 543 } else {
544 544 p.setNewRef(PyObject_GetAttrString(p, b.data()));
545 545 }
546 546 }
547 547 PyErr_Clear();
548 548 return p;
549 549 }
550 550
551 551 PythonQtObjectPtr PythonQt::getMainModule() {
552 552 //both borrowed
553 553 PythonQtObjectPtr dict = PyImport_GetModuleDict();
554 554 return PyDict_GetItemString(dict, "__main__");
555 555 }
556 556
557 557 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
558 558 QVariant result;
559 559 if (pycode) {
560 560 PyObject* dict = NULL;
561 561 if (PyModule_Check(object)) {
562 562 dict = PyModule_GetDict(object);
563 563 } else if (PyDict_Check(object)) {
564 564 dict = object;
565 565 }
566 566 PyObject* r = NULL;
567 567 if (dict) {
568 568 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
569 569 }
570 570 if (r) {
571 571 result = PythonQtConv::PyObjToQVariant(r);
572 572 Py_DECREF(r);
573 573 } else {
574 574 handleError();
575 575 }
576 576 } else {
577 577 handleError();
578 578 }
579 579 return result;
580 580 }
581 581
582 582 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
583 583 {
584 584 QVariant result;
585 585 PythonQtObjectPtr p;
586 586 PyObject* dict = NULL;
587 587 if (PyModule_Check(object)) {
588 588 dict = PyModule_GetDict(object);
589 589 } else if (PyDict_Check(object)) {
590 590 dict = object;
591 591 }
592 592 if (dict) {
593 593 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
594 594 }
595 595 if (p) {
596 596 result = PythonQtConv::PyObjToQVariant(p);
597 597 } else {
598 598 handleError();
599 599 }
600 600 return result;
601 601 }
602 602
603 603 void PythonQt::evalFile(PyObject* module, const QString& filename)
604 604 {
605 605 PythonQtObjectPtr code = parseFile(filename);
606 606 if (code) {
607 607 evalCode(module, code);
608 608 } else {
609 609 handleError();
610 610 }
611 611 }
612 612
613 613 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
614 614 {
615 615 PythonQtObjectPtr p;
616 616 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
617 617 if (!p) {
618 618 handleError();
619 619 }
620 620 return p;
621 621 }
622 622
623 623 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
624 624 {
625 625 PythonQtObjectPtr code = parseFile(filename);
626 626 PythonQtObjectPtr module = _p->createModule(name, code);
627 627 return module;
628 628 }
629 629
630 630 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
631 631 {
632 632 PyErr_Clear();
633 633 QString scriptCode = script;
634 634 if (scriptCode.isEmpty()) {
635 635 // we always need at least a linefeed
636 636 scriptCode = "\n";
637 637 }
638 638 PythonQtObjectPtr pycode;
639 639 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
640 640 PythonQtObjectPtr module = _p->createModule(name, pycode);
641 641 return module;
642 642 }
643 643
644 644 PythonQtObjectPtr PythonQt::createUniqueModule()
645 645 {
646 646 static QString pyQtStr("PythonQt_module");
647 647 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
648 648 return createModuleFromScript(moduleName);
649 649 }
650 650
651 651 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
652 652 {
653 653 if (PyModule_Check(object)) {
654 654 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
655 655 } else if (PyDict_Check(object)) {
656 656 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
657 657 } else {
658 658 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
659 659 }
660 660 }
661 661
662 662 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
663 663 {
664 664 if (PyModule_Check(object)) {
665 665 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
666 666 } else if (PyDict_Check(object)) {
667 667 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
668 668 } else {
669 669 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
670 670 }
671 671 }
672 672
673 673 void PythonQt::removeVariable(PyObject* object, const QString& name)
674 674 {
675 675 if (PyDict_Check(object)) {
676 676 PyDict_DelItemString(object, name.toLatin1().data());
677 677 } else {
678 678 PyObject_DelAttrString(object, name.toLatin1().data());
679 679 }
680 680 }
681 681
682 682 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
683 683 {
684 684 QVariant result;
685 685 PythonQtObjectPtr obj = lookupObject(object, objectname);
686 686 if (obj) {
687 687 result = PythonQtConv::PyObjToQVariant(obj);
688 688 }
689 689 return result;
690 690 }
691 691
692 692 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
693 693 {
694 694 QStringList results;
695 695
696 696 PythonQtObjectPtr object;
697 697 if (objectname.isEmpty()) {
698 698 object = module;
699 699 } else {
700 700 object = lookupObject(module, objectname);
701 701 if (!object && type == CallOverloads) {
702 702 PyObject* dict = lookupObject(module, "__builtins__");
703 703 if (dict) {
704 704 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
705 705 }
706 706 }
707 707 }
708 708
709 709 if (object) {
710 710 if (type == CallOverloads) {
711 711 if (PythonQtSlotFunction_Check(object)) {
712 712 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
713 713 PythonQtSlotInfo* info = o->m_ml;
714 714
715 715 while (info) {
716 716 results << info->fullSignature();
717 717 info = info->nextInfo();
718 718 }
719 719 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
720 720 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
721 721 PythonQtSlotInfo* info = o->classInfo()->constructors();
722 722
723 723 while (info) {
724 724 results << info->fullSignature();
725 725 info = info->nextInfo();
726 726 }
727 727 } else {
728 728 //TODO: use pydoc!
729 729 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
730 730 if (doc) {
731 731 results << PyString_AsString(doc);
732 732 Py_DECREF(doc);
733 733 }
734 734 }
735 735 } else {
736 736 PyObject* keys = NULL;
737 737 bool isDict = false;
738 738 if (PyDict_Check(object)) {
739 739 keys = PyDict_Keys(object);
740 740 isDict = true;
741 741 } else {
742 742 keys = PyObject_Dir(object);
743 743 }
744 744 if (keys) {
745 745 int count = PyList_Size(keys);
746 746 PyObject* key;
747 747 PyObject* value;
748 748 QString keystr;
749 749 for (int i = 0;i<count;i++) {
750 750 key = PyList_GetItem(keys,i);
751 751 if (isDict) {
752 752 value = PyDict_GetItem(object, key);
753 753 Py_INCREF(value);
754 754 } else {
755 755 value = PyObject_GetAttr(object, key);
756 756 }
757 757 if (!value) continue;
758 758 keystr = PyString_AsString(key);
759 759 static const QString underscoreStr("__tmp");
760 760 if (!keystr.startsWith(underscoreStr)) {
761 761 switch (type) {
762 762 case Anything:
763 763 results << keystr;
764 764 break;
765 765 case Class:
766 766 if (value->ob_type == &PyClass_Type) {
767 767 results << keystr;
768 768 }
769 769 break;
770 770 case Variable:
771 771 if (value->ob_type != &PyClass_Type
772 772 && value->ob_type != &PyCFunction_Type
773 773 && value->ob_type != &PyFunction_Type
774 774 && value->ob_type != &PyModule_Type
775 775 ) {
776 776 results << keystr;
777 777 }
778 778 break;
779 779 case Function:
780 780 if (value->ob_type == &PyFunction_Type ||
781 781 value->ob_type == &PyMethod_Type
782 782 ) {
783 783 results << keystr;
784 784 }
785 785 break;
786 786 case Module:
787 787 if (value->ob_type == &PyModule_Type) {
788 788 results << keystr;
789 789 }
790 790 break;
791 791 default:
792 792 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
793 793 }
794 794 }
795 795 Py_DECREF(value);
796 796 }
797 797 Py_DECREF(keys);
798 798 }
799 799 }
800 800 }
801 801 return results;
802 802 }
803 803
804 804 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
805 805 {
806 806 PythonQtObjectPtr callable = lookupCallable(object, name);
807 807 if (callable) {
808 808 return call(callable, args);
809 809 } else {
810 810 return QVariant();
811 811 }
812 812 }
813 813
814 814 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
815 815 {
816 816 QVariant r;
817 817 PythonQtObjectPtr result;
818 818 result.setNewRef(callAndReturnPyObject(callable, args));
819 819 if (result) {
820 820 r = PythonQtConv::PyObjToQVariant(result);
821 821 } else {
822 822 PythonQt::self()->handleError();
823 823 }
824 824 return r;
825 825 }
826 826
827 827 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
828 828 {
829 829 PyObject* result = NULL;
830 830 if (callable) {
831 831 PythonQtObjectPtr pargs;
832 832 int count = args.size();
833 833 if (count>0) {
834 834 pargs.setNewRef(PyTuple_New(count));
835 835 }
836 836 bool err = false;
837 837 // transform QVariants to Python
838 838 for (int i = 0; i < count; i++) {
839 839 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
840 840 if (arg) {
841 841 // steals reference, no unref
842 842 PyTuple_SetItem(pargs, i,arg);
843 843 } else {
844 844 err = true;
845 845 break;
846 846 }
847 847 }
848 848
849 849 if (!err) {
850 850 PyErr_Clear();
851 851 result = PyObject_CallObject(callable, pargs);
852 852 }
853 853 }
854 854 return result;
855 855 }
856 856
857 857 void PythonQt::addInstanceDecorators(QObject* o)
858 858 {
859 859 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
860 860 }
861 861
862 862 void PythonQt::addClassDecorators(QObject* o)
863 863 {
864 864 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
865 865 }
866 866
867 867 void PythonQt::addDecorators(QObject* o)
868 868 {
869 869 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
870 870 }
871 871
872 872 void PythonQt::registerQObjectClassNames(const QStringList& names)
873 873 {
874 874 _p->registerQObjectClassNames(names);
875 875 }
876 876
877 877 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
878 878 {
879 879 _p->_importInterface = importInterface;
880 880 PythonQtImport::init();
881 881 }
882 882
883 883 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
884 884 {
885 885 _p->_importIgnorePaths = paths;
886 886 }
887 887
888 888 const QStringList& PythonQt::getImporterIgnorePaths()
889 889 {
890 890 return _p->_importIgnorePaths;
891 891 }
892 892
893 893 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
894 894 {
895 895 _p->_cppWrapperFactories.append(factory);
896 896 }
897 897
898 898 //---------------------------------------------------------------------------------------------------
899 899 PythonQtPrivate::PythonQtPrivate()
900 900 {
901 901 _importInterface = NULL;
902 902 _defaultImporter = new PythonQtQFileImporter;
903 903 _noLongerWrappedCB = NULL;
904 904 _wrappedCB = NULL;
905 905 _currentClassInfoForClassWrapperCreation = NULL;
906 906 }
907 907
908 908 void PythonQtPrivate::setupSharedLibrarySuffixes()
909 909 {
910 910 _sharedLibrarySuffixes.clear();
911 911 PythonQtObjectPtr imp;
912 912 imp.setNewRef(PyImport_ImportModule("imp"));
913 913 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
914 914 QVariant result = imp.call("get_suffixes");
915 915 foreach (QVariant entry, result.toList()) {
916 916 QVariantList suffixEntry = entry.toList();
917 917 if (suffixEntry.count()==3) {
918 918 int code = suffixEntry.at(2).toInt();
919 919 if (code == cExtensionCode) {
920 920 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
921 921 }
922 922 }
923 923 }
924 924 }
925 925
926 926 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
927 927 {
928 928 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
929 929 _currentClassInfoForClassWrapperCreation = NULL;
930 930 return info;
931 931 }
932 932
933 933 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
934 934 {
935 935 o->setParent(this);
936 936 int numMethods = o->metaObject()->methodCount();
937 937 for (int i = 0; i < numMethods; i++) {
938 938 QMetaMethod m = o->metaObject()->method(i);
939 939 if ((m.methodType() == QMetaMethod::Method ||
940 940 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
941 941 if (qstrncmp(m.signature(), "new_", 4)==0) {
942 942 if ((decoTypes & ConstructorDecorator) == 0) continue;
943 943 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
944 944 if (info->parameters().at(0).isPointer) {
945 945 QByteArray signature = m.signature();
946 946 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
947 947 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
948 948 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
949 949 classInfo->addConstructor(newSlot);
950 950 }
951 951 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
952 952 if ((decoTypes & DestructorDecorator) == 0) continue;
953 953 QByteArray signature = m.signature();
954 954 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
955 955 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
956 956 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
957 957 classInfo->setDestructor(newSlot);
958 958 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
959 959 if ((decoTypes & StaticDecorator) == 0) continue;
960 960 QByteArray signature = m.signature();
961 961 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
962 962 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
963 963 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
964 964 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
965 965 classInfo->addDecoratorSlot(newSlot);
966 966 } else {
967 967 if ((decoTypes & InstanceDecorator) == 0) continue;
968 968 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
969 969 if (info->parameters().count()>1) {
970 970 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
971 971 if (p.isPointer) {
972 972 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
973 973 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
974 974 classInfo->addDecoratorSlot(newSlot);
975 975 }
976 976 }
977 977 }
978 978 }
979 979 }
980 980 }
981 981
982 982 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
983 983 {
984 984 foreach(QString name, names) {
985 985 _knownQObjectClassNames.insert(name.toLatin1(), true);
986 986 }
987 987 }
988 988
989 989 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
990 990 {
991 991 _signalReceivers.remove(obj);
992 992 }
993 993
994 994 bool PythonQt::handleError()
995 995 {
996 996 bool flag = false;
997 997 if (PyErr_Occurred()) {
998 998
999 999 // currently we just print the error and the stderr handler parses the errors
1000 1000 PyErr_Print();
1001 1001
1002 1002 /*
1003 1003 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1004 1004 PyObject *ptype;
1005 1005 PyObject *pvalue;
1006 1006 PyObject *ptraceback;
1007 1007 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1008 1008
1009 1009 Py_XDECREF(ptype);
1010 1010 Py_XDECREF(pvalue);
1011 1011 Py_XDECREF(ptraceback);
1012 1012 */
1013 1013 PyErr_Clear();
1014 1014 flag = true;
1015 1015 }
1016 1016 return flag;
1017 1017 }
1018 1018
1019 1019 void PythonQt::addSysPath(const QString& path)
1020 1020 {
1021 1021 PythonQtObjectPtr sys;
1022 1022 sys.setNewRef(PyImport_ImportModule("sys"));
1023 1023 PythonQtObjectPtr obj = lookupObject(sys, "path");
1024 1024 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1025 1025 }
1026 1026
1027 1027 void PythonQt::overwriteSysPath(const QStringList& paths)
1028 1028 {
1029 1029 PythonQtObjectPtr sys;
1030 1030 sys.setNewRef(PyImport_ImportModule("sys"));
1031 1031 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1032 1032 }
1033 1033
1034 1034 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1035 1035 {
1036 1036 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1037 1037 }
1038 1038
1039 1039 void PythonQt::stdOutRedirectCB(const QString& str)
1040 1040 {
1041 1041 emit PythonQt::self()->pythonStdOut(str);
1042 1042 }
1043 1043
1044 1044 void PythonQt::stdErrRedirectCB(const QString& str)
1045 1045 {
1046 1046 emit PythonQt::self()->pythonStdErr(str);
1047 1047 }
1048 1048
1049 1049 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1050 1050 {
1051 1051 _p->_wrappedCB = cb;
1052 1052 }
1053 1053
1054 1054 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1055 1055 {
1056 1056 _p->_noLongerWrappedCB = cb;
1057 1057 }
1058 1058
1059 1059
1060 1060
1061 1061 static PyMethodDef PythonQtMethods[] = {
1062 1062 {NULL, NULL, 0, NULL}
1063 1063 };
1064 1064
1065 1065 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1066 1066 {
1067 1067 QByteArray name = "PythonQt";
1068 1068 if (!pythonQtModuleName.isEmpty()) {
1069 1069 name = pythonQtModuleName;
1070 1070 }
1071 1071 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1072 1072 _p->_pythonQtModuleName = name;
1073 1073
1074 1074 if (redirectStdOut) {
1075 1075 PythonQtObjectPtr sys;
1076 1076 PythonQtObjectPtr out;
1077 1077 PythonQtObjectPtr err;
1078 1078 sys.setNewRef(PyImport_ImportModule("sys"));
1079 1079 // create a redirection object for stdout and stderr
1080 1080 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1081 1081 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1082 1082 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1083 1083 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1084 1084 // replace the built in file objects with our own objects
1085 1085 PyModule_AddObject(sys, "stdout", out);
1086 1086 PyModule_AddObject(sys, "stderr", err);
1087 1087 }
1088 1088 }
1089 1089
1090 1090 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1091 1091 {
1092 1092 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1093 1093 }
1094 1094
1095 1095
1096 1096 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1097 1097 {
1098 1098 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1099 1099 if (!info) {
1100 1100 info = new PythonQtClassInfo();
1101 1101 info->setupCPPObject(typeName);
1102 1102 _knownClassInfos.insert(typeName, info);
1103 1103 }
1104 1104 return info;
1105 1105 }
1106 1106
1107 1107 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1108 1108 {
1109 1109 _p->addPolymorphicHandler(typeName, cb);
1110 1110 }
1111 1111
1112 1112 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1113 1113 {
1114 1114 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1115 1115 info->addPolymorphicHandler(cb);
1116 1116 }
1117 1117
1118 1118 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1119 1119 {
1120 1120 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1121 1121 }
1122 1122
1123 1123 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1124 1124 {
1125 1125 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1126 1126 if (info) {
1127 1127 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1128 1128 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1129 1129 return true;
1130 1130 } else {
1131 1131 return false;
1132 1132 }
1133 1133 }
1134 1134
1135 1135 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1136 1136 {
1137 1137 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1138 1138 if (!info->pythonQtClassWrapper()) {
1139 1139 info->setTypeSlots(typeSlots);
1140 1140 info->setupCPPObject(typeName);
1141 1141 createPythonQtClassWrapper(info, package, module);
1142 1142 }
1143 1143 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1144 1144 addParentClass(typeName, parentTypeName, 0);
1145 1145 }
1146 1146 if (wrapperCreator) {
1147 1147 info->setDecoratorProvider(wrapperCreator);
1148 1148 }
1149 1149 if (shell) {
1150 1150 info->setShellSetInstanceWrapperCB(shell);
1151 1151 }
1152 1152 }
1153 1153
1154 1154 PyObject* PythonQtPrivate::packageByName(const char* name)
1155 1155 {
1156 1156 if (name==NULL || name[0]==0) {
1157 1157 name = "private";
1158 1158 }
1159 1159 PyObject* v = _packages.value(name);
1160 1160 if (!v) {
1161 1161 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1162 1162 _packages.insert(name, v);
1163 1163 // AddObject steals the reference, so increment it!
1164 1164 Py_INCREF(v);
1165 1165 PyModule_AddObject(_pythonQtModule, name, v);
1166 1166 }
1167 1167 return v;
1168 1168 }
1169 1169
1170 1170 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1171 1171 {
1172 1172 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1173 1173 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1174 1174 PythonQt::self()->handleError();
1175 1175 }
1176 1176
1177 1177 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1178 1178 {
1179 1179 if (_p->_initFlags & ExternalHelp) {
1180 1180 emit pythonHelpRequest(QByteArray(info->className()));
1181 1181 return Py_BuildValue("");
1182 1182 } else {
1183 1183 return PyString_FromString(info->help().toLatin1().data());
1184 1184 }
1185 1185 }
1186 1186
1187 1187 void PythonQtPrivate::removeWrapperPointer(void* obj)
1188 1188 {
1189 1189 _wrappedObjects.remove(obj);
1190 1190 }
1191 1191
1192 1192 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1193 1193 {
1194 1194 _wrappedObjects.insert(obj, wrapper);
1195 1195 }
1196 1196
1197 1197 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1198 1198 {
1199 1199 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1200 1200 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1201 1201 // this is a wrapper whose QObject was already removed due to destruction
1202 1202 // so the obj pointer has to be a new QObject with the same address...
1203 1203 // we remove the old one and set the copy to NULL
1204 1204 wrap->_objPointerCopy = NULL;
1205 1205 removeWrapperPointer(obj);
1206 1206 wrap = NULL;
1207 1207 }
1208 1208 return wrap;
1209 1209 }
1210 1210
1211 1211 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1212 1212 {
1213 1213 PythonQtObjectPtr result;
1214 1214 if (pycode) {
1215 1215 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1216 1216 } else {
1217 1217 PythonQt::self()->handleError();
1218 1218 }
1219 1219 return result;
1220 1220 }
@@ -1,579 +1,579
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 71
72 72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73 73
74 74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75 75
76 76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 79 }
80 80
81 81 //! callback to create a QObject lazily
82 82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83 83
84 84 //! helper template to create a derived QObject class
85 85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86 86
87 87 //! the main interface to the Python Qt binding, realized as a singleton
88 88 class PYTHONQT_EXPORT PythonQt : public QObject {
89 89
90 90 Q_OBJECT
91 91
92 92 public:
93 93 enum InitFlags {
94 94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
95 95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
96 96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
97 97 };
98 98
99 99 //! flags that tell PythonQt which operators to expect on the registered type
100 100 enum TypeSlots {
101 101 Type_Add = 1,
102 102 Type_Subtract = 1 << 1,
103 103 Type_Multiply = 1 << 2,
104 104 Type_Divide = 1 << 3,
105 105 Type_Mod = 1 << 4,
106 106 Type_And = 1 << 5,
107 107 Type_Or = 1 << 6,
108 108 Type_Xor = 1 << 7,
109 109 Type_LShift = 1 << 8,
110 110 Type_RShift = 1 << 9,
111 111
112 112 Type_InplaceAdd = 1 << 10,
113 113 Type_InplaceSubtract = 1 << 11,
114 114 Type_InplaceMultiply = 1 << 12,
115 115 Type_InplaceDivide = 1 << 13,
116 116 Type_InplaceMod = 1 << 14,
117 117 Type_InplaceAnd = 1 << 15,
118 118 Type_InplaceOr = 1 << 16,
119 119 Type_InplaceXor = 1 << 17,
120 120 Type_InplaceLShift = 1 << 18,
121 121 Type_InplaceRShift = 1 << 19,
122 122
123 123 // Not yet needed/nicely mappable/generated...
124 124 //Type_Positive = 1 << 29,
125 125 //Type_Negative = 1 << 29,
126 126 //Type_Abs = 1 << 29,
127 127 //Type_Hash = 1 << 29,
128 128
129 129 Type_Invert = 1 << 29,
130 130 Type_RichCompare = 1 << 30,
131 131 Type_NonZero = 1 << 31,
132 132
133 133 };
134 134
135 135 //! initialize the python qt binding (flags are a or combination of InitFlags), if \c pythonQtModuleName is given
136 136 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
137 137 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
138 138 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
139 139
140 140 //! cleanup
141 141 static void cleanup();
142 142
143 143 //! get the singleton instance
144 144 static PythonQt* self() { return _self; }
145 145
146 146 //-----------------------------------------------------------------------------
147 147 // Public API:
148 148
149 149 //! defines the object types for introspection
150 150 enum ObjectType {
151 151 Class,
152 152 Function,
153 153 Variable,
154 154 Module,
155 155 Anything,
156 156 CallOverloads
157 157 };
158 158
159 159 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
160 160 void overwriteSysPath(const QStringList& paths);
161 161
162 162 //! prepend a path to sys.path to allow importing from it
163 163 void addSysPath(const QString& path);
164 164
165 165 //! sets the __path__ list of a module to the given list (important for local imports)
166 166 void setModuleImportPath(PyObject* module, const QStringList& paths);
167 167
168 168 //! get the __main__ module of python
169 169 PythonQtObjectPtr getMainModule();
170 170
171 171 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
172 172 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
173 173 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
174 174 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
175 175
176 176 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
177 177 //! (ownership of wrapper is passed to PythonQt)
178 178 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
179 179
180 180 This will add a wrapper object that is used to make calls to the given classname \c typeName.
181 181 All slots that take a pointer to typeName as the first argument will be callable from Python on
182 182 a variant object that contains such a type.
183 183 */
184 184 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
185 185
186 186 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
187 187 //! and it will register the classes when it first sees a pointer to such a derived class
188 188 void registerQObjectClassNames(const QStringList& names);
189 189
190 190 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
191 191 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
192 192 //! type is really derived from parentType.
193 193 //! Returns false if the typeName was not yet registered.
194 194 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
195 195
196 196 //! add a handler for polymorphic downcasting
197 197 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
198 198
199 199 //! parses the given file and returns the python code object, this can then be used to call evalCode()
200 200 PythonQtObjectPtr parseFile(const QString& filename);
201 201
202 202 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
203 203 //! If pycode is NULL, a python error is printed.
204 204 QVariant evalCode(PyObject* object, PyObject* pycode);
205 205
206 206 //! evaluates the given script code and returns the result value
207 207 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
208 208
209 209 //! evaluates the given script code from file
210 210 void evalFile(PyObject* object, const QString& filename);
211 211
212 212 //! creates the new module \c name and evaluates the given file in the context of that module
213 213 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
214 214 //! to a module later on.
215 215 //! The user needs to make sure that the \c name is unique in the python module dictionary.
216 216 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
217 217
218 218 //! creates the new module \c name and evaluates the given script in the context of that module.
219 219 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
220 220 //! to a module later on.
221 221 //! The user needs to make sure that the \c name is unique in the python module dictionary.
222 222 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
223 223
224 224 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
225 225 //! script code
226 226 PythonQtObjectPtr createUniqueModule();
227 227
228 228 //@{ Signal handlers
229 229
230 230 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
231 231 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
232 232
233 233 //! remove a signal handler from the given \c signal of \c obj
234 234 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
235 235
236 236 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
237 237 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
238 238
239 239 //! remove a signal handler from the given \c signal of \c obj
240 240 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
241 241
242 242 //@}
243 243
244 244 //@{ Variable access
245 245
246 246 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
247 247 void addObject(PyObject* object, const QString& name, QObject* qObject);
248 248
249 249 //! add the given variable to the object
250 250 void addVariable(PyObject* object, const QString& name, const QVariant& v);
251 251
252 252 //! remove the given variable
253 253 void removeVariable(PyObject* module, const QString& name);
254 254
255 255 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
256 256 QVariant getVariable(PyObject* object, const QString& name);
257 257
258 258 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
259 259 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
260 260
261 261 //! returns the found callable object or NULL
262 262 //! @return new reference
263 263 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
264 264
265 265 //@}
266 266
267 267 //@{ Calling of python callables
268 268
269 269 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
270 270 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
271 271
272 272 //! call the given python object, returns the result converted to a QVariant
273 273 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
274 274
275 275 //! call the given python object, returns the result as new PyObject
276 276 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
277 277
278 278 //@}
279 279
280 280 //@{ Decorations, constructors, wrappers...
281 281
282 282
283 283 //! add an object whose slots will be used as decorator slots for
284 284 //! other QObjects or CPP classes. The slots need to follow the
285 285 //! convention that the first argument is a pointer to the wrapped object.
286 286 //! (ownership is passed to PythonQt)
287 287 /*!
288 288 Example:
289 289
290 290 A slot with the signature
291 291
292 292 \code
293 293 bool doSomething(QWidget* w, int a)
294 294 \endcode
295 295
296 296 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
297 297 that will be called with the concrete instance as first argument.
298 298 So in Python you can now e.g. call
299 299
300 300 \code
301 301 someWidget.doSomething(12)
302 302 \endcode
303 303
304 304 without QWidget really having this method. This allows to easily make normal methods
305 305 of Qt classes callable by forwarding them with such decorator slots
306 306 or to make CPP classes (which are not derived from QObject) callable from Python.
307 307 */
308 308 void addInstanceDecorators(QObject* o);
309 309
310 310 //! add an object whose slots will be used as decorator slots for
311 311 //! class objects (ownership is passed to PythonQt)
312 312 /*!
313 313 The slots need to follow the following convention:
314 314 - SomeClass* new_SomeClass(...)
315 315 - QVariant new_SomeClass(...)
316 316 - void delete_SomeClass(SomeClass*)
317 317 - ... static_SomeClass_someName(...)
318 318
319 319 This will add:
320 320 - a constructor
321 321 - a constructor which generates a QVariant
322 322 - a destructor (only useful for CPP objects)
323 323 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
324 324
325 325 */
326 326 void addClassDecorators(QObject* o);
327 327
328 328 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
329 329 void addDecorators(QObject* o);
330 330
331 331 //! add the given factory to PythonQt (ownership stays with caller)
332 332 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
333 333
334 334 //@}
335 335
336 336 //@{ Custom importer (to replace internal import implementation of python)
337 337
338 338 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
339 339 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
340 340 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
341 341 //! This is not reversible, so even setting setImporter(NULL) afterwards will
342 342 //! keep the custom PythonQt importer with a QFile default import interface.
343 343 //! Subsequent python import calls will make use of the passed importInterface
344 344 //! which forwards all import calls to the given \c importInterface.
345 345 //! Passing NULL will install a default QFile importer.
346 346 //! (\c importInterface ownership stays with caller)
347 347 void setImporter(PythonQtImportFileInterface* importInterface);
348 348
349 349 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
350 350 //! (without calling setImporter or installDefaultImporter at least once, the default python import
351 351 //! mechanism is in place)
352 352 //! the default importer allows to import files from anywhere QFile can read from,
353 353 //! including the Qt resource system using ":". Keep in mind that you need to extend
354 354 //! "sys.path" with ":" to be able to import from the Qt resources.
355 355 void installDefaultImporter() { setImporter(NULL); }
356 356
357 357 //! set paths that the importer should ignore
358 358 void setImporterIgnorePaths(const QStringList& paths);
359 359
360 360 //! get paths that the importer should ignore
361 361 const QStringList& getImporterIgnorePaths();
362 362
363 363 //@}
364 364
365 365 //! get access to internal data (should not be used on the public API, but is used by some C functions)
366 366 static PythonQtPrivate* priv() { return _self->_p; }
367 367
368 368 //! get access to the file importer (if set)
369 369 static PythonQtImportFileInterface* importInterface();
370 370
371 371 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
372 372 //! The error is currently just output to the python stderr, future version might implement better trace printing
373 373 bool handleError();
374 374
375 375 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
376 376 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
377 377 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
378 378 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
379 379
380 380 //! call the callback if it is set
381 381 static void qObjectNoLongerWrappedCB(QObject* o);
382 382
383 383 signals:
384 384 //! emitted when python outputs something to stdout (and redirection is turned on)
385 385 void pythonStdOut(const QString& str);
386 386 //! emitted when python outputs something to stderr (and redirection is turned on)
387 387 void pythonStdErr(const QString& str);
388 388
389 389 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
390 390 void pythonHelpRequest(const QByteArray& cppClassName);
391 391
392 392
393 393 public:
394 394 //! called by internal help methods
395 395 PyObject* helpCalled(PythonQtClassInfo* info);
396 396
397 397 //! returns the found object or NULL
398 398 //! @return new reference
399 399 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
400 400
401 401 private:
402 402 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
403 403
404 404 //! callback for stdout redirection, emits pythonStdOut signal
405 405 static void stdOutRedirectCB(const QString& str);
406 406 //! callback for stderr redirection, emits pythonStdErr signal
407 407 static void stdErrRedirectCB(const QString& str);
408 408
409 409 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
410 410 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
411 411
412 412 PythonQt(int flags, const QByteArray& pythonQtModuleName);
413 413 ~PythonQt();
414 414
415 415 static PythonQt* _self;
416 416 static int _uniqueModuleCount;
417 417
418 418 PythonQtPrivate* _p;
419 419
420 420 };
421 421
422 422 //! internal PythonQt details
423 423 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
424 424
425 425 Q_OBJECT
426 426
427 427 public:
428 428 PythonQtPrivate();
429 429 ~PythonQtPrivate();
430 430
431 431 enum DecoratorTypes {
432 432 StaticDecorator = 1,
433 433 ConstructorDecorator = 2,
434 434 DestructorDecorator = 4,
435 435 InstanceDecorator = 8,
436 436 AllDecorators = 0xffff
437 437 };
438 438
439 439 //! get the suffixes that are used for shared libraries
440 440 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
441 441
442 442 //! returns if the id is the id for PythonQtObjectPtr
443 443 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
444 444
445 445 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
446 446 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
447 447 //! remove the wrapper ptr again
448 448 void removeWrapperPointer(void* obj);
449 449
450 450 //! add parent class relation
451 451 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
452 452
453 453 //! add a handler for polymorphic downcasting
454 454 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
455 455
456 456 //! lookup existing classinfo and return new if not yet present
457 457 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
458 458
459 459 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
460 460 void removeSignalEmitter(QObject* obj);
461 461
462 462 //! wrap the given QObject into a Python object (or return existing wrapper!)
463 463 PyObject* wrapQObject(QObject* obj);
464 464
465 465 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
466 466 PyObject* wrapPtr(void* ptr, const QByteArray& name);
467 467
468 468 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
469 469 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
470 470 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
471 471 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
472 472
473 473 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
474 474 //! (ownership of wrapper is passed to PythonQt)
475 475 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
476 476
477 477 This will add a wrapper object that is used to make calls to the given classname \c typeName.
478 478 All slots that take a pointer to typeName as the first argument will be callable from Python on
479 479 a variant object that contains such a type.
480 480 */
481 481 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
482 482
483 483 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
484 484 //! and it will register the classes when it first sees a pointer to such a derived class
485 485 void registerQObjectClassNames(const QStringList& names);
486 486
487 487 //! add a decorator object
488 488 void addDecorators(QObject* o, int decoTypes);
489 489
490 490 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
491 491 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
492 492
493 493 //! create a new instance of the given enum type with given value (returns a new reference)
494 494 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
495 495
496 496 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
497 497 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
498 498
499 499 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
500 500 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
501 501
502 502 //! get the class info for a meta object (if available)
503 503 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
504 504
505 505 //! get the class info for a meta object (if available)
506 506 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
507 507
508 508 //! creates the new module from the given pycode
509 509 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
510 510
511 511 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
512 512 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
513 513
514 514 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
515 515 static PyObject* dummyTuple();
516 516
517 517 //! called by virtual overloads when a python return value can not be converted to the required Qt type
518 518 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
519 519
520 520 //! get access to the PythonQt module
521 521 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
522 522
523 523 private:
524 524 //! Setup the shared library suffixes by getting them from the "imp" module.
525 525 void setupSharedLibrarySuffixes();
526 526
527 527 //! create a new pythonqt class wrapper and place it in the pythonqt module
528 528 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
529 529
530 530 //! get/create new package module (the returned object is a borrowed reference)
531 531 PyObject* packageByName(const char* name);
532 532
533 533 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
534 534 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
535 535
536 536 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
537 537 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
538 538
539 539 //! stores the meta info of known Qt classes
540 540 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
541 541
542 542 //! names of qobject derived classes that can be casted to qobject savely
543 543 QHash<QByteArray, bool> _knownQObjectClassNames;
544 544
545 545 //! stores signal receivers for QObjects
546 546 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
547 547
548 548 //! the PythonQt python module
549 549 PythonQtObjectPtr _pythonQtModule;
550 550
551 551 //! the name of the PythonQt python module
552 552 QByteArray _pythonQtModuleName;
553 553
554 554 //! the importer interface (if set)
555 555 PythonQtImportFileInterface* _importInterface;
556 556
557 557 //! the default importer
558 558 PythonQtQFileImporter* _defaultImporter;
559 559
560 560 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
561 561 PythonQtQObjectWrappedCB* _wrappedCB;
562 562
563 563 QStringList _importIgnorePaths;
564 564 QStringList _sharedLibrarySuffixes;
565 565
566 566 //! the cpp object wrapper factories
567 567 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
568 568
569 569 QHash<QByteArray, PyObject*> _packages;
570 570
571 571 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
572 572
573 573 int _initFlags;
574 574 int _PythonQtObjectPtr_metaId;
575 575
576 576 friend class PythonQt;
577 577 };
578 578
579 579 #endif
@@ -1,849 +1,849
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _typeSlots = 0;
61 61 _isQObject = false;
62 62 _enumsCreated = false;
63 63 }
64 64
65 65 PythonQtClassInfo::~PythonQtClassInfo()
66 66 {
67 67 clearCachedMembers();
68 68
69 69 if (_constructors) {
70 70 _constructors->deleteOverloadsAndThis();
71 71 }
72 72 if (_destructor) {
73 73 _destructor->deleteOverloadsAndThis();
74 74 }
75 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
76 76 info->deleteOverloadsAndThis();
77 77 }
78 78 }
79 79
80 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
81 81 {
82 82 // _wrappedClassName is already set earlier in the class setup
83 83 _isQObject = true;
84 84 _meta = meta;
85 85 }
86 86
87 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
88 88 {
89 89 _isQObject = false;
90 90 _wrappedClassName = classname;
91 91 _metaTypeId = QMetaType::type(classname);
92 92 }
93 93
94 94 void PythonQtClassInfo::clearCachedMembers()
95 95 {
96 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
97 97 while (i.hasNext()) {
98 98 PythonQtMemberInfo member = i.next().value();
99 99 if (member._type== PythonQtMemberInfo::Slot) {
100 100 PythonQtSlotInfo* info = member._slot;
101 101 while (info) {
102 102 PythonQtSlotInfo* next = info->nextInfo();
103 103 delete info;
104 104 info = next;
105 105 }
106 106 }
107 107 }
108 108 }
109 109
110 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
111 111 {
112 112 const char* sigEnd = sigStart;
113 113 char c;
114 114 do {
115 115 c = *sigEnd++;
116 116 } while (c!=someChar && c!=0);
117 117 return sigEnd-sigStart-1;
118 118 }
119 119
120 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
121 121 {
122 122 if (!_meta) return false;
123 123
124 124 bool found = false;
125 125 bool nameMapped = false;
126 126 const char* attributeName = memberName;
127 127 // look for properties
128 128 int i = _meta->indexOfProperty(attributeName);
129 129 if (i==-1) {
130 130 // try to map name to objectName
131 131 if (qstrcmp(attributeName, "name")==0) {
132 132 attributeName = "objectName";
133 133 nameMapped = true;
134 134 i = _meta->indexOfProperty(attributeName);
135 135 }
136 136 }
137 137 if (i!=-1) {
138 138 PythonQtMemberInfo newInfo(_meta->property(i));
139 139 _cachedMembers.insert(attributeName, newInfo);
140 140 if (nameMapped) {
141 141 _cachedMembers.insert(memberName, newInfo);
142 142 }
143 143 #ifdef PYTHONQT_DEBUG
144 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
145 145 #endif
146 146 found = true;
147 147 }
148 148 return found;
149 149 }
150 150
151 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
152 152 {
153 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
154 154 foreach(const ParentClassInfo& info, _parentClasses) {
155 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
156 156 }
157 157 return inputInfo;
158 158 }
159 159
160 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
161 161 QObject* decoratorProvider = decorator();
162 162 int memberNameLen = strlen(memberName);
163 163 if (decoratorProvider) {
164 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
165 165 const QMetaObject* meta = decoratorProvider->metaObject();
166 166 int numMethods = meta->methodCount();
167 167 int startFrom = QObject::staticMetaObject.methodCount();
168 168 for (int i = startFrom; i < numMethods; i++) {
169 169 QMetaMethod m = meta->method(i);
170 170 if ((m.methodType() == QMetaMethod::Method ||
171 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
172 172
173 173 const char* sigStart = m.signature();
174 174 bool isClassDeco = false;
175 175 if (qstrncmp(sigStart, "static_", 7)==0) {
176 176 // skip the static_classname_ part of the string
177 177 sigStart += 7 + 1 + strlen(className());
178 178 isClassDeco = true;
179 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
180 180 isClassDeco = true;
181 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
182 182 isClassDeco = true;
183 183 }
184 184 // find the first '('
185 185 int offset = findCharOffset(sigStart, '(');
186 186
187 187 // XXX no checking is currently done if the slots have correct first argument or not...
188 188
189 189 // check if same length and same name
190 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
191 191 found = true;
192 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
193 193 info->setUpcastingOffset(upcastingOffset);
194 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
195 195 if (tail) {
196 196 tail->setNextInfo(info);
197 197 } else {
198 198 PythonQtMemberInfo newInfo(info);
199 199 memberCache.insert(memberName, newInfo);
200 200 }
201 201 tail = info;
202 202 }
203 203 }
204 204 }
205 205 }
206 206
207 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
208 208
209 209 return tail;
210 210 }
211 211
212 212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
213 213 {
214 214 bool found = false;
215 215 int memberNameLen = strlen(memberName);
216 216 PythonQtSlotInfo* tail = NULL;
217 217 if (_meta) {
218 218 int numMethods = _meta->methodCount();
219 219 for (int i = 0; i < numMethods; i++) {
220 220 QMetaMethod m = _meta->method(i);
221 221 if (((m.methodType() == QMetaMethod::Method ||
222 222 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
223 223 || m.methodType()==QMetaMethod::Signal) {
224 224
225 225 const char* sigStart = m.signature();
226 226 // find the first '('
227 227 int offset = findCharOffset(sigStart, '(');
228 228
229 229 // check if same length and same name
230 230 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
231 231 found = true;
232 232 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
233 233 if (tail) {
234 234 tail->setNextInfo(info);
235 235 } else {
236 236 PythonQtMemberInfo newInfo(info);
237 237 _cachedMembers.insert(memberName, newInfo);
238 238 }
239 239 tail = info;
240 240 }
241 241 }
242 242 }
243 243 }
244 244
245 245 // look for dynamic decorators in this class and in derived classes
246 246 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
247 247
248 248 return found;
249 249 }
250 250
251 251 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
252 252 {
253 253 bool found = false;
254 254 // look for enum values
255 255 int enumCount = meta->enumeratorCount();
256 256 for (int i=0;i<enumCount; i++) {
257 257 QMetaEnum e = meta->enumerator(i);
258 258 // we do not want flags, they will cause our values to appear two times
259 259 if (e.isFlag()) continue;
260 260
261 261 for (int j=0; j < e.keyCount(); j++) {
262 262 if (qstrcmp(e.key(j), memberName)==0) {
263 263 PyObject* enumType = findEnumWrapper(e.name());
264 264 if (enumType) {
265 265 PythonQtObjectPtr enumValuePtr;
266 266 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
267 267 PythonQtMemberInfo newInfo(enumValuePtr);
268 268 _cachedMembers.insert(memberName, newInfo);
269 269 #ifdef PYTHONQT_DEBUG
270 270 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
271 271 #endif
272 272 found = true;
273 273 break;
274 274 } else {
275 275 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
276 276 }
277 277 }
278 278 }
279 279 }
280 280 return found;
281 281 }
282 282
283 283 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
284 284 {
285 285 PythonQtMemberInfo info = _cachedMembers.value(memberName);
286 286 if (info._type != PythonQtMemberInfo::Invalid) {
287 287 return info;
288 288 } else {
289 289 bool found = false;
290 290
291 291 found = lookForPropertyAndCache(memberName);
292 292 if (!found) {
293 293 found = lookForMethodAndCache(memberName);
294 294 }
295 295 if (!found) {
296 296 if (_meta) {
297 297 // check enums in our meta object directly
298 298 found = lookForEnumAndCache(_meta, memberName);
299 299 }
300 300 if (!found) {
301 301 // check enums in the class hierachy of CPP classes
302 302 // look for dynamic decorators in this class and in derived classes
303 303 QList<QObject*> decoObjects;
304 304 recursiveCollectDecoratorObjects(decoObjects);
305 305 foreach(QObject* deco, decoObjects) {
306 306 // call on ourself for caching, but with different metaObject():
307 307 found = lookForEnumAndCache(deco->metaObject(), memberName);
308 308 if (found) {
309 309 break;
310 310 }
311 311 }
312 312 }
313 313 }
314 314 if (!found) {
315 315 // maybe it is an enum wrapper?
316 316 PyObject* p = findEnumWrapper(memberName);
317 317 if (p) {
318 318 info._type = PythonQtMemberInfo::EnumWrapper;
319 319 info._enumWrapper = p;
320 320 _cachedMembers.insert(memberName, info);
321 321 found = true;
322 322 }
323 323 }
324 324 if (!found) {
325 325 // since python keywords can not be looked up, we check if the name contains a single trailing _
326 326 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
327 327 QByteArray mbrName(memberName);
328 328 if ((mbrName.length()>2) &&
329 329 (mbrName.at(mbrName.length()-1) == '_') &&
330 330 (mbrName.at(mbrName.length()-2) != '_')) {
331 331 mbrName = mbrName.mid(0,mbrName.length()-1);
332 332 found = lookForMethodAndCache(mbrName.constData());
333 333 if (found) {
334 334 return _cachedMembers.value(mbrName);
335 335 }
336 336 }
337 337 }
338 338 if (!found) {
339 339 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
340 340 info._type = PythonQtMemberInfo::NotFound;
341 341 _cachedMembers.insert(memberName, info);
342 342 }
343 343 }
344 344
345 345 return _cachedMembers.value(memberName);
346 346 }
347 347
348 348 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
349 349 QObject* deco = decorator();
350 350 if (deco) {
351 351 decoratorObjects.append(deco);
352 352 }
353 353 foreach(const ParentClassInfo& info, _parentClasses) {
354 354 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
355 355 }
356 356 }
357 357
358 358 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
359 359 classInfoObjects.append(this);
360 360 foreach(const ParentClassInfo& info, _parentClasses) {
361 361 info._parent->recursiveCollectClassInfos(classInfoObjects);
362 362 }
363 363 }
364 364
365 365 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
366 366 {
367 367 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
368 368 while (it.hasNext()) {
369 369
370 370 PythonQtSlotInfo* infoOrig = it.next();
371 371
372 372 const char* sigStart = infoOrig->metaMethod()->signature();
373 373 if (qstrncmp("static_", sigStart, 7)==0) {
374 374 sigStart += 7;
375 375 sigStart += findCharOffset(sigStart, '_')+1;
376 376 }
377 377 int offset = findCharOffset(sigStart, '(');
378 378 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
379 379 //make a copy, otherwise we will have trouble on overloads!
380 380 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
381 381 info->setUpcastingOffset(upcastingOffset);
382 382 found = true;
383 383 if (tail) {
384 384 tail->setNextInfo(info);
385 385 } else {
386 386 PythonQtMemberInfo newInfo(info);
387 387 memberCache.insert(memberName, newInfo);
388 388 }
389 389 tail = info;
390 390 }
391 391 }
392 392 return tail;
393 393 }
394 394
395 395 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
396 396 QObject* decoratorProvider = decorator();
397 397 if (decoratorProvider) {
398 398 const QMetaObject* meta = decoratorProvider->metaObject();
399 399 int numMethods = meta->methodCount();
400 400 int startFrom = QObject::staticMetaObject.methodCount();
401 401 for (int i = startFrom; i < numMethods; i++) {
402 402 QMetaMethod m = meta->method(i);
403 403 if ((m.methodType() == QMetaMethod::Method ||
404 404 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
405 405
406 406 const char* sigStart = m.signature();
407 407 bool isClassDeco = false;
408 408 if (qstrncmp(sigStart, "static_", 7)==0) {
409 409 // skip the static_classname_ part of the string
410 410 sigStart += 7 + 1 + strlen(className());
411 411 isClassDeco = true;
412 412 } else if (qstrncmp(sigStart, "new_", 4)==0) {
413 413 continue;
414 414 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
415 415 continue;
416 416 } else if (qstrncmp(sigStart, "py_", 3)==0) {
417 417 // hide everything that starts with py_
418 418 continue;
419 419 }
420 420 // find the first '('
421 421 int offset = findCharOffset(sigStart, '(');
422 422
423 423 // XXX no checking is currently done if the slots have correct first argument or not...
424 424 if (!metaOnly || isClassDeco) {
425 425 list << QString::fromLatin1(sigStart, offset);
426 426 }
427 427 }
428 428 }
429 429 }
430 430
431 431 // look for global decorator slots
432 432 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
433 433 while (it.hasNext()) {
434 434 PythonQtSlotInfo* slot = it.next();
435 435 if (metaOnly) {
436 436 if (slot->isClassDecorator()) {
437 437 QByteArray first = slot->slotName();
438 438 if (first.startsWith("static_")) {
439 439 int idx = first.indexOf('_');
440 440 idx = first.indexOf('_', idx+1);
441 441 first = first.mid(idx+1);
442 442 }
443 443 list << first;
444 444 }
445 445 } else {
446 446 list << slot->slotName();
447 447 }
448 448 }
449 449 }
450 450
451 451 QStringList PythonQtClassInfo::propertyList()
452 452 {
453 453 QStringList l;
454 454 if (_isQObject && _meta) {
455 455 int i;
456 456 int numProperties = _meta->propertyCount();
457 457 for (i = 0; i < numProperties; i++) {
458 458 QMetaProperty p = _meta->property(i);
459 459 l << QString(p.name());
460 460 }
461 461 }
462 462 return l;
463 463 }
464 464
465 465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
466 466 {
467 467 decorator();
468 468
469 469 QStringList l;
470 470 QString h;
471 471 if (_isQObject && _meta && !metaOnly) {
472 472 l = propertyList();
473 473 }
474 474
475 475 // normal slots of QObject (or wrapper QObject)
476 476 if (!metaOnly && _meta) {
477 477 int numMethods = _meta->methodCount();
478 478 bool skipQObj = !_isQObject;
479 479 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
480 480 QMetaMethod m = _meta->method(i);
481 481 if (((m.methodType() == QMetaMethod::Method ||
482 482 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
483 483 || m.methodType()==QMetaMethod::Signal) {
484 484 QByteArray signa(m.signature());
485 485 signa = signa.left(signa.indexOf('('));
486 486 l << signa;
487 487 }
488 488 }
489 489 }
490 490
491 491 {
492 492 // look for dynamic decorators in this class and in derived classes
493 493 QList<PythonQtClassInfo*> infos;
494 494 recursiveCollectClassInfos(infos);
495 495 foreach(PythonQtClassInfo* info, infos) {
496 496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
497 497 }
498 498 }
499 499
500 500 // List enumerator keys...
501 501 QList<const QMetaObject*> enumMetaObjects;
502 502 if (_meta) {
503 503 enumMetaObjects << _meta;
504 504 }
505 505 // check enums in the class hierachy of CPP classes
506 506 QList<QObject*> decoObjects;
507 507 recursiveCollectDecoratorObjects(decoObjects);
508 508 foreach(QObject* deco, decoObjects) {
509 509 enumMetaObjects << deco->metaObject();
510 510 }
511 511
512 512 foreach(const QMetaObject* meta, enumMetaObjects) {
513 513 for (int i = 0; i<meta->enumeratorCount(); i++) {
514 514 QMetaEnum e = meta->enumerator(i);
515 515 l << e.name();
516 516 // we do not want flags, they will cause our values to appear two times
517 517 if (e.isFlag()) continue;
518 518
519 519 for (int j=0; j < e.keyCount(); j++) {
520 520 l << QString(e.key(j));
521 521 }
522 522 }
523 523 }
524 524
525 525 return QSet<QString>::fromList(l).toList();
526 526 }
527 527
528 528 const char* PythonQtClassInfo::className()
529 529 {
530 530 return _wrappedClassName.constData();
531 531 }
532 532
533 533 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
534 534 {
535 535 if (ptr==NULL) {
536 536 return NULL;
537 537 }
538 538 if (_wrappedClassName == classname) {
539 539 return ptr;
540 540 }
541 541 foreach(const ParentClassInfo& info, _parentClasses) {
542 542 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
543 543 if (result) {
544 544 return result;
545 545 }
546 546 }
547 547 return NULL;
548 548 }
549 549
550 550 bool PythonQtClassInfo::inherits(const char* name)
551 551 {
552 552 if (_wrappedClassName == name) {
553 553 return true;
554 554 }
555 555 foreach(const ParentClassInfo& info, _parentClasses) {
556 556 if (info._parent->inherits(name)) {
557 557 return true;
558 558 }
559 559 }
560 560 return false;
561 561 }
562 562
563 563 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
564 564 {
565 565 if (classInfo == this) {
566 566 return true;
567 567 }
568 568 foreach(const ParentClassInfo& info, _parentClasses) {
569 569 if (info._parent->inherits(classInfo)) {
570 570 return true;
571 571 }
572 572 }
573 573 return false;
574 574 }
575 575
576 576 QString PythonQtClassInfo::help()
577 577 {
578 578 decorator();
579 579 QString h;
580 580 h += QString("--- ") + QString(className()) + QString(" ---\n");
581 581
582 582 if (_isQObject) {
583 583 h += "Properties:\n";
584 584
585 585 int i;
586 586 int numProperties = _meta->propertyCount();
587 587 for (i = 0; i < numProperties; i++) {
588 588 QMetaProperty p = _meta->property(i);
589 589 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
590 590 }
591 591 }
592 592
593 593 if (constructors()) {
594 594 h += "Constructors:\n";
595 595 PythonQtSlotInfo* constr = constructors();
596 596 while (constr) {
597 597 h += constr->fullSignature() + "\n";
598 598 constr = constr->nextInfo();
599 599 }
600 600 }
601 601
602 602 h += "Slots:\n";
603 603 h += "QString help()\n";
604 604 h += "QString className()\n";
605 605
606 606 if (_meta) {
607 607 int numMethods = _meta->methodCount();
608 608 for (int i = 0; i < numMethods; i++) {
609 609 QMetaMethod m = _meta->method(i);
610 610 if ((m.methodType() == QMetaMethod::Method ||
611 611 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
612 612 PythonQtSlotInfo slot(this, m, i);
613 613 h += slot.fullSignature()+ "\n";
614 614 }
615 615 }
616 616 }
617 617
618 618 // TODO xxx : decorators and enums from decorator() are missing...
619 619 // maybe we can reuse memberlist()?
620 620
621 621 if (_meta && _meta->enumeratorCount()) {
622 622 h += "Enums:\n";
623 623 for (int i = 0; i<_meta->enumeratorCount(); i++) {
624 624 QMetaEnum e = _meta->enumerator(i);
625 625 h += QString(e.name()) + " {";
626 626 for (int j=0; j < e.keyCount(); j++) {
627 627 if (j) { h+= ", "; }
628 628 h += e.key(j);
629 629 }
630 630 h += " }\n";
631 631 }
632 632 }
633 633
634 634 if (_isQObject && _meta) {
635 635 int numMethods = _meta->methodCount();
636 636 if (numMethods>0) {
637 637 h += "Signals:\n";
638 638 for (int i = 0; i < numMethods; i++) {
639 639 QMetaMethod m = _meta->method(i);
640 640 if (m.methodType() == QMetaMethod::Signal) {
641 641 h += QString(m.signature()) + "\n";
642 642 }
643 643 }
644 644 }
645 645 }
646 646 return h;
647 647 }
648 648
649 649 PythonQtSlotInfo* PythonQtClassInfo::constructors()
650 650 {
651 651 if (!_constructors) {
652 652 // force creation of lazy decorator, which will register the decorators
653 653 decorator();
654 654 }
655 655 return _constructors;
656 656 }
657 657
658 658 PythonQtSlotInfo* PythonQtClassInfo::destructor()
659 659 {
660 660 if (!_destructor) {
661 661 // force creation of lazy decorator, which will register the decorators
662 662 decorator();
663 663 }
664 664 return _destructor;
665 665 }
666 666
667 667 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
668 668 {
669 669 PythonQtSlotInfo* prev = constructors();
670 670 if (prev) {
671 671 info->setNextInfo(prev->nextInfo());
672 672 prev->setNextInfo(info);
673 673 } else {
674 674 _constructors = info;
675 675 }
676 676 }
677 677
678 678 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
679 679 {
680 680 _decoratorSlots.append(info);
681 681 }
682 682
683 683 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
684 684 {
685 685 if (_destructor) {
686 686 _destructor->deleteOverloadsAndThis();
687 687 }
688 688 _destructor = info;
689 689 }
690 690
691 691 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
692 692 {
693 693 _meta = meta;
694 694 clearCachedMembers();
695 695 }
696 696
697 697 QObject* PythonQtClassInfo::decorator()
698 698 {
699 699 if (!_decoratorProvider && _decoratorProviderCB) {
700 700 _decoratorProvider = (*_decoratorProviderCB)();
701 701 if (_decoratorProvider) {
702 702 _decoratorProvider->setParent(PythonQt::priv());
703 703 // setup enums early, since they might be needed by the constructor decorators:
704 704 if (!_enumsCreated) {
705 705 createEnumWrappers();
706 706 }
707 707 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
708 708 }
709 709 }
710 710 // check if enums need to be created and create them if they are not yet created
711 711 if (!_enumsCreated) {
712 712 createEnumWrappers();
713 713 }
714 714 return _decoratorProvider;
715 715 }
716 716
717 717 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
718 718 {
719 719 PythonQtMemberInfo info = member("py_hasOwner");
720 720 if (info._type == PythonQtMemberInfo::Slot) {
721 721 void* obj = object;
722 722 bool result = false;
723 723 void* args[2];
724 724 args[0] = &result;
725 725 args[1] = &obj;
726 726 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
727 727 return !result;
728 728 } else {
729 729 return false;
730 730 }
731 731 }
732 732
733 733 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
734 734 {
735 735 if (!_polymorphicHandlers.isEmpty()) {
736 736 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
737 737 void* resultPtr = (*cb)(ptr, resultClassName);
738 738 if (resultPtr) {
739 739 return resultPtr;
740 740 }
741 741 }
742 742 }
743 743 foreach(const ParentClassInfo& info, _parentClasses) {
744 744 if (!info._parent->isQObject()) {
745 745 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
746 746 if (resultPtr) {
747 747 return resultPtr;
748 748 }
749 749 }
750 750 }
751 751 return NULL;
752 752 }
753 753
754 754 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
755 755 {
756 756 char* className;
757 757 // this would do downcasting recursively...
758 758 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
759 759
760 760 // we only do downcasting on the base object, not on the whole inheritance tree...
761 761 void* resultPtr = NULL;
762 762 if (!_polymorphicHandlers.isEmpty()) {
763 763 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
764 764 resultPtr = (*cb)(ptr, &className);
765 765 if (resultPtr) {
766 766 break;
767 767 }
768 768 }
769 769 }
770 770 if (resultPtr) {
771 771 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
772 772 } else {
773 773 *resultClassInfo = this;
774 774 resultPtr = ptr;
775 775 }
776 776 return resultPtr;
777 777 }
778 778
779 779 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
780 780 {
781 781 if (isLocalEnum) {
782 782 *isLocalEnum = true;
783 783 }
784 784 int scopePos = name.lastIndexOf("::");
785 785 if (scopePos != -1) {
786 786 if (isLocalEnum) {
787 787 *isLocalEnum = false;
788 788 }
789 789 // split into scope and enum name
790 790 QByteArray enumScope = name.mid(0,scopePos);
791 791 QByteArray enumName = name.mid(scopePos+2);
792 792 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
793 793 if (info) {
794 794 return info->findEnumWrapper(enumName);
795 795 } else{
796 796 return NULL;
797 797 }
798 798 }
799 799 if (localScope) {
800 800 return localScope->findEnumWrapper(name);
801 801 } else {
802 802 return NULL;
803 803 }
804 804 }
805 805
806 806 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
807 807 {
808 808 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
809 809 QMetaEnum e = meta->enumerator(i);
810 810 PythonQtObjectPtr p;
811 811 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
812 812 _enumWrappers.append(p);
813 813 }
814 814 }
815 815
816 816 void PythonQtClassInfo::createEnumWrappers()
817 817 {
818 818 if (!_enumsCreated) {
819 819 _enumsCreated = true;
820 820 if (_meta) {
821 821 createEnumWrappers(_meta);
822 822 }
823 823 if (decorator()) {
824 824 createEnumWrappers(decorator()->metaObject());
825 825 }
826 826 foreach(const ParentClassInfo& info, _parentClasses) {
827 827 info._parent->createEnumWrappers();
828 828 }
829 829 }
830 830 }
831 831
832 832 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
833 833 // force enum creation
834 834 if (!_enumsCreated) {
835 835 createEnumWrappers();
836 836 }
837 837 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
838 838 const char* className = ((PyTypeObject*)p.object())->tp_name;
839 839 if (qstrcmp(className, name)==0) {
840 840 return p.object();
841 841 }
842 842 }
843 843 foreach(const ParentClassInfo& info, _parentClasses) {
844 844 PyObject* p = info._parent->findEnumWrapper(name);
845 845 if (p) return p;
846 846 }
847 847 return NULL;
848 848 }
849 849
@@ -1,262 +1,262
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 53 _type = Slot;
54 54 _slot = info;
55 55 _enumValue = NULL;
56 56 }
57 57
58 58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 59 _type = EnumValue;
60 60 _slot = NULL;
61 61 _enumValue = enumValue;
62 62 _enumWrapper = NULL;
63 63 }
64 64
65 65 PythonQtMemberInfo(const QMetaProperty& prop) {
66 66 _type = Property;
67 67 _slot = NULL;
68 68 _enumValue = NULL;
69 69 _property = prop;
70 70 _enumWrapper = NULL;
71 71 }
72 72
73 73 Type _type;
74 74
75 75 // TODO: this could be a union...
76 76 PythonQtSlotInfo* _slot;
77 77 PyObject* _enumWrapper;
78 78 PythonQtObjectPtr _enumValue;
79 79 QMetaProperty _property;
80 80 };
81 81
82 82 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
83 83 /*! for fast lookup of slots when calling the object from Python
84 84 */
85 85 class PythonQtClassInfo {
86 86
87 87 public:
88 88 PythonQtClassInfo();
89 89 ~PythonQtClassInfo();
90 90
91 91 //! store information about parent classes
92 92 struct ParentClassInfo {
93 93 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
94 94 {};
95 95
96 96 PythonQtClassInfo* _parent;
97 97 int _upcastingOffset;
98 98 };
99 99
100 100
101 101 //! setup as a QObject, taking the meta object as meta information about the QObject
102 102 void setupQObject(const QMetaObject* meta);
103 103
104 104 //! setup as a CPP (non-QObject), taking the classname
105 105 void setupCPPObject(const QByteArray& classname);
106 106
107 107 //! set the type capabilities
108 108 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109 109 //! get the type capabilities
110 110 int typeSlots() const { return _typeSlots; }
111 111
112 112 //! get the Python method definition for a given slot name (without return type and signature)
113 113 PythonQtMemberInfo member(const char* member);
114 114
115 115 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
116 116 PythonQtSlotInfo* constructors();
117 117
118 118 //! get access to the destructor slot
119 119 PythonQtSlotInfo* destructor();
120 120
121 121 //! add a constructor, ownership is passed to classinfo
122 122 void addConstructor(PythonQtSlotInfo* info);
123 123
124 124 //! set a destructor, ownership is passed to classinfo
125 125 void setDestructor(PythonQtSlotInfo* info);
126 126
127 127 //! add a decorator slot, ownership is passed to classinfo
128 128 void addDecoratorSlot(PythonQtSlotInfo* info);
129 129
130 130 //! get the classname (either of the QObject or of the wrapped CPP object)
131 131 const char* className();
132 132
133 133 //! returns if the QObject
134 134 bool isQObject() { return _isQObject; }
135 135
136 136 //! returns if the class is a CPP wrapper
137 137 bool isCPPWrapper() { return !_isQObject; }
138 138
139 139 //! get the meta object
140 140 const QMetaObject* metaObject() { return _meta; }
141 141
142 142 //! set the meta object, this will reset the caching
143 143 void setMetaObject(const QMetaObject* meta);
144 144
145 145 //! returns if this class inherits from the given classname
146 146 bool inherits(const char* classname);
147 147
148 148 //! returns if this class inherits from the given classinfo
149 149 bool inherits(PythonQtClassInfo* info);
150 150
151 151 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
152 152 //! which might be different to \c ptr due to C++ multiple inheritance
153 153 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
154 154 void* castTo(void* ptr, const char* classname);
155 155
156 156 //! get help string for the metaobject
157 157 QString help();
158 158
159 159 //! get list of all properties (on QObjects only, otherwise the list is empty)
160 160 QStringList propertyList();
161 161
162 162 //! get list of all members
163 163 QStringList memberList(bool metaOnly = false);
164 164
165 165 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
166 166 int metaTypeId() { return _metaTypeId; }
167 167
168 168 //! set an additional decorator provider that offers additional decorator slots for this class
169 169 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
170 170
171 171 //! get the decorator qobject instance
172 172 QObject* decorator();
173 173
174 174 //! add the parent class info of a CPP object
175 175 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
176 176
177 177 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
178 178 bool hasOwnerMethodButNoOwner(void* object);
179 179
180 180 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
181 181 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
182 182
183 183 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
184 184 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
185 185
186 186 //! set the shell set instance wrapper cb
187 187 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
188 188 _shellSetInstanceWrapperCB = cb;
189 189 }
190 190
191 191 //! get the shell set instance wrapper cb
192 192 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
193 193 return _shellSetInstanceWrapperCB;
194 194 }
195 195
196 196 //! add a handler for polymorphic downcasting
197 197 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
198 198
199 199 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
200 200 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
201 201
202 202 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
203 203 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
204 204
205 205 private:
206 206 void createEnumWrappers();
207 207 void createEnumWrappers(const QMetaObject* meta);
208 208 PyObject* findEnumWrapper(const char* name);
209 209
210 210 //! clear all cached members
211 211 void clearCachedMembers();
212 212
213 213 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
214 214
215 215 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
216 216 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
217 217 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
218 218
219 219 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
220 220 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
221 221
222 222 bool lookForPropertyAndCache(const char* memberName);
223 223 bool lookForMethodAndCache(const char* memberName);
224 224 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
225 225
226 226 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
227 227 int findCharOffset(const char* sigStart, char someChar);
228 228
229 229 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
230 230
231 231 PythonQtSlotInfo* _constructors;
232 232 PythonQtSlotInfo* _destructor;
233 233 QList<PythonQtSlotInfo*> _decoratorSlots;
234 234
235 235 QList<PythonQtObjectPtr> _enumWrappers;
236 236
237 237 const QMetaObject* _meta;
238 238
239 239 QByteArray _wrappedClassName;
240 240 QList<ParentClassInfo> _parentClasses;
241 241
242 242 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
243 243
244 244 QObject* _decoratorProvider;
245 245 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
246 246
247 247 PyObject* _pythonQtClassWrapper;
248 248
249 249 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
250 250
251 251 int _metaTypeId;
252 252 int _typeSlots;
253 253
254 254 bool _isQObject;
255 255 bool _enumsCreated;
256 256
257 257 };
258 258
259 259 //---------------------------------------------------------------
260 260
261 261
262 262 #endif
@@ -1,454 +1,454
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtClassWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtInstanceWrapper.h"
50 50
51 51 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
52 52 {
53 53 PyObject* result = NULL;
54 54 static QByteArray memberName = "__invert__";
55 55 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
56 56 if (opSlot._type == PythonQtMemberInfo::Slot) {
57 57 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
58 58 }
59 59 return result;
60 60 }
61 61
62 62 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
63 63 {
64 64 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
65 65 if (result) {
66 66 static QByteArray memberName = "__nonzero__";
67 67 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
68 68 if (opSlot._type == PythonQtMemberInfo::Slot) {
69 69 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
70 70 if (resultObj == Py_False) {
71 71 result = 0;
72 72 }
73 73 Py_XDECREF(resultObj);
74 74 }
75 75 }
76 76 return result;
77 77 }
78 78
79 79
80 80 static PyObject* PythonQtInstanceWrapper_binaryfunc(PythonQtInstanceWrapper* wrapper, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
81 81 {
82 82 PyObject* result = NULL;
83 83 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
84 84 if (opSlot._type == PythonQtMemberInfo::Slot) {
85 85 // TODO get rid of tuple
86 86 PyObject* args = PyTuple_New(1);
87 87 Py_INCREF(other);
88 88 PyTuple_SET_ITEM(args, 0, other);
89 89 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
90 90 Py_DECREF(args);
91 91 if (!result && !fallbackOpName.isEmpty()) {
92 92 // try fallback if we did not get a result
93 93 result = PythonQtInstanceWrapper_binaryfunc(wrapper, other, fallbackOpName);
94 94 }
95 95 }
96 96 return result;
97 97 }
98 98
99 99 #define BINARY_OP(NAME) \
100 100 static PyObject* PythonQtInstanceWrapper_ ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
101 101 { \
102 102 static const QByteArray opName("__" #NAME "__"); \
103 103 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName); \
104 104 }
105 105
106 106 #define BINARY_OP_INPLACE(NAME) \
107 107 static PyObject* PythonQtInstanceWrapper_i ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
108 108 { \
109 109 static const QByteArray opName("__i" #NAME "__"); \
110 110 static const QByteArray fallbackName("__" #NAME "__"); \
111 111 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName, fallbackName); \
112 112 }
113 113
114 114 BINARY_OP(add)
115 115 BINARY_OP(sub)
116 116 BINARY_OP(mul)
117 117 BINARY_OP(div)
118 118 BINARY_OP(and)
119 119 BINARY_OP(or)
120 120 BINARY_OP(xor)
121 121 BINARY_OP(mod)
122 122 BINARY_OP(lshift)
123 123 BINARY_OP(rshift)
124 124
125 125 BINARY_OP_INPLACE(add)
126 126 BINARY_OP_INPLACE(sub)
127 127 BINARY_OP_INPLACE(mul)
128 128 BINARY_OP_INPLACE(div)
129 129 BINARY_OP_INPLACE(and)
130 130 BINARY_OP_INPLACE(or)
131 131 BINARY_OP_INPLACE(xor)
132 132 BINARY_OP_INPLACE(mod)
133 133 BINARY_OP_INPLACE(lshift)
134 134 BINARY_OP_INPLACE(rshift)
135 135
136 136 static void initializeSlots(PythonQtClassWrapper* wrap)
137 137 {
138 138 int typeSlots = wrap->classInfo()->typeSlots();
139 139 if (typeSlots) {
140 140 if (typeSlots & PythonQt::Type_Add) {
141 141 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
142 142 }
143 143 if (typeSlots & PythonQt::Type_Subtract) {
144 144 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
145 145 }
146 146 if (typeSlots & PythonQt::Type_Multiply) {
147 147 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
148 148 }
149 149 if (typeSlots & PythonQt::Type_Divide) {
150 150 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
151 151 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
152 152 }
153 153 if (typeSlots & PythonQt::Type_And) {
154 154 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
155 155 }
156 156 if (typeSlots & PythonQt::Type_Or) {
157 157 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
158 158 }
159 159 if (typeSlots & PythonQt::Type_Xor) {
160 160 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
161 161 }
162 162 if (typeSlots & PythonQt::Type_Mod) {
163 163 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
164 164 }
165 165 if (typeSlots & PythonQt::Type_LShift) {
166 166 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
167 167 }
168 168 if (typeSlots & PythonQt::Type_RShift) {
169 169 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
170 170 }
171 171
172 172 if (typeSlots & PythonQt::Type_InplaceAdd) {
173 173 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
174 174 }
175 175 if (typeSlots & PythonQt::Type_InplaceSubtract) {
176 176 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
177 177 }
178 178 if (typeSlots & PythonQt::Type_InplaceMultiply) {
179 179 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
180 180 }
181 181 if (typeSlots & PythonQt::Type_InplaceDivide) {
182 182 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
183 183 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
184 184 }
185 185 if (typeSlots & PythonQt::Type_InplaceAnd) {
186 186 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
187 187 }
188 188 if (typeSlots & PythonQt::Type_InplaceOr) {
189 189 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
190 190 }
191 191 if (typeSlots & PythonQt::Type_InplaceXor) {
192 192 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
193 193 }
194 194 if (typeSlots & PythonQt::Type_InplaceMod) {
195 195 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
196 196 }
197 197 if (typeSlots & PythonQt::Type_InplaceLShift) {
198 198 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
199 199 }
200 200 if (typeSlots & PythonQt::Type_InplaceRShift) {
201 201 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
202 202 }
203 203 if (typeSlots & PythonQt::Type_Invert) {
204 204 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
205 205 }
206 206 if (typeSlots & PythonQt::Type_NonZero) {
207 207 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
208 208 }
209 209 }
210 210 }
211 211
212 212 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
213 213 {
214 214 // call the default type alloc
215 215 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
216 216
217 217 // take current class type, if we are called via newPythonQtClassWrapper()
218 218 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
219 219 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
220 220 if (wrap->_classInfo) {
221 221 initializeSlots(wrap);
222 222 }
223 223
224 224 return obj;
225 225 }
226 226
227 227
228 228 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
229 229 {
230 230 // call the default type init
231 231 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
232 232 return -1;
233 233 }
234 234
235 235 // if we have no CPP class information, try our base class
236 236 if (!self->classInfo()) {
237 237 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
238 238
239 239 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
240 240 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
241 241 return -1;
242 242 }
243 243
244 244 // take the class info from the superType
245 245 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
246 246 }
247 247
248 248 return 0;
249 249 }
250 250
251 251 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
252 252 {
253 253 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
254 254 }
255 255
256 256 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
257 257 {
258 258 return PythonQt::self()->helpCalled(type->classInfo());
259 259 }
260 260
261 261 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args)
262 262 {
263 263 Py_ssize_t argc = PyTuple_Size(args);
264 264 if (argc>0) {
265 265 // we need to call __init__ of the instance
266 266 PyObject* self = PyTuple_GET_ITEM(args, 0);
267 267 if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) {
268 268 PyObject* newargs = PyTuple_New(argc-1);
269 269 for (int i = 0;i<argc-1; i++) {
270 270 PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1));
271 271 }
272 272 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
273 273 int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL);
274 274 Py_DECREF(newargs);
275 275 if (result==0) {
276 276 Py_INCREF(Py_None);
277 277 return Py_None;
278 278 } else {
279 279 // init failed!
280 280 }
281 281 } else {
282 282 // self not of correct type!
283 283 }
284 284 } else {
285 285 // wrong number of args
286 286 }
287 287 return NULL;
288 288 }
289 289
290 290 static PyMethodDef PythonQtClassWrapper_methods[] = {
291 291 {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS,
292 292 "Return the classname of the object"
293 293 },
294 294 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
295 295 "Return the classname of the object"
296 296 },
297 297 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
298 298 "Shows the help of available methods for this class"
299 299 },
300 300 {NULL, NULL, 0 , NULL} /* Sentinel */
301 301 };
302 302
303 303
304 304 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
305 305 {
306 306 const char *attributeName;
307 307 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
308 308
309 309 if ((attributeName = PyString_AsString(name)) == NULL) {
310 310 return NULL;
311 311 }
312 312 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
313 313 return NULL;
314 314 }
315 315
316 316 if (qstrcmp(attributeName, "__dict__")==0) {
317 317 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
318 318 if (!wrapper->classInfo()) {
319 319 Py_INCREF(dict);
320 320 return dict;
321 321 }
322 322 dict = PyDict_Copy(dict);
323 323
324 324 QStringList l = wrapper->classInfo()->memberList(false);
325 325 foreach (QString name, l) {
326 326 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
327 327 if (o) {
328 328 PyDict_SetItemString(dict, name.toLatin1().data(), o);
329 329 Py_DECREF(o);
330 330 } else {
331 331 // it must have been a property or child, which we do not know as a class object...
332 332 }
333 333 }
334 334 if (wrapper->classInfo()->constructors()) {
335 335 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj);
336 336 PyDict_SetItemString(dict, "__init__", func);
337 337 Py_DECREF(func);
338 338 }
339 339 for (int i = 1;i<3;i++) {
340 340 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
341 341 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
342 342 Py_DECREF(func);
343 343 }
344 344 return dict;
345 345 }
346 346
347 347 if (wrapper->classInfo()) {
348 348 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
349 349 if (member._type == PythonQtMemberInfo::EnumValue) {
350 350 PyObject* enumValue = member._enumValue;
351 351 Py_INCREF(enumValue);
352 352 return enumValue;
353 353 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
354 354 PyObject* enumWrapper = member._enumWrapper;
355 355 Py_INCREF(enumWrapper);
356 356 return enumWrapper;
357 357 } else if (member._type == PythonQtMemberInfo::Slot) {
358 358 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
359 359 return PythonQtSlotFunction_New(member._slot, obj, NULL);
360 360 }
361 361 }
362 362
363 363 // look for the interal methods (className(), help())
364 364 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
365 365 if (internalMethod) {
366 366 return internalMethod;
367 367 }
368 368 PyErr_Clear();
369 369
370 370 // look in super
371 371 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
372 372 if (superAttr) {
373 373 return superAttr;
374 374 }
375 375
376 376 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
377 377 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
378 378 return NULL;
379 379 }
380 380
381 381 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
382 382 {
383 383 return PyType_Type.tp_setattro(obj,name,value);
384 384 }
385 385
386 386 /*
387 387 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
388 388 {
389 389 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
390 390 if (wrapper->classInfo()->isCPPWrapper()) {
391 391 const QMetaObject* meta = wrapper->classInfo()->metaObject();
392 392 if (!meta) {
393 393 QObject* decorator = wrapper->classInfo()->decorator();
394 394 if (decorator) {
395 395 meta = decorator->metaObject();
396 396 }
397 397 }
398 398 if (meta) {
399 399 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
400 400 } else {
401 401 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
402 402 }
403 403 } else {
404 404 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
405 405 }
406 406 }
407 407
408 408 */
409 409
410 410 PyTypeObject PythonQtClassWrapper_Type = {
411 411 PyObject_HEAD_INIT(NULL)
412 412 0, /*ob_size*/
413 413 "PythonQt.PythonQtClassWrapper", /*tp_name*/
414 414 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
415 415 0, /*tp_itemsize*/
416 416 0, /*tp_dealloc*/
417 417 0, /*tp_print*/
418 418 0, /*tp_getattr*/
419 419 0, /*tp_setattr*/
420 420 0, /*tp_compare*/
421 421 0, //PythonQtClassWrapper_repr, /*tp_repr*/
422 422 0, /*tp_as_number*/
423 423 0, /*tp_as_sequence*/
424 424 0, /*tp_as_mapping*/
425 425 0, /*tp_hash */
426 426 0, /*tp_call*/
427 427 0, /*tp_str*/
428 428 PythonQtClassWrapper_getattro, /*tp_getattro*/
429 429 PythonQtClassWrapper_setattro, /*tp_setattro*/
430 430 0, /*tp_as_buffer*/
431 431 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
432 432 0, /* tp_doc */
433 433 0, /* tp_traverse */
434 434 0, /* tp_clear */
435 435 0, /* tp_richcompare */
436 436 0, /* tp_weaklistoffset */
437 437 0, /* tp_iter */
438 438 0, /* tp_iternext */
439 439 0, /* tp_methods */
440 440 0, /* tp_members */
441 441 0, /* tp_getset */
442 442 0, /* tp_base */
443 443 0, /* tp_dict */
444 444 0, /* tp_descr_get */
445 445 0, /* tp_descr_set */
446 446 0, /* tp_dictoffset */
447 447 (initproc)PythonQtClassWrapper_init, /* tp_init */
448 448 PythonQtClassWrapper_alloc, /* tp_alloc */
449 449 0, /* tp_new */
450 450 0, /* tp_free */
451 451 };
452 452
453 453 //-------------------------------------------------------
454 454
@@ -1,77 +1,77
1 1 #ifndef _PYTHONQTCLASSWRAPPER_H
2 2 #define _PYTHONQTCLASSWRAPPER_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtClassWrapper.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46
47 47 #include "PythonQtSystem.h"
48 48
49 49 #include "structmember.h"
50 50 #include "methodobject.h"
51 51 #include "compile.h"
52 52 #include "eval.h"
53 53 #include <QString>
54 54
55 55 class PythonQtClassInfo;
56 56
57 57 //! the type of the PythonQt class wrapper objects
58 58 extern PYTHONQT_EXPORT PyTypeObject PythonQtClassWrapper_Type;
59 59
60 60 //---------------------------------------------------------------
61 61 //! a Python wrapper object for PythonQt wrapped classes
62 62 //! which inherits from the Python type object to allow
63 63 //! deriving of wrapped CPP classes from Python.
64 64 typedef struct {
65 65 PyHeapTypeObject _base;
66 66
67 67 //! the additional class information that PythonQt stores for the CPP class
68 68 PythonQtClassInfo* _classInfo;
69 69
70 70 //! get the class info
71 71 PythonQtClassInfo* classInfo() { return _classInfo; }
72 72
73 73 } PythonQtClassWrapper;
74 74
75 75 //---------------------------------------------------------------
76 76
77 77 #endif
@@ -1,1228 +1,1228
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 63 // is it an enum value?
64 64 if (info.enumWrapper) {
65 65 if (!info.isPointer) {
66 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 67 } else {
68 68 // we do not support pointers to enums (who needs them?)
69 69 Py_INCREF(Py_None);
70 70 return Py_None;
71 71 }
72 72 }
73 73
74 74 if (info.typeId == QMetaType::Void) {
75 75 Py_INCREF(Py_None);
76 76 return Py_None;
77 77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
78 78 // a char ptr will probably be a null terminated string, so we support that:
79 79 return PyString_FromString(*((char**)data));
80 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 81 info.name.startsWith("QList<")) {
82 82 // it is a QList template:
83 83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
84 84 if (innerType.endsWith("*")) {
85 85 innerType.truncate(innerType.length()-1);
86 86 QList<void*>* listPtr;
87 87 if (info.isPointer) {
88 88 listPtr = *((QList<void*>**)data);
89 89 } else {
90 90 listPtr = (QList<void*>*)data;
91 91 }
92 92 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
93 93 }
94 94 }
95 95
96 96 if (info.typeId >= QMetaType::User) {
97 97 // if a converter is registered, we use is:
98 98 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
99 99 if (converter) {
100 100 return (*converter)(data, info.typeId);
101 101 }
102 102 }
103 103
104 104 // special handling did not match, so we convert the usual way (either pointer or value version):
105 105 if (info.isPointer) {
106 106 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
107 107 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
108 108 } else {
109 109 // handle values that are not yet handled and not pointers
110 110 return ConvertQtValueToPythonInternal(info.typeId, data);
111 111 }
112 112 }
113 113
114 114 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
115 115 switch (type) {
116 116 case QMetaType::Void:
117 117 Py_INCREF(Py_None);
118 118 return Py_None;
119 119 case QMetaType::Char:
120 120 return PyInt_FromLong(*((char*)data));
121 121 case QMetaType::UChar:
122 122 return PyInt_FromLong(*((unsigned char*)data));
123 123 case QMetaType::Short:
124 124 return PyInt_FromLong(*((short*)data));
125 125 case QMetaType::UShort:
126 126 return PyInt_FromLong(*((unsigned short*)data));
127 127 case QMetaType::Long:
128 128 return PyInt_FromLong(*((long*)data));
129 129 case QMetaType::ULong:
130 130 // does not fit into simple int of python
131 131 return PyLong_FromUnsignedLong(*((unsigned long*)data));
132 132 case QMetaType::Bool:
133 133 return PythonQtConv::GetPyBool(*((bool*)data));
134 134 case QMetaType::Int:
135 135 return PyInt_FromLong(*((int*)data));
136 136 case QMetaType::UInt:
137 137 // does not fit into simple int of python
138 138 return PyLong_FromUnsignedLong(*((unsigned int*)data));
139 139 case QMetaType::QChar:
140 140 return PyInt_FromLong(*((short*)data));
141 141 case QMetaType::Float:
142 142 return PyFloat_FromDouble(*((float*)data));
143 143 case QMetaType::Double:
144 144 return PyFloat_FromDouble(*((double*)data));
145 145 case QMetaType::LongLong:
146 146 return PyLong_FromLongLong(*((qint64*)data));
147 147 case QMetaType::ULongLong:
148 148 return PyLong_FromUnsignedLongLong(*((quint64*)data));
149 149 // implicit conversion from QByteArray to str has been removed:
150 150 //case QMetaType::QByteArray: {
151 151 // QByteArray* v = (QByteArray*) data;
152 152 // return PyString_FromStringAndSize(*v, v->size());
153 153 // }
154 154 case QMetaType::QVariantMap:
155 155 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
156 156 case QMetaType::QVariantList:
157 157 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
158 158 case QMetaType::QString:
159 159 return PythonQtConv::QStringToPyObject(*((QString*)data));
160 160 case QMetaType::QStringList:
161 161 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
162 162
163 163 case PythonQtMethodInfo::Variant:
164 164 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
165 165 case QMetaType::QObjectStar:
166 166 case QMetaType::QWidgetStar:
167 167 return PythonQt::priv()->wrapQObject(*((QObject**)data));
168 168
169 169 default:
170 170 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
171 171 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
172 172 PyObject* o = ((PythonQtObjectPtr*)data)->object();
173 173 Py_INCREF(o);
174 174 return o;
175 175 } else {
176 176 if (type > 0) {
177 177 // if the type is known, we can construct it via QMetaType::construct
178 178 void* newCPPObject = QMetaType::construct(type, data);
179 179 // XXX this could be optimized by using metatypeid directly
180 180 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
181 181 wrap->_ownedByPythonQt = true;
182 182 wrap->_useQMetaTypeDestroy = true;
183 183 return (PyObject*)wrap;
184 184 }
185 185 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
186 186 }
187 187 }
188 188 Py_INCREF(Py_None);
189 189 return Py_None;
190 190 }
191 191
192 192 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
193 193 void* ptr = NULL;
194 194 if (info.isPointer) {
195 195 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
196 196 } else if (info.enumWrapper) {
197 197 // create enum return value
198 198 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
199 199 } else {
200 200 switch (info.typeId) {
201 201 case QMetaType::Char:
202 202 case QMetaType::UChar:
203 203 case QMetaType::Short:
204 204 case QMetaType::UShort:
205 205 case QMetaType::Long:
206 206 case QMetaType::ULong:
207 207 case QMetaType::Bool:
208 208 case QMetaType::Int:
209 209 case QMetaType::UInt:
210 210 case QMetaType::QChar:
211 211 case QMetaType::Float:
212 212 case QMetaType::Double:
213 213 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
214 214 break;
215 215 case PythonQtMethodInfo::Variant:
216 216 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
217 217 // return the ptr to the variant
218 218 break;
219 219 default:
220 220 if (info.typeId == PythonQtMethodInfo::Unknown) {
221 221 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
222 222 if (info.name.startsWith("QList<")) {
223 223 QByteArray innerType = info.name.mid(6,info.name.length()-7);
224 224 if (innerType.endsWith("*")) {
225 225 static int id = QMetaType::type("QList<void*>");
226 226 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
227 227 // return the constData pointer that will be filled with the result value later on
228 228 ptr = (void*)((QVariant*)ptr)->constData();
229 229 }
230 230 }
231 231 }
232 232
233 233 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
234 234 // everything else is stored in a QVariant, if we know the meta type...
235 235 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
236 236 // return the constData pointer that will be filled with the result value later on
237 237 ptr = (void*)((QVariant*)ptr)->constData();
238 238 }
239 239 }
240 240 }
241 241 return ptr;
242 242 }
243 243
244 244 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
245 245 {
246 246 void* object;
247 247 if (wrapper->classInfo()->isCPPWrapper()) {
248 248 object = wrapper->_wrappedPtr;
249 249 } else {
250 250 QObject* tmp = wrapper->_obj;
251 251 object = tmp;
252 252 }
253 253 if (object) {
254 254 // if we can be upcasted to the given name, we pass the casted pointer in:
255 255 object = wrapper->classInfo()->castTo(object, className);
256 256 ok = object!=NULL;
257 257 } else {
258 258 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
259 259 ok = wrapper->classInfo()->inherits(className);
260 260 }
261 261 return object;
262 262 }
263 263
264 264 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
265 265 {
266 266 void* ptr = alreadyAllocatedCPPObject;
267 267
268 268 static int penId = QMetaType::type("QPen");
269 269 static int brushId = QMetaType::type("QBrush");
270 270 static int cursorId = QMetaType::type("QCursor");
271 271 static int colorId = QMetaType::type("QColor");
272 272 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
273 273 if (typeId == cursorId) {
274 274 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
275 275 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
276 276 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
277 277 if (!ptr) {
278 278 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
279 279 ptr = (void*)((QVariant*)ptr)->constData();
280 280 }
281 281 *((QCursor*)ptr) = QCursor(val);
282 282 return ptr;
283 283 }
284 284 } else if (typeId == penId) {
285 285 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
286 286 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
287 287 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
288 288 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
289 289 if (!ptr) {
290 290 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
291 291 ptr = (void*)((QVariant*)ptr)->constData();
292 292 }
293 293 *((QPen*)ptr) = QPen(QColor(val));
294 294 return ptr;
295 295 } else if ((PyObject*)obj->ob_type == qtColorClass) {
296 296 if (!ptr) {
297 297 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
298 298 ptr = (void*)((QVariant*)ptr)->constData();
299 299 }
300 300 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
301 301 return ptr;
302 302 }
303 303 } else if (typeId == brushId) {
304 304 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
305 305 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
306 306 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
307 307 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
308 308 if (!ptr) {
309 309 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
310 310 ptr = (void*)((QVariant*)ptr)->constData();
311 311 }
312 312 *((QBrush*)ptr) = QBrush(QColor(val));
313 313 return ptr;
314 314 } else if ((PyObject*)obj->ob_type == qtColorClass) {
315 315 if (!ptr) {
316 316 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
317 317 ptr = (void*)((QVariant*)ptr)->constData();
318 318 }
319 319 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
320 320 return ptr;
321 321 }
322 322 } else if (typeId == colorId) {
323 323 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
324 324 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
325 325 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
326 326 if (!ptr) {
327 327 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
328 328 ptr = (void*)((QVariant*)ptr)->constData();
329 329 }
330 330 *((QColor*)ptr) = QColor(val);
331 331 return ptr;
332 332 }
333 333 }
334 334 return NULL;
335 335 }
336 336
337 337 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
338 338 {
339 339 bool ok = false;
340 340 void* ptr = NULL;
341 341
342 342 // autoconversion of QPen/QBrush/QCursor/QColor from different type
343 343 if (!info.isPointer && !strict) {
344 344 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
345 345 if (ptr) {
346 346 return ptr;
347 347 }
348 348 }
349 349
350 350 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
351 351 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
352 352 // (the Variant case is handled below in a switch)
353 353
354 354 // a C++ wrapper (can be passed as pointer or reference)
355 355 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
356 356 void* object = castWrapperTo(wrap, info.name, ok);
357 357 if (ok) {
358 358 if (info.isPointer) {
359 359 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
360 360 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
361 361 } else {
362 362 // store the wrapped pointer directly, since we are a reference
363 363 ptr = object;
364 364 }
365 365 } else {
366 366 // not matching
367 367 }
368 368 } else if (info.isPointer) {
369 369 // a pointer
370 370 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
371 371 {
372 372 QString str = PyObjGetString(obj, strict, ok);
373 373 if (ok) {
374 374 void* ptr2 = NULL;
375 375 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
376 376 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
377 377 }
378 378 } else if (info.name == "PyObject") {
379 379 // handle low level PyObject directly
380 380 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
381 381 } else if (obj == Py_None) {
382 382 // None is treated as a NULL ptr
383 383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
384 384 } else {
385 385 // if we are not strict, we try if we are passed a 0 integer
386 386 if (!strict) {
387 387 bool ok;
388 388 int value = PyObjGetInt(obj, true, ok);
389 389 if (ok && value==0) {
390 390 // TODOXXX is this wise? or should it be expected from the programmer to use None?
391 391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
392 392 }
393 393 }
394 394 }
395 395 } else {
396 396 // not a pointer
397 397 switch (info.typeId) {
398 398 case QMetaType::Char:
399 399 {
400 400 int val = PyObjGetInt(obj, strict, ok);
401 401 if (ok) {
402 402 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
403 403 }
404 404 }
405 405 break;
406 406 case QMetaType::UChar:
407 407 {
408 408 int val = PyObjGetInt(obj, strict, ok);
409 409 if (ok) {
410 410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
411 411 }
412 412 }
413 413 break;
414 414 case QMetaType::Short:
415 415 {
416 416 int val = PyObjGetInt(obj, strict, ok);
417 417 if (ok) {
418 418 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
419 419 }
420 420 }
421 421 break;
422 422 case QMetaType::UShort:
423 423 {
424 424 int val = PyObjGetInt(obj, strict, ok);
425 425 if (ok) {
426 426 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
427 427 }
428 428 }
429 429 break;
430 430 case QMetaType::Long:
431 431 {
432 432 long val = (long)PyObjGetLongLong(obj, strict, ok);
433 433 if (ok) {
434 434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
435 435 }
436 436 }
437 437 break;
438 438 case QMetaType::ULong:
439 439 {
440 440 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
441 441 if (ok) {
442 442 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
443 443 }
444 444 }
445 445 break;
446 446 case QMetaType::Bool:
447 447 {
448 448 bool val = PyObjGetBool(obj, strict, ok);
449 449 if (ok) {
450 450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
451 451 }
452 452 }
453 453 break;
454 454 case QMetaType::Int:
455 455 {
456 456 int val = PyObjGetInt(obj, strict, ok);
457 457 if (ok) {
458 458 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
459 459 }
460 460 }
461 461 break;
462 462 case QMetaType::UInt:
463 463 {
464 464 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
465 465 if (ok) {
466 466 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
467 467 }
468 468 }
469 469 break;
470 470 case QMetaType::QChar:
471 471 {
472 472 int val = PyObjGetInt(obj, strict, ok);
473 473 if (ok) {
474 474 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
475 475 }
476 476 }
477 477 break;
478 478 case QMetaType::Float:
479 479 {
480 480 float val = (float)PyObjGetDouble(obj, strict, ok);
481 481 if (ok) {
482 482 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
483 483 }
484 484 }
485 485 break;
486 486 case QMetaType::Double:
487 487 {
488 488 double val = (double)PyObjGetDouble(obj, strict, ok);
489 489 if (ok) {
490 490 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
491 491 }
492 492 }
493 493 break;
494 494 case QMetaType::LongLong:
495 495 {
496 496 qint64 val = PyObjGetLongLong(obj, strict, ok);
497 497 if (ok) {
498 498 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
499 499 }
500 500 }
501 501 break;
502 502 case QMetaType::ULongLong:
503 503 {
504 504 quint64 val = PyObjGetULongLong(obj, strict, ok);
505 505 if (ok) {
506 506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
507 507 }
508 508 }
509 509 break;
510 510 case QMetaType::QByteArray:
511 511 {
512 512 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
513 513 if (ok) {
514 514 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
515 515 ptr = (void*)((QVariant*)ptr)->constData();
516 516 }
517 517 }
518 518 break;
519 519 case QMetaType::QString:
520 520 {
521 521 QString str = PyObjGetString(obj, strict, ok);
522 522 if (ok) {
523 523 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
524 524 ptr = (void*)((QVariant*)ptr)->constData();
525 525 }
526 526 }
527 527 break;
528 528 case QMetaType::QStringList:
529 529 {
530 530 QStringList l = PyObjToStringList(obj, strict, ok);
531 531 if (ok) {
532 532 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
533 533 ptr = (void*)((QVariant*)ptr)->constData();
534 534 }
535 535 }
536 536 break;
537 537
538 538 case PythonQtMethodInfo::Variant:
539 539 {
540 540 QVariant v = PyObjToQVariant(obj);
541 541 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
542 542 // so we do not check v.isValid() here
543 543 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
544 544 }
545 545 break;
546 546 default:
547 547 {
548 548 // check for enum case
549 549 if (info.enumWrapper) {
550 550 unsigned int val;
551 551 ok = false;
552 552 if ((PyObject*)obj->ob_type == info.enumWrapper) {
553 553 // we have a exact enum type match:
554 554 val = PyInt_AS_LONG(obj);
555 555 ok = true;
556 556 } else if (!strict) {
557 557 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
558 558 // we want an integer overload to be taken first!
559 559 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
560 560 }
561 561 if (ok) {
562 562 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
563 563 return ptr;
564 564 } else {
565 565 return NULL;
566 566 }
567 567 }
568 568
569 569 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
570 570 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
571 571 if (info.name.startsWith("QList<")) {
572 572 QByteArray innerType = info.name.mid(6,info.name.length()-7);
573 573 if (innerType.endsWith("*")) {
574 574 innerType.truncate(innerType.length()-1);
575 575 static int id = QMetaType::type("QList<void*>");
576 576 if (!alreadyAllocatedCPPObject) {
577 577 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
578 578 ptr = (void*)((QVariant*)ptr)->constData();
579 579 } else {
580 580 ptr = alreadyAllocatedCPPObject;
581 581 }
582 582 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
583 583 if (ok) {
584 584 return ptr;
585 585 } else {
586 586 return NULL;
587 587 }
588 588 }
589 589 }
590 590 }
591 591
592 592 // We only do this for registered type > QMetaType::User for performance reasons.
593 593 if (info.typeId >= QMetaType::User) {
594 594 // Maybe we have a special converter that is registered for that type:
595 595 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
596 596 if (converter) {
597 597 if (!alreadyAllocatedCPPObject) {
598 598 // create a new empty variant of concrete type:
599 599 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
600 600 ptr = (void*)((QVariant*)ptr)->constData();
601 601 } else {
602 602 ptr = alreadyAllocatedCPPObject;
603 603 }
604 604 // now call the converter, passing the internal object of the variant
605 605 ok = (*converter)(obj, ptr, info.typeId, strict);
606 606 if (ok) {
607 607 return ptr;
608 608 } else {
609 609 return NULL;
610 610 }
611 611 }
612 612 }
613 613 // if no type id is available, conversion to a QVariant makes no sense/is not possible
614 614 if (info.typeId != PythonQtMethodInfo::Unknown) {
615 615 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
616 616 QVariant v = PyObjToQVariant(obj, info.typeId);
617 617 if (v.isValid()) {
618 618 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
619 619 ptr = (void*)((QVariant*)ptr)->constData();
620 620 }
621 621 }
622 622 }
623 623 }
624 624 }
625 625 return ptr;
626 626 }
627 627
628 628
629 629 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
630 630 QStringList v;
631 631 ok = false;
632 632 // if we are strict, we do not want to convert a string to a stringlist
633 633 // (strings in python are detected to be sequences)
634 634 if (strict &&
635 635 (val->ob_type == &PyString_Type ||
636 636 PyUnicode_Check(val))) {
637 637 ok = false;
638 638 return v;
639 639 }
640 640 if (PySequence_Check(val)) {
641 641 int count = PySequence_Size(val);
642 642 for (int i = 0;i<count;i++) {
643 643 PyObject* value = PySequence_GetItem(val,i);
644 644 v.append(PyObjGetString(value,false,ok));
645 645 }
646 646 ok = true;
647 647 }
648 648 return v;
649 649 }
650 650
651 651 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
652 652 {
653 653 QString r;
654 654 PyObject* str = PyObject_Repr(val);
655 655 if (str) {
656 656 r = QString(PyString_AS_STRING(str));
657 657 Py_DECREF(str);
658 658 }
659 659 return r;
660 660 }
661 661
662 662 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
663 663 QString r;
664 664 ok = true;
665 665 if (val->ob_type == &PyString_Type) {
666 666 r = QString(PyString_AS_STRING(val));
667 667 } else if (PyUnicode_Check(val)) {
668 668 #ifdef WIN32
669 669 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
670 670 #else
671 671 PyObject *ptmp = PyUnicode_AsUTF8String(val);
672 672 if(ptmp) {
673 673 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
674 674 Py_DECREF(ptmp);
675 675 }
676 676 #endif
677 677 } else if (!strict) {
678 678 // EXTRA: could also use _Unicode, but why should we?
679 679 PyObject* str = PyObject_Str(val);
680 680 if (str) {
681 681 r = QString(PyString_AS_STRING(str));
682 682 Py_DECREF(str);
683 683 } else {
684 684 ok = false;
685 685 }
686 686 } else {
687 687 ok = false;
688 688 }
689 689 return r;
690 690 }
691 691
692 692 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
693 693 // TODO: support buffer objects in general
694 694 QByteArray r;
695 695 ok = true;
696 696 if (val->ob_type == &PyString_Type) {
697 697 long size = PyString_GET_SIZE(val);
698 698 r = QByteArray(PyString_AS_STRING(val), size);
699 699 } else {
700 700 ok = false;
701 701 }
702 702 return r;
703 703 }
704 704
705 705 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
706 706 bool d = false;
707 707 ok = false;
708 708 if (val == Py_False) {
709 709 d = false;
710 710 ok = true;
711 711 } else if (val == Py_True) {
712 712 d = true;
713 713 ok = true;
714 714 } else if (!strict) {
715 715 d = PyObjGetInt(val, false, ok)!=0;
716 716 ok = true;
717 717 }
718 718 return d;
719 719 }
720 720
721 721 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
722 722 int d = 0;
723 723 ok = true;
724 724 if (val->ob_type == &PyInt_Type) {
725 725 d = PyInt_AS_LONG(val);
726 726 } else if (!strict) {
727 727 if (PyObject_TypeCheck(val, &PyInt_Type)) {
728 728 // support for derived int classes, e.g. for our enums
729 729 d = PyInt_AS_LONG(val);
730 730 } else if (val->ob_type == &PyFloat_Type) {
731 731 d = floor(PyFloat_AS_DOUBLE(val));
732 732 } else if (val->ob_type == &PyLong_Type) {
733 733 // handle error on overflow!
734 734 d = PyLong_AsLong(val);
735 735 } else if (val == Py_False) {
736 736 d = 0;
737 737 } else if (val == Py_True) {
738 738 d = 1;
739 739 } else {
740 740 ok = false;
741 741 }
742 742 } else {
743 743 ok = false;
744 744 }
745 745 return d;
746 746 }
747 747
748 748 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
749 749 qint64 d = 0;
750 750 ok = true;
751 751 if (val->ob_type == &PyInt_Type) {
752 752 d = PyInt_AS_LONG(val);
753 753 } else if (val->ob_type == &PyLong_Type) {
754 754 d = PyLong_AsLongLong(val);
755 755 } else if (!strict) {
756 756 if (PyObject_TypeCheck(val, &PyInt_Type)) {
757 757 // support for derived int classes, e.g. for our enums
758 758 d = PyInt_AS_LONG(val);
759 759 } else if (val->ob_type == &PyFloat_Type) {
760 760 d = floor(PyFloat_AS_DOUBLE(val));
761 761 } else if (val == Py_False) {
762 762 d = 0;
763 763 } else if (val == Py_True) {
764 764 d = 1;
765 765 } else {
766 766 ok = false;
767 767 }
768 768 } else {
769 769 ok = false;
770 770 }
771 771 return d;
772 772 }
773 773
774 774 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
775 775 quint64 d = 0;
776 776 ok = true;
777 777 if (PyObject_TypeCheck(val, &PyInt_Type)) {
778 778 d = PyInt_AS_LONG(val);
779 779 } else if (val->ob_type == &PyLong_Type) {
780 780 d = PyLong_AsLongLong(val);
781 781 } else if (!strict) {
782 782 if (PyObject_TypeCheck(val, &PyInt_Type)) {
783 783 // support for derived int classes, e.g. for our enums
784 784 d = PyInt_AS_LONG(val);
785 785 } else if (val->ob_type == &PyFloat_Type) {
786 786 d = floor(PyFloat_AS_DOUBLE(val));
787 787 } else if (val == Py_False) {
788 788 d = 0;
789 789 } else if (val == Py_True) {
790 790 d = 1;
791 791 } else {
792 792 ok = false;
793 793 }
794 794 } else {
795 795 ok = false;
796 796 }
797 797 return d;
798 798 }
799 799
800 800 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
801 801 double d = 0;
802 802 ok = true;
803 803 if (val->ob_type == &PyFloat_Type) {
804 804 d = PyFloat_AS_DOUBLE(val);
805 805 } else if (!strict) {
806 806 if (PyObject_TypeCheck(val, &PyInt_Type)) {
807 807 d = PyInt_AS_LONG(val);
808 808 } else if (val->ob_type == &PyLong_Type) {
809 809 d = PyLong_AsLong(val);
810 810 } else if (val == Py_False) {
811 811 d = 0;
812 812 } else if (val == Py_True) {
813 813 d = 1;
814 814 } else {
815 815 ok = false;
816 816 }
817 817 } else {
818 818 ok = false;
819 819 }
820 820 return d;
821 821 }
822 822
823 823 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
824 824 {
825 825 QVariant v;
826 826 bool ok = true;
827 827
828 828 if (type==-1) {
829 829 // no special type requested
830 830 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
831 831 type = QVariant::String;
832 832 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
833 833 type = QVariant::Int;
834 834 } else if (val->ob_type==&PyLong_Type) {
835 835 type = QVariant::LongLong;
836 836 } else if (val->ob_type==&PyFloat_Type) {
837 837 type = QVariant::Double;
838 838 } else if (val == Py_False || val == Py_True) {
839 839 type = QVariant::Bool;
840 840 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
841 841 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
842 842 // c++ wrapper, check if the class names of the c++ objects match
843 843 if (wrap->classInfo()->isCPPWrapper()) {
844 844 if (wrap->classInfo()->metaTypeId()>0) {
845 845 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
846 846 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
847 847 } else {
848 848 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
849 849 // the pointer here...
850 850 // is this worth anything? we loose the knowledge of the cpp object type
851 851 v = qVariantFromValue(wrap->_wrappedPtr);
852 852 }
853 853 } else {
854 854 // this gives us a QObject pointer
855 855 QObject* myObject = wrap->_obj;
856 856 v = qVariantFromValue(myObject);
857 857 }
858 858 return v;
859 859 } else if (val->ob_type==&PyDict_Type) {
860 860 type = QVariant::Map;
861 861 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
862 862 type = QVariant::List;
863 863 } else if (val == Py_None) {
864 864 // none is invalid
865 865 type = QVariant::Invalid;
866 866 } else {
867 867 // this used to be:
868 868 // type = QVariant::String;
869 869 // but now we want to transport the Python Objects directly:
870 870 PythonQtObjectPtr o(val);
871 871 v = qVariantFromValue(o);
872 872 return v;
873 873 }
874 874 }
875 875 // special type request:
876 876 switch (type) {
877 877 case QVariant::Invalid:
878 878 return v;
879 879 break;
880 880 case QVariant::Int:
881 881 {
882 882 int d = PyObjGetInt(val, false, ok);
883 883 if (ok) return QVariant(d);
884 884 }
885 885 break;
886 886 case QVariant::UInt:
887 887 {
888 888 int d = PyObjGetInt(val, false,ok);
889 889 if (ok) v = QVariant((unsigned int)d);
890 890 }
891 891 break;
892 892 case QVariant::Bool:
893 893 {
894 894 int d = PyObjGetBool(val,false,ok);
895 895 if (ok) v = QVariant((bool)(d!=0));
896 896 }
897 897 break;
898 898 case QVariant::Double:
899 899 {
900 900 double d = PyObjGetDouble(val,false,ok);
901 901 if (ok) v = QVariant(d);
902 902 break;
903 903 }
904 904 case QMetaType::Float:
905 905 {
906 906 float d = (float) PyObjGetDouble(val,false,ok);
907 907 if (ok) v = qVariantFromValue(d);
908 908 break;
909 909 }
910 910 case QMetaType::Long:
911 911 {
912 912 long d = (long) PyObjGetLongLong(val,false,ok);
913 913 if (ok) v = qVariantFromValue(d);
914 914 break;
915 915 }
916 916 case QMetaType::ULong:
917 917 {
918 918 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
919 919 if (ok) v = qVariantFromValue(d);
920 920 break;
921 921 }
922 922 case QMetaType::LongLong:
923 923 {
924 924 qint64 d = PyObjGetLongLong(val, false, ok);
925 925 if (ok) v = qVariantFromValue(d);
926 926 }
927 927 break;
928 928 case QMetaType::ULongLong:
929 929 {
930 930 quint64 d = PyObjGetULongLong(val, false, ok);
931 931 if (ok) v = qVariantFromValue(d);
932 932 }
933 933 break;
934 934 case QMetaType::Short:
935 935 {
936 936 short d = (short) PyObjGetInt(val,false,ok);
937 937 if (ok) v = qVariantFromValue(d);
938 938 break;
939 939 }
940 940 case QMetaType::UShort:
941 941 {
942 942 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
943 943 if (ok) v = qVariantFromValue(d);
944 944 break;
945 945 }
946 946 case QMetaType::Char:
947 947 {
948 948 char d = (char) PyObjGetInt(val,false,ok);
949 949 if (ok) v = qVariantFromValue(d);
950 950 break;
951 951 }
952 952 case QMetaType::UChar:
953 953 {
954 954 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
955 955 if (ok) v = qVariantFromValue(d);
956 956 break;
957 957 }
958 958
959 959 case QVariant::ByteArray:
960 960 case QVariant::String:
961 961 {
962 962 bool ok;
963 963 v = QVariant(PyObjGetString(val, false, ok));
964 964 }
965 965 break;
966 966
967 967 // these are important for MeVisLab
968 968 case QVariant::Map:
969 969 {
970 970 if (PyMapping_Check(val)) {
971 971 QMap<QString,QVariant> map;
972 972 PyObject* items = PyMapping_Items(val);
973 973 if (items) {
974 974 int count = PyList_Size(items);
975 975 PyObject* value;
976 976 PyObject* key;
977 977 PyObject* tuple;
978 978 for (int i = 0;i<count;i++) {
979 979 tuple = PyList_GetItem(items,i);
980 980 key = PyTuple_GetItem(tuple, 0);
981 981 value = PyTuple_GetItem(tuple, 1);
982 982 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
983 983 }
984 984 Py_DECREF(items);
985 985 v = map;
986 986 }
987 987 }
988 988 }
989 989 break;
990 990 case QVariant::List:
991 991 if (PySequence_Check(val)) {
992 992 QVariantList list;
993 993 int count = PySequence_Size(val);
994 994 PyObject* value;
995 995 for (int i = 0;i<count;i++) {
996 996 value = PySequence_GetItem(val,i);
997 997 list.append(PyObjToQVariant(value, -1));
998 998 }
999 999 v = list;
1000 1000 }
1001 1001 break;
1002 1002 case QVariant::StringList:
1003 1003 {
1004 1004 bool ok;
1005 1005 QStringList l = PyObjToStringList(val, false, ok);
1006 1006 if (ok) {
1007 1007 v = l;
1008 1008 }
1009 1009 }
1010 1010 break;
1011 1011
1012 1012 default:
1013 1013 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1014 1014 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1015 1015 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1016 1016 // construct a new variant from the C++ object if it has the same meta type
1017 1017 v = QVariant(type, wrap->_wrappedPtr);
1018 1018 } else {
1019 1019 v = QVariant();
1020 1020 }
1021 1021 } else {
1022 1022 v = QVariant();
1023 1023 }
1024 1024 }
1025 1025 return v;
1026 1026 }
1027 1027
1028 1028 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1029 1029 {
1030 1030 if (str.isNull()) {
1031 1031 return PyString_FromString("");
1032 1032 } else {
1033 1033 #ifdef WIN32
1034 1034 // return PyString_FromString(str.toLatin1().data());
1035 1035 return PyUnicode_FromUnicode(str.utf16(), str.length());
1036 1036 #else
1037 1037 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1038 1038 #endif
1039 1039 }
1040 1040 }
1041 1041
1042 1042 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1043 1043 {
1044 1044 PyObject* result = PyTuple_New(list.count());
1045 1045 int i = 0;
1046 1046 QString str;
1047 1047 foreach (str, list) {
1048 1048 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1049 1049 i++;
1050 1050 }
1051 1051 // why is the error state bad after this?
1052 1052 PyErr_Clear();
1053 1053 return result;
1054 1054 }
1055 1055
1056 1056 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1057 1057 {
1058 1058 PyObject* result = PyList_New(list.count());
1059 1059 int i = 0;
1060 1060 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1061 1061 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1062 1062 i++;
1063 1063 }
1064 1064 return result;
1065 1065 }
1066 1066
1067 1067 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1068 1068 {
1069 1069 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1070 1070 }
1071 1071
1072 1072 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1073 1073 PyObject* result = PyDict_New();
1074 1074 QVariantMap::const_iterator t = m.constBegin();
1075 1075 PyObject* key;
1076 1076 PyObject* val;
1077 1077 for (;t!=m.end();t++) {
1078 1078 key = QStringToPyObject(t.key());
1079 1079 val = QVariantToPyObject(t.value());
1080 1080 PyDict_SetItem(result, key, val);
1081 1081 Py_DECREF(key);
1082 1082 Py_DECREF(val);
1083 1083 }
1084 1084 return result;
1085 1085 }
1086 1086
1087 1087 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1088 1088 PyObject* result = PyTuple_New(l.count());
1089 1089 int i = 0;
1090 1090 QVariant v;
1091 1091 foreach (v, l) {
1092 1092 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1093 1093 i++;
1094 1094 }
1095 1095 // why is the error state bad after this?
1096 1096 PyErr_Clear();
1097 1097 return result;
1098 1098 }
1099 1099
1100 1100 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1101 1101 {
1102 1102 PyObject* result = PyTuple_New(list->count());
1103 1103 int i = 0;
1104 1104 foreach (void* value, *list) {
1105 1105 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1106 1106 i++;
1107 1107 }
1108 1108 return result;
1109 1109 }
1110 1110
1111 1111 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1112 1112 {
1113 1113 bool result = false;
1114 1114 if (PySequence_Check(obj)) {
1115 1115 result = true;
1116 1116 int count = PySequence_Size(obj);
1117 1117 PyObject* value;
1118 1118 for (int i = 0;i<count;i++) {
1119 1119 value = PySequence_GetItem(obj,i);
1120 1120 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1121 1121 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1122 1122 bool ok;
1123 1123 void* object = castWrapperTo(wrap, type, ok);
1124 1124 if (ok) {
1125 1125 list->append(object);
1126 1126 } else {
1127 1127 result = false;
1128 1128 break;
1129 1129 }
1130 1130 }
1131 1131 }
1132 1132 }
1133 1133 return result;
1134 1134 }
1135 1135
1136 1136 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1137 1137 {
1138 1138 int idx = typeName.indexOf("<");
1139 1139 if (idx>0) {
1140 1140 int idx2 = typeName.indexOf(">");
1141 1141 if (idx2>0) {
1142 1142 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1143 1143 return QMetaType::type(innerType.constData());
1144 1144 }
1145 1145 }
1146 1146 return QMetaType::Void;
1147 1147 }
1148 1148
1149 1149
1150 1150 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1151 1151 QString r;
1152 1152 switch (type) {
1153 1153 case QVariant::Size: {
1154 1154 const QSize* s = static_cast<const QSize*>(data);
1155 1155 r = QString::number(s->width()) + ", " + QString::number(s->height());
1156 1156 }
1157 1157 break;
1158 1158 case QVariant::SizeF: {
1159 1159 const QSizeF* s = static_cast<const QSizeF*>(data);
1160 1160 r = QString::number(s->width()) + ", " + QString::number(s->height());
1161 1161 }
1162 1162 break;
1163 1163 case QVariant::Point: {
1164 1164 const QPoint* s = static_cast<const QPoint*>(data);
1165 1165 r = QString::number(s->x()) + ", " + QString::number(s->y());
1166 1166 }
1167 1167 break;
1168 1168 case QVariant::PointF: {
1169 1169 const QPointF* s = static_cast<const QPointF*>(data);
1170 1170 r = QString::number(s->x()) + ", " + QString::number(s->y());
1171 1171 }
1172 1172 break;
1173 1173 case QVariant::Rect: {
1174 1174 const QRect* s = static_cast<const QRect*>(data);
1175 1175 r = QString::number(s->x()) + ", " + QString::number(s->y());
1176 1176 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1177 1177 }
1178 1178 break;
1179 1179 case QVariant::RectF: {
1180 1180 const QRectF* s = static_cast<const QRectF*>(data);
1181 1181 r = QString::number(s->x()) + ", " + QString::number(s->y());
1182 1182 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1183 1183 }
1184 1184 break;
1185 1185 case QVariant::Date: {
1186 1186 const QDate* s = static_cast<const QDate*>(data);
1187 1187 r = s->toString(Qt::ISODate);
1188 1188 }
1189 1189 break;
1190 1190 case QVariant::DateTime: {
1191 1191 const QDateTime* s = static_cast<const QDateTime*>(data);
1192 1192 r = s->toString(Qt::ISODate);
1193 1193 }
1194 1194 break;
1195 1195 case QVariant::Time: {
1196 1196 const QTime* s = static_cast<const QTime*>(data);
1197 1197 r = s->toString(Qt::ISODate);
1198 1198 }
1199 1199 break;
1200 1200 case QVariant::Pixmap:
1201 1201 {
1202 1202 const QPixmap* s = static_cast<const QPixmap*>(data);
1203 1203 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1204 1204 }
1205 1205 break;
1206 1206 case QVariant::Image:
1207 1207 {
1208 1208 const QImage* s = static_cast<const QImage*>(data);
1209 1209 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1210 1210 }
1211 1211 break;
1212 1212 case QVariant::Url:
1213 1213 {
1214 1214 const QUrl* s = static_cast<const QUrl*>(data);
1215 1215 r = s->toString();
1216 1216 }
1217 1217 break;
1218 1218 //TODO: add more printing for other variant types
1219 1219 default:
1220 1220 // this creates a copy, but that should not be expensive for typical simple variants
1221 1221 // (but we do not want to do this for our won user types!
1222 1222 if (type>0 && type < (int)QVariant::UserType) {
1223 1223 QVariant v(type, data);
1224 1224 r = v.toString();
1225 1225 }
1226 1226 }
1227 1227 return r;
1228 1228 }
@@ -1,210 +1,210
1 1 #ifndef _PYTHONQTCONVERSION_H
2 2 #define _PYTHONQTCONVERSION_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtConversion.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtMethodInfo.h"
49 49
50 50 #include <QWidget>
51 51 #include <QList>
52 52 #include <vector>
53 53
54 54 typedef PyObject* PythonQtConvertMetaTypeToPythonCB(const void* inObject, int metaTypeId);
55 55 typedef bool PythonQtConvertPythonToMetaTypeCB(PyObject* inObject, void* outObject, int metaTypeId, bool strict);
56 56
57 57 #define PythonQtRegisterListTemplateConverter(type, innertype) \
58 58 { int typeId = qRegisterMetaType<type<innertype> >(#type"<"#innertype">"); \
59 59 PythonQtConv::registerPythonToMetaTypeConverter(typeId, PythonQtConvertPythonListToListOfValueType<type<innertype>, innertype>); \
60 60 PythonQtConv::registerMetaTypeToPythonConverter(typeId, PythonQtConvertListOfValueTypeToPythonList<type<innertype>, innertype>); \
61 61 }
62 62
63 63 #define PythonQtRegisterToolClassesTemplateConverter(innertype) \
64 64 PythonQtRegisterListTemplateConverter(QList, innertype); \
65 65 PythonQtRegisterListTemplateConverter(QVector, innertype); \
66 66 PythonQtRegisterListTemplateConverter(std::vector, innertype);
67 67 // TODO: add QHash etc. here!
68 68
69 69 //! a static class that offers methods for type conversion
70 70 class PYTHONQT_EXPORT PythonQtConv {
71 71
72 72 public:
73 73
74 74 //! get a ref counted True or False Python object
75 75 static PyObject* GetPyBool(bool val);
76 76
77 77 //! converts the Qt parameter given in \c data, interpreting it as a \c info parameter, into a Python object,
78 78 static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data);
79 79
80 80 //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore)
81 81 static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject = NULL);
82 82
83 83 //! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall
84 84 static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info);
85 85
86 86 //! converts QString to Python string (unicode!)
87 87 static PyObject* QStringToPyObject(const QString& str);
88 88
89 89 //! converts QStringList to Python tuple
90 90 static PyObject* QStringListToPyObject(const QStringList& list);
91 91
92 92 //! converts QStringList to Python list
93 93 static PyObject* QStringListToPyList(const QStringList& list);
94 94
95 95 //! get string representation of py object
96 96 static QString PyObjGetRepresentation(PyObject* val);
97 97
98 98 //! get string value from py object
99 99 static QString PyObjGetString(PyObject* val) { bool ok; QString s = PyObjGetString(val, false, ok); return s; }
100 100 //! get string value from py object
101 101 static QString PyObjGetString(PyObject* val, bool strict, bool &ok);
102 102 //! get bytes from py object
103 103 static QByteArray PyObjGetBytes(PyObject* val, bool strict, bool &ok);
104 104 //! get int from py object
105 105 static int PyObjGetInt(PyObject* val, bool strict, bool &ok);
106 106 //! get int64 from py object
107 107 static qint64 PyObjGetLongLong(PyObject* val, bool strict, bool &ok);
108 108 //! get int64 from py object
109 109 static quint64 PyObjGetULongLong(PyObject* val, bool strict, bool &ok);
110 110 //! get double from py object
111 111 static double PyObjGetDouble(PyObject* val, bool strict, bool &ok);
112 112 //! get bool from py object
113 113 static bool PyObjGetBool(PyObject* val, bool strict, bool &ok);
114 114
115 115 //! create a string list from python sequence
116 116 static QStringList PyObjToStringList(PyObject* val, bool strict, bool& ok);
117 117
118 118 //! convert python object to qvariant, if type is given it will try to create a qvariant of that type, otherwise
119 119 //! it will guess from the python type
120 120 static QVariant PyObjToQVariant(PyObject* val, int type = -1);
121 121
122 122 //! convert QVariant from PyObject
123 123 static PyObject* QVariantToPyObject(const QVariant& v);
124 124
125 125 static PyObject* QVariantMapToPyObject(const QVariantMap& m);
126 126 static PyObject* QVariantListToPyObject(const QVariantList& l);
127 127
128 128 //! get human readable string from CPP object (when the metatype is known)
129 129 static QString CPPObjectToString(int type, const void* data);
130 130
131 131 //! register a converter callback from python to cpp for given metatype
132 132 static void registerPythonToMetaTypeConverter(int metaTypeId, PythonQtConvertPythonToMetaTypeCB* cb) { _pythonToMetaTypeConverters.insert(metaTypeId, cb); }
133 133
134 134 //! register a converter callback from cpp to python for given metatype
135 135 static void registerMetaTypeToPythonConverter(int metaTypeId, PythonQtConvertMetaTypeToPythonCB* cb) { _metaTypeToPythonConverters.insert(metaTypeId, cb); }
136 136
137 137 //! returns the inner type id of a simple template of the form SomeObject<InnerType>
138 138 static int getInnerTemplateMetaType(const QByteArray& typeName);
139 139
140 140 //! converts the Qt parameter given in \c data, interpreting it as a \c type registered qvariant/meta type, into a Python object,
141 141 static PyObject* ConvertQtValueToPythonInternal(int type, const void* data);
142 142
143 143 public:
144 144
145 145 static PythonQtValueStorage<qint64, 128> global_valueStorage;
146 146 static PythonQtValueStorage<void*, 128> global_ptrStorage;
147 147 static PythonQtValueStorage<QVariant, 32> global_variantStorage;
148 148
149 149 protected:
150 150 static QHash<int, PythonQtConvertMetaTypeToPythonCB*> _metaTypeToPythonConverters;
151 151 static QHash<int, PythonQtConvertPythonToMetaTypeCB*> _pythonToMetaTypeConverters;
152 152
153 153 //! handle automatic conversion of some special types (QColor, QBrush, ...)
154 154 static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject);
155 155
156 156 //! converts the list of pointers of given type to Python
157 157 static PyObject* ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& type);
158 158 //! tries to convert the python object to a QList of pointers to \c type objects, returns true on success
159 159 static bool ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool strict);
160 160
161 161 //! cast wrapper to given className if possible
162 162 static void* castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok);
163 163 };
164 164
165 165 template<class ListType, class T>
166 166 PyObject* PythonQtConvertListOfValueTypeToPythonList(const void* /*QList<T>* */ inList, int metaTypeId)
167 167 {
168 168 ListType* list = (ListType*)inList;
169 169 static const int innerType = PythonQtConv::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId)));
170 170 if (innerType == QVariant::Invalid) {
171 171 std::cerr << "PythonQtConvertListOfValueTypeToPythonList: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl;
172 172 }
173 173 PyObject* result = PyTuple_New(list->size());
174 174 int i = 0;
175 175 foreach (const T& value, *list) {
176 176 PyTuple_SET_ITEM(result, i, PythonQtConv::ConvertQtValueToPythonInternal(innerType, &value));
177 177 i++;
178 178 }
179 179 return result;
180 180 }
181 181
182 182 template<class ListType, class T>
183 183 bool PythonQtConvertPythonListToListOfValueType(PyObject* obj, void* /*QList<T>* */ outList, int metaTypeId, bool /*strict*/)
184 184 {
185 185 ListType* list = (ListType*)outList;
186 186 static const int innerType = PythonQtConv::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId)));
187 187 if (innerType == QVariant::Invalid) {
188 188 std::cerr << "PythonQtConvertPythonListToListOfValueType: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl;
189 189 }
190 190 bool result = false;
191 191 if (PySequence_Check(obj)) {
192 192 result = true;
193 193 int count = PySequence_Size(obj);
194 194 PyObject* value;
195 195 for (int i = 0;i<count;i++) {
196 196 value = PySequence_GetItem(obj,i);
197 197 // this is quite some overhead, but it avoids having another large switch...
198 198 QVariant v = PythonQtConv::PyObjToQVariant(value, innerType);
199 199 if (v.isValid()) {
200 200 list->push_back(qVariantValue<T>(v));
201 201 } else {
202 202 result = false;
203 203 break;
204 204 }
205 205 }
206 206 }
207 207 return result;
208 208 }
209 209
210 210 #endif
@@ -1,61 +1,61
1 1 #ifndef _PYTHONQTCPPWRAPPERFACTORY_H
2 2 #define _PYTHONQTCPPWRAPPERFACTORY_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtCppWrapperFactory.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 //! Factory interface for C++ classes that can be wrapped by QObject objects
46 46 /*! To create your own factory, derive PythonQtCppWrapperFactory and implement
47 47 the create() method.
48 48 A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
49 49 */
50 50 class PYTHONQT_EXPORT PythonQtCppWrapperFactory
51 51 {
52 52 public:
53 53 PythonQtCppWrapperFactory() {};
54 54 virtual ~PythonQtCppWrapperFactory() {};
55 55
56 56 //! create a wrapper for the given object
57 57 virtual QObject* create(const QByteArray& name, void *ptr) = 0;
58 58
59 59 };
60 60
61 61 #endif No newline at end of file
@@ -1,509 +1,509
1 1 #ifndef _PYTHONQTDOC_H
2 2 #define _PYTHONQTDOC_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtDoc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 /*!
46 46 \if USE_GLOBAL_DOXYGEN_DOC
47 47 \page PythonQtPage PythonQt Overview
48 48 \else
49 49 \mainpage PythonQt Overview
50 50 \endif
51 51
52 52 \section Introduction
53 53
54 54 \b PythonQt is a dynamic Python (http://www.python.org) binding for the Qt framework (http://qt.nokia.com).
55 55 It offers an easy way to embed the Python scripting language into
56 56 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt4.x.
57 57
58 58 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
59 59 application completely in Python. If you want to write your whole application in Python,
60 60 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/">PyQt</a> or <a href="http://www.pyside.org">PySide</a> instead.
61 61
62 62 If you are looking for a simple way to embed Python objects into your C++/Qt Application
63 63 and to script parts of your application via Python, PythonQt is the way to go!
64 64
65 65 PythonQt is a stable library that was developed to make the
66 66 Image Processing and Visualization platform MeVisLab (http://www.mevislab.de)
67 67 scriptable from Python.
68 68
69 69 \section Download
70 70
71 71 PythonQt is hosted on SourceForge at http://sourceforge.net/projects/pythonqt , you can access it via SVN
72 72 or download a tarball.
73 73
74 74 \section Licensing
75 75
76 76 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
77 77 to be used in commercial applications when following the LGPL 2.1 obligations.
78 78
79 79 \section LicensingWrapper Licensing of Wrapper Generator
80 80
81 81 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
82 82 located in the "generator" directory.
83 83
84 84 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
85 85 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
86 86 Qt typesystem files!
87 87
88 88 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
89 89
90 90 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
91 91 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
92 92 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
93 93 , but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
94 94
95 95 \section Features
96 96
97 97 The following are the built-in features of the PythonQt library:
98 98
99 99 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
100 100 - Connecting Qt Signals to Python functions (both from within Python and from C++)
101 101 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
102 102 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
103 103 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
104 104 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
105 105 - StdOut/Err redirection to Qt signals instead of cout
106 106 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
107 107 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
108 108 - Support for wrapping of user QVariant types which are registerd via QMetaType
109 109 - Support for Qt namespace (with all enumerators)
110 110 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
111 111 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
112 112 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
113 113 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
114 114 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
115 115 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
116 116
117 117 \section FeaturesQtAll Features (with PythonQt_QtAll linked in)
118 118
119 119 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
120 120 This offers the following features:
121 121
122 122 - Complete Qt API wrapped and accessible
123 123 - The following modules are available as submodules of the PythonQt module:
124 124 - QtCore
125 125 - QtGui
126 126 - QtNetwork
127 127 - QtOpenGL
128 128 - QtSql
129 129 - QtSvg
130 130 - QtUiTools
131 131 - QtWebKit
132 132 - QtXml
133 133 - QtXmlPatterns
134 134 - (phonon, QtHelp, assistant, designer are currently not supported, this would require some additional effort on the code generator)
135 135 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
136 136 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python
137 137 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
138 138 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
139 139
140 140 \section Comparision Comparision with PyQt/PySide
141 141
142 142 - PythonQt is not as Pythonic as PyQt in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
143 143 - PythonQt allows to communicate in both directions, e.g., calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
144 144 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
145 145 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
146 146 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
147 147 - PythonQt does not (yet) offer to add new signals to Python/C++ objects
148 148 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually referenced in Python to not get deleted too early (this will be fixed)
149 149 - QStrings are always converted to unicode Python objects (PyQt returns QString instead), we prefered to return Python strings.
150 150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
151 151
152 152 \section Interface
153 153
154 154 The main interface to PythonQt is the PythonQt singleton.
155 155 PythonQt needs to be initialized via PythonQt::init() once.
156 156 Afterwards you communicate with the singleton via PythonQt::self().
157 157 PythonQt offers a complete Qt binding, which
158 158 needs to be enabled via PythonQt_QtAll::init().
159 159
160 160
161 161 \section Datatype Datatype Mapping
162 162
163 163 The following table shows the mapping between Python and Qt objects:
164 164 <table>
165 165 <tr><th>Qt/C++</th><th>Python</th></tr>
166 166 <tr><td>bool</td><td>bool</td></tr>
167 167 <tr><td>double</td><td>float</td></tr>
168 168 <tr><td>float</td><td>float</td></tr>
169 169 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
170 170 <tr><td>long</td><td>integer</td></tr>
171 171 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
172 172 <tr><td>QString</td><td>unicode string</td></tr>
173 173 <tr><td>QByteArray</td><td>str</td></tr>
174 174 <tr><td>char*</td><td>str</td></tr>
175 175 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
176 176 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
177 177 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
178 178 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
179 179 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
180 180 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
181 181 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
182 182 <tr><td>EnumType</td><td>integer (all enums that are known via the moc and the Qt namespace are supported)</td></tr>
183 183 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
184 184 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
185 185 <tr><td>PyObject</td><td>PyObject</td></tr>
186 186 </table>
187 187
188 188 PyObject is passed as simple pointer, which allows to pass/return any Python Object directly to/from
189 189 a Qt slot.
190 190 QVariants are mapped recursively as given above, e.g. a dictionary can
191 191 contain lists of dictionaries of doubles.
192 192 For example a QVariant of type "String" is mapped to a python unicode string.
193 193 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
194 194
195 195 \section QObject QObject Wrapping
196 196
197 197 All classes derived from QObject are automatically wrapped with a python wrapper class
198 198 when they become visible to the Python interpreter. This can happen via
199 199 - the PythonQt::addObject() method
200 200 - when a Qt \b slot returns a QObject derived object to python
201 201 - when a Qt \b signal contains a QObject and is connected to a python function
202 202
203 203 It is important that you call PythonQt::registerClass() for any QObject derived class
204 204 that may become visible to Python, except when you add it via PythonQt::addObject().
205 205 This will register the complete parent hierachy of the registered class, so that
206 206 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
207 207 parents).
208 208
209 209 From Python, you can talk to the returned QObjects in a natural way by calling
210 210 their slots and receiving the return values. You can also read/write all
211 211 properties of the objects as if they where normal python properties.
212 212
213 213 In addition to this, the wrapped objects support
214 214 - className() - returns a string that reprents the classname of the QObject
215 215 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
216 216 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
217 217 - connect(signal, function) - connect the signal of the given object to a python function
218 218 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
219 219 - disconnect(signal, function) - disconnect the signal of the given object from a python function
220 220 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
221 221 - children() - returns the children of the object
222 222 - setParent(QObject) - set the parent
223 223 - QObject* parent() - get the parent
224 224
225 225 The below example shows how to connect signals in Python:
226 226
227 227 \code
228 228 # define a signal handler function
229 229 def someFunction(flag):
230 230 print flag
231 231
232 232 # button1 is a QPushButton that has been added to Python via addObject()
233 233 # connect the clicked signal to a python function:
234 234 button1.connect("clicked(bool)", someFunction)
235 235
236 236 \endcode
237 237
238 238 \section CPP CPP Wrapping
239 239
240 240 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
241 241 and adding your factory via addWrapperFactory().
242 242 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
243 243 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
244 244 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
245 245 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
246 246
247 247 \section MetaObject Meta Object/Class access
248 248
249 249 For each known C++ class, PythonQt provides a Python class. These classes are visible
250 250 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
251 251
252 252 A Meta class supports:
253 253
254 254 - access to all declared enum values
255 255 - constructors
256 256 - static methods
257 257 - unbound non-static methods
258 258 - help() and className()
259 259
260 260 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
261 261
262 262 \code
263 263 from PythonQt import QtCore
264 264
265 265 # namespace access:
266 266 print QtCore.Qt.AlignLeft
267 267
268 268 # constructors
269 269 a = QtCore.QSize(12,13)
270 270 b = QtCore.QFont()
271 271
272 272 # static method
273 273 QtCore.QDate.currentDate()
274 274
275 275 # enum value
276 276 QtCore.QFont.UltraCondensed
277 277
278 278 \endcode
279 279
280 280 \section Decorators Decorator slots
281 281
282 282 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
283 283
284 284 - constructors
285 285 - destructors (for CPP objects)
286 286 - additional slots
287 287 - static slots (callable on both the Meta object and the instances)
288 288
289 289 The idea behind decorators is that we wanted to make it as easy as possible to extend
290 290 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
291 291 Python, it looked promising to use this approach for the extension of wrapped objects as well.
292 292 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
293 293 Qt when he wants to create static methods, constructors and additional member functions.
294 294
295 295 The basic idea about decorators is to create a QObject derived class that implements slots
296 296 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
297 297 These slots are then assigned to other classes via the naming convention.
298 298
299 299 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
300 300 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
301 301 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
302 302 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
303 303
304 304 The below example shows all kinds of decorators in action:
305 305
306 306 \code
307 307
308 308 // an example CPP object
309 309 class YourCPPObject {
310 310 public:
311 311 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
312 312
313 313 float doSomething(int arg1) { return arg1*a*b; };
314 314
315 315 private:
316 316
317 317 int a;
318 318 float b;
319 319 };
320 320
321 321 // an example decorator
322 322 class ExampleDecorator : public QObject
323 323 {
324 324 Q_OBJECT
325 325
326 326 public slots:
327 327 // add a constructor to QSize that takes a QPoint
328 328 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
329 329
330 330 // add a constructor for QPushButton that takes a text and a parent widget
331 331 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
332 332
333 333 // add a constructor for a CPP object
334 334 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
335 335
336 336 // add a destructor for a CPP object
337 337 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
338 338
339 339 // add a static method to QWidget
340 340 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
341 341
342 342 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
343 343 void move(QWidget* w, const QPoint& p) { w->move(p); }
344 344
345 345 // add an additional slot to QWidget, overloading the above move method
346 346 void move(QWidget* w, int x, int y) { w->move(x,y); }
347 347
348 348 // add a method to your own CPP object
349 349 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
350 350 };
351 351
352 352 ...
353 353
354 354 PythonQt::self()->addDecorators(new ExampleDecorator());
355 355 PythonQt::self()->registerCPPClass("YourCPPObject");
356 356
357 357 \endcode
358 358
359 359 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
360 360 (all these calls are mapped to the above decorator slots):
361 361
362 362 \code
363 363 from PythonQt import QtCore, QtGui, YourCPPObject
364 364
365 365 # call our new constructor of QSize
366 366 size = QtCore.QSize(QPoint(1,2));
367 367
368 368 # call our new QPushButton constructor
369 369 button = QtGui.QPushButton("sometext");
370 370
371 371 # call the move slot (overload1)
372 372 button.move(QPoint(0,0))
373 373
374 374 # call the move slot (overload2)
375 375 button.move(0,0)
376 376
377 377 # call the static method
378 378 grabber = QtGui.QWidget.mouseWrapper();
379 379
380 380 # create a CPP object via constructor
381 381 yourCpp = YourCPPObject(1,11.5)
382 382
383 383 # call the wrapped method on CPP object
384 384 print yourCpp.doSomething(1);
385 385
386 386 # destructor will be called:
387 387 yourCpp = None
388 388
389 389 \endcode
390 390
391 391 \section Building
392 392
393 393 PythonQt requires Qt 4.6.1 (or higher) and Python 2.5 or 2.6 on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
394 394 To compile PythonQt, you will need a python developer installation which includes Python's header files and
395 395 the python2x.[lib | dll | so | dynlib].
396 396 The build scripts a currently set to use Python 2.5.
397 397 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
398 398
399 399 \subsection Windows
400 400
401 401 On Windows, the (non-source) Python Windows installer can be used.
402 402 Make sure that you use the same compiler, the current Python distribution is built
403 403 with Visual Studio 2003. If you want to use another compiler, you will need to build
404 404 Python yourself, using your compiler.
405 405
406 406 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
407 407 dir of the python installation and \b PYTHON_LIB to point to
408 408 the directory where the python lib file is located.
409 409
410 410 When using the prebuild Python installer, this will be:
411 411
412 412 \code
413 413 > set PYTHON_PATH = c:\Python25
414 414 > set PYTHON_LIB = c:\Python25\libs
415 415 \endcode
416 416
417 417 When using the python sources, this will be something like:
418 418
419 419 \code
420 420 > set PYTHON_PATH = c:\yourDir\Python-2.5.1\
421 421 > set PYTHON_LIB = c:\yourDir\Python-2.5.1\PCbuild8\Win32
422 422 \endcode
423 423
424 424 To build all, do the following (after setting the above variables):
425 425
426 426 \code
427 427 > cd PythonQtRoot
428 428 > vcvars32
429 429 > qmake
430 430 > nmake
431 431 \endcode
432 432
433 433 This should build everything. If Python can not be linked or include files can not be found,
434 434 you probably need to tweak \b build/python.prf
435 435
436 436 The tests and examples are located in PythonQt/lib.
437 437
438 438 \subsection Linux
439 439
440 440 On Linux, you need to install a Python-dev package.
441 441 If Python can not be linked or include files can not be found,
442 442 you probably need to tweak \b build/python.prf
443 443
444 444 To build PythonQt, just do a:
445 445
446 446 \code
447 447 > cd PythonQtRoot
448 448 > qmake
449 449 > make all
450 450 \endcode
451 451
452 452 The tests and examples are located in PythonQt/lib.
453 453 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
454 454 linker can find the *.so files.
455 455
456 456 \subsection MacOsX
457 457
458 458 On Mac, Python is installed as a Framework, so you should not need to install it.
459 459 To build PythonQt, just do a:
460 460
461 461 \code
462 462 > cd PythonQtRoot
463 463 > qmake
464 464 > make all
465 465 \endcode
466 466
467 467 \section Tests
468 468
469 469 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
470 470
471 471 \section Examples
472 472
473 473 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
474 474 interactive scripting console that shows how to script a simple application.
475 475
476 476 The following shows how to integrate PythonQt into you Qt application:
477 477
478 478 \code
479 479 #include "PythonQt.h"
480 480 #include <QApplication>
481 481 ...
482 482
483 483 int main( int argc, char **argv )
484 484 {
485 485
486 486 QApplication qapp(argc, argv);
487 487
488 488 // init PythonQt and Python itself
489 489 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
490 490
491 491
492 492 // get a smart pointer to the __main__ module of the Python interpreter
493 493 PythonQtObjectPtr mainContext = PythonQt::self()->getMainModule();
494 494
495 495 // add a QObject as variable of name "example" to the namespace of the __main__ module
496 496 PyExampleObject example;
497 497 PythonQt::self()->addObject(mainContext, "example", &example);
498 498
499 499 // do something
500 500 PythonQt::self()->runScript(mainContext, "print example\n");
501 501 PythonQt::self()->runScript(mainContext, "def multiply(a,b):\n return a*b;\n");
502 502 QVariantList args;
503 503 args << 42 << 47;
504 504 QVariant result = PythonQt::self()->call(mainContext,"multiply", args);
505 505 ...
506 506 \endcode
507 507
508 508
509 509 */
@@ -1,72 +1,72
1 1 #ifndef _PYTHONQTIMPORTFILEINTERFACE_H
2 2 #define _PYTHONQTIMPORTFILEINTERFACE_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtImportFileInterface.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <QDateTime>
46 46 #include <QString>
47 47 #include <QByteArray>
48 48
49 49 //! Defines an abstract interface to file access for the Python import statement.
50 50 //! see PythonQt::setImporter()
51 51 class PythonQtImportFileInterface {
52 52
53 53 public:
54 54 // get rid of warnings
55 55 virtual ~PythonQtImportFileInterface() {}
56 56
57 57 //! read the given file as byte array, without doing any linefeed translations
58 58 virtual QByteArray readFileAsBytes(const QString& filename) = 0;
59 59
60 60 //! read a source file, expects a readable Python text file with translated line feeds.
61 61 //! If the file can not be load OR it can not be verified, ok is set to false
62 62 virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
63 63
64 64 //! returns if the file exists
65 65 virtual bool exists(const QString& filename) = 0;
66 66
67 67 //! get the last modified data of a file
68 68 virtual QDateTime lastModifiedDate(const QString& filename) = 0;
69 69
70 70 };
71 71
72 72 #endif No newline at end of file
@@ -1,793 +1,793
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 // This module was inspired by the zipimport.c module of the original
41 41 // Python distribution. Most of the functions are identical or slightly
42 42 // modified to do all the loading of Python files via an external file interface.
43 43 // In contrast to zipimport.c, this module also writes *.pyc files
44 44 // automatically if it has write access/is not inside of a zip file.
45 45 //----------------------------------------------------------------------------------
46 46
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 50 #include "PythonQtConversion.h"
51 51 #include <QFile>
52 52 #include <QFileInfo>
53 53
54 54 #define IS_SOURCE 0x0
55 55 #define IS_BYTECODE 0x1
56 56 #define IS_PACKAGE 0x2
57 57
58 58 struct st_mlab_searchorder {
59 59 char suffix[14];
60 60 int type;
61 61 };
62 62
63 63 /* mlab_searchorder defines how we search for a module in the Zip
64 64 archive: we first search for a package __init__, then for
65 65 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
66 66 are swapped by initmlabimport() if we run in optimized mode. Also,
67 67 '/' is replaced by SEP there. */
68 68 struct st_mlab_searchorder mlab_searchorder[] = {
69 69 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
70 70 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
71 71 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
72 72 {".pyc", IS_BYTECODE},
73 73 {".pyo", IS_BYTECODE},
74 74 {".py", IS_SOURCE},
75 75 {"", 0}
76 76 };
77 77
78 78 extern PyTypeObject PythonQtImporter_Type;
79 79 PyObject *PythonQtImportError;
80 80
81 81 QString PythonQtImport::getSubName(const QString& str)
82 82 {
83 83 int idx = str.lastIndexOf('.');
84 84 if (idx!=-1) {
85 85 return str.mid(idx+1);
86 86 } else {
87 87 return str;
88 88 }
89 89 }
90 90
91 91 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
92 92 {
93 93 ModuleInfo info;
94 94 QString subname;
95 95 struct st_mlab_searchorder *zso;
96 96
97 97 subname = getSubName(fullname);
98 98 QString path = *self->_path + "/" + subname;
99 99
100 100 QString test;
101 101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
102 102 test = path + zso->suffix;
103 103 if (PythonQt::importInterface()->exists(test)) {
104 104 info.fullPath = test;
105 105 info.moduleName = subname;
106 106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
107 107 return info;
108 108 }
109 109 }
110 110 // test if it is a shared library
111 111 foreach(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) {
112 112 test = path+suffix;
113 113 if (PythonQt::importInterface()->exists(test)) {
114 114 info.fullPath = test;
115 115 info.moduleName = subname;
116 116 info.type = MI_SHAREDLIBRARY;
117 117 }
118 118 }
119 119 return info;
120 120 }
121 121
122 122
123 123 /* PythonQtImporter.__init__
124 124 Just store the path argument (or reject if it is in the ignorePaths list
125 125 */
126 126 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*kwds*/)
127 127 {
128 128 self->_path = NULL;
129 129
130 130 const char* cpath;
131 131 if (!PyArg_ParseTuple(args, "s",
132 132 &cpath))
133 133 return -1;
134 134
135 135 QString path(cpath);
136 136 if (PythonQt::importInterface()->exists(path)) {
137 137 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
138 138 foreach(QString ignorePath, ignorePaths) {
139 139 if (path.startsWith(ignorePath)) {
140 140 PyErr_SetString(PythonQtImportError,
141 141 "path ignored");
142 142 return -1;
143 143 }
144 144 }
145 145
146 146 self->_path = new QString(path);
147 147 return 0;
148 148 } else {
149 149 PyErr_SetString(PythonQtImportError,
150 150 "path does not exist error");
151 151 return -1;
152 152 }
153 153 }
154 154
155 155 void
156 156 PythonQtImporter_dealloc(PythonQtImporter *self)
157 157 {
158 158 // free the stored path
159 159 if (self->_path) delete self->_path;
160 160 // free ourself
161 161 self->ob_type->tp_free((PyObject *)self);
162 162 }
163 163
164 164
165 165 /* Check whether we can satisfy the import of the module named by
166 166 'fullname'. Return self if we can, None if we can't. */
167 167 PyObject *
168 168 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
169 169 {
170 170 PythonQtImporter *self = (PythonQtImporter *)obj;
171 171 PyObject *path = NULL;
172 172 char *fullname;
173 173
174 174 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
175 175 &fullname, &path))
176 176 return NULL;
177 177
178 178 //qDebug() << "looking for " << fullname << " at " << *self->_path;
179 179
180 180 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
181 181 if (info.type != PythonQtImport::MI_NOT_FOUND) {
182 182 Py_INCREF(self);
183 183 return (PyObject *)self;
184 184 } else {
185 185 Py_INCREF(Py_None);
186 186 return Py_None;
187 187 }
188 188 }
189 189
190 190 /* Load and return the module named by 'fullname'. */
191 191 PyObject *
192 192 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
193 193 {
194 194 PythonQtImporter *self = (PythonQtImporter *)obj;
195 195 PyObject *code = NULL, *mod = NULL, *dict = NULL;
196 196 char *fullname;
197 197
198 198 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
199 199 &fullname))
200 200 return NULL;
201 201
202 202 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
203 203 if (info.type == PythonQtImport::MI_NOT_FOUND) {
204 204 return NULL;
205 205 }
206 206
207 207 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
208 208 QString fullPath;
209 209 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
210 210 if (code == NULL) {
211 211 return NULL;
212 212 }
213 213
214 214 mod = PyImport_AddModule(fullname);
215 215 if (mod == NULL) {
216 216 Py_DECREF(code);
217 217 return NULL;
218 218 }
219 219 dict = PyModule_GetDict(mod);
220 220
221 221 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
222 222 Py_DECREF(code);
223 223 Py_DECREF(mod);
224 224 return NULL;
225 225 }
226 226
227 227 if (info.type == PythonQtImport::MI_PACKAGE) {
228 228 PyObject *pkgpath, *fullpath;
229 229 QString subname = info.moduleName;
230 230 int err;
231 231
232 232 fullpath = PyString_FromFormat("%s%c%s",
233 233 self->_path->toLatin1().constData(),
234 234 SEP,
235 235 subname.toLatin1().constData());
236 236 if (fullpath == NULL) {
237 237 Py_DECREF(code);
238 238 Py_DECREF(mod);
239 239 return NULL;
240 240 }
241 241
242 242 pkgpath = Py_BuildValue("[O]", fullpath);
243 243 Py_DECREF(fullpath);
244 244 if (pkgpath == NULL) {
245 245 Py_DECREF(code);
246 246 Py_DECREF(mod);
247 247 return NULL;
248 248 }
249 249 err = PyDict_SetItemString(dict, "__path__", pkgpath);
250 250 Py_DECREF(pkgpath);
251 251 if (err != 0) {
252 252 Py_DECREF(code);
253 253 Py_DECREF(mod);
254 254 return NULL;
255 255 }
256 256 }
257 257 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
258 258 Py_DECREF(code);
259 259 if (Py_VerboseFlag) {
260 260 PySys_WriteStderr("import %s # loaded from %s\n",
261 261 fullname, fullPath.toLatin1().constData());
262 262 }
263 263 } else {
264 264 PythonQtObjectPtr imp;
265 265 imp.setNewRef(PyImport_ImportModule("imp"));
266 266
267 267 // Create a PyList with the current path as its single element,
268 268 // which is required for find_module (it won't accept a tuple...)
269 269 PythonQtObjectPtr pathList;
270 270 pathList.setNewRef(PythonQtConv::QStringListToPyList(QStringList() << *self->_path));
271 271
272 272 QVariantList args;
273 273 // Pass the module name without the package prefix
274 274 args.append(info.moduleName);
275 275 // And the path where we know that the shared library is
276 276 args.append(QVariant::fromValue(pathList));
277 277 QVariant result = imp.call("find_module", args);
278 278 if (result.isValid()) {
279 279 // This will return a tuple with (file, pathname, description)
280 280 QVariantList list = result.toList();
281 281 if (list.count()==3) {
282 282 // We prepend the full module name (including package prefix)
283 283 list.prepend(fullname);
284 284 // And call "load_module" with (fullname, file, pathname, description)
285 285 PythonQtObjectPtr module = imp.call("load_module", list);
286 286 mod = module.object();
287 287 if (mod) {
288 288 Py_INCREF(mod);
289 289 }
290 290
291 291 // Finally, we need to close the file again, which find_module opened for us
292 292 PythonQtObjectPtr file = list.at(1);
293 293 file.call("close");
294 294 }
295 295 }
296 296 }
297 297 return mod;
298 298 }
299 299
300 300
301 301 PyObject *
302 302 PythonQtImporter_get_data(PyObject* /*obj*/, PyObject* /*args*/)
303 303 {
304 304 // EXTRA, NOT YET IMPLEMENTED
305 305 return NULL;
306 306 }
307 307
308 308 PyObject *
309 309 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
310 310 {
311 311 PythonQtImporter *self = (PythonQtImporter *)obj;
312 312 char *fullname;
313 313
314 314 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
315 315 return NULL;
316 316
317 317 QString notused;
318 318 return PythonQtImport::getModuleCode(self, fullname, notused);
319 319 }
320 320
321 321 PyObject *
322 322 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
323 323 {
324 324 // EXTRA, NOT YET IMPLEMENTED
325 325 return NULL;
326 326 }
327 327
328 328 PyDoc_STRVAR(doc_find_module,
329 329 "find_module(fullname, path=None) -> self or None.\n\
330 330 \n\
331 331 Search for a module specified by 'fullname'. 'fullname' must be the\n\
332 332 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
333 333 instance itself if the module was found, or None if it wasn't.\n\
334 334 The optional 'path' argument is ignored -- it's there for compatibility\n\
335 335 with the importer protocol.");
336 336
337 337 PyDoc_STRVAR(doc_load_module,
338 338 "load_module(fullname) -> module.\n\
339 339 \n\
340 340 Load the module specified by 'fullname'. 'fullname' must be the\n\
341 341 fully qualified (dotted) module name. It returns the imported\n\
342 342 module, or raises PythonQtImportError if it wasn't found.");
343 343
344 344 PyDoc_STRVAR(doc_get_data,
345 345 "get_data(pathname) -> string with file data.\n\
346 346 \n\
347 347 Return the data associated with 'pathname'. Raise IOError if\n\
348 348 the file wasn't found.");
349 349
350 350 PyDoc_STRVAR(doc_get_code,
351 351 "get_code(fullname) -> code object.\n\
352 352 \n\
353 353 Return the code object for the specified module. Raise PythonQtImportError\n\
354 354 is the module couldn't be found.");
355 355
356 356 PyDoc_STRVAR(doc_get_source,
357 357 "get_source(fullname) -> source string.\n\
358 358 \n\
359 359 Return the source code for the specified module. Raise PythonQtImportError\n\
360 360 is the module couldn't be found, return None if the archive does\n\
361 361 contain the module, but has no source for it.");
362 362
363 363 PyMethodDef PythonQtImporter_methods[] = {
364 364 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
365 365 doc_find_module},
366 366 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
367 367 doc_load_module},
368 368 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
369 369 doc_get_data},
370 370 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
371 371 doc_get_code},
372 372 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
373 373 doc_get_source},
374 374 {NULL, NULL, 0 , NULL} /* sentinel */
375 375 };
376 376
377 377
378 378 PyDoc_STRVAR(PythonQtImporter_doc,
379 379 "PythonQtImporter(path) -> PythonQtImporter object\n\
380 380 \n\
381 381 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
382 382 . Every path is accepted.");
383 383
384 384 #define DEFERRED_ADDRESS(ADDR) 0
385 385
386 386 PyTypeObject PythonQtImporter_Type = {
387 387 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
388 388 0,
389 389 "PythonQtImport.PythonQtImporter",
390 390 sizeof(PythonQtImporter),
391 391 0, /* tp_itemsize */
392 392 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
393 393 0, /* tp_print */
394 394 0, /* tp_getattr */
395 395 0, /* tp_setattr */
396 396 0, /* tp_compare */
397 397 0, /* tp_repr */
398 398 0, /* tp_as_number */
399 399 0, /* tp_as_sequence */
400 400 0, /* tp_as_mapping */
401 401 0, /* tp_hash */
402 402 0, /* tp_call */
403 403 0, /* tp_str */
404 404 PyObject_GenericGetAttr, /* tp_getattro */
405 405 0, /* tp_setattro */
406 406 0, /* tp_as_buffer */
407 407 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
408 408 PythonQtImporter_doc, /* tp_doc */
409 409 0, /* tp_traverse */
410 410 0, /* tp_clear */
411 411 0, /* tp_richcompare */
412 412 0, /* tp_weaklistoffset */
413 413 0, /* tp_iter */
414 414 0, /* tp_iternext */
415 415 PythonQtImporter_methods, /* tp_methods */
416 416 0, /* tp_members */
417 417 0, /* tp_getset */
418 418 0, /* tp_base */
419 419 0, /* tp_dict */
420 420 0, /* tp_descr_get */
421 421 0, /* tp_descr_set */
422 422 0, /* tp_dictoffset */
423 423 (initproc)PythonQtImporter_init, /* tp_init */
424 424 PyType_GenericAlloc, /* tp_alloc */
425 425 PyType_GenericNew, /* tp_new */
426 426 PyObject_Del, /* tp_free */
427 427 };
428 428
429 429
430 430 /* Given a buffer, return the long that is represented by the first
431 431 4 bytes, encoded as little endian. This partially reimplements
432 432 marshal.c:r_long() */
433 433 long
434 434 PythonQtImport::getLong(unsigned char *buf)
435 435 {
436 436 long x;
437 437 x = buf[0];
438 438 x |= (long)buf[1] << 8;
439 439 x |= (long)buf[2] << 16;
440 440 x |= (long)buf[3] << 24;
441 441 #if SIZEOF_LONG > 4
442 442 /* Sign extension for 64-bit machines */
443 443 x |= -(x & 0x80000000L);
444 444 #endif
445 445 return x;
446 446 }
447 447
448 448 FILE *
449 449 open_exclusive(const QString& filename)
450 450 {
451 451 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
452 452 /* Use O_EXCL to avoid a race condition when another process tries to
453 453 write the same file. When that happens, our open() call fails,
454 454 which is just fine (since it's only a cache).
455 455 XXX If the file exists and is writable but the directory is not
456 456 writable, the file will never be written. Oh well.
457 457 */
458 458 QFile::remove(filename);
459 459
460 460 int fd;
461 461 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
462 462 #ifdef O_BINARY
463 463 flags |= O_BINARY; /* necessary for Windows */
464 464 #endif
465 465 #ifdef WIN32
466 466 fd = _wopen(filename.ucs2(), flags, 0666);
467 467 #else
468 468 fd = open(filename.local8Bit(), flags, 0666);
469 469 #endif
470 470 if (fd < 0)
471 471 return NULL;
472 472 return fdopen(fd, "wb");
473 473 #else
474 474 /* Best we can do -- on Windows this can't happen anyway */
475 475 return fopen(filename.toLocal8Bit().constData(), "wb");
476 476 #endif
477 477 }
478 478
479 479
480 480 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
481 481 {
482 482 FILE *fp;
483 483 // we do not want to write Qt resources to disk, do we?
484 484 if (filename.startsWith(":")) {
485 485 return;
486 486 }
487 487 fp = open_exclusive(filename);
488 488 if (fp == NULL) {
489 489 if (Py_VerboseFlag)
490 490 PySys_WriteStderr(
491 491 "# can't create %s\n", filename.toLatin1().constData());
492 492 return;
493 493 }
494 494 #if PY_VERSION_HEX < 0x02040000
495 495 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
496 496 #else
497 497 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
498 498 #endif
499 499 /* First write a 0 for mtime */
500 500 #if PY_VERSION_HEX < 0x02040000
501 501 PyMarshal_WriteLongToFile(0L, fp);
502 502 #else
503 503 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
504 504 #endif
505 505 #if PY_VERSION_HEX < 0x02040000
506 506 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
507 507 #else
508 508 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
509 509 #endif
510 510 if (ferror(fp)) {
511 511 if (Py_VerboseFlag)
512 512 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
513 513 /* Don't keep partial file */
514 514 fclose(fp);
515 515 QFile::remove(filename);
516 516 return;
517 517 }
518 518 /* Now write the true mtime */
519 519 fseek(fp, 4L, 0);
520 520 #if PY_VERSION_HEX < 0x02040000
521 521 PyMarshal_WriteLongToFile(mtime, fp);
522 522 #else
523 523 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
524 524 #endif
525 525 fflush(fp);
526 526 fclose(fp);
527 527 if (Py_VerboseFlag)
528 528 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
529 529 //#ifdef macintosh
530 530 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
531 531 //#endif
532 532 }
533 533
534 534 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
535 535 and return the code object. Return None if it the magic word doesn't
536 536 match (we do this instead of raising an exception as we fall back
537 537 to .py if available and we don't want to mask other errors).
538 538 Returns a new reference. */
539 539 PyObject *
540 540 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
541 541 {
542 542 PyObject *code;
543 543 // ugly cast, but Python API is not const safe
544 544 char *buf = (char*) data.constData();
545 545 int size = data.size();
546 546
547 547 if (size <= 9) {
548 548 PySys_WriteStderr("# %s has bad pyc data\n",
549 549 path.toLatin1().constData());
550 550 Py_INCREF(Py_None);
551 551 return Py_None;
552 552 }
553 553
554 554 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
555 555 if (Py_VerboseFlag)
556 556 PySys_WriteStderr("# %s has bad magic\n",
557 557 path.toLatin1().constData());
558 558 Py_INCREF(Py_None);
559 559 return Py_None;
560 560 }
561 561
562 562 if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) {
563 563 if (Py_VerboseFlag)
564 564 PySys_WriteStderr("# %s has bad mtime\n",
565 565 path.toLatin1().constData());
566 566 Py_INCREF(Py_None);
567 567 return Py_None;
568 568 }
569 569
570 570 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
571 571 if (code == NULL)
572 572 return NULL;
573 573 if (!PyCode_Check(code)) {
574 574 Py_DECREF(code);
575 575 PyErr_Format(PyExc_TypeError,
576 576 "compiled module %.200s is not a code object",
577 577 path.toLatin1().constData());
578 578 return NULL;
579 579 }
580 580 return code;
581 581 }
582 582
583 583
584 584 /* Given a string buffer containing Python source code, compile it
585 585 return and return a code object as a new reference. */
586 586 PyObject *
587 587 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
588 588 {
589 589 PyObject *code;
590 590 QByteArray data1 = data;
591 591 // in qt4, data is null terminated
592 592 // data1.resize(data.size()+1);
593 593 // data1.data()[data.size()-1] = 0;
594 594 code = Py_CompileString(data.data(), path.toLatin1().constData(),
595 595 Py_file_input);
596 596 return code;
597 597 }
598 598
599 599
600 600 /* Return the code object for the module named by 'fullname' from the
601 601 Zip archive as a new reference. */
602 602 PyObject *
603 603 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispackage*/, time_t mtime)
604 604 {
605 605 PyObject *code;
606 606
607 607 QByteArray qdata;
608 608 if (!isbytecode) {
609 609 // mlabDebugConst("MLABPython", "reading source " << path);
610 610 bool ok;
611 611 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
612 612 if (!ok) {
613 613 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
614 614 return NULL;
615 615 }
616 616 if (qdata == " ") {
617 617 qdata.clear();
618 618 }
619 619 } else {
620 620 qdata = PythonQt::importInterface()->readFileAsBytes(path);
621 621 }
622 622
623 623 if (isbytecode) {
624 624 // mlabDebugConst("MLABPython", "reading bytecode " << path);
625 625 code = unmarshalCode(path, qdata, mtime);
626 626 }
627 627 else {
628 628 // mlabDebugConst("MLABPython", "compiling source " << path);
629 629 code = compileSource(path, qdata);
630 630 if (code) {
631 631 // save a pyc file if possible
632 632 QDateTime time;
633 633 time = PythonQt::importInterface()->lastModifiedDate(path);
634 634 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
635 635 }
636 636 }
637 637 return code;
638 638 }
639 639
640 640 time_t
641 641 PythonQtImport::getMTimeOfSource(const QString& path)
642 642 {
643 643 time_t mtime = 0;
644 644 QString path2 = path;
645 645 path2.truncate(path.length()-1);
646 646
647 647 if (PythonQt::importInterface()->exists(path2)) {
648 648 mtime = PythonQt::importInterface()->lastModifiedDate(path2).toTime_t();
649 649 }
650 650
651 651 return mtime;
652 652 }
653 653
654 654 /* Get the code object associated with the module specified by
655 655 'fullname'. */
656 656 PyObject *
657 657 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
658 658 {
659 659 QString subname;
660 660 struct st_mlab_searchorder *zso;
661 661
662 662 subname = getSubName(fullname);
663 663 QString path = *self->_path + "/" + subname;
664 664
665 665 QString test;
666 666 for (zso = mlab_searchorder; *zso->suffix; zso++) {
667 667 PyObject *code = NULL;
668 668 test = path + zso->suffix;
669 669
670 670 if (Py_VerboseFlag > 1)
671 671 PySys_WriteStderr("# trying %s\n",
672 672 test.toLatin1().constData());
673 673 if (PythonQt::importInterface()->exists(test)) {
674 674 time_t mtime = 0;
675 675 int ispackage = zso->type & IS_PACKAGE;
676 676 int isbytecode = zso->type & IS_BYTECODE;
677 677
678 678 if (isbytecode) {
679 679 mtime = getMTimeOfSource(test);
680 680 }
681 681 code = getCodeFromData(test, isbytecode, ispackage, mtime);
682 682 if (code == Py_None) {
683 683 Py_DECREF(code);
684 684 continue;
685 685 }
686 686 if (code != NULL) {
687 687 modpath = test;
688 688 }
689 689 return code;
690 690 }
691 691 }
692 692 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
693 693
694 694 return NULL;
695 695 }
696 696
697 697 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
698 698 {
699 699 QString r;
700 700 int i = str.lastIndexOf('.');
701 701 if (i!=-1) {
702 702 r = str.mid(0,i) + "." + ext;
703 703 } else {
704 704 r = str + "." + ext;
705 705 }
706 706 return r;
707 707 }
708 708
709 709 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
710 710 {
711 711 PyObject* code;
712 712 const static QString pycStr("pyc");
713 713 QString pyc = replaceExtension(file, pycStr);
714 714 if (PythonQt::importInterface()->exists(pyc)) {
715 715 time_t mtime = 0;
716 716 mtime = getMTimeOfSource(pyc);
717 717 code = getCodeFromData(pyc, true, false, mtime);
718 718 if (code != Py_None && code != NULL) {
719 719 return code;
720 720 }
721 721 if (code) {
722 722 Py_DECREF(code);
723 723 }
724 724 }
725 725 code = getCodeFromData(file,false,false,0);
726 726 return code;
727 727 }
728 728
729 729 /* Module init */
730 730
731 731 PyDoc_STRVAR(mlabimport_doc,
732 732 "Imports python files into PythonQt, completely replaces internal python import");
733 733
734 734 void PythonQtImport::init()
735 735 {
736 736 static bool first = true;
737 737 if (!first) {
738 738 return;
739 739 }
740 740 first = false;
741 741
742 742 PyObject *mod;
743 743
744 744 if (PyType_Ready(&PythonQtImporter_Type) < 0)
745 745 return;
746 746
747 747 /* Correct directory separator */
748 748 mlab_searchorder[0].suffix[0] = SEP;
749 749 mlab_searchorder[1].suffix[0] = SEP;
750 750 mlab_searchorder[2].suffix[0] = SEP;
751 751 if (Py_OptimizeFlag) {
752 752 /* Reverse *.pyc and *.pyo */
753 753 struct st_mlab_searchorder tmp;
754 754 tmp = mlab_searchorder[0];
755 755 mlab_searchorder[0] = mlab_searchorder[1];
756 756 mlab_searchorder[1] = tmp;
757 757 tmp = mlab_searchorder[3];
758 758 mlab_searchorder[3] = mlab_searchorder[4];
759 759 mlab_searchorder[4] = tmp;
760 760 }
761 761
762 762 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
763 763 NULL, PYTHON_API_VERSION);
764 764
765 765 PythonQtImportError = PyErr_NewException("PythonQtImport.PythonQtImportError",
766 766 PyExc_ImportError, NULL);
767 767 if (PythonQtImportError == NULL)
768 768 return;
769 769
770 770 Py_INCREF(PythonQtImportError);
771 771 if (PyModule_AddObject(mod, "PythonQtImportError",
772 772 PythonQtImportError) < 0)
773 773 return;
774 774
775 775 Py_INCREF(&PythonQtImporter_Type);
776 776 if (PyModule_AddObject(mod, "PythonQtImporter",
777 777 (PyObject *)&PythonQtImporter_Type) < 0)
778 778 return;
779 779
780 780 // set our importer into the path_hooks to handle all path on sys.path
781 781 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
782 782 PyObject* path_hooks = PySys_GetObject("path_hooks");
783 783 PyList_Append(path_hooks, classobj);
784 784
785 785 #ifndef WIN32
786 786 // reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
787 787 PyObject* modules = PyImport_GetModuleDict();
788 788 PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
789 789 if (encodingsModule != NULL) {
790 790 PyImport_ReloadModule(encodingsModule);
791 791 }
792 792 #endif
793 793 }
@@ -1,137 +1,137
1 1 #ifndef _PYTHONQTIMPORTER_
2 2 #define _PYTHONQTIMPORTER_
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtImporter.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: stk $
41 41 // \date 2004-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "Python.h"
46 46 #include "structmember.h"
47 47 #include "osdefs.h"
48 48 #include "marshal.h"
49 49 #include "compile.h"
50 50 #include <time.h>
51 51
52 52 #include <qobject.h>
53 53 #include <qstring.h>
54 54
55 55
56 56 //! defines a python object that stores a Qt slot info
57 57 typedef struct _PythonQtImporter {
58 58 PyObject_HEAD
59 59 QString* _path;
60 60 } PythonQtImporter;
61 61
62 62
63 63 //! implements importing of python files into PythonQt
64 64 /*! also compiles/marshalls/unmarshalls py/pyc files and handles time stamps correctly
65 65 */
66 66 class PythonQtImport
67 67 {
68 68 public:
69 69
70 70 enum ModuleType {
71 71 MI_NOT_FOUND,
72 72 MI_MODULE,
73 73 MI_PACKAGE,
74 74 MI_SHAREDLIBRARY
75 75 };
76 76
77 77 struct ModuleInfo {
78 78 ModuleInfo() {
79 79 type = MI_NOT_FOUND;
80 80 }
81 81 QString fullPath; //!< the full path to the found file
82 82 QString moduleName; //!< the module name without the package prefix
83 83 ModuleType type;
84 84 };
85 85
86 86 //! initialize
87 87 static void init();
88 88
89 89 //! writes the python code to disk, marshalling and writing the time stamp
90 90 static void writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime);
91 91
92 92 /*! Given the contents of a .py[co] file in a buffer, unmarshal the data
93 93 and return the code object. Return None if it the magic word doesn't
94 94 match (we do this instead of raising an exception as we fall back
95 95 to .py if available and we don't want to mask other errors).
96 96 Returns a new reference. */
97 97 static PyObject *unmarshalCode(const QString& path, const QByteArray& data, time_t mtime);
98 98
99 99 //! Given a string buffer containing Python source code, compile it
100 100 //! return and return a code object as a new reference.
101 101 static PyObject *compileSource(const QString& path, const QByteArray& data);
102 102
103 103 //! Return the code object for the module named by 'fullname' from the
104 104 //! Zip archive as a new reference.
105 105 static PyObject *getCodeFromData(const QString& path, int isbytecode = 0, int ispackage = 0,
106 106 time_t mtime = 0);
107 107
108 108 //! Get the code object associated with the module specified by
109 109 //! 'fullname'.
110 110 static PyObject * getModuleCode(PythonQtImporter *self,
111 111 const char* fullname, QString& modpath);
112 112
113 113
114 114 //! gets the compiled code for the given *.py file if there is a valid pyc file, otherwise compiles the file and writes the pyc
115 115 static PyObject* getCodeFromPyc(const QString& file);
116 116
117 117 //! Return if module exists and is a package or a module
118 118 static ModuleInfo getModuleInfo(PythonQtImporter* self, const QString& fullname);
119 119
120 120 //! get the last name of a dot chain (first.second.last)
121 121 static QString getSubName(const QString& str);
122 122
123 123 //! Given a buffer, return the long that is represented by the first
124 124 //! 4 bytes, encoded as little endian. This partially reimplements
125 125 //! marshal.c:r_long()
126 126 static long getLong(unsigned char *buf);
127 127
128 128 //! get time stamp of file
129 129 static time_t getMTimeOfSource(const QString& path);
130 130
131 131 //! replace extension of file
132 132 static QString replaceExtension(const QString& str, const QString& ext);
133 133
134 134 };
135 135
136 136 #endif
137 137
@@ -1,726 +1,726
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtInstanceWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtClassInfo.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtClassWrapper.h"
49 49
50 50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 51 {
52 52 // take the class info from our type object
53 53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 54 }
55 55
56 56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57 57
58 58 // is this a C++ wrapper?
59 59 if (self->_wrappedPtr) {
60 60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61 61
62 62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 63 // we own our qobject, so we delete it now:
64 64 delete self->_obj;
65 65 self->_obj = NULL;
66 66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 67 int type = self->classInfo()->metaTypeId();
68 68 if (self->_useQMetaTypeDestroy && type>=0) {
69 69 // use QMetaType to destroy the object
70 70 QMetaType::destroy(type, self->_wrappedPtr);
71 71 } else {
72 72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 73 if (slot) {
74 74 void* args[2];
75 75 args[0] = NULL;
76 76 args[1] = &self->_wrappedPtr;
77 77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 78 self->_wrappedPtr = NULL;
79 79 } else {
80 80 if (type>=0) {
81 81 // use QMetaType to destroy the object
82 82 QMetaType::destroy(type, self->_wrappedPtr);
83 83 } else {
84 84 // TODO: warn about not being able to destroy the object?
85 85 }
86 86 }
87 87 }
88 88 }
89 89 } else {
90 90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 91 if (self->_objPointerCopy) {
92 92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 93 }
94 94 if (self->_obj) {
95 95 if (force || self->_ownedByPythonQt) {
96 96 if (force || !self->_obj->parent()) {
97 97 delete self->_obj;
98 98 }
99 99 } else {
100 100 if (self->_obj->parent()==NULL) {
101 101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 103 }
104 104 }
105 105 }
106 106 }
107 107 self->_obj = NULL;
108 108 }
109 109
110 110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 111 {
112 112 PythonQtInstanceWrapper_deleteObject(self);
113 113 self->_obj.~QPointer<QObject>();
114 114 self->ob_type->tp_free((PyObject*)self);
115 115 }
116 116
117 117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118 118 {
119 119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 120 PythonQtInstanceWrapper *self;
121 121 static PyObject* emptyTuple = NULL;
122 122 if (emptyTuple==NULL) {
123 123 emptyTuple = PyTuple_New(0);
124 124 }
125 125
126 126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127 127
128 128 if (self != NULL) {
129 129 new (&self->_obj) QPointer<QObject>();
130 130 self->_wrappedPtr = NULL;
131 131 self->_ownedByPythonQt = false;
132 132 self->_useQMetaTypeDestroy = false;
133 133 self->_isShellInstance = false;
134 134 }
135 135 return (PyObject *)self;
136 136 }
137 137
138 138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 139 {
140 140 if (args == PythonQtPrivate::dummyTuple()) {
141 141 // we are called from the internal PythonQt API, so our data will be filled later on...
142 142 return 0;
143 143 }
144 144
145 145 // we are called from python, try to construct our object
146 146 if (self->classInfo()->constructors()) {
147 147 void* directCPPPointer = NULL;
148 148 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 149 if (PyErr_Occurred()) {
150 150 return -1;
151 151 }
152 152 if (directCPPPointer) {
153 153 // change ownershipflag to be owned by PythonQt
154 154 self->_ownedByPythonQt = true;
155 155 self->_useQMetaTypeDestroy = false;
156 156 if (self->classInfo()->isCPPWrapper()) {
157 157 self->_wrappedPtr = directCPPPointer;
158 158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 159 } else {
160 160 self->setQObject((QObject*)directCPPPointer);
161 161 }
162 162 // register with PythonQt
163 163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164 164
165 165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 166 if (cb) {
167 167 // if we are a derived python class, we set the wrapper
168 168 // to activate the shell class, otherwise we just ignore that it is a shell...
169 169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 170 // which is the case for all non-python derived types
171 171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 172 // set the wrapper and remember that we have a shell instance!
173 173 (*cb)(directCPPPointer, self);
174 174 self->_isShellInstance = true;
175 175 }
176 176 }
177 177 }
178 178 } else {
179 179 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 181 return -1;
182 182 }
183 183 return 0;
184 184 }
185 185
186 186 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
187 187 {
188 188 bool validPtrs = false;
189 189 bool areSamePtrs = false;
190 190 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
191 191 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
192 192 validPtrs = true;
193 193 PythonQtInstanceWrapper* w1 = wrapper;
194 194 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
195 195 // check pointers directly
196 196 if (w1->_wrappedPtr != NULL) {
197 197 if (w1->_wrappedPtr == w2->_wrappedPtr) {
198 198 areSamePtrs = true;
199 199 }
200 200 } else if (w1->_obj == w2->_obj) {
201 201 areSamePtrs = true;
202 202 }
203 203 } else if (other == Py_None) {
204 204 validPtrs = true;
205 205 if (wrapper->_obj || wrapper->_wrappedPtr) {
206 206 areSamePtrs = false;
207 207 } else {
208 208 areSamePtrs = true;
209 209 }
210 210 }
211 211 }
212 212
213 213 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
214 214 // shortcut if richcompare is not supported:
215 215 if (validPtrs && code == Py_EQ) {
216 216 return PythonQtConv::GetPyBool(areSamePtrs);
217 217 } else if (validPtrs && code == Py_NE) {
218 218 return PythonQtConv::GetPyBool(!areSamePtrs);
219 219 }
220 220 Py_INCREF(Py_NotImplemented);
221 221 return Py_NotImplemented;
222 222 }
223 223
224 224 QByteArray memberName;
225 225 switch (code) {
226 226 case Py_LT:
227 227 {
228 228 static QByteArray name = "__lt__";
229 229 memberName = name;
230 230 }
231 231 break;
232 232
233 233 case Py_LE:
234 234 {
235 235 static QByteArray name = "__le__";
236 236 memberName = name;
237 237 }
238 238 break;
239 239
240 240 case Py_EQ:
241 241 {
242 242 static QByteArray name = "__eq__";
243 243 memberName = name;
244 244 }
245 245 break;
246 246
247 247 case Py_NE:
248 248 {
249 249 static QByteArray name = "__ne__";
250 250 memberName = name;
251 251 }
252 252 break;
253 253
254 254 case Py_GT:
255 255 {
256 256 static QByteArray name = "__gt__";
257 257 memberName = name;
258 258 }
259 259 break;
260 260
261 261 case Py_GE:
262 262 {
263 263 static QByteArray name = "__ge__";
264 264 memberName = name;
265 265 }
266 266 break;
267 267 }
268 268
269 269 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
270 270 if (opSlot._type == PythonQtMemberInfo::Slot) {
271 271 // TODO get rid of tuple
272 272 PyObject* args = PyTuple_New(1);
273 273 Py_INCREF(other);
274 274 PyTuple_SET_ITEM(args, 0, other);
275 275 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
276 276 Py_DECREF(args);
277 277 return result;
278 278 } else {
279 279 // not implemented, let python try something else!
280 280 Py_INCREF(Py_NotImplemented);
281 281 return Py_NotImplemented;
282 282 }
283 283 }
284 284
285 285
286 286 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
287 287 {
288 288 return PyString_FromString(obj->ob_type->tp_name);
289 289 }
290 290
291 291 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
292 292 {
293 293 return PythonQt::self()->helpCalled(obj->classInfo());
294 294 }
295 295
296 296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
297 297 {
298 298 PythonQtInstanceWrapper_deleteObject(self, true);
299 299 Py_INCREF(Py_None);
300 300 return Py_None;
301 301 }
302 302
303 303
304 304 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
305 305 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
306 306 "Return the classname of the object"
307 307 },
308 308 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
309 309 "Shows the help of available methods for this class"
310 310 },
311 311 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
312 312 "Deletes the C++ object (at your own risk, my friend!)"
313 313 },
314 314 {NULL, NULL, 0, NULL} /* Sentinel */
315 315 };
316 316
317 317
318 318 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
319 319 {
320 320 const char *attributeName;
321 321 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
322 322
323 323 if ((attributeName = PyString_AsString(name)) == NULL) {
324 324 return NULL;
325 325 }
326 326
327 327 if (qstrcmp(attributeName, "__dict__")==0) {
328 328 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
329 329 dict = PyDict_Copy(dict);
330 330
331 331 if (wrapper->_obj) {
332 332 // only the properties are missing, the rest is already available from
333 333 // PythonQtClassWrapper...
334 334 QStringList l = wrapper->classInfo()->propertyList();
335 335 foreach (QString name, l) {
336 336 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
337 337 if (o) {
338 338 PyDict_SetItemString(dict, name.toLatin1().data(), o);
339 339 Py_DECREF(o);
340 340 } else {
341 341 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
342 342 }
343 343 }
344 344
345 345 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
346 346 foreach (QByteArray name, dynamicProps) {
347 347 PyObject* o = PyObject_GetAttrString(obj, name.data());
348 348 if (o) {
349 349 PyDict_SetItemString(dict, name.data(), o);
350 350 Py_DECREF(o);
351 351 } else {
352 352 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
353 353 }
354 354 }
355 355 }
356 356 // Note: we do not put children into the dict, is would look confusing?!
357 357 return dict;
358 358 }
359 359
360 360 // first look in super, to return derived methods from base object first
361 361 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
362 362 if (superAttr) {
363 363 return superAttr;
364 364 }
365 365 PyErr_Clear();
366 366
367 367 // mlabDebugConst("Python","get " << attributeName);
368 368
369 369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
370 370 switch (member._type) {
371 371 case PythonQtMemberInfo::Property:
372 372 if (wrapper->_obj) {
373 373 if (member._property.userType() != QVariant::Invalid) {
374 374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
375 375 } else {
376 376 Py_INCREF(Py_None);
377 377 return Py_None;
378 378 }
379 379 } else {
380 380 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
381 381 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
382 382 return NULL;
383 383 }
384 384 break;
385 385 case PythonQtMemberInfo::Slot:
386 386 return PythonQtSlotFunction_New(member._slot, obj, NULL);
387 387 break;
388 388 case PythonQtMemberInfo::EnumValue:
389 389 {
390 390 PyObject* enumValue = member._enumValue;
391 391 Py_INCREF(enumValue);
392 392 return enumValue;
393 393 }
394 394 break;
395 395 case PythonQtMemberInfo::EnumWrapper:
396 396 {
397 397 PyObject* enumWrapper = member._enumWrapper;
398 398 Py_INCREF(enumWrapper);
399 399 return enumWrapper;
400 400 }
401 401 break;
402 402 case PythonQtMemberInfo::NotFound:
403 403 {
404 404 static const QByteArray getterString("py_get_");
405 405 // check for a getter slot
406 406 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
407 407 if (member._type == PythonQtMemberInfo::Slot) {
408 408 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
409 409 }
410 410
411 411 // handle dynamic properties
412 412 if (wrapper->_obj) {
413 413 QVariant v = wrapper->_obj->property(attributeName);
414 414 if (v.isValid()) {
415 415 return PythonQtConv::QVariantToPyObject(v);
416 416 }
417 417 }
418 418 }
419 419 break;
420 420 default:
421 421 // is an invalid type, go on
422 422 break;
423 423 }
424 424
425 425 // look for the internal methods (className(), help())
426 426 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
427 427 if (internalMethod) {
428 428 return internalMethod;
429 429 }
430 430 PyErr_Clear();
431 431
432 432 if (wrapper->_obj) {
433 433 // look for a child
434 434 QObjectList children = wrapper->_obj->children();
435 435 for (int i = 0; i < children.count(); i++) {
436 436 QObject *child = children.at(i);
437 437 if (child->objectName() == attributeName) {
438 438 return PythonQt::priv()->wrapQObject(child);
439 439 }
440 440 }
441 441 }
442 442
443 443 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
444 444 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
445 445 return NULL;
446 446 }
447 447
448 448 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
449 449 {
450 450 QString error;
451 451 const char *attributeName;
452 452 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
453 453
454 454 if ((attributeName = PyString_AsString(name)) == NULL)
455 455 return -1;
456 456
457 457 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
458 458 if (member._type == PythonQtMemberInfo::Property) {
459 459
460 460 if (!wrapper->_obj) {
461 461 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
462 462 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
463 463 return -1;
464 464 }
465 465
466 466 QMetaProperty prop = member._property;
467 467 if (prop.isWritable()) {
468 468 QVariant v;
469 469 if (prop.isEnumType()) {
470 470 // this will give us either a string or an int, everything else will probably be an error
471 471 v = PythonQtConv::PyObjToQVariant(value);
472 472 } else {
473 473 int t = prop.userType();
474 474 v = PythonQtConv::PyObjToQVariant(value, t);
475 475 }
476 476 bool success = false;
477 477 if (v.isValid()) {
478 478 success = prop.write(wrapper->_obj, v);
479 479 }
480 480 if (success) {
481 481 return 0;
482 482 } else {
483 483 error = QString("Property '") + attributeName + "' of type '" +
484 484 prop.typeName() + "' does not accept an object of type "
485 485 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
486 486 }
487 487 } else {
488 488 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
489 489 }
490 490 } else if (member._type == PythonQtMemberInfo::Slot) {
491 491 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
492 492 } else if (member._type == PythonQtMemberInfo::EnumValue) {
493 493 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
494 494 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
495 495 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
496 496 } else if (member._type == PythonQtMemberInfo::NotFound) {
497 497 // check for a setter slot
498 498 static const QByteArray setterString("py_set_");
499 499 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
500 500 if (setter._type == PythonQtMemberInfo::Slot) {
501 501 // call the setter and ignore the result value
502 502 void* result;
503 503 PyObject* args = PyTuple_New(1);
504 504 Py_INCREF(value);
505 505 PyTuple_SET_ITEM(args, 0, value);
506 506 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
507 507 Py_DECREF(args);
508 508 return 0;
509 509 }
510 510
511 511 // handle dynamic properties
512 512 if (wrapper->_obj) {
513 513 QVariant prop = wrapper->_obj->property(attributeName);
514 514 if (prop.isValid()) {
515 515 QVariant v = PythonQtConv::PyObjToQVariant(value);
516 516 if (v.isValid()) {
517 517 wrapper->_obj->setProperty(attributeName, v);
518 518 return 0;
519 519 } else {
520 520 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
521 521 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
522 522 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
523 523 return -1;
524 524 }
525 525 }
526 526 }
527 527
528 528 // if we are a derived python class, we allow setting attributes.
529 529 // if we are a direct CPP wrapper, we do NOT allow it, since
530 530 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
531 531 // and when it is recreated from a CPP pointer the attributes are gone...
532 532 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
533 533 return PyBaseObject_Type.tp_setattro(obj,name,value);
534 534 } else {
535 535 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
536 536 }
537 537 }
538 538
539 539 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
540 540 return -1;
541 541 }
542 542
543 543 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
544 544 QString result;
545 545 if (wrapper->_wrappedPtr) {
546 546 // first try some manually string conversions for some variants
547 547 int metaid = wrapper->classInfo()->metaTypeId();
548 548 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
549 549 if (!result.isEmpty()) {
550 550 return result;
551 551 }
552 552 }
553 553 // next, try to call py_toString
554 554 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
555 555 if (info._type == PythonQtMemberInfo::Slot) {
556 556 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
557 557 if (resultObj) {
558 558 // TODO this is one conversion too much, would be nicer to call the slot directly...
559 559 result = PythonQtConv::PyObjGetString(resultObj);
560 560 Py_DECREF(resultObj);
561 561 }
562 562 }
563 563 return result;
564 564 }
565 565
566 566 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
567 567 {
568 568 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
569 569
570 570 // QByteArray should be directly returned as a str
571 571 if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) {
572 572 QByteArray* b = (QByteArray*) wrapper->_wrappedPtr;
573 573 if (b->data()) {
574 574 return PyString_FromStringAndSize(b->data(), b->size());
575 575 } else {
576 576 return PyString_FromString("");
577 577 }
578 578 }
579 579
580 580 const char* typeName = obj->ob_type->tp_name;
581 581 QObject *qobj = wrapper->_obj;
582 582 QString str = getStringFromObject(wrapper);
583 583 if (!str.isEmpty()) {
584 584 return PyString_FromFormat("%s", str.toLatin1().constData());
585 585 }
586 586 if (wrapper->_wrappedPtr) {
587 587 if (wrapper->_obj) {
588 588 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
589 589 } else {
590 590 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
591 591 }
592 592 } else {
593 593 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
594 594 }
595 595 }
596 596
597 597 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
598 598 {
599 599 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
600 600 const char* typeName = obj->ob_type->tp_name;
601 601
602 602 QObject *qobj = wrapper->_obj;
603 603 QString str = getStringFromObject(wrapper);
604 604 if (!str.isEmpty()) {
605 605 if (str.startsWith(typeName)) {
606 606 return PyString_FromFormat("%s", str.toLatin1().constData());
607 607 } else {
608 608 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
609 609 }
610 610 }
611 611 if (wrapper->_wrappedPtr) {
612 612 if (wrapper->_obj) {
613 613 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
614 614 } else {
615 615 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
616 616 }
617 617 } else {
618 618 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
619 619 }
620 620 }
621 621
622 622 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
623 623 {
624 624 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
625 625 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
626 626 }
627 627
628 628
629 629 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
630 630 {
631 631 if (obj->_wrappedPtr != NULL) {
632 632 return reinterpret_cast<long>(obj->_wrappedPtr);
633 633 } else {
634 634 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
635 635 return reinterpret_cast<long>(qobj);
636 636 }
637 637 }
638 638
639 639
640 640
641 641 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
642 642 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
643 643 0, /* nb_add */
644 644 0, /* nb_subtract */
645 645 0, /* nb_multiply */
646 646 0, /* nb_divide */
647 647 0, /* nb_remainder */
648 648 0, /* nb_divmod */
649 649 0, /* nb_power */
650 650 0, /* nb_negative */
651 651 0, /* nb_positive */
652 652 0, /* nb_absolute */
653 653 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
654 654 0, /* nb_invert */
655 655 0, /* nb_lshift */
656 656 0, /* nb_rshift */
657 657 0, /* nb_and */
658 658 0, /* nb_xor */
659 659 0, /* nb_or */
660 660 0, /* nb_coerce */
661 661 0, /* nb_int */
662 662 0, /* nb_long */
663 663 0, /* nb_float */
664 664 0, /* nb_oct */
665 665 0, /* nb_hex */
666 666 0, /* nb_inplace_add */
667 667 0, /* nb_inplace_subtract */
668 668 0, /* nb_inplace_multiply */
669 669 0, /* nb_inplace_divide */
670 670 0, /* nb_inplace_remainder */
671 671 0, /* nb_inplace_power */
672 672 0, /* nb_inplace_lshift */
673 673 0, /* nb_inplace_rshift */
674 674 0, /* nb_inplace_and */
675 675 0, /* nb_inplace_xor */
676 676 0, /* nb_inplace_or */
677 677 0, /* nb_floor_divide */
678 678 0, /* nb_true_divide */
679 679 0, /* nb_inplace_floor_divide */
680 680 0, /* nb_inplace_true_divide */
681 681 };
682 682
683 683 PyTypeObject PythonQtInstanceWrapper_Type = {
684 684 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
685 685 0, /*ob_size*/
686 686 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
687 687 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
688 688 0, /*tp_itemsize*/
689 689 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
690 690 0, /*tp_print*/
691 691 0, /*tp_getattr*/
692 692 0, /*tp_setattr*/
693 693 0, /*tp_compare*/
694 694 PythonQtInstanceWrapper_repr, /*tp_repr*/
695 695 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
696 696 0, /*tp_as_sequence*/
697 697 0, /*tp_as_mapping*/
698 698 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
699 699 0, /*tp_call*/
700 700 PythonQtInstanceWrapper_str, /*tp_str*/
701 701 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
702 702 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
703 703 0, /*tp_as_buffer*/
704 704 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
705 705 "PythonQtInstanceWrapper object", /* tp_doc */
706 706 0, /* tp_traverse */
707 707 0, /* tp_clear */
708 708 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
709 709 0, /* tp_weaklistoffset */
710 710 0, /* tp_iter */
711 711 0, /* tp_iternext */
712 712 0, /* tp_methods */
713 713 0, /* tp_members */
714 714 0, /* tp_getset */
715 715 0, /* tp_base */
716 716 0, /* tp_dict */
717 717 0, /* tp_descr_get */
718 718 0, /* tp_descr_set */
719 719 0, /* tp_dictoffset */
720 720 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
721 721 0, /* tp_alloc */
722 722 PythonQtInstanceWrapper_new, /* tp_new */
723 723 };
724 724
725 725 //-------------------------------------------------------
726 726
@@ -1,98 +1,98
1 1 #ifndef _PYTHONQTINSTANCEWRAPPER_H
2 2 #define _PYTHONQTINSTANCEWRAPPER_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtInstanceWrapper.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46
47 47 #include "PythonQtSystem.h"
48 48 #include <QPointer>
49 49
50 50 #include "structmember.h"
51 51 #include "methodobject.h"
52 52 #include "compile.h"
53 53 #include "eval.h"
54 54
55 55 class PythonQtClassInfo;
56 56 class QObject;
57 57
58 58 extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type;
59 59
60 60 //---------------------------------------------------------------
61 61 //! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects)
62 62 typedef struct PythonQtInstanceWrapperStruct {
63 63 PyObject_HEAD
64 64
65 65 //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
66 66 PythonQtClassInfo* classInfo();
67 67
68 68 //! set the QObject pointer
69 69 void setQObject(QObject* object) {
70 70 _obj = object;
71 71 _objPointerCopy = object;
72 72 }
73 73
74 74 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
75 75 QPointer<QObject> _obj;
76 76 //! a copy of the _obj pointer, which is required because the wrapper needs to
77 77 //! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
78 78 void* _objPointerCopy;
79 79
80 80 //! optional C++ object Ptr that is wrapped by the above _obj
81 81 void* _wrappedPtr;
82 82
83 83 // TODO xxx: put booleans into int that holds flags
84 84
85 85 //! flag that stores if the object is owned by pythonQt
86 86 bool _ownedByPythonQt;
87 87
88 88 //! stores that the owned object should be destroyed using QMetaType::destroy()
89 89 bool _useQMetaTypeDestroy;
90 90
91 91 //! stores if the object is a shell instance
92 92 bool _isShellInstance;
93 93
94 94 } PythonQtInstanceWrapper;
95 95
96 96 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds);
97 97
98 98 #endif No newline at end of file
@@ -1,351 +1,351
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMethodInfo.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 102 arguments << QByteArray(args[i]);
103 103 }
104 104 fullSig += ")";
105 105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 106 if (!result) {
107 107 result = new PythonQtMethodInfo(typeName, arguments);
108 108 _cachedSignatures.insert(fullSig, result);
109 109 }
110 110 return result;
111 111 }
112 112
113 113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
114 114 {
115 115 QByteArray name = orgName;
116 116
117 117 type.enumWrapper = NULL;
118 118
119 119 int len = name.length();
120 120 if (len>0) {
121 121 if (strncmp(name.constData(), "const ", 6)==0) {
122 122 name = name.mid(6);
123 123 len -= 6;
124 124 type.isConst = true;
125 125 } else {
126 126 type.isConst = false;
127 127 }
128 128 bool hadPointer = false;
129 129 bool hadReference = false;
130 130 // remove * and & from the end of the string, handle & and * the same way
131 131 while (name.at(len-1) == '*') {
132 132 len--;
133 133 hadPointer = true;
134 134 }
135 135 while (name.at(len-1) == '&') {
136 136 len--;
137 137 hadReference = true;
138 138 }
139 139 if (len!=name.length()) {
140 140 name = name.left(len);
141 141 }
142 142 type.isPointer = hadPointer;
143 143
144 144 QByteArray alias = _parameterNameAliases.value(name);
145 145 if (!alias.isEmpty()) {
146 146 name = alias;
147 147 }
148 148
149 149 type.typeId = nameToType(name);
150 150 if (!type.isPointer && type.typeId == Unknown) {
151 151 type.typeId = QMetaType::type(name.constData());
152 152 if (type.typeId == QMetaType::Void) {
153 153 type.typeId = Unknown;
154 154 }
155 155 }
156 156 type.name = name;
157 157
158 158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
159 159 bool isLocalEnum;
160 160 // TODOXXX: make use of this flag!
161 161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
162 162 }
163 163 } else {
164 164 type.typeId = QMetaType::Void;
165 165 type.isPointer = false;
166 166 type.isConst = false;
167 167 }
168 168 }
169 169
170 170 int PythonQtMethodInfo::nameToType(const char* name)
171 171 {
172 172 if (_parameterTypeDict.isEmpty()) {
173 173 // we could also use QMetaType::nameToType, but that does a string compare search
174 174 // and does not support QVariant
175 175
176 176 // QMetaType names
177 177 _parameterTypeDict.insert("long", QMetaType::Long);
178 178 _parameterTypeDict.insert("int", QMetaType::Int);
179 179 _parameterTypeDict.insert("short", QMetaType::Short);
180 180 _parameterTypeDict.insert("char", QMetaType::Char);
181 181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
182 182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
183 183 _parameterTypeDict.insert("uint", QMetaType::UInt);
184 184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
185 185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
186 186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
187 187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
188 188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
189 189 _parameterTypeDict.insert("bool", QMetaType::Bool);
190 190 _parameterTypeDict.insert("float", QMetaType::Float);
191 191 _parameterTypeDict.insert("double", QMetaType::Double);
192 192 _parameterTypeDict.insert("qreal", QMetaType::Double);
193 193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
194 194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
195 195 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
196 196 _parameterTypeDict.insert("QString", QMetaType::QString);
197 197 _parameterTypeDict.insert("", QMetaType::Void);
198 198 _parameterTypeDict.insert("void", QMetaType::Void);
199 199 // QVariant names
200 200 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
201 201 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
202 202 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
203 203 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
204 204 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
205 205 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
206 206 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
207 207 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
208 208 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
209 209 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
210 210 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
211 211 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
212 212 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
213 213 _parameterTypeDict.insert("QDate", QMetaType::QDate);
214 214 _parameterTypeDict.insert("QTime", QMetaType::QTime);
215 215 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
216 216 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
217 217 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
218 218 _parameterTypeDict.insert("QRect", QMetaType::QRect);
219 219 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
220 220 _parameterTypeDict.insert("QSize", QMetaType::QSize);
221 221 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
222 222 _parameterTypeDict.insert("QLine", QMetaType::QLine);
223 223 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
224 224 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
225 225 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
226 226 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
227 227 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
228 228 _parameterTypeDict.insert("QFont", QMetaType::QFont);
229 229 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
230 230 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
231 231 _parameterTypeDict.insert("QColor", QMetaType::QColor);
232 232 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
233 233 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
234 234 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
235 235 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
236 236 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
237 237 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
238 238 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
239 239 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
240 240 _parameterTypeDict.insert("QPen", QMetaType::QPen);
241 241 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
242 242 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
243 243 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
244 244 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
245 245 // own special types... (none so far, could be e.g. ObjectList
246 246 }
247 247 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
248 248 if (it!=_parameterTypeDict.end()) {
249 249 return it.value();
250 250 } else {
251 251 return PythonQtMethodInfo::Unknown;
252 252 }
253 253 }
254 254
255 255 void PythonQtMethodInfo::cleanupCachedMethodInfos()
256 256 {
257 257 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
258 258 while (i.hasNext()) {
259 259 delete i.next().value();
260 260 }
261 261 }
262 262
263 263 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
264 264 {
265 265 _parameterNameAliases.insert(alias, name);
266 266 }
267 267
268 268 //-------------------------------------------------------------------------------------------------
269 269
270 270 void PythonQtSlotInfo::deleteOverloadsAndThis()
271 271 {
272 272 PythonQtSlotInfo* cur = this;
273 273 while(cur->nextInfo()) {
274 274 PythonQtSlotInfo* next = cur->nextInfo();
275 275 delete cur;
276 276 cur = next;
277 277 }
278 278 }
279 279
280 280
281 281 QString PythonQtSlotInfo::fullSignature()
282 282 {
283 283 bool skipFirstArg = isInstanceDecorator();
284 284 QString result = _meta.typeName();
285 285 QByteArray sig = slotName();
286 286 QList<QByteArray> names = _meta.parameterNames();
287 287
288 288 bool isStatic = false;
289 289 bool isConstructor = false;
290 290 bool isDestructor = false;
291 291
292 292 if (_type == ClassDecorator) {
293 293 if (sig.startsWith("new_")) {
294 294 sig = sig.mid(strlen("new_"));
295 295 isConstructor = true;
296 296 } else if (sig.startsWith("delete_")) {
297 297 sig = sig.mid(strlen("delete_"));
298 298 isDestructor = true;
299 299 } else if(sig.startsWith("static_")) {
300 300 isStatic = true;
301 301 sig = sig.mid(strlen("static_"));
302 302 int idx = sig.indexOf("_");
303 303 if (idx>=0) {
304 304 sig = sig.mid(idx+1);
305 305 }
306 306 }
307 307 }
308 308
309 309 result += QByteArray(" ") + sig;
310 310 result += "(";
311 311
312 312 int lastEntry = _parameters.count()-1;
313 313 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
314 314 if (_parameters.at(i).isConst) {
315 315 result += "const ";
316 316 }
317 317 result += _parameters.at(i).name;
318 318 if (_parameters.at(i).isPointer) {
319 319 result += "*";
320 320 }
321 321 if (!names.at(i-1).isEmpty()) {
322 322 result += " ";
323 323 result += names.at(i-1);
324 324 }
325 325 if (i!=lastEntry) {
326 326 result += ", ";
327 327 }
328 328 }
329 329 result += ")";
330 330
331 331 if (isStatic) {
332 332 result = QString("static ") + result;
333 333 }
334 334 if (isConstructor) {
335 335 // result = QString("constructor ") + result;
336 336 }
337 337 if (isDestructor) {
338 338 result = QString("~") + result;
339 339 }
340 340 return result;
341 341 }
342 342
343 343
344 344 QByteArray PythonQtSlotInfo::slotName()
345 345 {
346 346 QByteArray sig(_meta.signature());
347 347 int idx = sig.indexOf('(');
348 348 sig = sig.left(idx);
349 349 return sig;
350 350 }
351 351
@@ -1,190 +1,190
1 1 #ifndef _PYTHONQTMETHODINFO_H
2 2 #define _PYTHONQTMETHODINFO_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMethodInfo.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46
47 47 #include <QByteArray>
48 48 #include <QHash>
49 49 #include <QList>
50 50 #include <QMetaMethod>
51 51
52 52 class PythonQtClassInfo;
53 53 struct _object;
54 54 typedef struct _object PyObject;
55 55
56 56 //! stores information about a specific signal/slot/method
57 57 class PYTHONQT_EXPORT PythonQtMethodInfo
58 58 {
59 59 public:
60 60 enum ParameterType {
61 61 Unknown = -1,
62 62 Variant = -2
63 63 };
64 64
65 65 //! stores the QVariant id (if available) and the name of the type
66 66 struct ParameterInfo {
67 67 QByteArray name;
68 68 PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
69 69 int typeId; // a mixture from QMetaType and ParameterType
70 70 bool isPointer;
71 71 bool isConst;
72 72 };
73 73
74 74 PythonQtMethodInfo() {};
75 75 ~PythonQtMethodInfo() {};
76 76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
77 77 PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
78 78 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
79 79 _parameters = other._parameters;
80 80 }
81 81
82 82 //! returns the method info of the signature, uses a cache internally to speed up
83 83 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
84 84 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
85 85
86 86 //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
87 87 static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
88 88
89 89 //! cleanup the cache
90 90 static void cleanupCachedMethodInfos();
91 91
92 92 //! returns the number of parameters including the return value
93 93 int parameterCount() const { return _parameters.size(); };
94 94
95 95 //! returns the id for the given type (using an internal dictionary)
96 96 static int nameToType(const char* name);
97 97
98 98 //! get the parameter infos
99 99 const QList<ParameterInfo>& parameters() const { return _parameters; }
100 100
101 101 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
102 102 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
103 103
104 104 protected:
105 105 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
106 106
107 107 static QHash<QByteArray, int> _parameterTypeDict;
108 108 static QHash<QByteArray, QByteArray> _parameterNameAliases;
109 109
110 110 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
111 111 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
112 112
113 113 QList<ParameterInfo> _parameters;
114 114 };
115 115
116 116 //! stores information about a slot, including a next pointer to overloaded slots
117 117 class PythonQtSlotInfo : public PythonQtMethodInfo
118 118 {
119 119 public:
120 120 enum Type {
121 121 MemberSlot, InstanceDecorator, ClassDecorator
122 122 };
123 123
124 124 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
125 125 _meta = info._meta;
126 126 _parameters = info._parameters;
127 127 _slotIndex = info._slotIndex;
128 128 _next = NULL;
129 129 _decorator = info._decorator;
130 130 _type = info._type;
131 131 _upcastingOffset = 0;
132 132 }
133 133
134 134 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
135 135 {
136 136 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
137 137 _meta = meta;
138 138 _parameters = info->parameters();
139 139 _slotIndex = slotIndex;
140 140 _next = NULL;
141 141 _decorator = decorator;
142 142 _type = type;
143 143 _upcastingOffset = 0;
144 144 }
145 145
146 146
147 147 public:
148 148
149 149 void deleteOverloadsAndThis();
150 150
151 151 const QMetaMethod* metaMethod() const { return &_meta; }
152 152
153 153 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
154 154
155 155 int upcastingOffset() const { return _upcastingOffset; }
156 156
157 157 //! get the index of the slot (needed for qt_metacall)
158 158 int slotIndex() const { return _slotIndex; }
159 159
160 160 //! get next overloaded slot (which has the same name)
161 161 PythonQtSlotInfo* nextInfo() const { return _next; }
162 162
163 163 //! set the next overloaded slot
164 164 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
165 165
166 166 //! returns if the slot is a decorator slot
167 167 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
168 168
169 169 //! returns if the slot is a constructor slot
170 170 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
171 171
172 172 QObject* decorator() { return _decorator; }
173 173
174 174 //! get the full signature including return type
175 175 QString fullSignature();
176 176
177 177 //! get the short slot name
178 178 QByteArray slotName();
179 179
180 180 private:
181 181 int _slotIndex;
182 182 PythonQtSlotInfo* _next;
183 183 QObject* _decorator;
184 184 Type _type;
185 185 QMetaMethod _meta;
186 186 int _upcastingOffset;
187 187 };
188 188
189 189
190 190 #endif
@@ -1,43 +1,43
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMisc.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMisc.h"
43 43
@@ -1,142 +1,142
1 1 #ifndef _PYTHONQTMISC_H
2 2 #define _PYTHONQTMISC_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMisc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45
46 46 #include <QList>
47 47
48 48 #define PythonQtValueStorage_ADD_VALUE(store, type, value, ptr) \
49 49 { type* item = (type*)store.nextValuePtr(); \
50 50 *item = value; \
51 51 ptr = (void*)item; \
52 52 }
53 53
54 54 #define PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, type, value, ptr) \
55 55 { \
56 56 type* item = (type*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store.nextValuePtr()); \
57 57 *item = value; \
58 58 ptr = (void*)item; \
59 59 }
60 60
61 61 //! stores a position in the PythonQtValueStorage
62 62 class PythonQtValueStoragePosition {
63 63
64 64 public:
65 65 PythonQtValueStoragePosition() { chunkIdx = 0; chunkOffset = 0; }
66 66
67 67 int chunkIdx;
68 68 int chunkOffset;
69 69
70 70 };
71 71
72 72 //! a helper class that stores basic C++ value types in chunks
73 73 template <typename T, int chunkEntries> class PythonQtValueStorage
74 74 {
75 75 public:
76 76 PythonQtValueStorage() {
77 77 _chunkIdx = 0;
78 78 _chunkOffset = 0;
79 79 _currentChunk = new T[chunkEntries];
80 80 _chunks.append(_currentChunk);
81 81 };
82 82
83 83 //! clear all memory
84 84 void clear() {
85 85 T* chunk;
86 86 foreach(chunk, _chunks) {
87 87 delete[]chunk;
88 88 }
89 89 _chunks.clear();
90 90 }
91 91
92 92 //! reset the storage to 0 (without freeing memory, thus caching old entries for reuse)
93 93 void reset() {
94 94 _chunkIdx = 0;
95 95 _chunkOffset = 0;
96 96 _currentChunk = _chunks.at(0);
97 97 }
98 98
99 99 //! get the current position to be restored with setPos
100 100 void getPos(PythonQtValueStoragePosition & pos) {
101 101 pos.chunkIdx = _chunkIdx;
102 102 pos.chunkOffset = _chunkOffset;
103 103 }
104 104
105 105 //! set the current position (without freeing memory, thus caching old entries for reuse)
106 106 void setPos(const PythonQtValueStoragePosition& pos) {
107 107 _chunkOffset = pos.chunkOffset;
108 108 if (_chunkIdx != pos.chunkIdx) {
109 109 _chunkIdx = pos.chunkIdx;
110 110 _currentChunk = _chunks.at(_chunkIdx);
111 111 }
112 112 }
113 113
114 114 //! add one default constructed value and return the pointer to it
115 115 T* nextValuePtr() {
116 116 if (_chunkOffset>=chunkEntries) {
117 117 _chunkIdx++;
118 118 if (_chunkIdx >= _chunks.size()) {
119 119 T* newChunk = new T[chunkEntries];
120 120 _chunks.append(newChunk);
121 121 _currentChunk = newChunk;
122 122 } else {
123 123 _currentChunk = _chunks.at(_chunkIdx);
124 124 }
125 125 _chunkOffset = 0;
126 126 }
127 127 T* newEntry = _currentChunk + _chunkOffset;
128 128 _chunkOffset++;
129 129 return newEntry;
130 130 };
131 131
132 132 private:
133 133 QList<T*> _chunks;
134 134
135 135 int _chunkIdx;
136 136 int _chunkOffset;
137 137 T* _currentChunk;
138 138
139 139 };
140 140
141 141
142 142 #endif
@@ -1,101 +1,101
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtObjectPtr.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include <PythonQt.h>
43 43
44 44 QVariant PythonQtObjectPtr::evalScript(const QString& script, int start)
45 45 {
46 46 return PythonQt::self()->evalScript(_object, script, start);
47 47 }
48 48
49 49 void PythonQtObjectPtr::evalFile(const QString& file)
50 50 {
51 51 PythonQt::self()->evalFile(_object, file);
52 52 }
53 53
54 54 QVariant PythonQtObjectPtr::evalCode(PyObject* pycode)
55 55 {
56 56 return PythonQt::self()->evalCode(_object, pycode);
57 57 }
58 58
59 59 void PythonQtObjectPtr::addObject(const QString& name, QObject* object)
60 60 {
61 61 PythonQt::self()->addObject(_object, name, object);
62 62 }
63 63
64 64 void PythonQtObjectPtr::addVariable(const QString& name, const QVariant& v)
65 65 {
66 66 PythonQt::self()->addVariable(_object, name, v);
67 67 }
68 68
69 69 void PythonQtObjectPtr::removeVariable(const QString& name)
70 70 {
71 71 PythonQt::self()->removeVariable(_object, name);
72 72 }
73 73
74 74 QVariant PythonQtObjectPtr::getVariable(const QString& name)
75 75 {
76 76 return PythonQt::self()->getVariable(_object, name);
77 77 }
78 78
79 79
80 80 QVariant PythonQtObjectPtr::call(const QString& callable, const QVariantList& args)
81 81 {
82 82 return PythonQt::self()->call(_object, callable, args);
83 83 }
84 84
85 85 QVariant PythonQtObjectPtr::call(const QVariantList& args)
86 86 {
87 87 return PythonQt::self()->call(_object, args);
88 88 }
89 89
90 90 bool PythonQtObjectPtr::fromVariant(const QVariant& variant)
91 91 {
92 92 if (!variant.isNull()) {
93 93 setObject(qVariantValue<PythonQtObjectPtr>(variant));
94 94 return true;
95 95 }
96 96 else {
97 97 setObject(0);
98 98 return false;
99 99 }
100 100
101 101 }
@@ -1,174 +1,174
1 1 #ifndef _PYTHONQTOBJECTPTR_H
2 2 #define _PYTHONQTOBJECTPTR_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtObjectPtr.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include <QVariant>
48 48 #include <QVariantList>
49 49
50 50 //! a smart pointer that stores a PyObject pointer and that handles reference counting automatically
51 51 class PYTHONQT_EXPORT PythonQtObjectPtr
52 52 {
53 53 public:
54 54 PythonQtObjectPtr():_object(NULL) {}
55 55
56 56 PythonQtObjectPtr(const PythonQtObjectPtr &p):_object(NULL) {
57 57 setObject(p.object());
58 58 }
59 59
60 60 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
61 61 PythonQtObjectPtr(const QVariant& variant):_object(NULL) {
62 62 fromVariant(variant);
63 63 }
64 64
65 65 PythonQtObjectPtr(PyObject* o) {
66 66 _object = o;
67 67 if (o) Py_INCREF(_object);
68 68 }
69 69
70 70 ~PythonQtObjectPtr() { if (_object) Py_DECREF(_object); }
71 71
72 72 //! If the given variant holds a PythonQtObjectPtr, extract the value from it and hold onto the reference. This results in an increment of the reference count.
73 73 bool fromVariant(const QVariant& variant);
74 74
75 75 PythonQtObjectPtr &operator=(const PythonQtObjectPtr &p) {
76 76 setObject(p.object());
77 77 return *this;
78 78 }
79 79
80 80 PythonQtObjectPtr &operator=(PyObject* o) {
81 81 setObject(o);
82 82 return *this;
83 83 }
84 84
85 85
86 86 PythonQtObjectPtr &operator=(const QVariant& variant) {
87 87 fromVariant(variant);
88 88 return *this;
89 89 }
90 90
91 91
92 92 bool operator==( const PythonQtObjectPtr &p ) const {
93 93 return object() == p.object();
94 94 }
95 95
96 96 bool operator!= ( const PythonQtObjectPtr& p ) const {
97 97 return !( *this == p );
98 98 }
99 99
100 100 bool operator==( PyObject* p ) const {
101 101 return object() == p;
102 102 }
103 103
104 104 bool operator!= ( PyObject* p ) const {
105 105 return object() != p;
106 106 }
107 107
108 108 bool isNull() const { return !object(); }
109 109
110 110 PyObject* operator->() const { return object(); }
111 111
112 112 PyObject& operator*() const { return *( object() ); }
113 113
114 114 operator PyObject*() const { return object(); }
115 115
116 116 //! sets the object and passes the ownership (stealing the reference, in Python slang)
117 117 void setNewRef(PyObject* o) {
118 118 if (o != _object) {
119 119 if (_object) Py_DECREF(_object);
120 120 _object = o;
121 121 }
122 122 }
123 123
124 124 PyObject* object() const {
125 125 return _object;
126 126 }
127 127
128 128 //! evaluates the given script code in the context of this object and returns the result value
129 129 QVariant evalScript(const QString& script, int start = Py_file_input);
130 130
131 131 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
132 132 //! If pycode is NULL, a python error is printed.
133 133 QVariant evalCode(PyObject* pycode);
134 134
135 135 //! evaluates the given code in the context
136 136 void evalFile(const QString& filename);
137 137
138 138 //! add the given \c object to the \c module as a variable with \c name (it can be removed via clearVariable)
139 139 void addObject(const QString& name, QObject* object);
140 140
141 141 //! add the given variable to the module
142 142 void addVariable(const QString& name, const QVariant& v);
143 143
144 144 //! remove the given variable
145 145 void removeVariable(const QString& name);
146 146
147 147 //! get the variable with the \c name of the \c module, returns an invalid QVariant on error
148 148 QVariant getVariable(const QString& name);
149 149
150 150 //! call the given python object (in the scope of the current object), returns the result converted to a QVariant
151 151 QVariant call(const QString& callable, const QVariantList& args = QVariantList());
152 152
153 153 //! call the contained python object directly, returns the result converted to a QVariant
154 154 QVariant call(const QVariantList& args = QVariantList());
155 155
156 156 protected:
157 157
158 158 void setObject(PyObject* o) {
159 159 if (o != _object) {
160 160 if (_object) Py_DECREF(_object);
161 161 _object = o;
162 162 if (_object) Py_INCREF(_object);
163 163 }
164 164 }
165 165
166 166 private:
167 167 PyObject* _object;
168 168 };
169 169
170 170
171 171 // register it to the meta type system
172 172 Q_DECLARE_METATYPE(PythonQtObjectPtr)
173 173
174 174 #endif No newline at end of file
@@ -1,80 +1,80
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtQFileImporter.h
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2009-03
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include <QFile>
43 43 #include <QFileInfo>
44 44
45 45 #include "PythonQtQFileImporter.h"
46 46
47 47 PythonQtQFileImporter::PythonQtQFileImporter() {
48 48 }
49 49
50 50 PythonQtQFileImporter::~PythonQtQFileImporter() {
51 51 }
52 52
53 53 QByteArray PythonQtQFileImporter::readFileAsBytes (const QString &filename) {
54 54 QFile f(filename);
55 55 if (f.open(QIODevice::ReadOnly)) {
56 56 return f.readAll();
57 57 } else {
58 58 return QByteArray();
59 59 }
60 60 }
61 61
62 62 QByteArray PythonQtQFileImporter::readSourceFile (const QString &filename, bool &ok) {
63 63 QFile f(filename);
64 64 if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
65 65 ok = true;
66 66 return f.readAll();
67 67 } else {
68 68 ok = false;
69 69 return QByteArray();
70 70 }
71 71 }
72 72
73 73 bool PythonQtQFileImporter::exists (const QString &filename) {
74 74 return QFile::exists(filename);
75 75 }
76 76
77 77 QDateTime PythonQtQFileImporter::lastModifiedDate (const QString &filename) {
78 78 QFileInfo fi(filename);
79 79 return fi.lastModified();
80 80 }
@@ -1,63 +1,63
1 1 #ifndef _PYTHONQTQFILEIMPORTER_H
2 2 #define _PYTHONQTQFILEIMPORTER_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtQFileImporter.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2009-03
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <PythonQtImportFileInterface.h>
46 46
47 47 //! default importer implementation using QFile to load python code
48 48 class PythonQtQFileImporter : public PythonQtImportFileInterface {
49 49 public:
50 50 PythonQtQFileImporter();
51 51 ~PythonQtQFileImporter();
52 52
53 53 QByteArray readFileAsBytes (const QString &filename);
54 54
55 55 QByteArray readSourceFile (const QString &filename, bool &ok);
56 56
57 57 bool exists (const QString &filename);
58 58
59 59 QDateTime lastModifiedDate (const QString &filename);
60 60
61 61 };
62 62
63 63 #endif
@@ -1,226 +1,226
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSignalReceiver.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtSignalReceiver.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include "PythonQtMethodInfo.h"
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 48 #include "funcobject.h"
49 49
50 50 void PythonQtSignalTarget::call(void **arguments) const {
51 51 PyObject* result = call(_callable, methodInfo(), arguments);
52 52 if (result) {
53 53 Py_DECREF(result);
54 54 }
55 55 }
56 56
57 57 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInfo* methodInfos, void **arguments, bool skipFirstArgumentOfMethodInfo)
58 58 {
59 59 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
60 60 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
61 61
62 62 int numPythonArgs = -1;
63 63 if (PyFunction_Check(callable)) {
64 64 PyObject* o = callable;
65 65 PyFunctionObject* func = (PyFunctionObject*)o;
66 66 PyCodeObject* code = (PyCodeObject*)func->func_code;
67 67 if (!(code->co_flags & 0x04)) {
68 68 numPythonArgs = code->co_argcount;
69 69 } else {
70 70 // variable numbers of arguments allowed
71 71 }
72 72 } else if (PyMethod_Check(callable)) {
73 73 PyObject* o = callable;
74 74 PyMethodObject* method = (PyMethodObject*)o;
75 75 if (PyFunction_Check(method->im_func)) {
76 76 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
77 77 PyCodeObject* code = (PyCodeObject*)func->func_code;
78 78 if (!(code->co_flags & 0x04)) {
79 79 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
80 80 } else {
81 81 // variable numbers of arguments allowed
82 82 }
83 83 }
84 84 }
85 85
86 86 const PythonQtMethodInfo* m = methodInfos;
87 87 // parameterCount includes return value:
88 88 int count = m->parameterCount();
89 89 if (numPythonArgs!=-1) {
90 90 if (count>numPythonArgs+1) {
91 91 // take less arguments
92 92 count = numPythonArgs+1;
93 93 }
94 94 }
95 95
96 96 PyObject* pargs = NULL;
97 97 if (count>1) {
98 98 pargs = PyTuple_New(count-1);
99 99 }
100 100 bool err = false;
101 101 // transform Qt values to Python
102 102 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
103 103 for (int i = 1; i < count; i++) {
104 104 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
105 105 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
106 106 if (arg) {
107 107 // steals reference, no unref
108 108 PyTuple_SetItem(pargs, i-1,arg);
109 109 } else {
110 110 err = true;
111 111 break;
112 112 }
113 113 }
114 114
115 115 PyObject* result = NULL;
116 116 if (!err) {
117 117 PyErr_Clear();
118 118 result = PyObject_CallObject(callable, pargs);
119 119 if (result) {
120 120 // ok
121 121 } else {
122 122 PythonQt::self()->handleError();
123 123 }
124 124 }
125 125 if (pargs) {
126 126 // free the arguments again
127 127 Py_DECREF(pargs);
128 128 }
129 129
130 130 return result;
131 131 }
132 132
133 133 //------------------------------------------------------------------------------
134 134
135 135 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalReceiverBase(obj)
136 136 {
137 137 _obj = obj;
138 138
139 139 // fetch the class info for object, since we will need to for correct enum resolution in
140 140 // signals
141 141 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
142 142 if (!_objClassInfo || !_objClassInfo->isQObject()) {
143 143 PythonQt::self()->registerClass(obj->metaObject());
144 144 _objClassInfo = PythonQt::priv()->getClassInfo(obj->metaObject());
145 145 }
146 146 // force decorator/enum creation
147 147 _objClassInfo->decorator();
148 148
149 149 _slotCount = staticMetaObject.methodOffset();
150 150 }
151 151
152 152 PythonQtSignalReceiver::~PythonQtSignalReceiver()
153 153 {
154 154 PythonQt::priv()->removeSignalEmitter(_obj);
155 155 }
156 156
157 157
158 158 bool PythonQtSignalReceiver::addSignalHandler(const char* signal, PyObject* callable)
159 159 {
160 160 bool flag = false;
161 161 int sigId = getSignalIndex(signal);
162 162 if (sigId>=0) {
163 163 // create PythonQtMethodInfo from signal
164 164 QMetaMethod meta = _obj->metaObject()->method(sigId);
165 165 const PythonQtMethodInfo* signalInfo = PythonQtMethodInfo::getCachedMethodInfo(meta, _objClassInfo);
166 166 PythonQtSignalTarget t(sigId, signalInfo, _slotCount, callable);
167 167 _targets.append(t);
168 168 // now connect to ourselves with the new slot id
169 169 QMetaObject::connect(_obj, sigId, this, _slotCount, Qt::AutoConnection, 0);
170 170
171 171 _slotCount++;
172 172 flag = true;
173 173 }
174 174 return flag;
175 175 }
176 176
177 177 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* callable)
178 178 {
179 179 bool found = false;
180 180 int sigId = getSignalIndex(signal);
181 181 if (sigId>=0) {
182 182 QMutableListIterator<PythonQtSignalTarget> i(_targets);
183 183 while (i.hasNext()) {
184 184 if (i.next().isSame(sigId, callable)) {
185 185 i.remove();
186 186 found = true;
187 187 break;
188 188 }
189 189 }
190 190 }
191 191 return found;
192 192 }
193 193
194 194 void PythonQtSignalReceiver::removeSignalHandlers()
195 195 {
196 196 _targets.clear();
197 197 }
198 198
199 199 int PythonQtSignalReceiver::getSignalIndex(const char* signal)
200 200 {
201 201 int sigId = _obj->metaObject()->indexOfSignal(signal+1);
202 202 if (sigId<0) {
203 203 QByteArray tmpSig = QMetaObject::normalizedSignature(signal+1);
204 204 sigId = _obj->metaObject()->indexOfSignal(tmpSig);
205 205 }
206 206 return sigId;
207 207 }
208 208
209 209 int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **arguments)
210 210 {
211 211 // mlabDebugConst("PythonQt", "PythonQtSignalReceiver invoke " << _obj->className() << " " << _obj->name() << " " << id);
212 212 if (c != QMetaObject::InvokeMetaMethod) {
213 213 QObject::qt_metacall(c, id, arguments);
214 214 }
215 215
216 216 bool found = false;
217 217 foreach(const PythonQtSignalTarget& t, _targets) {
218 218 if (t.slotId() == id) {
219 219 found = true;
220 220 t.call(arguments);
221 221 break;
222 222 }
223 223 }
224 224 return 0;
225 225 }
226 226
@@ -1,141 +1,141
1 1 #ifndef _PYTHONQTSIGNALRECEIVER_H
2 2 #define _PYTHONQTSIGNALRECEIVER_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSignalReceiver.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <Python.h>
46 46 #include "PythonQtSystem.h"
47 47 #include "PythonQtObjectPtr.h"
48 48
49 49 class PythonQtMethodInfo;
50 50 class PythonQtClassInfo;
51 51
52 52 //! stores information about a signal target
53 53 /*! copy construction and assignment works fine with the C++ standard behaviour and are thus not implemented
54 54 */
55 55 class PYTHONQT_EXPORT PythonQtSignalTarget {
56 56 public:
57 57 PythonQtSignalTarget() {
58 58 _signalId = -1;
59 59 _methodInfo = NULL;
60 60 _slotId = -1;
61 61 }
62 62
63 63 PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
64 64 {
65 65 _signalId = signalId;
66 66 _slotId = slotId;
67 67 _methodInfo = methodInfo;
68 68 _callable = callable;
69 69 };
70 70
71 71 ~PythonQtSignalTarget() {
72 72 };
73 73
74 74 //! get the id of the original signal
75 75 int signalId() const { return _signalId; }
76 76
77 77 //! get the id that was assigned to this simulated slot
78 78 int slotId() const { return _slotId; }
79 79
80 80 //! get the signals parameter info
81 81 const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
82 82
83 83 //! call the python callable with the given arguments (as defined in methodInfo)
84 84 void call(void **arguments) const;
85 85
86 86 //! check if it is the same signal target
87 87 bool isSame(int signalId, PyObject* callable) const { return callable==_callable && signalId==_signalId; }
88 88
89 89 //! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
90 90 static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
91 91
92 92 private:
93 93 int _signalId;
94 94 int _slotId;
95 95 const PythonQtMethodInfo* _methodInfo;
96 96 PythonQtObjectPtr _callable;
97 97 };
98 98
99 99 //! base class for signal receivers
100 100 /*!
101 101 */
102 102 class PythonQtSignalReceiverBase : public QObject {
103 103 Q_OBJECT
104 104 public:
105 105 PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
106 106 };
107 107
108 108 //! receives all signals for one QObject
109 109 /*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
110 110 */
111 111 class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
112 112
113 113 public:
114 114 PythonQtSignalReceiver(QObject* obj);
115 115 ~PythonQtSignalReceiver();
116 116
117 117 //! add a signal handler
118 118 bool addSignalHandler(const char* signal, PyObject* callable);
119 119
120 120 //! remove a signal handler
121 121 bool removeSignalHandler(const char* signal, PyObject* callable);
122 122
123 123 //! remove all signal handlers
124 124 void removeSignalHandlers();
125 125
126 126 //! we implement this method to simulate a number of slots that match the ids in _targets
127 127 virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
128 128
129 129 private:
130 130 //! get the index of the signal
131 131 int getSignalIndex(const char* signal);
132 132
133 133 QObject* _obj;
134 134 PythonQtClassInfo* _objClassInfo;
135 135 int _slotCount;
136 136 // linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
137 137 QList<PythonQtSignalTarget> _targets;
138 138 };
139 139
140 140
141 141 #endif
@@ -1,511 +1,511
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSlot.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 54 {
55 55 static unsigned int recursiveEntry = 0;
56 56
57 57 if (directReturnValuePointer) {
58 58 *directReturnValuePointer = NULL;
59 59 }
60 60 // store the current storage position, so that we can get back to this state after a slot is called
61 61 // (do this locally, so that we have all positions on the stack
62 62 PythonQtValueStoragePosition globalValueStoragePos;
63 63 PythonQtValueStoragePosition globalPtrStoragePos;
64 64 PythonQtValueStoragePosition globalVariantStoragePos;
65 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68 68
69 69 recursiveEntry++;
70 70
71 71 // the arguments that are passed to qt_metacall
72 72 void* argList[PYTHONQT_MAX_ARGS];
73 73 PyObject* result = NULL;
74 74 int argc = info->parameterCount();
75 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76 76
77 77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80 80
81 81 bool ok = true;
82 82 bool skipFirst = false;
83 83 if (info->isInstanceDecorator()) {
84 84 skipFirst = true;
85 85
86 86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 87 void* arg1 = firstArgument;
88 88 if (!arg1) {
89 89 arg1 = objectToCall;
90 90 }
91 91 if (arg1) {
92 92 // upcast to correct parent class
93 93 arg1 = ((char*)arg1)+info->upcastingOffset();
94 94 }
95 95
96 96 argList[1] = &arg1;
97 97 if (ok) {
98 98 for (int i = 2; i<argc && ok; i++) {
99 99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 100 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
101 101 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
102 102 if (argList[i]==NULL) {
103 103 ok = false;
104 104 break;
105 105 }
106 106 }
107 107 }
108 108 } else {
109 109 for (int i = 1; i<argc && ok; i++) {
110 110 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
111 111 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
112 112 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
113 113 if (argList[i]==NULL) {
114 114 ok = false;
115 115 break;
116 116 }
117 117 }
118 118 }
119 119
120 120 if (ok) {
121 121 // parameters are ok, now create the qt return value which is assigned to by metacall
122 122 if (returnValueParam.typeId != QMetaType::Void) {
123 123 // create empty default value for the return value
124 124 if (!directReturnValuePointer) {
125 125 // create empty default value for the return value
126 126 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
127 127 if (argList[0]==NULL) {
128 128 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
129 129 // pass its internal pointer
130 130 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
131 131 if (info && info->pythonQtClassWrapper()) {
132 132 PyObject* emptyTuple = PyTuple_New(0);
133 133 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
134 134 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
135 135 if (result) {
136 136 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
137 137 }
138 138 Py_DECREF(emptyTuple);
139 139 }
140 140 }
141 141 } else {
142 142 // we can use our pointer directly!
143 143 argList[0] = directReturnValuePointer;
144 144 }
145 145 }
146 146
147 147 // invoke the slot via metacall
148 148 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
149 149
150 150 // handle the return value (which in most cases still needs to be converted to a Python object)
151 151 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
152 152 if (directReturnValuePointer) {
153 153 result = NULL;
154 154 } else {
155 155 // the resulting object maybe present already, because we created it above at 1)...
156 156 if (!result) {
157 157 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
158 158 }
159 159 }
160 160 } else {
161 161 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
162 162 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
163 163 result = NULL;
164 164 }
165 165 }
166 166 recursiveEntry--;
167 167
168 168 // reset the parameter storage position to the stored pos to "pop" the parameter stack
169 169 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
170 170 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
171 171 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
172 172
173 173 *pythonReturnValue = result;
174 174 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
175 175 return result || (directReturnValuePointer && *directReturnValuePointer);
176 176 }
177 177
178 178 //-----------------------------------------------------------------------------------
179 179
180 180 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
181 181
182 182 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
183 183 {
184 184 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
185 185 PythonQtSlotInfo* info = f->m_ml;
186 186 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
187 187 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
188 188 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
189 189 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
190 190 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
191 191 return NULL;
192 192 } else {
193 193 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
194 194 }
195 195 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
196 196 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
197 197 if (info->isClassDecorator()) {
198 198 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
199 199 } else {
200 200 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
201 201 Py_ssize_t argc = PyTuple_Size(args);
202 202 if (argc>0) {
203 203 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
204 204 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
205 205 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
206 206 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
207 207 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
208 208 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
209 209 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
210 210 return NULL;
211 211 }
212 212 // strip the first argument...
213 213 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
214 214 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
215 215 Py_DECREF(newargs);
216 216 return result;
217 217 } else {
218 218 // first arg is not of correct type!
219 219 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
220 220 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
221 221 return NULL;
222 222 }
223 223 } else {
224 224 // wrong number of args
225 225 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
226 226 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
227 227 return NULL;
228 228 }
229 229 }
230 230 }
231 231 return NULL;
232 232 }
233 233
234 234 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
235 235 {
236 236 int argc = args?PyTuple_Size(args):0;
237 237
238 238 #ifdef PYTHONQT_DEBUG
239 239 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
240 240 #endif
241 241
242 242 PyObject* r = NULL;
243 243 bool ok = false;
244 244 if (directReturnValuePointer) {
245 245 *directReturnValuePointer = NULL;
246 246 }
247 247 if (info->nextInfo()) {
248 248 // overloaded slot call, try on all slots with strict conversion first
249 249 bool strict = true;
250 250 PythonQtSlotInfo* i = info;
251 251 while (i) {
252 252 bool skipFirst = i->isInstanceDecorator();
253 253 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
254 254 PyErr_Clear();
255 255 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
256 256 if (PyErr_Occurred() || ok) break;
257 257 }
258 258 i = i->nextInfo();
259 259 if (!i) {
260 260 if (strict) {
261 261 // one more run without being strict
262 262 strict = false;
263 263 i = info;
264 264 }
265 265 }
266 266 }
267 267 if (!ok && !PyErr_Occurred()) {
268 268 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
269 269 PythonQtSlotInfo* i = info;
270 270 while (i) {
271 271 e += QString(i->fullSignature()) + "\n";
272 272 i = i->nextInfo();
273 273 }
274 274 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
275 275 }
276 276 } else {
277 277 // simple (non-overloaded) slot call
278 278 bool skipFirst = info->isInstanceDecorator();
279 279 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
280 280 PyErr_Clear();
281 281 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
282 282 if (!ok && !PyErr_Occurred()) {
283 283 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
284 284 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
285 285 }
286 286 } else {
287 287 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
288 288 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
289 289 }
290 290 }
291 291
292 292 return r;
293 293 }
294 294
295 295 PyObject *
296 296 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
297 297 {
298 298 PythonQtSlotFunctionObject *op;
299 299 op = pythonqtslot_free_list;
300 300 if (op != NULL) {
301 301 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
302 302 PyObject_INIT(op, &PythonQtSlotFunction_Type);
303 303 }
304 304 else {
305 305 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
306 306 if (op == NULL)
307 307 return NULL;
308 308 }
309 309 op->m_ml = ml;
310 310 Py_XINCREF(self);
311 311 op->m_self = self;
312 312 Py_XINCREF(module);
313 313 op->m_module = module;
314 314 PyObject_GC_Track(op);
315 315 return (PyObject *)op;
316 316 }
317 317
318 318 PythonQtSlotInfo*
319 319 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
320 320 {
321 321 if (!PythonQtSlotFunction_Check(op)) {
322 322 PyErr_BadInternalCall();
323 323 return NULL;
324 324 }
325 325 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
326 326 }
327 327
328 328 PyObject *
329 329 PythonQtSlotFunction_GetSelf(PyObject *op)
330 330 {
331 331 if (!PythonQtSlotFunction_Check(op)) {
332 332 PyErr_BadInternalCall();
333 333 return NULL;
334 334 }
335 335 return ((PythonQtSlotFunctionObject *)op) -> m_self;
336 336 }
337 337
338 338 /* Methods (the standard built-in methods, that is) */
339 339
340 340 static void
341 341 meth_dealloc(PythonQtSlotFunctionObject *m)
342 342 {
343 343 PyObject_GC_UnTrack(m);
344 344 Py_XDECREF(m->m_self);
345 345 Py_XDECREF(m->m_module);
346 346 m->m_self = (PyObject *)pythonqtslot_free_list;
347 347 pythonqtslot_free_list = m;
348 348 }
349 349
350 350 static PyObject *
351 351 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
352 352 {
353 353 Py_INCREF(Py_None);
354 354 return Py_None;
355 355 }
356 356
357 357 static PyObject *
358 358 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
359 359 {
360 360 return PyString_FromString(m->m_ml->metaMethod()->signature());
361 361 }
362 362
363 363 static int
364 364 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
365 365 {
366 366 int err;
367 367 if (m->m_self != NULL) {
368 368 err = visit(m->m_self, arg);
369 369 if (err)
370 370 return err;
371 371 }
372 372 if (m->m_module != NULL) {
373 373 err = visit(m->m_module, arg);
374 374 if (err)
375 375 return err;
376 376 }
377 377 return 0;
378 378 }
379 379
380 380 static PyObject *
381 381 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
382 382 {
383 383 PyObject *self;
384 384 if (PyEval_GetRestricted()) {
385 385 PyErr_SetString(PyExc_RuntimeError,
386 386 "method.__self__ not accessible in restricted mode");
387 387 return NULL;
388 388 }
389 389 self = m->m_self;
390 390 if (self == NULL)
391 391 self = Py_None;
392 392 Py_INCREF(self);
393 393 return self;
394 394 }
395 395
396 396 static PyGetSetDef meth_getsets [] = {
397 397 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
398 398 {"__name__", (getter)meth_get__name__, NULL, NULL},
399 399 {"__self__", (getter)meth_get__self__, NULL, NULL},
400 400 {NULL, NULL, NULL,NULL},
401 401 };
402 402
403 403 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
404 404 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
405 405 #endif
406 406
407 407 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
408 408
409 409 static PyMemberDef meth_members[] = {
410 410 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
411 411 {NULL}
412 412 };
413 413
414 414 static PyObject *
415 415 meth_repr(PythonQtSlotFunctionObject *f)
416 416 {
417 417 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
418 418 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
419 419 return PyString_FromFormat("<unbound qt slot %s of %s type>",
420 420 f->m_ml->slotName().data(),
421 421 self->classInfo()->className());
422 422 } else {
423 423 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
424 424 f->m_ml->slotName().data(),
425 425 f->m_self->ob_type->tp_name,
426 426 f->m_self);
427 427 }
428 428 }
429 429
430 430 static int
431 431 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
432 432 {
433 433 if (a->m_self != b->m_self)
434 434 return (a->m_self < b->m_self) ? -1 : 1;
435 435 if (a->m_ml == b->m_ml)
436 436 return 0;
437 437 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
438 438 return -1;
439 439 else
440 440 return 1;
441 441 }
442 442
443 443 static long
444 444 meth_hash(PythonQtSlotFunctionObject *a)
445 445 {
446 446 long x,y;
447 447 if (a->m_self == NULL)
448 448 x = 0;
449 449 else {
450 450 x = PyObject_Hash(a->m_self);
451 451 if (x == -1)
452 452 return -1;
453 453 }
454 454 y = _Py_HashPointer((void*)(a->m_ml));
455 455 if (y == -1)
456 456 return -1;
457 457 x ^= y;
458 458 if (x == -1)
459 459 x = -2;
460 460 return x;
461 461 }
462 462
463 463
464 464 PyTypeObject PythonQtSlotFunction_Type = {
465 465 PyObject_HEAD_INIT(&PyType_Type)
466 466 0,
467 467 "builtin_qt_slot",
468 468 sizeof(PythonQtSlotFunctionObject),
469 469 0,
470 470 (destructor)meth_dealloc, /* tp_dealloc */
471 471 0, /* tp_print */
472 472 0, /* tp_getattr */
473 473 0, /* tp_setattr */
474 474 (cmpfunc)meth_compare, /* tp_compare */
475 475 (reprfunc)meth_repr, /* tp_repr */
476 476 0, /* tp_as_number */
477 477 0, /* tp_as_sequence */
478 478 0, /* tp_as_mapping */
479 479 (hashfunc)meth_hash, /* tp_hash */
480 480 PythonQtSlotFunction_Call, /* tp_call */
481 481 0, /* tp_str */
482 482 PyObject_GenericGetAttr, /* tp_getattro */
483 483 0, /* tp_setattro */
484 484 0, /* tp_as_buffer */
485 485 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
486 486 0, /* tp_doc */
487 487 (traverseproc)meth_traverse, /* tp_traverse */
488 488 0, /* tp_clear */
489 489 0, /* tp_richcompare */
490 490 0, /* tp_weaklistoffset */
491 491 0, /* tp_iter */
492 492 0, /* tp_iternext */
493 493 0, /* tp_methods */
494 494 meth_members, /* tp_members */
495 495 meth_getsets, /* tp_getset */
496 496 0, /* tp_base */
497 497 0, /* tp_dict */
498 498 };
499 499
500 500 /* Clear out the free list */
501 501
502 502 void
503 503 PythonQtSlotFunction_Fini(void)
504 504 {
505 505 while (pythonqtslot_free_list) {
506 506 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
507 507 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
508 508 PyObject_GC_Del(v);
509 509 }
510 510 }
511 511
@@ -1,80 +1,80
1 1 #ifndef _PYTHONQTSLOT_H
2 2 #define _PYTHONQTSLOT_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSlot.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "Python.h"
46 46 #include "PythonQtSystem.h"
47 47 #include "structmember.h"
48 48
49 49 class PythonQtSlotInfo;
50 50
51 51 extern PYTHONQT_EXPORT PyTypeObject PythonQtSlotFunction_Type;
52 52
53 53 #define PythonQtSlotFunction_Check(op) ((op)->ob_type == &PythonQtSlotFunction_Type)
54 54
55 55 PythonQtSlotInfo* PythonQtSlotFunction_GetSlotInfo(PyObject *);
56 56 PyObject* PythonQtSlotFunction_GetSelf(PyObject *);
57 57
58 58 /* Macros for direct access to these values. Type checks are *not*
59 59 done, so use with care. */
60 60 #define PythonQtSlotFunction_GET_SELF(func) \
61 61 (((PythonQtSlotFunctionObject *)func) -> m_self)
62 62
63 63 PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *);
64 64
65 65 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL);
66 66
67 67
68 68 PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *,
69 69 PyObject *);
70 70
71 71 //! defines a python object that stores a Qt slot info
72 72 typedef struct {
73 73 PyObject_HEAD
74 74 PythonQtSlotInfo *m_ml; /* Description of the C function to call */
75 75 PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
76 76 PyObject *m_module; /* The __module__ attribute, can be anything */
77 77 } PythonQtSlotFunctionObject;
78 78
79 79
80 80 #endif
@@ -1,314 +1,314
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtStdDecorators.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2007-04
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdDecorators.h"
43 43 #include "PythonQt.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include <QCoreApplication>
46 46
47 47 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, PyObject* callable)
48 48 {
49 49 QByteArray signalTmp;
50 50 char first = signal.at(0);
51 51 if (first>='0' && first<='9') {
52 52 signalTmp = signal;
53 53 } else {
54 54 signalTmp = "2" + signal;
55 55 }
56 56
57 57 if (sender) {
58 58 return PythonQt::self()->addSignalHandler(sender, signalTmp, callable);
59 59 } else {
60 60 return false;
61 61 }
62 62 }
63 63
64 64 bool PythonQtStdDecorators::connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
65 65 {
66 66 bool r = false;
67 67 if (sender && receiver) {
68 68 QByteArray signalTmp;
69 69 char first = signal.at(0);
70 70 if (first>='0' && first<='9') {
71 71 signalTmp = signal;
72 72 } else {
73 73 signalTmp = "2" + signal;
74 74 }
75 75
76 76 QByteArray slotTmp;
77 77 first = slot.at(0);
78 78 if (first>='0' && first<='9') {
79 79 slotTmp = slot;
80 80 } else {
81 81 slotTmp = "1" + slot;
82 82 }
83 83 r = QObject::connect(sender, signalTmp, receiver, slotTmp);
84 84 }
85 85 return r;
86 86 }
87 87
88 88 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, PyObject* callable)
89 89 {
90 90 QByteArray signalTmp;
91 91 char first = signal.at(0);
92 92 if (first>='0' && first<='9') {
93 93 signalTmp = signal;
94 94 } else {
95 95 signalTmp = "2" + signal;
96 96 }
97 97 if (sender) {
98 98 return PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
99 99 } else {
100 100 return false;
101 101 }
102 102 }
103 103
104 104 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot)
105 105 {
106 106 bool r = false;
107 107 if (sender && receiver) {
108 108 QByteArray signalTmp;
109 109 char first = signal.at(0);
110 110 if (first>='0' && first<='9') {
111 111 signalTmp = signal;
112 112 } else {
113 113 signalTmp = "2" + signal;
114 114 }
115 115
116 116 QByteArray slotTmp;
117 117 first = slot.at(0);
118 118 if (first>='0' && first<='9') {
119 119 slotTmp = slot;
120 120 } else {
121 121 slotTmp = "1" + slot;
122 122 }
123 123
124 124 r = QObject::disconnect(sender, signalTmp, receiver, slotTmp);
125 125 }
126 126 return r;
127 127 }
128 128
129 129 #undef emit
130 130 void PythonQtStdDecorators::emit(QObject* sender, const QByteArray& signal, PyObject* arg1 ,PyObject* arg2 ,
131 131 PyObject* arg3 ,PyObject* arg4 ,PyObject* arg5 ,PyObject* arg6 ,PyObject* arg7 )
132 132 {
133 133 // TODO xxx
134 134 // use normal PythonQtSlot calling code, add "allowSignal" to member lookup?!
135 135 }
136 136 #define emit
137 137
138 138 QObject* PythonQtStdDecorators::parent(QObject* o) {
139 139 return o->parent();
140 140 }
141 141
142 142 void PythonQtStdDecorators::setParent(QObject* o, QObject* parent)
143 143 {
144 144 o->setParent(parent);
145 145 }
146 146
147 147 const QObjectList* PythonQtStdDecorators::children(QObject* o)
148 148 {
149 149 return &o->children();
150 150 }
151 151
152 152 bool PythonQtStdDecorators::setProperty(QObject* o, const char* name, const QVariant& value)
153 153 {
154 154 return o->setProperty(name, value);
155 155 }
156 156
157 157 QVariant PythonQtStdDecorators::property(QObject* o, const char* name)
158 158 {
159 159 return o->property(name);
160 160 }
161 161
162 162 QString PythonQtStdDecorators::tr(QObject* obj, const QByteArray& text, const QByteArray& ambig, int n)
163 163 {
164 164 return QCoreApplication::translate(obj->metaObject()->className(), text.constData(), ambig.constData(), QCoreApplication::CodecForTr, n);
165 165 }
166 166
167 167 QObject* PythonQtStdDecorators::findChild(QObject* parent, PyObject* type, const QString& name)
168 168 {
169 169 const QMetaObject* meta = NULL;
170 170 const char* typeName = NULL;
171 171
172 172 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
173 173 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
174 174 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
175 175 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
176 176 } else if (PyString_Check(type)) {
177 177 typeName = PyString_AsString(type);
178 178 }
179 179
180 180 if (!typeName && !meta)
181 181 return NULL;
182 182
183 183 return findChild(parent, typeName, meta, name);
184 184 }
185 185
186 186 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QString& name)
187 187 {
188 188 const QMetaObject* meta = NULL;
189 189 const char* typeName = NULL;
190 190
191 191 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
192 192 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
193 193 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
194 194 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
195 195 } else if (PyString_Check(type)) {
196 196 typeName = PyString_AsString(type);
197 197 }
198 198
199 199 QList<QObject*> list;
200 200
201 201 if (!typeName && !meta)
202 202 return list;
203 203
204 204 findChildren(parent, typeName, meta, name, list);
205 205
206 206 return list;
207 207 }
208 208
209 209 QList<QObject*> PythonQtStdDecorators::findChildren(QObject* parent, PyObject* type, const QRegExp& regExp)
210 210 {
211 211 const QMetaObject* meta = NULL;
212 212 const char* typeName = NULL;
213 213
214 214 if (PyObject_TypeCheck(type, &PythonQtClassWrapper_Type)) {
215 215 meta = ((PythonQtClassWrapper*)type)->classInfo()->metaObject();
216 216 } else if (PyObject_TypeCheck(type, &PythonQtInstanceWrapper_Type)) {
217 217 meta = ((PythonQtInstanceWrapper*)type)->classInfo()->metaObject();
218 218 } else if (PyString_Check(type)) {
219 219 typeName = PyString_AsString(type);
220 220 }
221 221
222 222 QList<QObject*> list;
223 223
224 224 if (!typeName && !meta)
225 225 return list;
226 226
227 227 findChildren(parent, typeName, meta, regExp, list);
228 228
229 229 return list;
230 230 }
231 231
232 232 QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name)
233 233 {
234 234 const QObjectList &children = parent->children();
235 235
236 236 int i;
237 237 for (i = 0; i < children.size(); ++i) {
238 238 QObject* obj = children.at(i);
239 239
240 240 if (!obj)
241 241 return NULL;
242 242
243 243 // Skip if the name doesn't match.
244 244 if (!name.isNull() && obj->objectName() != name)
245 245 continue;
246 246
247 247 if ((typeName && obj->inherits(typeName)) ||
248 248 (meta && meta->cast(obj)))
249 249 return obj;
250 250 }
251 251
252 252 for (i = 0; i < children.size(); ++i) {
253 253 QObject* obj = findChild(children.at(i), typeName, meta, name);
254 254
255 255 if (obj != NULL)
256 256 return obj;
257 257 }
258 258
259 259 return NULL;
260 260 }
261 261
262 262 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list)
263 263 {
264 264 const QObjectList& children = parent->children();
265 265 int i;
266 266
267 267 for (i = 0; i < children.size(); ++i) {
268 268 QObject* obj = children.at(i);
269 269
270 270 if (!obj)
271 271 return -1;
272 272
273 273 // Skip if the name doesn't match.
274 274 if (!name.isNull() && obj->objectName() != name)
275 275 continue;
276 276
277 277 if ((typeName && obj->inherits(typeName)) ||
278 278 (meta && meta->cast(obj))) {
279 279 list += obj;
280 280 }
281 281
282 282 if (findChildren(obj, typeName, meta, name, list) < 0)
283 283 return -1;
284 284 }
285 285
286 286 return 0;
287 287 }
288 288
289 289 int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list)
290 290 {
291 291 const QObjectList& children = parent->children();
292 292 int i;
293 293
294 294 for (i = 0; i < children.size(); ++i) {
295 295 QObject* obj = children.at(i);
296 296
297 297 if (!obj)
298 298 return -1;
299 299
300 300 // Skip if the name doesn't match.
301 301 if (regExp.indexIn(obj->objectName()) == -1)
302 302 continue;
303 303
304 304 if ((typeName && obj->inherits(typeName)) ||
305 305 (meta && meta->cast(obj))) {
306 306 list += obj;
307 307 }
308 308
309 309 if (findChildren(obj, typeName, meta, regExp, list) < 0)
310 310 return -1;
311 311 }
312 312
313 313 return 0;
314 314 }
@@ -1,112 +1,112
1 1 #ifndef _PYTHONQTSTDDECORATORS_H
2 2 #define _PYTHONQTSTDDECORATORS_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtStdDecorators.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2007-04
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include <Python.h>
47 47 #include <QObject>
48 48 #include <QVariantList>
49 49 #include <QTextDocument>
50 50 #include <QColor>
51 51 #include <QDateTime>
52 52 #include <QDate>
53 53 #include <QTime>
54 54
55 55 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
56 56 {
57 57 Q_OBJECT
58 58
59 59 public slots:
60 60 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
61 61 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
62 62 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 63 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64 64
65 65 #undef emit
66 66 void emit(QObject* sender, const QByteArray& signal, PyObject* arg1 = NULL,PyObject* arg2 = NULL,
67 67 PyObject* arg3 = NULL,PyObject* arg4 = NULL,PyObject* arg5 = NULL,PyObject* arg6 = NULL,PyObject* arg7 = NULL);
68 68 #define emit
69 69
70 70 QObject* parent(QObject* o);
71 71 void setParent(QObject* o, QObject* parent);
72 72
73 73 const QObjectList* children(QObject* o);
74 74 QObject* findChild(QObject* parent, PyObject* type, const QString& name = QString());
75 75 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QString& name= QString());
76 76 QList<QObject*> findChildren(QObject* parent, PyObject* type, const QRegExp& regExp);
77 77
78 78 bool setProperty(QObject* o, const char* name, const QVariant& value);
79 79 QVariant property(QObject* o, const char* name);
80 80
81 81 double static_Qt_qAbs(double a) { return qAbs(a); }
82 82 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
83 83 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
84 84 // TODO: multi arg qDebug...
85 85 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
86 86 // TODO: multi arg qWarning...
87 87 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
88 88 // TODO: multi arg qCritical...
89 89 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
90 90 // TODO: multi arg qFatal...
91 91 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
92 92 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
93 93 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
94 94 int static_Qt_qRound(double a) { return qRound(a); }
95 95 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
96 96 const char* static_Qt_qVersion() { return qVersion(); }
97 97 int static_Qt_qrand() { return qrand(); }
98 98 void static_Qt_qsrand(uint a) { qsrand(a); }
99 99
100 100 QString tr(QObject* obj, const QByteArray& text, const QByteArray& ambig = QByteArray(), int n = -1);
101 101
102 102 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
103 103 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
104 104
105 105 private:
106 106 QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name);
107 107 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList<QObject*>& list);
108 108 int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegExp& regExp, QList<QObject*>& list);
109 109 };
110 110
111 111
112 112 #endif
@@ -1,136 +1,136
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtStdOut.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtStdOut.h"
43 43
44 44 static PyObject *PythonQtStdOutRedirect_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
45 45 {
46 46 PythonQtStdOutRedirect *self;
47 47 self = (PythonQtStdOutRedirect *)type->tp_alloc(type, 0);
48 48
49 49 self->softspace = 0;
50 50 self->_cb = NULL;
51 51
52 52 return (PyObject *)self;
53 53 }
54 54
55 55 static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args)
56 56 {
57 57 PythonQtStdOutRedirect* s = (PythonQtStdOutRedirect*)self;
58 58 if (s->_cb) {
59 59 char *string;
60 60 if (!PyArg_ParseTuple(args, "s", &string))
61 61 return NULL;
62 62
63 63 if (s->softspace > 0) {
64 64 (*s->_cb)(QString(""));
65 65 s->softspace = 0;
66 66 }
67 67
68 68 (*s->_cb)(QString(string));
69 69 }
70 70 return Py_BuildValue("");
71 71 }
72 72
73 73 static PyObject *PythonQtStdOutRedirect_flush(PyObject * /*self*/, PyObject * /*args*/)
74 74 {
75 75 return Py_BuildValue("");
76 76 }
77 77
78 78
79 79
80 80 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
81 81 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
82 82 "redirect the writing to a callback"},
83 83 {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS,
84 84 "flush the output, currently not implemented but needed for logging framework"
85 85 },
86 86 {NULL, NULL, 0 , NULL} /* sentinel */
87 87 };
88 88
89 89 static PyMemberDef PythonQtStdOutRedirect_members[] = {
90 90 {"softspace", T_INT, offsetof(PythonQtStdOutRedirect, softspace), 0,
91 91 "soft space flag"
92 92 },
93 93 {NULL} /* Sentinel */
94 94 };
95 95
96 96 PyTypeObject PythonQtStdOutRedirectType = {
97 97 PyObject_HEAD_INIT(NULL)
98 98 0, /*ob_size*/
99 99 "PythonQtStdOutRedirect", /*tp_name*/
100 100 sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/
101 101 0, /*tp_itemsize*/
102 102 0, /*tp_dealloc*/
103 103 0, /*tp_print*/
104 104 0, /*tp_getattr*/
105 105 0, /*tp_setattr*/
106 106 0, /*tp_compare*/
107 107 0, /*tp_repr*/
108 108 0, /*tp_as_number*/
109 109 0, /*tp_as_sequence*/
110 110 0, /*tp_as_mapping*/
111 111 0, /*tp_hash */
112 112 0, /*tp_call*/
113 113 0, /*tp_str*/
114 114 0, /*tp_getattro*/
115 115 0, /*tp_setattro*/
116 116 0, /*tp_as_buffer*/
117 117 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
118 118 "PythonQtStdOutRedirect", /* tp_doc */
119 119 0, /* tp_traverse */
120 120 0, /* tp_clear */
121 121 0, /* tp_richcompare */
122 122 0, /* tp_weaklistoffset */
123 123 0, /* tp_iter */
124 124 0, /* tp_iternext */
125 125 PythonQtStdOutRedirect_methods, /* tp_methods */
126 126 PythonQtStdOutRedirect_members, /* tp_members */
127 127 0, /* tp_getset */
128 128 0, /* tp_base */
129 129 0, /* tp_dict */
130 130 0, /* tp_descr_get */
131 131 0, /* tp_descr_set */
132 132 0, /* tp_dictoffset */
133 133 0, /* tp_init */
134 134 0, /* tp_alloc */
135 135 PythonQtStdOutRedirect_new, /* tp_new */
136 136 };
@@ -1,63 +1,63
1 1 #ifndef _PYTHONQTSTDOUT_H
2 2 #define _PYTHONQTSTDOUT_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtStdOut.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45
46 46 #include <Python.h>
47 47 #include "structmember.h"
48 48 #include <QString>
49 49
50 50 //! declares the type of the stdout redirection class
51 51 extern PyTypeObject PythonQtStdOutRedirectType;
52 52
53 53 //! declares the callback that is called from the write() function
54 54 typedef void PythonQtOutputChangedCB(const QString& str);
55 55
56 56 //! declares the stdout redirection class
57 57 typedef struct {
58 58 PyObject_HEAD
59 59 PythonQtOutputChangedCB* _cb;
60 60 int softspace;
61 61 } PythonQtStdOutRedirect;
62 62
63 63 #endif
@@ -1,56 +1,56
1 1 #ifndef _PYTHONQTSYSTEM_
2 2 #define _PYTHONQTSYSTEM_
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtSystem.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #ifdef WIN32
46 46 #ifdef PYTHONQT_EXPORTS
47 47 #define PYTHONQT_EXPORT __declspec(dllexport)
48 48 #else
49 49 #define PYTHONQT_EXPORT __declspec(dllimport)
50 50 #endif
51 51 #else
52 52 #define PYTHONQT_EXPORT
53 53 #endif
54 54
55 55 #endif
56 56
@@ -1,78 +1,78
1 1 #ifndef _PYTHONQTVARIANTS_
2 2 #define _PYTHONQTVARIANTS_
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtVariants.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: stk $
41 41 // \date 2006-08
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include <QBitArray>
46 46 #include <QDate>
47 47 #include <QTime>
48 48 #include <QDateTime>
49 49 #include <QUrl>
50 50 #include <QLocale>
51 51 #include <QRect>
52 52 #include <QRectF>
53 53 #include <QLine>
54 54 #include <QLineF>
55 55 #include <QPoint>
56 56 #include <QPointF>
57 57 #include <QRegExp>
58 58
59 59 #include <QFont>
60 60 #include <QBitmap>
61 61 #include <QBrush>
62 62 #include <QColor>
63 63 #include <QPalette>
64 64 #include <QIcon>
65 65 #include <QImage>
66 66 #include <QPolygon>
67 67 #include <QRegion>
68 68 #include <QBitmap>
69 69 #include <QCursor>
70 70 #include <QSizePolicy>
71 71 #include <QKeySequence>
72 72 #include <QPen>
73 73 #include <QTextLength>
74 74 #include <QTextFormat>
75 75 #include <QMatrix>
76 76
77 77 #endif
78 78
@@ -1,575 +1,575
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtScriptingConsole.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-10
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtScriptingConsole.h"
43 43
44 44 #include <QMenu>
45 45 #include <QMouseEvent>
46 46 #include <QKeyEvent>
47 47 #include <QApplication>
48 48 #include <QTextDocumentFragment>
49 49 #include <QTextBlock>
50 50 #include <QTextCursor>
51 51 #include <QDebug>
52 52 #include <QCompleter>
53 53 #include <QStringListModel>
54 54 #include <QScrollBar>
55 55
56 56 //-----------------------------------------------------------------------------
57 57
58 58 PythonQtScriptingConsole::PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags windowFlags)
59 59 : QTextEdit(parent) {
60 60
61 61 setWindowFlags(windowFlags);
62 62
63 63 _defaultTextCharacterFormat = currentCharFormat();
64 64 _context = context;
65 65 _historyPosition = 0;
66 66 _hadError = false;
67 67
68 68 _completer = new QCompleter(this);
69 69 _completer->setWidget(this);
70 70 QObject::connect(_completer, SIGNAL(activated(const QString&)),
71 71 this, SLOT(insertCompletion(const QString&)));
72 72
73 73 clear();
74 74
75 75 connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), this, SLOT(stdOut(const QString&)));
76 76 connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), this, SLOT(stdErr(const QString&)));
77 77 }
78 78
79 79 //-----------------------------------------------------------------------------
80 80
81 81 void PythonQtScriptingConsole::stdOut(const QString& s)
82 82 {
83 83 _stdOut += s;
84 84 int idx;
85 85 while ((idx = _stdOut.indexOf('\n'))!=-1) {
86 86 consoleMessage(_stdOut.left(idx));
87 87 std::cout << _stdOut.left(idx).toLatin1().data() << std::endl;
88 88 _stdOut = _stdOut.mid(idx+1);
89 89 }
90 90 }
91 91
92 92 void PythonQtScriptingConsole::stdErr(const QString& s)
93 93 {
94 94 _hadError = true;
95 95 _stdErr += s;
96 96 int idx;
97 97 while ((idx = _stdErr.indexOf('\n'))!=-1) {
98 98 consoleMessage(_stdErr.left(idx));
99 99 std::cerr << _stdErr.left(idx).toLatin1().data() << std::endl;
100 100 _stdErr = _stdErr.mid(idx+1);
101 101 }
102 102 }
103 103
104 104 void PythonQtScriptingConsole::flushStdOut()
105 105 {
106 106 if (!_stdOut.isEmpty()) {
107 107 stdOut("\n");
108 108 }
109 109 if (!_stdErr.isEmpty()) {
110 110 stdErr("\n");
111 111 }
112 112 }
113 113
114 114 //-----------------------------------------------------------------------------
115 115
116 116 PythonQtScriptingConsole::~PythonQtScriptingConsole() {
117 117 }
118 118
119 119
120 120
121 121 //-----------------------------------------------------------------------------
122 122
123 123 void PythonQtScriptingConsole::clear() {
124 124
125 125 QTextEdit::clear();
126 126 appendCommandPrompt();
127 127 }
128 128
129 129 //-----------------------------------------------------------------------------
130 130
131 131 void PythonQtScriptingConsole::executeLine(bool storeOnly)
132 132 {
133 133 QTextCursor textCursor = this->textCursor();
134 134 textCursor.movePosition(QTextCursor::End);
135 135
136 136 // Select the text from the command prompt until the end of the block
137 137 // and get the selected text.
138 138 textCursor.setPosition(commandPromptPosition());
139 139 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
140 140 QString code = textCursor.selectedText();
141 141
142 142 // i don't know where this trailing space is coming from, blast it!
143 143 if (code.endsWith(" ")) {
144 144 code.truncate(code.length()-1);
145 145 }
146 146
147 147 if (!code.isEmpty()) {
148 148 // Update the history
149 149 _history << code;
150 150 _historyPosition = _history.count();
151 151 _currentMultiLineCode += code + "\n";
152 152
153 153 if (!storeOnly) {
154 154 executeCode(_currentMultiLineCode);
155 155 _currentMultiLineCode = "";
156 156 }
157 157 }
158 158 // Insert a new command prompt
159 159 appendCommandPrompt(storeOnly);
160 160
161 161 }
162 162
163 163 void PythonQtScriptingConsole::executeCode(const QString& code)
164 164 {
165 165 // put visible cursor to the end of the line
166 166 QTextCursor cursor = QTextEdit::textCursor();
167 167 cursor.movePosition(QTextCursor::End);
168 168 setTextCursor(cursor);
169 169
170 170 int cursorPosition = this->textCursor().position();
171 171
172 172 // evaluate the code
173 173 _stdOut = "";
174 174 _stdErr = "";
175 175 PythonQtObjectPtr p;
176 176 PyObject* dict = NULL;
177 177 if (PyModule_Check(_context)) {
178 178 dict = PyModule_GetDict(_context);
179 179 } else if (PyDict_Check(_context)) {
180 180 dict = _context;
181 181 }
182 182 if (dict) {
183 183 p.setNewRef(PyRun_String(code.toLatin1().data(), Py_single_input, dict, dict));
184 184 }
185 185
186 186 if (!p) {
187 187 PythonQt::self()->handleError();
188 188 }
189 189
190 190 flushStdOut();
191 191
192 192 bool messageInserted = (this->textCursor().position() != cursorPosition);
193 193
194 194 // If a message was inserted, then put another empty line before the command prompt
195 195 // to improve readability.
196 196 if (messageInserted) {
197 197 append(QString());
198 198 }
199 199 }
200 200
201 201
202 202 //-----------------------------------------------------------------------------
203 203
204 204 void PythonQtScriptingConsole::appendCommandPrompt(bool storeOnly) {
205 205 if (storeOnly) {
206 206 _commandPrompt = "...> ";
207 207 } else {
208 208 _commandPrompt = "py> ";
209 209 }
210 210 append(_commandPrompt);
211 211
212 212 QTextCursor cursor = textCursor();
213 213 cursor.movePosition(QTextCursor::End);
214 214 setTextCursor(cursor);
215 215 }
216 216
217 217
218 218
219 219 //-----------------------------------------------------------------------------
220 220
221 221 void PythonQtScriptingConsole::setCurrentFont(const QColor& color, bool bold) {
222 222
223 223 QTextCharFormat charFormat(_defaultTextCharacterFormat);
224 224
225 225 QFont font(charFormat.font());
226 226 font.setBold(bold);
227 227 charFormat.setFont(font);
228 228
229 229 QBrush brush(charFormat.foreground());
230 230 brush.setColor(color);
231 231 charFormat.setForeground(brush);
232 232
233 233 setCurrentCharFormat(charFormat);
234 234 }
235 235
236 236
237 237
238 238 //-----------------------------------------------------------------------------
239 239
240 240 int PythonQtScriptingConsole::commandPromptPosition() {
241 241
242 242 QTextCursor textCursor(this->textCursor());
243 243 textCursor.movePosition(QTextCursor::End);
244 244
245 245 return textCursor.block().position() + _commandPrompt.length();
246 246 }
247 247
248 248
249 249
250 250 //-----------------------------------------------------------------------------
251 251
252 252 void PythonQtScriptingConsole::insertCompletion(const QString& completion)
253 253 {
254 254 QTextCursor tc = textCursor();
255 255 tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
256 256 if (tc.selectedText()==".") {
257 257 tc.insertText(QString(".") + completion);
258 258 } else {
259 259 tc = textCursor();
260 260 tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
261 261 tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
262 262 tc.insertText(completion);
263 263 setTextCursor(tc);
264 264 }
265 265 }
266 266
267 267 //-----------------------------------------------------------------------------
268 268 void PythonQtScriptingConsole::handleTabCompletion()
269 269 {
270 270 QTextCursor textCursor = this->textCursor();
271 271 int pos = textCursor.position();
272 272 textCursor.setPosition(commandPromptPosition());
273 273 textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
274 274 int startPos = textCursor.selectionStart();
275 275
276 276 int offset = pos-startPos;
277 277 QString text = textCursor.selectedText();
278 278
279 279 QString textToComplete;
280 280 int cur = offset;
281 281 while (cur--) {
282 282 QChar c = text.at(cur);
283 283 if (c.isLetterOrNumber() || c == '.' || c == '_') {
284 284 textToComplete.prepend(c);
285 285 } else {
286 286 break;
287 287 }
288 288 }
289 289
290 290
291 291 QString lookup;
292 292 QString compareText = textToComplete;
293 293 int dot = compareText.lastIndexOf('.');
294 294 if (dot!=-1) {
295 295 lookup = compareText.mid(0, dot);
296 296 compareText = compareText.mid(dot+1, offset);
297 297 }
298 298 if (!lookup.isEmpty() || !compareText.isEmpty()) {
299 299 compareText = compareText.toLower();
300 300 QStringList found;
301 301 QStringList l = PythonQt::self()->introspection(_context, lookup, PythonQt::Anything);
302 302 foreach (QString n, l) {
303 303 if (n.toLower().startsWith(compareText)) {
304 304 found << n;
305 305 }
306 306 }
307 307
308 308 if (!found.isEmpty()) {
309 309 _completer->setCompletionPrefix(compareText);
310 310 _completer->setCompletionMode(QCompleter::PopupCompletion);
311 311 _completer->setModel(new QStringListModel(found, _completer));
312 312 _completer->setCaseSensitivity(Qt::CaseInsensitive);
313 313 QTextCursor c = this->textCursor();
314 314 c.movePosition(QTextCursor::StartOfWord);
315 315 QRect cr = cursorRect(c);
316 316 cr.setWidth(_completer->popup()->sizeHintForColumn(0)
317 317 + _completer->popup()->verticalScrollBar()->sizeHint().width());
318 318 cr.translate(0,8);
319 319 _completer->complete(cr);
320 320 } else {
321 321 _completer->popup()->hide();
322 322 }
323 323 } else {
324 324 _completer->popup()->hide();
325 325 }
326 326 }
327 327
328 328 void PythonQtScriptingConsole::keyPressEvent(QKeyEvent* event) {
329 329
330 330 if (_completer && _completer->popup()->isVisible()) {
331 331 // The following keys are forwarded by the completer to the widget
332 332 switch (event->key()) {
333 333 case Qt::Key_Return:
334 334 if (!_completer->popup()->currentIndex().isValid()) {
335 335 insertCompletion(_completer->currentCompletion());
336 336 _completer->popup()->hide();
337 337 event->accept();
338 338 }
339 339 event->ignore();
340 340 return;
341 341 break;
342 342 case Qt::Key_Enter:
343 343 case Qt::Key_Escape:
344 344 case Qt::Key_Tab:
345 345 case Qt::Key_Backtab:
346 346
347 347 event->ignore();
348 348 return; // let the completer do default behavior
349 349 default:
350 350 break;
351 351 }
352 352 }
353 353 bool eventHandled = false;
354 354 QTextCursor textCursor = this->textCursor();
355 355
356 356 int key = event->key();
357 357 switch (key) {
358 358
359 359 case Qt::Key_Left:
360 360
361 361 // Moving the cursor left is limited to the position
362 362 // of the command prompt.
363 363
364 364 if (textCursor.position() <= commandPromptPosition()) {
365 365
366 366 QApplication::beep();
367 367 eventHandled = true;
368 368 }
369 369 break;
370 370
371 371 case Qt::Key_Up:
372 372
373 373 // Display the previous command in the history
374 374 if (_historyPosition>0) {
375 375 _historyPosition--;
376 376 changeHistory();
377 377 }
378 378
379 379 eventHandled = true;
380 380 break;
381 381
382 382 case Qt::Key_Down:
383 383
384 384 // Display the next command in the history
385 385 if (_historyPosition+1<_history.count()) {
386 386 _historyPosition++;
387 387 changeHistory();
388 388 }
389 389
390 390 eventHandled = true;
391 391 break;
392 392
393 393 case Qt::Key_Return:
394 394
395 395 executeLine(event->modifiers() & Qt::ShiftModifier);
396 396 eventHandled = true;
397 397 break;
398 398
399 399 case Qt::Key_Backspace:
400 400
401 401 if (textCursor.hasSelection()) {
402 402
403 403 cut();
404 404 eventHandled = true;
405 405
406 406 } else {
407 407
408 408 // Intercept backspace key event to check if
409 409 // deleting a character is allowed. It is not
410 410 // allowed, if the user wants to delete the
411 411 // command prompt.
412 412
413 413 if (textCursor.position() <= commandPromptPosition()) {
414 414
415 415 QApplication::beep();
416 416 eventHandled = true;
417 417 }
418 418 }
419 419 break;
420 420
421 421 case Qt::Key_Delete:
422 422
423 423 cut();
424 424 eventHandled = true;
425 425 break;
426 426
427 427 default:
428 428
429 429 if (key >= Qt::Key_Space && key <= Qt::Key_division) {
430 430
431 431 if (textCursor.hasSelection() && !verifySelectionBeforeDeletion()) {
432 432
433 433 // The selection must not be deleted.
434 434 eventHandled = true;
435 435
436 436 } else {
437 437
438 438 // The key is an input character, check if the cursor is
439 439 // behind the last command prompt, else inserting the
440 440 // character is not allowed.
441 441
442 442 int commandPromptPosition = this->commandPromptPosition();
443 443 if (textCursor.position() < commandPromptPosition) {
444 444
445 445 textCursor.setPosition(commandPromptPosition);
446 446 setTextCursor(textCursor);
447 447 }
448 448 }
449 449 }
450 450 }
451 451
452 452 if (eventHandled) {
453 453
454 454 _completer->popup()->hide();
455 455 event->accept();
456 456
457 457 } else {
458 458
459 459 QTextEdit::keyPressEvent(event);
460 460 QString text = event->text();
461 461 if (!text.isEmpty()) {
462 462 handleTabCompletion();
463 463 } else {
464 464 _completer->popup()->hide();
465 465 }
466 466 eventHandled = true;
467 467 }
468 468 }
469 469
470 470
471 471
472 472 //-----------------------------------------------------------------------------
473 473
474 474 void PythonQtScriptingConsole::cut() {
475 475
476 476 bool deletionAllowed = verifySelectionBeforeDeletion();
477 477 if (deletionAllowed) {
478 478 QTextEdit::cut();
479 479 }
480 480 }
481 481
482 482
483 483
484 484 //-----------------------------------------------------------------------------
485 485
486 486 bool PythonQtScriptingConsole::verifySelectionBeforeDeletion() {
487 487
488 488 bool deletionAllowed = true;
489 489
490 490
491 491 QTextCursor textCursor = this->textCursor();
492 492
493 493 int commandPromptPosition = this->commandPromptPosition();
494 494 int selectionStart = textCursor.selectionStart();
495 495 int selectionEnd = textCursor.selectionEnd();
496 496
497 497 if (textCursor.hasSelection()) {
498 498
499 499 // Selected text may only be deleted after the last command prompt.
500 500 // If the selection is partly after the command prompt set the selection
501 501 // to the part and deletion is allowed. If the selection occurs before the
502 502 // last command prompt, then deletion is not allowed.
503 503
504 504 if (selectionStart < commandPromptPosition ||
505 505 selectionEnd < commandPromptPosition) {
506 506
507 507 // Assure selectionEnd is bigger than selection start
508 508 if (selectionStart > selectionEnd) {
509 509 int tmp = selectionEnd;
510 510 selectionEnd = selectionStart;
511 511 selectionStart = tmp;
512 512 }
513 513
514 514 if (selectionEnd < commandPromptPosition) {
515 515
516 516 // Selection is completely before command prompt,
517 517 // so deletion is not allowed.
518 518 QApplication::beep();
519 519 deletionAllowed = false;
520 520
521 521 } else {
522 522
523 523 // The selectionEnd is after the command prompt, so set
524 524 // the selection start to the commandPromptPosition.
525 525 selectionStart = commandPromptPosition;
526 526 textCursor.setPosition(selectionStart);
527 527 textCursor.setPosition(selectionStart, QTextCursor::KeepAnchor);
528 528 setTextCursor(textCursor);
529 529 }
530 530 }
531 531
532 532 } else { // if (hasSelectedText())
533 533
534 534 // When there is no selected text, deletion is not allowed before the
535 535 // command prompt.
536 536 if (textCursor.position() < commandPromptPosition) {
537 537
538 538 QApplication::beep();
539 539 deletionAllowed = false;
540 540 }
541 541 }
542 542
543 543 return deletionAllowed;
544 544 }
545 545
546 546
547 547
548 548 //-----------------------------------------------------------------------------
549 549
550 550 void PythonQtScriptingConsole::changeHistory() {
551 551
552 552 // Select the text after the last command prompt ...
553 553 QTextCursor textCursor = this->textCursor();
554 554 textCursor.movePosition(QTextCursor::End);
555 555 textCursor.setPosition(commandPromptPosition(), QTextCursor::KeepAnchor);
556 556
557 557 // ... and replace it with the history text.
558 558 textCursor.insertText(_history.value(_historyPosition));
559 559
560 560 textCursor.movePosition(QTextCursor::End);
561 561 setTextCursor(textCursor);
562 562 }
563 563
564 564
565 565
566 566 //-----------------------------------------------------------------------------
567 567
568 568 void PythonQtScriptingConsole::consoleMessage(const QString & message) {
569 569
570 570 append(QString());
571 571 insertPlainText(message);
572 572
573 573 // Reset all font modifications done by the html string
574 574 setCurrentCharFormat(_defaultTextCharacterFormat);
575 575 }
@@ -1,149 +1,149
1 1 #ifndef _PythonQtScriptingConsole_H
2 2 #define _PythonQtScriptingConsole_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtScriptingConsole.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include <QVariant>
47 47 #include <QTextEdit>
48 48
49 49 class QCompleter;
50 50
51 51 //-------------------------------------------------------------------------------
52 52 //! A simple console for python scripting
53 53 class PYTHONQT_EXPORT PythonQtScriptingConsole : public QTextEdit
54 54 {
55 55 Q_OBJECT
56 56
57 57 public:
58 58 PythonQtScriptingConsole(QWidget* parent, const PythonQtObjectPtr& context, Qt::WindowFlags i = 0);
59 59
60 60 ~PythonQtScriptingConsole();
61 61
62 62 public slots:
63 63 //! execute current line
64 64 void executeLine(bool storeOnly);
65 65
66 66 //! derived key press event
67 67 void keyPressEvent (QKeyEvent * e);
68 68
69 69 //! output from console
70 70 void consoleMessage(const QString & message);
71 71
72 72 //! get history
73 73 QStringList history() { return _history; }
74 74
75 75 //! set history
76 76 void setHistory(const QStringList& h) { _history = h; _historyPosition = 0; }
77 77
78 78 //! clear the console
79 79 void clear();
80 80
81 81 //! overridden to control which characters a user may delete
82 82 virtual void cut();
83 83
84 84 //! output redirection
85 85 void stdOut(const QString& s);
86 86 //! output redirection
87 87 void stdErr(const QString& s);
88 88
89 89 void insertCompletion(const QString&);
90 90
91 91 //! Appends a newline and command prompt at the end of the document.
92 92 void appendCommandPrompt(bool storeOnly = false);
93 93
94 94 public:
95 95 //! returns true if python cerr had an error
96 96 bool hadError() { return _hadError; }
97 97
98 98 //! returns true if python cerr had an error
99 99 void clearError() {
100 100 _hadError = false;
101 101 }
102 102
103 103 protected:
104 104 //! handle the pressing of tab
105 105 void handleTabCompletion();
106 106
107 107 //! Returns the position of the command prompt
108 108 int commandPromptPosition();
109 109
110 110 //! Returns if deletion is allowed at the current cursor
111 111 //! (with and without selected text)
112 112 bool verifySelectionBeforeDeletion();
113 113
114 114 //! Sets the current font
115 115 void setCurrentFont(const QColor& color = QColor(0,0,0), bool bold = false);
116 116
117 117 //! change the history according to _historyPos
118 118 void changeHistory();
119 119
120 120 //! flush output that was not yet printed
121 121 void flushStdOut();
122 122
123 123
124 124 private:
125 125 void executeCode(const QString& code);
126 126
127 127 PythonQtObjectPtr _context;
128 128
129 129 QStringList _history;
130 130 int _historyPosition;
131 131
132 132 QString _clickedAnchor;
133 133 QString _storageKey;
134 134 QString _commandPrompt;
135 135
136 136 QString _currentMultiLineCode;
137 137
138 138 QString _stdOut;
139 139 QString _stdErr;
140 140
141 141 QTextCharFormat _defaultTextCharacterFormat;
142 142 QCompleter* _completer;
143 143
144 144 bool _hadError;
145 145 };
146 146
147 147
148 148
149 149 #endif No newline at end of file
@@ -1,68 +1,68
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtTests.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtTests.h"
44 44
45 45 int main( int argc, char **argv )
46 46 {
47 47 QApplication qapp(argc, argv);
48 48
49 49 PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
50 50
51 51 int failCount = 0;
52 52 PythonQtTestApi api;
53 53 failCount += QTest::qExec(&api, argc, argv);
54 54 PythonQtTestSignalHandler signalHandler;
55 55 failCount += QTest::qExec(&signalHandler, argc, argv);
56 56 PythonQtTestSlotCalling slotCalling;
57 57 failCount += QTest::qExec(&slotCalling, argc, argv);
58 58
59 59 PythonQt::cleanup();
60 60
61 61 if (failCount>0) {
62 62 std::cerr << "Tests failed: " << failCount << std::endl;
63 63 } else {
64 64 std::cout << "All tests passed successfully." << std::endl;
65 65 }
66 66 return failCount;
67 67 }
68 68
@@ -1,585 +1,585
1 1 /*
2 2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtTests.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtTests.h"
43 43
44 44 void PythonQtTestSlotCalling::initTestCase()
45 45 {
46 46 _helper = new PythonQtTestSlotCallingHelper(this);
47 47 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
48 48 main.evalScript("import PythonQt");
49 49 PythonQt::self()->addObject(main, "obj", _helper);
50 50 }
51 51
52 52 void PythonQtTestSlotCalling::init() {
53 53
54 54 }
55 55
56 56
57 57 void* polymorphic_ClassB_Handler(const void* ptr, char** className) {
58 58 ClassB* o = (ClassB*)ptr;
59 59 if (o->type()==2) {
60 60 *className = "ClassB";
61 61 return (ClassB*)o;
62 62 }
63 63 if (o->type()==3) {
64 64 *className = "ClassC";
65 65 return (ClassC*)o;
66 66 }
67 67 if (o->type()==4) {
68 68 *className = "ClassD";
69 69 return (ClassD*)o;
70 70 }
71 71 return NULL;
72 72 }
73 73
74 74 void PythonQtTestSlotCalling::testInheritance() {
75 75 PythonQt::self()->registerCPPClass("ClassA",NULL,NULL, PythonQtCreateObject<ClassAWrapper>);
76 76 PythonQt::self()->registerCPPClass("ClassB",NULL,NULL, PythonQtCreateObject<ClassBWrapper>);
77 77 PythonQt::self()->registerCPPClass("ClassC",NULL,NULL, PythonQtCreateObject<ClassCWrapper>);
78 78 PythonQt::self()->addParentClass("ClassC", "ClassA", PythonQtUpcastingOffset<ClassC,ClassA>());
79 79 PythonQt::self()->addParentClass("ClassC", "ClassB", PythonQtUpcastingOffset<ClassC,ClassB>());
80 80 PythonQt::self()->registerClass(&ClassD::staticMetaObject, NULL, PythonQtCreateObject<ClassDWrapper>);
81 81 PythonQt::self()->addParentClass("ClassD", "ClassA", PythonQtUpcastingOffset<ClassD,ClassA>());
82 82 PythonQt::self()->addParentClass("ClassD", "ClassB", PythonQtUpcastingOffset<ClassD,ClassB>());
83 83
84 84 PythonQtObjectPtr classA = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassA");
85 85 PythonQtObjectPtr classB = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassB");
86 86 PythonQtObjectPtr classC = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassC");
87 87 PythonQtObjectPtr classD = PythonQt::self()->getMainModule().getVariable("PythonQt.private.ClassD");
88 88 QVERIFY(classA);
89 89 QVERIFY(classB);
90 90 QVERIFY(classC);
91 91 QVERIFY(classD);
92 92
93 93 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
94 94 QEXPECT_FAIL("", "ClassB can not be converted to ClassA", Continue);
95 95 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
96 96 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
97 97 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n"));
98 98
99 99 QEXPECT_FAIL("", "ClassA can not be converted to ClassB", Continue);
100 100 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
101 101 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
102 102 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
103 103 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n"));
104 104
105 105 QEXPECT_FAIL("", "ClassA can not be converted to ClassC", Continue);
106 106 QVERIFY(_helper->runScript("a = PythonQt.private.ClassA();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
107 107 QEXPECT_FAIL("", "ClassB can not be converted to ClassC", Continue);
108 108 QVERIFY(_helper->runScript("a = PythonQt.private.ClassB();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
109 109 QVERIFY(_helper->runScript("a = PythonQt.private.ClassC();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
110 110 QEXPECT_FAIL("", "ClassD can not be converted to ClassC", Continue);
111 111 QVERIFY(_helper->runScript("a = PythonQt.private.ClassD();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n"));
112 112
113 113 QVERIFY(_helper->runScript("if type(obj.createClassA())==PythonQt.private.ClassA: obj.setPassed();\n"));
114 114 QVERIFY(_helper->runScript("if type(obj.createClassB())==PythonQt.private.ClassB: obj.setPassed();\n"));
115 115 QVERIFY(_helper->runScript("if type(obj.createClassCAsA())==PythonQt.private.ClassA: obj.setPassed();\n"));
116 116 QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.private.ClassB: obj.setPassed();\n"));
117 117 QVERIFY(_helper->runScript("if type(obj.createClassD())==PythonQt.private.ClassD: obj.setPassed();\n"));
118 118 QVERIFY(_helper->runScript("if type(obj.createClassDAsA())==PythonQt.private.ClassA: obj.setPassed();\n"));
119 119 QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.private.ClassB: obj.setPassed();\n"));
120 120
121 121 PythonQt::self()->addPolymorphicHandler("ClassB", polymorphic_ClassB_Handler);
122 122
123 123 QVERIFY(_helper->runScript("if type(obj.getClassBPtr(obj.createClassB()))==PythonQt.private.ClassB: obj.setPassed();\n"));
124 124 QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.private.ClassC: obj.setPassed();\n"));
125 125 QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.private.ClassD: obj.setPassed();\n"));
126 126
127 127 }
128 128
129 129 void PythonQtTestSlotCalling::testAutoConversion() {
130 130 QVERIFY(_helper->runScript("if obj.setAutoConvertColor(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
131 131 QVERIFY(_helper->runScript("if obj.setAutoConvertBrush(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QBrush(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
132 132 QVERIFY(_helper->runScript("if obj.setAutoConvertPen(PythonQt.QtCore.Qt.red)==PythonQt.Qt.QPen(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
133 133 QVERIFY(_helper->runScript("if obj.setAutoConvertBrush(PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red))==PythonQt.Qt.QBrush(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
134 134 QVERIFY(_helper->runScript("if obj.setAutoConvertPen(PythonQt.Qt.QColor(PythonQt.QtCore.Qt.red))==PythonQt.Qt.QPen(PythonQt.QtCore.Qt.red): obj.setPassed();\n"));
135 135 QVERIFY(_helper->runScript("if obj.setAutoConvertCursor(PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor)).shape()==PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape(): obj.setPassed();\n"));
136 136 QVERIFY(_helper->runScript("if obj.setAutoConvertCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape()==PythonQt.Qt.QCursor(PythonQt.QtCore.Qt.UpArrowCursor).shape(): obj.setPassed();\n"));
137 137 }
138 138
139 139 void PythonQtTestSlotCalling::testNoArgSlotCall()
140 140 {
141 141 QVERIFY(_helper->runScript("obj.testNoArg(); obj.setPassed();\n"));
142 142 }
143 143
144 144 void PythonQtTestSlotCalling::testOverloadedCall()
145 145 {
146 146 QVERIFY(_helper->runScript("obj.overload(False); obj.setPassed();\n", 0));
147 147 QVERIFY(_helper->runScript("obj.overload(True); obj.setPassed();\n", 0));
148 148 QVERIFY(_helper->runScript("obj.overload(12.5); obj.setPassed();\n", 1));
149 149 QVERIFY(_helper->runScript("obj.overload(12); obj.setPassed();\n", 2));
150 150 QVERIFY(_helper->runScript("obj.overload('test'); obj.setPassed();\n", 3));
151 151 QVERIFY(_helper->runScript("obj.overload(u'test'); obj.setPassed();\n", 3));
152 152 QVERIFY(_helper->runScript("obj.overload(('test','test2')); obj.setPassed();\n", 4));
153 153 QVERIFY(_helper->runScript("obj.overload(obj); obj.setPassed();\n", 5));
154 154 QVERIFY(_helper->runScript("obj.overload(12,13); obj.setPassed();\n", 6));
155 155 }
156 156
157 157 void PythonQtTestSlotCalling::testPyObjectSlotCall()
158 158 {
159 159 QVERIFY(_helper->runScript("if obj.getPyObject(PythonQt)==PythonQt: obj.setPassed();\n"));
160 160 QVERIFY(_helper->runScript("if obj.getPyObject('Hello')=='Hello': obj.setPassed();\n"));
161 161 QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant(PythonQt)==PythonQt: obj.setPassed();\n"));
162 162 QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant2(PythonQt)==PythonQt: obj.setPassed();\n"));
163 163 // QVERIFY(_helper->runScript("if obj.getPyObjectFromPtr(PythonQt)==PythonQt: obj.setPassed();\n"));
164 164 }
165 165
166 166 void PythonQtTestSlotCalling::testCPPSlotCalls()
167 167 {
168 168 // test QColor compare operation
169 169 QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();obj.testNoArg()\n"));
170 170 QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)!=PythonQt.QtGui.QColor(3,2,1): obj.setPassed();obj.testNoArg()\n"));
171 171
172 172 // test passing/returning QColors
173 173 QVERIFY(_helper->runScript("if obj.getQColor1(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
174 174 QVERIFY(_helper->runScript("if obj.getQColor2(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
175 175 QVERIFY(_helper->runScript("if obj.getQColor3(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
176 176 QVERIFY(_helper->runScript("if obj.getQColor4(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
177 177 QVERIFY(_helper->runScript("if obj.getQColor5()==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n"));
178 178 }
179 179
180 180 void PythonQtTestSlotCalling::testPODSlotCalls()
181 181 {
182 182 QVERIFY(_helper->runScript("if obj.getBool(False)==False: obj.setPassed();\n"));
183 183 QVERIFY(_helper->runScript("if obj.getBool(True)==True: obj.setPassed();\n"));
184 184 QVERIFY(_helper->runScript("if obj.getInt(-42)==-42: obj.setPassed();\n"));
185 185 QVERIFY(_helper->runScript("if obj.getUInt(42)==42: obj.setPassed();\n"));
186 186 QVERIFY(_helper->runScript("if obj.getShort(-43)==-43: obj.setPassed();\n"));
187 187 QVERIFY(_helper->runScript("if obj.getUShort(43)==43: obj.setPassed();\n"));
188 188 QVERIFY(_helper->runScript("if obj.getChar(-12)==-12: obj.setPassed();\n"));
189 189 QVERIFY(_helper->runScript("if obj.getUChar(12)==12: obj.setPassed();\n"));
190 190 QVERIFY(_helper->runScript("if obj.getLong(-256*256*256)==-256*256*256: obj.setPassed();\n"));
191 191 QVERIFY(_helper->runScript("if obj.getULong(256*256*256)==256*256*256: obj.setPassed();\n"));
192 192 QVERIFY(_helper->runScript("if obj.getLongLong(-42)==-42: obj.setPassed();\n"));
193 193 QVERIFY(_helper->runScript("if obj.getULongLong(42)==42: obj.setPassed();\n"));
194 194 QVERIFY(_helper->runScript("if obj.getQChar(4096)==4096: obj.setPassed();\n"));
195 195 QVERIFY(_helper->runScript("if obj.getDouble(47.12)==47.12: obj.setPassed();\n"));
196 196 QVERIFY(_helper->runScript("if abs(obj.getFloat(47.11)-47.11)<0.01: obj.setPassed();\n"));
197 197 QVERIFY(_helper->runScript("if obj.getQString('testStr')=='testStr': obj.setPassed();\n"));
198 198 QVERIFY(_helper->runScript("if obj.getQString('')=='': obj.setPassed();\n"));
199 199 QVERIFY(_helper->runScript("if obj.getQStringList(('test','test2'))==('test','test2'): obj.setPassed();\n"));
200 200 }
201 201
202 202 void PythonQtTestSlotCalling::testQVariantSlotCalls()
203 203 {
204 204 QVERIFY(_helper->runScript("if obj.getQVariant(-42)==-42: obj.setPassed();\n"));
205 205 QVERIFY(_helper->runScript("if obj.getQVariant('testStr')=='testStr': obj.setPassed();\n"));
206 206 QVERIFY(_helper->runScript("if obj.getQVariant(('test','test2'))==('test','test2'): obj.setPassed();\n"));
207 207 QVERIFY(_helper->runScript("if obj.getQVariant(('test',12, 47.11))==('test',12, 47.11): obj.setPassed();\n"));
208 208 QVERIFY(_helper->runScript("if obj.getQVariant({'test':'bla','test2':47.11})=={'test':'bla','test2':47.11}: obj.setPassed();\n"));
209 209 QEXPECT_FAIL("", "Testing to pass a map and compare with a different map", Continue);
210 210 QVERIFY(_helper->runScript("if obj.getQVariant({'test':'bla2','test2':47.11})=={'test':'bla','test2':47.11}: obj.setPassed();\n"));
211 211 QVERIFY(_helper->runScript("if obj.getQVariant(obj)==obj: obj.setPassed();\n"));
212 212 }
213 213
214 214 void PythonQtTestSlotCalling::testObjectSlotCalls()
215 215 {
216 216 QVERIFY(_helper->runScript("if obj.getQObject(obj)==obj: obj.setPassed();\n"));
217 217 QVERIFY(_helper->runScript("if obj.getTestObject(obj)==obj: obj.setPassed();\n"));
218 218 QVERIFY(_helper->runScript("if obj.getNewObject().className()=='PythonQtTestSlotCallingHelper': obj.setPassed();\n"));
219 219 QEXPECT_FAIL("", "Testing to pass a QObject when another object was expected", Continue);
220 220 QVERIFY(_helper->runScript("if obj.getQWidget(obj)==obj: obj.setPassed();\n"));
221 221 }
222 222
223 223 void PythonQtTestSlotCalling::testCppFactory()
224 224 {
225 225 PythonQtTestCppFactory* f = new PythonQtTestCppFactory;
226 226 PythonQt::self()->addInstanceDecorators(new PQCppObjectDecorator);
227 227 // do not register, since we want to know if that works as well
228 228 //qRegisterMetaType<PQCppObjectNoWrap>("PQCppObjectNoWrap");
229 229 PythonQt::self()->addDecorators(new PQCppObjectNoWrapDecorator);
230 230
231 231 PythonQt::self()->addWrapperFactory(f);
232 232 QVERIFY(_helper->runScript("if obj.createPQCppObject(12).getHeight()==12: obj.setPassed();\n"));
233 233 QVERIFY(_helper->runScript("if obj.createPQCppObject(12).getH()==12: obj.setPassed();\n"));
234 234 QVERIFY(_helper->runScript("pq1 = obj.createPQCppObject(12);\n"
235 235 "pq2 = obj.createPQCppObject(13);\n"
236 236 "pq3 = obj.getPQCppObject(pq1);\n"
237 237 "pq4 = obj.getPQCppObject(pq2);\n"
238 238 "if pq3.getHeight()==12 and pq4.getHeight()==13: obj.setPassed();\n"
239 239 ));
240 240
241 241 QVERIFY(_helper->runScript("if obj.createPQCppObjectNoWrap(12).getH()==12: obj.setPassed();\n"));
242 242
243 243 QVERIFY(_helper->runScript("if obj.getPQCppObjectNoWrapAsValue().getH()==47: obj.setPassed();\n"));
244 244
245 245 qRegisterMetaType<PQUnknownButRegisteredValueObject>("PQUnknownButRegisteredValueObject");
246 246 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n"));
247 247 QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n"));
248 248 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n"));
249 249 QEXPECT_FAIL("", "Testing by value return without the object being registered as QMetaType or having registered a default constructor decorator", Continue);
250 250 QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n"));
251 251
252 252 // expect to get strict call to double overload
253 253 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22.2)\nif a.getH()==2: obj.setPassed();\n"));
254 254 // expect to get un-strict call to double overload
255 255 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22)\nif a.getH()==2: obj.setPassed();\n"));
256 256 // expect to get strict call to copy constructor overload
257 257 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(PQCppObjectNoWrap())\nprint a.getH()\nif a.getH()==1: obj.setPassed();\n"));
258 258
259 259 // test decorated enums
260 260 // already registered by signals test
261 261 //PythonQt::self()->registerCPPClass("PQCppObject2",NULL,NULL, PythonQtCreateObject<PQCppObject2Decorator>);
262 262
263 263 // local enum (decorated)
264 264 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nprint a.testEnumFlag1\nif a.testEnumFlag1(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
265 265 // enum with namespace (decorated)
266 266 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag2(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
267 267 // with int overload to check overloading
268 268 QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag3(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n"));
269 269
270 270 }
271 271
272 272 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag1(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) {
273 273 return flag;
274 274 }
275 275
276 276 PQCppObject2::TestEnumFlag PQCppObject2Decorator::testEnumFlag2(PQCppObject2* obj, PQCppObject2::TestEnumFlag flag) {
277 277 return flag;
278 278 }
279 279
280 280 // with int overload
281 281 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, int flag) {
282 282 return (TestEnumFlag)-1;
283 283 }
284 284 PQCppObject2Decorator::TestEnumFlag PQCppObject2Decorator::testEnumFlag3(PQCppObject2* obj, PQCppObject2Decorator::TestEnumFlag flag) {
285 285 return flag;
286 286 }
287 287
288 288 void PythonQtTestSlotCalling::testMultiArgsSlotCall()
289 289 {
290 290 QVERIFY(_helper->runScript("if obj.getMultiArgs(12,47.11,'test')==(12,47.11,'test'): obj.setPassed();\n"));
291 291 }
292 292
293 293 bool PythonQtTestSlotCallingHelper::runScript(const char* script, int expectedOverload)
294 294 {
295 295 _called = false;
296 296 _passed = false;
297 297 _calledOverload = -1;
298 298 PyRun_SimpleString(script);
299 299 return _called && _passed && _calledOverload==expectedOverload;
300 300 }
301 301
302 302
303 303 void PythonQtTestSignalHandler::initTestCase()
304 304 {
305 305 _helper = new PythonQtTestSignalHandlerHelper(this);
306 306 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
307 307 PythonQt::self()->addObject(main, "obj", _helper);
308 308 }
309 309
310 310 void PythonQtTestSignalHandler::testSignalHandler()
311 311 {
312 312 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
313 313 PyRun_SimpleString("def testIntSignal(a):\n if a==12: obj.setPassed();\n");
314 314 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(intSignal(int)), main, "testIntSignal"));
315 315 QVERIFY(_helper->emitIntSignal(12));
316 316
317 317 PyRun_SimpleString("def testFloatSignal(a):\n if a==12: obj.setPassed();\n");
318 318 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(floatSignal(float)), main, "testFloatSignal"));
319 319 QVERIFY(_helper->emitFloatSignal(12));
320 320
321 321 // test decorated enums
322 322 PythonQt::self()->registerCPPClass("PQCppObject2",NULL,NULL, PythonQtCreateObject<PQCppObject2Decorator>);
323 323
324 324 PyRun_SimpleString("def testEnumSignal(a):\n if a==1: obj.setPassed();\n");
325 325 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(enumSignal(PQCppObject2::TestEnumFlag)), main, "testEnumSignal"));
326 326 QVERIFY(_helper->emitEnumSignal(PQCppObject2::TestEnumValue2));
327 327
328 328 PyRun_SimpleString("def testVariantSignal(a):\n if a==obj.expectedVariant(): obj.setPassed();\n");
329 329 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(variantSignal(QVariant)), main, "testVariantSignal"));
330 330 _helper->setExpectedVariant(QString("Test"));
331 331 QVERIFY(_helper->emitVariantSignal(QString("Test")));
332 332 _helper->setExpectedVariant(12);
333 333 QVERIFY(_helper->emitVariantSignal(12));
334 334 _helper->setExpectedVariant(QStringList() << "test1" << "test2");
335 335 QVERIFY(_helper->emitVariantSignal(QStringList() << "test1" << "test2"));
336 336 _helper->setExpectedVariant(qVariantFromValue((QObject*)_helper));
337 337 QVERIFY(_helper->emitVariantSignal(qVariantFromValue((QObject*)_helper)));
338 338
339 339 PyRun_SimpleString("def testComplexSignal(a,b,l,o):\n if a==12 and b==13 and l==('test1','test2') and o == obj: obj.setPassed();\n");
340 340 // intentionally not normalized signal:
341 341 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(complexSignal( int, float , const QStringList , QObject*)), main, "testComplexSignal"));
342 342 QVERIFY(_helper->emitComplexSignal(12,13,QStringList() << "test1" << "test2", _helper));
343 343
344 344 // try removing the handler
345 345 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(complexSignal( int, float , const QStringList , QObject*)), main, "testComplexSignal"));
346 346 // and emit the signal, which should fail because the handler was removed
347 347 QVERIFY(!_helper->emitComplexSignal(12,13,QStringList() << "test1" << "test2", _helper));
348 348
349 349 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(intSignal(int)), main, "testIntSignal"));
350 350 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(floatSignal(float)), main, "testFloatSignal"));
351 351 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(variantSignal(QVariant)), main, "testVariantSignal"));
352 352 QVERIFY(PythonQt::self()->removeSignalHandler(_helper, SIGNAL(enumSignal(PQCppObject2::TestEnumFlag)), main, "testEnumSignal"));
353 353
354 354 }
355 355
356 356 void PythonQtTestSignalHandler::testRecursiveSignalHandler()
357 357 {
358 358 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
359 359 PyRun_SimpleString("def testSignal1(a):\n obj.emitSignal2(a);\n");
360 360 PyRun_SimpleString("def testSignal2(a):\n obj.emitSignal3(float(a));\n");
361 361 PyRun_SimpleString("def testSignal3(a):\n if a==12: obj.setPassed();\n");
362 362 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal1(int)), main, "testSignal1"));
363 363 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal2(const QString&)), main, "testSignal2"));
364 364 QVERIFY(PythonQt::self()->addSignalHandler(_helper, SIGNAL(signal3(float)), main, "testSignal3"));
365 365 QVERIFY(_helper->emitSignal1(12));
366 366 }
367 367
368 368
369 369 void PythonQtTestApi::initTestCase()
370 370 {
371 371 _helper = new PythonQtTestApiHelper();
372 372 _main = PythonQt::self()->getMainModule();
373 373 _main.evalScript("import PythonQt");
374 374 _main.addObject("obj", _helper);
375 375 }
376 376
377 377 void PythonQtTestApi::testProperties()
378 378 {
379 379 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
380 380 // check for name alias (for backward comp to Qt3)
381 381 main.evalScript("obj.name = 'hello'");
382 382 QVERIFY(QString("hello") == main.getVariable("obj.name").toString());
383 383
384 384 main.evalScript("obj.objectName = 'hello2'");
385 385 QVERIFY(QString("hello2") == main.getVariable("obj.objectName").toString());
386 386
387 387 }
388 388
389 389 void PythonQtTestApi::testDynamicProperties()
390 390 {
391 391 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
392 392
393 393 // this fails and should fail, but how could that be tested?
394 394 // main.evalScript("obj.testProp = 1");
395 395
396 396 // create a new dynamic property
397 397 main.evalScript("obj.setProperty('testProp','testValue')");
398 398
399 399 // read the property
400 400 QVERIFY(QString("testValue") == main.getVariable("obj.testProp").toString());
401 401 // modify and read again
402 402 main.evalScript("obj.testProp = 12");
403 403 QVERIFY(12 == main.getVariable("obj.testProp").toInt());
404 404
405 405 // check if dynamic property is in dict
406 406 QVERIFY(12 == main.evalScript("obj.__dict__['testProp']", Py_eval_input).toInt());
407 407
408 408 // check if dynamic property is in introspection
409 409 QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), "obj", PythonQt::Anything);
410 410 QVERIFY(l.contains("testProp"));
411 411
412 412 // check with None, previous value expected
413 413 main.evalScript("obj.testProp = None");
414 414 QVERIFY(12 == main.getVariable("obj.testProp").toInt());
415 415
416 416 // remove the dynamic property
417 417 main.evalScript("obj.setProperty('testProp', None)");
418 418
419 419 // check if dynamic property is really gone
420 420 QStringList l2 = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), "obj", PythonQt::Anything);
421 421 QVERIFY(!l2.contains("testProp"));
422 422
423 423 }
424 424
425 425
426 426 bool PythonQtTestApiHelper::call(const QString& function, const QVariantList& args, const QVariant& expectedResult) {
427 427 _passed = false;
428 428 QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), function, args);
429 429 return _passed && expectedResult==r;
430 430 }
431 431
432 432 void PythonQtTestApi::testCall()
433 433 {
434 434 PythonQtObjectPtr main = PythonQt::self()->getMainModule();
435 435
436 436 QVERIFY(qVariantValue<QObject*>(PythonQt::self()->getVariable(main, "obj"))==_helper);
437 437
438 438 PyRun_SimpleString("def testCallNoArgs():\n obj.setPassed();\n");
439 439 QVERIFY(_helper->call("testCallNoArgs", QVariantList(), QVariant()));
440 440
441 441 PyRun_SimpleString("def testCall1(a):\n if a=='test': obj.setPassed();\n return 'test2';\n");
442 442 QVERIFY(_helper->call("testCall1", QVariantList() << QVariant("test"), QVariant(QString("test2"))));
443 443
444 444 PyRun_SimpleString("def testCall2(a, b):\n if a=='test' and b==obj: obj.setPassed();\n return obj;\n");
445 445 QVariant r = PythonQt::self()->call(PythonQt::self()->getMainModule(), "testCall2", QVariantList() << QVariant("test") << qVariantFromValue((QObject*)_helper));
446 446 QObject* p = qVariantValue<QObject*>(r);
447 447 QVERIFY(p==_helper);
448 448 }
449 449
450 450 void PythonQtTestApi::testVariables()
451 451 {
452 452 PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "someObject", _helper);
453 453 QVariant v = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject");
454 454 QObject* p = qVariantValue<QObject*>(v);
455 455 QVERIFY(p==_helper);
456 456 // test for unset variable
457 457 QVariant v2 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject2");
458 458 QVERIFY(v2==QVariant());
459 459
460 460 PythonQt::self()->addVariable(PythonQt::self()->getMainModule(), "someValue", QStringList() << "test1" << "test2");
461 461 QVariant v3 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someValue");
462 462 QVERIFY(v3 == QVariant(QStringList() << "test1" << "test2"));
463 463
464 464 QStringList l = PythonQt::self()->introspection(PythonQt::self()->getMainModule(), QString::null, PythonQt::Variable);
465 465 QSet<QString> s;
466 466 // check that at least these three variables are set
467 467 s << "obj" << "someObject" << "someValue";
468 468 foreach (QString value, s) {
469 469 QVERIFY(l.indexOf(value)!=-1);
470 470 }
471 471
472 472 // insert a second time!
473 473 PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "someObject", _helper);
474 474 // and remove
475 475 PythonQt::self()->removeVariable(PythonQt::self()->getMainModule(), "someObject");
476 476 // we expect to find no variable
477 477 QVariant v4 = PythonQt::self()->getVariable(PythonQt::self()->getMainModule(), "someObject");
478 478 QVERIFY(v4==QVariant());
479 479 }
480 480
481 481 void PythonQtTestApi::testImporter()
482 482 {
483 483 PythonQt::self()->setImporter(_helper);
484 484 PythonQt::self()->overwriteSysPath(QStringList() << "c:\\test");
485 485 PyRun_SimpleString("import bla\n");
486 486 }
487 487
488 488 void PythonQtTestApi::testQtNamespace()
489 489 {
490 490 QVERIFY(_main.getVariable("PythonQt.QtCore.Qt.red").toInt()==Qt::red);
491 491 QVERIFY(_main.getVariable("PythonQt.QtCore.Qt.FlatCap").toInt()==Qt::FlatCap);
492 492 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.escape")));
493 493 // check for an enum type wrapper
494 494 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.AlignmentFlag")));
495 495 // check for a flags type wrapper
496 496 QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.Alignment")));
497 497 }
498 498
499 499 void PythonQtTestApi::testConnects()
500 500 {
501 501 // QVERIFY(qVariantValue<QColor>(_main.evalScript("PythonQt.Qt.QColor(PythonQt.Qt.Qt.red)" ,Py_eval_input)) == QColor(Qt::red));
502 502 //TODO: add signal/slot connect both with QObject.connect and connect
503 503 }
504 504
505 505 void PythonQtTestApi::testQColorDecorators()
506 506 {
507 507 PythonQtObjectPtr colorClass = _main.getVariable("PythonQt.QtGui.QColor");
508 508 QVERIFY(colorClass);
509 509 // verify that the class is in the correct module
510 510 QVERIFY(colorClass.getVariable("__module__") == "PythonQt.QtGui");
511 511 // test on Qt module as well:
512 512 colorClass = _main.getVariable("PythonQt.Qt.QColor");
513 513 QVERIFY(colorClass);
514 514 // constructors
515 515 QVERIFY(qVariantValue<QColor>(colorClass.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
516 516 QVERIFY(qVariantValue<QColor>(colorClass.call()) == QColor());
517 517 QEXPECT_FAIL("", "Testing non-existing constructor", Continue);
518 518 QVERIFY(colorClass.call(QVariantList() << 1 << 2) != QVariant());
519 519
520 520 // check that enum overload is taken over int
521 521 QVERIFY(qVariantValue<QColor>(_main.evalScript("PythonQt.Qt.QColor(PythonQt.Qt.Qt.red)" ,Py_eval_input)) == QColor(Qt::red));
522 522 // check that int overload is taken over enum
523 523 QVERIFY(qVariantValue<QColor>(_main.evalScript("PythonQt.Qt.QColor(0x112233)" ,Py_eval_input)) == QColor(0x112233));
524 524
525 525 // check for decorated Cmyk enum value
526 526 QVERIFY(colorClass.getVariable("Cmyk").toInt() == QColor::Cmyk);
527 527 PythonQtObjectPtr staticMethod = colorClass.getVariable("fromRgb");
528 528 QVERIFY(staticMethod);
529 529 // direct call of static method via class
530 530 QVERIFY(qVariantValue<QColor>(colorClass.call("fromRgb", QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
531 531 // direct call of static method
532 532 QVERIFY(qVariantValue<QColor>(staticMethod.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3));
533 533 PythonQtObjectPtr publicMethod = colorClass.getVariable("red");
534 534 QVERIFY(publicMethod);
535 535 // call with passing self in:
536 536 QVERIFY(colorClass.call("red", QVariantList() << QColor(255,0,0)).toInt() == 255);
537 537 }
538 538
539 539 QByteArray PythonQtTestApiHelper::readFileAsBytes(const QString& filename)
540 540 {
541 541 QByteArray b;
542 542 return b;
543 543 }
544 544
545 545 QByteArray PythonQtTestApiHelper::readSourceFile(const QString& filename, bool& ok)
546 546 {
547 547 QByteArray b;
548 548 ok = true;
549 549 return b;
550 550 }
551 551
552 552 bool PythonQtTestApiHelper::exists(const QString& filename)
553 553 {
554 554 return true;
555 555 }
556 556
557 557 QDateTime PythonQtTestApiHelper::lastModifiedDate(const QString& filename) {
558 558 return QDateTime::currentDateTime();
559 559 }
560 560
561 561
562 562 void PythonQtTestApi::testRedirect()
563 563 {
564 564 connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), _helper, SLOT(stdOut(const QString&)));
565 565 connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), _helper, SLOT(stdErr(const QString&)));
566 566 PyRun_SimpleString("print 'test'\n");
567 567 }
568 568
569 569 void PythonQtTestApiHelper::stdOut(const QString& s)
570 570 {
571 571 qDebug() << s;
572 572 }
573 573
574 574 void PythonQtTestApiHelper::stdErr(const QString& s)
575 575 {
576 576 qDebug() << s;
577 577 }
578 578
579 579 QObject* PythonQtTestCppFactory::create(const QByteArray& name, void *ptr)
580 580 {
581 581 if (name == "PQCppObject") {
582 582 return new PQCppObjectWrapper(ptr);
583 583 }
584 584 return NULL;
585 585 }
@@ -1,515 +1,515
1 1 #ifndef _PYTHONQTTESTS_H
2 2 #define _PYTHONQTTESTS_H
3 3
4 4 /*
5 5 *
6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtTests.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQt.h"
46 46 #include <QtTest/QtTest>
47 47 #include <QVariant>
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50
51 51 #include <QPen>
52 52 #include <QColor>
53 53 #include <QBrush>
54 54 #include <QCursor>
55 55
56 56 class PythonQtTestSlotCallingHelper;
57 57 class PythonQtTestApiHelper;
58 58 class QWidget;
59 59
60 60 //! test the PythonQt api
61 61 class PythonQtTestApi : public QObject
62 62 {
63 63 Q_OBJECT
64 64
65 65 private slots:
66 66 void initTestCase();
67 67 void testCall();
68 68 void testVariables();
69 69 void testRedirect();
70 70 void testImporter();
71 71 void testQColorDecorators();
72 72 void testQtNamespace();
73 73 void testConnects();
74 74
75 75 void testProperties();
76 76 void testDynamicProperties();
77 77
78 78 private:
79 79 PythonQtTestApiHelper* _helper;
80 80 PythonQtObjectPtr _main;
81 81
82 82 };
83 83
84 84 class ClassA {
85 85 public:
86 86 ClassA() { x = 1; }
87 87 int x;
88 88 };
89 89
90 90 class ClassB {
91 91 public:
92 92 ClassB() { y = 2; }
93 93 int y;
94 94
95 95 virtual int type() { return 2; }
96 96 };
97 97
98 98 class ClassC : public ClassA, public ClassB {
99 99 public:
100 100 ClassC() { z = 3; }
101 101 int z;
102 102
103 103 virtual int type() { return 3; }
104 104 };
105 105
106 106 class ClassD : public QObject, public ClassA, public ClassB {
107 107 Q_OBJECT
108 108 public:
109 109 ClassD() { d = 4; }
110 110 public slots:
111 111 int getD() { return d; }
112 112 private:
113 113 int d;
114 114
115 115 virtual int type() { return 4; }
116 116 };
117 117
118 118 class ClassAWrapper : public QObject {
119 119 Q_OBJECT
120 120 public slots:
121 121 ClassA* new_ClassA() { return new ClassA; }
122 122 int getX(ClassA* o) { return o->x; }
123 123 };
124 124
125 125 class ClassBWrapper : public QObject {
126 126 Q_OBJECT
127 127 public slots:
128 128 ClassB* new_ClassB() { return new ClassB; }
129 129 int getY(ClassB* o) { return o->y; }
130 130 };
131 131
132 132 class ClassCWrapper : public QObject {
133 133 Q_OBJECT
134 134 public slots:
135 135 ClassC* new_ClassC() { return new ClassC; }
136 136 int getZ(ClassC* o) { return o->z; }
137 137 };
138 138
139 139 class ClassDWrapper : public QObject {
140 140 Q_OBJECT
141 141 public slots:
142 142 ClassD* new_ClassD() { return new ClassD; }
143 143 };
144 144
145 145
146 146 //! test the PythonQt api (helper)
147 147 class PythonQtTestApiHelper : public QObject , public PythonQtImportFileInterface
148 148 {
149 149 Q_OBJECT
150 150 public:
151 151 PythonQtTestApiHelper() {
152 152 };
153 153
154 154 bool call(const QString& function, const QVariantList& args, const QVariant& expectedResult);
155 155
156 156 virtual QByteArray readFileAsBytes(const QString& filename);
157 157
158 158 virtual QByteArray readSourceFile(const QString& filename, bool& ok);
159 159
160 160 virtual bool exists(const QString& filename);
161 161
162 162 virtual QDateTime lastModifiedDate(const QString& filename);
163 163
164 164 public slots:
165 165
166 166 //! call to set that the test has passed (from Python!)
167 167 void setPassed() { _passed = true; }
168 168
169 169 void stdOut(const QString&);
170 170 void stdErr(const QString&);
171 171
172 172 private:
173 173 bool _passed;
174 174 };
175 175
176 176
177 177 // test implementation of the wrapper factory
178 178 class PythonQtTestCppFactory : public PythonQtCppWrapperFactory
179 179 {
180 180 public:
181 181 virtual QObject* create(const QByteArray& name, void *ptr);
182 182 };
183 183
184 184 //! an cpp object to be wrapped
185 185 class PQCppObject {
186 186
187 187 public:
188 188 PQCppObject(int h) { _height = h; }
189 189
190 190 int getHeight() { return _height; }
191 191 void setHeight(int h) { _height = h; }
192 192
193 193 private:
194 194 int _height;
195 195 };
196 196
197 197 //! an qobject that wraps the existing cpp object
198 198 class PQCppObjectWrapper : public QObject {
199 199 Q_OBJECT
200 200 public:
201 201 PQCppObjectWrapper(void* ptr) {
202 202 _ptr = (PQCppObject*)ptr;
203 203 }
204 204
205 205 public slots:
206 206 int getHeight() { return _ptr->getHeight(); }
207 207 void setHeight(int h) { _ptr->setHeight(h); }
208 208
209 209 private:
210 210 PQCppObject* _ptr;
211 211 };
212 212
213 213 class PQCppObjectDecorator : public QObject {
214 214 Q_OBJECT
215 215 public slots:
216 216 int getH(PQCppObject* obj) { return obj->getHeight(); }
217 217
218 218 };
219 219
220 220 //! an cpp object to be wrapped by decorators only
221 221 class PQCppObjectNoWrap {
222 222
223 223 public:
224 224 PQCppObjectNoWrap() { _height = 0; }
225 225 PQCppObjectNoWrap(int h) { _height = h; }
226 226
227 227 int getHeight() { return _height; }
228 228 void setHeight(int h) { _height = h; }
229 229
230 230 private:
231 231 int _height;
232 232 };
233 233
234 234 class PQCppObjectNoWrapDecorator : public QObject {
235 235 Q_OBJECT
236 236
237 237 public slots:
238 238 PQCppObjectNoWrap* new_PQCppObjectNoWrap() {
239 239 return new PQCppObjectNoWrap(0);
240 240 }
241 241 PQCppObjectNoWrap* new_PQCppObjectNoWrap(const PQCppObjectNoWrap& other) {
242 242 return new PQCppObjectNoWrap(1);
243 243 }
244 244 PQCppObjectNoWrap* new_PQCppObjectNoWrap(double value) {
245 245 return new PQCppObjectNoWrap(2);
246 246 }
247 247
248 248 int getH(PQCppObjectNoWrap* obj) { return obj->getHeight(); }
249 249
250 250 };
251 251
252 252
253 253 //! an cpp object that is to be wrapped by decorators only
254 254 class PQCppObject2 {
255 255
256 256 public:
257 257 enum TestEnumFlag {
258 258 TestEnumValue1 = 0,
259 259 TestEnumValue2 = 1
260 260 };
261 261
262 262 PQCppObject2() {}
263 263
264 264 };
265 265
266 266 class PQCppObject2Decorator : public QObject {
267 267 Q_OBJECT
268 268
269 269 public:
270 270 Q_ENUMS(TestEnumFlag)
271 271 Q_FLAGS(TestEnum)
272 272
273 273 enum TestEnumFlag {
274 274 TestEnumValue1 = 0,
275 275 TestEnumValue2 = 1
276 276 };
277 277
278 278 Q_DECLARE_FLAGS(TestEnum, TestEnumFlag)
279 279
280 280 public slots:
281 281 PQCppObject2* new_PQCppObject2() {
282 282 return new PQCppObject2();
283 283 }
284 284
285 285 TestEnumFlag testEnumFlag1(PQCppObject2* obj, TestEnumFlag flag);
286 286
287 287 PQCppObject2::TestEnumFlag testEnumFlag2(PQCppObject2* obj, PQCppObject2::TestEnumFlag flag);
288 288
289 289 // with int overload
290 290 TestEnumFlag testEnumFlag3(PQCppObject2* obj, int flag);
291 291 TestEnumFlag testEnumFlag3(PQCppObject2* obj, TestEnumFlag flag);
292 292
293 293 };
294 294
295 295 class PQUnknownValueObject
296 296 {
297 297 public:
298 298 PQUnknownValueObject() {};
299 299 };
300 300
301 301 class PQUnknownButRegisteredValueObject
302 302 {
303 303 public:
304 304 PQUnknownButRegisteredValueObject() {};
305 305 };
306 306
307 307 //! test the calling of slots
308 308 class PythonQtTestSlotCalling : public QObject
309 309 {
310 310 Q_OBJECT
311 311
312 312 private slots:
313 313 void initTestCase();
314 314 void init();
315 315
316 316 void testNoArgSlotCall();
317 317 void testPODSlotCalls();
318 318 void testCPPSlotCalls();
319 319 void testQVariantSlotCalls();
320 320 void testObjectSlotCalls();
321 321 void testMultiArgsSlotCall();
322 322 void testPyObjectSlotCall();
323 323 void testOverloadedCall();
324 324 void testCppFactory();
325 325 void testInheritance();
326 326 void testAutoConversion();
327 327
328 328 private:
329 329 PythonQtTestSlotCallingHelper* _helper;
330 330
331 331 };
332 332
333 333 //! helper class for slot calling test
334 334 class PythonQtTestSlotCallingHelper : public QObject
335 335 {
336 336 Q_OBJECT
337 337 public:
338 338 PythonQtTestSlotCallingHelper(PythonQtTestSlotCalling* test) {
339 339 _test = test;
340 340 };
341 341
342 342 bool runScript(const char* script, int expectedOverload = -1);
343 343
344 344 public slots:
345 345
346 346 //! call to set that the test has passed (from Python!)
347 347 void setPassed() { _passed = true; }
348 348
349 349 //! no arguments, no return value:
350 350 void testNoArg() { _called = true; }
351 351
352 352 //! overload test!
353 353 void overload(bool a) { _calledOverload = 0; _called = true; }
354 354 void overload(float a) { _calledOverload = 1; _called = true;}
355 355 void overload(int a) { _calledOverload = 2; _called = true;}
356 356 void overload(const QString& str) { _calledOverload = 3; _called = true;}
357 357 void overload(const QStringList& str) { _calledOverload = 4; _called = true;}
358 358 void overload(QObject* str) { _calledOverload = 5; _called = true;}
359 359 void overload(float a, int b) { _calledOverload = 6; _called = true;}
360 360
361 361 //! POD values:
362 362 int getInt(int a) { _called = true; return a; }
363 363 unsigned int getUInt(unsigned int a) { _called = true; return a; }
364 364 bool getBool(bool a) { _called = true; return a; }
365 365 char getChar(char a) { _called = true; return a; }
366 366 unsigned char getUChar(unsigned char a) { _called = true; return a; }
367 367 long getLong(long a) { _called = true; return a; }
368 368 unsigned long getULong(unsigned long a) { _called = true; return a; }
369 369 short getShort(short a) { _called = true; return a; }
370 370 unsigned short getUShort(unsigned short a) { _called = true; return a; }
371 371 QChar getQChar(QChar a) { _called = true; return a; }
372 372 qint64 getLongLong(qint64 a) { _called = true; return a; }
373 373 quint64 getULongLong(quint64 a) { _called = true; return a; }
374 374 double getDouble(double d) { _called = true; return d; }
375 375 float getFloat(float d) { _called = true; return d; }
376 376
377 377 //! important qt types:
378 378 QString getQString(const QString& s) { _called = true; return s; }
379 379 QStringList getQStringList(const QStringList& l) { _called = true; return l; }
380 380 QVariant getQVariant(const QVariant& var) { _called = true; return var; }
381 381
382 382 // QColor as representative for C++ value classes
383 383 QColor getQColor1(const QColor& var) { _called = true; return var; }
384 384 QColor getQColor2(QColor& var) { _called = true; return var; }
385 385 QColor getQColor3(QColor* col) { _called = true; return *col; }
386 386 QColor getQColor4(const QVariant& color) { _called = true; return qVariantValue<QColor>(color); }
387 387 QColor* getQColor5() { _called = true; static QColor c(1,2,3); return &c; }
388 388
389 389 PyObject* getPyObject(PyObject* obj) { _called = true; return obj; }
390 390 PyObject* getPyObjectFromVariant(const QVariant& val) { _called = true; return PythonQtObjectPtr(val); };
391 391 QVariant getPyObjectFromVariant2(const QVariant& val) { _called = true; return val; };
392 392 // this does not yet work but is not required to work:
393 393 //PyObject* getPyObjectFromPtr(const PythonQtObjectPtr& val) { _called = true; return val; };
394 394
395 395 //! testing pointer passing
396 396 PythonQtTestSlotCallingHelper* getTestObject(PythonQtTestSlotCallingHelper* obj) { _called = true; return obj; }
397 397 //! testing inheritance checking
398 398 QObject* getQObject(QObject* obj) { _called = true; return obj; }
399 399 QWidget* getQWidget(QWidget* obj) { _called = true; return obj; }
400 400 //! testing if an object that was not wrapped is wrapped earlier is wrapped correctly
401 401 QObject* getNewObject() { _called = true; return new PythonQtTestSlotCallingHelper(NULL); }
402 402
403 403 QVariantList getMultiArgs(int a, double b, const QString& str) { _called = true; return (QVariantList() << a << b << str); }
404 404
405 405 //! cpp wrapper factory test
406 406 PQCppObject* createPQCppObject(int h) { _called = true; return new PQCppObject(h); }
407 407
408 408 //! cpp wrapper factory test
409 409 PQCppObject* getPQCppObject(PQCppObject* p) { _called = true; return p; }
410 410
411 411 //! cpp wrapper factory test
412 412 PQCppObjectNoWrap* createPQCppObjectNoWrap(int h) { _called = true; return new PQCppObjectNoWrap(h); }
413 413
414 414 //! cpp wrapper factory test
415 415 PQCppObjectNoWrap* getPQCppObjectNoWrap(PQCppObjectNoWrap* p) { _called = true; return p; }
416 416
417 417 //! get a return by value PQCppObjectNoWrap
418 418 PQCppObjectNoWrap getPQCppObjectNoWrapAsValue() { _called = true; return PQCppObjectNoWrap(47); }
419 419
420 420 PQUnknownButRegisteredValueObject getUnknownButRegisteredValueObjectAsValue() { _called = true; return PQUnknownButRegisteredValueObject(); }
421 421 PQUnknownValueObject getUnknownValueObjectAsValue() { _called = true; return PQUnknownValueObject(); }
422 422
423 423 PQUnknownButRegisteredValueObject* getUnknownButRegisteredValueObjectAsPtr() { _called = true; return new PQUnknownButRegisteredValueObject(); }
424 424 PQUnknownValueObject* getUnknownValueObjectAsPtr() { _called = true; return new PQUnknownValueObject(); }
425 425
426 426 ClassA* getClassAPtr(ClassA* o) { _called = true; return o; }
427 427 ClassB* getClassBPtr(ClassB* o) { _called = true; return o; }
428 428 ClassC* getClassCPtr(ClassC* o) { _called = true; return o; }
429 429 ClassD* getClassDPtr(ClassD* o) { _called = true; return o; }
430 430
431 431 ClassA* createClassA() { _called = true; return new ClassA; }
432 432 ClassB* createClassB() { _called = true; return new ClassB; }
433 433 ClassC* createClassC() { _called = true; return new ClassC; }
434 434 ClassD* createClassD() { _called = true; return new ClassD; }
435 435 ClassA* createClassCAsA() { _called = true; return new ClassC; }
436 436 ClassB* createClassCAsB() { _called = true; return new ClassC; }
437 437 ClassA* createClassDAsA() { _called = true; return new ClassD; }
438 438 ClassB* createClassDAsB() { _called = true; return new ClassD; }
439 439
440 440 QColor setAutoConvertColor(const QColor& color) { _called = true; return color; };
441 441 QBrush setAutoConvertBrush(const QBrush& brush) { _called = true; return brush; };
442 442 QPen setAutoConvertPen(const QPen& pen) { _called = true; return pen; };
443 443 QCursor setAutoConvertCursor(const QCursor& cursor) { _called = true; return cursor; };
444 444
445 445 private:
446 446 bool _passed;
447 447 bool _called;
448 448 int _calledOverload;
449 449 PythonQtTestSlotCalling* _test;
450 450 };
451 451
452 452 class PythonQtTestSignalHandlerHelper;
453 453
454 454 //! test the connection of signals to python
455 455 class PythonQtTestSignalHandler : public QObject
456 456 {
457 457 Q_OBJECT
458 458
459 459 private slots:
460 460 void initTestCase();
461 461
462 462 void testSignalHandler();
463 463 void testRecursiveSignalHandler();
464 464
465 465 private:
466 466 PythonQtTestSignalHandlerHelper* _helper;
467 467
468 468 };
469 469
470 470 //! helper class for signal testing
471 471 class PythonQtTestSignalHandlerHelper : public QObject
472 472 {
473 473 Q_OBJECT
474 474
475 475 public:
476 476 PythonQtTestSignalHandlerHelper(PythonQtTestSignalHandler* test) {
477 477 _test = test;
478 478 };
479 479
480 480 public slots:
481 481 void setPassed() { _passed = true; }
482 482
483 483 bool emitIntSignal(int a) { _passed = false; emit intSignal(a); return _passed; };
484 484 bool emitFloatSignal(float a) { _passed = false; emit floatSignal(a); return _passed; };
485 485 bool emitEnumSignal(PQCppObject2::TestEnumFlag flag) { _passed = false; emit enumSignal(flag); return _passed; };
486 486
487 487 bool emitVariantSignal(const QVariant& v) { _passed = false; emit variantSignal(v); return _passed; };
488 488 QVariant expectedVariant() { return _v; }
489 489 void setExpectedVariant(const QVariant& v) { _v = v; }
490 490
491 491 bool emitComplexSignal(int a, float b, const QStringList& l, QObject* obj) { _passed = false; emit complexSignal(a,b,l,obj); return _passed; };
492 492
493 493 bool emitSignal1(int a) { _passed = false; emit signal1(a); return _passed; };
494 494 bool emitSignal2(const QString& s) { _passed = false; emit signal2(s); return _passed; };
495 495 bool emitSignal3(float a) { _passed = false; emit signal3(a); return _passed; };
496 496
497 497 signals:
498 498 void intSignal(int);
499 499 void floatSignal(float);
500 500 void variantSignal(const QVariant& v);
501 501 void complexSignal(int a, float b, const QStringList& l, QObject* obj);
502 502 void enumSignal(PQCppObject2::TestEnumFlag flag);
503 503
504 504 void signal1(int);
505 505 void signal2(const QString&);
506 506 void signal3(float);
507 507
508 508 private:
509 509 bool _passed;
510 510 QVariant _v;
511 511
512 512 PythonQtTestSignalHandler* _test;
513 513 };
514 514
515 515 #endif
General Comments 0
You need to be logged in to leave comments. Login now