2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "breakhandler.h"
|
|
|
|
|
|
2009-09-23 16:11:25 +02:00
|
|
|
#include "debuggeractions.h"
|
2009-08-14 13:04:05 +02:00
|
|
|
#include "debuggermanager.h"
|
|
|
|
|
#include "stackframe.h"
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "imports.h" // TextEditor::BaseTextMark
|
2008-12-09 16:18:28 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QDebug>
|
2009-05-12 14:28:27 +02:00
|
|
|
#include <QtCore/QTextStream>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
|
|
|
|
|
|
using namespace Debugger;
|
|
|
|
|
using namespace Debugger::Internal;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// BreakpointMarker
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
// The red blob on the left side in the cpp editor.
|
|
|
|
|
class BreakpointMarker : public TextEditor::BaseTextMark
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
public:
|
|
|
|
|
BreakpointMarker(BreakpointData *data, const QString &fileName, int lineNumber)
|
2009-04-28 15:08:52 +02:00
|
|
|
: BaseTextMark(fileName, lineNumber)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-04-28 15:08:52 +02:00
|
|
|
m_data = data;
|
|
|
|
|
m_pending = true;
|
|
|
|
|
m_enabled = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
//qDebug() << "CREATE MARKER " << fileName << lineNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~BreakpointMarker()
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "REMOVE MARKER ";
|
|
|
|
|
m_data = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QIcon icon() const
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
|
|
|
|
return icon(m_pending, m_enabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const QIcon &icon(bool pending, bool enabled)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-05-19 15:33:17 +02:00
|
|
|
static const QIcon icon(":/debugger/images/breakpoint.svg");
|
|
|
|
|
static const QIcon icon1(":/debugger/images/breakpoint_disabled.svg");
|
|
|
|
|
static const QIcon icon2(":/debugger/images/breakpoint_pending.svg");
|
2009-04-28 15:08:52 +02:00
|
|
|
return enabled ? (pending ? icon2 : icon) : icon1;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
void setPending(bool pending, bool enabled)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-04-28 15:08:52 +02:00
|
|
|
if (pending == m_pending && enabled == m_enabled)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
m_pending = pending;
|
2009-04-28 15:08:52 +02:00
|
|
|
m_enabled = enabled;
|
2008-12-02 12:01:29 +01:00
|
|
|
updateMarker();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateBlock(const QTextBlock &)
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "BREAKPOINT MARKER UPDATE BLOCK";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removedFromEditor()
|
|
|
|
|
{
|
|
|
|
|
if (!m_data)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
BreakHandler *handler = m_data->handler();
|
|
|
|
|
handler->removeBreakpoint(handler->indexOf(m_data));
|
|
|
|
|
handler->saveBreakpoints();
|
|
|
|
|
handler->updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateLineNumber(int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
if (!m_data)
|
|
|
|
|
return;
|
|
|
|
|
//if (m_data->markerLineNumber == lineNumber)
|
|
|
|
|
// return;
|
|
|
|
|
if (m_data->markerLineNumber != lineNumber) {
|
|
|
|
|
m_data->markerLineNumber = lineNumber;
|
|
|
|
|
// FIXME: should we tell gdb about the change?
|
|
|
|
|
// Ignore it for now, as we would require re-compilation
|
|
|
|
|
// and debugger re-start anyway.
|
|
|
|
|
if (0 && !m_data->bpLineNumber.isEmpty()) {
|
|
|
|
|
if (!m_data->bpNumber.trimmed().isEmpty()) {
|
|
|
|
|
m_data->pending = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_data->lineNumber = QString::number(lineNumber);
|
|
|
|
|
m_data->handler()->updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
BreakpointData *m_data;
|
|
|
|
|
bool m_pending;
|
2009-04-28 15:08:52 +02:00
|
|
|
bool m_enabled;
|
2008-12-02 12:01:29 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// BreakpointData
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
BreakpointData::BreakpointData(BreakHandler *handler)
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "CREATE BREAKPOINTDATA" << this;
|
|
|
|
|
m_handler = handler;
|
2009-04-28 15:08:52 +02:00
|
|
|
enabled = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
pending = true;
|
|
|
|
|
marker = 0;
|
|
|
|
|
markerLineNumber = 0;
|
|
|
|
|
bpMultiple = false;
|
2009-05-11 13:21:59 +02:00
|
|
|
//#if defined(Q_OS_MAC)
|
|
|
|
|
// // full names do not work on Mac/MI
|
|
|
|
|
useFullPath = false;
|
|
|
|
|
//#else
|
|
|
|
|
// //where = m_manager->shortName(data->fileName);
|
|
|
|
|
// useFullPath = true;
|
|
|
|
|
//#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakpointData::~BreakpointData()
|
|
|
|
|
{
|
|
|
|
|
removeMarker();
|
|
|
|
|
//qDebug() << "DESTROY BREAKPOINTDATA" << this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakpointData::removeMarker()
|
|
|
|
|
{
|
|
|
|
|
BreakpointMarker *m = marker;
|
|
|
|
|
marker = 0;
|
|
|
|
|
delete m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakpointData::updateMarker()
|
|
|
|
|
{
|
|
|
|
|
if (marker && (markerFileName != marker->fileName()
|
|
|
|
|
|| markerLineNumber != marker->lineNumber()))
|
|
|
|
|
removeMarker();
|
|
|
|
|
|
|
|
|
|
if (!marker && !markerFileName.isEmpty() && markerLineNumber > 0)
|
|
|
|
|
marker = new BreakpointMarker(this, markerFileName, markerLineNumber);
|
|
|
|
|
|
|
|
|
|
if (marker)
|
2009-04-28 15:08:52 +02:00
|
|
|
marker->setPending(pending, enabled);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString BreakpointData::toToolTip() const
|
|
|
|
|
{
|
2009-05-12 14:28:27 +02:00
|
|
|
QString rc;
|
|
|
|
|
QTextStream str(&rc);
|
|
|
|
|
str << "<html><body><table>";
|
2009-09-15 12:10:15 +02:00
|
|
|
str << "<tr><td>" << BreakHandler::tr("Marker File:")
|
|
|
|
|
<< "</td><td>" << markerFileName << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Marker Line:")
|
|
|
|
|
<< "</td><td>" << markerLineNumber << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Breakpoint Number:")
|
|
|
|
|
<< "</td><td>" << bpNumber << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
|
|
|
|
|
<< "</td><td>" << bpAddress << "</td></tr>";
|
2009-05-12 14:28:27 +02:00
|
|
|
str << "</table><br><hr><table>";
|
|
|
|
|
str << "<tr><th>" << BreakHandler::tr("Property")
|
|
|
|
|
<< "</th><th>" << BreakHandler::tr("Requested")
|
|
|
|
|
<< "</th><th>" << BreakHandler::tr("Obtained") << "</th></tr>";
|
2009-09-15 12:10:15 +02:00
|
|
|
str << "<tr><td>" << BreakHandler::tr("Internal Number:")
|
|
|
|
|
<< "</td><td>—</td><td>" << bpNumber << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("File Name:")
|
|
|
|
|
<< "</td><td>" << fileName << "</td><td>" << bpFileName << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Function Name:")
|
|
|
|
|
<< "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Line Number:")
|
|
|
|
|
<< "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Condition:")
|
|
|
|
|
<< "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>";
|
|
|
|
|
str << "<tr><td>" << BreakHandler::tr("Ignore Count:")
|
|
|
|
|
<< "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>";
|
2009-05-12 14:28:27 +02:00
|
|
|
str << "</table></body></html>";
|
|
|
|
|
return rc;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
if (lineNumber != QString::number(lineNumber_))
|
|
|
|
|
return false;
|
|
|
|
|
if (fileName == fileName_)
|
|
|
|
|
return true;
|
|
|
|
|
if (fileName_.endsWith(fileName))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
*/
|
|
|
|
|
return lineNumber_ == markerLineNumber && fileName_ == markerFileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BreakpointData::conditionsMatch() const
|
|
|
|
|
{
|
|
|
|
|
// same versions of gdb "beautify" the passed condition
|
|
|
|
|
QString s1 = condition;
|
|
|
|
|
s1.remove(QChar(' '));
|
|
|
|
|
QString s2 = bpCondition;
|
|
|
|
|
s2.remove(QChar(' '));
|
|
|
|
|
return s1 == s2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// BreakHandler
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-08-14 13:04:05 +02:00
|
|
|
BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent)
|
|
|
|
|
: QAbstractItemModel(parent), m_manager(manager)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-04 11:37:43 +01:00
|
|
|
BreakHandler::~BreakHandler()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
int BreakHandler::columnCount(const QModelIndex &parent) const
|
|
|
|
|
{
|
|
|
|
|
return parent.isValid() ? 0 : 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BreakHandler::rowCount(const QModelIndex &parent) const
|
|
|
|
|
{
|
|
|
|
|
return parent.isValid() ? 0 : size();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
bool BreakHandler::hasPendingBreakpoints() const
|
|
|
|
|
{
|
|
|
|
|
for (int i = size() - 1; i >= 0; i--)
|
|
|
|
|
if (at(i)->pending)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::removeAt(int index)
|
|
|
|
|
{
|
|
|
|
|
BreakpointData *data = at(index);
|
|
|
|
|
m_bp.removeAt(index);
|
|
|
|
|
delete data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::clear()
|
|
|
|
|
{
|
2009-06-30 15:50:56 +02:00
|
|
|
qDeleteAll(m_bp);
|
|
|
|
|
m_bp.clear();
|
|
|
|
|
m_enabled.clear();
|
|
|
|
|
m_disabled.clear();
|
|
|
|
|
m_removed.clear();
|
|
|
|
|
m_inserted.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BreakHandler::findBreakpoint(const BreakpointData &needle)
|
|
|
|
|
{
|
|
|
|
|
// looks for a breakpoint we might refer to
|
|
|
|
|
for (int index = 0; index != size(); ++index) {
|
|
|
|
|
const BreakpointData *data = at(index);
|
|
|
|
|
// clear hit.
|
|
|
|
|
if (data->bpNumber == needle.bpNumber)
|
|
|
|
|
return index;
|
|
|
|
|
// at least at a position we were looking for
|
|
|
|
|
// FIXME: breaks multiple breakpoints at the same location
|
|
|
|
|
if (data->fileName == needle.bpFileName
|
|
|
|
|
&& data->lineNumber == needle.bpLineNumber)
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
for (int index = 0; index != size(); ++index)
|
|
|
|
|
if (at(index)->isLocatedAt(fileName, lineNumber))
|
|
|
|
|
return index;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
int BreakHandler::findBreakpoint(int bpNumber)
|
|
|
|
|
{
|
2009-06-10 10:29:31 +02:00
|
|
|
if (!size())
|
|
|
|
|
return -1;
|
|
|
|
|
QString numStr = QString::number(bpNumber);
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int index = 0; index != size(); ++index)
|
2009-06-10 10:29:31 +02:00
|
|
|
if (at(index)->bpNumber == numStr)
|
2008-12-02 12:01:29 +01:00
|
|
|
return index;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::saveBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
QList<QVariant> list;
|
|
|
|
|
for (int index = 0; index != size(); ++index) {
|
|
|
|
|
const BreakpointData *data = at(index);
|
|
|
|
|
QMap<QString, QVariant> map;
|
|
|
|
|
if (!data->fileName.isEmpty())
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("filename"), data->fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->lineNumber.isEmpty())
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("linenumber"), data->lineNumber);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->funcName.isEmpty())
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("funcname"), data->funcName);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->condition.isEmpty())
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("condition"), data->condition);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->ignoreCount.isEmpty())
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("ignorecount"), data->ignoreCount);
|
2009-04-28 15:08:52 +02:00
|
|
|
if (!data->enabled)
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("disabled"), QLatin1String("1"));
|
2009-05-11 13:21:59 +02:00
|
|
|
if (data->useFullPath)
|
2009-06-30 15:50:56 +02:00
|
|
|
map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
|
2008-12-02 12:01:29 +01:00
|
|
|
list.append(map);
|
|
|
|
|
}
|
2009-08-14 13:04:05 +02:00
|
|
|
m_manager->setSessionValue("Breakpoints", list);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadBreakpoints()
|
|
|
|
|
{
|
2009-08-14 13:04:05 +02:00
|
|
|
QVariant value = m_manager->sessionValue("Breakpoints");
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<QVariant> list = value.toList();
|
|
|
|
|
clear();
|
|
|
|
|
foreach (const QVariant &var, list) {
|
|
|
|
|
const QMap<QString, QVariant> map = var.toMap();
|
|
|
|
|
BreakpointData *data = new BreakpointData(this);
|
2009-06-30 15:50:56 +02:00
|
|
|
QVariant v = map.value(QLatin1String("filename"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->fileName = v.toString();
|
|
|
|
|
v = map.value(QLatin1String("linenumber"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->lineNumber = v.toString();
|
|
|
|
|
v = map.value(QLatin1String("condition"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->condition = v.toString();
|
|
|
|
|
v = map.value(QLatin1String("ignorecount"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->ignoreCount = v.toInt();
|
|
|
|
|
v = map.value(QLatin1String("funcname"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->funcName = v.toString();
|
|
|
|
|
v = map.value(QLatin1String("disabled"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->enabled = !v.toInt();
|
|
|
|
|
v = map.value(QLatin1String("usefullpath"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->useFullPath = bool(v.toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
data->markerFileName = data->fileName;
|
|
|
|
|
data->markerLineNumber = data->lineNumber.toInt();
|
|
|
|
|
append(data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::resetBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
for (int index = size(); --index >= 0;) {
|
|
|
|
|
BreakpointData *data = at(index);
|
|
|
|
|
data->pending = true;
|
2009-06-17 17:19:32 +02:00
|
|
|
data->bpMultiple = false;
|
|
|
|
|
data->bpEnabled = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
data->bpNumber.clear();
|
|
|
|
|
data->bpFuncName.clear();
|
|
|
|
|
data->bpFileName.clear();
|
|
|
|
|
data->bpLineNumber.clear();
|
|
|
|
|
data->bpCondition.clear();
|
|
|
|
|
data->bpIgnoreCount.clear();
|
2009-06-17 17:19:32 +02:00
|
|
|
data->bpAddress.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
// keep marker data if it was primary
|
|
|
|
|
if (data->markerFileName != data->fileName)
|
|
|
|
|
data->markerFileName.clear();
|
|
|
|
|
if (data->markerLineNumber != data->lineNumber.toInt())
|
|
|
|
|
data->markerLineNumber = 0;
|
|
|
|
|
}
|
2009-06-17 17:19:32 +02:00
|
|
|
m_enabled.clear();
|
|
|
|
|
m_disabled.clear();
|
|
|
|
|
m_removed.clear();
|
|
|
|
|
m_inserted.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::updateMarkers()
|
|
|
|
|
{
|
|
|
|
|
for (int index = 0; index != size(); ++index)
|
|
|
|
|
at(index)->updateMarker();
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant BreakHandler::headerData(int section,
|
|
|
|
|
Qt::Orientation orientation, int role) const
|
|
|
|
|
{
|
|
|
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
|
static QString headers[] = {
|
|
|
|
|
tr("Number"), tr("Function"), tr("File"), tr("Line"),
|
|
|
|
|
tr("Condition"), tr("Ignore")
|
|
|
|
|
};
|
|
|
|
|
return headers[section];
|
|
|
|
|
}
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|
|
|
|
{
|
|
|
|
|
static const QString empty = QString(QLatin1Char('-'));
|
|
|
|
|
|
2008-12-09 12:08:56 +01:00
|
|
|
QTC_ASSERT(mi.isValid(), return QVariant());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
if (mi.row() >= size())
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
|
|
const BreakpointData *data = at(mi.row());
|
|
|
|
|
switch (mi.column()) {
|
|
|
|
|
case 0:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
|
QString str = data->bpNumber;
|
|
|
|
|
return str.isEmpty() ? empty : str;
|
|
|
|
|
}
|
2009-04-28 15:08:52 +02:00
|
|
|
//if (role == Qt::CheckStateRole)
|
|
|
|
|
// return data->enabled ? Qt::Checked : Qt::Unchecked;
|
|
|
|
|
if (role == Qt::UserRole)
|
|
|
|
|
return data->enabled;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (role == Qt::DecorationRole)
|
2009-04-28 15:08:52 +02:00
|
|
|
return BreakpointMarker::icon(data->pending, data->enabled);
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
|
QString str = data->pending ? data->funcName : data->bpFuncName;
|
|
|
|
|
return str.isEmpty() ? empty : str;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
|
QString str = data->pending ? data->fileName : data->bpFileName;
|
|
|
|
|
str = QFileInfo(str).fileName();
|
|
|
|
|
//if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
|
|
|
|
|
// str = data->markerFileName;
|
2009-05-11 13:21:59 +02:00
|
|
|
str = str.isEmpty() ? empty : str;
|
|
|
|
|
if (data->useFullPath)
|
|
|
|
|
str = "/.../" + str;
|
|
|
|
|
return str;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-11 13:21:59 +02:00
|
|
|
if (role == Qt::UserRole)
|
|
|
|
|
return data->useFullPath;
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
|
QString str = data->pending ? data->lineNumber : data->bpLineNumber;
|
|
|
|
|
//if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
|
|
|
|
|
// str = data->markerLineNumber;
|
|
|
|
|
return str.isEmpty() ? empty : str;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
if (role == Qt::DisplayRole)
|
|
|
|
|
return data->pending ? data->condition : data->bpCondition;
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
|
|
|
|
return tr("Breakpoint will only be hit if this condition is met.");
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
if (role == Qt::DisplayRole)
|
|
|
|
|
return data->pending ? data->ignoreCount : data->bpIgnoreCount;
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
|
|
|
|
return tr("Breakpoint will only be hit after being ignored so many times.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
2009-09-23 16:11:25 +02:00
|
|
|
return theDebuggerBoolSetting(UseToolTipsInLocalsView)
|
|
|
|
|
? data->toToolTip() : QVariant();
|
2008-12-02 12:01:29 +01:00
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
Qt::ItemFlags BreakHandler::flags(const QModelIndex &mi) const
|
|
|
|
|
{
|
|
|
|
|
switch (mi.column()) {
|
|
|
|
|
//case 0:
|
|
|
|
|
// return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
|
|
|
|
|
default:
|
|
|
|
|
return QAbstractItemModel::flags(mi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
|
|
|
|
|
{
|
|
|
|
|
if (role != Qt::EditRole)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
BreakpointData *data = at(mi.row());
|
|
|
|
|
switch (mi.column()) {
|
2009-04-28 15:08:52 +02:00
|
|
|
case 0: {
|
|
|
|
|
if (data->enabled != value.toBool()) {
|
|
|
|
|
toggleBreakpointEnabled(data);
|
|
|
|
|
dataChanged(mi, mi);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2009-05-11 13:21:59 +02:00
|
|
|
case 2: {
|
|
|
|
|
if (data->useFullPath != value.toBool()) {
|
|
|
|
|
data->useFullPath = value.toBool();
|
|
|
|
|
dataChanged(mi, mi);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
case 4: {
|
|
|
|
|
QString val = value.toString();
|
|
|
|
|
if (val != data->condition) {
|
|
|
|
|
data->condition = val;
|
|
|
|
|
dataChanged(mi, mi);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case 5: {
|
|
|
|
|
QString val = value.toString();
|
|
|
|
|
if (val != data->ignoreCount) {
|
|
|
|
|
data->ignoreCount = val;
|
|
|
|
|
dataChanged(mi, mi);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-12 14:28:27 +02:00
|
|
|
void BreakHandler::append(BreakpointData *data)
|
|
|
|
|
{
|
|
|
|
|
m_bp.append(data);
|
|
|
|
|
m_inserted.append(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<BreakpointData *> BreakHandler::insertedBreakpoints() const
|
|
|
|
|
{
|
|
|
|
|
return m_inserted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::takeInsertedBreakPoint(BreakpointData *d)
|
|
|
|
|
{
|
|
|
|
|
m_inserted.removeAll(d);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
QList<BreakpointData *> result = m_removed;
|
|
|
|
|
m_removed.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
QList<BreakpointData *> BreakHandler::takeEnabledBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
QList<BreakpointData *> result = m_enabled;
|
|
|
|
|
m_enabled.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<BreakpointData *> BreakHandler::takeDisabledBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
QList<BreakpointData *> result = m_disabled;
|
|
|
|
|
m_disabled.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::removeBreakpointHelper(int index)
|
|
|
|
|
{
|
|
|
|
|
BreakpointData *data = m_bp.at(index);
|
|
|
|
|
m_bp.removeAt(index);
|
|
|
|
|
data->removeMarker();
|
|
|
|
|
m_removed.append(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::removeBreakpoint(int index)
|
|
|
|
|
{
|
|
|
|
|
if (index < 0 || index >= size())
|
|
|
|
|
return;
|
2009-06-11 13:40:44 +02:00
|
|
|
removeBreakpointHelper(index);
|
2008-12-02 12:01:29 +01:00
|
|
|
emit layoutChanged();
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(data, return);
|
|
|
|
|
data->enabled = !data->enabled;
|
|
|
|
|
if (data->enabled) {
|
|
|
|
|
m_enabled.append(data);
|
|
|
|
|
m_disabled.removeAll(data);
|
|
|
|
|
} else {
|
|
|
|
|
m_enabled.removeAll(data);
|
|
|
|
|
m_disabled.append(data);
|
|
|
|
|
}
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
void BreakHandler::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-04-28 15:08:52 +02:00
|
|
|
toggleBreakpointEnabled(at(findBreakpoint(fileName, lineNumber)));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setBreakpoint(const QString &fileName, int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fi(fileName);
|
|
|
|
|
|
|
|
|
|
BreakpointData *data = new BreakpointData(this);
|
|
|
|
|
data->fileName = fileName;
|
|
|
|
|
data->lineNumber = QString::number(lineNumber);
|
|
|
|
|
data->pending = true;
|
|
|
|
|
data->markerFileName = fileName;
|
|
|
|
|
data->markerLineNumber = lineNumber;
|
|
|
|
|
append(data);
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::removeAllBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
for (int index = size(); --index >= 0;)
|
|
|
|
|
removeBreakpointHelper(index);
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setAllPending()
|
|
|
|
|
{
|
|
|
|
|
loadBreakpoints();
|
|
|
|
|
for (int index = size(); --index >= 0;)
|
|
|
|
|
at(index)->pending = true;
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::saveSessionData()
|
|
|
|
|
{
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadSessionData()
|
|
|
|
|
{
|
|
|
|
|
//resetBreakpoints();
|
|
|
|
|
loadBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-10 17:30:11 +01:00
|
|
|
void BreakHandler::activateBreakpoint(int index)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
const BreakpointData *data = at(index);
|
|
|
|
|
//qDebug() << "BREAKPOINT ACTIVATED: " << data->fileName;
|
2009-08-14 13:04:05 +02:00
|
|
|
if (!data->markerFileName.isEmpty()) {
|
|
|
|
|
StackFrame frame;
|
|
|
|
|
frame.file = data->markerFileName;
|
|
|
|
|
frame.line = data->markerLineNumber;
|
|
|
|
|
m_manager->gotoLocation(frame, false);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::breakByFunction(const QString &functionName)
|
|
|
|
|
{
|
|
|
|
|
// One per function is enough for now
|
|
|
|
|
for (int index = size(); --index >= 0;) {
|
|
|
|
|
const BreakpointData *data = at(index);
|
2008-12-09 12:08:56 +01:00
|
|
|
QTC_ASSERT(data, break);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (data->funcName == functionName && data->condition.isEmpty()
|
|
|
|
|
&& data->ignoreCount.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
BreakpointData *data = new BreakpointData(this);
|
|
|
|
|
data->funcName = functionName;
|
|
|
|
|
append(data);
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "breakhandler.moc"
|