Todo: added ability to filter todo list by keywords
Change-Id: I4be35caf461e50e256527ca72993f5d83d08ef3e Reviewed-by: hjk <hjk@qt.io>
@@ -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
|
||||
|
BIN
src/plugins/todo/images/bug.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
src/plugins/todo/images/bug@2x.png
Normal file
After Width: | Height: | Size: 449 B |
BIN
src/plugins/todo/images/bugfill.png
Normal file
After Width: | Height: | Size: 159 B |
BIN
src/plugins/todo/images/bugfill@2x.png
Normal file
After Width: | Height: | Size: 180 B |
BIN
src/plugins/todo/images/tasklist.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
src/plugins/todo/images/tasklist@2x.png
Normal file
After Width: | Height: | Size: 165 B |
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 165 B |
@@ -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,
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<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>
|
||||
|