[processing] list native QGIS algorithms first in modeler dialog

This commit is contained in:
Mathieu Pellerin 2017-12-05 11:52:06 +07:00 committed by GitHub
parent 13cb44fd9d
commit ad54073b1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -27,11 +27,12 @@ __revision__ = '$Format:%H$'
import codecs
import sys
import operator
import os
import math
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QByteArray, QSize, QSizeF, pyqtSignal
from qgis.PyQt.QtCore import Qt, QCoreApplication, QRectF, QMimeData, QPoint, QPointF, QByteArray, QSize, QSizeF, pyqtSignal
from qgis.PyQt.QtWidgets import QGraphicsView, QTreeWidget, QMessageBox, QFileDialog, QTreeWidgetItem, QSizePolicy, QMainWindow, QShortcut
from qgis.PyQt.QtGui import QIcon, QImage, QPainter, QKeySequence
from qgis.PyQt.QtSvg import QSvgGenerator
@ -62,6 +63,13 @@ WIDGET, BASE = uic.loadUiType(
class ModelerDialog(BASE, WIDGET):
ALG_ITEM = 'ALG_ITEM'
PROVIDER_ITEM = 'PROVIDER_ITEM'
GROUP_ITEM = 'GROUP_ITEM'
NAME_ROLE = Qt.UserRole
TAG_ROLE = Qt.UserRole + 1
TYPE_ROLE = Qt.UserRole + 2
CANVAS_SIZE = 4000
@ -239,7 +247,7 @@ class ModelerDialog(BASE, WIDGET):
# Connect signals and slots
self.inputsTree.doubleClicked.connect(self.addInput)
self.searchBox.textChanged.connect(self.fillAlgorithmTree)
self.searchBox.textChanged.connect(self.textChanged)
self.algorithmTree.doubleClicked.connect(self.addAlgorithm)
# Ctrl+= should also trigger a zoom in action
@ -272,7 +280,7 @@ class ModelerDialog(BASE, WIDGET):
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
self.fillInputsTree()
self.fillAlgorithmTree()
self.fillTreeUsingProviders()
self.view.centerOn(0, 0)
self.help = None
@ -563,6 +571,49 @@ class ModelerDialog(BASE, WIDGET):
newX = MARGIN + BOX_WIDTH / 2
return QPointF(newX, MARGIN + BOX_HEIGHT / 2)
def textChanged(self):
text = self.searchBox.text().strip(' ').lower()
for item in list(self.disabledProviderItems.values()):
item.setHidden(True)
self._filterItem(self.algorithmTree.invisibleRootItem(), [t for t in text.split(' ') if t])
if text:
self.algorithmTree.expandAll()
self.disabledWithMatchingAlgs = []
for provider in QgsApplication.processingRegistry().providers():
if not provider.isActive():
for alg in provider.algorithms():
if text in alg.name():
self.disabledWithMatchingAlgs.append(provider.id())
break
else:
self.algorithmTree.collapseAll()
def _filterItem(self, item, text):
if (item.childCount() > 0):
show = False
for i in range(item.childCount()):
child = item.child(i)
showChild = self._filterItem(child, text)
show = (showChild or show) and item not in list(self.disabledProviderItems.values())
item.setHidden(not show)
return show
elif isinstance(item, (TreeAlgorithmItem, TreeActionItem)):
# hide if every part of text is not contained somewhere in either the item text or item user role
item_text = [item.text(0).lower(), item.data(0, ModelerDialog.NAME_ROLE).lower()]
if isinstance(item, TreeAlgorithmItem):
item_text.append(item.alg.id())
item_text.extend(item.data(0, ModelerDialog.TAG_ROLE))
hide = bool(text) and not all(
any(part in t for t in item_text)
for part in text)
item.setHidden(hide)
return not hide
else:
item.setHidden(True)
return False
def fillInputsTree(self):
icon = QIcon(os.path.join(pluginPath, 'images', 'input.svg'))
parametersItem = QTreeWidgetItem()
@ -619,80 +670,95 @@ class ModelerDialog(BASE, WIDGET):
newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2
return QPointF(newX, newY)
def fillAlgorithmTree(self):
self.fillAlgorithmTreeUsingProviders()
self.algorithmTree.sortItems(0, Qt.AscendingOrder)
text = str(self.searchBox.text())
if text != '':
self.algorithmTree.expandAll()
def fillAlgorithmTreeUsingProviders(self):
def fillTreeUsingProviders(self):
self.algorithmTree.clear()
text = str(self.searchBox.text())
search_strings = text.split(' ')
qgis_groups = {}
self.disabledProviderItems = {}
# TODO - replace with proper model for toolbox!
# first add qgis/native providers, since they create top level groups
for provider in QgsApplication.processingRegistry().providers():
if not provider.isActive():
if provider.id() in ('qgis', 'native', '3d'):
self.addAlgorithmsFromProvider(provider, self.algorithmTree.invisibleRootItem())
else:
continue
groups = {}
# Add algorithms
for alg in provider.algorithms():
if alg.flags() & QgsProcessingAlgorithm.FlagHideFromModeler:
continue
if alg.id() == self.model.id():
continue
item_text = [alg.displayName().lower()]
item_text.extend(alg.tags())
show = not search_strings or all(
any(part in t for t in item_text)
for part in search_strings)
if show:
if alg.group() in groups:
groupItem = groups[alg.group()]
elif provider.id() in ('qgis', 'native', '3d') and alg.group() in qgis_groups:
groupItem = qgis_groups[alg.group()]
else:
groupItem = QTreeWidgetItem()
name = alg.group()
groupItem.setText(0, name)
groupItem.setToolTip(0, name)
groupItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
if provider.id() in ('qgis', 'native', '3d'):
groupItem.setIcon(0, provider.icon())
qgis_groups[alg.group()] = groupItem
else:
groups[alg.group()] = groupItem
algItem = TreeAlgorithmItem(alg)
groupItem.addChild(algItem)
if len(groups) > 0:
providerItem = QTreeWidgetItem()
providerItem.setText(0, provider.name())
providerItem.setToolTip(0, provider.name())
providerItem.setIcon(0, provider.icon())
providerItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
for groupItem in list(groups.values()):
providerItem.addChild(groupItem)
self.algorithmTree.addTopLevelItem(providerItem)
providerItem.setExpanded(text != '')
for groupItem in list(groups.values()):
if text != '':
groupItem.setExpanded(True)
if len(qgis_groups) > 0:
for groupItem in list(qgis_groups.values()):
self.algorithmTree.addTopLevelItem(groupItem)
for groupItem in list(qgis_groups.values()):
if text != '':
groupItem.setExpanded(True)
self.algorithmTree.sortItems(0, Qt.AscendingOrder)
for provider in QgsApplication.processingRegistry().providers():
if provider.id() in ('qgis', 'native', '3d'):
# already added
continue
else:
providerItem = TreeProviderItem(provider, self.algorithmTree, self)
if not provider.isActive():
providerItem.setHidden(True)
self.disabledProviderItems[provider.id()] = providerItem
# insert non-native providers at end of tree, alphabetically
for i in range(self.algorithmTree.invisibleRootItem().childCount()):
child = self.algorithmTree.invisibleRootItem().child(i)
if isinstance(child, TreeProviderItem):
if child.text(0) > providerItem.text(0):
break
self.algorithmTree.insertTopLevelItem(i + 1, providerItem)
def addAlgorithmsFromProvider(self, provider, parent):
groups = {}
count = 0
algs = provider.algorithms()
active = provider.isActive()
# Add algorithms
for alg in algs:
if alg.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox:
continue
groupItem = None
if alg.group() in groups:
groupItem = groups[alg.group()]
else:
# check if group already exists
for i in range(parent.childCount()):
if parent.child(i).text(0) == alg.group():
groupItem = parent.child(i)
groups[alg.group()] = groupItem
break
if not groupItem:
groupItem = TreeGroupItem(alg.group())
if not active:
groupItem.setInactive()
if provider.id() in ('qgis', 'native', '3d'):
groupItem.setIcon(0, provider.icon())
groups[alg.group()] = groupItem
algItem = TreeAlgorithmItem(alg)
if not active:
algItem.setForeground(0, Qt.darkGray)
groupItem.addChild(algItem)
count += 1
text = provider.name()
if not provider.id() in ('qgis', 'native', '3d'):
if not active:
def activateProvider():
self.activateProvider(provider.id())
label = QLabel(text + "&nbsp;&nbsp;&nbsp;&nbsp;<a href='%s'>Activate</a>")
label.setStyleSheet("QLabel {background-color: white; color: grey;}")
label.linkActivated.connect(activateProvider)
self.algorithmTree.setItemWidget(parent, 0, label)
else:
parent.setText(0, text)
for group, groupItem in sorted(groups.items(), key=operator.itemgetter(1)):
parent.addChild(groupItem)
if not provider.id() in ('qgis', 'native', '3d'):
parent.setHidden(parent.childCount() == 0)
class TreeAlgorithmItem(QTreeWidgetItem):
@ -700,7 +766,61 @@ class TreeAlgorithmItem(QTreeWidgetItem):
QTreeWidgetItem.__init__(self)
self.alg = alg
icon = alg.icon()
nameEn = alg.name()
name = alg.displayName()
name = name if name != '' else nameEn
self.setIcon(0, icon)
self.setToolTip(0, self.formatAlgorithmTooltip(alg))
self.setText(0, name)
self.setData(0, ModelerDialog.NAME_ROLE, nameEn)
self.setData(0, ModelerDialog.TAG_ROLE, alg.tags())
self.setData(0, ModelerDialog.TYPE_ROLE, ModelerDialog.ALG_ITEM)
def formatAlgorithmTooltip(self, alg):
return '<p><b>{}</b></p><p>{}</p>'.format(
alg.displayName(),
QCoreApplication.translate('Toolbox', 'Algorithm ID: {}').format('<i>{}</i>'.format(alg.id()))
)
class TreeGroupItem(QTreeWidgetItem):
def __init__(self, name):
QTreeWidgetItem.__init__(self)
self.setToolTip(0, name)
self.setText(0, name)
self.setData(0, ModelerDialog.NAME_ROLE, name)
self.setData(0, ModelerDialog.TYPE_ROLE, ModelerDialog.GROUP_ITEM)
def setInactive(self):
self.setForeground(0, Qt.darkGray)
class TreeActionItem(QTreeWidgetItem):
def __init__(self, action):
QTreeWidgetItem.__init__(self)
self.action = action
self.setText(0, action.i18n_name)
self.setIcon(0, action.getIcon())
self.setData(0, ModelerDialog.NAME_ROLE, action.name)
class TreeProviderItem(QTreeWidgetItem):
def __init__(self, provider, tree, toolbox):
QTreeWidgetItem.__init__(self, None)
self.tree = tree
self.toolbox = toolbox
self.provider = provider
self.setIcon(0, self.provider.icon())
self.setData(0, ModelerDialog.TYPE_ROLE, ModelerDialog.PROVIDER_ITEM)
self.setToolTip(0, self.provider.longName())
self.populate()
def refresh(self):
self.takeChildren()
self.populate()
def populate(self):
self.toolbox.addAlgorithmsFromProvider(self.provider, self)