[processing] more friendly error message when layers not created

This commit includes changes to the log system as well, which now logs only algorithms. Messages are logged to the QGIS logging system
This commit is contained in:
volaya 2015-05-20 19:33:47 +02:00
parent 2e7f344214
commit 5a00912b3d
9 changed files with 35 additions and 113 deletions

View File

@ -81,7 +81,7 @@ class ProcessingPlugin:
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)

View File

@ -510,20 +510,3 @@ class GrassAlgorithm(GeoAlgorithm):
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

View File

@ -519,20 +519,3 @@ class Grass7Algorithm(GeoAlgorithm):
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

View File

@ -415,27 +415,4 @@ class RAlgorithm(GeoAlgorithm):
'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

View File

@ -525,38 +525,6 @@ class GeoAlgorithm:
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__

View File

@ -31,6 +31,7 @@ import codecs
import datetime
from processing.tools.system import userFolder
from processing.core.ProcessingConfig import ProcessingConfig
from qgis.core import *
class ProcessingLog:
@ -66,20 +67,15 @@ class ProcessingLog:
# 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)
@ -87,6 +83,13 @@ class ProcessingLog:
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
@ -113,10 +116,7 @@ class ProcessingLog:
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

View File

@ -54,11 +54,11 @@ class HistoryDialog(BASE, WIDGET):
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)
@ -74,7 +74,7 @@ class HistoryDialog(BASE, WIDGET):
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
)
@ -128,6 +128,7 @@ class HistoryDialog(BASE, WIDGET):
TestTools.createTest(item.entry.text)
def showPopupMenu(self, point):
return
item = self.tree.currentItem()
if isinstance(item, TreeLogEntryItem):
if item.isAlg:

View File

@ -29,7 +29,9 @@ import os
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(
@ -51,4 +53,9 @@ class MessageDialog(BASE, WIDGET):
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)

View File

@ -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
@ -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: