kde-extraapps/kdevplatform/plugins/problemreporter/problemwidget.cpp

264 lines
10 KiB
C++
Raw Normal View History

/*
* KDevelop Problem Reporter
*
* Copyright (c) 2006-2007 Hamish Rodda <rodda@kde.org>
* Copyright 2006 Adam Treat <treat@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "problemwidget.h"
#include <QMenu>
#include <QCursor>
#include <QContextMenuEvent>
#include <QSignalMapper>
#include <QHeaderView>
#include <kaction.h>
#include <kactionmenu.h>
#include <klocale.h>
#include <kicon.h>
#include <KMenu>
#include <interfaces/icore.h>
#include <interfaces/idocumentcontroller.h>
#include <interfaces/iassistant.h>
#include <language/duchain/duchain.h>
#include <language/duchain/duchainlock.h>
#include <util/kdevstringhandler.h>
#include "problemreporterplugin.h"
#include "problemmodel.h"
//#include "modeltest.h"
using namespace KDevelop;
ProblemWidget::ProblemWidget(QWidget* parent, ProblemReporterPlugin* plugin)
: QTreeView(parent)
, m_plugin(plugin)
{
setObjectName("Problem Reporter Tree");
setWindowTitle(i18n("Problems"));
setWindowIcon( KIcon("dialog-information") ); ///@todo Use a proper icon
setRootIsDecorated(false);
setWhatsThis( i18n( "Problems" ) );
setModel(m_plugin->getModel());
header()->setStretchLastSection(false);
KAction* fullUpdateAction = new KAction(this);
fullUpdateAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
fullUpdateAction->setText(i18n("Force Full Update"));
fullUpdateAction->setToolTip(i18nc("@info:tooltip", "Re-parse all watched documents"));
fullUpdateAction->setIcon(KIcon("view-refresh"));
connect(fullUpdateAction, SIGNAL(triggered(bool)), model(), SLOT(forceFullUpdate()));
addAction(fullUpdateAction);
KAction* showImportsAction = new KAction(this);
addAction(showImportsAction);
showImportsAction->setCheckable(true);
showImportsAction->setChecked(false);
showImportsAction->setText(i18n("Show Imports"));
showImportsAction->setToolTip(i18nc("@info:tooltip", "Display problems in imported files"));
this->model()->setShowImports(false);
connect(showImportsAction, SIGNAL(triggered(bool)), this->model(), SLOT(setShowImports(bool)));
KActionMenu* scopeMenu = new KActionMenu(this);
scopeMenu->setDelayed(false);
scopeMenu->setText(i18n("Scope"));
scopeMenu->setToolTip(i18nc("@info:tooltip", "Which files to display the problems for"));
QActionGroup* scopeActions = new QActionGroup(this);
KAction* currentDocumentAction = new KAction(this);
currentDocumentAction->setText(i18n("Current Document"));
currentDocumentAction->setToolTip(i18nc("@info:tooltip", "Display problems in current document"));
KAction* openDocumentsAction = new KAction(this);
openDocumentsAction->setText(i18n("Open Documents"));
openDocumentsAction->setToolTip(i18nc("@info:tooltip", "Display problems in all open documents"));
KAction* currentProjectAction = new KAction(this);
currentProjectAction->setText(i18n("Current Project"));
currentProjectAction->setToolTip(i18nc("@info:tooltip", "Display problems in current project"));
KAction* allProjectAction = new KAction(this);
allProjectAction->setText(i18n("All Projects"));
allProjectAction->setToolTip(i18nc("@info:tooltip", "Display problems in all projects"));
KAction* scopeActionArray[] = {currentDocumentAction, openDocumentsAction, currentProjectAction, allProjectAction};
for (int i = 0; i < 4; ++i) {
scopeActionArray[i]->setCheckable(true);
scopeActions->addAction(scopeActionArray[i]);
scopeMenu->addAction(scopeActionArray[i]);
}
addAction(scopeMenu);
currentDocumentAction->setChecked(true);
model()->setScope(ProblemModel::CurrentDocument);
QSignalMapper * scopeMapper = new QSignalMapper(this);
scopeMapper->setMapping(currentDocumentAction, ProblemModel::CurrentDocument);
scopeMapper->setMapping(openDocumentsAction, ProblemModel::OpenDocuments);
scopeMapper->setMapping(currentProjectAction, ProblemModel::CurrentProject);
scopeMapper->setMapping(allProjectAction, ProblemModel::AllProjects);
connect(currentDocumentAction, SIGNAL(triggered()), scopeMapper, SLOT(map()));
connect(openDocumentsAction, SIGNAL(triggered()), scopeMapper, SLOT(map()));
connect(currentProjectAction, SIGNAL(triggered()), scopeMapper, SLOT(map()));
connect(allProjectAction, SIGNAL(triggered()), scopeMapper, SLOT(map()));
connect(scopeMapper, SIGNAL(mapped(int)), model(), SLOT(setScope(int)));
KActionMenu* severityMenu = new KActionMenu(i18n("Severity"), this);
severityMenu->setDelayed(false);
severityMenu->setToolTip(i18nc("@info:tooltip", "Select the lowest level of problem severity to be displayed"));
QActionGroup* severityActions = new QActionGroup(this);
KAction* errorSeverityAction = new KAction(i18n("Error"), this);
errorSeverityAction->setToolTip(i18nc("@info:tooltip", "Display only errors"));
KAction* warningSeverityAction = new KAction(i18n("Warning"), this);
warningSeverityAction->setToolTip(i18nc("@info:tooltip", "Display errors and warnings"));
KAction* hintSeverityAction = new KAction(i18n("Hint"), this);
hintSeverityAction->setToolTip(i18nc("@info:tooltip", "Display errors, warnings and hints"));
KAction* severityActionArray[] = {errorSeverityAction, warningSeverityAction, hintSeverityAction};
for (int i = 0; i < 3; ++i) {
severityActionArray[i]->setCheckable(true);
severityActions->addAction(severityActionArray[i]);
severityMenu->addAction(severityActionArray[i]);
}
addAction(severityMenu);
hintSeverityAction->setChecked(true);
model()->setSeverity(ProblemData::Hint);
QSignalMapper * severityMapper = new QSignalMapper(this);
severityMapper->setMapping(errorSeverityAction, ProblemData::Error);
severityMapper->setMapping(warningSeverityAction, ProblemData::Warning);
severityMapper->setMapping(hintSeverityAction, ProblemData::Hint);
connect(errorSeverityAction, SIGNAL(triggered()), severityMapper, SLOT(map()));
connect(warningSeverityAction, SIGNAL(triggered()), severityMapper, SLOT(map()));
connect(hintSeverityAction, SIGNAL(triggered()), severityMapper, SLOT(map()));
connect(severityMapper, SIGNAL(mapped(int)), model(), SLOT(setSeverity(int)));
connect(this, SIGNAL(activated(QModelIndex)), SLOT(itemActivated(QModelIndex)));
}
ProblemWidget::~ProblemWidget()
{
}
void ProblemWidget::itemActivated(const QModelIndex& index)
{
if (!index.isValid())
return;
KTextEditor::Cursor start;
KUrl url;
{
// TODO: is this really necessary?
DUChainReadLocker lock(DUChain::lock());
ProblemPointer problem = model()->problemForIndex(index);
url = KUrl(problem->finalLocation().document.str());
start = problem->finalLocation().start.textCursor();
}
m_plugin->core()->documentController()->openDocument(url, start);
}
void ProblemWidget::resizeColumns()
{
// Do actual resizing only if the widget is visible and there are not too many items
const int ResizeRowLimit = 15;
if (isVisible() && model()->rowCount() > 0 && model()->rowCount() < ResizeRowLimit) {
const int columnCount = model()->columnCount();
QVector<int> widthArray(columnCount);
int totalWidth = 0;
for (int i = 0; i < columnCount; ++i) {
widthArray[i] = columnWidth(i);
totalWidth += widthArray[i];
}
for (int i = 0; i < columnCount; ++i) {
int columnWidthHint = qMax(sizeHintForColumn(i), header()->sectionSizeHint(i));
if (columnWidthHint - widthArray[i] > 0) {
if (columnWidthHint - widthArray[i] < width() - totalWidth) { // enough space to resize
setColumnWidth(i, columnWidthHint);
totalWidth += (columnWidthHint - widthArray[i]);
} else {
setColumnWidth(i, widthArray[i] + width() - totalWidth);
break;
}
}
}
}
}
void ProblemWidget::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
QTreeView::dataChanged(topLeft, bottomRight);
resizeColumns();
}
void ProblemWidget::reset()
{
QTreeView::reset();
resizeColumns();
}
ProblemModel * ProblemWidget::model() const
{
return static_cast<ProblemModel*>(QTreeView::model());
}
void ProblemWidget::contextMenuEvent(QContextMenuEvent* event) {
QModelIndex index = indexAt(event->pos());
if(index.isValid()) {
KDevelop::ProblemPointer problem = model()->problemForIndex(index);
if(problem) {
KSharedPtr<KDevelop::IAssistant> solution = problem->solutionAssistant();
if(solution) {
QList<QAction*> actions;
foreach(KDevelop::IAssistantAction::Ptr action, solution->actions()) {
actions << action->toKAction();
}
if(!actions.isEmpty()) {
QString title = solution->title();
title = KDevelop::htmlToPlainText(title);
title.replace("&apos;", "\'");
QPointer<KMenu> m = new KMenu(this);
m->addTitle(title);
m->addActions(actions);
m->exec(event->globalPos());
delete m;
}
}
}
}
}
void ProblemWidget::showEvent(QShowEvent * event)
{
Q_UNUSED(event)
for (int i = 0; i < model()->columnCount(); ++i)
resizeColumnToContents(i);
}
#include "moc_problemwidget.cpp"