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 }