Skip to content

Commit

Permalink
Merge pull request #32 from goanpeca/enh/doisplay-name
Browse files Browse the repository at this point in the history
  • Loading branch information
goanpeca authored May 29, 2024
2 parents c091217 + 31944fa commit 8f701cf
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 39 deletions.
87 changes: 48 additions & 39 deletions napari_plugin_manager/qt_plugin_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from enum import Enum, auto
from functools import partial
from pathlib import Path
from typing import Dict, List, Literal, Optional, Sequence, Tuple
from typing import Dict, List, Literal, NamedTuple, Optional, Sequence, Tuple

import napari.plugins
import napari.resources
Expand Down Expand Up @@ -47,26 +47,34 @@
InstallerQueue,
InstallerTools,
)
from napari_plugin_manager.qt_widgets import ClickableLabel
from napari_plugin_manager.utils import is_conda_package

# TODO: add error icon and handle pip install errors

# Scaling factor for each list widget item when expanding.
SCALE = 1.6

CONDA = 'Conda'
PYPI = 'PyPI'
ON_BUNDLE = running_as_constructor_app()
IS_NAPARI_CONDA_INSTALLED = is_conda_package('napari')


class ProjectInfoVersions(NamedTuple):
metadata: npe2.PackageMetadata
display_name: str
pypi_versions: List[str]
conda_versions: List[str]


class PluginListItem(QFrame):
"""An entry in the plugin dialog. This will include the package name, summary,
author, source, version, and buttons to update, install/uninstall, etc."""

def __init__(
self,
package_name: str,
display_name: str,
version: str = '',
url: str = '',
summary: str = '',
Expand All @@ -86,7 +94,12 @@ def __init__(
self._versions_conda = versions_conda
self._versions_pypi = versions_pypi
self.setup_ui(enabled)
self.plugin_name.setText(package_name)
if package_name == display_name:
name = package_name
else:
name = f"{display_name} <small>({package_name})</small>"

self.plugin_name.setText(name)

if len(versions_pypi) > 0:
self._populate_version_dropdown(PYPI)
Expand Down Expand Up @@ -188,7 +201,7 @@ def setup_ui(self, enabled=True):
self.enabled_checkbox.setMinimumSize(QSize(20, 0))
self.enabled_checkbox.setText("")
self.row1.addWidget(self.enabled_checkbox)
self.plugin_name = QPushButton(self)
self.plugin_name = ClickableLabel(self) # To style content
# Do not want to highlight on hover unless there is a website.
if self.url and self.url != 'UNKNOWN':
self.plugin_name.setObjectName('plugin_name_web')
Expand Down Expand Up @@ -436,17 +449,13 @@ def _count_visible(self) -> int:
@Slot(tuple)
def addItem(
self,
project_info_versions: Tuple[
npe2.PackageMetadata, List[str], List[str]
],
project_info: ProjectInfoVersions,
installed=False,
plugin_name=None,
enabled=True,
npe_version=None,
):
project_info, versions_pypi, versions_conda = project_info_versions

pkg_name = project_info.name
pkg_name = project_info.metadata.name
# don't add duplicates
if (
self.findItems(pkg_name, Qt.MatchFlag.MatchFixedString)
Expand All @@ -455,37 +464,38 @@ def addItem(
return

# including summary here for sake of filtering below.
searchable_text = f"{pkg_name} {project_info.summary}"
searchable_text = f"{pkg_name} {project_info.display_name} {project_info.metadata.summary}"
item = QListWidgetItem(searchable_text, self)
item.version = project_info.version
item.version = project_info.metadata.version
super().addItem(item)
widg = PluginListItem(
package_name=pkg_name,
version=project_info.version,
url=project_info.home_page,
summary=project_info.summary,
author=project_info.author,
license=project_info.license,
display_name=project_info.display_name,
version=project_info.metadata.version,
url=project_info.metadata.home_page,
summary=project_info.metadata.summary,
author=project_info.metadata.author,
license=project_info.metadata.license,
parent=self,
plugin_name=plugin_name,
enabled=enabled,
installed=installed,
npe_version=npe_version,
versions_conda=versions_conda,
versions_pypi=versions_pypi,
versions_conda=project_info.conda_versions,
versions_pypi=project_info.pypi_versions,
)
item.widget = widg
item.npe_version = npe_version
action_name = 'uninstall' if installed else 'install'
item.setSizeHint(widg.sizeHint())
self.setItemWidget(item, widg)

if project_info.home_page:
if project_info.metadata.home_page:
import webbrowser

# FIXME: Partial may lead to leak memory when connecting to Qt signals.
widg.plugin_name.clicked.connect(
partial(webbrowser.open, project_info.home_page)
partial(webbrowser.open, project_info.metadata.home_page)
)

# FIXME: Partial may lead to leak memory when connecting to Qt signals.
Expand Down Expand Up @@ -620,20 +630,18 @@ def handle_action(
widget.setProperty("current_job_id", None)

@Slot(npe2.PackageMetadata, bool)
def tag_outdated(
self, project_info: npe2.PackageMetadata, is_available: bool
):
def tag_outdated(self, metadata: npe2.PackageMetadata, is_available: bool):
"""Determines if an installed plugin is up to date with the latest version.
If it is not, the latest version will be displayed on the update button.
"""
if not is_available:
return

for item in self.findItems(
project_info.name, Qt.MatchFlag.MatchStartsWith
metadata.name, Qt.MatchFlag.MatchStartsWith
):
current = item.version
latest = project_info.version
latest = metadata.version
if parse_version(current) >= parse_version(latest):
continue
if hasattr(item, 'outdated'):
Expand All @@ -648,15 +656,15 @@ def tag_outdated(
trans._("update (v{latest})", latest=latest)
)

def tag_unavailable(self, project_info: npe2.PackageMetadata):
def tag_unavailable(self, metadata: npe2.PackageMetadata):
"""
Tag list items as unavailable for install with conda-forge.
This will disable the item and the install button and add a warning
icon with a hover tooltip.
"""
for item in self.findItems(
project_info.name, Qt.MatchFlag.MatchStartsWith
metadata.name, Qt.MatchFlag.MatchStartsWith
):
widget = self.itemWidget(item)
widget.show_warning(
Expand Down Expand Up @@ -771,7 +779,7 @@ def _add_to_installed(distname, enabled, npe_version=1):
meta = {}

self.installed_list.addItem(
(
ProjectInfoVersions(
npe2.PackageMetadata(
metadata_version="1.0",
name=norm_name,
Expand All @@ -781,6 +789,7 @@ def _add_to_installed(distname, enabled, npe_version=1):
author=meta.get('author', ''),
license=meta.get('license', ''),
),
norm_name,
[],
[],
),
Expand Down Expand Up @@ -1019,23 +1028,23 @@ def _add_items(self):
return

data = self._plugin_data.pop(0)
project_info, is_available_in_conda, extra_info = data
if project_info.name in self.already_installed:
self.installed_list.tag_outdated(
project_info, is_available_in_conda
)
metadata, is_available_in_conda, extra_info = data
display_name = extra_info.get('display_name', metadata.name)
if metadata.name in self.already_installed:
self.installed_list.tag_outdated(metadata, is_available_in_conda)
else:
if project_info.name not in self.available_set:
self.available_set.add(project_info.name)
if metadata.name not in self.available_set:
self.available_set.add(metadata.name)
self.available_list.addItem(
(
project_info,
ProjectInfoVersions(
metadata,
display_name,
extra_info['pypi_versions'],
extra_info['conda_versions'],
)
)
if ON_BUNDLE and not is_available_in_conda:
self.available_list.tag_unavailable(project_info)
self.available_list.tag_unavailable(metadata)

self.filter()

Expand Down
14 changes: 14 additions & 0 deletions napari_plugin_manager/qt_widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from qtpy.QtCore import Signal
from qtpy.QtGui import QMouseEvent
from qtpy.QtWidgets import QLabel


class ClickableLabel(QLabel):
clicked = Signal()

def __init__(self, parent=None):
super().__init__(parent=parent)

def mouseReleaseEvent(self, event: QMouseEvent):
super().mouseReleaseEvent(event)
self.clicked.emit()

0 comments on commit 8f701cf

Please sign in to comment.