Skip to content
Permalink
Browse files
[processing] Port algorithm log to new history provider API
No user visible changes, but we gain the flexibility for better
history storage, including the ability to store the outputs
calculated by the algorithm execution...!
  • Loading branch information
nyalldawson committed Dec 21, 2021
1 parent dd5cbb7 commit 5e5540c890982ea14a5641b3c5e4385cd8bde73d
@@ -24,6 +24,13 @@ Abstract base class for objects which track user history (i.e. operations perfor
%End
public:

%ConvertToSubClassCode
if ( dynamic_cast<QgsProcessingHistoryProvider *>( sipCpp ) )
sipType = sipType_QgsProcessingHistoryProvider;
else
sipType = nullptr;
%End

virtual ~QgsAbstractHistoryProvider();

virtual QString id() const = 0;
@@ -75,6 +75,7 @@ QgsHistoryProviderRegistry is not usually directly created, but rather accessed

~QgsHistoryProviderRegistry();


bool addProvider( QgsAbstractHistoryProvider *provider /Transfer/ );
%Docstring
Adds a ``provider`` to the registry. Ownership of the provider is
@@ -0,0 +1,47 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessinghistoryprovider.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsProcessingHistoryProvider : QgsAbstractHistoryProvider
{
%Docstring(signature="appended")
History provider for operations performed through the Processing framework.

.. versionadded:: 3.24
%End

%TypeHeaderCode
#include "qgsprocessinghistoryprovider.h"
%End
public:

QgsProcessingHistoryProvider();

virtual QString id() const;


void portOldLog();
%Docstring
Ports the old text log to the history framework.

This should only be called once -- calling multiple times will result in duplicate log entries
%End

};




/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessinghistoryprovider.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@@ -365,6 +365,7 @@
%Include auto_generated/processing/qgsprocessingalgorithmdialogbase.sip
%Include auto_generated/processing/qgsprocessinggui.sip
%Include auto_generated/processing/qgsprocessingguiregistry.sip
%Include auto_generated/processing/qgsprocessinghistoryprovider.sip
%Include auto_generated/processing/qgsprocessingmaplayercombobox.sip
%Include auto_generated/processing/qgsprocessingmodelerparameterwidget.sip
%Include auto_generated/processing/qgsprocessingmultipleselectiondialog.sip
@@ -34,8 +34,10 @@
QgsDataProvider,
QgsDataItem,
QgsMapLayerType,
QgsMimeDataUtils)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsMimeDataUtils,
QgsSettings)
from qgis.gui import (QgsGui,
QgsOptionsWidgetFactory,
QgsCustomDropHandler)
from qgis.PyQt.QtCore import QObject, Qt, QItemSelectionModel, QCoreApplication, QDir, QFileInfo, pyqtSlot
from qgis.PyQt.QtWidgets import QWidget, QMenu, QAction
@@ -184,6 +186,14 @@ def initProcessing(self):
Processing.initialize()

def initGui(self):
# port old log, ONCE ONLY!
settings = QgsSettings()
if not settings.value("/Processing/hasPortedOldLog", False, bool):
processing_history_provider = QgsGui.historyProviderRegistry().providerById('processing')
if processing_history_provider:
processing_history_provider.portOldLog()
settings.setValue("/Processing/hasPortedOldLog", True)

self.options_factory = ProcessingOptionsFactory()
self.options_factory.setTitle(self.tr('Processing'))
iface.registerOptionsWidgetFactory(self.options_factory)

This file was deleted.

@@ -42,7 +42,6 @@
QgsProcessingContextGenerator)
from qgis.utils import iface

from processing.core.ProcessingLog import ProcessingLog
from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.ProcessingResults import resultsList
from processing.gui.ParametersPanel import ParametersPanel
@@ -268,7 +267,10 @@ def elapsed_time(start_time, result):
else:
command = self.algorithm().asPythonCommand(parameters, self.context)
if command:
ProcessingLog.addToLog(command)
QgsGui.historyProviderRegistry().addEntry('processing', {
'python_command': command,
'algorithm_id': self.algorithm().id()
})
QgsGui.instance().processingRecentAlgorithmLog().push(self.algorithm().id())
self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel)

@@ -26,16 +26,15 @@
import re
from datetime import datetime

from qgis.core import QgsApplication
from qgis.gui import QgsGui, QgsHelp
from qgis.core import QgsApplication, Qgis
from qgis.gui import QgsGui, QgsHelp, QgsHistoryEntry
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDate
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDate, QDateTime
from qgis.PyQt.QtWidgets import QAction, QPushButton, QDialogButtonBox, QStyle, QMessageBox, QFileDialog, QMenu, QTreeWidgetItem, QShortcut
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.Qsci import QsciScintilla

from processing.gui import TestTools
from processing.core.ProcessingLog import ProcessingLog, LOG_SEPARATOR

pluginPath = os.path.split(os.path.dirname(__file__))[0]

@@ -46,6 +45,7 @@


class HistoryDialog(BASE, WIDGET):
LOG_SEPARATOR = '|~|'

def __init__(self):
super(HistoryDialog, self).__init__(None)
@@ -100,7 +100,7 @@ def clearLog(self):
QMessageBox.No
)
if reply == QMessageBox.Yes:
ProcessingLog.clearLog()
QgsGui.historyProviderRegistry().clearHistory(Qgis.HistoryProviderBackend.LocalProfile)
self.fillTree()

def saveLog(self):
@@ -113,30 +113,36 @@ def saveLog(self):
if not fileName.lower().endswith('.log'):
fileName += '.log'

ProcessingLog.saveLog(fileName)
entries = QgsGui.historyProviderRegistry().queryEntries(providerId='processing')
with open(fileName, 'w', encoding='utf-8') as f:
for entry in entries:
f.write('ALGORITHM{}{}{}{}\n'.format(HistoryDialog.LOG_SEPARATOR,
entry.timestamp.toString("YYYY-mm-dd HH:MM:SS"),
HistoryDialog.LOG_SEPARATOR,
entry.entry.get('python_command')))

def openHelp(self):
QgsHelp.openHelp("processing/history.html")

def contextDateString(self, date):
def contextDateString(self, date: QDateTime):
if date in self.contextDateStrings:
return self.contextDateStrings[date]

if date == datetime.today().strftime('%Y-%m-%d'):
if date.date() == QDateTime.currentDateTime().date():
self.contextDateStrings[date] = self.tr('Today')
else:
interval_days = (datetime.today() - datetime.strptime(date, '%Y-%m-%d')).days
interval_days = date.date().daysTo(QDateTime.currentDateTime().date())
if interval_days == 1:
self.contextDateStrings[date] = self.tr('Yesterday')
elif interval_days < 8:
self.contextDateStrings[date] = self.tr('Last 7 days')
else:
self.contextDateStrings[date] = QDate.fromString(date, 'yyyy-MM-dd').toString('MMMM yyyy')
self.contextDateStrings[date] = date.toString('MMMM yyyy')
return self.contextDateString(date)

def fillTree(self):
self.tree.clear()
entries = ProcessingLog.getLogEntries()
entries = QgsGui.historyProviderRegistry().queryEntries(providerId='processing')

if not entries:
return
@@ -147,7 +153,7 @@ def fillTree(self):
current_group_item = -1
current_date = ''
for entry in entries:
date = self.contextDateString(entry.date[0:10])
date = self.contextDateString(entry.timestamp)
if date != current_date:
current_date = date
current_group_item += 1
@@ -156,9 +162,8 @@ def fillTree(self):
group_items[current_group_item].setIcon(0, self.groupIcon)
icon = self.keyIcon
name = ''
match = re.search('processing.run\\("(.*?)"', entry.text)
if match.group:
algorithm_id = match.group(1)
algorithm_id = entry.entry.get('algorithm_id')
if algorithm_id:
if algorithm_id not in names:
algorithm = QgsApplication.processingRegistry().algorithmById(algorithm_id)
if algorithm:
@@ -185,23 +190,23 @@ def executeAlgorithm(self):
script += 'from qgis.core import QgsProcessingOutputLayerDefinition, QgsProcessingFeatureSourceDefinition, QgsProperty, QgsCoordinateReferenceSystem, QgsFeatureRequest\n'
script += 'from qgis.PyQt.QtCore import QDate, QTime, QDateTime\n'
script += 'from qgis.PyQt.QtGui import QColor\n'
script += item.entry.text.replace('processing.run(', 'processing.execAlgorithmDialog(')
script += item.python_command.replace('processing.run(', 'processing.execAlgorithmDialog(')
self.close()
exec(script)

def changeText(self):
item = self.tree.currentItem()
if isinstance(item, TreeLogEntryItem):
self.text.setText('"""\n' + self.tr('Double-click on the history item or paste the command below to re-run the algorithm') + '\n"""\n\n' +
item.entry.text.replace(LOG_SEPARATOR, '\n'))
item.python_command)
else:
self.text.setText('')

def createTest(self):
item = self.tree.currentItem()
if isinstance(item, TreeLogEntryItem):
if item.isAlg:
TestTools.createTest(item.entry.text)
TestTools.createTest(item.python_command)

def showPopupMenu(self, point):
item = self.tree.currentItem()
@@ -216,8 +221,9 @@ def showPopupMenu(self, point):

class TreeLogEntryItem(QTreeWidgetItem):

def __init__(self, entry, isAlg, algName):
def __init__(self, entry: QgsHistoryEntry, isAlg, algName):
QTreeWidgetItem.__init__(self)
self.entry = entry
self.isAlg = isAlg
self.setText(0, '[' + entry.date[:-3] + '] ' + algName + ' - ' + entry.text.split(LOG_SEPARATOR)[0])
self.python_command = entry.entry.get('python_command', '')
self.setText(0, '[' + entry.timestamp.toString('yyyy-MM-dd hh:mm') + '] ' + algName + ' - ' + self.python_command)
@@ -325,6 +325,7 @@ set(QGIS_GUI_SRCS
processing/qgsprocessingfeaturesourceoptionswidget.cpp
processing/qgsprocessingfieldmapwidgetwrapper.cpp
processing/qgsprocessingguiregistry.cpp
processing/qgsprocessinghistoryprovider.cpp
processing/qgsprocessingmaplayercombobox.cpp
processing/qgsprocessingmatrixmodelerwidget.cpp
processing/qgsprocessingmatrixparameterdialog.cpp
@@ -1150,6 +1151,7 @@ set(QGIS_GUI_HDRS
processing/qgsprocessingfieldmapwidgetwrapper.h
processing/qgsprocessinggui.h
processing/qgsprocessingguiregistry.h
processing/qgsprocessinghistoryprovider.h
processing/qgsprocessingmaplayercombobox.h
processing/qgsprocessingmatrixmodelerwidget.h
processing/qgsprocessingmatrixparameterdialog.h

0 comments on commit 5e5540c

Please sign in to comment.