Use a Deque for roomEvents's ListModel

- Take a custom container callable for ListModel __init__ (defaults to
  list, must be a MutableSequence)

- Use a Deque for roomEvents, which is much faster for inserting
  new items at the beginning.
This commit is contained in:
miruka 2019-04-17 17:07:20 -04:00
parent f0dab1801a
commit 9e5e2c6718
4 changed files with 31 additions and 28 deletions

View File

@ -1,6 +1,7 @@
import logging import logging
from typing import ( from typing import (
Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union Any, Callable, Dict, Iterable, List, Mapping, MutableSequence, Optional,
Sequence, Tuple, Union
) )
from namedlist import namedlist from namedlist import namedlist
@ -17,23 +18,24 @@ class ListModel(QAbstractListModel):
changed = pyqtSignal() changed = pyqtSignal()
def __init__(self, def __init__(self,
initial_data: Optional[List[NewValue]] = None, initial_data: Optional[List[NewValue]] = None,
parent: Optional[QObject] = None) -> None: container: Callable[..., MutableSequence] = list,
parent: Optional[QObject] = None) -> None:
super().__init__(parent) super().__init__(parent)
self._ref_namedlist = None self._ref_namedlist = None
self._roles: Tuple[str, ...] = () self._roles: Tuple[str, ...] = ()
self._list: list = [] self._data: MutableSequence = container()
if initial_data: if initial_data:
self.extend(initial_data) self.extend(initial_data)
def __repr__(self) -> str: def __repr__(self) -> str:
return "%s[%s]" % (type(self).__name__, return "%s(%r)" % (type(self).__name__, self._data)
", ".join((repr(i) for i in self)))
def __getitem__(self, index): def __getitem__(self, index):
return self._list[index] return self._data[index]
def __setitem__(self, index, value) -> None: def __setitem__(self, index, value) -> None:
@ -57,11 +59,11 @@ class ListModel(QAbstractListModel):
if role <= Qt.UserRole: if role <= Qt.UserRole:
return None return None
return self._list[index.row()][role - Qt.UserRole - 1] return self._data[index.row()][role - Qt.UserRole - 1]
def rowCount(self, _: QModelIndex = QModelIndex()) -> int: def rowCount(self, _: QModelIndex = QModelIndex()) -> int:
return len(self._list) return len(self._data)
def _convert_new_value(self, value: NewValue) -> Any: def _convert_new_value(self, value: NewValue) -> Any:
@ -98,12 +100,12 @@ class ListModel(QAbstractListModel):
@pyqtSlot(int, result="QVariantMap") @pyqtSlot(int, result="QVariantMap")
def get(self, index: int) -> ReturnItem: def get(self, index: int) -> ReturnItem:
return self._list[index]._asdict() return self._data[index]._asdict()
@pyqtSlot(str, "QVariant", result=int) @pyqtSlot(str, "QVariant", result=int)
def indexWhere(self, prop: str, is_value: Any) -> int: def indexWhere(self, prop: str, is_value: Any) -> int:
for i, item in enumerate(self._list): for i, item in enumerate(self._data):
if getattr(item, prop) == is_value: if getattr(item, prop) == is_value:
return i return i
@ -120,7 +122,7 @@ class ListModel(QAbstractListModel):
def insert(self, index: int, value: NewValue) -> None: def insert(self, index: int, value: NewValue) -> None:
value = self._convert_new_value(value) value = self._convert_new_value(value)
self.beginInsertRows(QModelIndex(), index, index) self.beginInsertRows(QModelIndex(), index, index)
self._list.insert(index, value) self._data.insert(index, value)
self.endInsertRows() self.endInsertRows()
self.changed.emit() self.changed.emit()
@ -140,14 +142,14 @@ class ListModel(QAbstractListModel):
def set(self, index: int, value: NewValue) -> None: def set(self, index: int, value: NewValue) -> None:
qidx = QAbstractListModel.index(self, index, 0) qidx = QAbstractListModel.index(self, index, 0)
value = self._convert_new_value(value) value = self._convert_new_value(value)
self._list[index] = value self._data[index] = value
self.dataChanged.emit(qidx, qidx, self.roleNames()) self.dataChanged.emit(qidx, qidx, self.roleNames())
self.changed.emit() self.changed.emit()
@pyqtSlot(int, str, "QVariant") @pyqtSlot(int, str, "QVariant")
def setProperty(self, index: int, prop: str, value: Any) -> None: def setProperty(self, index: int, prop: str, value: Any) -> None:
self._list[index][self._roles.index(prop)] = value self._data[index][self._roles.index(prop)] = value
qidx = QAbstractListModel.index(self, index, 0) qidx = QAbstractListModel.index(self, index, 0)
self.dataChanged.emit(qidx, qidx, self.roleNames()) self.dataChanged.emit(qidx, qidx, self.roleNames())
self.changed.emit() self.changed.emit()
@ -175,9 +177,9 @@ class ListModel(QAbstractListModel):
return return
last = from_ + n last = from_ + n
cut = self._list[from_:last] cut = self._data[from_:last]
del self._list[from_:last] del self._data[from_:last]
self._list[to:to] = cut self._data[to:to] = cut
self.endMoveRows() self.endMoveRows()
self.changed.emit() self.changed.emit()
@ -186,7 +188,7 @@ class ListModel(QAbstractListModel):
@pyqtSlot(int) @pyqtSlot(int)
def remove(self, index: int) -> None: # pylint: disable=arguments-differ def remove(self, index: int) -> None: # pylint: disable=arguments-differ
self.beginRemoveRows(QModelIndex(), index, index) self.beginRemoveRows(QModelIndex(), index, index)
del self._list[index] del self._data[index]
self.endRemoveRows() self.endRemoveRows()
self.changed.emit() self.changed.emit()
@ -195,6 +197,6 @@ class ListModel(QAbstractListModel):
def clear(self) -> None: def clear(self) -> None:
# Reimplemented for performance reasons (begin/endRemoveRows) # Reimplemented for performance reasons (begin/endRemoveRows)
self.beginRemoveRows(QModelIndex(), 0, self.rowCount()) self.beginRemoveRows(QModelIndex(), 0, self.rowCount())
self._list.clear() self._data.clear()
self.endRemoveRows() self.endRemoveRows()
self.changed.emit() self.changed.emit()

View File

@ -1,4 +1,4 @@
from typing import Any, DefaultDict from typing import Any, Callable, DefaultDict, MutableSequence
from PyQt5.QtCore import QObject, pyqtSlot from PyQt5.QtCore import QObject, pyqtSlot
@ -6,12 +6,14 @@ from .list_model import ListModel
class ListModelMap(QObject): class ListModelMap(QObject):
def __init__(self) -> None: def __init__(self, models_container: Callable[..., MutableSequence] = list
) -> None:
super().__init__() super().__init__()
# Set the parent to prevent item garbage-collection on the C++ side # Set the parent to prevent item garbage-collection on the C++ side
self.dict: DefaultDict[Any, ListModel] = \ self.dict: DefaultDict[Any, ListModel] = \
DefaultDict(lambda: ListModel(parent=self)) DefaultDict(lambda: ListModel(parent = self,
container = models_container))
@pyqtSlot(str, result="QVariant") @pyqtSlot(str, result="QVariant")

View File

@ -1,6 +1,8 @@
# Copyright 2019 miruka # Copyright 2019 miruka
# This file is part of harmonyqml, licensed under GPLv3. # This file is part of harmonyqml, licensed under GPLv3.
from typing import Deque
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
from .list_model import ListModel from .list_model import ListModel
@ -15,7 +17,7 @@ class QMLModels(QObject):
super().__init__() super().__init__()
self._accounts: ListModel = ListModel() self._accounts: ListModel = ListModel()
self._rooms: ListModelMap = ListModelMap() self._rooms: ListModelMap = ListModelMap()
self._room_events: ListModelMap = ListModelMap() self._room_events: ListModelMap = ListModelMap(models_container=Deque)
@pyqtProperty(ListModel, constant=True) @pyqtProperty(ListModel, constant=True)

View File

@ -7,7 +7,6 @@ Column {
id: "rootCol" id: "rootCol"
function mins_between(date1, date2) { function mins_between(date1, date2) {
console.log(Math.round((((date2 - date1) % 86400000) % 3600000) / 60000))
return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000) return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000)
} }
@ -59,8 +58,6 @@ Column {
combine ? standardSpacing / 4 : combine ? standardSpacing / 4 :
standardSpacing standardSpacing
//Text { text: rootCol.topPadding }
Daybreak { visible: dayBreak } Daybreak { visible: dayBreak }
MessageContent { visible: isMessage } MessageContent { visible: isMessage }