Addon Manager: Worker refactor (round 1)

This commit is contained in:
Chris Hennes
2022-08-02 12:44:07 -05:00
parent 71dc5ead2f
commit 2e51954b2b
16 changed files with 2145 additions and 1814 deletions

View File

@@ -44,13 +44,15 @@ translate = FreeCAD.Qt.translate
class ListDisplayStyle(IntEnum):
""" The display mode of the list """
"""The display mode of the list"""
COMPACT = 0
EXPANDED = 1
class StatusFilter(IntEnum):
""" Predefined filers """
"""Predefined filers"""
ANY = 0
INSTALLED = 1
NOT_INSTALLED = 2
@@ -97,7 +99,7 @@ class PackageList(QWidget):
self.item_model = None
def setModel(self, model):
""" This is a model-view-controller widget: set its model. """
"""This is a model-view-controller widget: set its model."""
self.item_model = model
self.item_filter.setSourceModel(self.item_model)
self.item_filter.sort(0)
@@ -117,8 +119,8 @@ class PackageList(QWidget):
)
def on_listPackages_clicked(self, index: QModelIndex):
""" Determine what addon was selected and emit the itemSelected signal with it as
an argument. """
"""Determine what addon was selected and emit the itemSelected signal with it as
an argument."""
source_selection = self.item_filter.mapToSource(index)
selected_repo = self.item_model.repos[source_selection.row()]
self.itemSelected.emit(selected_repo)
@@ -176,7 +178,7 @@ class PackageList(QWidget):
self.item_filter.setFilterRegExp(text_filter)
def set_view_style(self, style: ListDisplayStyle) -> None:
""" Set the style (compact or expanded) of the list """
"""Set the style (compact or expanded) of the list"""
self.item_model.layoutAboutToBeChanged.emit()
self.item_delegate.set_view(style)
if style == ListDisplayStyle.COMPACT:
@@ -190,7 +192,7 @@ class PackageList(QWidget):
class PackageListItemModel(QAbstractListModel):
""" The model for use with the PackageList class. """
"""The model for use with the PackageList class."""
repos = []
write_lock = threading.Lock()
@@ -200,19 +202,19 @@ class PackageListItemModel(QAbstractListModel):
IconUpdateRole = Qt.UserRole + 2
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
""" The number of rows """
"""The number of rows"""
if parent.isValid():
return 0
return len(self.repos)
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
""" Only one column, always returns 1. """
"""Only one column, always returns 1."""
if parent.isValid():
return 0
return 1
def data(self, index: QModelIndex, role: int = Qt.DisplayRole):
""" Get the data for a given index and role. """
"""Get the data for a given index and role."""
if not index.isValid():
return None
row = index.row()
@@ -235,7 +237,7 @@ class PackageListItemModel(QAbstractListModel):
return self.repos[row]
def headerData(self, _unused1, _unused2, _role=Qt.DisplayRole):
""" No header in this implementation: always returns None. """
"""No header in this implementation: always returns None."""
return None
def setData(self, index: QModelIndex, value, role=Qt.EditRole) -> None:
@@ -259,7 +261,7 @@ class PackageListItemModel(QAbstractListModel):
)
def append_item(self, repo: Addon) -> None:
""" Adds this addon to the end of the model. Thread safe. """
"""Adds this addon to the end of the model. Thread safe."""
if repo in self.repos:
# Cowardly refuse to insert the same repo a second time
return
@@ -269,7 +271,7 @@ class PackageListItemModel(QAbstractListModel):
self.endInsertRows()
def clear(self) -> None:
""" Clear the model, removing all rows. Thread safe. """
"""Clear the model, removing all rows. Thread safe."""
if self.rowCount() > 0:
with self.write_lock:
self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1)
@@ -277,7 +279,7 @@ class PackageListItemModel(QAbstractListModel):
self.endRemoveRows()
def update_item_status(self, name: str, status: Addon.Status) -> None:
""" Set the status of addon with name to status. """
"""Set the status of addon with name to status."""
for row, item in enumerate(self.repos):
if item.name == name:
self.setData(
@@ -286,7 +288,7 @@ class PackageListItemModel(QAbstractListModel):
return
def update_item_icon(self, name: str, icon: QIcon) -> None:
""" Set the icon for Addon with name to icon """
"""Set the icon for Addon with name to icon"""
for row, item in enumerate(self.repos):
if item.name == name:
self.setData(
@@ -295,7 +297,7 @@ class PackageListItemModel(QAbstractListModel):
return
def reload_item(self, repo: Addon) -> None:
""" Sets the addon data for the given addon (based on its name) """
"""Sets the addon data for the given addon (based on its name)"""
for index, item in enumerate(self.repos):
if item.name == repo.name:
with self.write_lock:
@@ -336,17 +338,17 @@ class PackageListItemDelegate(QStyledItemDelegate):
self.widget = self.expanded
def set_view(self, style: ListDisplayStyle) -> None:
""" Set the view of to style """
"""Set the view of to style"""
if not self.displayStyle == style:
self.displayStyle = style
def sizeHint(self, _option, index):
""" Attempt to figure out the correct height for the widget based on its current contents. """
"""Attempt to figure out the correct height for the widget based on its current contents."""
self.update_content(index)
return self.widget.sizeHint()
def update_content(self, index):
""" Creates the display of the content for a given index. """
"""Creates the display of the content for a given index."""
repo = index.data(PackageListItemModel.DataAccessRole)
if self.displayStyle == ListDisplayStyle.EXPANDED:
self.widget = self.expanded
@@ -381,8 +383,8 @@ class PackageListItemDelegate(QStyledItemDelegate):
self.widget.adjustSize()
def _setup_expanded_package (self, repo:Addon):
""" Set up the display for a package in expanded view """
def _setup_expanded_package(self, repo: Addon):
"""Set up the display for a package in expanded view"""
maintainers = repo.metadata.Maintainer
maintainers_string = ""
if len(maintainers) == 1:
@@ -392,23 +394,17 @@ class PackageListItemDelegate(QStyledItemDelegate):
)
elif len(maintainers) > 1:
n = len(maintainers)
maintainers_string = translate(
"AddonsInstaller", "Maintainers:", "", n
)
maintainers_string = translate("AddonsInstaller", "Maintainers:", "", n)
for maintainer in maintainers:
maintainers_string += (
f"\n{maintainer['name']} <{maintainer['email']}>"
)
maintainers_string += f"\n{maintainer['name']} <{maintainer['email']}>"
self.widget.ui.labelMaintainer.setText(maintainers_string)
if repo.tags:
self.widget.ui.labelTags.setText(
translate("AddonsInstaller", "Tags")
+ ": "
+ ", ".join(repo.tags)
translate("AddonsInstaller", "Tags") + ": " + ", ".join(repo.tags)
)
def _setup_macro(self, repo:Addon):
""" Set up the display for a macro """
def _setup_macro(self, repo: Addon):
"""Set up the display for a macro"""
self.widget.ui.labelDescription.setText(repo.macro.comment)
version_string = ""
if repo.macro.version:
@@ -526,8 +522,8 @@ class PackageListItemDelegate(QStyledItemDelegate):
return result
def paint(self, painter: QPainter, option: QStyleOptionViewItem, _: QModelIndex):
""" Main paint function: renders this widget into a given rectangle, successively drawing
all of its children. """
"""Main paint function: renders this widget into a given rectangle, successively drawing
all of its children."""
painter.save()
self.widget.resize(option.rect.size())
painter.translate(option.rect.topLeft())
@@ -550,42 +546,42 @@ class PackageListFilter(QSortFilterProxyModel):
def setPackageFilter(
self, package_type: int
) -> None: # 0=All, 1=Workbenches, 2=Macros, 3=Preference Packs
""" Set the package filter to package_type and refreshes. """
"""Set the package filter to package_type and refreshes."""
self.package_type = package_type
self.invalidateFilter()
def setStatusFilter(
self, status: int
) -> None: # 0=Any, 1=Installed, 2=Not installed, 3=Update available
""" Sets the status filter to status and refreshes. """
"""Sets the status filter to status and refreshes."""
self.status = status
self.invalidateFilter()
def setHidePy2(self, hide_py2: bool) -> None:
""" Sets whether or not to hide Python 2-only Addons """
"""Sets whether or not to hide Python 2-only Addons"""
self.hide_py2 = hide_py2
self.invalidateFilter()
def setHideObsolete(self, hide_obsolete: bool) -> None:
""" Sets whether or not to hide Addons marked obsolete """
"""Sets whether or not to hide Addons marked obsolete"""
self.hide_obsolete = hide_obsolete
self.invalidateFilter()
def setHideNewerFreeCADRequired(self, hide_nfr: bool) -> None:
""" Sets whether or not to hide packages that have indicated they need a newer version
of FreeCAD than the one currently running. """
"""Sets whether or not to hide packages that have indicated they need a newer version
of FreeCAD than the one currently running."""
self.hide_newer_freecad_required = hide_nfr
self.invalidateFilter()
def lessThan(self, left, right) -> bool:
""" Enable sorting of display name (not case sensitive). """
"""Enable sorting of display name (not case sensitive)."""
l = self.sourceModel().data(left, PackageListItemModel.DataAccessRole)
r = self.sourceModel().data(right, PackageListItemModel.DataAccessRole)
return l.display_name.lower() < r.display_name.lower()
def filterAcceptsRow(self, row, parent=QModelIndex()):
""" Do the actual filtering (called automatically by Qt when drawing the list) """
"""Do the actual filtering (called automatically by Qt when drawing the list)"""
index = self.sourceModel().createIndex(row, 0)
data = self.sourceModel().data(index, PackageListItemModel.DataAccessRole)
if self.package_type == 1: