Skip to content

Commit

Permalink
Fixes and cleanups to algorithm dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Dec 1, 2017
1 parent ce17091 commit f6e63d7
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 314 deletions.
11 changes: 11 additions & 0 deletions python/gui/processing/qgsprocessingalgorithmdialogbase.sip
Expand Up @@ -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.
Expand All @@ -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 );
Expand Down
24 changes: 7 additions & 17 deletions python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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]")
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -80,7 +80,7 @@ def runAsBatch(self):
dlg.show()
dlg.exec_()

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

if self.mainWidget() is None:
Expand Down Expand Up @@ -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"),
Expand Down
246 changes: 1 addition & 245 deletions python/plugins/processing/gui/AlgorithmDialogBase.py
Expand Up @@ -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):

Expand Down

0 comments on commit f6e63d7

Please sign in to comment.