18#include "moc_qgsprocessinghistoryprovider.cpp"
30#include <nlohmann/json.hpp>
33#include <QRegularExpression>
34#include <QRegularExpressionMatch>
46 return QStringLiteral(
"processing" );
51 const QString logPath = oldLogPath();
52 if ( !QFile::exists( logPath ) )
55 QFile logFile( logPath );
56 if ( logFile.open( QIODevice::ReadOnly ) )
58 QTextStream in( &logFile );
59 QList< QgsHistoryEntry > entries;
62 const QString line = in.readLine().trimmed();
63 QStringList parts = line.split( QStringLiteral(
"|~|" ) );
64 if ( parts.size() <= 1 )
65 parts = line.split(
'|' );
67 if ( parts.size() == 3 && parts.at( 0 ).startsWith( QLatin1String(
"ALGORITHM" ), Qt::CaseInsensitive ) )
70 details.insert( QStringLiteral(
"python_command" ), parts.at( 2 ) );
72 const thread_local QRegularExpression algIdRegEx( QStringLiteral(
"processing\\.run\\(\"(.*?)\"" ) );
73 const QRegularExpressionMatch match = algIdRegEx.match( parts.at( 2 ) );
74 if ( match.hasMatch() )
75 details.insert( QStringLiteral(
"algorithm_id" ), match.captured( 1 ) );
78 QDateTime::fromString( parts.at( 1 ), QStringLiteral(
"yyyy-MM-d hh:mm:ss" ) ),
96 , mAlgorithmId( mEntry.entry.value(
"algorithm_id" ).toString() )
97 , mPythonCommand( mEntry.entry.value(
"python_command" ).toString() )
98 , mProcessCommand( mEntry.entry.value(
"process_command" ).toString() )
99 , mProvider( provider )
102 const QVariant parameters = mEntry.entry.value( QStringLiteral(
"parameters" ) );
103 if ( parameters.userType() == QMetaType::Type::QVariantMap )
105 const QVariantMap parametersMap = parameters.toMap();
106 mInputs = parametersMap.value( QStringLiteral(
"inputs" ) ).toMap();
112 if ( mPythonCommand.isEmpty() )
115 QString execAlgorithmDialogCommand = mPythonCommand;
116 execAlgorithmDialogCommand.replace( QLatin1String(
"processing.run(" ), QLatin1String(
"processing.execAlgorithmDialog(" ) );
119 const QStringList script =
121 QStringLiteral(
"import processing" ),
122 QStringLiteral(
"from qgis.core import QgsProcessingOutputLayerDefinition, QgsProcessingFeatureSourceDefinition, QgsProperty, QgsCoordinateReferenceSystem, QgsFeatureRequest" ),
123 QStringLiteral(
"from qgis.PyQt.QtCore import QDate, QTime, QDateTime" ),
124 QStringLiteral(
"from qgis.PyQt.QtGui import QColor" ),
125 execAlgorithmDialogCommand
128 mProvider->emitExecute( script.join(
'\n' ) );
134 if ( !mPythonCommand.isEmpty() )
136 QAction *pythonAction =
new QAction(
137 QObject::tr(
"Copy as Python Command" ), menu );
139 QObject::connect( pythonAction, &QAction::triggered, menu, [ = ]
141 copyText( mPythonCommand );
143 menu->addAction( pythonAction );
145 if ( !mProcessCommand.isEmpty() )
147 QAction *processAction =
new QAction(
148 QObject::tr(
"Copy as qgis_process Command" ), menu );
150 QObject::connect( processAction, &QAction::triggered, menu, [ = ]
152 copyText( mProcessCommand );
154 menu->addAction( processAction );
156 if ( !mInputs.isEmpty() )
158 QAction *inputsAction =
new QAction(
159 QObject::tr(
"Copy as JSON" ), menu );
161 QObject::connect( inputsAction, &QAction::triggered, menu, [ = ]
165 menu->addAction( inputsAction );
168 if ( !mPythonCommand.isEmpty() )
170 if ( !menu->isEmpty() )
172 menu->addSeparator();
175 QAction *createTestAction =
new QAction(
176 QObject::tr(
"Create Test…" ), menu );
177 QObject::connect( createTestAction, &QAction::triggered, menu, [ = ]
179 mProvider->emitCreateTest( mPythonCommand );
181 menu->addAction( createTestAction );
185 void copyText(
const QString &text )
187 QMimeData *m =
new QMimeData();
189 QApplication::clipboard()->setMimeData( m );
193 QString mAlgorithmId;
194 QString mPythonCommand;
195 QString mProcessCommand;
202class ProcessingHistoryPythonCommandNode :
public ProcessingHistoryBaseNode
207 : ProcessingHistoryBaseNode( entry, provider )
210 QVariant data(
int role = Qt::DisplayRole )
const override
214 case Qt::DisplayRole:
216 QString display = mPythonCommand;
217 if ( display.length() > 300 )
219 display = QObject::tr(
"%1…" ).arg( display.left( 299 ) );
223 case Qt::DecorationRole:
235 codeEditor->setReadOnly(
true );
236 codeEditor->setCaretLineVisible(
false );
239 codeEditor->setEdgeMode( QsciScintilla::EdgeNone );
240 codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord );
243 const QString introText = QStringLiteral(
"\"\"\"\n%1\n\"\"\"\n\n " ).arg(
244 QObject::tr(
"Double-click on the history item or paste the command below to re-run the algorithm" ) );
245 codeEditor->setText( introText + mPythonCommand );
251class ProcessingHistoryProcessCommandNode :
public ProcessingHistoryBaseNode
256 : ProcessingHistoryBaseNode( entry, provider )
259 QVariant data(
int role = Qt::DisplayRole )
const override
263 case Qt::DisplayRole:
265 QString display = mProcessCommand;
266 if ( display.length() > 300 )
268 display = QObject::tr(
"%1…" ).arg( display.left( 299 ) );
272 case Qt::DecorationRole:
284 codeEditor->setReadOnly(
true );
285 codeEditor->setCaretLineVisible(
false );
288 codeEditor->setEdgeMode( QsciScintilla::EdgeNone );
289 codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord );
291 codeEditor->setText( mProcessCommand );
298class ProcessingHistoryJsonNode :
public ProcessingHistoryBaseNode
303 : ProcessingHistoryBaseNode( entry, provider )
309 QVariant data(
int role = Qt::DisplayRole )
const override
313 case Qt::DisplayRole:
315 QString display = mJsonSingleLine;
316 if ( display.length() > 300 )
318 display = QObject::tr(
"%1…" ).arg( display.left( 299 ) );
322 case Qt::DecorationRole:
334 codeEditor->setReadOnly(
true );
335 codeEditor->setCaretLineVisible(
false );
338 codeEditor->setEdgeMode( QsciScintilla::EdgeNone );
339 codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord );
341 codeEditor->setText( mJson );
347 QString mJsonSingleLine;
351class ProcessingHistoryRootNode :
public ProcessingHistoryBaseNode
356 : ProcessingHistoryBaseNode( entry, provider )
358 const QVariant parameters = mEntry.entry.value( QStringLiteral(
"parameters" ) );
359 if ( parameters.type() == QVariant::Map )
366 mDescription = mPythonCommand;
369 if ( mDescription.length() > 300 )
371 mDescription = QObject::tr(
"%1…" ).arg( mDescription.left( 299 ) );
374 addChild(
new ProcessingHistoryPythonCommandNode( mEntry, mProvider ) );
375 addChild(
new ProcessingHistoryProcessCommandNode( mEntry, mProvider ) );
376 addChild(
new ProcessingHistoryJsonNode( mEntry, mProvider ) );
384 QVariant data(
int role = Qt::DisplayRole )
const override
386 if ( mAlgorithmInformation.displayName.isEmpty() )
393 case Qt::DisplayRole:
395 const QString algName = mAlgorithmInformation.
displayName;
396 if ( !mDescription.isEmpty() )
397 return QStringLiteral(
"[%1] %2 - %3" ).arg( mEntry.timestamp.toString( QStringLiteral(
"yyyy-MM-dd hh:mm" ) ),
401 return QStringLiteral(
"[%1] %2" ).arg( mEntry.timestamp.toString( QStringLiteral(
"yyyy-MM-dd hh:mm" ) ),
405 case Qt::DecorationRole:
407 return mAlgorithmInformation.icon;
418 return mEntry.entry.value( QStringLiteral(
"log" ) ).toString();
421 QString mDescription;
430 return new ProcessingHistoryRootNode( entry,
this );
435 if ( ProcessingHistoryRootNode *rootNode =
dynamic_cast< ProcessingHistoryRootNode *
>( node ) )
437 rootNode->setEntry( entry );
441QString QgsProcessingHistoryProvider::oldLogPath()
const
444 return userDir + QStringLiteral(
"/processing.log" );
447void QgsProcessingHistoryProvider::emitExecute(
const QString &commands )
452void QgsProcessingHistoryProvider::emitCreateTest(
const QString &command )
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
A JSON editor based on QScintilla2.
A Python editor based on QScintilla2.
A shell script code editor based on QScintilla2.
void setFoldingVisible(bool folding)
Set whether the folding controls are visible in the editor.
void setLineNumbersVisible(bool visible)
Sets whether line numbers should be visible in the editor.
static QgsHistoryProviderRegistry * historyProviderRegistry()
Returns the global history provider registry, used for tracking history providers.
Base class for history entry "group" nodes, which contain children of their own.
Base class for nodes representing a QgsHistoryEntry.
virtual void populateContextMenu(QMenu *menu, const QgsHistoryWidgetContext &context)
Allows the node to populate a context menu before display to the user.
virtual bool doubleClicked(const QgsHistoryWidgetContext &context)
Called when the node is double-clicked.
Encapsulates a history entry.
bool addEntries(const QList< QgsHistoryEntry > &entries, QgsHistoryProviderRegistry::HistoryEntryOptions options=QgsHistoryProviderRegistry::HistoryEntryOptions())
Adds a list of entries to the history logs.
Contains settings which reflect the context in which a history widget is shown, e....
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
History provider for operations performed through the Processing framework.
void updateNodeForEntry(QgsHistoryEntryNode *node, const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context) override
Updates an existing history node for the given entry.
QString id() const override
Returns the provider's unique id, which is used to associate existing history entries with the provid...
void executePython(const QString &commands)
Emitted when the provider needs to execute python commands in the Processing context.
QgsHistoryEntryNode * createNodeForEntry(const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context) override
Creates a new history node for the given entry.
void createTest(const QString &command)
Emitted when the provider needs to create a Processing test with the given python command.
void portOldLog()
Ports the old text log to the history framework.
QgsProcessingHistoryProvider()
QgsProcessingAlgorithmInformation algorithmInformation(const QString &id) const
Returns basic algorithm information for the algorithm with matching ID.
static QString variantToPythonLiteral(const QVariant &value)
Converts a variant to a Python literal.