Last active
December 20, 2015 01:49
-
-
Save geojeff/6052347 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
in properties.pxd: | |
cdef class RecordingListProperty(Property): | |
cdef int op_started | |
cdef object op_info | |
cdef int sort_started | |
cdef list sort_largs | |
cdef list sort_kwds | |
cdef str sort_op | |
cdef list presort_indices | |
cdef list presort_items | |
class RecordingObservableList(list): | |
# Adds range-observing and other intelligence to a Python list, passing | |
# op_info for use by an observer. | |
def __init__(self, *largs): | |
self.prop = largs[0] | |
self.obj = ref(largs[1]) | |
super(RecordingObservableList, self).__init__(*largs[2:]) | |
# TODO: setitem and delitem are supposed to handle slices, instead of the | |
# deprecated setslice() and delslice() methods. | |
def __setitem__(self, key, value): | |
cdef Property prop = self.prop | |
self.prop.start_op() | |
list.__setitem__(self, key, value) | |
self.prop.record_op_info(('ROL_setitem', (key, key))) | |
observable_list_dispatch(self) | |
self.prop.stop_op() | |
def __delitem__(self, key): | |
cdef Property prop = self.prop | |
prop.start_op() | |
list.__delitem__(self, key) | |
prop.record_op_info(('ROL_delitem', (key, key))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def __setslice__(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
# | |
# Python docs: | |
# | |
# operator.__setslice__(a, b, c, v) | |
# | |
# Set the slice of a from index b to index c-1 to the sequence v. | |
# | |
# Deprecated since version 2.6: This function is removed in Python | |
# 3.x. Use setitem() with a slice index. | |
# | |
start_index = largs[0] | |
end_index = largs[1] - 1 | |
list.__setslice__(self, *largs) | |
prop.record_op_info(('ROL_setslice', (start_index, end_index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def __delslice__(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
# Delete the slice of a from index b to index c-1. del a[b:c], | |
# where the args here are b and c. | |
# Also deprecated. | |
start_index = largs[0] | |
end_index = largs[1] - 1 | |
list.__delslice__(self, *largs) | |
prop.record_op_info(('ROL_delslice', (start_index, end_index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def __iadd__(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
start_index = len(self) | |
end_index = start_index + len(largs) - 1 | |
list.__iadd__(self, *largs) | |
prop.record_op_info(('ROL_iadd', (start_index, end_index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def __imul__(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
num = largs[0] | |
start_index = len(self) | |
end_index = start_index + (len(self) * num) | |
list.__imul__(self, *largs) | |
prop.record_op_info(('ROL_imul', (start_index, end_index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def append(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
index = len(self) | |
list.append(self, *largs) | |
prop.record_op_info(('ROL_append', (index, index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def remove(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
index = self.index(largs[0]) | |
list.remove(self, *largs) | |
prop.record_op_info(('ROL_remove', (index, index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def insert(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
index = largs[0] | |
list.insert(self, *largs) | |
prop.record_op_info(('ROL_insert', (index, index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def pop(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
if largs: | |
index = largs[0] | |
else: | |
index = len(self) - 1 | |
cdef object result = list.pop(self, *largs) | |
prop.record_op_info(('ROL_pop', (index, index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
return result | |
def extend(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_op() | |
start_index = len(self) | |
end_index = start_index + len(largs[0]) - 1 | |
list.extend(self, *largs) | |
prop.record_op_info(('ROL_extend', (start_index, end_index))) | |
observable_list_dispatch(self) | |
prop.stop_op() | |
def start_sort_op(self, op, *largs, **kwds): | |
cdef Property prop = self.prop | |
prop.start_op() | |
prop.sort_largs = largs | |
prop.sort_kwds = kwds | |
prop.sort_op = op | |
# Trigger the "sort is starting" callback to the adapter, so it can do | |
# pre-sort writing of the current arrangement of indices and data. | |
prop.start_sort_op() | |
prop.stop_op() | |
def finish_sort_op(self): | |
cdef Property prop = self.prop | |
prop.start_op() | |
largs = prop.sort_largs | |
kwds = prop.sort_kwds | |
sort_op = prop.sort_op | |
# Perform the sort. | |
if sort_op == 'ROL_sort': | |
list.sort(self, *largs, **kwds) | |
else: | |
list.reverse(self, *largs) | |
# Finalize. Will go back to adapter for handling cached_views, | |
# selection, and prep for triggering data_changed on ListView. | |
prop.record_op_info((sort_op, (0, len(self) - 1))) | |
prop.stop_op() | |
prop.stop_sort_op() | |
def sort(self, *largs, **kwds): | |
cdef Property prop = self.prop | |
prop.start_sort_op('ROL_sort', *largs, **kwds) | |
def reverse(self, *largs): | |
cdef Property prop = self.prop | |
prop.start_sort_op('ROL_reverse', *largs) | |
cdef class RecordingListProperty(Property): | |
'''Property that represents a list, adding granular dispatching per op. | |
Only lists are allowed. Tuple or any other classes are forbidden. | |
''' | |
def __cinit__(self): | |
self.op_started = 0 | |
self.op_info = None | |
self.sort_started = False | |
self.sort_largs = [] | |
self.sort_kwds = [] | |
self.sort_op = '' | |
# This association has keys as the indices of the owner's | |
# cached_views and the owner's data items, for use in post-sort | |
# widget reordering. It is set by the owner when needed. It is | |
# cleared by the owner at the end of its sort op callback. | |
self.presort_indices = [] | |
self.presort_items = [] | |
def __init__(self, defaultvalue=None, **kw): | |
defaultvalue = defaultvalue or [] | |
self.op_started = 0 | |
self.op_info = None | |
self.sort_started = False | |
self.sort_largs = [] | |
self.sort_kwds = [] | |
self.sort_op = '' | |
super(RecordingListProperty, self).__init__(defaultvalue, **kw) | |
cpdef link(self, EventDispatcher obj, str name): | |
Property.link(self, obj, name) | |
cdef PropertyStorage ps = obj.__storage[self._name] | |
ps.value = RecordingObservableList(self, obj, ps.value) | |
cdef check(self, EventDispatcher obj, value): | |
if Property.check(self, obj, value): | |
return True | |
if type(value) is not RecordingObservableList: | |
raise ValueError('{}.{} accept only {}'.format( | |
obj.__class__.__name__, | |
self.name, | |
RecordingObservableList.__name__)) | |
cpdef set(self, EventDispatcher obj, value): | |
value = RecordingObservableList(self, obj, value) | |
Property.set(self, obj, value) | |
def record_op_info(self, op_info): | |
self.op_info = op_info | |
def start_op(self): | |
print dir(self) | |
self.op_started = True | |
def stop_op(self): | |
self.op_started = False | |
def start_sort_op(self): | |
self.sort_started = True | |
def stop_sort_op(self): | |
self.sort_started = False | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment