mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-26 20:03:10 +00:00
384 lines
10 KiB
C++
384 lines
10 KiB
C++
![]() |
/* This file is part of the KDE project
|
||
|
Copyright (C) 2002 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
|
||
|
Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
|
||
|
Copyright (C) 2006, 2008 Vladimir Prus <ghost@cs.msu.su>
|
||
|
Copyright (C) 2007 Hamish Rodda <rodda@kde.org>
|
||
|
|
||
|
This library 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 library 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
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB.
|
||
|
If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "breakpoint.h"
|
||
|
|
||
|
#include <KDE/KLocale>
|
||
|
#include <KDE/KIcon>
|
||
|
#include <KDE/KConfigGroup>
|
||
|
#include <KDE/KDebug>
|
||
|
|
||
|
#include "breakpointmodel.h"
|
||
|
#include "../../interfaces/icore.h"
|
||
|
#include "../../interfaces/idebugcontroller.h"
|
||
|
#include "../interfaces/idebugsession.h"
|
||
|
#include "../interfaces/ibreakpointcontroller.h"
|
||
|
|
||
|
using namespace KDevelop;
|
||
|
|
||
|
static const char* BREAKPOINT_KINDS[Breakpoint::LastBreakpointKind] = {
|
||
|
"Code",
|
||
|
"Write",
|
||
|
"Read",
|
||
|
"Access"
|
||
|
};
|
||
|
|
||
|
static Breakpoint::BreakpointKind stringToKind(const QString& kindString)
|
||
|
{
|
||
|
for (int i = 0; i < Breakpoint::LastBreakpointKind; ++i) {
|
||
|
if (BREAKPOINT_KINDS[i] == kindString) {
|
||
|
return (Breakpoint::BreakpointKind)i;
|
||
|
}
|
||
|
}
|
||
|
return Breakpoint::CodeBreakpoint;
|
||
|
}
|
||
|
|
||
|
Breakpoint::Breakpoint(BreakpointModel *model, BreakpointKind kind)
|
||
|
: m_model(model), m_enabled(true)
|
||
|
, m_deleted(false), m_kind(kind)
|
||
|
, m_line(-1)
|
||
|
, m_movingCursor(0), m_ignoreHits(0)
|
||
|
{
|
||
|
if (model) {
|
||
|
model->registerBreakpoint(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Breakpoint::Breakpoint(BreakpointModel *model, const KConfigGroup& config)
|
||
|
: m_model(model), m_enabled(true)
|
||
|
, m_deleted(false)
|
||
|
, m_line(-1)
|
||
|
, m_movingCursor(0), m_ignoreHits(0)
|
||
|
{
|
||
|
if (model) {
|
||
|
model->registerBreakpoint(this);
|
||
|
}
|
||
|
|
||
|
m_kind = stringToKind(config.readEntry("kind", ""));
|
||
|
m_enabled = config.readEntry("enabled", false);
|
||
|
m_url = config.readEntry("url", KUrl());
|
||
|
m_line = config.readEntry("line", -1);
|
||
|
m_expression = config.readEntry("expression", QString());
|
||
|
setCondition(config.readEntry("condition", ""));
|
||
|
setIgnoreHits(config.readEntry("ignoreHits", 0));
|
||
|
|
||
|
}
|
||
|
|
||
|
BreakpointModel *Breakpoint::breakpointModel()
|
||
|
{
|
||
|
return m_model;
|
||
|
}
|
||
|
|
||
|
bool Breakpoint::setData(int index, const QVariant& value)
|
||
|
{
|
||
|
if (index == EnableColumn)
|
||
|
{
|
||
|
m_enabled = static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked;
|
||
|
}
|
||
|
|
||
|
if (index == LocationColumn || index == ConditionColumn)
|
||
|
{
|
||
|
QString s = value.toString();
|
||
|
if (index == LocationColumn) {
|
||
|
QRegExp rx("^(.+):([0-9]+)$");
|
||
|
int idx = rx.indexIn(s);
|
||
|
if (m_kind == CodeBreakpoint && idx != -1) {
|
||
|
m_url = KUrl(rx.cap(1));
|
||
|
m_line = rx.cap(2).toInt() - 1;
|
||
|
m_expression.clear();
|
||
|
} else {
|
||
|
m_expression = s;
|
||
|
m_url.clear();
|
||
|
m_line = -1;
|
||
|
}
|
||
|
} else {
|
||
|
m_condition = s;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
reportChange(static_cast<Column>(index));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
QVariant Breakpoint::data(int column, int role) const
|
||
|
{
|
||
|
if (column == EnableColumn)
|
||
|
{
|
||
|
if (role == Qt::CheckStateRole)
|
||
|
return m_enabled ? Qt::Checked : Qt::Unchecked;
|
||
|
else if (role == Qt::DisplayRole)
|
||
|
return QVariant();
|
||
|
else
|
||
|
return QVariant();
|
||
|
}
|
||
|
|
||
|
if (column == StateColumn)
|
||
|
{
|
||
|
if (role == Qt::DecorationRole) {
|
||
|
if (!errors().isEmpty()) {
|
||
|
return KIcon("dialog-warning");
|
||
|
}
|
||
|
switch (state()) {
|
||
|
case NotStartedState:
|
||
|
return QVariant();
|
||
|
case DirtyState:
|
||
|
return KIcon("system-switch-user");
|
||
|
case PendingState:
|
||
|
return KIcon("help-contents");
|
||
|
case CleanState:
|
||
|
return KIcon("dialog-ok-apply");
|
||
|
}
|
||
|
} else if (role == Qt::ToolTipRole) {
|
||
|
if (!errors().isEmpty()) {
|
||
|
return i18nc("@info:tooltip", "Error");
|
||
|
}
|
||
|
switch (state()) {
|
||
|
case NotStartedState:
|
||
|
return QString();
|
||
|
case DirtyState:
|
||
|
return i18nc("@info:tooltip", "Dirty");
|
||
|
case PendingState:
|
||
|
return i18nc("@info:tooltip", "Pending");
|
||
|
case CleanState:
|
||
|
return i18nc("@info:tooltip", "Clean");
|
||
|
}
|
||
|
} else if (role == Qt::DisplayRole) {
|
||
|
return QVariant();
|
||
|
}
|
||
|
return QVariant();
|
||
|
}
|
||
|
|
||
|
if (column == TypeColumn && role == Qt::DisplayRole)
|
||
|
{
|
||
|
return BREAKPOINT_KINDS[m_kind];
|
||
|
}
|
||
|
|
||
|
if (role == Qt::DecorationRole)
|
||
|
{
|
||
|
if ((column == LocationColumn && errors().contains(LocationColumn))
|
||
|
|| (column == ConditionColumn && errors().contains(ConditionColumn)))
|
||
|
{
|
||
|
/* FIXME: does this leak? Is this efficient? */
|
||
|
return KIcon("dialog-warning");
|
||
|
}
|
||
|
return QVariant();
|
||
|
}
|
||
|
|
||
|
if (column == ConditionColumn && (role == Qt::DisplayRole || role == Qt::EditRole)) {
|
||
|
return m_condition;
|
||
|
}
|
||
|
|
||
|
if (column == LocationColumn) {
|
||
|
if (role == LocationRole || role == Qt::EditRole || role == Qt::ToolTipRole || role == Qt::DisplayRole) {
|
||
|
QString ret;
|
||
|
if (m_kind == CodeBreakpoint && m_line != -1) {
|
||
|
if (role == Qt::DisplayRole) {
|
||
|
ret = m_url.fileName();
|
||
|
} else {
|
||
|
ret = m_url.pathOrUrl(KUrl::RemoveTrailingSlash);
|
||
|
}
|
||
|
ret += ':' + QString::number(m_line+1);
|
||
|
} else {
|
||
|
ret = m_expression;
|
||
|
}
|
||
|
//FIXME: there should be proper columns for function name and address.
|
||
|
if (!m_address.isEmpty() && role == Qt::DisplayRole) {
|
||
|
ret = QString("%1 (%2)").arg(ret).arg(m_address);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return QVariant();
|
||
|
}
|
||
|
|
||
|
void Breakpoint::setDeleted()
|
||
|
{
|
||
|
m_deleted = true;
|
||
|
BreakpointModel* m = breakpointModel();
|
||
|
if (!m)
|
||
|
return; // already removed
|
||
|
|
||
|
if (m->breakpointIndex(this, 0).isValid()) {
|
||
|
m->removeRow(m->breakpointIndex(this, 0).row());
|
||
|
}
|
||
|
m_model = 0; // invalidate
|
||
|
}
|
||
|
|
||
|
int Breakpoint::line() const {
|
||
|
return m_line;
|
||
|
}
|
||
|
void Breakpoint::setLine(int line) {
|
||
|
Q_ASSERT(m_kind == CodeBreakpoint);
|
||
|
m_line = line;
|
||
|
reportChange(LocationColumn);
|
||
|
}
|
||
|
void Breakpoint::setUrl(const KUrl& url) {
|
||
|
Q_ASSERT(m_kind == CodeBreakpoint);
|
||
|
m_url = url;
|
||
|
reportChange(LocationColumn);
|
||
|
}
|
||
|
KUrl Breakpoint::url() const {
|
||
|
return m_url;
|
||
|
}
|
||
|
void Breakpoint::setLocation(const KUrl& url, int line)
|
||
|
{
|
||
|
Q_ASSERT(m_kind == CodeBreakpoint);
|
||
|
m_url = url;
|
||
|
m_line = line;
|
||
|
reportChange(LocationColumn);
|
||
|
}
|
||
|
|
||
|
QString KDevelop::Breakpoint::location() {
|
||
|
return data(LocationColumn, LocationRole).toString();
|
||
|
}
|
||
|
|
||
|
|
||
|
void Breakpoint::save(KConfigGroup& config)
|
||
|
{
|
||
|
config.writeEntry("kind", BREAKPOINT_KINDS[m_kind]);
|
||
|
config.writeEntry("enabled", m_enabled);
|
||
|
config.writeEntry("url", m_url);
|
||
|
config.writeEntry("line", m_line);
|
||
|
config.writeEntry("expression", m_expression);
|
||
|
config.writeEntry("condition", m_condition);
|
||
|
config.writeEntry("ignoreHits", m_ignoreHits);
|
||
|
}
|
||
|
|
||
|
Breakpoint::BreakpointKind Breakpoint::kind() const
|
||
|
{
|
||
|
return m_kind;
|
||
|
}
|
||
|
|
||
|
void Breakpoint::setAddress(const QString& address)
|
||
|
{
|
||
|
m_address = address;
|
||
|
//reportChange();
|
||
|
}
|
||
|
|
||
|
QString Breakpoint::address() const
|
||
|
{
|
||
|
return m_address;
|
||
|
}
|
||
|
|
||
|
int Breakpoint::hitCount() const
|
||
|
{
|
||
|
IDebugSession* session = ICore::self()->debugController()->currentSession();
|
||
|
if (session) {
|
||
|
return session->breakpointController()->breakpointHitCount(this);
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Breakpoint::deleted() const
|
||
|
{
|
||
|
return m_deleted;
|
||
|
}
|
||
|
|
||
|
bool Breakpoint::enabled() const
|
||
|
{
|
||
|
return data(EnableColumn, Qt::CheckStateRole).toBool();
|
||
|
}
|
||
|
|
||
|
void KDevelop::Breakpoint::setMovingCursor(KTextEditor::MovingCursor* cursor) {
|
||
|
m_movingCursor = cursor;
|
||
|
}
|
||
|
KTextEditor::MovingCursor* KDevelop::Breakpoint::movingCursor() const {
|
||
|
return m_movingCursor;
|
||
|
}
|
||
|
|
||
|
void Breakpoint::setIgnoreHits(int c)
|
||
|
{
|
||
|
if (m_ignoreHits != c) {
|
||
|
m_ignoreHits = c;
|
||
|
reportChange(IgnoreHitsColumn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int Breakpoint::ignoreHits() const
|
||
|
{
|
||
|
return m_ignoreHits;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Breakpoint::setCondition(const QString& c)
|
||
|
{
|
||
|
m_condition = c;
|
||
|
reportChange(ConditionColumn);
|
||
|
}
|
||
|
|
||
|
QString Breakpoint::condition() const
|
||
|
{
|
||
|
return m_condition;
|
||
|
}
|
||
|
|
||
|
void Breakpoint::setExpression(const QString& e)
|
||
|
{
|
||
|
m_expression = e;
|
||
|
reportChange(LocationColumn);
|
||
|
}
|
||
|
|
||
|
QString Breakpoint::expression() const
|
||
|
{
|
||
|
return m_expression;
|
||
|
}
|
||
|
|
||
|
Breakpoint::BreakpointState Breakpoint::state() const
|
||
|
{
|
||
|
IDebugSession* session = ICore::self()->debugController()->currentSession();
|
||
|
if (session) {
|
||
|
return session->breakpointController()->breakpointState(this);
|
||
|
} else {
|
||
|
return NotStartedState;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QSet<Breakpoint::Column> Breakpoint::errors() const
|
||
|
{
|
||
|
IDebugSession* session = ICore::self()->debugController()->currentSession();
|
||
|
if (session) {
|
||
|
return session->breakpointController()->breakpointErrors(this);
|
||
|
} else {
|
||
|
return QSet<Breakpoint::Column>();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
QString Breakpoint::errorText() const
|
||
|
{
|
||
|
IDebugSession* session = ICore::self()->debugController()->currentSession();
|
||
|
if (session) {
|
||
|
return session->breakpointController()->breakpointErrorText(this);
|
||
|
} else {
|
||
|
return QString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KDevelop::Breakpoint::reportChange(Column c)
|
||
|
{
|
||
|
if (!breakpointModel())
|
||
|
return;
|
||
|
|
||
|
breakpointModel()->reportChange(this, c);
|
||
|
}
|