summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Huuhko <kai.huuhko@gmail.com>2016-02-02 20:29:21 +0200
committerKai Huuhko <kai.huuhko@gmail.com>2016-02-02 20:30:20 +0200
commit3661a78c96a6a264f131d5b9d344248180b68c6b (patch)
tree29b3c84980ae436ea98d5ec1e3c833b0cd003983
parentcaef23bb34d2183c8d9ee611a086713f084f7ed6 (diff)
Elm.MultiButtonEntry: Attempt to fix leaks, add more docs
-rw-r--r--efl/elementary/multibuttonentry.pxi150
-rw-r--r--efl/elementary/multibuttonentry_cdef.pxi4
-rw-r--r--examples/elementary/test_multibuttonentry.py46
3 files changed, 153 insertions, 47 deletions
diff --git a/efl/elementary/multibuttonentry.pxi b/efl/elementary/multibuttonentry.pxi
index aa874bc..13c28e3 100644
--- a/efl/elementary/multibuttonentry.pxi
+++ b/efl/elementary/multibuttonentry.pxi
@@ -18,24 +18,51 @@
18 18
19include "multibuttonentry_cdef.pxi" 19include "multibuttonentry_cdef.pxi"
20 20
21class MultiButtonEntryFilterOut(Exception):
22 """An exception you may raise in an item filter callback if you wish to prevent addition of the item"""
23 pass
24
21cdef Eina_Bool _multibuttonentry_filter_callback(Evas_Object *obj, \ 25cdef Eina_Bool _multibuttonentry_filter_callback(Evas_Object *obj, \
22 const char *item_label, void *item_data, void *data) with gil: 26 char *item_label, void *item_data, void *data) with gil:
23 27
24 cdef: 28 cdef:
25 MultiButtonEntry mbe = object_from_instance(obj) 29 MultiButtonEntry mbe = object_from_instance(obj)
26 bint ret 30 object ret
27 31 list callbacks = mbe._item_filters
28 (callback, a, ka) = <object>data 32
29 33 for func, args, kargs in callbacks:
30 try: 34 try:
31 ret = callback(mbe, _ctouni(item_label), *a, **ka) 35 # raise MultiButtonEntryFilterOut -> cancels item add
32 except Exception: 36 # ret is None -> no change, continue to next filter
33 traceback.print_exc() 37 # ret is not None -> change label to value of ret, continue to next filter
34 38 ret = func(mbe, _ctouni(item_label), *args, **kargs)
35 return ret 39 except MultiButtonEntryFilterOut:
40 #free(item_label) # FIXME: This will result in a double free, find out if it's bad elm documentation
41 # or wrong ref handling on our side.
42
43 #item_label = NULL
44 return 0
45 except Exception:
46 traceback.print_exc()
47 continue
48
49 if ret:
50 if not isinstance(ret, basestring):
51 EINA_LOG_DOM_WARN(PY_EFL_ELM_LOG_DOMAIN,
52 "Ignoring invalid return value from MultiButtonEntry item filter callback!", NULL)
53 continue
54 if isinstance(ret, unicode): ret = PyUnicode_AsUTF8String(ret)
55 #free(item_label) # FIXME: This will result in a double free, find out if it's bad elm documentation
56 # or wrong ref handling on our side.
57
58 item_label = strdup(ret) # Elm will manage the string
59 # FIXME: This doesn't apply, why?
60
61 return 1
36 62
37cdef char * _multibuttonentry_format_cb(int count, void *data) with gil: 63cdef char * _multibuttonentry_format_cb(int count, void *data) with gil:
38 (callback, a, ka) = <object>data 64 cdef MultiButtonEntry obj = <MultiButtonEntry>data
65 (callback, a, ka) = obj.internal_data["multibuttonentry_format_cb"]
39 66
40 try: 67 try:
41 s = callback(count, *a, **ka) 68 s = callback(count, *a, **ka)
@@ -44,8 +71,7 @@ cdef char * _multibuttonentry_format_cb(int count, void *data) with gil:
44 traceback.print_exc() 71 traceback.print_exc()
45 return NULL 72 return NULL
46 73
47 # FIXME: leak here 74 return strdup(s) # Elm will manage the string
48 return strdup(<char *>s)
49 75
50 76
51cdef class MultiButtonEntryItem(ObjectItem): 77cdef class MultiButtonEntryItem(ObjectItem):
@@ -198,6 +224,8 @@ cdef class MultiButtonEntry(Object):
198 224
199 """ 225 """
200 226
227 cdef list _item_filters
228
201 def __init__(self, evasObject parent, *args, **kwargs): 229 def __init__(self, evasObject parent, *args, **kwargs):
202 """MultiButtonEntry(...) 230 """MultiButtonEntry(...)
203 231
@@ -213,6 +241,7 @@ cdef class MultiButtonEntry(Object):
213 _py_elm_mbe_item_added_cb, NULL 241 _py_elm_mbe_item_added_cb, NULL
214 ) 242 )
215 self._set_properties_from_keyword_args(kwargs) 243 self._set_properties_from_keyword_args(kwargs)
244 self._item_filters = list()
216 245
217 property entry: 246 property entry:
218 """The Entry object child of the multibuttonentry. 247 """The Entry object child of the multibuttonentry.
@@ -227,7 +256,10 @@ cdef class MultiButtonEntry(Object):
227 return object_from_instance(elm_multibuttonentry_entry_get(self.obj)) 256 return object_from_instance(elm_multibuttonentry_entry_get(self.obj))
228 257
229 property expanded: 258 property expanded:
230 """The expanded state of the multibuttonentry. 259 """Control the multibuttonentry to expanded state.
260
261 In expanded state, the complete entry will be displayed.
262 Otherwise, only single line of the entry will be displayed.
231 263
232 :type: bool 264 :type: bool
233 265
@@ -342,6 +374,11 @@ cdef class MultiButtonEntry(Object):
342 return None 374 return None
343 375
344 property items: 376 property items:
377 """List of items in the multibuttonentry
378
379 :type: list
380
381 """
345 def __get__(self): 382 def __get__(self):
346 return _object_item_list_to_python(elm_multibuttonentry_items_get(self.obj)) 383 return _object_item_list_to_python(elm_multibuttonentry_items_get(self.obj))
347 384
@@ -349,6 +386,11 @@ cdef class MultiButtonEntry(Object):
349 return _object_item_list_to_python(elm_multibuttonentry_items_get(self.obj)) 386 return _object_item_list_to_python(elm_multibuttonentry_items_get(self.obj))
350 387
351 property first_item: 388 property first_item:
389 """The first item in the multibuttonentry
390
391 :type: :class:`MultiButtonEntryItem`
392
393 """
352 def __get__(self): 394 def __get__(self):
353 return _object_item_to_python(elm_multibuttonentry_first_item_get(self.obj)) 395 return _object_item_to_python(elm_multibuttonentry_first_item_get(self.obj))
354 396
@@ -356,6 +398,11 @@ cdef class MultiButtonEntry(Object):
356 return _object_item_to_python(elm_multibuttonentry_first_item_get(self.obj)) 398 return _object_item_to_python(elm_multibuttonentry_first_item_get(self.obj))
357 399
358 property last_item: 400 property last_item:
401 """The last item in the multibuttonentry
402
403 :type: :class:`MultiButtonEntryItem`
404
405 """
359 def __get__(self): 406 def __get__(self):
360 return _object_item_to_python(elm_multibuttonentry_last_item_get(self.obj)) 407 return _object_item_to_python(elm_multibuttonentry_last_item_get(self.obj))
361 408
@@ -363,6 +410,11 @@ cdef class MultiButtonEntry(Object):
363 return _object_item_to_python(elm_multibuttonentry_last_item_get(self.obj)) 410 return _object_item_to_python(elm_multibuttonentry_last_item_get(self.obj))
364 411
365 property selected_item: 412 property selected_item:
413 """The selected item in the multibuttonentry
414
415 :type: :class:`MultiButtonEntryItem`
416
417 """
366 def __get__(self): 418 def __get__(self):
367 return _object_item_to_python(elm_multibuttonentry_selected_item_get(self.obj)) 419 return _object_item_to_python(elm_multibuttonentry_selected_item_get(self.obj))
368 420
@@ -370,29 +422,66 @@ cdef class MultiButtonEntry(Object):
370 return _object_item_to_python(elm_multibuttonentry_selected_item_get(self.obj)) 422 return _object_item_to_python(elm_multibuttonentry_selected_item_get(self.obj))
371 423
372 def clear(self): 424 def clear(self):
425 """Remove all items in the multibuttonentry"""
373 elm_multibuttonentry_clear(self.obj) 426 elm_multibuttonentry_clear(self.obj)
374 427
375 def filter_append(self, func, *args, **kwargs): 428 def filter_append(self, func, *args, **kwargs):
376 cbdata = (func, args, kwargs) 429 """Append an item filter function for text inserted in the Multibuttonentry
430
431 Append the given callback to the list. This function will be called
432 whenever any text is inserted into the Multibuttonentry, with the text to be inserted
433 as a parameter. The callback function is free to alter the text in any way
434 it wants with the modified text passed back as return value.
435 If the new text is to be left intact, the function can return ``None``.
436 If the new text is to be discarded, the function must raise
437 :class:`MultiButtonEntryFilterOut`.
438 This will also prevent any following filters from being called.
377 439
378 elm_multibuttonentry_item_filter_append(self.obj, 440 Callback signature::
379 _multibuttonentry_filter_callback, <void *>cbdata)
380 441
381 # FIXME: leak here 442 func(obj, text, *args, **kwargs) -> modified text or None
382 Py_INCREF(cbdata) 443
444 """
445 if not self._item_filters:
446 elm_multibuttonentry_item_filter_append(
447 self.obj,
448 _multibuttonentry_filter_callback,
449 NULL)
450
451 cbdata = (func, args, kwargs)
452 self._item_filters.append(cbdata)
383 453
384 def filter_prepend(self, func, *args, **kwargs): 454 def filter_prepend(self, func, *args, **kwargs):
455 """Prepend a filter function for text inserted in the Multibuttonentry
456
457 Prepend the given callback to the list. See :meth:`filter_append`
458 for more information
459
460 """
461 if not self._item_filters:
462 elm_multibuttonentry_item_filter_append(
463 self.obj,
464 _multibuttonentry_filter_callback,
465 NULL)
466
385 cbdata = (func, args, kwargs) 467 cbdata = (func, args, kwargs)
468 self._item_filters[0] = cbdata
386 469
387 elm_multibuttonentry_item_filter_prepend(self.obj, 470 def filter_remove(self, func, *args, **kwargs):
388 _multibuttonentry_filter_callback, <void *>cbdata) 471 """Remove a filter from the list
389 472
390 # FIXME: leak here 473 Removes the given callback from the filter list. See :meth:`filter_append`
391 Py_INCREF(cbdata) 474 for more information.
392 475
393 #TODO 476 """
394 #def filter_remove(self, func, *args, **kwargs): 477 cbdata = (func, args, kwargs)
395 #pass 478 self._item_filters.remove(cbdata)
479
480 if not self._item_filters:
481 elm_multibuttonentry_item_filter_remove(
482 self.obj,
483 _multibuttonentry_filter_callback,
484 NULL)
396 485
397 property editable: 486 property editable:
398 """Whether the multibuttonentry is to be editable or not. 487 """Whether the multibuttonentry is to be editable or not.
@@ -428,15 +517,16 @@ cdef class MultiButtonEntry(Object):
428 517
429 """ 518 """
430 if func is None: 519 if func is None:
520 self.internal_data["multibuttonentry_format_cb"] = None
431 elm_multibuttonentry_format_function_set(self.obj, NULL, NULL) 521 elm_multibuttonentry_format_function_set(self.obj, NULL, NULL)
432 return 522 return
433 523
434 cbdata = (func, args, kwargs) 524 cbdata = (func, args, kwargs)
525 self.internal_data["multibuttonentry_format_cb"] = cbdata
526
435 elm_multibuttonentry_format_function_set(self.obj, 527 elm_multibuttonentry_format_function_set(self.obj,
436 _multibuttonentry_format_cb, 528 _multibuttonentry_format_cb,
437 <void *>cbdata) 529 <void *>self)
438 # FIXME: leak here
439 Py_INCREF(cbdata)
440 530
441 def callback_item_selected_add(self, func, *args, **kwargs): 531 def callback_item_selected_add(self, func, *args, **kwargs):
442 self._callback_add_full("item,selected", _cb_object_item_conv, func, args, kwargs) 532 self._callback_add_full("item,selected", _cb_object_item_conv, func, args, kwargs)
diff --git a/efl/elementary/multibuttonentry_cdef.pxi b/efl/elementary/multibuttonentry_cdef.pxi
index 1168b48..5b2aa34 100644
--- a/efl/elementary/multibuttonentry_cdef.pxi
+++ b/efl/elementary/multibuttonentry_cdef.pxi
@@ -1,6 +1,6 @@
1cdef extern from "Elementary.h": 1cdef extern from "Elementary.h":
2 2
3 ctypedef Eina_Bool (*Elm_Multibuttonentry_Item_Filter_Cb)(Evas_Object *obj, const char *item_label, void *item_data, void *data) 3 ctypedef Eina_Bool (*Elm_Multibuttonentry_Item_Filter_Cb)(Evas_Object *obj, char *item_label, void *item_data, void *data)
4 ctypedef char * (*Elm_Multibuttonentry_Format_Cb)(int count, void *data) 4 ctypedef char * (*Elm_Multibuttonentry_Format_Cb)(int count, void *data)
5 5
6 Evas_Object *elm_multibuttonentry_add(Evas_Object *parent) 6 Evas_Object *elm_multibuttonentry_add(Evas_Object *parent)
@@ -22,7 +22,7 @@ cdef extern from "Elementary.h":
22 Elm_Object_Item *elm_multibuttonentry_item_next_get(const Elm_Object_Item *it) 22 Elm_Object_Item *elm_multibuttonentry_item_next_get(const Elm_Object_Item *it)
23 void elm_multibuttonentry_item_filter_append(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data) 23 void elm_multibuttonentry_item_filter_append(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data)
24 void elm_multibuttonentry_item_filter_prepend(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data) 24 void elm_multibuttonentry_item_filter_prepend(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data)
25 # TODO: void elm_multibuttonentry_item_filter_remove(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data) 25 void elm_multibuttonentry_item_filter_remove(Evas_Object *obj, Elm_Multibuttonentry_Item_Filter_Cb func, void *data)
26 void elm_multibuttonentry_editable_set(Evas_Object *obj, Eina_Bool editable) 26 void elm_multibuttonentry_editable_set(Evas_Object *obj, Eina_Bool editable)
27 Eina_Bool elm_multibuttonentry_editable_get(const Evas_Object *obj) 27 Eina_Bool elm_multibuttonentry_editable_get(const Evas_Object *obj)
28 void elm_multibuttonentry_format_function_set(Evas_Object *obj, Elm_Multibuttonentry_Format_Cb f_func, const void *data) 28 void elm_multibuttonentry_format_function_set(Evas_Object *obj, Elm_Multibuttonentry_Format_Cb f_func, const void *data)
diff --git a/examples/elementary/test_multibuttonentry.py b/examples/elementary/test_multibuttonentry.py
index b8ad5b6..989598f 100644
--- a/examples/elementary/test_multibuttonentry.py
+++ b/examples/elementary/test_multibuttonentry.py
@@ -1,16 +1,13 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2# encoding: utf-8 2# encoding: utf-8
3 3
4from efl.evas import EVAS_HINT_EXPAND, EVAS_HINT_FILL, \ 4from efl.evas import EXPAND_BOTH, FILL_BOTH, EXPAND_HORIZ, FILL_HORIZ
5 EXPAND_BOTH, FILL_BOTH, EXPAND_HORIZ, FILL_HORIZ
6from efl import elementary 5from efl import elementary
7from efl.elementary.window import StandardWindow 6from efl.elementary import StandardWindow
8from efl.elementary.box import Box 7from efl.elementary import Box
9from efl.elementary.button import Button 8from efl.elementary import Button
10from efl.elementary.entry import Entry 9from efl.elementary import MultiButtonEntry, MultiButtonEntryFilterOut
11from efl.elementary.multibuttonentry import MultiButtonEntry 10from efl.elementary import Scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO
12from efl.elementary.scroller import Scroller, ELM_SCROLLER_POLICY_OFF, \
13 ELM_SCROLLER_POLICY_AUTO
14 11
15SCROLL_POLICY_VERT = ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO 12SCROLL_POLICY_VERT = ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO
16 13
@@ -30,27 +27,27 @@ def cb_btn_item_prepend(btn, mbe):
30 global counter 27 global counter
31 28
32 counter += 1 29 counter += 1
33 item = mbe.item_prepend("item #%d" % (counter), cb_item_selected) 30 mbe.item_prepend("item #%d" % (counter), cb_item_selected)
34 31
35def cb_btn_item_append(btn, mbe): 32def cb_btn_item_append(btn, mbe):
36 global counter 33 global counter
37 34
38 counter += 1 35 counter += 1
39 item = mbe.item_append("item #%d" % (counter), cb_item_selected) 36 mbe.item_append("item #%d" % (counter), cb_item_selected)
40 37
41def cb_btn_item_insert_after(btn, mbe): 38def cb_btn_item_insert_after(btn, mbe):
42 global counter 39 global counter
43 40
44 counter += 1 41 counter += 1
45 after = mbe.selected_item 42 after = mbe.selected_item
46 item = mbe.item_insert_after(after, "item #%d" % (counter), cb_item_selected) 43 mbe.item_insert_after(after, "item #%d" % (counter), cb_item_selected)
47 44
48def cb_btn_item_insert_before(btn, mbe): 45def cb_btn_item_insert_before(btn, mbe):
49 global counter 46 global counter
50 47
51 counter += 1 48 counter += 1
52 before = mbe.selected_item 49 before = mbe.selected_item
53 item = mbe.item_insert_before(before, "item #%d" % (counter), cb_item_selected) 50 mbe.item_insert_before(before, "item #%d" % (counter), cb_item_selected)
54 51
55def cb_btn_clear2(btn, mbe): 52def cb_btn_clear2(btn, mbe):
56 for item in mbe.items: 53 for item in mbe.items:
@@ -58,7 +55,13 @@ def cb_btn_clear2(btn, mbe):
58 55
59def cb_filter1(mbe, text): 56def cb_filter1(mbe, text):
60 print(text) 57 print(text)
61 return True 58
59def cb_filter2(mbe, text):
60 return text[:-2]
61
62def cb_filter3(mbe, text):
63 print(text)
64 #raise MultiButtonEntryFilterOut
62 65
63def cb_print(btn, mbe): 66def cb_print(btn, mbe):
64 for i in mbe.items: 67 for i in mbe.items:
@@ -85,6 +88,8 @@ def multibuttonentry_clicked(obj, item=None):
85 mbe.callback_item_longpressed_add(cb_item_longpressed) 88 mbe.callback_item_longpressed_add(cb_item_longpressed)
86 mbe.part_text_set("guide", "Tap to add recipient") 89 mbe.part_text_set("guide", "Tap to add recipient")
87 mbe.filter_append(cb_filter1) 90 mbe.filter_append(cb_filter1)
91 mbe.filter_append(cb_filter2)
92 mbe.filter_append(cb_filter3)
88 mbe.show() 93 mbe.show()
89 94
90 sc = Scroller(win, bounce=(False, True), policy=SCROLL_POLICY_VERT, 95 sc = Scroller(win, bounce=(False, True), policy=SCROLL_POLICY_VERT,
@@ -181,7 +186,18 @@ def multibuttonentry_clicked(obj, item=None):
181 186
182if __name__ == "__main__": 187if __name__ == "__main__":
183 188
189 import logging
190 elog = logging.getLogger("efl")
191 elog.setLevel(logging.INFO)
192
193 elog_form = logging.Formatter(
194 "[%(name)s] %(levelname)s in %(funcName)s:%(lineno)d - %(message)s"
195 )
196 elog_hdlr = logging.StreamHandler()
197 elog_hdlr.setFormatter(elog_form)
198
199 elog.addHandler(elog_hdlr)
200
184 multibuttonentry_clicked(None) 201 multibuttonentry_clicked(None)
185 202
186 elementary.run() 203 elementary.run()
187