1 // This is the implementation of the various Chimera helpers.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of PyQt5.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file. Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license. For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19
20
21 #include <Python.h>
22
23 #include <QList>
24 #include <QMetaType>
25 #include <QObject>
26
27 #include "qpyquick_chimera_helpers.h"
28
29 #include "sipAPIQtQuick.h"
30
31
32 // Forward declarations.
33 static int QList_QObject_metatype();
34 static bool to_QList_QObject(PyObject *obj, QList<QObject *>&cpp);
35
36
37 // Convert a QVariant to a Python object.
qpyquick_from_qvariant_convertor(const QVariant * varp,PyObject ** objp)38 bool qpyquick_from_qvariant_convertor(const QVariant *varp, PyObject **objp)
39 {
40 // Check we handle the meta-type.
41 if (varp->userType() != QList_QObject_metatype())
42 return false;
43
44 const QList<QObject *> *cpp = reinterpret_cast<const QList<QObject *> *>(varp->data());
45
46 PyObject *obj = PyList_New(cpp->count());
47
48 if (obj)
49 {
50 for (int i = 0; i < cpp->count(); ++i)
51 {
52 PyObject *itm = sipConvertFromType(cpp->at(i), sipType_QObject, 0);
53
54 if (!itm)
55 {
56 Py_DECREF(obj);
57 obj = 0;
58 break;
59 }
60
61 PyList_SetItem(obj, i, itm);
62 }
63 }
64
65 *objp = obj;
66
67 return true;
68 }
69
70
71 // Convert a Python object to a QVariant.
qpyquick_to_qvariant_convertor(PyObject * obj,QVariant & var,bool * okp)72 bool qpyquick_to_qvariant_convertor(PyObject *obj, QVariant &var, bool *okp)
73 {
74 int metatype = QList_QObject_metatype();
75
76 // Check the meta-type has been defined.
77 if (metatype == 0)
78 return false;
79
80 QList<QObject *> qlo;
81
82 // A failure to convert isn't an error, just the wrong type of Python
83 // object.
84 if (!to_QList_QObject(obj, qlo))
85 return false;
86
87 var = QVariant(metatype, &qlo);
88 *okp = true;
89
90 return true;
91 }
92
93
94 // Convert a Python object to QVariant data.
qpyquick_to_qvariant_data_convertor(PyObject * obj,void * data,int metatype,bool * okp)95 bool qpyquick_to_qvariant_data_convertor(PyObject *obj, void *data,
96 int metatype, bool *okp)
97 {
98 // Check we handle the meta-type.
99 if (metatype != QList_QObject_metatype())
100 return false;
101
102 QList<QObject *> qlo;
103
104 // A failure to convert isn't an error, just the wrong type of Python
105 // object.
106 if (!to_QList_QObject(obj, qlo))
107 return false;
108
109 *reinterpret_cast<QList<QObject *> *>(data) = qlo;
110 *okp = true;
111
112 return true;
113 }
114
115
116 // Get the metatype for QList<QObject *> or 0 if it hasn't been registered.
QList_QObject_metatype()117 static int QList_QObject_metatype()
118 {
119 static int lo_metatype = 0;
120
121 // We look each time until we find it rather than rely on any particular
122 // behaviour from QtQuick.
123 if (lo_metatype == 0)
124 lo_metatype = QMetaType::type("QList<QObject*>");
125
126 return lo_metatype;
127 }
128
129
130 // Convert a Python list object to a QList<QObject*> and return true if the
131 // conversion was successful. An empty list is never converted and left to the
132 // QtCore module to handle.
to_QList_QObject(PyObject * obj,QList<QObject * > & cpp)133 static bool to_QList_QObject(PyObject *obj, QList<QObject *>&cpp)
134 {
135 if (!PyList_CheckExact(obj) || PyList_Size(obj) == 0)
136 return false;
137
138 for (Py_ssize_t i = 0; i < PyList_Size(obj); ++i)
139 {
140 PyObject *val_obj = PyList_GetItem(obj, i);
141
142 if (!val_obj)
143 return false;
144
145 int iserr = 0;
146
147 QObject *val = reinterpret_cast<QObject *>(sipForceConvertToType(
148 val_obj, sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr));
149
150 if (iserr)
151 return false;
152
153 cpp.append(val);
154 }
155
156 return true;
157 }
158