OSDN Git Service

Merge remote branch 'origin/2.0'
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / breakhandler.cpp
index 39e3fd8..931ab27 100644 (file)
 #include "breakhandler.h"
 
 #include "debuggeractions.h"
-#include "debuggermanager.h"
+#include "debuggerengine.h"
+#include "debuggerplugin.h"
+#include "debuggerstringutils.h"
+#include "threadshandler.h"
+#include "stackhandler.h"
 #include "stackframe.h"
 
 #include <texteditor/basetextmark.h>
 #include <utils/qtcassert.h>
 
+#include <QtCore/QByteArray>
 #include <QtCore/QDebug>
 #include <QtCore/QTextStream>
 #include <QtCore/QFileInfo>
 
-using namespace Debugger;
-using namespace Debugger::Internal;
-
 
 //////////////////////////////////////////////////////////////////
 //
@@ -53,18 +55,18 @@ using namespace Debugger::Internal;
 // Compare file names case insensitively on Windows.
 static inline bool fileNameMatch(const QString &f1, const QString &f2)
 {
-    return f1.compare(f2,
 #ifdef Q_OS_WIN
-                      Qt::CaseInsensitive
+    return f1.compare(f2, Qt::CaseInsensitive) == 0;
 #else
-                      Qt::CaseSensitive
+    return f1 == f2;
 #endif
-                      ) == 0;
 }
 
 namespace Debugger {
 namespace Internal {
 
+static DebuggerPlugin *plugin() { return DebuggerPlugin::instance(); }
+
 // The red blob on the left side in the cpp editor.
 class BreakpointMarker : public TextEditor::BaseTextMark
 {
@@ -87,7 +89,7 @@ public:
 
     QIcon icon() const
     {
-        const BreakHandler *handler = DebuggerManager::instance()->breakHandler();
+        const BreakHandler *handler = m_data->handler();
         if (!m_enabled)
             return handler->disabledBreakpointIcon();
         return m_pending ? handler->pendingBreakPointIcon() : handler->breakpointIcon();
@@ -113,8 +115,8 @@ public:
             return;
 
         BreakHandler *handler = m_data->handler();
-        handler->removeBreakpoint(handler->indexOf(m_data));
-        handler->saveBreakpoints();
+        handler->removeBreakpoint(m_data);
+        //handler->saveBreakpoints();
         handler->updateMarkers();
     }
 
@@ -137,7 +139,7 @@ public:
         }
         // Ignore updates to the "real" line number while the debugger is
         // running, as this can be triggered by moving the breakpoint to
-        // the next line that generated code. 
+        // the next line that generated code.
         // FIXME: Do we need yet another data member?
         if (m_data->bpNumber.trimmed().isEmpty()) {
             m_data->lineNumber = QByteArray::number(lineNumber);
@@ -151,10 +153,6 @@ private:
     bool m_enabled;
 };
 
-} // namespace Internal
-} // namespace Debugger
-
-
 
 //////////////////////////////////////////////////////////////////
 //
@@ -162,28 +160,41 @@ private:
 //
 //////////////////////////////////////////////////////////////////
 
-BreakpointData::BreakpointData(BreakHandler *handler)
+BreakpointData::BreakpointData()
 {
-    //qDebug() << "CREATE BREAKPOINTDATA" << this;
-    m_handler = handler;
+    m_handler = 0;
     enabled = true;
     pending = true;
+    type = BreakpointType;
     marker = 0;
     m_markerLineNumber = 0;
     bpMultiple = false;
-//#if defined(Q_OS_MAC)
-//    // full names do not work on Mac/MI
+    bpEnabled = true;
     useFullPath = false;
-//#else
-//    //where = m_manager->shortName(data->fileName);
-//    useFullPath = true;
-//#endif
+}
+
+BreakpointData *BreakpointData::clone() const
+{
+    BreakpointData *data = new BreakpointData();
+    data->m_handler = m_handler;
+    data->m_markerFileName = m_markerFileName;
+    data->m_markerLineNumber = m_markerLineNumber;
+    data->enabled = enabled;
+    data->type = type;
+    data->fileName = fileName;
+    data->condition = condition;
+    data->ignoreCount = ignoreCount;
+    data->lineNumber = lineNumber;
+    data->address = address;
+    data->threadSpec = threadSpec;
+    data->funcName = funcName;
+    data->useFullPath = useFullPath;
+    return data;
 }
 
 BreakpointData::~BreakpointData()
 {
     removeMarker();
-    //qDebug() << "DESTROY BREAKPOINTDATA" << this;
 }
 
 void BreakpointData::removeMarker()
@@ -227,8 +238,12 @@ QString BreakpointData::toToolTip() const
         << "</td><td>" << m_markerLineNumber << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Breakpoint Number:")
         << "</td><td>" << bpNumber << "</td></tr>"
-        << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
-        << "</td><td>" << bpAddress << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Breakpoint Type:")
+        << "</td><td>"
+        << (type == BreakpointType ? BreakHandler::tr("Breakpoint")
+            : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+            : BreakHandler::tr("Unknown breakpoint type"))
+        << "</td></tr>"
         << "</table><br><hr><table>"
         << "<tr><th>" << BreakHandler::tr("Property")
         << "</th><th>" << BreakHandler::tr("Requested")
@@ -241,12 +256,16 @@ QString BreakpointData::toToolTip() const
         << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Line Number:")
         << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
+        << "</td><td>" << address << "</td><td>" << bpAddress << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Corrected Line Number:")
         << "</td><td>-</td><td>" << bpCorrectedLineNumber << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Condition:")
         << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Ignore Count:")
         << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Thread Specification:")
+        << "</td><td>" << threadSpec << "</td><td>" << bpThreadSpec << "</td></tr>"
         << "</table></body></html>";
     return rc;
 }
@@ -255,20 +274,27 @@ QString BreakpointData::toString() const
 {
     QString rc;
     QTextStream str(&rc);
-    str << BreakHandler::tr("Marker File:") << m_markerFileName << ' '
-        << BreakHandler::tr("Marker Line:") << m_markerLineNumber << ' '
-        << BreakHandler::tr("Breakpoint Number:") << bpNumber << ' '
-        << BreakHandler::tr("Breakpoint Address:") << bpAddress << '\n'
-        << BreakHandler::tr("File Name:")
+    str << BreakHandler::tr("Marker File:") << ' ' <<  m_markerFileName << '\n'
+        << BreakHandler::tr("Marker Line:") <<  ' ' << m_markerLineNumber << '\n'
+        << BreakHandler::tr("Breakpoint Number:") <<  ' ' << bpNumber << '\n'
+        << BreakHandler::tr("Breakpoint Type:") << ' '
+        << (type == BreakpointType ? BreakHandler::tr("Breakpoint")
+            : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+            : BreakHandler::tr("Unknown breakpoint type")) << '\n'
+        << BreakHandler::tr("File Name:") << ' '
         << fileName << " -- " << bpFileName << '\n'
-        << BreakHandler::tr("Function Name:")
+        << BreakHandler::tr("Function Name:") << ' '
         << funcName << " -- " << bpFuncName << '\n'
-        << BreakHandler::tr("Line Number:")
+        << BreakHandler::tr("Line Number:") << ' '
         << lineNumber << " -- " << bpLineNumber << '\n'
-        << BreakHandler::tr("Condition:")
+        << BreakHandler::tr("Breakpoint Address:") << ' '
+        << address << " -- " << bpAddress << '\n'
+        << BreakHandler::tr("Condition:") << ' '
         << condition << " -- " << bpCondition << '\n'
-        << BreakHandler::tr("Ignore Count:")
-        << ignoreCount << " -- " << bpIgnoreCount << '\n';
+        << BreakHandler::tr("Ignore Count:") << ' '
+        << ignoreCount << " -- " << bpIgnoreCount << '\n'
+        << BreakHandler::tr("Thread Specification:") << ' '
+        << threadSpec << " -- " << bpThreadSpec << '\n';
     return rc;
 }
 
@@ -287,6 +313,43 @@ bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) cons
         && fileNameMatch(fileName_, m_markerFileName);
 }
 
+bool BreakpointData::isSimilarTo(const BreakpointData *needle) const
+{
+    //qDebug() << "COMPARING " << toString() << " WITH " << needle->toString();
+
+    // Clear hit.
+    if (bpNumber == needle->bpNumber
+            && !bpNumber.isEmpty()
+            && bpNumber.toInt() != 0)
+        return true;
+
+    // Clear miss.
+    if (type != needle->type)
+        return false;
+
+    // We have numbers, but they are different.
+    if (!bpNumber.isEmpty() && !needle->bpNumber.isEmpty()
+            && !bpNumber.startsWith(needle->bpNumber)
+            && !needle->bpNumber.startsWith(bpNumber))
+        return false;
+
+    // At least at a position we were looking for.
+    // FIXME: breaks multiple breakpoints at the same location
+    if (!fileName.isEmpty()
+            && fileNameMatch(fileName, needle->fileName)
+            && lineNumber == needle->lineNumber)
+        return true;
+
+    // At least at a position we were looking for.
+    // FIXME: breaks multiple breakpoints at the same location
+    if (!fileName.isEmpty()
+            && fileNameMatch(fileName, needle->bpFileName)
+            && lineNumber == needle->bpLineNumber)
+        return true;
+
+    return false;
+}
+
 bool BreakpointData::conditionsMatch() const
 {
     // Some versions of gdb "beautify" the passed condition.
@@ -304,13 +367,16 @@ bool BreakpointData::conditionsMatch() const
 //
 //////////////////////////////////////////////////////////////////
 
-BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent) :
-    QAbstractTableModel(parent),
-    m_breakpointIcon(QLatin1String(":/debugger/images/breakpoint_16.png")),
-    m_disabledBreakpointIcon(QLatin1String(":/debugger/images/breakpoint_disabled_16.png")),
-    m_pendingBreakPointIcon(QLatin1String(":/debugger/images/breakpoint_pending_16.png")),
-    m_manager(manager)
+BreakHandler::BreakHandler(DebuggerEngine *engine)
+  : m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
+    m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
+    m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
+    m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
+    m_engine(engine),
+    m_lastFound(0),
+    m_lastFoundQueried(false)
 {
+    QTC_ASSERT(m_engine, /**/);
 }
 
 BreakHandler::~BreakHandler()
@@ -320,7 +386,7 @@ BreakHandler::~BreakHandler()
 
 int BreakHandler::columnCount(const QModelIndex &parent) const
 {
-    return parent.isValid() ? 0 : 7;
+    return parent.isValid() ? 0 : 8;
 }
 
 int BreakHandler::rowCount(const QModelIndex &parent) const
@@ -359,39 +425,18 @@ void BreakHandler::clear()
     m_inserted.clear();
 }
 
-int BreakHandler::findBreakpoint(const BreakpointData &needle) const
+BreakpointData *BreakHandler::findSimilarBreakpoint(const BreakpointData *needle) const
 {
     // Search 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 (fileNameMatch(data->fileName, needle.bpFileName)
-                && data->lineNumber == needle.bpLineNumber)
-            return index;
+        BreakpointData *data = m_bp[index];
+        if (data->isSimilarTo(needle))
+            return data;
     }
-    return -1;
-}
-
-int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) const
-{
-    if (lineNumber <= 0) {
-        QByteArray address = fileName.toLatin1();
-        for (int index = 0; index != size(); ++index)
-            if (at(index)->bpAddress == address)
-                return index;
-    } else {
-        for (int index = 0; index != size(); ++index)
-            if (at(index)->isLocatedAt(fileName, lineNumber))
-                return index;
-    }
-    return -1;
+    return 0;
 }
 
-BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const
+BreakpointData *BreakHandler::findBreakpointByNumber(int bpNumber) const
 {
     if (!size())
         return 0;
@@ -402,91 +447,104 @@ BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const
     return 0;
 }
 
+int BreakHandler::findWatchPointIndexByAddress(const QByteArray &a) const
+{
+    for (int index = size() - 1; index >= 0; --index) {
+        BreakpointData *bd = at(index);
+        if (bd->type == BreakpointData::WatchpointType && bd->address == a)
+            return index;
+    }
+    return -1;
+}
+
+bool BreakHandler::watchPointAt(quint64 address) const
+{
+    const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16);
+    return findWatchPointIndexByAddress(addressBA) != -1;
+}
+
 void BreakHandler::saveBreakpoints()
 {
+    //qDebug() << "SAVING BREAKPOINTS...";
+    QTC_ASSERT(plugin(), return);
     QList<QVariant> list;
     for (int index = 0; index != size(); ++index) {
         const BreakpointData *data = at(index);
         QMap<QString, QVariant> map;
+        // Do not persist Watchpoints.
+        //if (data->type == BreakpointData::WatchpointType)
+        //    continue;
+        if (data->type != BreakpointData::BreakpointType)
+            map.insert(_("type"), data->type);
         if (!data->fileName.isEmpty())
-            map.insert(QLatin1String("filename"), data->fileName);
+            map.insert(_("filename"), data->fileName);
         if (!data->lineNumber.isEmpty())
-            map.insert(QLatin1String("linenumber"), data->lineNumber);
+            map.insert(_("linenumber"), data->lineNumber);
         if (!data->funcName.isEmpty())
-            map.insert(QLatin1String("funcname"), data->funcName);
+            map.insert(_("funcname"), data->funcName);
+        if (!data->address.isEmpty())
+            map.insert(_("address"), data->address);
         if (!data->condition.isEmpty())
-            map.insert(QLatin1String("condition"), data->condition);
+            map.insert(_("condition"), data->condition);
         if (!data->ignoreCount.isEmpty())
-            map.insert(QLatin1String("ignorecount"), data->ignoreCount);
+            map.insert(_("ignorecount"), data->ignoreCount);
+        if (!data->threadSpec.isEmpty())
+            map.insert(_("threadspec"), data->threadSpec);
         if (!data->enabled)
-            map.insert(QLatin1String("disabled"), QLatin1String("1"));
+            map.insert(_("disabled"), _("1"));
         if (data->useFullPath)
-            map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
+            map.insert(_("usefullpath"), _("1"));
         list.append(map);
     }
-    m_manager->setSessionValue("Breakpoints", list);
+    plugin()->setSessionValue("Breakpoints", list);
+    //qDebug() << "SAVED BREAKPOINTS" << this << list.size();
 }
 
 void BreakHandler::loadBreakpoints()
 {
-    QVariant value = m_manager->sessionValue("Breakpoints");
+    QTC_ASSERT(plugin(), return);
+    //qDebug() << "LOADING BREAKPOINTS...";
+    QVariant value = plugin()->sessionValue("Breakpoints");
     QList<QVariant> list = value.toList();
     clear();
     foreach (const QVariant &var, list) {
         const QMap<QString, QVariant> map = var.toMap();
-        BreakpointData *data = new BreakpointData(this);
-        QVariant v = map.value(QLatin1String("filename"));
+        BreakpointData *data = new BreakpointData;
+        QVariant v = map.value(_("filename"));
         if (v.isValid())
             data->fileName = v.toString();
-        v = map.value(QLatin1String("linenumber"));
+        v = map.value(_("linenumber"));
         if (v.isValid())
             data->lineNumber = v.toString().toLatin1();
-        v = map.value(QLatin1String("condition"));
+        v = map.value(_("condition"));
         if (v.isValid())
             data->condition = v.toString().toLatin1();
-        v = map.value(QLatin1String("ignorecount"));
+        v = map.value(_("address"));
+        if (v.isValid())
+            data->address = v.toString().toLatin1();
+        v = map.value(_("ignorecount"));
         if (v.isValid())
             data->ignoreCount = v.toString().toLatin1();
-        v = map.value(QLatin1String("funcname"));
+        v = map.value(_("threadspec"));
+        if (v.isValid())
+            data->threadSpec = v.toString().toLatin1();
+        v = map.value(_("funcname"));
         if (v.isValid())
             data->funcName = v.toString();
-        v = map.value(QLatin1String("disabled"));
+        v = map.value(_("disabled"));
         if (v.isValid())
             data->enabled = !v.toInt();
-        v = map.value(QLatin1String("usefullpath"));
+        v = map.value(_("usefullpath"));
         if (v.isValid())
             data->useFullPath = bool(v.toInt());
+        v = map.value(_("type"));
+        if (v.isValid())
+            data->type = BreakpointData::Type(v.toInt());
         data->setMarkerFileName(data->fileName);
         data->setMarkerLineNumber(data->lineNumber.toInt());
         append(data);
     }
-}
-
-void BreakHandler::resetBreakpoints()
-{
-    for (int index = size(); --index >= 0;) {
-        BreakpointData *data = at(index);
-        data->pending = true;
-        data->bpMultiple = false;
-        data->bpEnabled = true;
-        data->bpNumber.clear();
-        data->bpFuncName.clear();
-        data->bpFileName.clear();
-        data->bpLineNumber.clear();
-        data->bpCorrectedLineNumber.clear();
-        data->bpCondition.clear();
-        data->bpIgnoreCount.clear();
-        data->bpAddress.clear();
-        // Keep marker data if it was primary.
-        if (data->markerFileName() != data->fileName)
-            data->setMarkerFileName(QString());
-        if (data->markerLineNumber() != data->lineNumber.toInt())
-            data->setMarkerLineNumber(0);
-    }
-    m_enabled.clear();
-    m_disabled.clear();
-    m_removed.clear();
-    m_inserted.clear();
+    //qDebug() << "LOADED BREAKPOINTS" << this << list.size();
 }
 
 void BreakHandler::updateMarkers()
@@ -502,7 +560,7 @@ QVariant BreakHandler::headerData(int section,
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
         static QString headers[] = {
             tr("Number"),  tr("Function"), tr("File"), tr("Line"),
-            tr("Condition"), tr("Ignore"), tr("Address")
+            tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
         };
         return headers[section];
     }
@@ -513,21 +571,50 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
 {
     static const QString empty = QString(QLatin1Char('-'));
 
-    QTC_ASSERT(mi.isValid(), return QVariant());
+    switch (role) {
+        case CurrentThreadIdRole:
+            QTC_ASSERT(m_engine, return QVariant());
+            return m_engine->threadsHandler()->currentThreadId();
+
+        case EngineActionsEnabledRole:
+            QTC_ASSERT(m_engine, return QVariant());
+            return m_engine->debuggerActionsEnabled();
+
+        case EngineCapabilitiesRole:
+            QTC_ASSERT(m_engine, return QVariant());
+            return m_engine->debuggerCapabilities();
+
+        default:
+            break;
+    }
 
+    QTC_ASSERT(mi.isValid(), return QVariant());
     if (mi.row() >= size())
         return QVariant();
 
     const BreakpointData *data = at(mi.row());
+
+    if (role == BreakpointUseFullPathRole)
+        return data->useFullPath;
+
+    if (role == BreakpointFileNameRole)
+        return data->fileName;
+
+    if (role == BreakpointEnabledRole)
+        return data->enabled;
+
+    if (role == BreakpointFunctionNameRole)
+        return data->funcName;
+
     switch (mi.column()) {
         case 0:
             if (role == Qt::DisplayRole) {
                 const QString str = data->bpNumber;
                 return str.isEmpty() ? empty : str;
             }
-            if (role == Qt::UserRole)
-                return data->enabled;
             if (role == Qt::DecorationRole) {
+                if (data->type == BreakpointData::WatchpointType)
+                    return m_watchpointIcon;
                 if (!data->enabled)
                     return m_disabledBreakpointIcon;
                 return data->pending ? m_pendingBreakPointIcon : m_breakpointIcon;
@@ -551,8 +638,6 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                     str = "/.../" + str;
                 return str;
             }
-            if (role == Qt::UserRole)
-                return data->useFullPath;
             break;
         case 3:
             if (role == Qt::DisplayRole) {
@@ -562,21 +647,43 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                 const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
                 return str.isEmpty() ? empty : str;
             }
+            if (role == Qt::UserRole + 1)
+                return data->lineNumber;
             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.");
+            if (role == Qt::UserRole + 1)
+                return data->condition;
             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.");
+            if (role == Qt::UserRole + 1)
+                return data->ignoreCount;
+            break;
         case 6:
-            if (role == Qt::DisplayRole)
+            if (role == Qt::DisplayRole) {
+                if (data->pending)
+                    return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
+                else
+                    return !data->bpThreadSpec.isEmpty() ? data->bpThreadSpec : tr("(all)");
+            }
+            if (role == Qt::ToolTipRole)
+                return tr("Breakpoint will only be hit in the specified thread(s).");
+            if (role == Qt::UserRole + 1)
+                return data->threadSpec;
+            break;
+        case 7:
+            if (role == Qt::DisplayRole) {
+                if (data->type == BreakpointData::WatchpointType)
+                    return data->address;
                 return data->bpAddress;
+            }
             break;
     }
     if (role == Qt::ToolTipRole)
@@ -585,66 +692,127 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
     return QVariant();
 }
 
-Qt::ItemFlags BreakHandler::flags(const QModelIndex &mi) const
+Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const
 {
-    //switch (mi.column()) {
-        //case 0:
-        //    return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
-        //default:
-            return QAbstractTableModel::flags(mi);
-    //}
+//    switch (index.column()) {
+//        //case 0:
+//        //    return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
+//        default:
+            return QAbstractTableModel::flags(index);
+//    }
 }
 
-bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
+bool BreakHandler::setData(const QModelIndex &index, const QVariant &value, int role)
 {
-    if (role != Qt::EditRole)
-        return false;
+    switch (role) {
+        case RequestActivateBreakpointRole: {
+            const BreakpointData *data = at(value.toInt());
+            QTC_ASSERT(data, return false);
+            m_engine->gotoLocation(data->markerFileName(),
+                data->markerLineNumber(), false);
+            return true;
+        }
 
-    BreakpointData *data = at(mi.row());
-    switch (mi.column()) {
-        case 0: {
+        case RequestRemoveBreakpointByIndexRole: {
+            BreakpointData *data = at(value.toInt());
+            QTC_ASSERT(data, return false);
+            removeBreakpoint(data);
+            return true;
+        }
+
+        case RequestSynchronizeBreakpointsRole:
+            QTC_ASSERT(m_engine, return false);
+            m_engine->attemptBreakpointSynchronization();
+            return true;
+
+        case RequestBreakByFunctionRole:
+            QTC_ASSERT(m_engine, return false);
+            m_engine->breakByFunction(value.toString());
+            return true;
+
+        case RequestBreakByFunctionMainRole:
+            QTC_ASSERT(m_engine, return false);
+            m_engine->breakByFunctionMain();
+            return true;
+    }
+
+    BreakpointData *data = at(index.row());
+
+    switch (role) {
+        case BreakpointEnabledRole:
             if (data->enabled != value.toBool()) {
                 toggleBreakpointEnabled(data);
-                dataChanged(mi, mi);
+                layoutChanged();
             }
             return true;
-        }
-        case 2: {
+
+        case BreakpointUseFullPathRole:
             if (data->useFullPath != value.toBool()) {
                 data->useFullPath = value.toBool();
-                dataChanged(mi, mi);
+                layoutChanged();
             }
             return true;
-        }
-        case 4: {
+
+        /*
             QString val = value.toString();
-            if (val != data->condition) {
-                data->condition = val.toLatin1();
-                dataChanged(mi, mi);
+            if (data->funcName != val) {
+                data->funcName = val;
+                layoutChanged();
             }
             return true;
-        }
-        case 5: {
+
             QString val = value.toString();
-            if (val != data->ignoreCount) {
-                data->ignoreCount = val.toLatin1();
-                dataChanged(mi, mi);
+            if (data->fileName != val) {
+                data->fileName = val;
+                layoutChanged();
+            }
+            return true;
+
+            QByteArray val = value.toString().toLatin1();
+            if (data->lineNumber != val) {
+                data->lineNumber = val;
+                layoutChanged();
+            }
+            return true;
+        */
+        case BreakpointConditionRole: {
+                QByteArray val = value.toString().toLatin1();
+                if (val != data->condition) {
+                    data->condition = val;
+                    layoutChanged();
+                }
+            }
+            return true;
+
+        case BreakpointIgnoreCountRole: {
+                QByteArray val = value.toString().toLatin1();
+                if (val != data->ignoreCount) {
+                    data->ignoreCount = val;
+                    layoutChanged();
+                }
+            }
+            return true;
+
+        case BreakpointThreadSpecRole: {
+                QByteArray val = value.toString().toLatin1();
+                if (val != data->threadSpec) {
+                    data->threadSpec = val;
+                    layoutChanged();
+                }
             }
             return true;
-        }
-        default: {
-            return false;
-        }
     }
+    return false;
 }
 
 void BreakHandler::append(BreakpointData *data)
 {
+    data->m_handler = this;
     m_bp.append(data);
     m_inserted.append(data);
 }
 
-QList<BreakpointData *> BreakHandler::insertedBreakpoints() const
+Breakpoints BreakHandler::insertedBreakpoints() const
 {
     return m_inserted;
 }
@@ -654,23 +822,23 @@ void BreakHandler::takeInsertedBreakPoint(BreakpointData *d)
     m_inserted.removeAll(d);
 }
 
-QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
+Breakpoints BreakHandler::takeRemovedBreakpoints()
 {
-    QList<BreakpointData *> result = m_removed;
+    Breakpoints result = m_removed;
     m_removed.clear();
     return result;
 }
 
-QList<BreakpointData *> BreakHandler::takeEnabledBreakpoints()
+Breakpoints BreakHandler::takeEnabledBreakpoints()
 {
-    QList<BreakpointData *> result = m_enabled;
+    Breakpoints result = m_enabled;
     m_enabled.clear();
     return result;
 }
 
-QList<BreakpointData *> BreakHandler::takeDisabledBreakpoints()
+Breakpoints BreakHandler::takeDisabledBreakpoints()
 {
-    QList<BreakpointData *> result = m_disabled;
+    Breakpoints result = m_disabled;
     m_disabled.clear();
     return result;
 }
@@ -689,7 +857,12 @@ void BreakHandler::removeBreakpoint(int index)
         return;
     removeBreakpointHelper(index);
     emit layoutChanged();
-    saveBreakpoints();
+}
+
+void BreakHandler::removeBreakpoint(BreakpointData *data)
+{
+    removeBreakpointHelper(m_bp.indexOf(data));
+    emit layoutChanged();
 }
 
 void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
@@ -703,7 +876,6 @@ void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
         m_enabled.removeAll(data);
         m_disabled.append(data);
     }
-    saveBreakpoints();
     updateMarkers();
 }
 
@@ -711,7 +883,7 @@ void BreakHandler::appendBreakpoint(BreakpointData *data)
 {
     append(data);
     emit layoutChanged();
-    saveBreakpoints();
+    saveBreakpoints();  // FIXME: remove?
     updateMarkers();
 }
 
@@ -720,28 +892,52 @@ void BreakHandler::removeAllBreakpoints()
     for (int index = size(); --index >= 0;)
         removeBreakpointHelper(index);
     emit layoutChanged();
-    saveBreakpoints();
     updateMarkers();
 }
 
-void BreakHandler::setAllPending()
+BreakpointData *BreakHandler::findBreakpoint(const QString &fileName, int lineNumber)
 {
-    loadBreakpoints();
-    for (int index = size(); --index >= 0;)
-        at(index)->pending = true;
-    saveBreakpoints();
-    updateMarkers();
+    foreach (BreakpointData *data, m_bp)
+        if (data->isLocatedAt(fileName, lineNumber))
+            return data;
+    return 0;
+}
+
+void BreakHandler::toggleBreakpoint(const QString &fileName, int lineNumber)
+{
+    BreakpointData *data = findBreakpoint(fileName, lineNumber);
+    if (data) {
+        removeBreakpoint(data);
+    } else {
+        data = new BreakpointData;
+        data->fileName = fileName;
+        data->lineNumber = QByteArray::number(lineNumber);
+        data->pending = true;
+        data->setMarkerFileName(fileName);
+        data->setMarkerLineNumber(lineNumber);
+        appendBreakpoint(data);
+        m_engine->attemptBreakpointSynchronization();
+    }
+}
+
+void BreakHandler::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
+{
+    BreakpointData *data = findBreakpoint(fileName, lineNumber);
+    QTC_ASSERT(data, return);
+    data->enabled = !data->enabled;
+    data->updateMarker();
+    m_engine->attemptBreakpointSynchronization();
 }
 
 void BreakHandler::saveSessionData()
 {
+    QTC_ASSERT(m_engine->isSessionEngine(), return);
     saveBreakpoints();
-    updateMarkers();
 }
 
 void BreakHandler::loadSessionData()
 {
-    //resetBreakpoints();
+    QTC_ASSERT(m_engine->isSessionEngine(), return);
     loadBreakpoints();
     updateMarkers();
 }
@@ -757,11 +953,35 @@ void BreakHandler::breakByFunction(const QString &functionName)
                 && data->ignoreCount.isEmpty())
             return;
     }
-    BreakpointData *data = new BreakpointData(this);
+    BreakpointData *data = new BreakpointData;
     data->funcName = functionName;
     append(data);
-    saveBreakpoints();
+    //saveBreakpoints();
     updateMarkers();
 }
 
+void BreakHandler::initializeFromTemplate(BreakHandler *other)
+{
+    //qDebug() << "COPYING BREAKPOINTS INTO NEW SESSION";
+    QTC_ASSERT(m_bp.isEmpty(), /**/);
+    foreach (BreakpointData *data, other->m_bp) {
+        append(data->clone());
+        data->removeMarker();
+    }
+    updateMarkers();
+}
+
+void BreakHandler::storeToTemplate(BreakHandler *other)
+{
+    other->removeAllBreakpoints();
+    foreach (BreakpointData *data, m_bp)
+        other->append(data->clone());
+    removeAllBreakpoints();
+    other->updateMarkers();
+    other->saveSessionData();
+}
+
+} // namespace Internal
+} // namespace Debugger
+
 #include "breakhandler.moc"