diff --git a/outputview/CMakeLists.txt b/outputview/CMakeLists.txt --- a/outputview/CMakeLists.txt +++ b/outputview/CMakeLists.txt @@ -24,6 +24,7 @@ filtereditem.h outputmodel.h outputdelegate.h + outputfilteringstrategies.h ioutputviewmodel.h ifilterstrategy.h outputjob.h diff --git a/outputview/ifilterstrategy.h b/outputview/ifilterstrategy.h --- a/outputview/ifilterstrategy.h +++ b/outputview/ifilterstrategy.h @@ -1,6 +1,7 @@ /* Interface description for KDevelop OutputView Filter strategies Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com + Copyright (C) 2016 Kevin Funk This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +23,8 @@ #include "outputviewexport.h" -class QString; +#include +#include namespace KDevelop { @@ -38,10 +40,20 @@ class KDEVPLATFORMOUTPUTVIEW_EXPORT IFilterStrategy { public: - IFilterStrategy(); virtual ~IFilterStrategy(); + class Progress + { + public: + Progress(const QString& status = QString(), int percent = 0) + : status(status), percent(percent) + {} + + QString status; + int percent; + }; + /** * Examine if a given line contains output that is defined as an error (E.g. from a script or from a compiler, or other). * @param line the line to examine @@ -56,10 +68,24 @@ **/ virtual FilteredItem actionInLine(QString const& line) = 0; -}; - + /** + * Examine if a given line contains output which reports progress information + * + * E.g. `make` reports progress like this: + * @code + * [ 5%] Doing something + * [ 6%] Doing something + * @encode + * + * @return Processed percent & status of the output, default implementation returns default-constructed value + */ + virtual Progress progressInLine(const QString& line); +}; } // namespace KDevelop +Q_DECLARE_METATYPE(KDevelop::IFilterStrategy*) +Q_DECLARE_METATYPE(KDevelop::IFilterStrategy::Progress); + #endif // KDEVPLATFORM_IFILTERSTRATEGY_H diff --git a/outputview/ifilterstrategy.cpp b/outputview/ifilterstrategy.cpp --- a/outputview/ifilterstrategy.cpp +++ b/outputview/ifilterstrategy.cpp @@ -1,6 +1,7 @@ /* Interface description for KDevelop OutputView Filter strategies Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com + Copyright (C) 2016 Kevin Funk This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,4 +32,10 @@ { } +IFilterStrategy::Progress IFilterStrategy::progressInLine(const QString& line) +{ + Q_UNUSED(line); + return {}; +} + } diff --git a/outputview/outputexecutejob.h b/outputview/outputexecutejob.h --- a/outputview/outputexecutejob.h +++ b/outputview/outputexecutejob.h @@ -155,11 +155,16 @@ void setJobName( const QString& name ); /** - * Set the filtering strategy for the output model. + * Set one of the standard filtering strategies for the output model. */ void setFilteringStrategy( OutputModel::OutputFilterStrategy strategy ); /** + * Set the filtering strategy for the output model. + */ + void setFilteringStrategy(IFilterStrategy* filterStrategy); + + /** * Get the current properties of the job. * * @note Default-set properties are: \ref DisplayStdout. @@ -237,6 +242,7 @@ virtual void childProcessError( QProcess::ProcessError processError ); private: + friend class OutputExecuteJobPrivate; OutputExecuteJobPrivate* d; Q_PRIVATE_SLOT(d, void childProcessStdout()); diff --git a/outputview/outputexecutejob.cpp b/outputview/outputexecutejob.cpp --- a/outputview/outputexecutejob.cpp +++ b/outputview/outputexecutejob.cpp @@ -40,6 +40,8 @@ void childProcessStdout(); void childProcessStderr(); + void emitProgress(IFilterStrategy::Progress progress); + QString joinCommandLine() const; QString getJobName(); @@ -55,6 +57,7 @@ OutputExecuteJob::JobStatus m_status; OutputExecuteJob::JobProperties m_properties; OutputModel::OutputFilterStrategy m_filteringStrategy; + IFilterStrategy* m_filteringStrategyPtr; QStringList m_arguments; QStringList m_privilegedExecutionCommand; QUrl m_workingDirectory; @@ -221,9 +224,18 @@ } Q_ASSERT( model() ); - model()->setFilteringStrategy( d->m_filteringStrategy ); + if (d->m_filteringStrategy != OutputModel::NoFilter) { + model()->setFilteringStrategy(d->m_filteringStrategy); + } else { + model()->setFilteringStrategy(d->m_filteringStrategyPtr); + } + setDelegate( new OutputDelegate ); + connect(model(), &OutputModel::progress, this, [&](IFilterStrategy::Progress progress) { + d->emitProgress(progress); + }); + // Slots hasRawStdout() and hasRawStderr() are responsible // for feeding raw data to the line maker; so property-based channel filtering is implemented there. if( d->m_properties.testFlag( PostProcessOutput ) ) { @@ -368,6 +380,17 @@ } } +void OutputExecuteJobPrivate::emitProgress(IFilterStrategy::Progress progress) +{ + m_owner->emitPercent(progress.percent, 100); + + if (progress.percent == 100) { + m_owner->infoMessage(m_owner, i18n("Build finished")); + } else { + m_owner->infoMessage(m_owner, progress.status); + } +} + void OutputExecuteJob::postProcessStdout( const QStringList& lines ) { model()->appendLines( lines ); @@ -381,6 +404,18 @@ void OutputExecuteJob::setFilteringStrategy( OutputModel::OutputFilterStrategy strategy ) { d->m_filteringStrategy = strategy; + + // clear the other + delete d->m_filteringStrategyPtr; + d->m_filteringStrategyPtr = nullptr; +} + +void OutputExecuteJob::setFilteringStrategy(IFilterStrategy* filterStrategy) +{ + d->m_filteringStrategyPtr = filterStrategy; + + // clear the other + d->m_filteringStrategy = OutputModel::NoFilter; } OutputExecuteJob::JobProperties OutputExecuteJob::properties() const diff --git a/outputview/outputfilteringstrategies.h b/outputview/outputfilteringstrategies.h --- a/outputview/outputfilteringstrategies.h +++ b/outputview/outputfilteringstrategies.h @@ -26,7 +26,6 @@ #include "ifilterstrategy.h" -#include "outputformats.h" #include @@ -36,17 +35,19 @@ #include #include -#include +#include #include namespace KDevelop { +struct ErrorFormat; + /** * This filter strategy is for not applying any filtering at all. Implementation of the * interface methods are basically noops **/ -class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT NoFilterStrategy final : public IFilterStrategy +class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT NoFilterStrategy : public IFilterStrategy { public: @@ -62,7 +63,7 @@ * This filter stategy checks if a given line contains output * that is defined as an error (or an action) from a compiler. **/ -class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT CompilerFilterStrategy final : public IFilterStrategy +class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT CompilerFilterStrategy : public IFilterStrategy { public: @@ -75,6 +76,7 @@ QVector getCurrentDirs(); private: + // TODO: Pimpl KDevelop::Path pathForFile( const QString& ) const; bool isMultiLineCase(ErrorFormat curErrFilter) const; void putDirAtEnd(const KDevelop::Path& pathToInsert); @@ -89,7 +91,7 @@ /** * This filter stategy filters out errors (no actions) from Python and PHP scripts. **/ -class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT ScriptErrorFilterStrategy final : public IFilterStrategy +class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT ScriptErrorFilterStrategy : public IFilterStrategy { public: @@ -107,7 +109,7 @@ * This is especially useful for runtime output of Qt applications, for example lines such as: * "ASSERT: "errors().isEmpty()" in file /tmp/foo/bar.cpp", line 49" */ -class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT NativeAppErrorFilterStrategy final : public IFilterStrategy +class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT NativeAppErrorFilterStrategy : public IFilterStrategy { public: NativeAppErrorFilterStrategy(); @@ -119,7 +121,7 @@ /** * This filter stategy filters out errors (no actions) from Static code analysis tools (Cppcheck,) **/ -class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT StaticAnalysisFilterStrategy final : public IFilterStrategy +class KDEVPLATFORMOUTPUTVIEW_TEST_EXPORT StaticAnalysisFilterStrategy : public IFilterStrategy { public: diff --git a/outputview/outputmodel.h b/outputview/outputmodel.h --- a/outputview/outputmodel.h +++ b/outputview/outputmodel.h @@ -24,6 +24,7 @@ #include "outputviewexport.h" #include "ioutputviewmodel.h" +#include "ifilterstrategy.h" #include #include @@ -68,13 +69,16 @@ QVariant headerData( int, Qt::Orientation, int = Qt::DisplayRole ) const override; void setFilteringStrategy(const OutputFilterStrategy& currentStrategy); + void setFilteringStrategy(IFilterStrategy* filterStrategy); public Q_SLOTS: void appendLine( const QString& ); void appendLines( const QStringList& ); void ensureAllDone(); signals: + /// If the current filter strategy supports it, reports progress information + void progress(KDevelop::IFilterStrategy::Progress); void allDone(); private: diff --git a/outputview/outputmodel.cpp b/outputview/outputmodel.cpp --- a/outputview/outputmodel.cpp +++ b/outputview/outputmodel.cpp @@ -40,7 +40,6 @@ #include Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(KDevelop::IFilterStrategy*) namespace KDevelop { @@ -101,6 +100,7 @@ signals: void parsedBatch(const QVector& filteredItems); + void progress(KDevelop::IFilterStrategy::Progress progress); void allDone(); private slots: @@ -125,6 +125,12 @@ filteredItems << item; + auto progress = m_filter->progressInLine(line); + if (progress.percent > 0 && m_progress.percent != progress.percent) { + m_progress = progress; + emit this->progress(m_progress); + } + if( filteredItems.size() == BATCH_SIZE ) { emit parsedBatch(filteredItems); filteredItems.clear(); @@ -144,6 +150,7 @@ QStringList m_cachedLines; QTimer* m_timer; + IFilterStrategy::Progress m_progress; }; class ParsingThread @@ -209,11 +216,15 @@ { qRegisterMetaType >(); qRegisterMetaType(); + qRegisterMetaType(); + s_parsingThread->addWorker(worker); model->connect(worker, &ParseWorker::parsedBatch, model, [=] (const QVector& items) { linesParsed(items); }); model->connect(worker, &ParseWorker::allDone, model, &OutputModel::allDone); + model->connect(worker, &ParseWorker::progress, + model, &OutputModel::progress); } bool OutputModelPrivate::isValidIndex( const QModelIndex& idx, int currentRowCount ) const @@ -396,6 +407,12 @@ Q_ARG(KDevelop::IFilterStrategy*, filter)); } +void OutputModel::setFilteringStrategy(IFilterStrategy* filterStrategy) +{ + QMetaObject::invokeMethod(d->worker, "changeFilterStrategy", + Q_ARG(KDevelop::IFilterStrategy*, filterStrategy)); +} + void OutputModel::appendLines( const QStringList& lines ) { if( lines.isEmpty() )