OSDN Git Service

Debugger: Add functionality for copying watch data to clipboard.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Mon, 14 Feb 2011 08:40:43 +0000 (09:40 +0100)
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>
Mon, 14 Feb 2011 08:40:43 +0000 (09:40 +0100)
in watch window and tooltips.

src/plugins/debugger/debuggertooltipmanager.cpp
src/plugins/debugger/debuggertooltipmanager.h
src/plugins/debugger/watchwindow.cpp

index 65aab92..738ab14 100644 (file)
@@ -65,6 +65,7 @@
 #include <QtGui/QLabel>
 #include <QtGui/QMenu>
 #include <QtGui/QAction>
+#include <QtGui/QClipboard>
 
 #include <QtCore/QVariant>
 #include <QtCore/QStack>
@@ -294,10 +295,15 @@ void XmlWriterTreeModelVisitor::handleItem(const QModelIndex &m)
     }
 }
 
-// TreeModelVisitor for debugging models
+// TreeModelVisitor for debugging/copying models
 class DumpTreeModelVisitor : public TreeModelVisitor {
 public:
-    explicit DumpTreeModelVisitor(const QAbstractItemModel *model, QTextStream &s);
+    enum Mode
+    {
+        DebugMode,      // For debugging, "|'data'|"
+        ClipboardMode   // Tab-delimited "\tdata" for clipboard (see stack window)
+    };
+    explicit DumpTreeModelVisitor(const QAbstractItemModel *model, Mode m, QTextStream &s);
 
 protected:
     virtual void rowStarted();
@@ -305,31 +311,61 @@ protected:
     virtual void rowEnded();
 
 private:
+    const Mode m_mode;
+
     QTextStream &m_stream;
     int m_level;
+    unsigned m_itemsInRow;
 };
 
-DumpTreeModelVisitor::DumpTreeModelVisitor(const QAbstractItemModel *model, QTextStream &s) :
-    TreeModelVisitor(model), m_stream(s), m_level(0)
+DumpTreeModelVisitor::DumpTreeModelVisitor(const QAbstractItemModel *model, Mode m, QTextStream &s) :
+    TreeModelVisitor(model), m_mode(m), m_stream(s), m_level(0), m_itemsInRow(0)
 {
-    m_stream << model->metaObject()->className() << '/' << model->objectName();
+    if (m_mode == DebugMode)
+        m_stream << model->metaObject()->className() << '/' << model->objectName();
 }
 
 void DumpTreeModelVisitor::rowStarted()
 {
     m_level++;
-    m_stream << '\n' << QString(2 * m_level, QLatin1Char(' '));
+    if (m_itemsInRow) { // Nested row.
+        m_stream << '\n';
+        m_itemsInRow = 0;
+    }
+    switch (m_mode) {
+    case DebugMode:
+        m_stream << QString(2 * m_level, QLatin1Char(' '));
+        break;
+    case ClipboardMode:
+        m_stream << QString(m_level, QLatin1Char('\t'));
+        break;
+    }
 }
 
 void DumpTreeModelVisitor::handleItem(const QModelIndex &m)
 {
-    if (m.column())
-        m_stream << '|';
-    m_stream << '\'' << m.data().toString() << '\'';
+    const QString data = m.data().toString();
+    switch (m_mode) {
+    case DebugMode:
+        if (m.column())
+            m_stream << '|';
+        m_stream << '\'' << data << '\'';
+        break;
+    case ClipboardMode:
+        if (m.column())
+            m_stream << '\t';
+        m_stream << data;
+        break;
+    }
+    m_itemsInRow++;
 }
 
 void DumpTreeModelVisitor::rowEnded()
 {
+    if (m_itemsInRow) {
+        m_stream << '\n';
+        m_itemsInRow = 0;
+    }
     m_level--;
 }
 
@@ -340,7 +376,7 @@ static inline QDebug operator<<(QDebug d, const QAbstractItemModel &model)
 {
     QString s;
     QTextStream str(&s);
-    Debugger::Internal::DumpTreeModelVisitor v(&model, str);
+    Debugger::Internal::DumpTreeModelVisitor v(&model, Debugger::Internal::DumpTreeModelVisitor::DebugMode, str);
     v.run();
     qDebug().nospace() << s;
     return d;
@@ -390,7 +426,6 @@ PinnableToolTipWidget::PinnableToolTipWidget(QWidget *parent) :
     const QList<QSize> pinIconSizes = pinIcon.availableSizes();
 
     m_toolButton->setIcon(pinIcon);
-    m_menu->addAction(tr("Close All"), this, SIGNAL(closeAllRequested()));
     m_toolButton->setMenu(m_menu);
     m_toolButton->setPopupMode(QToolButton::MenuButtonPopup);
     connect(m_toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked()));
@@ -405,6 +440,16 @@ PinnableToolTipWidget::PinnableToolTipWidget(QWidget *parent) :
     setLayout(m_mainVBoxLayout);
 }
 
+void PinnableToolTipWidget::addMenuAction(QAction *a)
+{
+    m_menu->addAction(a);
+}
+
+void PinnableToolTipWidget::addCloseAllMenuAction()
+{
+    m_menu->addAction(tr("Close All"), this, SIGNAL(closeAllRequested()));
+}
+
 void PinnableToolTipWidget::addWidget(QWidget *w)
 {
     w->setFocusPolicy(Qt::NoFocus);
@@ -510,6 +555,10 @@ AbstractDebuggerToolTipWidget::AbstractDebuggerToolTipWidget(QWidget *parent) :
 {
     m_titleLabel->setText(msgReleasedText());
     addToolBarWidget(m_titleLabel);
+    QAction *copyAction = new QAction(tr("Copy"), this);
+    connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
+    addMenuAction(copyAction);
+    addCloseAllMenuAction();
 }
 
 bool AbstractDebuggerToolTipWidget::matches(const QString &fileName,
@@ -553,6 +602,16 @@ void AbstractDebuggerToolTipWidget::releaseEngine()
     m_engineAcquired = false;
 }
 
+void AbstractDebuggerToolTipWidget::copy()
+{
+    const QString clipboardText = clipboardContents();
+    QClipboard *clipboard = QApplication::clipboard();
+#ifdef Q_WS_X11
+    clipboard->setText(clipboardText, QClipboard::Selection);
+#endif
+    clipboard->setText(clipboardText, QClipboard::Clipboard);
+}
+
 bool AbstractDebuggerToolTipWidget::positionShow(const QPlainTextEdit *pe)
 {
     // Figure out new position of tooltip using the text edit.
@@ -912,6 +971,22 @@ void DebuggerTreeViewToolTipWidget::doLoadSessionData(QXmlStreamReader &r)
     m_treeView->swapModel(m_defaultModel);
 }
 
+QString DebuggerTreeViewToolTipWidget::treeModelClipboardContents(const QAbstractItemModel *m)
+{
+    QString rc;
+    QTextStream str(&rc);
+    DumpTreeModelVisitor v(m, DumpTreeModelVisitor::ClipboardMode, str);
+    v.run();
+    return rc;
+}
+
+QString DebuggerTreeViewToolTipWidget::clipboardContents() const
+{
+    if (const QAbstractItemModel *model = m_treeView->model())
+        return DebuggerTreeViewToolTipWidget::treeModelClipboardContents(model);
+    return QString();
+}
+
 /*!
     \class DebuggerToolTipManager
 
index c50dd02..f17ee5a 100644 (file)
@@ -54,6 +54,7 @@ class QLabel;
 class QToolBar;
 class QMenu;
 class QDebug;
+class QAction;
 QT_END_NAMESPACE
 
 namespace Core {
@@ -82,6 +83,9 @@ public:
 
     void addWidget(QWidget *w);
     void addToolBarWidget(QWidget *w);
+    void addMenuAction(QAction *a);
+    // Add an action to "close all". Call in constructor after populating the tool button menu.
+    void addCloseAllMenuAction();
 
 public slots:
     void pin();
@@ -151,6 +155,7 @@ public slots:
 
     void acquireEngine(Debugger::DebuggerEngine *engine);
     void releaseEngine();
+    void copy();
     bool positionShow(const QPlainTextEdit *pe);
 
 protected:
@@ -158,6 +163,8 @@ protected:
     virtual void doReleaseEngine() = 0;
     virtual void doSaveSessionData(QXmlStreamWriter &w) const = 0;
     virtual void doLoadSessionData(QXmlStreamReader &r) = 0;
+    // Return a string suitable for copying contents
+    virtual QString clipboardContents() const { return QString(); }
 
 private:
     static AbstractDebuggerToolTipWidget *loadSessionDataI(QXmlStreamReader &r);
@@ -202,11 +209,14 @@ public:
     QString expression() const { return m_expression; }
     void setExpression(const QString &e) { m_expression = e; }
 
+    static QString treeModelClipboardContents(const QAbstractItemModel *m);
+
 protected:
     virtual void doAcquireEngine(Debugger::DebuggerEngine *engine);
     virtual void doReleaseEngine();
     virtual void doSaveSessionData(QXmlStreamWriter &w) const;
     virtual void doLoadSessionData(QXmlStreamReader &r);
+    virtual QString clipboardContents() const;
 
 private:
     static void restoreTreeModel(QXmlStreamReader &r, QStandardItemModel *m);
index 2af4485..19b3eb7 100644 (file)
@@ -41,6 +41,7 @@
 #include "debuggerengine.h"
 #include "watchdelegatewidgets.h"
 #include "watchhandler.h"
+#include "debuggertooltipmanager.h"
 
 #include <utils/qtcassert.h>
 #include <utils/savedaction.h>
@@ -55,7 +56,8 @@
 #include <QtGui/QItemDelegate>
 #include <QtGui/QMenu>
 #include <QtGui/QResizeEvent>
-
+#include <QtGui/QClipboard>
+#include <QtGui/QApplication>
 
 /////////////////////////////////////////////////////////////////////
 //
@@ -421,6 +423,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
         memoryMenu.setEnabled(false);
     }
 
+    QAction *actCopy = new QAction(tr("Copy Contents to Clipboard"), &menu);
+
     menu.addAction(actInsertNewWatchItem);
     menu.addAction(actSelectWidgetToWatch);
     menu.addMenu(&formatMenu);
@@ -428,6 +432,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     menu.addAction(actSetWatchpointAtVariableAddress);
     if (actSetWatchpointAtPointerValue)
         menu.addAction(actSetWatchpointAtPointerValue);
+    menu.addAction(actCopy );
     menu.addSeparator();
 
     menu.addAction(debuggerCore()->action(UseDebuggingHelpers));
@@ -485,6 +490,13 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
         watchExpression(exp);
     } else if (act == actRemoveWatchExpression) {
         removeWatchExpression(exp);
+    } else if (act == actCopy ) {
+        const QString clipboardText = DebuggerTreeViewToolTipWidget::treeModelClipboardContents(model());
+        QClipboard *clipboard = QApplication::clipboard();
+#ifdef Q_WS_X11
+        clipboard->setText(clipboardText, QClipboard::Selection);
+#endif
+        clipboard->setText(clipboardText, QClipboard::Clipboard);
     } else if (act == actRemoveWatches) {
         currentEngine()->watchHandler()->clearWatches();
     } else if (act == actClearCodeModelSnapshot) {