Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 67 additions & 10 deletions Orange/canvas/application/addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from collections import namedtuple, deque
from xml.sax.saxutils import escape
from distutils import version
from typing import Optional, List, Union, Tuple # pylint: disable=unused-import

import pkg_resources
import requests
Expand All @@ -27,7 +28,7 @@
QWidget, QDialog, QLabel, QLineEdit, QTreeView, QHeaderView,
QTextBrowser, QDialogButtonBox, QProgressDialog,
QVBoxLayout, QStyle, QStyledItemDelegate, QStyleOptionViewItem,
QApplication, QHBoxLayout, QPushButton, QFormLayout
QApplication, QHBoxLayout, QPushButton, QFormLayout
)

from AnyQt.QtGui import (
Expand Down Expand Up @@ -83,8 +84,12 @@
"local"]
)

#: An installable item/slot
Item = Union[Available, Installed]


def is_updatable(item):
# type: (Item) -> bool
if isinstance(item, Available):
return False
elif item.installable is None:
Expand Down Expand Up @@ -249,10 +254,10 @@ def __init__(self, parent=None, **kwargs):
self.layout().addWidget(self.__details)

def set_items(self, items):
# type: (List[Item]) -> None
self.__items = items
model = self.__model
model.clear()
model.setHorizontalHeaderLabels(["", "Name", "Version", "Action"])
model.setRowCount(0)

for item in items:
if isinstance(item, Installed):
Expand Down Expand Up @@ -282,9 +287,9 @@ def set_items(self, items):
item1.setCheckState(Qt.Checked)
else:
item1.setCheckState(Qt.Unchecked)
item1.setData(item, Qt.UserRole)

item2 = QStandardItem(cleanup(name))

item2.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
item2.setToolTip(summary)
item2.setData(item, Qt.UserRole)
Expand All @@ -300,6 +305,8 @@ def set_items(self, items):

model.appendRow([item1, item2, item3, item4])

model.sort(1)

self.__view.resizeColumnToContents(0)
self.__view.setColumnWidth(
1, max(150, self.__view.sizeHintForColumn(1)))
Expand All @@ -312,10 +319,16 @@ def set_items(self, items):
QItemSelectionModel.Select | QItemSelectionModel.Rows
)

def items(self):
# type: () -> List[Item]
return list(self.__items)

def item_state(self):
# type: () -> List['Action']
steps = []
for i, item in enumerate(self.__items):
for i in range(self.__model.rowCount()):
modelitem = self.__model.item(i, 0)
item = modelitem.data(Qt.UserRole)
state = modelitem.checkState()
if modelitem.flags() & Qt.ItemIsTristate and state == Qt.Checked:
steps.append((Upgrade, item))
Expand All @@ -326,6 +339,37 @@ def item_state(self):

return steps

def set_item_state(self, steps):
# type: (List['Action']) -> None
model = self.__model
if model.rowCount() == 0:
return

for row in range(model.rowCount()):
modelitem = model.item(row, 0) # type: QStandardItem
item = modelitem.data(Qt.UserRole) # type: Item
# Find the action command in the steps list for the item
cmd = -1
for cmd_, item_ in steps:
if item == item_:
cmd = cmd_
break
if isinstance(item, Available):
modelitem.setCheckState(
Qt.Checked if cmd == Install else Qt.Unchecked
)
elif isinstance(item, Installed):
if cmd == Upgrade:
modelitem.setCheckState(Qt.Checked)
elif cmd == Uninstall:
modelitem.setCheckState(Qt.Unchecked)
elif is_updatable(item):
modelitem.setCheckState(Qt.PartiallyChecked)
else:
modelitem.setCheckState(Qt.Checked)
else:
assert False

def __selected_row(self):
indices = self.__view.selectedIndexes()
if indices:
Expand All @@ -348,7 +392,7 @@ def __data_changed(self, topleft, bottomright):
for i in rows:
modelitem = self.__model.item(i, 0)
actionitem = self.__model.item(i, 3)
item = self.__items[i]
item = modelitem.data(Qt.UserRole)

state = modelitem.checkState()
flags = modelitem.flags()
Expand Down Expand Up @@ -546,7 +590,9 @@ def add_package(self, installable):
return
else:
packages = self._packages + [installable]
state = self.addonwidget.item_state()
self.set_packages(packages)
self.addonwidget.set_item_state(state)

def __progressDialog(self):
if self.__progress is None:
Expand Down Expand Up @@ -675,10 +721,19 @@ def dropEvent(self, event):
packages.append(
Installable(name, vers, summary,
descr or summary, path, [path]))
future = concurrent.futures.Future()
future.set_result((AddonManagerDialog._packages or []) + packages)
self._set_packages(future)
self.addonwidget.set_install_projects(names)

if packages:
state = self.addonwidget.item_state()
self.set_packages((self._packages or []) + packages)
items = self.addonwidget.items()
# mark for installation the added packages
for item in items:
if item.installable in packages:
if isinstance(item, Available):
state.append((Install, item))
elif isinstance(item, Installed) and is_updatable(item):
state.append((Upgrade, item))
self.addonwidget.set_item_state(state)

def __accepted(self):
steps = self.addonwidget.item_state()
Expand Down Expand Up @@ -840,6 +895,8 @@ def have_install_permissions():

Install, Upgrade, Uninstall = 1, 2, 3

Action = Tuple[int, Item]


class CommandFailed(Exception):
def __init__(self, cmd, retcode, output):
Expand Down