diff --git a/debugger/breakpoint/breakpoint.cpp b/debugger/breakpoint/breakpoint.cpp index b7aca20534..f4a8fd7f49 100644 --- a/debugger/breakpoint/breakpoint.cpp +++ b/debugger/breakpoint/breakpoint.cpp @@ -1,376 +1,383 @@ /* This file is part of the KDE project Copyright (C) 2002 Matthias Hoelzer-Kluepfel Copyright (C) 2002 John Firebaugh Copyright (C) 2006, 2008 Vladimir Prus Copyright (C) 2007 Hamish Rodda 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 . */ #include "breakpoint.h" #include #include #include #include #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(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(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::errors() const { IDebugSession* session = ICore::self()->debugController()->currentSession(); if (session) { return session->breakpointController()->breakpointErrors(this); } else { return QSet(); } } 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); } diff --git a/debugger/breakpoint/breakpoint.h b/debugger/breakpoint/breakpoint.h index 1410faf18b..63f36307af 100644 --- a/debugger/breakpoint/breakpoint.h +++ b/debugger/breakpoint/breakpoint.h @@ -1,137 +1,142 @@ /* This file is part of the KDE project Copyright (C) 2002 Matthias Hoelzer-Kluepfel Copyright (C) 2002 John Firebaugh Copyright (C) 2007 Hamish Rodda 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 . */ #ifndef KDEVPLATFORM_BREAKPOINT_H #define KDEVPLATFORM_BREAKPOINT_H #include #include #include "../util/treeitem.h" class KConfigGroup; namespace KTextEditor { class MovingCursor; } namespace KDevelop { class BreakpointModel; class KDEVPLATFORMDEBUGGER_EXPORT Breakpoint { public: enum BreakpointKind { CodeBreakpoint = 0, WriteBreakpoint, ReadBreakpoint, AccessBreakpoint, LastBreakpointKind }; enum BreakpointState { NotStartedState, DirtyState, PendingState, CleanState }; ///Custom roles for retrieving data from breakpoint model. enum BreakpointRole{ LocationRole = Qt::UserRole + 1 ///< Retrieves breakpoint's full path unlike Qt::DisplayRole. Note: it's only appliable to LocationColumn. }; Breakpoint(BreakpointModel *model, BreakpointKind kind); Breakpoint(BreakpointModel *model, const KConfigGroup& config); ///Note: EnableColumn has 3, not 2(true and false) values: Qt::Unchecked, Qt:PartiallyChecked and Qt::Checked bool setData(int index, const QVariant& value); void setDeleted(); ///Note: to retrieve the full path use LocationRole, Qt::DisplayRole return only a file's name QVariant data(int column, int role) const; void save(KConfigGroup& config); enum Column { EnableColumn, StateColumn, TypeColumn, LocationColumn, ConditionColumn, HitCountColumn, IgnoreHitsColumn }; void setUrl(const KUrl &url); KUrl url() const; void setLine(int line); int line() const; void setLocation(const KUrl& url, int line); QString location(); BreakpointKind kind() const; void setAddress(const QString& address); QString address() const; int hitCount() const; bool deleted() const; bool enabled() const; void setMovingCursor(KTextEditor::MovingCursor *cursor); KTextEditor::MovingCursor *movingCursor() const; void setIgnoreHits(int c); int ignoreHits() const; void setCondition(const QString &c); QString condition() const; void setExpression(const QString &c); QString expression() const; BreakpointState state() const; QString errorText() const; QSet errors() const; protected: friend class IBreakpointController; + /** + * Return the model this breakpoint is attached to + * + * @note This might be null, e.g. after the breakpoint has been marked as deleted + */ BreakpointModel *breakpointModel(); BreakpointModel *m_model; bool m_enabled; bool m_deleted; BreakpointKind m_kind; /* For watchpoints, the address it is set at. */ QString m_address; KUrl m_url; int m_line; QString m_condition; KTextEditor::MovingCursor *m_movingCursor; int m_ignoreHits; QString m_expression; void reportChange(Column c); }; } #endif diff --git a/debugger/breakpoint/breakpointmodel.cpp b/debugger/breakpoint/breakpointmodel.cpp index ab938d4035..5883eadc12 100644 --- a/debugger/breakpoint/breakpointmodel.cpp +++ b/debugger/breakpoint/breakpointmodel.cpp @@ -1,552 +1,551 @@ /* This file is part of the KDE project Copyright (C) 2002 Matthias Hoelzer-Kluepfel Copyright (C) 2002 John Firebaugh Copyright (C) 2006, 2008 Vladimir Prus Copyright (C) 2007 Hamish Rodda Copyright (C) 2009 Niko Sams 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 . */ #include "breakpointmodel.h" #include #include #include #include #include #include #include #include "../interfaces/icore.h" #include "../interfaces/idocumentcontroller.h" #include "../interfaces/idocument.h" #include "../interfaces/ipartcontroller.h" #include "breakpoint.h" #include #include #include #define IF_DEBUG(x) using namespace KDevelop; using namespace KTextEditor; BreakpointModel::BreakpointModel(QObject* parent) : QAbstractTableModel(parent), m_dontUpdateMarks(false) { connect(this, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(updateMarks())); if (KDevelop::ICore::self()->partController()) { //TODO remove if foreach(KParts::Part* p, KDevelop::ICore::self()->partController()->parts()) slotPartAdded(p); connect(KDevelop::ICore::self()->partController(), SIGNAL(partAdded(KParts::Part*)), this, SLOT(slotPartAdded(KParts::Part*))); } connect (KDevelop::ICore::self()->documentController(), SIGNAL(textDocumentCreated(KDevelop::IDocument*)), this, SLOT(textDocumentCreated(KDevelop::IDocument*))); connect (KDevelop::ICore::self()->documentController(), SIGNAL(documentSaved(KDevelop::IDocument*)), SLOT(documentSaved(KDevelop::IDocument*))); load(); } BreakpointModel::~BreakpointModel() { save(); qDeleteAll(m_breakpoints); } void BreakpointModel::slotPartAdded(KParts::Part* part) { if (KTextEditor::Document* doc = dynamic_cast(part)) { MarkInterface *iface = dynamic_cast(doc); if( !iface ) return; iface->setMarkDescription((MarkInterface::MarkTypes)BreakpointMark, i18n("Breakpoint")); iface->setMarkPixmap((MarkInterface::MarkTypes)BreakpointMark, *breakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)PendingBreakpointMark, *pendingBreakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)ReachedBreakpointMark, *reachedBreakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)DisabledBreakpointMark, *disabledBreakpointPixmap()); iface->setEditableMarks( MarkInterface::Bookmark | BreakpointMark ); updateMarks(); } } void BreakpointModel::textDocumentCreated(KDevelop::IDocument* doc) { KTextEditor::MarkInterface *iface = qobject_cast(doc->textDocument()); if( iface ) { connect (doc->textDocument(), SIGNAL( markChanged(KTextEditor::Document*, KTextEditor::Mark, KTextEditor::MarkInterface::MarkChangeAction)), this, SLOT(markChanged(KTextEditor::Document*, KTextEditor::Mark, KTextEditor::MarkInterface::MarkChangeAction))); connect(doc->textDocument(), SIGNAL(markContextMenuRequested(KTextEditor::Document*, KTextEditor::Mark, QPoint, bool&)), SLOT(markContextMenuRequested(KTextEditor::Document*, KTextEditor::Mark, QPoint, bool&))); } } void BreakpointModel::markContextMenuRequested(Document* document, Mark mark, const QPoint &pos, bool& handled) { int type = mark.type; kDebug() << type; /* Is this a breakpoint mark, to begin with? */ if (!(type & AllBreakpointMarks)) return; Breakpoint *b = breakpoint(document->url(), mark.line); Q_ASSERT(b); if (!b) return; QMenu menu; QAction deleteAction(KIcon("edit-delete"), i18n("&Delete Breakpoint"), 0); QAction disableAction(KIcon("dialog-cancel"), i18n("&Disable Breakpoint"), 0); QAction enableAction(KIcon("dialog-ok-apply"), i18n("&Enable Breakpoint"), 0); menu.addAction(&deleteAction); if (b->enabled()) { menu.addAction(&disableAction); } else { menu.addAction(&enableAction); } QAction *a = menu.exec(pos); if (a == &deleteAction) { b->setDeleted(); } else if (a == &disableAction) { b->setData(Breakpoint::EnableColumn, Qt::Unchecked); } else if (a == &enableAction) { b->setData(Breakpoint::EnableColumn, Qt::Checked); } handled = true; } QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical) return QVariant(); if (role == Qt::DecorationRole ) { if (section == 0) return KIcon("dialog-ok-apply"); else if (section == 1) return KIcon("system-switch-user"); } if (role == Qt::DisplayRole) { if (section == 0 || section == 1) return ""; if (section == 2) return i18n("Type"); if (section == 3) return i18n("Location"); if (section == 4) return i18n("Condition"); } if (role == Qt::ToolTipRole) { if (section == 0) return i18n("Active status"); if (section == 1) return i18n("State"); return headerData(section, orientation, Qt::DisplayRole); } return QVariant(); } Qt::ItemFlags BreakpointModel::flags(const QModelIndex &index) const { /* FIXME: all this logic must be in item */ if (!index.isValid()) return 0; if (index.column() == 0) return static_cast( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable); if (index.column() == Breakpoint::LocationColumn || index.column() == Breakpoint::ConditionColumn) return static_cast( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); return static_cast(Qt::ItemIsEnabled | Qt::ItemIsSelectable); } QModelIndex BreakpointModel::breakpointIndex(KDevelop::Breakpoint* b, int column) { int row = m_breakpoints.indexOf(b); if (row == -1) return QModelIndex(); return index(row, column); } bool KDevelop::BreakpointModel::removeRows(int row, int count, const QModelIndex& parent) { - if (row + count > m_breakpoints.count()) { - count = m_breakpoints.count() - row; - if (count <= 0) return false; - } + if (count < 1 || (row < 0) || (row + count) > rowCount(parent)) + return false; + beginRemoveRows(parent, row, row+count-1); for (int i=0; i < count; ++i) { Breakpoint *b = m_breakpoints.at(row); m_breakpoints.removeAt(row); IF_DEBUG ( kDebug() << m_breakpoints; ) - if (!b->deleted()) b->setDeleted(); + b->setDeleted(); emit breakpointDeleted(b); } endRemoveRows(); updateMarks(); return true; } int KDevelop::BreakpointModel::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return m_breakpoints.count(); } return 0; } int KDevelop::BreakpointModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 5; } QVariant BreakpointModel::data(const QModelIndex& index, int role) const { if (!index.parent().isValid() && index.row() < m_breakpoints.count()) { return m_breakpoints.at(index.row())->data(index.column(), role); } return QVariant(); } bool KDevelop::BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!index.parent().isValid() && index.row() < m_breakpoints.count() && (role == Qt::EditRole || role == Qt::CheckStateRole)) { return m_breakpoints.at(index.row())->setData(index.column(), value); } return false; } void BreakpointModel::markChanged( KTextEditor::Document *document, KTextEditor::Mark mark, KTextEditor::MarkInterface::MarkChangeAction action) { int type = mark.type; /* Is this a breakpoint mark, to begin with? */ if (!(type & AllBreakpointMarks)) return; if (action == KTextEditor::MarkInterface::MarkAdded) { Breakpoint *b = breakpoint(document->url(), mark.line); if (b) { //there was already a breakpoint, so delete instead of adding b->setDeleted(); return; } Breakpoint *breakpoint = addCodeBreakpoint(document->url(), mark.line); KTextEditor::MovingInterface *moving = qobject_cast(document); if (moving) { KTextEditor::MovingCursor* cursor = moving->newMovingCursor(KTextEditor::Cursor(mark.line, 0)); connect(document, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); breakpoint->setMovingCursor(cursor); } } else { // Find this breakpoint and delete it Breakpoint *b = breakpoint(document->url(), mark.line); if (b) { b->setDeleted(); } } #if 0 if ( KDevelop::ICore::self()->documentController()->activeDocument() && KDevelop::ICore::self()->documentController()->activeDocument()->textDocument() == document ) { //bring focus back to the editor // TODO probably want a different command here KDevelop::ICore::self()->documentController()->activateDocument(KDevelop::ICore::self()->documentController()->activeDocument()); } #endif } const QPixmap* BreakpointModel::breakpointPixmap() { static QPixmap pixmap=KIcon("script-error").pixmap(QSize(22,22), QIcon::Active, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::pendingBreakpointPixmap() { static QPixmap pixmap=KIcon("script-error").pixmap(QSize(22,22), QIcon::Normal, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::reachedBreakpointPixmap() { static QPixmap pixmap=KIcon("script-error").pixmap(QSize(22,22), QIcon::Selected, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::disabledBreakpointPixmap() { static QPixmap pixmap=KIcon("script-error").pixmap(QSize(22,22), QIcon::Disabled, QIcon::Off); return &pixmap; } void BreakpointModel::toggleBreakpoint(const KUrl& url, const KTextEditor::Cursor& cursor) { Breakpoint *b = breakpoint(url, cursor.line()); if (b) { b->setDeleted(); } else { addCodeBreakpoint(url, cursor.line()); } } void BreakpointModel::reportChange(Breakpoint* breakpoint, Breakpoint::Column column) { // note: just a portion of Breakpoint::Column is displayed in this model! if (column >= 0 && column < columnCount()) { QModelIndex idx = breakpointIndex(breakpoint, column); Q_ASSERT(idx.isValid()); // make sure we don't pass invalid indices to dataChanged() emit dataChanged(idx, idx); } emit breakpointChanged(breakpoint, column); } uint BreakpointModel::breakpointType(Breakpoint *breakpoint) { uint type = BreakpointMark; if (!breakpoint->enabled()) { type = DisabledBreakpointMark; } else if (breakpoint->hitCount() > 0) { type = ReachedBreakpointMark; } else if (breakpoint->state() == Breakpoint::PendingState) { type = PendingBreakpointMark; } return type; } void KDevelop::BreakpointModel::updateMarks() { if (m_dontUpdateMarks) return; //add marks foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->kind() != Breakpoint::CodeBreakpoint) continue; if (breakpoint->line() == -1) continue; IDocument *doc = ICore::self()->documentController()->documentForUrl(breakpoint->url()); if (!doc) continue; KTextEditor::MarkInterface *mark = qobject_cast(doc->textDocument()); if (!mark) continue; uint type = breakpointType(breakpoint); IF_DEBUG( kDebug() << type << breakpoint->url() << mark->mark(breakpoint->line()); ) doc->textDocument()->blockSignals(true); if (mark->mark(breakpoint->line()) & AllBreakpointMarks) { if (!(mark->mark(breakpoint->line()) & type)) { mark->removeMark(breakpoint->line(), AllBreakpointMarks); mark->addMark(breakpoint->line(), type); } } else { mark->addMark(breakpoint->line(), type); } doc->textDocument()->blockSignals(false); } //remove marks foreach (IDocument *doc, ICore::self()->documentController()->openDocuments()) { KTextEditor::MarkInterface *mark = qobject_cast(doc->textDocument()); if (!mark) continue; doc->textDocument()->blockSignals(true); foreach (KTextEditor::Mark *m, mark->marks()) { if (!(m->type & AllBreakpointMarks)) continue; IF_DEBUG( kDebug() << m->line << m->type; ) foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->kind() != Breakpoint::CodeBreakpoint) continue; if (doc->url() == breakpoint->url() && m->line == breakpoint->line()) { goto continueNextMark; } } mark->removeMark(m->line, AllBreakpointMarks); continueNextMark:; } doc->textDocument()->blockSignals(false); } } void BreakpointModel::documentSaved(KDevelop::IDocument* doc) { IF_DEBUG( kDebug(); ) foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->movingCursor()) { if (breakpoint->movingCursor()->document() != doc->textDocument()) continue; if (breakpoint->movingCursor()->line() == breakpoint->line()) continue; m_dontUpdateMarks = true; breakpoint->setLine(breakpoint->movingCursor()->line()); m_dontUpdateMarks = false; } } } void BreakpointModel::aboutToDeleteMovingInterfaceContent(KTextEditor::Document* document) { foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->movingCursor() && breakpoint->movingCursor()->document() == document) { breakpoint->setMovingCursor(0); } } } void BreakpointModel::load() { KConfigGroup breakpoints = KGlobal::config()->group("breakpoints"); int count = breakpoints.readEntry("number", 0); if (count == 0) return; beginInsertRows(QModelIndex(), 0, count); for (int i = 0; i < count; ++i) { if (!breakpoints.group(QString::number(i)).readEntry("kind", "").isEmpty()) { new Breakpoint(this, breakpoints.group(QString::number(i))); } } endInsertRows(); } void BreakpointModel::save() { KConfigGroup breakpoints = KGlobal::config()->group("breakpoints"); breakpoints.writeEntry("number", m_breakpoints.count()); int i = 0; foreach (Breakpoint *b, m_breakpoints) { KConfigGroup g = breakpoints.group(QString::number(i)); b->save(g); ++i; } breakpoints.sync(); } QList KDevelop::BreakpointModel::breakpoints() const { return m_breakpoints; } Breakpoint* BreakpointModel::breakpoint(int row) { if (row >= m_breakpoints.count()) return 0; return m_breakpoints.at(row); } Breakpoint* BreakpointModel::addCodeBreakpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::CodeBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addCodeBreakpoint(const KUrl& url, int line) { Breakpoint* n = addCodeBreakpoint(); n->setLocation(url, line); return n; } Breakpoint* BreakpointModel::addCodeBreakpoint(const QString& expression) { Breakpoint* n = addCodeBreakpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::WriteBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addWatchpoint(const QString& expression) { Breakpoint* n = addWatchpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addReadWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::ReadBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addReadWatchpoint(const QString& expression) { Breakpoint* n = addReadWatchpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addAccessWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::AccessBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addAccessWatchpoint(const QString& expression) { Breakpoint* n = addAccessWatchpoint(); n->setExpression(expression); return n; } void BreakpointModel::registerBreakpoint(Breakpoint* breakpoint) { Q_ASSERT(!m_breakpoints.contains(breakpoint)); m_breakpoints << breakpoint; } Breakpoint* BreakpointModel::breakpoint(const KUrl& url, int line) { foreach (Breakpoint *b, m_breakpoints) { if (b->url() == url && b->line() == line) { return b; } } return 0; } #include "breakpointmodel.moc"