summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2010-02-02 17:25:14 +0100
committerhjk <qtc-committer@nokia.com>2010-02-03 08:37:48 +0100
commit18445dc9c649036bf97631de2d1866ee036557a8 (patch)
tree1c2ed9883940c7ebfa410699843bce0691e6407b /src
parent7c823c6a26a4c3b1a078e09a1f59adcee2ceef52 (diff)
downloadqt-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.pro4
-rw-r--r--src/plugins/debugger/debugger.qrc1
-rw-r--r--src/plugins/debugger/debuggeractions.h1
-rw-r--r--src/plugins/debugger/debuggermanager.cpp52
-rw-r--r--src/plugins/debugger/debuggermanager.h5
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp9
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp100
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h9
-rw-r--r--src/plugins/debugger/idebuggerengine.h3
-rw-r--r--src/plugins/debugger/images/debugger_snapshot_small.pngbin0 -> 340 bytes
-rw-r--r--src/plugins/debugger/snapshothandler.cpp243
-rw-r--r--src/plugins/debugger/snapshothandler.h124
-rw-r--r--src/plugins/debugger/snapshotwindow.cpp176
-rw-r--r--src/plugins/debugger/snapshotwindow.h78
-rw-r--r--src/plugins/debugger/stackhandler.cpp1
-rw-r--r--src/plugins/debugger/stackwindow.h3
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
new file mode 100644
index 0000000000..603c3732be
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_snapshot_small.png
Binary files differ
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);