File indexing completed on 2024-05-12 04:37:34

0001 /*
0002     SPDX-FileCopyrightText: 2002 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
0003     SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org>
0004     SPDX-FileCopyrightText: 2006, 2008 Vladimir Prus <ghost@cs.msu.su>
0005     SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "breakpoint.h"
0011 
0012 #include <QIcon>
0013 
0014 #include <KLocalizedString>
0015 #include <KConfigGroup>
0016 
0017 #include "breakpointmodel.h"
0018 
0019 #include <array>
0020 
0021 using namespace KDevelop;
0022 
0023 static const std::array<QString, Breakpoint::LastBreakpointKind> BREAKPOINT_KINDS = {
0024     QStringLiteral("Code"),
0025     QStringLiteral("Write"),
0026     QStringLiteral("Read"),
0027     QStringLiteral("Access"),
0028 };
0029 
0030 static Breakpoint::BreakpointKind stringToKind(const QString& kindString)
0031 {
0032     for (int i = 0; i < Breakpoint::LastBreakpointKind; ++i) {
0033         if (kindString == BREAKPOINT_KINDS[i]) {
0034             return (Breakpoint::BreakpointKind)i;
0035         }
0036     }
0037     return Breakpoint::CodeBreakpoint;
0038 }
0039 
0040 Breakpoint::Breakpoint(BreakpointModel *model, BreakpointKind kind)
0041     : m_model(model), m_enabled(true)
0042     , m_deleted(false)
0043     , m_state(NotStartedState)
0044     , m_kind(kind)
0045     , m_line(-1)
0046     , m_movingCursor(nullptr)
0047     , m_hitCount(0)
0048     , m_ignoreHits(0)
0049 {
0050     if (model) {
0051         model->registerBreakpoint(this);
0052     }
0053 }
0054 
0055 Breakpoint::Breakpoint(BreakpointModel *model, const KConfigGroup& config)
0056     : m_model(model), m_enabled(true)
0057     , m_deleted(false)
0058     , m_state(NotStartedState)
0059     , m_line(-1)
0060     , m_movingCursor(nullptr)
0061     , m_hitCount(0)
0062     , m_ignoreHits(0)
0063 {
0064     if (model) {
0065         model->registerBreakpoint(this);
0066     }
0067 
0068     m_kind = stringToKind(config.readEntry("kind", ""));
0069     m_enabled = config.readEntry("enabled", false);
0070     m_url = config.readEntry("url", QUrl());
0071     m_line = config.readEntry("line", -1);
0072     m_expression = config.readEntry("expression", QString());
0073     setCondition(config.readEntry("condition", ""));
0074     setIgnoreHits(config.readEntry("ignoreHits", 0));
0075 }
0076 
0077 BreakpointModel *Breakpoint::breakpointModel()
0078 {
0079     return m_model;
0080 }
0081 
0082 bool Breakpoint::setData(int index, const QVariant& value)
0083 {
0084     if (index == EnableColumn)
0085     {
0086         m_enabled = static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked;
0087     }
0088 
0089     if (index == LocationColumn || index == ConditionColumn)
0090     {
0091         QString s = value.toString();
0092         if (index == LocationColumn) {
0093             QRegExp rx(QStringLiteral("^(.+):([0-9]+)$"));
0094             int idx = rx.indexIn(s);
0095             if (m_kind == CodeBreakpoint && idx != -1) {
0096                 m_url = QUrl::fromLocalFile(rx.cap(1));
0097                 m_line = rx.cap(2).toInt() - 1;
0098                 m_expression.clear();
0099             } else {
0100                 m_expression = s;
0101                 m_url.clear();
0102                 m_line = -1;
0103             }
0104         } else {
0105             m_condition = s;
0106         }
0107     }
0108 
0109     reportChange(static_cast<Column>(index));
0110 
0111     return true;
0112 }
0113 
0114 QVariant Breakpoint::data(int column, int role) const
0115 {
0116     if (column == EnableColumn)
0117     {
0118         if (role == Qt::CheckStateRole)
0119             return m_enabled ? Qt::Checked : Qt::Unchecked;
0120         else if (role == Qt::DisplayRole)
0121             return QVariant();
0122         else
0123             return QVariant();
0124     }
0125 
0126     if (column == StateColumn)
0127     {
0128         if (role == Qt::DecorationRole) {
0129             if (!errorText().isEmpty()) {
0130                 return QIcon::fromTheme(QStringLiteral("dialog-warning"));
0131             }
0132             switch (state()) {
0133                 case NotStartedState:
0134                     return QVariant();
0135                 case DirtyState:
0136                     return QIcon::fromTheme(QStringLiteral("system-switch-user"));
0137                 case PendingState:
0138                     return QIcon::fromTheme(QStringLiteral("help-contents"));
0139                 case CleanState:
0140                     return QIcon::fromTheme(QStringLiteral("dialog-ok-apply"));
0141             }
0142         } else if (role == Qt::ToolTipRole) {
0143             if (!errorText().isEmpty()) {
0144                 return i18nc("@info:tooltip", "Error");
0145             }
0146             switch (state()) {
0147                 case NotStartedState:
0148                     return QString();
0149                 case DirtyState:
0150                     return i18nc("@info:tooltip", "Dirty");
0151                 case PendingState:
0152                     return i18nc("@info:tooltip", "Pending");
0153                 case CleanState:
0154                     return i18nc("@info:tooltip", "Clean");
0155             }
0156         } else if (role == Qt::DisplayRole) {
0157             return QVariant();
0158         }
0159         return QVariant();
0160     }
0161 
0162     if (column == TypeColumn && role == Qt::DisplayRole)
0163     {
0164         return BREAKPOINT_KINDS[m_kind];
0165     }
0166 
0167     if (column == ConditionColumn && (role == Qt::DisplayRole || role == Qt::EditRole)) {
0168         return m_condition;
0169     }
0170 
0171     if (column == LocationColumn) {
0172         if (role == LocationRole || role == Qt::EditRole || role == Qt::ToolTipRole || role == Qt::DisplayRole) {
0173             QString ret;
0174             if (m_kind == CodeBreakpoint && m_line != -1) {
0175                 if (role == Qt::DisplayRole) {
0176                     ret = m_url.fileName();
0177                 } else {
0178                     ret = m_url.toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash);
0179                 }
0180                 ret += QLatin1Char(':') + QString::number(m_line+1);
0181             } else {
0182                 ret = m_expression;
0183             }
0184             //FIXME: there should be proper columns for function name and address.
0185             if (!m_address.isEmpty() && role == Qt::DisplayRole) {
0186                 ret = i18nc("location (address)", "%1 (%2)", ret, m_address);
0187             }
0188             return ret;
0189         }
0190     }
0191 
0192     return QVariant();
0193 }
0194 
0195 int Breakpoint::line() const {
0196     return m_line;
0197 }
0198 void Breakpoint::setLine(int line) {
0199     Q_ASSERT(m_kind == CodeBreakpoint);
0200     m_line = line;
0201     reportChange(LocationColumn);
0202 }
0203 void Breakpoint::setUrl(const QUrl& url) {
0204     Q_ASSERT(m_kind == CodeBreakpoint);
0205     Q_ASSERT(url.isEmpty() || (!url.isRelative() && !url.fileName().isEmpty()));
0206     m_url = url;
0207     reportChange(LocationColumn);
0208 }
0209 QUrl Breakpoint::url() const {
0210     return m_url;
0211 }
0212 void Breakpoint::setLocation(const QUrl& url, int line)
0213 {
0214     Q_ASSERT(m_kind == CodeBreakpoint);
0215     Q_ASSERT(url.isEmpty() || (!url.isRelative() && !url.fileName().isEmpty()));
0216     m_url = url;
0217     m_line = line;
0218     reportChange(LocationColumn);
0219 }
0220 
0221 QString KDevelop::Breakpoint::location() {
0222     return data(LocationColumn, LocationRole).toString();
0223 }
0224 
0225 
0226 void Breakpoint::save(KConfigGroup& config)
0227 {
0228     config.writeEntry("kind", BREAKPOINT_KINDS[m_kind]);
0229     config.writeEntry("enabled", m_enabled);
0230     config.writeEntry("url", m_url);
0231     config.writeEntry("line", m_line);
0232     config.writeEntry("expression", m_expression);
0233     config.writeEntry("condition", m_condition);
0234     config.writeEntry("ignoreHits", m_ignoreHits);
0235 }
0236 
0237 Breakpoint::BreakpointKind Breakpoint::kind() const
0238 {
0239     return m_kind;
0240 }
0241 
0242 void Breakpoint::setAddress(const QString& address)
0243 {
0244     m_address = address;
0245     //reportChange();
0246 }
0247 
0248 QString Breakpoint::address() const
0249 {
0250     return m_address;
0251 }
0252 
0253 int Breakpoint::hitCount() const
0254 {
0255     return m_hitCount;
0256 }
0257 
0258 bool Breakpoint::deleted() const
0259 {
0260     return m_deleted;
0261 }
0262 
0263 bool Breakpoint::enabled() const
0264 {
0265     return data(EnableColumn, Qt::CheckStateRole).toBool();
0266 }
0267 
0268 void KDevelop::Breakpoint::setMovingCursor(KTextEditor::MovingCursor* cursor) {
0269     m_movingCursor = cursor;
0270 }
0271 KTextEditor::MovingCursor* KDevelop::Breakpoint::movingCursor() const {
0272     return m_movingCursor;
0273 }
0274 
0275 void Breakpoint::setIgnoreHits(int c)
0276 {
0277     if (m_ignoreHits != c) {
0278         m_ignoreHits = c;
0279         reportChange(IgnoreHitsColumn);
0280     }
0281 }
0282 
0283 int Breakpoint::ignoreHits() const
0284 {
0285     return m_ignoreHits;
0286 }
0287 
0288 
0289 void Breakpoint::setCondition(const QString& c)
0290 {
0291     if (c != m_condition) {
0292         m_condition = c;
0293         reportChange(ConditionColumn);
0294     }
0295 }
0296 
0297 QString Breakpoint::condition() const
0298 {
0299     return m_condition;
0300 }
0301 
0302 void Breakpoint::setExpression(const QString& e)
0303 {
0304     if (e != m_expression) {
0305         m_expression = e;
0306         reportChange(LocationColumn);
0307     }
0308 }
0309 
0310 QString Breakpoint::expression() const
0311 {
0312     return m_expression;
0313 }
0314 
0315 Breakpoint::BreakpointState Breakpoint::state() const
0316 {
0317     return m_state;
0318 }
0319 
0320 QString Breakpoint::errorText() const
0321 {
0322     return m_errorText;
0323 }
0324 
0325 void KDevelop::Breakpoint::reportChange(Column c)
0326 {
0327     if (!breakpointModel())
0328         return;
0329 
0330     breakpointModel()->reportChange(this, c);
0331 }