1 // This contains the implementation of the QQmlListPropertyWrapper type.
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 <sip.h>
24 
25 #include "qpyqmllistpropertywrapper.h"
26 
27 
28 // The type object.
29 PyTypeObject *qpyqml_QQmlListPropertyWrapper_TypeObject;
30 
31 
32 // Forward declarations.
33 extern "C" {
34 static void QQmlListPropertyWrapper_dealloc(PyObject *self);
35 static Py_ssize_t QQmlListPropertyWrapper_sq_length(PyObject *self);
36 static PyObject *QQmlListPropertyWrapper_sq_concat(PyObject *self,
37         PyObject *other);
38 static PyObject *QQmlListPropertyWrapper_sq_repeat(PyObject *self,
39         Py_ssize_t count);
40 static PyObject *QQmlListPropertyWrapper_sq_item(PyObject *self, Py_ssize_t i);
41 #if PY_MAJOR_VERSION < 3
42 static PyObject *QQmlListPropertyWrapper_sq_slice(PyObject *self,
43         Py_ssize_t i1, Py_ssize_t i2);
44 #endif
45 static int QQmlListPropertyWrapper_sq_ass_item(PyObject *self, Py_ssize_t i,
46         PyObject *value);
47 #if PY_MAJOR_VERSION < 3
48 static int QQmlListPropertyWrapper_sq_ass_slice(PyObject *self, Py_ssize_t i1,
49         Py_ssize_t i2, PyObject *value);
50 #endif
51 static int QQmlListPropertyWrapper_sq_contains(PyObject *self,
52         PyObject *value);
53 static PyObject *QQmlListPropertyWrapper_sq_inplace_concat(PyObject *self,
54         PyObject *other);
55 static PyObject *QQmlListPropertyWrapper_sq_inplace_repeat(PyObject *self,
56         Py_ssize_t count);
57 }
58 
59 static PyObject *get_list(PyObject *self);
60 
61 
62 #if PY_VERSION_HEX >= 0x03040000
63 // Define the slots.
64 static PyType_Slot qpyqml_QQmlListPropertyWrapper_Slots[] = {
65     {Py_tp_dealloc,     (void *)QQmlListPropertyWrapper_dealloc},
66     {Py_sq_length,      (void *)QQmlListPropertyWrapper_sq_length},
67     {Py_sq_concat,      (void *)QQmlListPropertyWrapper_sq_concat},
68     {Py_sq_repeat,      (void *)QQmlListPropertyWrapper_sq_repeat},
69     {Py_sq_item,        (void *)QQmlListPropertyWrapper_sq_item},
70     {Py_sq_ass_item,    (void *)QQmlListPropertyWrapper_sq_ass_item},
71     {Py_sq_contains,    (void *)QQmlListPropertyWrapper_sq_contains},
72     {Py_sq_inplace_concat,  (void *)QQmlListPropertyWrapper_sq_inplace_concat},
73     {Py_sq_inplace_repeat,  (void *)QQmlListPropertyWrapper_sq_inplace_repeat},
74     {0,                 0}
75 };
76 
77 
78 // Define the type.
79 static PyType_Spec qpyqml_QQmlListPropertyWrapper_Spec = {
80     "PyQt5.QtQml.QQmlListPropertyWrapper",
81     sizeof (qpyqml_QQmlListPropertyWrapper),
82     0,
83     Py_TPFLAGS_DEFAULT,
84     qpyqml_QQmlListPropertyWrapper_Slots
85 };
86 #else
87 // Define the sequence methods.
88 PySequenceMethods QQmlListPropertyWrapper_as_sequence = {
89     QQmlListPropertyWrapper_sq_length,
90     QQmlListPropertyWrapper_sq_concat,
91     QQmlListPropertyWrapper_sq_repeat,
92     QQmlListPropertyWrapper_sq_item,
93 #if PY_MAJOR_VERSION < 3
94     QQmlListPropertyWrapper_sq_slice,
95 #else
96     0,
97 #endif
98     QQmlListPropertyWrapper_sq_ass_item,
99 #if PY_MAJOR_VERSION < 3
100     QQmlListPropertyWrapper_sq_ass_slice,
101 #else
102     0,
103 #endif
104     QQmlListPropertyWrapper_sq_contains,
105     QQmlListPropertyWrapper_sq_inplace_concat,
106     QQmlListPropertyWrapper_sq_inplace_repeat,
107 };
108 
109 // Define the type.
110 PyTypeObject qpyqml_QQmlListPropertyWrapper_Type = {
111     PyVarObject_HEAD_INIT(NULL, 0)
112 #if PY_VERSION_HEX >= 0x02050000
113     "PyQt5.QtQml.QQmlListPropertyWrapper",  /* tp_name */
114 #else
115     const_cast<char *>("PyQt5.QtQml.QQmlListPropertyWrapper"),  /* tp_name */
116 #endif
117     sizeof (qpyqml_QQmlListPropertyWrapper),    /* tp_basicsize */
118     0,                      /* tp_itemsize */
119     QQmlListPropertyWrapper_dealloc,    /* tp_dealloc */
120     0,                      /* tp_print */
121     0,                      /* tp_getattr */
122     0,                      /* tp_setattr */
123     0,                      /* tp_compare */
124     0,                      /* tp_repr */
125     0,                      /* tp_as_number */
126     &QQmlListPropertyWrapper_as_sequence,   /* tp_as_sequence */
127     0,                      /* tp_as_mapping */
128     0,                      /* tp_hash */
129     0,                      /* tp_call */
130     0,                      /* tp_str */
131     0,                      /* tp_getattro */
132     0,                      /* tp_setattro */
133     0,                      /* tp_as_buffer */
134     Py_TPFLAGS_DEFAULT,     /* tp_flags */
135     0,                      /* tp_doc */
136     0,                      /* tp_traverse */
137     0,                      /* tp_clear */
138     0,                      /* tp_richcompare */
139     0,                      /* tp_weaklistoffset */
140     0,                      /* tp_iter */
141     0,                      /* tp_iternext */
142     0,                      /* tp_methods */
143     0,                      /* tp_members */
144     0,                      /* tp_getset */
145     0,                      /* tp_base */
146     0,                      /* tp_dict */
147     0,                      /* tp_descr_get */
148     0,                      /* tp_descr_set */
149     0,                      /* tp_dictoffset */
150     0,                      /* tp_init */
151     0,                      /* tp_alloc */
152     0,                      /* tp_new */
153     0,                      /* tp_free */
154     0,                      /* tp_is_gc */
155     0,                      /* tp_bases */
156     0,                      /* tp_mro */
157     0,                      /* tp_cache */
158     0,                      /* tp_subclasses */
159     0,                      /* tp_weaklist */
160     0,                      /* tp_del */
161     0,                      /* tp_version_tag */
162 #if PY_VERSION_HEX >= 0x03040000
163     0,                      /* tp_finalize */
164 #endif
165 };
166 #endif
167 
168 
169 // Initialise the type and return true if there was no error.
qpyqml_QQmlListPropertyWrapper_init_type()170 bool qpyqml_QQmlListPropertyWrapper_init_type()
171 {
172 #if PY_VERSION_HEX >= 0x03040000
173     qpyqml_QQmlListPropertyWrapper_TypeObject = (PyTypeObject *)PyType_FromSpec(
174             &qpyqml_QQmlListPropertyWrapper_Spec);
175 
176     return qpyqml_QQmlListPropertyWrapper_TypeObject;
177 #else
178     if (PyType_Ready(&qpyqml_QQmlListPropertyWrapper_Type) < 0)
179         return false;
180 
181     qpyqml_QQmlListPropertyWrapper_TypeObject = &qpyqml_QQmlListPropertyWrapper_Type;
182 
183     return true;
184 #endif
185 }
186 
187 
188 // Create the wrapper object.
qpyqml_QQmlListPropertyWrapper_New(QQmlListProperty<QObject> * prop,PyObject * list)189 PyObject *qpyqml_QQmlListPropertyWrapper_New(QQmlListProperty<QObject> *prop,
190         PyObject *list)
191 {
192     qpyqml_QQmlListPropertyWrapper *obj;
193 
194     obj = PyObject_New(qpyqml_QQmlListPropertyWrapper,
195             qpyqml_QQmlListPropertyWrapper_TypeObject);
196 
197     if (!obj)
198         return 0;
199 
200     obj->qml_list_property = prop;
201     obj->py_list = list;
202 
203     return (PyObject *)obj;
204 }
205 
206 
207 // The type dealloc slot.
QQmlListPropertyWrapper_dealloc(PyObject * self)208 static void QQmlListPropertyWrapper_dealloc(PyObject *self)
209 {
210     delete ((qpyqml_QQmlListPropertyWrapper *)self)->qml_list_property;
211 
212     PyObject_Del(self);
213 }
214 
215 
216 // Return the underlying list.  Return 0 and raise an exception if there wasn't
217 // one.
get_list(PyObject * self)218 static PyObject *get_list(PyObject *self)
219 {
220     PyObject *list = ((qpyqml_QQmlListPropertyWrapper *)self)->py_list;
221 
222     if (!list)
223     {
224         PyErr_SetString(PyExc_TypeError,
225                 "there is no object bound to QQmlListProperty");
226         return 0;
227     }
228 
229     // Make sure it has sequence methods.
230     if (!PySequence_Check(list))
231     {
232         PyErr_SetString(PyExc_TypeError,
233                 "object bound to QQmlListProperty is not a sequence");
234         return 0;
235     }
236 
237     return list;
238 }
239 
240 
241 // The proxy sequence methods.
242 
QQmlListPropertyWrapper_sq_length(PyObject * self)243 static Py_ssize_t QQmlListPropertyWrapper_sq_length(PyObject *self)
244 {
245     PyObject *list = get_list(self);
246 
247     if (!list)
248         return -1;
249 
250     return PySequence_Size(list);
251 }
252 
QQmlListPropertyWrapper_sq_concat(PyObject * self,PyObject * other)253 static PyObject *QQmlListPropertyWrapper_sq_concat(PyObject *self,
254         PyObject *other)
255 {
256     PyObject *list = get_list(self);
257 
258     if (!list)
259         return 0;
260 
261     return PySequence_Concat(list, other);
262 }
263 
QQmlListPropertyWrapper_sq_repeat(PyObject * self,Py_ssize_t count)264 static PyObject *QQmlListPropertyWrapper_sq_repeat(PyObject *self,
265         Py_ssize_t count)
266 {
267     PyObject *list = get_list(self);
268 
269     if (!list)
270         return 0;
271 
272     return PySequence_Repeat(list, count);
273 }
274 
QQmlListPropertyWrapper_sq_item(PyObject * self,Py_ssize_t i)275 static PyObject *QQmlListPropertyWrapper_sq_item(PyObject *self, Py_ssize_t i)
276 {
277     PyObject *list = get_list(self);
278 
279     if (!list)
280         return 0;
281 
282     return PySequence_GetItem(list, i);
283 }
284 
285 #if PY_MAJOR_VERSION < 3
QQmlListPropertyWrapper_sq_slice(PyObject * self,Py_ssize_t i1,Py_ssize_t i2)286 static PyObject *QQmlListPropertyWrapper_sq_slice(PyObject *self,
287         Py_ssize_t i1, Py_ssize_t i2)
288 {
289     PyObject *list = get_list(self);
290 
291     if (!list)
292         return 0;
293 
294     return PySequence_GetSlice(list, i1, i2);
295 }
296 #endif
297 
QQmlListPropertyWrapper_sq_ass_item(PyObject * self,Py_ssize_t i,PyObject * value)298 static int QQmlListPropertyWrapper_sq_ass_item(PyObject *self, Py_ssize_t i,
299         PyObject *value)
300 {
301     PyObject *list = get_list(self);
302 
303     if (!list)
304         return -1;
305 
306     return PySequence_SetItem(list, i, value);
307 }
308 
309 #if PY_MAJOR_VERSION < 3
QQmlListPropertyWrapper_sq_ass_slice(PyObject * self,Py_ssize_t i1,Py_ssize_t i2,PyObject * value)310 static int QQmlListPropertyWrapper_sq_ass_slice(PyObject *self, Py_ssize_t i1,
311         Py_ssize_t i2, PyObject *value)
312 {
313     PyObject *list = get_list(self);
314 
315     if (!list)
316         return -1;
317 
318     return PySequence_SetSlice(list, i1, i2, value);
319 }
320 #endif
321 
QQmlListPropertyWrapper_sq_contains(PyObject * self,PyObject * value)322 static int QQmlListPropertyWrapper_sq_contains(PyObject *self, PyObject *value)
323 {
324     PyObject *list = get_list(self);
325 
326     if (!list)
327         return -1;
328 
329     return PySequence_Contains(list, value);
330 }
331 
QQmlListPropertyWrapper_sq_inplace_concat(PyObject * self,PyObject * other)332 static PyObject *QQmlListPropertyWrapper_sq_inplace_concat(PyObject *self,
333         PyObject *other)
334 {
335     PyObject *list = get_list(self);
336 
337     if (!list)
338         return 0;
339 
340     return PySequence_InPlaceConcat(list, other);
341 }
342 
QQmlListPropertyWrapper_sq_inplace_repeat(PyObject * self,Py_ssize_t count)343 static PyObject *QQmlListPropertyWrapper_sq_inplace_repeat(PyObject *self,
344         Py_ssize_t count)
345 {
346     PyObject *list = get_list(self);
347 
348     if (!list)
349         return 0;
350 
351     return PySequence_InPlaceRepeat(list, count);
352 }
353