diff options
author | hjk <qtc-committer@nokia.com> | 2010-02-02 17:25:14 +0100 |
---|---|---|
committer | hjk <qtc-committer@nokia.com> | 2010-02-03 08:37:48 +0100 |
commit | 18445dc9c649036bf97631de2d1866ee036557a8 (patch) | |
tree | 1c2ed9883940c7ebfa410699843bce0691e6407b /src | |
parent | 7c823c6a26a4c3b1a078e09a1f59adcee2ceef52 (diff) | |
download | qt-creator-18445dc9c649036bf97631de2d1866ee036557a8.tar.gz |
debugger: make handling multiple core files a bit more convenient
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/debugger/debugger.pro | 4 | ||||
-rw-r--r-- | src/plugins/debugger/debugger.qrc | 1 | ||||
-rw-r--r-- | src/plugins/debugger/debuggeractions.h | 1 | ||||
-rw-r--r-- | src/plugins/debugger/debuggermanager.cpp | 52 | ||||
-rw-r--r-- | src/plugins/debugger/debuggermanager.h | 5 | ||||
-rw-r--r-- | src/plugins/debugger/debuggerplugin.cpp | 9 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.cpp | 100 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.h | 9 | ||||
-rw-r--r-- | src/plugins/debugger/idebuggerengine.h | 3 | ||||
-rw-r--r-- | src/plugins/debugger/images/debugger_snapshot_small.png | bin | 0 -> 340 bytes | |||
-rw-r--r-- | src/plugins/debugger/snapshothandler.cpp | 243 | ||||
-rw-r--r-- | src/plugins/debugger/snapshothandler.h | 124 | ||||
-rw-r--r-- | src/plugins/debugger/snapshotwindow.cpp | 176 | ||||
-rw-r--r-- | src/plugins/debugger/snapshotwindow.h | 78 | ||||
-rw-r--r-- | src/plugins/debugger/stackhandler.cpp | 1 | ||||
-rw-r--r-- | src/plugins/debugger/stackwindow.h | 3 |
16 files changed, 794 insertions, 15 deletions
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index ae9f94bdce..e68de03846 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -38,6 +38,8 @@ HEADERS += breakhandler.h \ registerwindow.h \ stackhandler.h \ stackwindow.h \ + snapshothandler.h \ + snapshotwindow.h \ sourcefileswindow.h \ threadswindow.h \ watchhandler.h \ @@ -61,6 +63,8 @@ SOURCES += breakhandler.cpp \ procinterrupt.cpp \ registerhandler.cpp \ registerwindow.cpp \ + snapshothandler.cpp \ + snapshotwindow.cpp \ stackhandler.cpp \ stackwindow.cpp \ sourcefileswindow.cpp \ diff --git a/src/plugins/debugger/debugger.qrc b/src/plugins/debugger/debugger.qrc index 6b29c8479b..a9cf90ef6f 100644 --- a/src/plugins/debugger/debugger.qrc +++ b/src/plugins/debugger/debugger.qrc @@ -6,6 +6,7 @@ <file>images/debugger_breakpoints.png</file> <file>images/debugger_continue_small.png</file> <file>images/debugger_interrupt_small.png</file> + <file>images/debugger_snapshot_small.png</file> <file>images/debugger_start.png</file> <file>images/debugger_start_small.png</file> <file>images/debugger_stepinto_small.png</file> diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 36a3271caf..65941b1b39 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -151,6 +151,7 @@ struct DebuggerManagerActions QAction *runToFunctionAction; QAction *jumpToLineAction; QAction *nextAction; + QAction *snapshotAction; QAction *watchAction1; // in the Debug menu QAction *watchAction2; // in the text editor context menu QAction *breakAction; diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 4b013f53b7..1586e00b84 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -41,15 +41,16 @@ #include "debuggeroutputwindow.h" #include "moduleswindow.h" #include "registerwindow.h" +#include "snapshotwindow.h" #include "stackwindow.h" #include "sourcefileswindow.h" #include "threadswindow.h" #include "watchwindow.h" - #include "breakhandler.h" #include "moduleshandler.h" #include "registerhandler.h" +#include "snapshothandler.h" #include "stackhandler.h" #include "stackframe.h" #include "watchhandler.h" @@ -253,25 +254,28 @@ struct DebuggerManagerPrivate // FIXME: Remove engine-specific state DebuggerStartParametersPtr m_startParameters; qint64 m_inferiorPid; + /// Views Utils::FancyMainWindow *m_mainWindow; QLabel *m_statusLabel; + QDockWidget *m_breakDock; QDockWidget *m_modulesDock; QDockWidget *m_outputDock; QDockWidget *m_registerDock; - QDockWidget *m_stackDock; + QDockWidget *m_snapshotDock; QDockWidget *m_sourceFilesDock; + QDockWidget *m_stackDock; QDockWidget *m_threadsDock; QDockWidget *m_watchDock; BreakHandler *m_breakHandler; ModulesHandler *m_modulesHandler; RegisterHandler *m_registerHandler; + SnapshotHandler *m_snapshotHandler; StackHandler *m_stackHandler; ThreadsHandler *m_threadsHandler; WatchHandler *m_watchHandler; - SourceFilesWindow *m_sourceFilesWindow; DebuggerManagerActions m_actions; @@ -279,6 +283,8 @@ struct DebuggerManagerPrivate QWidget *m_localsWindow; QWidget *m_registerWindow; QWidget *m_modulesWindow; + QWidget *m_snapshotWindow; + SourceFilesWindow *m_sourceFilesWindow; QWidget *m_stackWindow; QWidget *m_threadsWindow; QWidget *m_watchersWindow; @@ -343,6 +349,7 @@ void DebuggerManager::init() d->m_modulesWindow = new ModulesWindow(this); d->m_outputWindow = new DebuggerOutputWindow; d->m_registerWindow = new RegisterWindow(this); + d->m_snapshotWindow = new SnapshotWindow(this); d->m_stackWindow = new StackWindow(this); d->m_sourceFilesWindow = new SourceFilesWindow; d->m_threadsWindow = new ThreadsWindow; @@ -354,6 +361,12 @@ void DebuggerManager::init() d->m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); d->m_mainWindow->setDocumentMode(true); + // Snapshots + d->m_snapshotHandler = new SnapshotHandler; + QAbstractItemView *snapshotView = + qobject_cast<QAbstractItemView *>(d->m_snapshotWindow); + snapshotView->setModel(d->m_snapshotHandler); + // Stack d->m_stackHandler = new StackHandler; QAbstractItemView *stackView = @@ -471,6 +484,9 @@ void DebuggerManager::init() d->m_actions.watchAction1 = new QAction(tr("Add to Watch Window"), this); d->m_actions.watchAction2 = new QAction(tr("Add to Watch Window"), this); + d->m_actions.snapshotAction = new QAction(tr("Snapshot"), this); + d->m_actions.snapshotAction->setIcon(QIcon(":/debugger/images/debugger_snapshot_small.png")); + d->m_actions.reverseDirectionAction = new QAction(tr("Reverse Direction"), this); d->m_actions.reverseDirectionAction->setCheckable(true); d->m_actions.reverseDirectionAction->setChecked(false); @@ -499,6 +515,8 @@ void DebuggerManager::init() this, SLOT(addToWatchWindow())); connect(d->m_actions.breakAction, SIGNAL(triggered()), this, SLOT(toggleBreakpoint())); + connect(d->m_actions.snapshotAction, SIGNAL(triggered()), + this, SLOT(makeSnapshot())); connect(d->m_statusTimer, SIGNAL(timeout()), this, SLOT(clearStatusMessage())); @@ -525,6 +543,8 @@ void DebuggerManager::init() d->m_outputDock = d->m_mainWindow->addDockForWidget(d->m_outputWindow); + d->m_snapshotDock = d->m_mainWindow->addDockForWidget(d->m_snapshotWindow); + d->m_stackDock = d->m_mainWindow->addDockForWidget(d->m_stackWindow); d->m_sourceFilesDock = d->m_mainWindow->addDockForWidget(d->m_sourceFilesWindow); @@ -617,6 +637,11 @@ WatchHandler *DebuggerManager::watchHandler() const return d->m_watchHandler; } +SnapshotHandler *DebuggerManager::snapshotHandler() const +{ + return d->m_snapshotHandler; +} + const CPlusPlus::Snapshot &DebuggerManager::cppCodeModelSnapshot() const { if (d->m_codeModelSnapshot.isEmpty() && theDebuggerAction(UseCodeModel)->isChecked()) @@ -671,6 +696,7 @@ void DebuggerManager::setSimpleDockWidgetArrangement() d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_registerDock); d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_threadsDock); d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_sourceFilesDock); + d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_snapshotDock); // They following views are rarely used in ordinary debugging. Hiding them // saves cycles since the corresponding information won't be retrieved. @@ -767,11 +793,30 @@ void DebuggerManager::shutdown() doDelete(d->m_threadsHandler); doDelete(d->m_modulesHandler); doDelete(d->m_registerHandler); + doDelete(d->m_snapshotHandler); doDelete(d->m_stackHandler); doDelete(d->m_watchHandler); #undef doDelete } +void DebuggerManager::makeSnapshot() +{ + QTC_ASSERT(d->m_engine, return); + d->m_engine->makeSnapshot(); +} + +void DebuggerManager::activateSnapshot(int index) +{ + QTC_ASSERT(d->m_engine, return); + d->m_engine->activateSnapshot(index); +} + +void DebuggerManager::removeSnapshot(int index) +{ + QTC_ASSERT(d->m_engine, return); + d->m_snapshotHandler->removeSnapshot(index); +} + BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber) { if (!d->m_breakHandler) @@ -1675,6 +1720,7 @@ void DebuggerManager::setState(DebuggerState state, bool forced) d->m_actions.watchAction1->setEnabled(true); d->m_actions.watchAction2->setEnabled(true); d->m_actions.breakAction->setEnabled(true); + d->m_actions.snapshotAction->setEnabled(stopped); bool interruptIsExit = !running; if (interruptIsExit) { diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 7332dec37f..953b5d55c0 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -78,6 +78,7 @@ class SourceFilesWindow; struct StackFrame; class StackHandler; class Symbol; +class SnapshotHandler; class ThreadsHandler; class WatchData; class WatchHandler; @@ -219,12 +220,15 @@ public slots: void setBreakpoint(const QString &fileName, int lineNumber); void activateFrame(int index); void selectThread(int index); + void activateSnapshot(int index); + void removeSnapshot(int index); void stepExec(); void stepOutExec(); void nextExec(); void continueExec(); void detachDebugger(); + void makeSnapshot(); void addToWatchWindow(); void updateWatchData(const Debugger::Internal::WatchData &data); @@ -282,6 +286,7 @@ private: Internal::StackHandler *stackHandler() const; Internal::ThreadsHandler *threadsHandler() const; Internal::WatchHandler *watchHandler() const; + Internal::SnapshotHandler *snapshotHandler() const; Internal::SourceFilesWindow *sourceFileWindow() const; QWidget *threadsWindow() const; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 79bf69ae6c..b4146dfa19 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -116,6 +116,7 @@ const char * const DETACH = "Debugger.Detach"; const char * const RUN_TO_LINE = "Debugger.RunToLine"; const char * const RUN_TO_FUNCTION = "Debugger.RunToFunction"; const char * const JUMP_TO_LINE = "Debugger.JumpToLine"; +const char * const SNAPSHOT = "Debugger.Snapshot"; const char * const TOGGLE_BREAK = "Debugger.ToggleBreak"; const char * const BREAK_BY_FUNCTION = "Debugger.BreakByFunction"; const char * const BREAK_AT_MAIN = "Debugger.BreakAtMain"; @@ -137,6 +138,7 @@ const char * const TOGGLE_BREAK_KEY = "F8"; const char * const BREAK_BY_FUNCTION_KEY = "Alt+D,Alt+F"; const char * const BREAK_AT_MAIN_KEY = "Alt+D,Alt+M"; const char * const ADD_TO_WATCH_KEY = "Alt+D,Alt+W"; +const char * const SNAPSHOT_KEY = "Alt+D,Alt+S"; #else const char * const INTERRUPT_KEY = "Shift+F5"; const char * const RESET_KEY = "Ctrl+Shift+F5"; @@ -151,6 +153,7 @@ const char * const TOGGLE_BREAK_KEY = "F9"; const char * const BREAK_BY_FUNCTION_KEY = ""; const char * const BREAK_AT_MAIN_KEY = ""; const char * const ADD_TO_WATCH_KEY = "Ctrl+Alt+Q"; +const char * const SNAPSHOT_KEY = "Alt+D,Alt+S"; #endif } // namespace Constants @@ -809,6 +812,11 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Break"), globalcontext); mdebug->addAction(cmd); + cmd = am->registerAction(actions.snapshotAction, + Constants::SNAPSHOT, debuggercontext); + cmd->setDefaultKeySequence(QKeySequence(Constants::SNAPSHOT_KEY)); + mdebug->addAction(cmd); + cmd = am->registerAction(theDebuggerAction(OperateByInstruction), Constants::OPERATE_BY_INSTRUCTION, debuggercontext); mdebug->addAction(cmd); @@ -941,6 +949,7 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEP)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEPOUT)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::OPERATE_BY_INSTRUCTION)->action())); + debugToolBarLayout->addWidget(toolButton(am->command(Constants::SNAPSHOT)->action())); #ifdef USE_REVERSE_DEBUGGING debugToolBarLayout->addWidget(new Utils::StyledSeparator); debugToolBarLayout->addWidget(toolButton(am->command(Constants::REVERSE)->action())); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 52979eb708..1f79057250 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -53,8 +53,10 @@ #include "breakhandler.h" #include "moduleshandler.h" #include "registerhandler.h" +#include "snapshothandler.h" #include "stackhandler.h" #include "watchhandler.h" + #include "sourcefileswindow.h" #include "debuggerdialogs.h" @@ -65,20 +67,21 @@ #include <projectexplorer/toolchain.h> #include <coreplugin/icore.h> +#include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFileInfo> #include <QtCore/QMetaObject> #include <QtCore/QTime> #include <QtCore/QTimer> +#include <QtCore/QTemporaryFile> #include <QtCore/QTextStream> #include <QtGui/QAction> -#include <QtCore/QCoreApplication> +#include <QtGui/QDialogButtonBox> #include <QtGui/QLabel> #include <QtGui/QMainWindow> #include <QtGui/QMessageBox> -#include <QtGui/QDialogButtonBox> #include <QtGui/QPushButton> #ifdef Q_OS_UNIX @@ -87,13 +90,6 @@ #endif #include <ctype.h> -#define DIVERT(func, pars) \ - do { \ - if (hasPython()) \ - func ## Python(pars); \ - else \ - func ## Plain(pars); \ - } while (0) namespace Debugger { namespace Internal { @@ -2701,6 +2697,92 @@ void GdbEngine::handleStackListThreads(const GdbResponse &response) ////////////////////////////////////////////////////////////////////// // +// Snapshot specific stuff +// +////////////////////////////////////////////////////////////////////// + +void GdbEngine::makeSnapshot() +{ + QString fileName; + QTemporaryFile tf(QDir::tempPath() + _("/gdbsnapshot")); + if (tf.open()) { + fileName = tf.fileName(); + tf.close(); + postCommand("gcore " + fileName.toLocal8Bit(), + NeedsStop, CB(handleMakeSnapshot), fileName); + } else { + showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"), + tr("Cannot create snapshot file.")); + } +} + +void GdbEngine::handleMakeSnapshot(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + SnapshotData snapshot; + snapshot.setDate(QDateTime::currentDateTime()); + snapshot.setLocation(response.cookie.toString()); + snapshot.setFrames(manager()->stackHandler()->frames()); + manager()->snapshotHandler()->appendSnapshot(snapshot); + } else { + QByteArray msg = response.data.findChild("msg").data(); + showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"), + tr("Cannot create snapshot:\n") + QString::fromLocal8Bit(msg)); + } +} + +void GdbEngine::activateSnapshot(int index) +{ + SnapshotData snapshot = m_manager->snapshotHandler()->setCurrentIndex(index); + m_startParameters->startMode = AttachCore; + m_startParameters->coreFile = snapshot.location(); + + if (state() == InferiorUnrunnable) { + // All is well. We are looking at another core file. + setState(EngineShuttingDown); + setState(DebuggerNotReady); + activateSnapshot2(); + } else if (state() != DebuggerNotReady) { + QMessageBox *mb = showMessageBox(QMessageBox::Critical, + tr("Snapshot Reloading"), + tr("In order to load snapshots the debugged process needs " + "to be stopped. Continuation will not be possible afterwards.\n" + "Do you want to stop the debugged process and load the selected " + "snapshot?"), QMessageBox::Ok | QMessageBox::Cancel); + if (mb->exec() == QMessageBox::Cancel) + return; + debugMessage(_("KILLING DEBUGGER AS REQUESTED BY USER")); + delete m_gdbAdapter; + m_gdbAdapter = createAdapter(m_startParameters); + postCommand("kill", NeedsStop, CB(handleActivateSnapshot)); + } else { + activateSnapshot2(); + } +} + +void GdbEngine::handleActivateSnapshot(const GdbResponse &response) +{ + Q_UNUSED(response); + setState(InferiorShuttingDown); + setState(InferiorShutDown); + setState(EngineShuttingDown); + setState(DebuggerNotReady); + activateSnapshot2(); +} + +void GdbEngine::activateSnapshot2() +{ + // Otherwise the stack data might be stale. + // See http://sourceware.org/bugzilla/show_bug.cgi?id=1124. + setState(EngineStarting); + setState(AdapterStarting); + postCommand("set stack-cache off"); + handleAdapterStarted(); +} + + +////////////////////////////////////////////////////////////////////// +// // Register specific stuff // ////////////////////////////////////////////////////////////////////// diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index df6e9df97f..73560d55fa 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -349,6 +349,15 @@ private: ////////// View & Data Stuff ////////// bool m_modulesListOutdated; // + // Snapshot specific stuff + // + virtual void makeSnapshot(); + void handleMakeSnapshot(const GdbResponse &response); + void handleActivateSnapshot(const GdbResponse &response); + void activateSnapshot(int index); + void activateSnapshot2(); + + // // Register specific stuff // Q_SLOT virtual void reloadRegisters(); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 6733971d2d..cc0a91af28 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -95,6 +95,9 @@ public: virtual void activateFrame(int index) = 0; virtual void selectThread(int index) = 0; + virtual void makeSnapshot() {} + virtual void activateSnapshot(int index) { Q_UNUSED(index); } + virtual void attemptBreakpointSynchronization() = 0; virtual void reloadModules() = 0; diff --git a/src/plugins/debugger/images/debugger_snapshot_small.png b/src/plugins/debugger/images/debugger_snapshot_small.png Binary files differnew file mode 100644 index 0000000000..603c3732be --- /dev/null +++ b/src/plugins/debugger/images/debugger_snapshot_small.png diff --git a/src/plugins/debugger/snapshothandler.cpp b/src/plugins/debugger/snapshothandler.cpp new file mode 100644 index 0000000000..91260d353d --- /dev/null +++ b/src/plugins/debugger/snapshothandler.cpp @@ -0,0 +1,243 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** 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. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snapshothandler.h" + +#include "debuggeractions.h" + +#include <utils/qtcassert.h> + +#include <QtCore/QAbstractTableModel> +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> + +namespace Debugger { +namespace Internal { + +SnapshotData::SnapshotData() +{} + +void SnapshotData::clear() +{ + m_frames.clear(); + m_location.clear(); + m_date = QDateTime(); +} + +QString SnapshotData::function() const +{ + if (m_frames.isEmpty()) + return QString(); + const StackFrame &frame = m_frames.at(0); + return frame.function + ":" + QString::number(frame.line); +} + +QString SnapshotData::toString() const +{ + QString res; + QTextStream str(&res); + str << SnapshotHandler::tr("Function:") << ' ' << function() << ' ' + << SnapshotHandler::tr("File:") << ' ' << m_location << ' ' + << SnapshotHandler::tr("Date:") << ' ' << m_date.toString(); + return res; +} + +QString SnapshotData::toToolTip() const +{ + QString res; + QTextStream str(&res); + str << "<html><body><table>" + << "<tr><td>" << SnapshotHandler::tr("Function:") + << "</td><td>" << function() << "</td></tr>" + << "<tr><td>" << SnapshotHandler::tr("File:") + << "</td><td>" << QDir::toNativeSeparators(m_location) << "</td></tr>" + << "</table></body></html>"; + return res; +} + +QDebug operator<<(QDebug d, const SnapshotData &f) +{ + QString res; + QTextStream str(&res); + str << f.location(); +/* + str << "level=" << f.level << " address=" << f.address; + if (!f.function.isEmpty()) + str << ' ' << f.function; + if (!f.location.isEmpty()) + str << ' ' << f.location << ':' << f.line; + if (!f.from.isEmpty()) + str << " from=" << f.from; + if (!f.to.isEmpty()) + str << " to=" << f.to; +*/ + d.nospace() << res; + return d; +} + +//////////////////////////////////////////////////////////////////////// +// +// SnapshotHandler +// +//////////////////////////////////////////////////////////////////////// + +SnapshotHandler::SnapshotHandler(QObject *parent) + : QAbstractTableModel(parent), + m_positionIcon(QIcon(":/debugger/images/location.svg")), + m_emptyIcon(QIcon(":/debugger/images/empty.svg")) +{ + m_currentIndex = 0; + connect(theDebuggerAction(OperateByInstruction), SIGNAL(triggered()), + this, SLOT(resetModel())); +} + +SnapshotHandler::~SnapshotHandler() +{ + foreach (const SnapshotData &snapshot, m_snapshots) + QFile::remove(snapshot.location()); +} + +int SnapshotHandler::rowCount(const QModelIndex &parent) const +{ + // Since the stack is not a tree, row count is 0 for any valid parent + return parent.isValid() ? 0 : m_snapshots.size(); +} + +int SnapshotHandler::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 3; +} + +QVariant SnapshotHandler::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= m_snapshots.size()) + return QVariant(); + + if (index.row() == m_snapshots.size()) { + if (role == Qt::DisplayRole && index.column() == 0) + return tr("..."); + if (role == Qt::DisplayRole && index.column() == 1) + return tr("<More>"); + if (role == Qt::DecorationRole && index.column() == 0) + return m_emptyIcon; + return QVariant(); + } + + const SnapshotData &snapshot = m_snapshots.at(index.row()); + + if (role == Qt::DisplayRole) { + switch (index.column()) { + case 0: // Function name of topmost snapshot + return snapshot.function(); + case 1: // Timestamp + return snapshot.date().toString(); + case 2: // File name + return snapshot.location(); + } + return QVariant(); + } + + if (role == Qt::ToolTipRole) { + //: Tooltip for variable + return snapshot.toToolTip(); + } + + if (role == Qt::DecorationRole && index.column() == 0) { + // Return icon that indicates whether this is the active stack frame + return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon; + } + + //if (role == Qt::UserRole) + // return QVariant::fromValue(snapshot); + + return QVariant(); +} + +QVariant SnapshotHandler::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: return tr("Function"); + case 1: return tr("Date"); + case 2: return tr("Location"); + }; + } + return QVariant(); +} + +Qt::ItemFlags SnapshotHandler::flags(const QModelIndex &index) const +{ + if (index.row() >= m_snapshots.size()) + return 0; + if (index.row() == m_snapshots.size()) + return QAbstractTableModel::flags(index); + //const SnapshotData &snapshot = m_snapshots.at(index.row()); + return true ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0); +} + +void SnapshotHandler::removeAll() +{ + m_snapshots.clear(); + m_currentIndex = 0; + reset(); +} + +void SnapshotHandler::appendSnapshot(const SnapshotData &snapshot) +{ + m_snapshots.append(snapshot); + m_currentIndex = m_snapshots.size() - 1; + reset(); +} + +void SnapshotHandler::removeSnapshot(int index) +{ + QFile::remove(m_snapshots.at(index).location()); + m_snapshots.removeAt(index); + if (index == m_currentIndex) + m_currentIndex = -1; + else if (index < m_currentIndex) + --m_currentIndex; + reset(); +} + +QList<SnapshotData> SnapshotHandler::snapshots() const +{ + return m_snapshots; +} + +SnapshotData SnapshotHandler::setCurrentIndex(int index) +{ + m_currentIndex = index; + reset(); + return m_snapshots.at(index); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/snapshothandler.h b/src/plugins/debugger/snapshothandler.h new file mode 100644 index 0000000000..5612c7ad21 --- /dev/null +++ b/src/plugins/debugger/snapshothandler.h @@ -0,0 +1,124 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** 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. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_SNAPSHOTHANDLER_H +#define DEBUGGER_SNAPSHOTHANDLER_H + +#include "stackframe.h" + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QDateTime> +#include <QtCore/QObject> + +#include <QtGui/QIcon> + + +namespace Debugger { +namespace Internal { + +//////////////////////////////////////////////////////////////////////// +// +// SnapshotData +// +//////////////////////////////////////////////////////////////////////// + +/*! An entry in the snapshot model. */ + +class SnapshotData +{ +public: + SnapshotData(); + + void clear(); + QString toString() const; + QString toToolTip() const; + + QDateTime date() const { return m_date; } + void setDate(const QDateTime &date) { m_date = date; } + + void setLocation(const QString &location) { m_location = location; } + QString location() const { return m_location; } + + void setFrames(const QList<StackFrame> &frames) { m_frames = frames; } + QList<StackFrame> frames() const { return m_frames; } + + QString function() const; // Topmost entry. + +private: + QString m_location; // Name of the core file. + QDateTime m_date; // Date of the snapshot + QList<StackFrame> m_frames; // Stack frames. +}; + + +//////////////////////////////////////////////////////////////////////// +// +// SnapshotModel +// +//////////////////////////////////////////////////////////////////////// + +/*! A model to represent the snapshot in a QTreeView. */ +class SnapshotHandler : public QAbstractTableModel +{ + Q_OBJECT + +public: + SnapshotHandler(QObject *parent = 0); + ~SnapshotHandler(); + + void setFrames(const QList<SnapshotData> &snapshots, bool canExpand = false); + QList<SnapshotData> snapshots() const; + + // Called from SnapshotHandler after a new snapshot has been added + void removeAll(); + void removeSnapshot(int index); + QAbstractItemModel *model() { return this; } + int currentIndex() const { return m_currentIndex; } + void appendSnapshot(const SnapshotData &snapshot); + SnapshotData setCurrentIndex(int index); + +private: + // QAbstractTableModel + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + Q_SLOT void resetModel() { reset(); } + + int m_currentIndex; + QList<SnapshotData> m_snapshots; + const QVariant m_positionIcon; + const QVariant m_emptyIcon; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_SNAPSHOTHANDLER_H diff --git a/src/plugins/debugger/snapshotwindow.cpp b/src/plugins/debugger/snapshotwindow.cpp new file mode 100644 index 0000000000..6cf04f7873 --- /dev/null +++ b/src/plugins/debugger/snapshotwindow.cpp @@ -0,0 +1,176 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** 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. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snapshotwindow.h" + +#include "debuggeractions.h" +#include "debuggeragents.h" + +#include <utils/qtcassert.h> + +#include <QtCore/QDebug> + +#include <QtGui/QAction> +#include <QtGui/QApplication> +#include <QtGui/QClipboard> +#include <QtGui/QComboBox> +#include <QtGui/QHeaderView> +#include <QtGui/QMenu> +#include <QtGui/QResizeEvent> +#include <QtGui/QTreeView> +#include <QtGui/QVBoxLayout> + + +static QModelIndexList normalizeIndexes(const QModelIndexList &list) +{ + QModelIndexList res; + foreach (const QModelIndex &idx, list) + if (idx.column() == 0) + res.append(idx); + return res; +} + + +namespace Debugger { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// SnapshotWindow +// +/////////////////////////////////////////////////////////////////////// + +SnapshotWindow::SnapshotWindow(DebuggerManager *manager, QWidget *parent) + : QTreeView(parent), m_manager(manager), m_alwaysResizeColumnsToContents(false) +{ + m_disassemblerAgent = new DisassemblerViewAgent(manager); + + QAction *act = theDebuggerAction(UseAlternatingRowColors); + setWindowTitle(tr("Snapshots")); + + setAlternatingRowColors(act->isChecked()); + setRootIsDecorated(false); + setIconSize(QSize(10, 10)); + + header()->setDefaultAlignment(Qt::AlignLeft); + + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(rowActivated(QModelIndex))); + connect(act, SIGNAL(toggled(bool)), + this, SLOT(setAlternatingRowColorsHelper(bool))); +} + +SnapshotWindow::~SnapshotWindow() +{ + delete m_disassemblerAgent; +} + +void SnapshotWindow::rowActivated(const QModelIndex &index) +{ + m_manager->activateSnapshot(index.row()); +} + +void SnapshotWindow::removeSnapshots(const QModelIndexList &indexes) +{ + QTC_ASSERT(!indexes.isEmpty(), return); + QList<int> list; + foreach (const QModelIndex &idx, indexes) + list.append(idx.row()); + removeSnapshots(list); +} + +void SnapshotWindow::removeSnapshots(QList<int> list) +{ + if (list.empty()) + return; + const int firstRow = list.front(); + qSort(list.begin(), list.end()); + for (int i = list.size(); --i >= 0; ) + m_manager->removeSnapshot(list.at(i)); + + const int row = qMin(firstRow, model()->rowCount() - 1); + if (row >= 0) + setCurrentIndex(model()->index(row, 0)); +} + +void SnapshotWindow::keyPressEvent(QKeyEvent *ev) +{ + if (ev->key() == Qt::Key_Delete) { + QItemSelectionModel *sm = selectionModel(); + QTC_ASSERT(sm, return); + QModelIndexList si = sm->selectedIndexes(); + if (si.isEmpty()) + si.append(currentIndex().sibling(currentIndex().row(), 0)); + removeSnapshots(normalizeIndexes(si)); + } + QTreeView::keyPressEvent(ev); +} + +void SnapshotWindow::contextMenuEvent(QContextMenuEvent *ev) +{ + //QModelIndex idx = indexAt(ev->pos()); + + QMenu menu; + + QAction *actAdjust = menu.addAction(tr("Adjust column widths to contents")); + + QAction *actAlwaysAdjust = + menu.addAction(tr("Always adjust column widths to contents")); + actAlwaysAdjust->setCheckable(true); + actAlwaysAdjust->setChecked(m_alwaysResizeColumnsToContents); + + menu.addSeparator(); + + menu.addAction(theDebuggerAction(SettingsDialog)); + + QAction *act = menu.exec(ev->globalPos()); + + if (act == actAdjust) + resizeColumnsToContents(); + else if (act == actAlwaysAdjust) + setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents); +} + +void SnapshotWindow::resizeColumnsToContents() +{ + for (int i = model()->columnCount(); --i >= 0; ) + resizeColumnToContents(i); +} + +void SnapshotWindow::setAlwaysResizeColumnsToContents(bool on) +{ + m_alwaysResizeColumnsToContents = on; + QHeaderView::ResizeMode mode = + on ? QHeaderView::ResizeToContents : QHeaderView::Interactive; + for (int i = model()->columnCount(); --i >= 0; ) + header()->setResizeMode(i, mode); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/snapshotwindow.h b/src/plugins/debugger/snapshotwindow.h new file mode 100644 index 0000000000..71da468550 --- /dev/null +++ b/src/plugins/debugger/snapshotwindow.h @@ -0,0 +1,78 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** 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. +** +** GNU Lesser General Public License Usage +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_SNAPSHOTWINDOW_H +#define DEBUGGER_SNAPSHOTWINDOW_H + +#include <QtGui/QTreeView> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QComboBox; +class QModelIndex; +QT_END_NAMESPACE + +namespace Debugger { +class DebuggerManager; + +namespace Internal { +class DisassemblerViewAgent; + +class SnapshotWindow : public QTreeView +{ + Q_OBJECT + +public: + SnapshotWindow(DebuggerManager *manager, QWidget *parent = 0); + ~SnapshotWindow(); + +public slots: + void resizeColumnsToContents(); + void setAlwaysResizeColumnsToContents(bool on); + +private slots: + void rowActivated(const QModelIndex &index); + void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); } + +private: + void keyPressEvent(QKeyEvent *ev); + void contextMenuEvent(QContextMenuEvent *ev); + void removeSnapshots(const QModelIndexList &list); + void removeSnapshots(QList<int> rows); + + DebuggerManager *m_manager; + DisassemblerViewAgent *m_disassemblerAgent; + bool m_alwaysResizeColumnsToContents; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_SNAPSHOTWINDOW_H + diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 83c5c8f104..d308d61402 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -408,5 +408,6 @@ void ThreadsHandler::notifyRunning() it->notifyRunning(); emit dataChanged(index(0, 1), index(m_threads.size()- 1, ColumnCount - 1)); } + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/stackwindow.h b/src/plugins/debugger/stackwindow.h index c8e847b08a..c94034027c 100644 --- a/src/plugins/debugger/stackwindow.h +++ b/src/plugins/debugger/stackwindow.h @@ -52,9 +52,6 @@ public: StackWindow(DebuggerManager *manager, QWidget *parent = 0); ~StackWindow(); -signals: - void frameActivated(int); - public slots: void resizeColumnsToContents(); void setAlwaysResizeColumnsToContents(bool on); |