diff --git a/python/PyQt6/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in b/python/PyQt6/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in index 0e2d50e421c8..6ebd566e919d 100644 --- a/python/PyQt6/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in +++ b/python/PyQt6/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in @@ -35,6 +35,8 @@ This should only be called once -- calling multiple times will result in duplica virtual QgsHistoryEntryNode *createNodeForEntry( const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ) /Factory/; + virtual void updateNodeForEntry( QgsHistoryEntryNode *node, const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ); + signals: diff --git a/python/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in b/python/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in index 0e2d50e421c8..6ebd566e919d 100644 --- a/python/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in +++ b/python/gui/auto_generated/processing/qgsprocessinghistoryprovider.sip.in @@ -35,6 +35,8 @@ This should only be called once -- calling multiple times will result in duplica virtual QgsHistoryEntryNode *createNodeForEntry( const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ) /Factory/; + virtual void updateNodeForEntry( QgsHistoryEntryNode *node, const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ); + signals: diff --git a/src/gui/processing/qgsprocessinghistoryprovider.cpp b/src/gui/processing/qgsprocessinghistoryprovider.cpp index 2aa47a050bd5..8b765780188c 100644 --- a/src/gui/processing/qgsprocessinghistoryprovider.cpp +++ b/src/gui/processing/qgsprocessinghistoryprovider.cpp @@ -22,6 +22,8 @@ #include "qgshistoryentrynode.h" #include "qgsprocessingregistry.h" #include "qgscodeeditorpython.h" +#include "qgscodeeditorshell.h" +#include "qgscodeeditorjson.h" #include "qgsjsonutils.h" #include @@ -83,11 +85,12 @@ void QgsProcessingHistoryProvider::portOldLog() ///@cond PRIVATE -class ProcessingHistoryNode : public QgsHistoryEntryGroup + +class ProcessingHistoryBaseNode : public QgsHistoryEntryGroup { public: - ProcessingHistoryNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) + ProcessingHistoryBaseNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) : mEntry( entry ) , mAlgorithmId( mEntry.entry.value( "algorithm_id" ).toString() ) , mPythonCommand( mEntry.entry.value( "python_command" ).toString() ) @@ -100,65 +103,7 @@ class ProcessingHistoryNode : public QgsHistoryEntryGroup { const QVariantMap parametersMap = parameters.toMap(); mInputs = parametersMap.value( QStringLiteral( "inputs" ) ).toMap(); - mDescription = QgsProcessingUtils::variantToPythonLiteral( mInputs ); - } - else - { - // an older history entry which didn't record inputs - mDescription = mPythonCommand; - } - - if ( mDescription.length() > 300 ) - { - mDescription = QObject::tr( "%1…" ).arg( mDescription.left( 299 ) ); - } - } - - QVariant data( int role = Qt::DisplayRole ) const override - { - if ( mAlgorithmInformation.displayName.isEmpty() ) - { - mAlgorithmInformation = QgsApplication::processingRegistry()->algorithmInformation( mAlgorithmId ); - } - - switch ( role ) - { - case Qt::DisplayRole: - { - const QString algName = mAlgorithmInformation.displayName; - if ( !mDescription.isEmpty() ) - return QStringLiteral( "[%1] %2 - %3" ).arg( mEntry.timestamp.toString( QStringLiteral( "yyyy-MM-dd hh:mm" ) ), - algName, - mDescription ); - else - return QStringLiteral( "[%1] %2" ).arg( mEntry.timestamp.toString( QStringLiteral( "yyyy-MM-dd hh:mm" ) ), - algName ); - } - - case Qt::DecorationRole: - { - return mAlgorithmInformation.icon; - } } - return QVariant(); - } - - QWidget *createWidget( const QgsHistoryWidgetContext & ) override - { - QgsCodeEditorPython *codeEditor = new QgsCodeEditorPython( ); - codeEditor->setReadOnly( true ); - codeEditor->setCaretLineVisible( false ); - codeEditor->setLineNumbersVisible( false ); - codeEditor->setFoldingVisible( false ); - codeEditor->setEdgeMode( QsciScintilla::EdgeNone ); - codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord ); - - - const QString introText = QStringLiteral( "\"\"\"\n%1\n\"\"\"\n\n " ).arg( - QObject::tr( "Double-click on the history item or paste the command below to re-run the algorithm" ) ); - codeEditor->setText( introText + mPythonCommand ); - - return codeEditor; } bool doubleClicked( const QgsHistoryWidgetContext & ) override @@ -248,18 +193,248 @@ class ProcessingHistoryNode : public QgsHistoryEntryGroup QString mPythonCommand; QString mProcessCommand; QVariantMap mInputs; - QString mDescription; - mutable QgsProcessingAlgorithmInformation mAlgorithmInformation; QgsProcessingHistoryProvider *mProvider = nullptr; }; +class ProcessingHistoryPythonCommandNode : public ProcessingHistoryBaseNode +{ + public: + + ProcessingHistoryPythonCommandNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) + : ProcessingHistoryBaseNode( entry, provider ) + {} + + QVariant data( int role = Qt::DisplayRole ) const override + { + switch ( role ) + { + case Qt::DisplayRole: + { + QString display = mPythonCommand; + if ( display.length() > 300 ) + { + display = QObject::tr( "%1…" ).arg( display.left( 299 ) ); + } + return display; + } + case Qt::DecorationRole: + return QgsApplication::getThemeIcon( QStringLiteral( "mIconPythonFile.svg" ) ); + + default: + break; + } + return QVariant(); + } + + QWidget *createWidget( const QgsHistoryWidgetContext & ) override + { + QgsCodeEditorPython *codeEditor = new QgsCodeEditorPython( ); + codeEditor->setReadOnly( true ); + codeEditor->setCaretLineVisible( false ); + codeEditor->setLineNumbersVisible( false ); + codeEditor->setFoldingVisible( false ); + codeEditor->setEdgeMode( QsciScintilla::EdgeNone ); + codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord ); + + + const QString introText = QStringLiteral( "\"\"\"\n%1\n\"\"\"\n\n " ).arg( + QObject::tr( "Double-click on the history item or paste the command below to re-run the algorithm" ) ); + codeEditor->setText( introText + mPythonCommand ); + + return codeEditor; + } +}; + +class ProcessingHistoryProcessCommandNode : public ProcessingHistoryBaseNode +{ + public: + + ProcessingHistoryProcessCommandNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) + : ProcessingHistoryBaseNode( entry, provider ) + {} + + QVariant data( int role = Qt::DisplayRole ) const override + { + switch ( role ) + { + case Qt::DisplayRole: + { + QString display = mProcessCommand; + if ( display.length() > 300 ) + { + display = QObject::tr( "%1…" ).arg( display.left( 299 ) ); + } + return display; + } + case Qt::DecorationRole: + return QgsApplication::getThemeIcon( QStringLiteral( "mActionTerminal.svg" ) ); + + default: + break; + } + return QVariant(); + } + + QWidget *createWidget( const QgsHistoryWidgetContext & ) override + { + QgsCodeEditorShell *codeEditor = new QgsCodeEditorShell( ); + codeEditor->setReadOnly( true ); + codeEditor->setCaretLineVisible( false ); + codeEditor->setLineNumbersVisible( false ); + codeEditor->setFoldingVisible( false ); + codeEditor->setEdgeMode( QsciScintilla::EdgeNone ); + codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord ); + + codeEditor->setText( mProcessCommand ); + + return codeEditor; + } +}; + + +class ProcessingHistoryJsonNode : public ProcessingHistoryBaseNode +{ + public: + + ProcessingHistoryJsonNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) + : ProcessingHistoryBaseNode( entry, provider ) + { + mJson = QString::fromStdString( QgsJsonUtils::jsonFromVariant( mInputs ).dump( 2 ) ); + mJsonSingleLine = QString::fromStdString( QgsJsonUtils::jsonFromVariant( mInputs ).dump() ); + } + + QVariant data( int role = Qt::DisplayRole ) const override + { + switch ( role ) + { + case Qt::DisplayRole: + { + QString display = mJsonSingleLine; + if ( display.length() > 300 ) + { + display = QObject::tr( "%1…" ).arg( display.left( 299 ) ); + } + return display; + } + case Qt::DecorationRole: + return QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldJson.svg" ) ); + + default: + break; + } + return QVariant(); + } + + QWidget *createWidget( const QgsHistoryWidgetContext & ) override + { + QgsCodeEditorJson *codeEditor = new QgsCodeEditorJson( ); + codeEditor->setReadOnly( true ); + codeEditor->setCaretLineVisible( false ); + codeEditor->setLineNumbersVisible( false ); + codeEditor->setFoldingVisible( false ); + codeEditor->setEdgeMode( QsciScintilla::EdgeNone ); + codeEditor->setWrapMode( QsciScintilla::WrapMode::WrapWord ); + + codeEditor->setText( mJson ); + + return codeEditor; + } + + QString mJson; + QString mJsonSingleLine; +}; + + +class ProcessingHistoryRootNode : public ProcessingHistoryBaseNode +{ + public: + + ProcessingHistoryRootNode( const QgsHistoryEntry &entry, QgsProcessingHistoryProvider *provider ) + : ProcessingHistoryBaseNode( entry, provider ) + { + const QVariant parameters = mEntry.entry.value( QStringLiteral( "parameters" ) ); + if ( parameters.type() == QVariant::Map ) + { + mDescription = QgsProcessingUtils::variantToPythonLiteral( mInputs ); + } + else + { + // an older history entry which didn't record inputs + mDescription = mPythonCommand; + } + + if ( mDescription.length() > 300 ) + { + mDescription = QObject::tr( "%1…" ).arg( mDescription.left( 299 ) ); + } + + addChild( new ProcessingHistoryPythonCommandNode( mEntry, mProvider ) ); + addChild( new ProcessingHistoryProcessCommandNode( mEntry, mProvider ) ); + addChild( new ProcessingHistoryJsonNode( mEntry, mProvider ) ); + } + + void setEntry( const QgsHistoryEntry &entry ) + { + mEntry = entry; + } + + QVariant data( int role = Qt::DisplayRole ) const override + { + if ( mAlgorithmInformation.displayName.isEmpty() ) + { + mAlgorithmInformation = QgsApplication::processingRegistry()->algorithmInformation( mAlgorithmId ); + } + + switch ( role ) + { + case Qt::DisplayRole: + { + const QString algName = mAlgorithmInformation.displayName; + if ( !mDescription.isEmpty() ) + return QStringLiteral( "[%1] %2 - %3" ).arg( mEntry.timestamp.toString( QStringLiteral( "yyyy-MM-dd hh:mm" ) ), + algName, + mDescription ); + else + return QStringLiteral( "[%1] %2" ).arg( mEntry.timestamp.toString( QStringLiteral( "yyyy-MM-dd hh:mm" ) ), + algName ); + } + + case Qt::DecorationRole: + { + return mAlgorithmInformation.icon; + } + + default: + break; + } + return QVariant(); + } + + QString html( const QgsHistoryWidgetContext & ) const override + { + return mEntry.entry.value( QStringLiteral( "log" ) ).toString(); + } + + QString mDescription; + mutable QgsProcessingAlgorithmInformation mAlgorithmInformation; + +}; + ///@endcond QgsHistoryEntryNode *QgsProcessingHistoryProvider::createNodeForEntry( const QgsHistoryEntry &entry, const QgsHistoryWidgetContext & ) { - return new ProcessingHistoryNode( entry, this ); + return new ProcessingHistoryRootNode( entry, this ); +} + +void QgsProcessingHistoryProvider::updateNodeForEntry( QgsHistoryEntryNode *node, const QgsHistoryEntry &entry, const QgsHistoryWidgetContext & ) +{ + if ( ProcessingHistoryRootNode *rootNode = dynamic_cast< ProcessingHistoryRootNode * >( node ) ) + { + rootNode->setEntry( entry ); + } } QString QgsProcessingHistoryProvider::oldLogPath() const diff --git a/src/gui/processing/qgsprocessinghistoryprovider.h b/src/gui/processing/qgsprocessinghistoryprovider.h index 03f74ddc8097..c24fe3db6a1f 100644 --- a/src/gui/processing/qgsprocessinghistoryprovider.h +++ b/src/gui/processing/qgsprocessinghistoryprovider.h @@ -45,6 +45,7 @@ class GUI_EXPORT QgsProcessingHistoryProvider : public QgsAbstractHistoryProvide void portOldLog(); QgsHistoryEntryNode *createNodeForEntry( const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ) override SIP_FACTORY; + void updateNodeForEntry( QgsHistoryEntryNode *node, const QgsHistoryEntry &entry, const QgsHistoryWidgetContext &context ) override; signals: @@ -72,7 +73,7 @@ class GUI_EXPORT QgsProcessingHistoryProvider : public QgsAbstractHistoryProvide //! Returns the path to the old log file QString oldLogPath() const; - friend class ProcessingHistoryNode; + friend class ProcessingHistoryBaseNode; };