Commit 887ba526 authored by Serhii Moroz's avatar Serhii Moroz
Browse files

Todo: added ability to filter todo list by keywords



Change-Id: I4be35caf461e50e256527ca72993f5d83d08ef3e
Reviewed-by: default avatarhjk <hjk@qt.io>
parent c94ce7b2
......@@ -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
src/plugins/todo/images/todo.png

195 Bytes | W: | H:

src/plugins/todo/images/todo.png

165 Bytes | W: | H:

src/plugins/todo/images/todo.png
src/plugins/todo/images/todo.png
src/plugins/todo/images/todo.png
src/plugins/todo/images/todo.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -95,6 +95,14 @@ void KeywordDialog::setupListWidget(IconType selectedIcon)
item->setData(Qt::UserRole, static_cast<int>(IconType::Error));
ui->listWidget->addItem(item);
item = new QListWidgetItem(icon(IconType::Bug), QLatin1String("bug"));
item->setData(Qt::UserRole, static_cast<int>(IconType::Bug));
ui->listWidget->addItem(item);
item = new QListWidgetItem(icon(IconType::Todo), QLatin1String("todo"));
item->setData(Qt::UserRole, static_cast<int>(IconType::Todo));
ui->listWidget->addItem(item);
for (int i = 0; i < ui->listWidget->count(); ++i) {
item = ui->listWidget->item(i);
if (static_cast<IconType>(item->data(Qt::UserRole).toInt()) == selectedIcon) {
......
......@@ -22,8 +22,17 @@
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QListWidget" name="keywordsList">
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
......
......@@ -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);
......
......@@ -23,11 +23,14 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <utils/icon.h>
#include <utils/theme/theme.h>
#include <coreplugin/coreicons.h>
#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();
......
......@@ -34,7 +34,9 @@ namespace Internal {
enum class IconType {
Info,
Error,
Warning
Warning,
Bug,
Todo
};
QIcon icon(IconType type);
......
......@@ -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();
}
......
......@@ -36,20 +36,22 @@
#include <QHeaderView>
#include <QToolButton>
#include <QButtonGroup>
#include <QSortFilterProxyModel>
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<QWidget*> 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()
......
......@@ -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<QToolButton*> 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<TodoItem> *items;
TodoItemsModel *m_todoItemsModel;
QSortFilterProxyModel *m_filteredTodoItemsModel;
const Settings *m_settings;
QToolButtonList m_filterButtons;
};
} // namespace Internal
......
......@@ -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,
......
<RCC>
<qresource prefix="/todoplugin">
<file>images/todo.png</file>
<file>images/tasklist@2x.png</file>
<file>images/tasklist.png</file>
<file>images/bug@2x.png</file>
<file>images/bug.png</file>
<file>images/bugfill.png</file>
<file>images/bugfill@2x.png</file>
</qresource>
</RCC>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment