File indexing completed on 2024-05-12 04:37:36
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 SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 0012 #include "ibreakpointcontroller.h" 0013 0014 #include <KNotification> 0015 #include <KLocalizedString> 0016 #include <KParts/MainWindow> 0017 0018 #include "idebugsession.h" 0019 #include "../../interfaces/icore.h" 0020 #include "../breakpoint/breakpointmodel.h" 0021 #include "../../interfaces/idebugcontroller.h" 0022 #include "../breakpoint/breakpoint.h" 0023 #include "../../interfaces/iuicontroller.h" 0024 #include <debug.h> 0025 0026 namespace KDevelop { 0027 0028 IBreakpointController::IBreakpointController(KDevelop::IDebugSession* parent) 0029 : QObject(parent), m_dontSendChanges(0) 0030 { 0031 connect(parent, &IDebugSession::stateChanged, 0032 this, &IBreakpointController::debuggerStateChanged); 0033 } 0034 0035 IDebugSession* IBreakpointController::debugSession() const 0036 { 0037 return static_cast<IDebugSession*>(const_cast<QObject*>(QObject::parent())); 0038 } 0039 0040 BreakpointModel* IBreakpointController::breakpointModel() const 0041 { 0042 if (!ICore::self()) return nullptr; 0043 return ICore::self()->debugController()->breakpointModel(); 0044 } 0045 0046 void IBreakpointController::updateState(int row, Breakpoint::BreakpointState state) 0047 { 0048 breakpointModel()->updateState(row, state); 0049 } 0050 0051 void IBreakpointController::updateHitCount(int row, int hitCount) 0052 { 0053 breakpointModel()->updateHitCount(row, hitCount); 0054 } 0055 0056 void IBreakpointController::updateErrorText(int row, const QString& errorText) 0057 { 0058 breakpointModel()->updateErrorText(row, errorText); 0059 } 0060 0061 void IBreakpointController::notifyHit(int row, const QString& msg) 0062 { 0063 BreakpointModel* model = breakpointModel(); 0064 model->notifyHit(row); 0065 0066 // This is a slightly odd place to issue this notification, 0067 // but then again it's not clear which place would be more natural 0068 Breakpoint* breakpoint = model->breakpoint(row); 0069 KNotification* ev = nullptr; 0070 switch(breakpoint->kind()) { 0071 case Breakpoint::CodeBreakpoint: 0072 ev = new KNotification(QStringLiteral("BreakpointHit")); 0073 ev->setWidget(ICore::self()->uiController()->activeMainWindow()); 0074 ev->setText(i18n("Breakpoint hit: %1", breakpoint->location()) + msg); 0075 break; 0076 case Breakpoint::WriteBreakpoint: 0077 case Breakpoint::ReadBreakpoint: 0078 case Breakpoint::AccessBreakpoint: 0079 ev = new KNotification(QStringLiteral("WatchpointHit")); 0080 ev->setWidget(ICore::self()->uiController()->activeMainWindow()); 0081 ev->setText(i18n("Watchpoint hit: %1", breakpoint->location()) + msg); 0082 break; 0083 default: 0084 Q_ASSERT(0); 0085 break; 0086 } 0087 if (ev) { 0088 ev->setPixmap(QIcon::fromTheme(QStringLiteral("breakpoint")).pixmap(QSize(22,22))); 0089 // TODO: Port 0090 //ev->setComponentName(ICore::self()->aboutData().componentName()); 0091 ev->sendEvent(); 0092 } 0093 } 0094 0095 // Temporary: empty default implementation 0096 void IBreakpointController::breakpointAdded(int row) 0097 { 0098 Q_UNUSED(row); 0099 } 0100 0101 // Temporary: implement old-style behavior to ease transition through API changes 0102 void IBreakpointController::breakpointModelChanged(int row, BreakpointModel::ColumnFlags columns) 0103 { 0104 if (m_dontSendChanges) 0105 return; 0106 0107 if ((columns & ~BreakpointModel::StateColumnFlag) != 0) { 0108 Breakpoint * breakpoint = breakpointModel()->breakpoint(row); 0109 for (int column = 0; column < BreakpointModel::NumColumns; ++column) { 0110 if (columns & (1 << column)) { 0111 m_dirty[breakpoint].insert(Breakpoint::Column(column)); 0112 auto errorIt = m_errors.find(breakpoint); 0113 if (errorIt != m_errors.end()) { 0114 errorIt->remove(Breakpoint::Column(column)); 0115 } 0116 } 0117 } 0118 breakpointStateChanged(breakpoint); 0119 if (debugSession()->isRunning()) { 0120 sendMaybe(breakpoint); 0121 } 0122 } 0123 } 0124 0125 void IBreakpointController::debuggerStateChanged(IDebugSession::DebuggerState state) 0126 { 0127 BreakpointModel* model = breakpointModel(); 0128 if (!model) 0129 return; 0130 0131 //breakpoint state changes when session started or stopped 0132 const auto breakpoints = model->breakpoints(); 0133 for (Breakpoint* breakpoint : breakpoints) { 0134 if (state == IDebugSession::StartingState) { 0135 auto& dirty = m_dirty[breakpoint]; 0136 0137 //when starting everything is dirty 0138 dirty.insert(Breakpoint::LocationColumn); 0139 if (!breakpoint->condition().isEmpty()) { 0140 dirty.insert(Breakpoint::ConditionColumn); 0141 } 0142 if (!breakpoint->enabled()) { 0143 dirty.insert(KDevelop::Breakpoint::EnableColumn); 0144 } 0145 } 0146 breakpointStateChanged(breakpoint); 0147 } 0148 } 0149 0150 void IBreakpointController::sendMaybeAll() 0151 { 0152 BreakpointModel* model = breakpointModel(); 0153 if (!model) 0154 return; 0155 0156 const auto breakpoints = model->breakpoints(); 0157 for (Breakpoint* breakpoint : breakpoints) { 0158 sendMaybe(breakpoint); 0159 } 0160 } 0161 0162 // Temporary implementation to ease the API transition 0163 void IBreakpointController::breakpointAboutToBeDeleted(int row) 0164 { 0165 Breakpoint* breakpoint = breakpointModel()->breakpoint(row); 0166 qCDebug(DEBUGGER) << "breakpointAboutToBeDeleted(" << row << "): " << breakpoint; 0167 sendMaybe(breakpoint); 0168 } 0169 0170 void IBreakpointController::breakpointStateChanged(Breakpoint* breakpoint) 0171 { 0172 if (breakpoint->deleted()) return; 0173 0174 Breakpoint::BreakpointState newState = Breakpoint::NotStartedState; 0175 if (debugSession()->state() != IDebugSession::EndedState && 0176 debugSession()->state() != IDebugSession::NotStartedState) 0177 { 0178 if (m_dirty.value(breakpoint).isEmpty()) { 0179 if (m_pending.contains(breakpoint)) { 0180 newState = Breakpoint::PendingState; 0181 } else { 0182 newState = Breakpoint::CleanState; 0183 } 0184 } else { 0185 newState = Breakpoint::DirtyState; 0186 } 0187 } 0188 0189 m_dontSendChanges++; 0190 updateState(breakpointModel()->breakpointIndex(breakpoint, 0).row(), newState); 0191 m_dontSendChanges--; 0192 } 0193 0194 void IBreakpointController::setHitCount(Breakpoint* breakpoint, int count) 0195 { 0196 m_dontSendChanges++; 0197 updateHitCount(breakpointModel()->breakpointIndex(breakpoint, 0).row(), count); 0198 m_dontSendChanges--; 0199 } 0200 0201 void IBreakpointController::error(Breakpoint* breakpoint, const QString &msg, Breakpoint::Column column) 0202 { 0203 BreakpointModel* model = breakpointModel(); 0204 int row = model->breakpointIndex(breakpoint, 0).row(); 0205 0206 m_dontSendChanges++; 0207 m_errors[breakpoint].insert(column); 0208 updateErrorText(row, msg); 0209 m_dontSendChanges--; 0210 } 0211 0212 void IBreakpointController::hit(KDevelop::Breakpoint* breakpoint, const QString &msg) 0213 { 0214 int row = breakpointModel()->breakpointIndex(breakpoint, 0).row(); 0215 notifyHit(row, msg); 0216 } 0217 0218 } 0219 0220 #include "moc_ibreakpointcontroller.cpp"