Skip to content

Commit

Permalink
[processing] more friendly error message when layers not created
Browse files Browse the repository at this point in the history
This commit includes changes to the log system as well, which now logs only algorithms. Messages are logged to the QGIS logging system
  • Loading branch information
volaya committed May 20, 2015
1 parent 2e7f344 commit 5a00912
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 113 deletions.
2 changes: 1 addition & 1 deletion python/plugins/processing/ProcessingPlugin.py
Expand Up @@ -81,7 +81,7 @@ def initGui(self):

self.historyAction = QAction(
QIcon(os.path.join(cmd_folder, 'images', 'history.gif')),
self.tr('&History and Log...'), self.iface.mainWindow())
self.tr('&History...'), self.iface.mainWindow())
self.historyAction.setObjectName('historyAction')
self.historyAction.triggered.connect(self.openHistory)
self.menu.addAction(self.historyAction)
Expand Down
17 changes: 0 additions & 17 deletions python/plugins/processing/algs/grass/GrassAlgorithm.py
Expand Up @@ -510,20 +510,3 @@ def checkParameterValuesBeforeExecuting(self):
func = getattr(module, 'checkParameterValuesBeforeExecuting')
return func(self)

def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = GrassUtils.checkGrassIsInstalled(True)
html += self.tr(
'<p>This algorithm requires GRASS to be run. A test to check '
'if GRASS is correctly installed and configured in your system '
'has been performed, with the following result:</p><ul><i>')
if msg is None:
html += self.tr('GRASS seems to be correctly installed and '
'configured</i></li></ul>')
else:
html += msg + '</i></li></ul>'
html += self.tr(
'<p><a href="http://docs.qgis.org/testing/en/docs/user_manual/processing/3rdParty.html">Click here</a> '
'to know more about how to install and configure GRASS to be used with QGIS</p>')

return html
17 changes: 0 additions & 17 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -519,20 +519,3 @@ def checkParameterValuesBeforeExecuting(self):
func = getattr(module, 'checkParameterValuesBeforeExecuting')
return func(self)

def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = Grass7Utils.checkGrass7IsInstalled(True)
html += self.tr(
'<p>This algorithm requires GRASS GIS 7 to be run. A test '
'to check if GRASS GIS 7 is correctly installed and configured in '
'your system has been performed, with the following result:</p><ul><i>')
if msg is None:
html += self.tr(
'GRASS GIS 7 seems to be correctly installed and configured</i></li></ul>')
else:
html += msg + '</i></li></ul>'
html += self.tr(
'<p><a href="http://docs.qgis.org/testing/en/docs/user_manual/processing/3rdParty.html">Click here</a> '
'to know more about how to install and configure GRASS GIS 7 to be used with QGIS</p>')

return html
23 changes: 0 additions & 23 deletions python/plugins/processing/algs/r/RAlgorithm.py
Expand Up @@ -415,27 +415,4 @@ def checkBeforeOpeningParametersDialog(self):
'to know more about how to install and configure R to be used with QGIS</p>')
return html

def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = RUtils.checkRIsInstalled(True)
html += self.tr(
'<p>This algorithm requires R to be run. A test to check if '
'R is correctly installed and configured in your system has '
'been performed, with the following result:</p><ul><i>')
if msg is None:
html += self.tr(
'R seems to be correctly installed and configured</i></li></ul>'
'<p>The script you have executed needs the following packages:</p><ul>')
packages = RUtils.getRequiredPackages(self.script)
for p in packages:
html += '<li>' + p + '</li>'
html += self.tr(
'</ul><p>Make sure they are installed in your R '
'environment before trying to execute this script.</p>')
else:
html += msg + '</i></li></ul>'
html += self.tr(
'<p><a href= "http://docs.qgis.org/testing/en/docs/user_manual/processing/3rdParty.html">Click here</a> '
'to know more about how to install and configure R to be used with QGIS</p>')

return html
32 changes: 0 additions & 32 deletions python/plugins/processing/core/GeoAlgorithm.py
Expand Up @@ -525,38 +525,6 @@ def getAsCommand(self):
s = s[:-1] + ')'
return s

def getPostProcessingErrorMessage(self, wrongLayers):
"""Returns the message to be shown to the user when, after
running this algorithm, there is a problem loading the
resulting layer.
This method should analyze if the problem is caused by wrong
entry data, a wrong or missing installation of a required 3rd
party app, or any other cause, and create an error response
accordingly.
Message is provided as an HTML code that will be displayed to
the user, and which might contains links to installation paths
for missing 3rd party apps.
- wrongLayers: a list of Output objects that could not be
loaded.
"""

html = self.tr('<p>Oooops! The following output layers could not be '
'open</p><ul>\n')
for layer in wrongLayers:
html += self.tr('<li>%s: <font size=3 face="Courier New" '
'color="#ff0000">%s</font></li>\n') % (
layer.description, layer.value
)
html += self.tr('</ul><p>The above files could not be opened, which '
'probably indicates that they were not correctly '
'produced by the executed algorithm</p>'
'<p>Checking the log information might help you see '
'why those layers were not created as expected</p>')
return html

def tr(self, string, context=''):
if context == '':
context = self.__class__.__name__
Expand Down
32 changes: 16 additions & 16 deletions python/plugins/processing/core/ProcessingLog.py
Expand Up @@ -31,6 +31,7 @@
import datetime
from processing.tools.system import userFolder
from processing.core.ProcessingConfig import ProcessingConfig
from qgis.core import *

class ProcessingLog:

Expand Down Expand Up @@ -66,27 +67,29 @@ def addToLog(msgtype, msg):
# added. To avoid it stopping the normal functioning of the
# algorithm, we catch all errors, assuming that is better
# to miss some log info that breaking the algorithm.
if isinstance(msg, list):
a = '|'.join(m.strip('\n') for m in msg)
text = a
else:
text = msg.replace('\n', '|')
line = msgtype + '|' + datetime.datetime.now().strftime(
ProcessingLog.DATE_FORMAT).decode('utf-8') + '|' \
+ text + '\n'
logfile = codecs.open(ProcessingLog.logFilename(), 'a',
encoding='utf-8')
logfile.write(line)
logfile.close()
if msgtype == ProcessingLog.LOG_ALGORITHM:
algname = text[len('Processing.runalg("'):]
line = msgtype + '|' + datetime.datetime.now().strftime(
ProcessingLog.DATE_FORMAT).decode('utf-8') + '|' \
+ msg + '\n'
logfile = codecs.open(ProcessingLog.logFilename(), 'a',
encoding='utf-8')
logfile.write(line)
logfile.close()
algname = msg[len('Processing.runalg("'):]
algname = algname[:algname.index('"')]
if algname not in ProcessingLog.recentAlgs:
ProcessingLog.recentAlgs.append(algname)
recentAlgsString = ';'.join(ProcessingLog.recentAlgs[-6:])
ProcessingConfig.setSettingValue(
ProcessingConfig.RECENT_ALGORITHMS,
recentAlgsString)
else:
if isinstance(msg, list):
msg = '\n'.join([m for m in msg])
msgtypes = {ProcessingLog.LOG_ERROR: QgsMessageLog.CRITICAL,
ProcessingLog.LOG_INFO: QgsMessageLog.INFO,
ProcessingLog.LOG_WARNING: QgsMessageLog.WARNING,}
QgsMessageLog.logMessage(msg, "Processing", msgtypes[msgtype])
except:
pass

Expand All @@ -113,10 +116,7 @@ def getLogEntries():
elif line.startswith(ProcessingLog.LOG_INFO):
info.append(LogEntry(tokens[1], text))

entries[ProcessingLog.LOG_ERROR] = errors
entries[ProcessingLog.LOG_ALGORITHM] = algorithms
entries[ProcessingLog.LOG_INFO] = info
entries[ProcessingLog.LOG_WARNING] = warnings
return entries

@staticmethod
Expand Down
7 changes: 4 additions & 3 deletions python/plugins/processing/gui/HistoryDialog.py
Expand Up @@ -54,11 +54,11 @@ def __init__(self):
self.keyIcon.addPixmap(self.style().standardPixmap(QStyle.SP_FileIcon))

self.clearButton = QPushButton(self.tr('Clear'))
self.clearButton.setToolTip(self.tr('Clear history and log'))
self.clearButton.setToolTip(self.tr('Clear history'))
self.buttonBox.addButton(self.clearButton, QDialogButtonBox.ActionRole)

self.saveButton = QPushButton(self.tr('Save As...'))
self.saveButton.setToolTip(self.tr('Save history and log'))
self.saveButton.setToolTip(self.tr('Save history'))
self.buttonBox.addButton(self.saveButton, QDialogButtonBox.ActionRole)

self.tree.doubleClicked.connect(self.executeAlgorithm)
Expand All @@ -74,7 +74,7 @@ def __init__(self):
def clearLog(self):
reply = QMessageBox.question(self,
self.tr('Confirmation'),
self.tr('Are you sure you want to clear log?'),
self.tr('Are you sure you want to clear the history?'),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
Expand Down Expand Up @@ -128,6 +128,7 @@ def createTest(self):
TestTools.createTest(item.entry.text)

def showPopupMenu(self, point):
return
item = self.tree.currentItem()
if isinstance(item, TreeLogEntryItem):
if item.isAlg:
Expand Down
11 changes: 9 additions & 2 deletions python/plugins/processing/gui/MessageDialog.py
Expand Up @@ -29,7 +29,9 @@

from PyQt4 import uic
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QDesktopServices
from PyQt4.QtGui import QDesktopServices, QDockWidget

from qgis.utils import iface

pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
Expand All @@ -51,4 +53,9 @@ def setMessage(self, message):
self.txtMessage.setHtml(message)

def openLink(self, url):
QDesktopServices.openUrl(QUrl(url))
if url.toString() == "log":
self.close()
logDock = iface.mainWindow().findChild(QDockWidget, 'MessageLog')
logDock.show()
else:
QDesktopServices.openUrl(url)
7 changes: 5 additions & 2 deletions python/plugins/processing/gui/Postprocessing.py
Expand Up @@ -71,7 +71,7 @@ def handleAlgorithmResults(alg, progress=None, showResults=True):
RenderingStyles.getStyle(alg.commandLineName(),
out.name))
except Exception, e:
wrongLayers.append(out)
wrongLayers.append(out.description)
elif isinstance(out, OutputHTML):
ProcessingResults.addResult(out.description, out.value)
htmlResults = True
Expand All @@ -80,7 +80,10 @@ def handleAlgorithmResults(alg, progress=None, showResults=True):
QApplication.restoreOverrideCursor()
dlg = MessageDialog()
dlg.setTitle(QCoreApplication.translate('Postprocessing', 'Problem loading output layers'))
dlg.setMessage(alg.getPostProcessingErrorMessage(wrongLayers))
msg = "The following layers were not correctly generated.<ul>"
msg += "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
msg += "You can check the <a href='log'>log messages</a> to find more information about the execution of the algorithm"
dlg.setMessage(msg)
dlg.exec_()

if showResults and htmlResults and not wrongLayers:
Expand Down

0 comments on commit 5a00912

Please sign in to comment.