Files
qt-creator/src/plugins/projectexplorer/taskwindow.cpp

969 lines
29 KiB
C++
Raw Normal View History

/**************************************************************************
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator
**
2010-03-05 11:25:49 +01:00
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
2008-12-02 12:01:29 +01:00
**
** Contact: Nokia Corporation (qt-info@nokia.com)
2008-12-02 12:01:29 +01:00
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
2009-08-14 09:30:56 +02:00
** contact the sales department at http://qt.nokia.com/contact.
2008-12-02 12:01:29 +01:00
**
**************************************************************************/
2008-12-02 16:19:05 +01:00
2008-12-02 12:01:29 +01:00
#include "taskwindow.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/actionmanager/command.h>
2008-12-02 12:01:29 +01:00
#include <texteditor/basetexteditor.h>
#include <texteditor/itexteditor.h>
2008-12-02 12:01:29 +01:00
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
#include <QtGui/QApplication>
#include <QtGui/QClipboard>
2008-12-02 12:01:29 +01:00
#include <QtGui/QKeyEvent>
#include <QtGui/QListView>
#include <QtGui/QPainter>
#include <QtGui/QStyledItemDelegate>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QMenu>
2010-02-19 13:06:28 +01:00
namespace {
const int TASK_ICON_SIZE = 16;
const int TASK_ICON_MARGIN = 2;
}
namespace ProjectExplorer {
namespace Internal {
class TaskView : public QListView
{
public:
TaskView(QWidget *parent = 0);
~TaskView();
void resizeEvent(QResizeEvent *e);
void keyPressEvent(QKeyEvent *e);
};
2008-12-02 12:01:29 +01:00
class TaskDelegate : public QStyledItemDelegate
2008-12-02 12:01:29 +01:00
{
Q_OBJECT
public:
TaskDelegate(QObject * parent = 0);
~TaskDelegate();
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
// TaskView uses this method if the size of the taskview changes
void emitSizeHintChanged(const QModelIndex &index);
public slots:
void currentChanged(const QModelIndex &current, const QModelIndex &previous);
private:
void generateGradientPixmap(int width, int height, QColor color, bool selected) const;
2008-12-02 12:01:29 +01:00
};
class TaskWindowContext : public Core::IContext
{
public:
TaskWindowContext(QWidget *widget);
virtual QList<int> context() const;
virtual QWidget *widget();
private:
QWidget *m_taskList;
QList<int> m_context;
};
class TaskModel : public QAbstractItemModel
2008-12-02 12:01:29 +01:00
{
public:
// Model stuff
TaskModel();
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QStringList categoryIds() const;
QString categoryDisplayName(const QString &categoryId) const;
void addCategory(const QString &categoryId, const QString &categoryName);
QList<Task> tasks(const QString &categoryId = QString()) const;
void addTask(const Task &task);
void clearTasks(const QString &categoryId = QString());
2008-12-02 12:01:29 +01:00
int sizeOfFile();
int sizeOfLineNumber();
void setFileNotFound(const QModelIndex &index, bool b);
enum Roles { File = Qt::UserRole, Line, Description, FileNotFound, Type, Category, Task_t };
QIcon iconFor(Task::TaskType type);
2008-12-02 12:01:29 +01:00
private:
QHash<QString,QString> m_categories; // category id -> display name
QList<Task> m_tasks; // all tasks (in order of insertion)
QMap<QString,QList<Task> > m_tasksInCategory; // categoryId->tasks
QHash<QString,bool> m_fileNotFound;
2008-12-02 12:01:29 +01:00
int m_maxSizeOfFileName;
QIcon m_errorIcon;
QIcon m_warningIcon;
2008-12-02 12:01:29 +01:00
};
class TaskFilterModel : public QSortFilterProxyModel
{
public:
TaskFilterModel(TaskModel *sourceModel, QObject *parent = 0);
TaskModel *taskModel() const;
bool filterIncludesUnknowns() const { return m_includeUnknowns; }
void setFilterIncludesUnknowns(bool b) { m_includeUnknowns = b; invalidateFilter(); }
bool filterIncludesWarnings() const { return m_includeWarnings; }
void setFilterIncludesWarnings(bool b) { m_includeWarnings = b; invalidateFilter(); }
bool filterIncludesErrors() const { return m_includeErrors; }
void setFilterIncludesErrors(bool b) { m_includeErrors = b; invalidateFilter(); }
QStringList filteredCategories() const { return m_categoryIds; }
void setFilteredCategories(const QStringList &categoryIds) { m_categoryIds = categoryIds; invalidateFilter(); }
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
bool m_includeUnknowns;
bool m_includeWarnings;
bool m_includeErrors;
QStringList m_categoryIds;
};
} // Internal
} // ProjectExplorer
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
2008-12-02 12:01:29 +01:00
////
// TaskView
////
TaskView::TaskView(QWidget *parent)
: QListView(parent)
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
TaskView::~TaskView()
{
}
void TaskView::resizeEvent(QResizeEvent *e)
{
Q_UNUSED(e)
2008-12-02 12:01:29 +01:00
static_cast<TaskDelegate *>(itemDelegate())->emitSizeHintChanged(selectionModel()->currentIndex());
}
void TaskView::keyPressEvent(QKeyEvent *e)
{
if (!e->modifiers() && e->key() == Qt::Key_Return) {
emit activated(currentIndex());
e->accept();
return;
}
QListView::keyPressEvent(e);
}
/////
// TaskModel
/////
TaskModel::TaskModel()
{
m_maxSizeOfFileName = 0;
m_errorIcon = QIcon(":/projectexplorer/images/compile_error.png");
m_warningIcon = QIcon(":/projectexplorer/images/compile_warning.png");
2008-12-02 12:01:29 +01:00
}
void TaskModel::addCategory(const QString &categoryId, const QString &categoryName)
{
Q_ASSERT(!categoryId.isEmpty());
m_categories.insert(categoryId, categoryName);
}
QList<Task> TaskModel::tasks(const QString &categoryId) const
{
if (categoryId.isEmpty()) {
return m_tasks;
} else {
return m_tasksInCategory.value(categoryId);
}
}
void TaskModel::addTask(const Task &task)
2008-12-02 12:01:29 +01:00
{
Q_ASSERT(m_categories.keys().contains(task.category));
QList<Task> tasksInCategory = m_tasksInCategory.value(task.category);
tasksInCategory.append(task);
m_tasksInCategory.insert(task.category, tasksInCategory);
2008-12-02 12:01:29 +01:00
beginInsertRows(QModelIndex(), m_tasks.size(), m_tasks.size());
m_tasks.append(task);
2008-12-02 12:01:29 +01:00
endInsertRows();
QFont font;
QFontMetrics fm(font);
QString filename = task.file;
const int pos = filename.lastIndexOf(QLatin1Char('/'));
2008-12-02 12:01:29 +01:00
if (pos != -1)
filename = task.file.mid(pos +1);
2008-12-02 12:01:29 +01:00
m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.width(filename));
}
//
//void TaskModel::removeTask(const ITaskWindow::Task &task)
//{
// Q_ASSERT(m_tasks.contains(task));
// int index = m_tasks.indexOf(task);
// beginRemoveRows(QModelIndex(), index, index);
// m_tasks.removeAt(index);
// endRemoveRows();
//}
void TaskModel::clearTasks(const QString &categoryId)
{
if (categoryId.isEmpty()) {
if (m_tasks.size() == 0)
return;
beginRemoveRows(QModelIndex(), 0, m_tasks.size() -1);
m_tasks.clear();
m_tasksInCategory.clear();
endRemoveRows();
m_maxSizeOfFileName = 0;
} else {
// TODO: Optimize this for consecutive rows
foreach (const Task &task, m_tasksInCategory.value(categoryId)) {
int index = m_tasks.indexOf(task);
Q_ASSERT(index >= 0);
beginRemoveRows(QModelIndex(), index, index);
2008-12-02 12:01:29 +01:00
m_tasks.removeAt(index);
QList<Task> tasksInCategory = m_tasksInCategory.value(categoryId);
tasksInCategory.removeOne(task);
m_tasksInCategory.insert(categoryId, tasksInCategory);
endRemoveRows();
}
// what to do with m_maxSizeOfFileName ?
}
2008-12-02 12:01:29 +01:00
}
QModelIndex TaskModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid())
return QModelIndex();
return createIndex(row, column, 0);
}
QModelIndex TaskModel::parent(const QModelIndex &child) const
{
Q_UNUSED(child)
2008-12-02 12:01:29 +01:00
return QModelIndex();
}
int TaskModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_tasks.count();
2008-12-02 12:01:29 +01:00
}
int TaskModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 1;
}
QVariant TaskModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_tasks.size() || index.column() != 0)
2008-12-02 12:01:29 +01:00
return QVariant();
if (role == TaskModel::File) {
return m_tasks.at(index.row()).file;
} else if (role == TaskModel::Line) {
if (m_tasks.at(index.row()).line <= 0)
return QVariant();
else
return m_tasks.at(index.row()).line;
} else if (role == TaskModel::Description) {
return m_tasks.at(index.row()).description;
} else if (role == TaskModel::FileNotFound) {
return m_fileNotFound.value(m_tasks.at(index.row()).file);
} else if (role == TaskModel::Type) {
return (int)m_tasks.at(index.row()).type;
} else if (role == TaskModel::Category) {
return m_tasks.at(index.row()).category;
} else if (role == TaskModel::Task_t) {
return QVariant::fromValue(m_tasks.at(index.row()));
}
2008-12-02 12:01:29 +01:00
return QVariant();
}
QStringList TaskModel::categoryIds() const
{
return m_categories.keys();
}
QString TaskModel::categoryDisplayName(const QString &categoryId) const
{
return m_categories.value(categoryId);
}
QIcon TaskModel::iconFor(Task::TaskType type)
{
if (type == Task::Error)
return m_errorIcon;
else if (type == Task::Warning)
return m_warningIcon;
else
return QIcon();
}
2008-12-02 12:01:29 +01:00
int TaskModel::sizeOfFile()
{
return m_maxSizeOfFileName;
}
int TaskModel::sizeOfLineNumber()
{
QFont font;
QFontMetrics fm(font);
return fm.width("8888");
}
void TaskModel::setFileNotFound(const QModelIndex &idx, bool b)
{
if (idx.isValid() && idx.row() < m_tasks.size()) {
m_fileNotFound.insert(m_tasks[idx.row()].file, b);
2008-12-02 12:01:29 +01:00
emit dataChanged(idx, idx);
}
}
/////
// TaskFilterModel
/////
TaskFilterModel::TaskFilterModel(TaskModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(sourceModel);
setDynamicSortFilter(true);
m_includeUnknowns = m_includeWarnings = m_includeErrors = true;
}
TaskModel *TaskFilterModel::taskModel() const
{
return static_cast<TaskModel*>(sourceModel());
}
bool TaskFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
bool accept = true;
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
Task::TaskType type = Task::TaskType(index.data(TaskModel::Type).toInt());
switch (type) {
case Task::Unknown:
accept = m_includeUnknowns;
break;
case Task::Warning:
accept = m_includeWarnings;
break;
case Task::Error:
accept = m_includeErrors;
break;
}
const QString &categoryId = index.data(TaskModel::Category).toString();
if (m_categoryIds.contains(categoryId))
accept = false;
return accept;
}
2008-12-02 12:01:29 +01:00
/////
// TaskWindow
/////
static QToolButton *createFilterButton(Task::TaskType type,
const QString &toolTip, TaskModel *model,
QObject *receiver, const char *slot)
{
QToolButton *button = new QToolButton;
button->setIcon(model->iconFor(type));
button->setToolTip(toolTip);
button->setCheckable(true);
button->setChecked(true);
button->setAutoRaise(true);
button->setEnabled(true);
QObject::connect(button, SIGNAL(toggled(bool)), receiver, slot);
return button;
}
2008-12-02 12:01:29 +01:00
TaskWindow::TaskWindow()
{
Core::ICore *core = Core::ICore::instance();
2008-12-02 12:01:29 +01:00
m_model = new TaskModel;
m_filter = new TaskFilterModel(m_model);
2008-12-02 12:01:29 +01:00
m_listview = new TaskView;
m_listview->setModel(m_filter);
2008-12-02 12:01:29 +01:00
m_listview->setFrameStyle(QFrame::NoFrame);
2008-12-09 17:04:50 +01:00
m_listview->setWindowTitle(tr("Build Issues"));
2008-12-02 12:01:29 +01:00
m_listview->setSelectionMode(QAbstractItemView::SingleSelection);
TaskDelegate *tld = new TaskDelegate(this);
m_listview->setItemDelegate(tld);
m_listview->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
m_listview->setContextMenuPolicy(Qt::ActionsContextMenu);
2009-01-30 17:09:09 +01:00
m_listview->setAttribute(Qt::WA_MacShowFocusRect, false);
m_taskWindowContext = new TaskWindowContext(m_listview);
core->addContextObject(m_taskWindowContext);
m_copyAction = new QAction(QIcon(Core::Constants::ICON_COPY), tr("&Copy"), this);
Core::Command *command = core->actionManager()->
registerAction(m_copyAction, Core::Constants::COPY, m_taskWindowContext->context());
m_listview->addAction(command->action());
connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));
2008-12-02 12:01:29 +01:00
// Annotate using VCS: Make visible in all contexts
m_vcsAnnotateAction = new QAction(tr("&Annotate"), this);
m_vcsAnnotateAction->setToolTip("Annotate using version control system");
QList<int> annotateContext = m_taskWindowContext->context();
annotateContext << Core::ICore::instance()->uniqueIDManager()->uniqueIdentifier(QLatin1String(Core::Constants::C_GLOBAL));
command = core->actionManager()->
registerAction(m_vcsAnnotateAction, QLatin1String("ProjectExplorer.Task.VCS_Annotate"), annotateContext);
m_listview->addAction(command->action());
connect(m_vcsAnnotateAction, SIGNAL(triggered()), SLOT(vcsAnnotate()));
2008-12-02 12:01:29 +01:00
connect(m_listview->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
tld, SLOT(currentChanged(QModelIndex,QModelIndex)));
2008-12-02 12:01:29 +01:00
connect(m_listview, SIGNAL(activated(QModelIndex)),
this, SLOT(showTaskInFile(QModelIndex)));
connect(m_listview, SIGNAL(clicked(QModelIndex)),
this, SLOT(showTaskInFile(QModelIndex)));
m_filterWarningsButton = createFilterButton(Task::Warning,
tr("Show Warnings"), m_model,
this, SLOT(setShowWarnings(bool)));
m_categoriesMenu = new QMenu;
connect(m_categoriesMenu, SIGNAL(aboutToShow()), this, SLOT(updateCategoriesMenu()));
connect(m_categoriesMenu, SIGNAL(triggered(QAction*)), this, SLOT(filterCategoryTriggered(QAction*)));
m_categoriesButton = new QToolButton;
m_categoriesButton->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
m_categoriesButton->setToolTip(tr("Filter by categories"));
m_categoriesButton->setAutoRaise(true);
m_categoriesButton->setPopupMode(QToolButton::InstantPopup);
m_categoriesButton->setMenu(m_categoriesMenu);
qRegisterMetaType<ProjectExplorer::Task>("ProjectExplorer::Task");
qRegisterMetaType<QList<ProjectExplorer::Task> >("QList<ProjectExplorer::Task>");
updateActions();
2008-12-02 12:01:29 +01:00
}
TaskWindow::~TaskWindow()
{
Core::ICore::instance()->removeContextObject(m_taskWindowContext);
delete m_filterWarningsButton;
2008-12-02 12:01:29 +01:00
delete m_listview;
delete m_filter;
2008-12-02 12:01:29 +01:00
delete m_model;
}
QList<QWidget*> TaskWindow::toolBarWidgets() const
{
return QList<QWidget*>() << m_filterWarningsButton << m_categoriesButton;
2008-12-02 12:01:29 +01:00
}
QWidget *TaskWindow::outputWidget(QWidget *)
{
return m_listview;
}
void TaskWindow::clearTasks(const QString &categoryId)
2008-12-02 12:01:29 +01:00
{
m_model->clearTasks(categoryId);
updateActions();
2008-12-02 12:01:29 +01:00
emit tasksChanged();
navigateStateChanged();
2008-12-02 12:01:29 +01:00
}
void TaskWindow::visibilityChanged(bool /* b */)
{
}
void TaskWindow::addCategory(const QString &categoryId, const QString &displayName)
{
Q_ASSERT(!categoryId.isEmpty());
m_model->addCategory(categoryId, displayName);
}
void TaskWindow::addTask(const Task &task)
2008-12-02 12:01:29 +01:00
{
m_model->addTask(task);
updateActions();
2008-12-02 12:01:29 +01:00
emit tasksChanged();
navigateStateChanged();
2008-12-02 12:01:29 +01:00
}
void TaskWindow::showTaskInFile(const QModelIndex &index)
{
if (!index.isValid())
return;
QString file = index.data(TaskModel::File).toString();
int line = index.data(TaskModel::Line).toInt();
if (file.isEmpty() || line == -1)
return;
QFileInfo fi(file);
if (fi.exists()) {
TextEditor::BaseTextEditor::openEditorAt(fi.canonicalFilePath(), line);
Core::EditorManager::instance()->ensureEditorManagerVisible();
}
2008-12-02 12:01:29 +01:00
else
m_model->setFileNotFound(index, true);
m_listview->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
}
// Right-click VCS annotate: Find version control and point it to line
void TaskWindow::vcsAnnotate()
{
const QModelIndex index = m_listview->selectionModel()->currentIndex();
if (!index.isValid())
return;
const QString file = index.data(TaskModel::File).toString();
const int line = index.data(TaskModel::Line).toInt();
const QFileInfo fi(file);
if (fi.exists())
if (Core::IVersionControl *vc = Core::ICore::instance()->vcsManager()->findVersionControlForDirectory(fi.absolutePath()))
if (vc->supportsOperation(Core::IVersionControl::AnnotateOperation))
vc->vcsAnnotate(fi.absoluteFilePath(), line);
}
void TaskWindow::copy()
{
const QModelIndex index = m_listview->selectionModel()->currentIndex();
if (!index.isValid())
return;
const QString file = index.data(TaskModel::File).toString();
const QString line = index.data(TaskModel::Line).toString();
const QString description = index.data(TaskModel::Description).toString();
QString type;
switch (index.data(TaskModel::Type).toInt()) {
case Task::Error:
type = "error: ";
break;
case Task::Warning:
type = "warning: ";
break;
}
QApplication::clipboard()->setText(file + ':' + line + ": " + type + description);
}
void TaskWindow::setShowWarnings(bool show)
{
m_filter->setFilterIncludesWarnings(show);
m_filter->setFilterIncludesUnknowns(show); // "Unknowns" are often associated with warnings
}
void TaskWindow::updateCategoriesMenu()
{
m_categoriesMenu->clear();
const QStringList filteredCategories = m_filter->filteredCategories();
foreach (const QString &categoryId, m_model->categoryIds()) {
const QString categoryName = m_model->categoryDisplayName(categoryId);
QAction *action = new QAction(m_categoriesMenu);
action->setCheckable(true);
action->setText(categoryName);
action->setData(categoryId);
action->setChecked(!filteredCategories.contains(categoryId));
m_categoriesMenu->addAction(action);
}
}
void TaskWindow::filterCategoryTriggered(QAction *action)
{
QString categoryId = action->data().toString();
Q_ASSERT(!categoryId.isEmpty());
QStringList categories = m_filter->filteredCategories();
Q_ASSERT(m_filter->filteredCategories().contains(categoryId) == action->isChecked());
if (action->isChecked()) {
categories.removeOne(categoryId);
} else {
categories.append(categoryId);
}
m_filter->setFilteredCategories(categories);
}
int TaskWindow::taskCount(const QString &categoryId) const
2008-12-02 12:01:29 +01:00
{
return m_model->tasks(categoryId).count();
2008-12-02 12:01:29 +01:00
}
int TaskWindow::errorTaskCount(const QString &categoryId) const
2008-12-02 12:01:29 +01:00
{
int errorTaskCount = 0;
foreach (const Task &task, m_model->tasks(categoryId)) {
if (task.type == Task::Error)
++ errorTaskCount;
}
return errorTaskCount;
2008-12-02 12:01:29 +01:00
}
int TaskWindow::priorityInStatusBar() const
{
return 90;
}
void TaskWindow::clearContents()
{
clearTasks();
}
2008-12-02 12:01:29 +01:00
bool TaskWindow::hasFocus()
{
return m_listview->hasFocus();
}
bool TaskWindow::canFocus()
{
return m_filter->rowCount();
2008-12-02 12:01:29 +01:00
}
void TaskWindow::setFocus()
{
if (m_filter->rowCount()) {
2008-12-02 12:01:29 +01:00
m_listview->setFocus();
if (m_listview->currentIndex() == QModelIndex()) {
m_listview->setCurrentIndex(m_filter->index(0,0, QModelIndex()));
2008-12-02 12:01:29 +01:00
}
}
}
bool TaskWindow::canNext()
{
return m_filter->rowCount();
}
bool TaskWindow::canPrevious()
{
return m_filter->rowCount();
}
void TaskWindow::goToNext()
{
if (!m_filter->rowCount())
return;
QModelIndex currentIndex = m_listview->currentIndex();
if (currentIndex.isValid()) {
int row = currentIndex.row() + 1;
if (row == m_filter->rowCount())
row = 0;
currentIndex = m_filter->index(row, 0);
} else {
currentIndex = m_filter->index(0, 0);
}
m_listview->setCurrentIndex(currentIndex);
showTaskInFile(currentIndex);
}
void TaskWindow::goToPrev()
{
if (!m_filter->rowCount())
return;
QModelIndex currentIndex = m_listview->currentIndex();
if (currentIndex.isValid()) {
int row = currentIndex.row() -1;
if (row < 0)
row = m_filter->rowCount() - 1;
currentIndex = m_filter->index(row, 0);
} else {
currentIndex = m_filter->index(m_filter->rowCount()-1, 0);
}
m_listview->setCurrentIndex(currentIndex);
showTaskInFile(currentIndex);
}
bool TaskWindow::canNavigate()
{
return true;
}
void TaskWindow::updateActions()
{
m_copyAction->setEnabled(m_model->tasks().count() > 0);
}
2008-12-02 12:01:29 +01:00
/////
// Delegate
/////
TaskDelegate::TaskDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
TaskDelegate::~TaskDelegate()
{
}
QSize TaskDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
QFontMetrics fm(option.font);
int fontHeight = fm.height();
int fontLeading = fm.leading();
2008-12-02 12:01:29 +01:00
QSize s;
s.setWidth(option.rect.width());
const QAbstractItemView * view = qobject_cast<const QAbstractItemView *>(opt.widget);
TaskModel *model = static_cast<TaskFilterModel *>(view->model())->taskModel();
2008-12-02 12:01:29 +01:00
int width = opt.rect.width() - model->sizeOfFile() - model->sizeOfLineNumber() - 12 - 22;
if (view->selectionModel()->currentIndex() == index) {
QString description = index.data(TaskModel::Description).toString();
// Layout the description
int leading = fontLeading;
2008-12-02 12:01:29 +01:00
int height = 0;
description.replace('\n', QChar::LineSeparator);
2008-12-02 12:01:29 +01:00
QTextLayout tl(description);
tl.beginLayout();
2008-12-09 11:07:24 +01:00
while (true) {
2008-12-02 12:01:29 +01:00
QTextLine line = tl.createLine();
if (!line.isValid())
break;
line.setLineWidth(width);
height += leading;
line.setPosition(QPoint(0, height));
height += static_cast<int>(line.height());
}
tl.endLayout();
s.setHeight(height + leading + fontHeight + 3);
2008-12-02 12:01:29 +01:00
} else {
s.setHeight(fontHeight + 3);
2008-12-02 12:01:29 +01:00
}
2010-02-19 13:06:28 +01:00
if (s.height() < TASK_ICON_SIZE + 2 * TASK_ICON_MARGIN)
s.setHeight(TASK_ICON_SIZE + 2 * TASK_ICON_MARGIN);
2008-12-02 12:01:29 +01:00
return s;
}
void TaskDelegate::emitSizeHintChanged(const QModelIndex &index)
{
emit sizeHintChanged(index);
}
void TaskDelegate::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
emit sizeHintChanged(current);
emit sizeHintChanged(previous);
}
void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
painter->save();
QFontMetrics fm(opt.font);
QColor backgroundColor;
QColor textColor;
const QAbstractItemView * view = qobject_cast<const QAbstractItemView *>(opt.widget);
bool selected = view->selectionModel()->currentIndex() == index;
if (selected) {
painter->setBrush(opt.palette.highlight().color());
backgroundColor = opt.palette.highlight().color();
} else {
painter->setBrush(opt.palette.background().color());
backgroundColor = opt.palette.background().color();
}
painter->setPen(Qt::NoPen);
painter->drawRect(opt.rect);
// Set Text Color
if (selected)
textColor = opt.palette.highlightedText().color();
else
textColor = opt.palette.text().color();
painter->setPen(textColor);
TaskModel *model = static_cast<TaskFilterModel *>(view->model())->taskModel();
Task::TaskType type = Task::TaskType(index.data(TaskModel::Type).toInt());
QIcon icon = model->iconFor(type);
2010-02-19 13:06:28 +01:00
painter->drawPixmap(TASK_ICON_MARGIN, opt.rect.top() + TASK_ICON_MARGIN, icon.pixmap(TASK_ICON_SIZE, TASK_ICON_SIZE));
2008-12-02 12:01:29 +01:00
int width = opt.rect.width() - model->sizeOfFile() - model->sizeOfLineNumber() - 12 - 22;
if (!selected) {
2008-12-02 12:01:29 +01:00
// in small mode we lay out differently
QString bottom = index.data(TaskModel::Description).toString().split('\n').first();
2008-12-02 12:01:29 +01:00
painter->drawText(22, 2 + opt.rect.top() + fm.ascent(), bottom);
if (fm.width(bottom) > width) {
// draw a gradient to mask the text
int gwidth = opt.rect.right() - width;
QLinearGradient lg(QPoint(width, 0), QPoint(width+gwidth, 0));
QColor c = backgroundColor;
c.setAlpha(0);
lg.setColorAt(0, c);
lg.setColorAt(20.0/gwidth, backgroundColor);
painter->fillRect(width, 2 + opt.rect.top(), gwidth, fm.height() + 1, lg);
}
} else {
// Description
2008-12-02 12:01:29 +01:00
QString description = index.data(TaskModel::Description).toString();
// Layout the description
int leading = fm.leading();
int height = 0;
description.replace('\n', QChar::LineSeparator);
2008-12-02 12:01:29 +01:00
QTextLayout tl(description);
tl.setAdditionalFormats(index.data(TaskModel::Task_t).value<ProjectExplorer::Task>().formats);
2008-12-02 12:01:29 +01:00
tl.beginLayout();
2008-12-09 11:07:24 +01:00
while (true) {
2008-12-02 12:01:29 +01:00
QTextLine line = tl.createLine();
if (!line.isValid())
break;
line.setLineWidth(width);
height += leading;
line.setPosition(QPoint(0, height));
height += static_cast<int>(line.height());
}
tl.endLayout();
tl.draw(painter, QPoint(22, 2 + opt.rect.top()));
//painter->drawText(22, 2 + opt.rect.top() + fm.ascent(), description);
QColor mix;
mix.setRgb( static_cast<int>(0.7 * textColor.red() + 0.3 * backgroundColor.red()),
static_cast<int>(0.7 * textColor.green() + 0.3 * backgroundColor.green()),
static_cast<int>(0.7 * textColor.blue() + 0.3 * backgroundColor.blue()));
painter->setPen(mix);
const QString directory = QDir::toNativeSeparators(index.data(TaskModel::File).toString());
2008-12-02 12:01:29 +01:00
int secondBaseLine = 2 + fm.ascent() + opt.rect.top() + height + leading; //opt.rect.top() + fm.ascent() + fm.height() + 6;
if (index.data(TaskModel::FileNotFound).toBool()) {
QString fileNotFound = tr("File not found: %1").arg(directory);
painter->setPen(Qt::red);
painter->drawText(22, secondBaseLine, fileNotFound);
} else {
painter->drawText(22, secondBaseLine, directory);
}
}
painter->setPen(textColor);
// Assemble string for the right side
// just filename + linenumer
QString file = index.data(TaskModel::File).toString();
const int pos = file.lastIndexOf(QLatin1Char('/'));
2008-12-02 12:01:29 +01:00
if (pos != -1)
file = file.mid(pos +1);
painter->drawText(width + 22 + 4, 2 + opt.rect.top() + fm.ascent(), file);
QString topRight = index.data(TaskModel::Line).toString();
painter->drawText(opt.rect.right() - fm.width(topRight) - 6 , 2 + opt.rect.top() + fm.ascent(), topRight);
// Separator lines
painter->setPen(QColor::fromRgb(150,150,150));
painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
painter->restore();
}
TaskWindowContext::TaskWindowContext(QWidget *widget)
: Core::IContext(widget), m_taskList(widget)
{
Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
m_context << uidm->uniqueIdentifier(Core::Constants::C_PROBLEM_PANE);
}
QList<int> TaskWindowContext::context() const
{
return m_context;
}
QWidget *TaskWindowContext::widget()
{
return m_taskList;
}
//
// functions
//
bool ProjectExplorer::operator==(const Task &t1, const Task &t2)
{
return t1.type == t2.type
&& t1.line == t2.line
&& t1.description == t2.description
&& t1.file == t2.file
&& t1.category == t2.category;
}
uint ProjectExplorer::qHash(const Task &task)
{
return qHash(task.file) + task.line;
}
#include "taskwindow.moc"