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"