27#include <nlohmann/json.hpp>
30#include <QRegularExpression>
31#include <QRegularExpressionMatch>
43 return QStringLiteral(
"processing" );
48 const QString logPath = oldLogPath();
49 if ( !QFile::exists( logPath ) )
52 QFile logFile( logPath );
53 if ( logFile.open( QIODevice::ReadOnly ) )
55 QTextStream in( &logFile );
56 QList< QgsHistoryEntry > entries;
59 const QString line = in.readLine().trimmed();
60 QStringList parts = line.split( QStringLiteral(
"|~|" ) );
61 if ( parts.size() <= 1 )
62 parts = line.split(
'|' );
64 if ( parts.size() == 3 && parts.at( 0 ).startsWith( QLatin1String(
"ALGORITHM" ), Qt::CaseInsensitive ) )
67 details.insert( QStringLiteral(
"python_command" ), parts.at( 2 ) );
69 const thread_local QRegularExpression algIdRegEx( QStringLiteral(
"processing\\.run\\(\"(.*?)\"" ) );
70 const QRegularExpressionMatch match = algIdRegEx.match( parts.at( 2 ) );
71 if ( match.hasMatch() )
72 details.insert( QStringLiteral(
"algorithm_id" ), match.captured( 1 ) );
75 QDateTime::fromString( parts.at( 1 ), QStringLiteral(
"yyyy-MM-d hh:mm:ss" ) ),
92 , mAlgorithmId( mEntry.entry.value(
"algorithm_id" ).toString() )
93 , mPythonCommand( mEntry.entry.value(
"python_command" ).toString() )
94 , mProcessCommand( mEntry.entry.value(
"process_command" ).toString() )
95 , mProvider( provider )
98 const QVariant parameters = mEntry.entry.value( QStringLiteral(
"parameters" ) );
99 if ( parameters.type() == QVariant::Map )
101 const QVariantMap parametersMap = parameters.toMap();
102 mInputs = parametersMap.value( QStringLiteral(
"inputs" ) ).toMap();
108 mDescription = mPythonCommand;
111 if ( mDescription.length() > 300 )
113 mDescription = QObject::tr(
"%1…" ).arg( mDescription.left( 299 ) );
117 QVariant
data(
int role = Qt::DisplayRole )
const override
119 if ( mAlgorithmInformation.displayName.isEmpty() )
126 case Qt::DisplayRole:
128 const QString algName = mAlgorithmInformation.
displayName;
129 if ( !mDescription.isEmpty() )
130 return QStringLiteral(
"[%1] %2 - %3" ).arg( mEntry.timestamp.toString( QStringLiteral(
"yyyy-MM-dd hh:mm" ) ),
134 return QStringLiteral(
"[%1] %2" ).arg( mEntry.timestamp.toString( QStringLiteral(
"yyyy-MM-dd hh:mm" ) ),
138 case Qt::DecorationRole:
140 return mAlgorithmInformation.icon;
149 codeEditor->setReadOnly(
true );
150 codeEditor->setCaretLineVisible(
false );
153 codeEditor->setEdgeMode( QsciScintilla::EdgeNone );
154 codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord );
157 const QString introText = QStringLiteral(
"\"\"\"\n%1\n\"\"\"\n\n " ).arg(
158 QObject::tr(
"Double-click on the history item or paste the command below to re-run the algorithm" ) );
159 codeEditor->setText( introText + mPythonCommand );
166 if ( mPythonCommand.isEmpty() )
169 QString execAlgorithmDialogCommand = mPythonCommand;
170 execAlgorithmDialogCommand.replace( QLatin1String(
"processing.run(" ), QLatin1String(
"processing.execAlgorithmDialog(" ) );
173 const QStringList script =
175 QStringLiteral(
"import processing" ),
176 QStringLiteral(
"from qgis.core import QgsProcessingOutputLayerDefinition, QgsProcessingFeatureSourceDefinition, QgsProperty, QgsCoordinateReferenceSystem, QgsFeatureRequest" ),
177 QStringLiteral(
"from qgis.PyQt.QtCore import QDate, QTime, QDateTime" ),
178 QStringLiteral(
"from qgis.PyQt.QtGui import QColor" ),
179 execAlgorithmDialogCommand
182 mProvider->emitExecute( script.join(
'\n' ) );
188 if ( !mPythonCommand.isEmpty() )
190 QAction *pythonAction =
new QAction(
191 QObject::tr(
"Copy as Python Command" ), menu );
193 QObject::connect( pythonAction, &QAction::triggered, menu, [ = ]
195 copyText( mPythonCommand );
197 menu->addAction( pythonAction );
199 if ( !mProcessCommand.isEmpty() )
201 QAction *processAction =
new QAction(
202 QObject::tr(
"Copy as qgis_process Command" ), menu );
204 QObject::connect( processAction, &QAction::triggered, menu, [ = ]
206 copyText( mProcessCommand );
208 menu->addAction( processAction );
210 if ( !mInputs.isEmpty() )
212 QAction *inputsAction =
new QAction(
213 QObject::tr(
"Copy as JSON" ), menu );
215 QObject::connect( inputsAction, &QAction::triggered, menu, [ = ]
219 menu->addAction( inputsAction );
222 if ( !mPythonCommand.isEmpty() )
224 if ( !menu->isEmpty() )
226 menu->addSeparator();
229 QAction *createTestAction =
new QAction(
230 QObject::tr(
"Create Test…" ), menu );
231 QObject::connect( createTestAction, &QAction::triggered, menu, [ = ]
233 mProvider->emitCreateTest( mPythonCommand );
235 menu->addAction( createTestAction );
239 void copyText(
const QString &text )
241 QMimeData *m =
new QMimeData();
243 QApplication::clipboard()->setMimeData( m );
247 QString mAlgorithmId;
248 QString mPythonCommand;
249 QString mProcessCommand;
251 QString mDescription;
265QString QgsProcessingHistoryProvider::oldLogPath()
const
268 return userDir + QStringLiteral(
"/processing.log" );
271void QgsProcessingHistoryProvider::emitExecute(
const QString &commands )
276void 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 Python 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 QWidget * createWidget(const QgsHistoryWidgetContext &context)
Returns a new widget which should be shown to users when selecting the node.
virtual QVariant data(int role=Qt::DisplayRole) const =0
Returns the node's data for the specified model role.
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.
QString id() const override
Returns the provider's unique id, which is used to associate existing history entries with the provid...
friend class ProcessingHistoryNode
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.