From 887ba526750706082ce31589fbaaae38e421ca2b Mon Sep 17 00:00:00 2001 From: Serhii Moroz Date: Wed, 20 Jul 2016 21:24:00 +0300 Subject: [PATCH] Todo: added ability to filter todo list by keywords Change-Id: I4be35caf461e50e256527ca72993f5d83d08ef3e Reviewed-by: hjk --- src/plugins/todo/constants.h | 2 + src/plugins/todo/images/bug.png | Bin 0 -> 244 bytes src/plugins/todo/images/bug@2x.png | Bin 0 -> 449 bytes src/plugins/todo/images/bugfill.png | Bin 0 -> 159 bytes src/plugins/todo/images/bugfill@2x.png | Bin 0 -> 180 bytes src/plugins/todo/images/tasklist.png | Bin 0 -> 152 bytes src/plugins/todo/images/tasklist@2x.png | Bin 0 -> 165 bytes src/plugins/todo/images/todo.png | Bin 195 -> 165 bytes src/plugins/todo/keyworddialog.cpp | 8 +++ src/plugins/todo/optionsdialog.ui | 11 ++- src/plugins/todo/settings.cpp | 4 +- src/plugins/todo/todoicons.cpp | 22 +++++- src/plugins/todo/todoicons.h | 4 +- src/plugins/todo/todoitemsmodel.cpp | 1 + src/plugins/todo/todooutputpane.cpp | 92 ++++++++++++++++++++---- src/plugins/todo/todooutputpane.h | 12 +++- src/plugins/todo/todoplugin.cpp | 2 +- src/plugins/todo/todoplugin.qrc | 6 ++ 18 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 src/plugins/todo/images/bug.png create mode 100644 src/plugins/todo/images/bug@2x.png create mode 100644 src/plugins/todo/images/bugfill.png create mode 100644 src/plugins/todo/images/bugfill@2x.png create mode 100644 src/plugins/todo/images/tasklist.png create mode 100644 src/plugins/todo/images/tasklist@2x.png diff --git a/src/plugins/todo/constants.h b/src/plugins/todo/constants.h index b4598dd0b97..d597bc5c6fa 100644 --- a/src/plugins/todo/constants.h +++ b/src/plugins/todo/constants.h @@ -68,5 +68,7 @@ const int OUTPUT_TOOLBAR_SPACER_WIDTH = 25; const int OUTPUT_PANE_UPDATE_INTERVAL = 2000; const char OUTPUT_PANE_TITLE[] = QT_TRANSLATE_NOOP("Todo::Internal::TodoOutputPane", "To-Do Entries"); +const char FILTER_KEYWORD_NAME[] = "filterKeywordName"; + } // namespace Constants } // namespace Todo diff --git a/src/plugins/todo/images/bug.png b/src/plugins/todo/images/bug.png new file mode 100644 index 0000000000000000000000000000000000000000..68409e843af69179b84523840df41cadd6fc37ff GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AWM&J1pv>6x}I14-?iy0WWg+Z8+Vb&Z8 z1_lQ95>H=O_6O|30@50*c7_HsFfdH^ba4!kkYqi0Hj^okq2VBZzu+IuqhT#?4;-_3 z^ExrxV1gOTeN)FhK50tES*Q2TJiLcx?|S>H_m_eWeeU{^wXL&wbN>cCeI}0U>PG3; ze@Aa~i%-ekGW%0ziPChpcGo@AL>U=aQ vR&hKINWPY+5chgliQV=!ue%u-{xR}8t@~G!6H~#!z`)??>gTe~DWM4fJ%?OG literal 0 HcmV?d00001 diff --git a/src/plugins/todo/images/bug@2x.png b/src/plugins/todo/images/bug@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ac43ab381dbef482bed8713e2f2f64f56b5a1663 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWMny5veGCi?oCO|{#S9GG!XV7ZFl&wk z0|NtliKnkC`vZ1iK?W7>-#e}{Ffb-~x;TbdoL)O=W6&W75m)|=j8dz%ObPSKd}zQW zKXJmj^B#)1c83mKN?EXA!{W(@*yX%jujTTgWX>aIC+%Whc9H~a3vMHg~^ z|H}QdpKFqW$3C$c+S2b&$%yaam9}_rVMpz1u9~XumBn_!M)5W;Uf!9hSM?*c{o~Bi z{heof*Pc7pu6*zHwBz5z7yXNqJNQqVWy(GGS$%HbYnSU3{QAE5;unRZUl$%ORect_ z+G$oejmoA(yyZhCN&x`)oo#l^#0lP522{-SKAB+qP3_6}Jjv*Y^lPwNh zI8eaAVQ&z_ki_xl{0CW%|IQDqHCQ$se9>=vcz+ekumAE4a@Q64mb>1*%)r3F;OXk; Jvd$@?2>`EhEvo`sf19o8nYvmR1S5z`EFgSX;IEHXsPyTV> zL*qjxfx3o6|9S2=ey|s@Yv26u@P++VZT|(n$Xovk<`4S(-k!@TsGCK6;sffq}u()z4*}Q$iB}wO2fG literal 0 HcmV?d00001 diff --git a/src/plugins/todo/images/tasklist.png b/src/plugins/todo/images/tasklist.png new file mode 100644 index 0000000000000000000000000000000000000000..998484aab3a0678c42ccba8c36b9027bf94b30e3 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRdMrH;E#vrTMEes3{YymzYt_%ze|NsAAdUO6= z1_lPs0*}aI1_o|n5N2eUHAjMhfq}im)7O>#0TU~~oci0D_kS`lFsOREIEHXsPqsL~ z&?tXEf`wJ$pRo>0l0;00!hhpAiEI;3^!)$Nc<+_`-wB=5)EO8U7(8A5T-G@yGywpC Cp(>sL literal 0 HcmV?d00001 diff --git a/src/plugins/todo/images/tasklist@2x.png b/src/plugins/todo/images/tasklist@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c45ab36d0ba6168c212971954e795402a8e0d821 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMrH;EM!U^76d4#8*aCb)Tp1V`{{R2K^yd7# z3=9mM1s;*b3=G`DAk4@xYmNj10|R@Br>`sf1145pJ$5cr*)s88osVtB1zl)121zm9={ Ofx*+&&t;ucLK6UX5-iOC literal 0 HcmV?d00001 diff --git a/src/plugins/todo/images/todo.png b/src/plugins/todo/images/todo.png index 32160841b06e238b46415963bf5499df28228acd..80b4257017ff14d3958fd58d372abe7e702540d5 100644 GIT binary patch delta 68 zcmX@ixRh~%1Scai0|P_und~DI6+;Y|1AIbUFVdQ&MBb@0AQUFp8x;= delta 98 zcmZ3=c$jg51Sba*0|Ud2guDwA6+`?iJzX3_A`ZVj$H>dTz`?Ar^~LY)8`_E|H24Kg i_mNdr!2!NlZmB3{tc{*GQ;~szfx*+&&t;ucLK6Vv{T*}w diff --git a/src/plugins/todo/keyworddialog.cpp b/src/plugins/todo/keyworddialog.cpp index 721f65f6aba..bffa7775b7c 100644 --- a/src/plugins/todo/keyworddialog.cpp +++ b/src/plugins/todo/keyworddialog.cpp @@ -95,6 +95,14 @@ void KeywordDialog::setupListWidget(IconType selectedIcon) item->setData(Qt::UserRole, static_cast(IconType::Error)); ui->listWidget->addItem(item); + item = new QListWidgetItem(icon(IconType::Bug), QLatin1String("bug")); + item->setData(Qt::UserRole, static_cast(IconType::Bug)); + ui->listWidget->addItem(item); + + item = new QListWidgetItem(icon(IconType::Todo), QLatin1String("todo")); + item->setData(Qt::UserRole, static_cast(IconType::Todo)); + ui->listWidget->addItem(item); + for (int i = 0; i < ui->listWidget->count(); ++i) { item = ui->listWidget->item(i); if (static_cast(item->data(Qt::UserRole).toInt()) == selectedIcon) { diff --git a/src/plugins/todo/optionsdialog.ui b/src/plugins/todo/optionsdialog.ui index 321978494e3..6bbb38f1755 100644 --- a/src/plugins/todo/optionsdialog.ui +++ b/src/plugins/todo/optionsdialog.ui @@ -22,8 +22,17 @@ + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + QAbstractItemView::SelectRows + - true + false diff --git a/src/plugins/todo/settings.cpp b/src/plugins/todo/settings.cpp index 89dfef94091..bb6c9bdaffa 100644 --- a/src/plugins/todo/settings.cpp +++ b/src/plugins/todo/settings.cpp @@ -110,7 +110,7 @@ void Settings::setDefault() Keyword keyword; keyword.name = QLatin1String("TODO"); - keyword.iconType = IconType::Warning; + keyword.iconType = IconType::Todo; keyword.color = QColor(QLatin1String(Constants::COLOR_TODO_BG)); keywords.append(keyword); @@ -125,7 +125,7 @@ void Settings::setDefault() keywords.append(keyword); keyword.name = QLatin1String("BUG"); - keyword.iconType = IconType::Error; + keyword.iconType = IconType::Bug; keyword.color = QColor(QLatin1String(Constants::COLOR_BUG_BG)); keywords.append(keyword); diff --git a/src/plugins/todo/todoicons.cpp b/src/plugins/todo/todoicons.cpp index a0fcef3978e..41f3ac41986 100644 --- a/src/plugins/todo/todoicons.cpp +++ b/src/plugins/todo/todoicons.cpp @@ -23,11 +23,14 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ - +#include +#include #include #include "todoicons.h" +using namespace Utils; + namespace Todo { namespace Internal { @@ -42,6 +45,23 @@ QIcon icon(IconType type) const static QIcon icon = Core::Icons::WARNING.icon(); return icon; } + case IconType::Bug: { + const static QIcon icon = + Icon({ + {":/todoplugin/images/bugfill.png", Theme::BackgroundColorNormal}, + {":/todoplugin/images/bug.png", Theme::IconsInterruptToolBarColor} + }, Icon::Tint).icon(); + + return icon; + } + case IconType::Todo: { + const static QIcon icon = + Icon({ + {":/todoplugin/images/tasklist.png", Theme::IconsRunToolBarColor} + }, Icon::Tint).icon(); + return icon; + } + default: case IconType::Error: { const static QIcon icon = Core::Icons::ERROR.icon(); diff --git a/src/plugins/todo/todoicons.h b/src/plugins/todo/todoicons.h index 721c81df821..23cb15d951c 100644 --- a/src/plugins/todo/todoicons.h +++ b/src/plugins/todo/todoicons.h @@ -34,7 +34,9 @@ namespace Internal { enum class IconType { Info, Error, - Warning + Warning, + Bug, + Todo }; QIcon icon(IconType type); diff --git a/src/plugins/todo/todoitemsmodel.cpp b/src/plugins/todo/todoitemsmodel.cpp index 5cd1cca36e2..f9f3273092b 100644 --- a/src/plugins/todo/todoitemsmodel.cpp +++ b/src/plugins/todo/todoitemsmodel.cpp @@ -141,6 +141,7 @@ void TodoItemsModel::sort(int column, Qt::SortOrder order) m_currentSortOrder = order; TodoItemSortPredicate predicate(m_currentSortColumn, m_currentSortOrder); + emit layoutAboutToBeChanged(); Utils::sort(*m_todoItemsList, predicate); emit layoutChanged(); } diff --git a/src/plugins/todo/todooutputpane.cpp b/src/plugins/todo/todooutputpane.cpp index e0099626ee0..8add645b073 100644 --- a/src/plugins/todo/todooutputpane.cpp +++ b/src/plugins/todo/todooutputpane.cpp @@ -36,20 +36,22 @@ #include #include #include +#include namespace Todo { namespace Internal { -TodoOutputPane::TodoOutputPane(TodoItemsModel *todoItemsModel, QObject *parent) : +TodoOutputPane::TodoOutputPane(TodoItemsModel *todoItemsModel, const Settings *settings, QObject *parent) : IOutputPane(parent), - m_todoItemsModel(todoItemsModel) + m_todoItemsModel(todoItemsModel), + m_settings(settings) { createTreeView(); createScopeButtons(); setScanningScope(ScanningScopeCurrentFile); // default - connect(m_todoItemsModel, &TodoItemsModel::layoutChanged, + connect(m_todoTreeView->model(), &TodoItemsModel::layoutChanged, this, &TodoOutputPane::navigateStateUpdate); - connect(m_todoItemsModel, &TodoItemsModel::layoutChanged, + connect(m_todoTreeView->model(), &TodoItemsModel::layoutChanged, this, &TodoOutputPane::updateTodoCount); } @@ -67,7 +69,14 @@ QWidget *TodoOutputPane::outputWidget(QWidget *parent) QList TodoOutputPane::toolBarWidgets() const { - return { m_spacer, m_currentFileButton, m_wholeProjectButton, m_subProjectButton }; + QWidgetList widgets; + + for (QToolButton *btn: m_filterButtons) + widgets << btn; + + widgets << m_spacer << m_currentFileButton << m_wholeProjectButton << m_subProjectButton; + + return widgets; } QString TodoOutputPane::displayName() const @@ -82,6 +91,7 @@ int TodoOutputPane::priorityInStatusBar() const void TodoOutputPane::clearContents() { + clearFilter(); } void TodoOutputPane::visibilityChanged(bool visible) @@ -111,19 +121,19 @@ bool TodoOutputPane::canNavigate() const bool TodoOutputPane::canNext() const { - return m_todoTreeView->model()->rowCount() > 1; + return m_todoTreeView->model()->rowCount() > 0; } bool TodoOutputPane::canPrevious() const { - return m_todoTreeView->model()->rowCount() > 1; + return m_todoTreeView->model()->rowCount() > 0; } void TodoOutputPane::goToNext() { const QModelIndex nextIndex = nextModelIndex(); m_todoTreeView->selectionModel()->setCurrentIndex(nextIndex, QItemSelectionModel::SelectCurrent - | QItemSelectionModel::Rows); + | QItemSelectionModel::Rows | QItemSelectionModel::Clear); todoTreeViewClicked(nextIndex); } @@ -131,7 +141,7 @@ void TodoOutputPane::goToPrev() { const QModelIndex prevIndex = previousModelIndex(); m_todoTreeView->selectionModel()->setCurrentIndex(prevIndex, QItemSelectionModel::SelectCurrent - | QItemSelectionModel::Rows); + | QItemSelectionModel::Rows | QItemSelectionModel::Clear); todoTreeViewClicked(prevIndex); } @@ -147,7 +157,7 @@ void TodoOutputPane::setScanningScope(ScanningScope scanningScope) Q_ASSERT_X(false, "Updating scanning scope buttons", "Unknown scanning scope enum value"); } -void TodoOutputPane::scopeButtonClicked(QAbstractButton* button) +void TodoOutputPane::scopeButtonClicked(QAbstractButton *button) { if (button == m_currentFileButton) emit scanningScopeChanged(ScanningScopeCurrentFile); @@ -155,7 +165,7 @@ void TodoOutputPane::scopeButtonClicked(QAbstractButton* button) emit scanningScopeChanged(ScanningScopeSubProject); else if (button == m_wholeProjectButton) emit scanningScopeChanged(ScanningScopeProject); - setBadgeNumber(m_todoItemsModel->rowCount()); + setBadgeNumber(m_todoTreeView->model()->rowCount()); } void TodoOutputPane::todoTreeViewClicked(const QModelIndex &index) @@ -177,13 +187,44 @@ void TodoOutputPane::todoTreeViewClicked(const QModelIndex &index) void TodoOutputPane::updateTodoCount() { - setBadgeNumber(m_todoItemsModel->rowCount()); + setBadgeNumber(m_todoTreeView->model()->rowCount()); +} + +void TodoOutputPane::updateFilter() +{ + QStringList keywords; + for (QToolButton *btn: m_filterButtons) { + if (btn->isChecked()) + keywords.append(btn->property(Constants::FILTER_KEYWORD_NAME).toString()); + } + + QString pattern = keywords.isEmpty() ? QString() : QString("^(%1).*").arg(keywords.join('|')); + int sortColumn = m_todoTreeView->header()->sortIndicatorSection(); + Qt::SortOrder sortOrder = m_todoTreeView->header()->sortIndicatorOrder(); + + m_filteredTodoItemsModel->setFilterRegExp(pattern); + m_filteredTodoItemsModel->sort(sortColumn, sortOrder); + + updateTodoCount(); +} + +void TodoOutputPane::clearFilter() +{ + for (QToolButton *btn: m_filterButtons) + btn->setChecked(false); + + updateFilter(); } void TodoOutputPane::createTreeView() { + m_filteredTodoItemsModel = new QSortFilterProxyModel(); + m_filteredTodoItemsModel->setSourceModel(m_todoItemsModel); + m_filteredTodoItemsModel->setDynamicSortFilter(false); + m_filteredTodoItemsModel->setFilterKeyColumn(Constants::OUTPUT_COLUMN_TEXT); + m_todoTreeView = new TodoOutputTreeView(); - m_todoTreeView->setModel(m_todoItemsModel); + m_todoTreeView->setModel(m_filteredTodoItemsModel); Aggregation::Aggregate *agg = new Aggregation::Aggregate; agg->add(m_todoTreeView); agg->add(new Core::ItemViewFind(m_todoTreeView)); @@ -194,6 +235,19 @@ void TodoOutputPane::createTreeView() void TodoOutputPane::freeTreeView() { delete m_todoTreeView; + delete m_filteredTodoItemsModel; +} + +QToolButton *TodoOutputPane::createCheckableToolButton(const QString &text, const QString &toolTip, const QIcon &icon) +{ + QToolButton *button = new QToolButton(); + + button->setCheckable(true); + button->setText(text); + button->setToolTip(toolTip); + button->setIcon(icon); + + return button; } void TodoOutputPane::createScopeButtons() @@ -222,6 +276,16 @@ void TodoOutputPane::createScopeButtons() m_spacer = new QWidget; m_spacer->setMinimumWidth(Constants::OUTPUT_TOOLBAR_SPACER_WIDTH); + + QString tooltip = tr("Show \"%1\" entries"); + for (const Keyword &keyword: m_settings->keywords) { + QToolButton *button = createCheckableToolButton(keyword.name, tooltip.arg(keyword.name), icon(keyword.iconType)); + button->setProperty(Constants::FILTER_KEYWORD_NAME, keyword.name); + button->setToolButtonStyle(Qt::ToolButtonIconOnly); + connect(button, &QToolButton::clicked, this, &TodoOutputPane::updateFilter); + + m_filterButtons.append(button); + } } void TodoOutputPane::freeScopeButtons() @@ -231,6 +295,8 @@ void TodoOutputPane::freeScopeButtons() delete m_subProjectButton; delete m_scopeButtons; delete m_spacer; + + qDeleteAll(m_filterButtons); } QModelIndex TodoOutputPane::selectedModelIndex() diff --git a/src/plugins/todo/todooutputpane.h b/src/plugins/todo/todooutputpane.h index c534fce0498..c2ef23ec146 100644 --- a/src/plugins/todo/todooutputpane.h +++ b/src/plugins/todo/todooutputpane.h @@ -35,6 +35,7 @@ class QToolButton; class QButtonGroup; class QModelIndex; class QAbstractButton; +class QSortFilterProxyModel; QT_END_NAMESPACE namespace Todo { @@ -44,12 +45,14 @@ class TodoItem; class TodoItemsModel; class TodoOutputTreeView; +typedef QList QToolButtonList; + class TodoOutputPane : public Core::IOutputPane { Q_OBJECT public: - TodoOutputPane(TodoItemsModel *todoItemsModel, QObject *parent = 0); + TodoOutputPane(TodoItemsModel *todoItemsModel, const Settings *settings, QObject *parent = 0); ~TodoOutputPane(); QWidget *outputWidget(QWidget *parent); @@ -77,6 +80,8 @@ private: void scopeButtonClicked(QAbstractButton *button); void todoTreeViewClicked(const QModelIndex &index); void updateTodoCount(); + void updateFilter(); + void clearFilter(); void createTreeView(); void freeTreeView(); @@ -87,6 +92,8 @@ private: QModelIndex nextModelIndex(); QModelIndex previousModelIndex(); + QToolButton *createCheckableToolButton(const QString &text, const QString &toolTip, const QIcon &icon); + TodoOutputTreeView *m_todoTreeView; QToolButton *m_currentFileButton; QToolButton *m_wholeProjectButton; @@ -95,6 +102,9 @@ private: QButtonGroup *m_scopeButtons; QList *items; TodoItemsModel *m_todoItemsModel; + QSortFilterProxyModel *m_filteredTodoItemsModel; + const Settings *m_settings; + QToolButtonList m_filterButtons; }; } // namespace Internal diff --git a/src/plugins/todo/todoplugin.cpp b/src/plugins/todo/todoplugin.cpp index 475c04cc425..bbbe1a077ac 100644 --- a/src/plugins/todo/todoplugin.cpp +++ b/src/plugins/todo/todoplugin.cpp @@ -125,7 +125,7 @@ void TodoPlugin::createItemsProvider() void TodoPlugin::createTodoOutputPane() { - m_todoOutputPane = new TodoOutputPane(m_todoItemsProvider->todoItemsModel()); + m_todoOutputPane = new TodoOutputPane(m_todoItemsProvider->todoItemsModel(), &m_settings); addAutoReleasedObject(m_todoOutputPane); m_todoOutputPane->setScanningScope(m_settings.scanningScope); connect(m_todoOutputPane, &TodoOutputPane::scanningScopeChanged, diff --git a/src/plugins/todo/todoplugin.qrc b/src/plugins/todo/todoplugin.qrc index ac97a969436..b9e44626664 100644 --- a/src/plugins/todo/todoplugin.qrc +++ b/src/plugins/todo/todoplugin.qrc @@ -1,5 +1,11 @@ images/todo.png + images/tasklist@2x.png + images/tasklist.png + images/bug@2x.png + images/bug.png + images/bugfill.png + images/bugfill@2x.png