Skip to content
Permalink
Browse files

Fixes and cleanups to algorithm dialogs

  • Loading branch information
nyalldawson committed Dec 1, 2017
1 parent ce17091 commit f6e63d7f4cbb2df3f4e0963d74b8ad7bf93c1e97
@@ -146,6 +146,12 @@ class QgsProcessingAlgorithmDialogBase : QDialog
:rtype: QDialogButtonBox
%End

QTabWidget *tabWidget();
%Docstring
Returns the dialog's tab widget.
:rtype: QTabWidget
%End

void clearProgress();
%Docstring
Clears any current progress from the dialog.
@@ -172,6 +178,11 @@ class QgsProcessingAlgorithmDialogBase : QDialog
:rtype: QgsMessageBar
%End

void hideShortHelp();
%Docstring
Hides the short help panel.
%End

protected slots:

virtual void finished( bool successful, const QVariantMap &result, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
@@ -40,7 +40,8 @@
from qgis.core import (QgsProcessingFeedback,
QgsProcessingParameterDefinition)
from qgis.gui import (QgsMessageBar,
QgsProjectionSelectionWidget)
QgsProjectionSelectionWidget,
QgsProcessingAlgorithmDialogBase)

from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
@@ -53,22 +54,11 @@
class GdalAlgorithmDialog(AlgorithmDialog):

def __init__(self, alg):
AlgorithmDialogBase.__init__(self, alg)
super().__init__(alg)
self.mainWidget().parametersHaveChanged()

self.alg = alg

self.bar = QgsMessageBar()
self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
self.layout().insertWidget(0, self.bar)

self.setMainWidget(GdalParametersPanel(self, alg))

self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
self.runAsBatchButton.clicked.connect(self.runAsBatch)
self.buttonBox.addButton(self.runAsBatchButton,
QDialogButtonBox.ResetRole) # reset role to ensure left alignment

self.mainWidget.parametersHaveChanged()
def getParametersPanel(self, alg, parent):
return GdalParametersPanel(parent, alg)


class GdalParametersPanel(ParametersPanel):
@@ -117,7 +107,7 @@ def parametersHaveChanged(self):
context = createContext()
feedback = QgsProcessingFeedback()
try:
parameters = self.parent.getParamValues()
parameters = self.parent.getParameterValues()
for output in self.alg.destinationParameterDefinitions():
if not output.name() in parameters or parameters[output.name()] is None:
parameters[output.name()] = self.tr("[temporary file]")
@@ -80,7 +80,7 @@ def runAsBatch(self):
dlg.show()
dlg.exec_()

def getParamValues(self):
def getParameterValues(self):
parameters = {}

if self.mainWidget() is None:
@@ -152,7 +152,7 @@ def accept(self):

checkCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_CRS)
try:
parameters = self.getParamValues()
parameters = self.getParameterValues()

if checkCRS and not self.algorithm().validateInputCrs(parameters, context):
reply = QMessageBox.question(self, self.tr("Unmatching CRS's"),
@@ -25,252 +25,8 @@

__revision__ = '$Format:%H$'

import os
import webbrowser
import html

from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal, Qt, QCoreApplication, QByteArray, QUrl
from qgis.PyQt.QtWidgets import QApplication, QDialogButtonBox, QVBoxLayout, QToolButton

from qgis.utils import iface
from qgis.core import (QgsProject,
QgsProcessingFeedback,
QgsSettings)
from qgis.gui import QgsHelp

from processing.core.ProcessingConfig import ProcessingConfig

pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
os.path.join(pluginPath, 'ui', 'DlgAlgorithmBase.ui'))


class AlgorithmDialogFeedback(QgsProcessingFeedback):

"""
Directs algorithm feedback to an algorithm dialog
"""

error = pyqtSignal(str)
progress_text = pyqtSignal(str)
info = pyqtSignal(str)
command_info = pyqtSignal(str)
debug_info = pyqtSignal(str)
console_info = pyqtSignal(str)

def __init__(self, dialog):
QgsProcessingFeedback.__init__(self)
self.dialog = dialog

def reportError(self, msg):
self.error.emit(msg)

def setProgressText(self, text):
self.progress_text.emit(text)

def pushInfo(self, msg):
self.info.emit(msg)

def pushCommandInfo(self, msg):
self.command_info.emit(msg)

def pushDebugInfo(self, msg):
self.debug_info.emit(msg)

def pushConsoleInfo(self, msg):
self.console_info.emit(msg)


class AlgorithmDialogBase(BASE, WIDGET):

def __init__(self, alg):
super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None)
self.setupUi(self)

# don't collapse parameters panel
self.splitter.setCollapsible(0, False)

# add collapse button to splitter
splitterHandle = self.splitter.handle(1)
handleLayout = QVBoxLayout()
handleLayout.setContentsMargins(0, 0, 0, 0)
self.btnCollapse = QToolButton(splitterHandle)
self.btnCollapse.setAutoRaise(True)
self.btnCollapse.setFixedSize(12, 12)
self.btnCollapse.setCursor(Qt.ArrowCursor)
handleLayout.addWidget(self.btnCollapse)
handleLayout.addStretch()
splitterHandle.setLayout(handleLayout)

self.settings = QgsSettings()
self.splitter.restoreState(self.settings.value("/Processing/dialogBaseSplitter", QByteArray()))
self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray()))
self.splitterState = self.splitter.saveState()
self.splitterChanged(0, 0)

self.executed = False
self.mainWidget = None
self.alg = alg

self.setWindowTitle(self.alg.displayName())

self.buttonBox.rejected.connect(self.reject)
self.buttonBox.accepted.connect(self.accept)

# Rename OK button to Run
self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok)
self.btnRun.setText(self.tr('Run'))

self.buttonCancel.setEnabled(False)

self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)

self.buttonBox.helpRequested.connect(self.openHelp)

self.btnCollapse.clicked.connect(self.toggleCollapsed)
self.splitter.splitterMoved.connect(self.splitterChanged)

# desktop = QDesktopWidget()
# if desktop.physicalDpiX() > 96:
# self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96)

algHelp = self.formatHelp(self.alg)
if algHelp is None:
self.textShortHelp.hide()
else:
self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; }
h2 { color: #555555; padding-bottom: 15px; }
a { text-decoration: none; color: #3498db; font-weight: bold; }
p { color: #666666; }
b { color: #333333; }
dl dd { margin-bottom: 5px; }''')
self.textShortHelp.setHtml(algHelp)

def linkClicked(url):
webbrowser.open(url.toString())

self.textShortHelp.anchorClicked.connect(linkClicked)

self.showDebug = ProcessingConfig.getSetting(
ProcessingConfig.SHOW_DEBUG_IN_DIALOG)

def createFeedback(self):
feedback = AlgorithmDialogFeedback(self)
feedback.progressChanged.connect(self.setPercentage)
feedback.error.connect(self.error)
feedback.progress_text.connect(self.setText)
feedback.info.connect(self.setInfo)
feedback.command_info.connect(self.setCommand)
feedback.debug_info.connect(self.setDebugInfo)
feedback.console_info.connect(self.setConsoleInfo)

self.buttonCancel.clicked.connect(feedback.cancel)
return feedback

def formatHelp(self, alg):
text = alg.shortHelpString()
if not text:
return None
return "<h2>%s</h2>%s" % (alg.displayName(), "".join(["<p>%s</p>" % s for s in text.split("\n")]))

def closeEvent(self, event):
self._saveGeometry()
super(AlgorithmDialogBase, self).closeEvent(event)

def setMainWidget(self, widget):
if self.mainWidget is not None:
QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged)
QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged)
self.mainWidget = widget
self.tabWidget.widget(0).layout().addWidget(self.mainWidget)
QgsProject.instance().layerWasAdded.connect(self.mainWidget.layerRegistryChanged)
QgsProject.instance().layersWillBeRemoved.connect(self.mainWidget.layerRegistryChanged)

def error(self, msg):
self.setInfo(msg, True)
self.resetGUI()
self.tabWidget.setCurrentIndex(1)

def resetGUI(self):
self.lblProgress.setText('')
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
self.btnRun.setEnabled(True)
self.btnClose.setEnabled(True)

def setInfo(self, msg, error=False, escape_html=True):
if error:
self.txtLog.append('<span style="color:red">{}</span><br />'.format(msg, quote=False))
elif escape_html:
self.txtLog.append(html.escape(msg))
else:
self.txtLog.append(msg)

def setCommand(self, cmd):
if self.showDebug:
self.txtLog.append('<code>{}<code>'.format(html.escape(cmd, quote=False)))

def setDebugInfo(self, msg):
if self.showDebug:
self.txtLog.append('<span style="color:blue">{}</span>'.format(html.escape(msg, quote=False)))

def setConsoleInfo(self, msg):
if self.showDebug:
self.txtLog.append('<code><span style="color:darkgray">{}</span></code>'.format(html.escape(msg, quote=False)))

def setPercentage(self, value):
if self.progressBar.maximum() == 0:
self.progressBar.setMaximum(100)
self.progressBar.setValue(value)

def setText(self, text):
self.lblProgress.setText(text)
self.setInfo(text, False)

def getParamValues(self):
return {}

def accept(self):
pass

def reject(self):
self._saveGeometry()
super(AlgorithmDialogBase, self).reject()

def finish(self, successful, result, context, feedback):
pass

def toggleCollapsed(self):
if self.helpCollapsed:
self.splitter.restoreState(self.splitterState)
self.btnCollapse.setArrowType(Qt.RightArrow)
else:
self.splitterState = self.splitter.saveState()
self.splitter.setSizes([1, 0])
self.btnCollapse.setArrowType(Qt.LeftArrow)
self.helpCollapsed = not self.helpCollapsed

def splitterChanged(self, pos, index):
if self.splitter.sizes()[1] == 0:
self.helpCollapsed = True
self.btnCollapse.setArrowType(Qt.LeftArrow)
else:
self.helpCollapsed = False
self.btnCollapse.setArrowType(Qt.RightArrow)

def openHelp(self):
algHelp = self.alg.helpUrl()
if not algHelp:
algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format(
self.alg.provider().id(), self.alg.id())).toString()

if algHelp not in [None, ""]:
webbrowser.open(algHelp)

def _saveGeometry(self):
self.settings.setValue("/Processing/dialogBaseSplitter", self.splitter.saveState())
self.settings.setValue("/Processing/dialogBase", self.saveGeometry())
class AlgorithmDialogBase:

class InvalidParameterValue(Exception):

0 comments on commit f6e63d7

Please sign in to comment.
You can’t perform that action at this time.