diff --git a/kdevplatform/shell/problemmodel.h b/kdevplatform/shell/problemmodel.h --- a/kdevplatform/shell/problemmodel.h +++ b/kdevplatform/shell/problemmodel.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace KDevelop { class IDocument; @@ -130,6 +131,20 @@ /// Retrieve problems for selected document QVector problems(const KDevelop::IndexedString& document) const; + /** + * Add new "placeholder" item (problem). The item will be displayed whenever the model is empty. + * + * The method should be used to notify user about some events. For example, analyzer plugin + * can set placeholders at analysis state changes - started/finished without errors/etc. + * + * \param[in] text Sets problem description. + * \param[in] location Sets problem final location. + * \param[in] source Sets problem source string. + */ + void setPlaceholderText(const QString& text, + const KDevelop::DocumentRange& location = KDevelop::DocumentRange::invalid(), + const QString& source = QString()); + /// Retrieve the supported features Features features() const; diff --git a/kdevplatform/shell/problemmodel.cpp b/kdevplatform/shell/problemmodel.cpp --- a/kdevplatform/shell/problemmodel.cpp +++ b/kdevplatform/shell/problemmodel.cpp @@ -68,12 +68,29 @@ : m_problems(store) , m_features(KDevelop::ProblemModel::NoFeatures) , m_fullUpdateTooltip(i18nc("@info:tooltip", "Re-parse all watched documents")) + , m_isPlaceholderShown(false) { } + KDevelop::IProblem::Ptr createPlaceholdreProblem() const + { + Q_ASSERT(!m_placeholderText.isEmpty()); + + KDevelop::IProblem::Ptr problem(new KDevelop::DetectedProblem(m_placeholderSource)); + problem->setDescription(m_placeholderText); + problem->setFinalLocation(m_placeholderLocation); + problem->setSeverity(KDevelop::IProblem::Hint); + + return problem; + } + QScopedPointer m_problems; KDevelop::ProblemModel::Features m_features; QString m_fullUpdateTooltip; + QString m_placeholderText; + QString m_placeholderSource; + KDevelop::DocumentRange m_placeholderLocation; + bool m_isPlaceholderShown; }; @@ -253,25 +270,51 @@ emit fullUpdateTooltipChanged(); } +void ProblemModel::setPlaceholderText( + const QString& text, + const KDevelop::DocumentRange& location, + const QString& source) +{ + d->m_placeholderText = text; + d->m_placeholderLocation = location; + d->m_placeholderSource = source; + + if (d->m_isPlaceholderShown) { + clearProblems(); + } else if (d->m_problems->count() == 0) { + setProblems({}); + } +} + void ProblemModel::addProblem(const IProblem::Ptr &problem) { - int c = d->m_problems->count(); - beginInsertRows(QModelIndex(), c, c); - d->m_problems->addProblem(problem); - endInsertRows(); + if (d->m_isPlaceholderShown) { + setProblems({ problem }); + } else { + int c = d->m_problems->count(); + beginInsertRows(QModelIndex(), c, c); + d->m_problems->addProblem(problem); + endInsertRows(); + } } void ProblemModel::setProblems(const QVector &problems) { beginResetModel(); - d->m_problems->setProblems(problems); + if (problems.isEmpty() && !d->m_placeholderText.isEmpty()) { + d->m_problems->setProblems({ d->createPlaceholdreProblem() }); + d->m_isPlaceholderShown = true; + } else { + d->m_problems->setProblems(problems); + d->m_isPlaceholderShown = false; + } endResetModel(); } void ProblemModel::clearProblems() { beginResetModel(); - d->m_problems->clear(); + setProblems({}); endResetModel(); } diff --git a/kdevplatform/shell/tests/test_problemmodel.cpp b/kdevplatform/shell/tests/test_problemmodel.cpp --- a/kdevplatform/shell/tests/test_problemmodel.cpp +++ b/kdevplatform/shell/tests/test_problemmodel.cpp @@ -49,6 +49,7 @@ void testNoGrouping(); void testPathGrouping(); void testSeverityGrouping(); + void testPlaceholderText(); private: void generateProblems(); @@ -362,6 +363,61 @@ m_model->clearProblems(); } +void TestProblemModel::testPlaceholderText() +{ + const QString text1 = QStringLiteral("testPlaceholderText1"); + const QString text2 = QStringLiteral("testPlaceholderText2"); + const QString empty; + + m_model->setGrouping(NoGrouping); + + // Test model with empty placeholder text + + QCOMPARE(m_model->rowCount(), 0); + m_model->setPlaceholderText(empty); + QCOMPARE(m_model->rowCount(), 0); + m_model->setProblems(m_problems); + QCOMPARE(m_model->rowCount(), 3); + m_model->clearProblems(); + QCOMPARE(m_model->rowCount(), 0); + + // Test empty model with non-empty placeholder text + + m_model->setPlaceholderText(text1); + QCOMPARE(m_model->rowCount(), 1); + QVERIFY(checkLabel(0, QModelIndex(), text1)); + + m_model->setPlaceholderText(text2); + QCOMPARE(m_model->rowCount(), 1); + QVERIFY(checkLabel(0, QModelIndex(), text2)); + + // Test non-empty model with non-empty placeholder text + + m_model->setProblems(m_problems); + QCOMPARE(m_model->rowCount(), 3); + + m_model->clearProblems(); + QCOMPARE(m_model->rowCount(), 1); + QVERIFY(checkLabel(0, QModelIndex(), text2)); + + m_model->addProblem(m_problems[0]); + QCOMPARE(m_model->rowCount(), 1); + QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0])); + + m_model->addProblem(m_problems[1]); + QCOMPARE(m_model->rowCount(), 2); + QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1])); + + m_model->setPlaceholderText(text1); + QCOMPARE(m_model->rowCount(), 2); + QVERIFY(checkIsSame(0, QModelIndex(), m_problems[0])); + QVERIFY(checkIsSame(1, QModelIndex(), m_problems[1])); + + m_model->setProblems({}); + QCOMPARE(m_model->rowCount(), 1); + QVERIFY(checkLabel(0, QModelIndex(), text1)); +} + // Generate 3 problems, all with different paths, different severity // Also generates a problem with diagnostics void TestProblemModel::generateProblems()