[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kdevelop-devel
Subject:    [PATCH] Improved variables view
From:       Vladimir Prus <ghost () cs ! msu ! su>
Date:       2005-06-08 11:06:57
Message-ID: 200506081506.57521.ghost () cs ! msu ! su
[Download RAW message or body]

Hello!

Attached is the patch that implements most of my suggestions for the variables 
view.

Now on variables in the current frame are shown. It's possible to either
evaluate an expression, or add a watch. The list of recently evaluated 
expressions is shown in the variables view, and it's possible to change a 
name of such expression to something more memorable.

Additionally, I've somewhat refactored interaction between gdbcontroller and 
variablewidget. Previously, gdbcontroller called a large number of vartree 
functions, now most interaction is done with signals, which I find a bit 
cleaner.

What I did not yet do is changing variables right in var widget, but my patch 
has grown long enough already ;-)

A couple of snapshots are
   http://zigzag.cs.msu.su/~ghost/variables_during_debugging.png
   http://zigzag.cs.msu.su/~ghost/variables_popup.png


Comments are very welcome!

- Volodya

Log message:
1. Do not immediately switch frames and hide framestack widget, when
opening an item corresponding to a frame. Switch frame only when frame
item is explicitly selected.

See
http://barney.cs.uni-potsdam.de/mailman/private/kdevelop-devel/2005-May/033098.html
for rationale.

2. Show only variables for the current frame in variables view

3. Allow to either evaluate an expression, and add it to the list of watched
   expressions.

4. Refactor communication between gdbcontroller and variableswidget to reduce
   the number of direct calls from gdbcontroller to methods of
   variableswidget.

* gdbcontroller.h 
  gdbcontroller.cpp:
  (GDBController::slotProduceBacktrace): New slot. Gets backtrace for
  a thread via "thread apply XXX backtrace" and so doesn't change current
  thread.
  (GDBController::slotProduceVariablesInfo): New slot. Gets info about
  parameters and local variables of a function. 
  (GDBController::parametersReady, GDBController::localsReady): New signals,
  emitted whenever gdb parses the corresponding reply from gdb. 
  (GDBController::currentFrame): New signal, emitted after current frame might
   have changed.  
  (GDBController::actOnProgramPause): Do not issue "info locals". Emit   
  'currentFrame'.
  (GDBController::programNoApp): Don't invoke variablewidget method. Rely
   instead on proper handling of the dbgStatus.
  (GDBController::parseBacktraceList): Don't trim frames in variables view.
   This will be done anyway on first currentFrame signal after program pause.
  (GDBController::parseLocals): Just emit parametersReady and localsReady.
 
* variablewidget.h
  variablewidget.cpp:
  (VariableWidget::slotEvaluateExpression): New slot.
  (VariableTree::setLocalViewState, setCurrentThread): Remove.
  (VariableTree::produceVariablesInfo): New signal.
  (VariableWidget::VariableWidget): Create new "Eval" button.
  (VariableTree::slotDbgStatus): New slot. Trim everything when the
   program no longer exists, and set a flag immediately after restart.
  (VariableTree::slotCurrentFrame): New slot. Hide VarFrameRoot corresponding
  to the previous frame, show the one corresponding to the selected one,
  and populate it with variables if needed.


* framestackwidget.h
  framestackwidget.cpp:
  (FramestackWidget::produceBacktrace): New signal.
  (FramestackWidget::getBacktrace): New method.
  (ThreadStackItem::setOpen): Only fetch backtrace when there are no
  children. Otherwise, when viewedThread_->setOpen(true) is called
  after parsing backtrace we immediately emit another signal.

["new_vars_view.diff" (text/x-diff)]

Index: variablewidget.h
===================================================================
--- variablewidget.h	(revision 412370)
+++ variablewidget.h	(working copy)
@@ -59,6 +59,8 @@
 public slots:
     void slotAddWatchVariable();
     void slotAddWatchVariable(const QString &ident);
+    void slotEvaluateExpression();
+    void slotEvaluateExpression(const QString &ident);
 
 private:
     VariableTree *varTree_;
@@ -91,13 +93,10 @@
     QListViewItem *findRoot(QListViewItem *item) const;
     VarFrameRoot *findFrame(int frameNo, int threadNo) const;
     WatchRoot *findWatch();
-    void setCurrentThread(int currentThread)
-                                        { currentThread_ = currentThread; }
 
     // Remove items that are not active
     void trim();
     void trimExcessFrames();
-    void setLocalViewState(bool localsOn, int frameNo, int threadNo);
 
 	// (from QToolTip) Display a tooltip when the cursor is over an item
 	virtual void maybeTip(const QPoint &);
@@ -108,6 +107,9 @@
     void expandItem(TrimmableItem *item);
     void expandUserItem(VarItem *item, const QCString &request);
     void setLocalViewState(bool localsOn);
+    // Emitted when *this is interested in args and locals for the
+    // current frame.
+    void produceVariablesInfo();
 
     // jw
     void varItemConstructed(VarItem *item);
@@ -116,22 +118,39 @@
     void toggleRadix(QListViewItem *item);
 public slots:
     void slotAddWatchVariable(const QString& watchVar);
+    void slotEvaluateExpression(const QString& expression);
 
     //rgr
     void slotToggleRadix(QListViewItem *item);
 
+    void slotDbgStatus(const QString &status, int statusFlag);
+    void slotParametersReady(const char* data);
+    void slotLocalsReady(const char* data);
+    void slotCurrentFrame(int frameNo, int threadNo);
+
 private slots:
     void slotContextMenu(KListView *, QListViewItem *item);
 
     // jw
     void slotDoubleClicked(QListViewItem *item, const QPoint &pos, int c);
 
+private: // helper functions
+    /** Get (if exists) and create (otherwise) frame root for
+        the specified frameNo/threadNo combination.
+    */    
+    VarFrameRoot* demand_frame_root(int frameNo, int threadNo);
+
 private:
     int activeFlag_;
     int currentThread_;
+    int currentFrame_;
     int iOutRadix;
+    bool justPaused_;
     //DbgController *controller;
 
+    // Root of all recently printed expressions.
+    TrimmableItem* recentExpressions_;
+
     friend class VarFrameRoot;
     friend class VarItem;
     friend class WatchRoot;
@@ -141,6 +160,24 @@
 /***************************************************************************/
 /***************************************************************************/
 
+/** List view item that can 'trim' outdated children.
+
+    The instances of this class hold a number of children corresponding
+    to variables. When program state changes, such as after a step in source,
+    some variable values can change, and some variables can go out of scope.
+    We need
+    - highlight modified variables
+    - remove gone variables
+
+    We could just remove all children and repopulate the list from
+    the data from debugger, but then we'd loose information about previous
+    variable values.
+
+    So, we first update the values, highlighting the modified variables, and
+    keeping track which variables were recieved from gdb. After that, the
+    'trim' method is called, removing all variables which were not recieved
+    from gdbr.    
+ */
 class TrimmableItem : public KListViewItem
 {
 public:
@@ -236,8 +273,10 @@
     VarFrameRoot(VariableTree *parent, int frameNo, int threadNo);
     virtual ~VarFrameRoot();
 
-    void setLocals(char *locals);
-    void setParams(char *params);
+    // Sets parameter information as passed from gdb.
+    void setParams(const char *params);
+    void setLocals(const char *locals);
+
     void setOpen(bool open);
 
     void setFrameName(const QString &frameName)
Index: gdbcontroller.h
===================================================================
--- gdbcontroller.h	(revision 412370)
+++ gdbcontroller.h	(working copy)
@@ -116,6 +116,10 @@
     void slotExpandUserItem(VarItem *parent, const QCString &userRequest);
     void slotSelectFrame(int frameNo, int threadNo, bool needFrames);
     void slotSetLocalViewState(bool onOff);
+    void slotProduceBacktrace(int threadNo);
+    /** Produces information about local variables of the current frame
+        by means of emitting localsReady and parametersReady signals. */
+    void slotProduceVariablesInfo();
 
     // jw - type determination requires a var object, so we do it here
     void slotVarItemConstructed(VarItem *item);
@@ -132,6 +136,15 @@
     void acceptPendingBPs     ();
     void unableToSetBPNow     (int BPNo);
     void debuggerRunError(int errorCode);
+    // Emitted whenever parameters info for the current frame is ready.
+    void parametersReady(const char* buf);
+    // Emitted whenever local vars info for the the current frame is ready.
+    void localsReady(const char* buf);
+    // Emitted to annouce what is the current frame, either after it's
+    // explicitly changed, of after it could possible changed (such as after
+    // "continue"). The singal can be emitted twice with the same parameters,
+    // and recievers should be prepared to handle it.
+    void currentFrame(int frameNo, int threadNo);
 
 private:
     FramestackWidget* frameStack_;
@@ -154,7 +167,6 @@
     // Some state variables
     int               state_;
     bool              programHasExited_;
-    bool              backtraceDueToProgramStop_;
 
     // Configuration values
     QDomDocument &dom;
Index: framestackwidget.h
===================================================================
--- framestackwidget.h	(revision 412370)
+++ framestackwidget.h	(working copy)
@@ -93,11 +93,14 @@
     int viewedThread()
     { return viewedThread_ ? viewedThread_->threadNo() : -1; }
 
+    void getBacktrace(int threadNo);
+
 public slots:
     void slotSelectFrame(int frameNo, int threadNo);
     void slotSelectionChanged(QListViewItem *thisItem);
 
 signals:
+    void produceBacktrace(int threadNo);
     void selectFrame(int frameNo, int threadNo, bool needFrames);
 
 #if QT_VERSION < 300
Index: variablewidget.cpp
===================================================================
--- variablewidget.cpp	(revision 412370)
+++ variablewidget.cpp	(working copy)
@@ -36,6 +36,30 @@
 #include <qclipboard.h>
 #include <kapplication.h>
 
+
+/** The variables widget is passive, and is invoked by the rest of the
+    code via two main slots:
+    - slotDbgStatus
+    - slotCurrentFrame
+
+    The first is received the program status changes and the second is
+    recieved after current frame in the debugger can possibly changes.
+
+    The widget has a list item for each frame/thread combination, with
+    variables as children. However, at each moment only one item is shown.
+    When handling the slotCurrentFrame, we check if variables for the
+    current frame are available. If yes, we simply show the corresponding item.
+    Otherwise, we fetch the new data from debugger.
+
+    Fetching the data is done by emitting the produceVariablesInfo signal.
+    In response, we get slotParametersReady and slotLocalsReady signal,
+    in that order.
+
+    The data is parsed and changed variables are highlighted. After that,
+    we 'trim' variable items that were not reported by gdb -- that is, gone
+    out of scope.
+*/
+
 // **************************************************************************
 // **************************************************************************
 // **************************************************************************
@@ -47,39 +71,41 @@
     : QWidget(parent, name)
 {
     varTree_ = new VariableTree(this);
-    QLabel *label = new QLabel(i18n("E&xpression to watch:"), this);
 
-    QHBox *watchEntry = new QHBox( this );
-
-    watchVarEditor_ = new KHistoryCombo( watchEntry, "var-to-watch editor");
+    
+    QHBox* expression_entry = new QHBox(this);
+    
+    QLabel *label = new QLabel(i18n("E&xpression:"), expression_entry);    
+    label->adjustSize();
+    label->setFixedWidth(label->width());
+    watchVarEditor_ = new KHistoryCombo( expression_entry, 
+                                         "var-to-watch editor");
     label->setBuddy(watchVarEditor_);
 
-//    watchVarEntry_ = new KLineEdit(this);
+    QHBox* buttons = new QHBox(this);
 
-    QPushButton *addButton = new QPushButton(i18n("&Add"), watchEntry );
+    QSpacerItem* spacer = new QSpacerItem( 5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding );
+    buttons->layout()->addItem(spacer);
+
+    QPushButton *evalButton = new QPushButton(i18n("&Evaluate"), buttons );
+    evalButton->adjustSize();
+    evalButton->setFixedWidth(evalButton->width());
+
+    QPushButton *addButton = new QPushButton(i18n("&Watch"), buttons );
     addButton->adjustSize();
     addButton->setFixedWidth(addButton->width());
 
-    QBoxLayout * vbox = new QVBoxLayout();
-
-//    QBoxLayout *watchEntry = new QHBoxLayout();
-//    watchEntry->addWidget(label);
-//    watchEntry->addWidget(watchVarEntry_);
-//    watchEntry->addWidget(watchVarEditor_);
-//    watchEntry->setStretchFactor(watchVarEditor_, 1);
-//    watchEntry->addWidget(addButton);
-
-    vbox->addWidget( label );
-    vbox->addWidget( watchEntry );
-
     QVBoxLayout *topLayout = new QVBoxLayout(this, 2);
     topLayout->addWidget(varTree_, 10);
-    topLayout->addLayout( vbox );
+    topLayout->addWidget(expression_entry);
+    topLayout->addWidget(buttons);
+    
 
     connect( addButton, SIGNAL(clicked()), SLOT(slotAddWatchVariable()) );
-    connect( watchVarEditor_, SIGNAL(returnPressed()), SLOT(slotAddWatchVariable()) );
-//    connect( watchVarEntry_, SIGNAL(returnPressed()), SLOT(slotAddWatchVariable()) );
+    connect( evalButton, SIGNAL(clicked()), SLOT(slotEvaluateExpression()) );
 
+    connect( watchVarEditor_, SIGNAL(returnPressed()), 
+             SLOT(slotEvaluateExpression()) );
 }
 
 // **************************************************************************
@@ -134,6 +160,25 @@
     }
 }
 
+void VariableWidget::slotEvaluateExpression()
+{
+    QString exp(watchVarEditor_->currentText());
+    if (!exp.isEmpty())
+    {
+        slotEvaluateExpression(exp);
+    }
+}
+
+void VariableWidget::slotEvaluateExpression(const QString &ident)
+{
+    if (!ident.isEmpty())
+    {
+        watchVarEditor_->addToHistory(ident);
+        varTree_->slotEvaluateExpression(ident);
+        watchVarEditor_->clearEdit();
+    }    
+}
+
 // **************************************************************************
 
 void VariableWidget::focusInEvent(QFocusEvent */*e*/)
@@ -142,6 +187,8 @@
 }
 
 
+
+
 // **************************************************************************
 // **************************************************************************
 // **************************************************************************
@@ -150,7 +197,9 @@
     : KListView(parent, name),
       QToolTip( viewport() ),
       activeFlag_(0),
-      currentThread_(-1)
+      currentThread_(-1),
+      justPaused_(false),
+      recentExpressions_(0)
 {
     setRootIsDecorated(true);
     setAllColumnsShowFocus(true);
@@ -193,16 +242,22 @@
     if (item->parent())
     {
         KPopupMenu popup(item->text(VarNameCol), this);
-        int idRemoveWatch = -2;
-        if (dynamic_cast<WatchRoot*>(findRoot(item)))
-            idRemoveWatch = popup.insertItem( i18n("Remove Watch Variable") );
+        int idRemove = -2;
+        int idReevaluate = -2;
+        QListViewItem* root = findRoot(item);
+        if (dynamic_cast<WatchRoot*>(root))
+            idRemove = popup.insertItem( i18n("Remove Watch Variable") );
+        if (root == recentExpressions_) {
+            idRemove = popup.insertItem( i18n("Remove Expression") );
+            idReevaluate = popup.insertItem( i18n("Reevalaute Expression") );
+        }
 
         int idToggleWatch = popup.insertItem( i18n("Toggle Watchpoint") );
         int idToggleRadix = popup.insertItem( i18n("Toggle Hex/Decimal") );
         int	idCopyToClipboard = popup.insertItem( i18n("Copy to Clipboard") );
         int res = popup.exec(QCursor::pos());
 
-        if (res == idRemoveWatch)
+        if (res == idRemove)
             delete item;
         if (res == idToggleRadix)
             emit toggleRadix(item);
@@ -224,6 +279,13 @@
             if (VarItem *item = dynamic_cast<VarItem*>(currentItem()))
                 emit toggleWatchpoint(item->fullName());
         }
+        else if (res == idReevaluate)
+        {
+            if (VarItem* item = dynamic_cast<VarItem*>(currentItem()))
+            {
+                emit expandItem(item);
+            }
+        }
     }
 }
 
@@ -236,6 +298,21 @@
     emit expandItem(varItem);
 }
 
+void VariableTree::slotEvaluateExpression(const QString &expression)
+{
+    if (recentExpressions_ == 0)
+    {
+        recentExpressions_ = new TrimmableItem(this);
+        recentExpressions_->setText(0, "Recent");
+        recentExpressions_->setOpen(true);
+    }
+
+    VarItem *varItem = new VarItem(recentExpressions_, expression, typeUnknown);
+    varItem->setRenameEnabled(0, 1);
+    emit expandItem(varItem);
+}
+
+
 // **************************************************************************
 
 // jw
@@ -257,30 +334,6 @@
 
 // **************************************************************************
 
-void VariableTree::setLocalViewState(bool localsOn, int frameNo, int threadNo)
-{
-    // When they want to _close_ a frame then we need to check the state of
-    // all other frames to determine whether we still need the locals.
-    if (!localsOn) {
-        QListViewItem *sibling = firstChild();
-        while (sibling) {
-            VarFrameRoot *frame = dynamic_cast<VarFrameRoot*> (sibling);
-            if (frame && frame->isOpen()) {
-                localsOn = true;
-                break;
-            }
-
-            sibling = sibling->nextSibling();
-        }
-    }
-
-    emit setLocalViewState(localsOn);
-    emit selectFrame(frameNo, threadNo);
-}
-
-
-// **************************************************************************
-
 QListViewItem *VariableTree::findRoot(QListViewItem *item) const
 {
     while (item->parent())
@@ -333,8 +386,9 @@
     while (child) {
         QListViewItem *nextChild = child->nextSibling();
 
-        // don't trim the watch root
-        if (!(dynamic_cast<WatchRoot*> (child))) {
+        // don't trim the watch root, or 'recent expressions' root.
+        if (!(dynamic_cast<WatchRoot*> (child)) 
+            && child != recentExpressions_) {
             if (TrimmableItem *item = dynamic_cast<TrimmableItem*> (child)) {
                 if (item->isActive())
                     item->trim();
@@ -434,6 +488,122 @@
   pOldItem=NULL;
 }
 
+void VariableTree::slotDbgStatus(const QString&, int statusFlag)
+{
+    if (statusFlag & s_appNotStarted)
+    {
+        // The application no longer exists. Remove all locals.
+        setActiveFlag();
+
+        // Now wipe the tree out
+        viewport()->setUpdatesEnabled(false);
+        trim();
+        setUpdatesEnabled(true);
+        repaint();
+    }
+    else
+    {
+        // Application still exists.
+        if (!(statusFlag & s_appBusy))
+        {
+            // But is not busy. This means application has just stopped for
+            // some reason. Need to refresh locals when
+            // slotChangedFrame is called. Cannot do it here, because
+            // we don't know which thread we're in.
+            justPaused_ = true;
+        }
+    }
+}
+
+VarFrameRoot* VariableTree::demand_frame_root(int frameNo, int threadNo)
+{
+    VarFrameRoot *frame = findFrame(frameNo, threadNo); 
+    if (!frame)
+    {
+        frame = new VarFrameRoot(this, frameNo, threadNo);
+        frame->setFrameName("Locals");
+        // Make sure "Locals" item is always the top item, before
+        // "watch" and "recent experessions" items.
+       this->takeItem(frame);
+       this->insertItem(frame);
+    }
+    return frame;
+}
+
+void VariableTree::slotParametersReady(const char* data)
+{
+    viewport()->setUpdatesEnabled(false);
+
+    // The locals are always attached to the currentFrame
+    VarFrameRoot *frame = demand_frame_root(currentFrame_, currentThread_);
+    frame->setParams(data);
+
+    viewport()->setUpdatesEnabled(true);
+    viewport()->repaint();
+}
+
+void VariableTree::slotLocalsReady(const char* data)
+{
+    viewport()->setUpdatesEnabled(false);
+
+    VarFrameRoot *frame = demand_frame_root(currentFrame_, currentThread_);
+    frame->setLocals(data);
+    frame->setOpen(true);
+    
+    // If we're regetting locals for the frame 0, it surely means
+    // the application was just paused. Otherwise, 
+    // (say after selecting frame 1 and then frame 0) we'd have locals
+    // for frame 0 already. If app was just paused, then other frames
+    // are out-of-date, and we trim them. If user later selects frame 1,
+    // we get locals for that frame.
+    // TODO: should we reset data for other threads?
+    if (currentFrame_ == 0 || currentThread_ == -1)
+        trim();
+    else 
+       frame->trim();
+
+    viewport()->setUpdatesEnabled(true);
+    viewport()->repaint();
+}
+
+void VariableTree::slotCurrentFrame(int frameNo, int threadNo)
+{
+    // It's quite likely that frameNo == currentFrame_ and
+    // threadNo == currentThread_. For example, this happens
+    // when the 'step' command is executed.
+    if (frameNo != currentFrame_ || threadNo != currentThread_)
+    {
+        // Hide the current frame vars root.
+        demand_frame_root(currentFrame_, currentThread_)->setVisible(false);
+        
+        currentFrame_ = frameNo;
+        currentThread_ = threadNo;
+    }
+
+    // Show the current frame.
+    VarFrameRoot* frame = demand_frame_root(currentFrame_, currentThread_);
+    frame->setVisible(true);
+        
+    // If no locals for frame were obtained, reget the local.
+    // Also reget the locals if the program was just paused. In that
+    // case we're always on frame 0, and the setLocals function
+    // we eventually remove frames 1, N, if they are present. They
+    // will be repopulated if needed.
+    if (frame->needLocals() || justPaused_) 
+    {
+        setActiveFlag();
+        // This will eventually call back to slotParametersReady and 
+        // slotLocalsReady
+        emit produceVariablesInfo();
+
+        if (justPaused_)
+        {
+            findWatch()->requestWatchVars();
+        }
+        justPaused_ = false;
+    }
+}
+
 // **************************************************************************
 // **************************************************************************
 // **************************************************************************
@@ -915,7 +1085,7 @@
 
 // **************************************************************************
 
-void VarFrameRoot::setParams(char *params)
+void VarFrameRoot::setParams(const char *params)
 {
     setActive();
     params_ = params;
@@ -923,7 +1093,7 @@
 
 // **************************************************************************
 
-void VarFrameRoot::setLocals(char *locals)
+void VarFrameRoot::setLocals(const char *locals)
 {
     setActive();
 
@@ -953,12 +1123,8 @@
 // state. This
 void VarFrameRoot::setOpen(bool open)
 {
-    bool localStateChange = (isOpen() != open);
     QListViewItem::setOpen(open);
 
-    if (localStateChange)
-        ((VariableTree*)listView())->setLocalViewState(open, frameNo_, threadNo_);
-
     if (!open)
         return;
 
Index: gdbcontroller.cpp
===================================================================
--- gdbcontroller.cpp	(revision 412370)
+++ gdbcontroller.cpp	(working copy)
@@ -139,7 +139,6 @@
         badCore_(QString()),
         state_(s_dbgNotStarted|s_appNotStarted|s_silent),
         programHasExited_(false),
-        backtraceDueToProgramStop_(false),
         dom(projectDom),
         config_breakOnLoadingLibrary_(true),
         config_forceBPSet_(true),
@@ -408,22 +407,17 @@
         // and we must reset the active flag
         viewedThread_ = -1;
         currentFrame_ = 0;
-        varTree_->setActiveFlag();
-        backtraceDueToProgramStop_ = true;
 
         // These two need to be actioned immediately. The order _is_ important
         if (stateIsOn(s_viewThreads))
             queueCmd(new GDBCommand("info thread", NOTRUNCMD, INFOCMD, INFOTHREAD), true);
 
         queueCmd(new GDBCommand("backtrace", NOTRUNCMD, INFOCMD, BACKTRACE), true);
-        if (stateIsOn(s_viewLocals))
-        {
-            queueCmd(new GDBCommand("info args", NOTRUNCMD, INFOCMD, ARGS));
-            queueCmd(new GDBCommand("info local", NOTRUNCMD, INFOCMD, LOCALS));
-        }
 
-        varTree_->findWatch()->requestWatchVars();
-        varTree_->findWatch()->setActive();
+        // The above should have changed viewedThread_, if we're in MT
+        // program. 
+        emit currentFrame(currentFrame_, viewedThread_);
+
         emit acceptPendingBPs();
     }
 }
@@ -443,14 +437,7 @@
     // and we must reset the active flag
     viewedThread_ = -1;
     currentFrame_ = 0;
-    varTree_->setActiveFlag();
 
-    // Now wipe the tree out
-    varTree_->viewport()->setUpdatesEnabled(false);
-    varTree_->trim();
-    varTree_->viewport()->setUpdatesEnabled(true);
-    varTree_->repaint();
-
     frameStack_->clear();
 
     if (msgBox)
@@ -818,15 +805,6 @@
 void GDBController::parseBacktraceList(char *buf)
 {
     frameStack_->parseGDBBacktraceList(buf);
-    if (backtraceDueToProgramStop_)
-    {
-        varTree_->trimExcessFrames();
-        VarFrameRoot *frame = varTree_->findFrame(currentFrame_, viewedThread_);
-        if (frame)
-            frame->setFrameName(
-                frameStack_->getFrameName(currentFrame_, viewedThread_));
-        backtraceDueToProgramStop_ = false;
-    }
 }
 
 // **************************************************************************
@@ -835,7 +813,6 @@
 {
     frameStack_->parseGDBThreadList(buf);
     viewedThread_ = frameStack_->viewedThread();
-    varTree_->setCurrentThread(viewedThread_);
 }
 
 // **************************************************************************
@@ -933,40 +910,14 @@
 // inactive.
 void GDBController::parseLocals(char type, char *buf)
 {
-    varTree_->viewport()->setUpdatesEnabled(false);
-
-    // The locals are always attached to the currentFrame
-    VarFrameRoot *frame = varTree_->findFrame(currentFrame_, viewedThread_);
-    if (!frame)
-    {
-        frame = new VarFrameRoot(varTree_, currentFrame_, viewedThread_);
-        frame->setFrameName(
-                frameStack_->getFrameName(currentFrame_, viewedThread_));
-    }
-
-    Q_ASSERT(frame);
-
     if (type == (char) ARGS)
     {
-        frame->setParams(buf);
+        emit parametersReady(buf);
     }
     else
     {
-        frame->setLocals(buf);
-        // Trim the whole tree when we're on the top most
-        // frame so that they always see only "frame 0" on a program stop.
-        // User selects frame 1, will show both frame 0 and frame 1.
-        // Reselecting a frame 0 regenerates the data and therefore trims
-        // the whole tree _but_ all the items in every frame will be active
-        // so nothing will be deleted.
-        if (currentFrame_ == 0 || viewedThread_ == -1)
-            varTree_->trim();
-        else
-            frame->trim();
+        emit localsReady(buf);
     }
-
-    varTree_->viewport()->setUpdatesEnabled(true);
-    varTree_->repaint();
 }
 
 // **************************************************************************
@@ -1758,30 +1709,34 @@
     viewedThread_ = threadNo;
     currentFrame_ = frameNo;
 
-    // Find or add the frame details. hold onto whether it existed because
-    // we're about to create one if it didn't.
-    VarFrameRoot *frame = varTree_->findFrame(frameNo, viewedThread_);
-    if (!frame)
+    emit currentFrame(frameNo, threadNo);
+}
+
+/** Produces backtrace for the specified thread, or for main
+    thread if threadNo is -1. Does not change the current thread or
+    the current thread.
+*/
+void GDBController::slotProduceBacktrace(int threadNo)
+{
+    QString command;
+    if (threadNo != -1)
     {
-        frame = new VarFrameRoot(varTree_, currentFrame_, viewedThread_);
-        frame->setFrameName(
-                frameStack_->getFrameName(currentFrame_, viewedThread_));
+        command = QString("thread apply %1 backtrace").arg(threadNo);
     }
-
-    Q_ASSERT(frame);
-    if (stateIsOn(s_viewLocals))
+    else
     {
-        // Have we already got these details?
-        if (frame->needLocals())
-        {
-            // Add the frame params to the variable list
-            // and ask for the locals
-            queueCmd(new GDBCommand("info args", NOTRUNCMD, INFOCMD, ARGS));
-            queueCmd(new GDBCommand("info local", NOTRUNCMD, INFOCMD, LOCALS));
-        }
+        command = "backtrace";
     }
+    queueCmd(new GDBCommand(command.local8Bit(), 
+             NOTRUNCMD, INFOCMD, BACKTRACE));    
 }
 
+void GDBController::slotProduceVariablesInfo()
+{
+    queueCmd(new GDBCommand("info args", NOTRUNCMD, INFOCMD, ARGS));
+    queueCmd(new GDBCommand("info local", NOTRUNCMD, INFOCMD, LOCALS));    
+}
+
 // **************************************************************************
 
 void GDBController::slotVarItemConstructed(VarItem *item)
Index: debuggerpart.cpp
===================================================================
--- debuggerpart.cpp	(revision 412370)
+++ debuggerpart.cpp	(working copy)
@@ -507,6 +507,8 @@
              controller,            SLOT(slotSetLocalViewState(bool)));
     connect( variableTree,          SIGNAL(varItemConstructed(VarItem*)),
              controller,            SLOT(slotVarItemConstructed(VarItem*)));     // jw
+    connect( variableTree,          SIGNAL(produceVariablesInfo()),
+             controller,            SLOT(slotProduceVariablesInfo()));
 
     // variableTree -> gdbBreakpointWidget
     connect( variableTree,          SIGNAL(toggleWatchpoint(const QString &)),
@@ -515,7 +517,10 @@
     // framestackWidget -> controller
     connect( framestackWidget,      SIGNAL(selectFrame(int,int,bool)),
              controller,            SLOT(slotSelectFrame(int,int,bool)));
+    connect( framestackWidget,      SIGNAL(produceBacktrace(int)),
+             controller,            SLOT(slotProduceBacktrace(int)));
 
+
     // gdbBreakpointWidget -> controller
     connect( gdbBreakpointWidget,   SIGNAL(clearAllBreakpoints()),
              controller,            SLOT(slotClearAllBreakpoints()));
@@ -570,6 +575,16 @@
     connect( controller,            SIGNAL(dbgStatus(const QString&, int)),
              gdbOutputWidget,       SLOT(slotDbgStatus(const QString&, int)));
 
+    // controller -> variableTree
+    connect( controller, SIGNAL(dbgStatus(const QString&, int)),
+             variableTree, SLOT(slotDbgStatus(const QString&, int)));
+    connect( controller, SIGNAL(parametersReady(const char*)),
+             variableTree, SLOT(slotParametersReady(const char*)));
+    connect( controller, SIGNAL(localsReady(const char*)),
+             variableTree, SLOT(slotLocalsReady(const char*)));
+    connect( controller, SIGNAL(currentFrame(int, int)),
+             variableTree, SLOT(slotCurrentFrame(int, int)));
+
     // gdbBreakpointWidget -> disassembleWidget
     connect( gdbBreakpointWidget,   SIGNAL(publishBPState(const Breakpoint&)),
              disassembleWidget,     SLOT(slotBPState(const Breakpoint &)));
Index: framestackwidget.cpp
===================================================================
--- framestackwidget.cpp	(revision 412370)
+++ framestackwidget.cpp	(working copy)
@@ -114,6 +114,22 @@
     emit selectFrame(frameNo, threadNo, !(frame));
 }
 
+void FramestackWidget::getBacktrace(int threadNo)
+{
+    if (threadNo != -1)
+    {
+        viewedThread_ = findThread(threadNo);
+        if (!viewedThread_)
+        {
+            Q_ASSERT(!viewedThread_);
+            return;                 // fatal
+        }
+    }
+
+    emit produceBacktrace(threadNo);    
+}
+
+
 /***************************************************************************/
 
 void FramestackWidget::parseGDBThreadList(char *str)
@@ -353,8 +369,10 @@
 
 void ThreadStackItem::setOpen(bool open)
 {
-    if (open)
-        ((FramestackWidget*)listView())->slotSelectFrame(0, threadNo());
+    // If we're openining, and have no child yet, get backtrace from
+    // gdb.
+    if (open && !firstChild())
+        ((FramestackWidget*)listView())->getBacktrace(threadNo());
 
     QListViewItem::setOpen(open);
 }

_______________________________________________
KDevelop-devel mailing list
KDevelop-devel@barney.cs.uni-potsdam.de
http://barney.cs.uni-potsdam.de/mailman/listinfo/kdevelop-devel

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic