Protect proxy/filter models with write_lock
This commit is contained in:
parent
9862e39108
commit
de894ab4bb
|
@ -33,42 +33,47 @@ class ModelFilter(ModelProxy):
|
||||||
value: "ModelItem",
|
value: "ModelItem",
|
||||||
_changed_fields: Optional[Dict[str, Any]] = None,
|
_changed_fields: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if self.accept_source(source):
|
with self.write_lock:
|
||||||
value = self.convert_item(value)
|
if self.accept_source(source):
|
||||||
|
value = self.convert_item(value)
|
||||||
|
|
||||||
if self.accept_item(value):
|
if self.accept_item(value):
|
||||||
self.__setitem__((source.sync_id, key), value, _changed_fields)
|
self.__setitem__(
|
||||||
self.filtered_out.pop((source.sync_id, key), None)
|
(source.sync_id, key), value, _changed_fields,
|
||||||
else:
|
)
|
||||||
self.filtered_out[source.sync_id, key] = value
|
self.filtered_out.pop((source.sync_id, key), None)
|
||||||
self.pop((source.sync_id, key), None)
|
else:
|
||||||
|
self.filtered_out[source.sync_id, key] = value
|
||||||
|
self.pop((source.sync_id, key), None)
|
||||||
|
|
||||||
for callback in self.items_changed_callbacks:
|
for callback in self.items_changed_callbacks:
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
def source_item_deleted(self, source: Model, key) -> None:
|
def source_item_deleted(self, source: Model, key) -> None:
|
||||||
if self.accept_source(source):
|
with self.write_lock:
|
||||||
try:
|
if self.accept_source(source):
|
||||||
del self[source.sync_id, key]
|
try:
|
||||||
except KeyError:
|
del self[source.sync_id, key]
|
||||||
del self.filtered_out[source.sync_id, key]
|
except KeyError:
|
||||||
|
del self.filtered_out[source.sync_id, key]
|
||||||
|
|
||||||
for callback in self.items_changed_callbacks:
|
for callback in self.items_changed_callbacks:
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
def source_cleared(self, source: Model) -> None:
|
def source_cleared(self, source: Model) -> None:
|
||||||
if self.accept_source(source):
|
with self.write_lock:
|
||||||
for source_sync_id, key in self.copy():
|
if self.accept_source(source):
|
||||||
if source_sync_id == source.sync_id:
|
for source_sync_id, key in self.copy():
|
||||||
try:
|
if source_sync_id == source.sync_id:
|
||||||
del self[source.sync_id, key]
|
try:
|
||||||
except KeyError:
|
del self[source.sync_id, key]
|
||||||
del self.filtered_out[source.sync_id, key]
|
except KeyError:
|
||||||
|
del self.filtered_out[source.sync_id, key]
|
||||||
|
|
||||||
for callback in self.items_changed_callbacks:
|
for callback in self.items_changed_callbacks:
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
def refilter(
|
def refilter(
|
||||||
|
|
|
@ -188,27 +188,28 @@ class Model(MutableMapping):
|
||||||
and one `ModelItemDeleted` pyotherside event is fired per sequence.
|
and one `ModelItemDeleted` pyotherside event is fired per sequence.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
with self.write_lock:
|
||||||
self._active_batch_remove_indice = []
|
try:
|
||||||
yield None
|
self._active_batch_remove_indice = []
|
||||||
finally:
|
yield None
|
||||||
indice = self._active_batch_remove_indice
|
finally:
|
||||||
groups = [list(group) for item, group in itertools.groupby(indice)]
|
indice = self._active_batch_remove_indice
|
||||||
last = None
|
groups = [list(group) for item, group in itertools.groupby(indice)]
|
||||||
|
last = None
|
||||||
|
|
||||||
if groups:
|
if groups:
|
||||||
last = groups[-1].pop()
|
last = groups[-1].pop()
|
||||||
if not groups[-1]:
|
if not groups[-1]:
|
||||||
del groups[-1]
|
del groups[-1]
|
||||||
|
|
||||||
for grp in groups:
|
for grp in groups:
|
||||||
ModelItemDeleted(self.sync_id, index=grp[0], count=len(grp))
|
ModelItemDeleted(self.sync_id, index=grp[0], count=len(grp))
|
||||||
|
|
||||||
# Seems QML ListView has an horrible bug where removing a large
|
# Seems QML ListView has an horrible bug where removing a large
|
||||||
# amount of items at once will result in a corrupted empty display,
|
# amount of items at once will result in a corrupted empty display,
|
||||||
# this dumb workaround is the only way I've found
|
# this dumb workaround is the only way I've found
|
||||||
if last:
|
if last:
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
ModelItemDeleted(self.sync_id, index=last, count=1)
|
ModelItemDeleted(self.sync_id, index=last, count=1)
|
||||||
|
|
||||||
self._active_batch_remove_indice = None
|
self._active_batch_remove_indice = None
|
||||||
|
|
|
@ -17,10 +17,11 @@ class ModelProxy(Model):
|
||||||
self.take_items_ownership = False
|
self.take_items_ownership = False
|
||||||
Model.proxies[sync_id] = self
|
Model.proxies[sync_id] = self
|
||||||
|
|
||||||
for sync_id, model in Model.instances.items():
|
with self.write_lock:
|
||||||
if sync_id != self.sync_id and self.accept_source(model):
|
for sync_id, model in Model.instances.items():
|
||||||
for key, item in model.items():
|
if sync_id != self.sync_id and self.accept_source(model):
|
||||||
self.source_item_set(model, key, item)
|
for key, item in model.items():
|
||||||
|
self.source_item_set(model, key, item)
|
||||||
|
|
||||||
|
|
||||||
def accept_source(self, source: Model) -> bool:
|
def accept_source(self, source: Model) -> bool:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user