summaryrefslogtreecommitdiffstats
path: root/languages/ruby/debugger/variablewidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/ruby/debugger/variablewidget.cpp')
-rw-r--r--languages/ruby/debugger/variablewidget.cpp1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/languages/ruby/debugger/variablewidget.cpp b/languages/ruby/debugger/variablewidget.cpp
new file mode 100644
index 00000000..0dbdce9a
--- /dev/null
+++ b/languages/ruby/debugger/variablewidget.cpp
@@ -0,0 +1,1018 @@
+// **************************************************************************
+// begin : Sun Aug 8 1999
+// copyright : (C) 1999 by John Birch
+// email : jbb@kdevelop.org
+//
+// Adapted for ruby debugging
+// --------------------------
+// begin : Mon Nov 1 2004
+// copyright : (C) 2004 by Richard Dale
+// email : Richard_Dale@tipitina.demon.co.uk
+// **************************************************************************
+
+// **************************************************************************
+// * *
+// * This program is free software; you can redistribute it and/or modify *
+// * it under the terms of the GNU General Public License as published by *
+// * the Free Software Foundation; either version 2 of the License, or *
+// * (at your option) any later version. *
+// * *
+// **************************************************************************
+
+#include "variablewidget.h"
+#include "rdbparser.h"
+#include "rdbcommand.h"
+
+#include <kdebug.h>
+#include <kpopupmenu.h>
+#include <klineedit.h>
+#include <kdeversion.h>
+
+#include <qheader.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qpainter.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qcursor.h>
+#include <klocale.h>
+
+#include <qpoint.h>
+#include <qclipboard.h>
+#include <kapplication.h>
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+namespace RDBDebugger
+{
+
+VariableWidget::VariableWidget(QWidget *parent, const char *name)
+ : 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");
+ label->setBuddy(watchVarEditor_);
+
+ QPushButton *addButton = new QPushButton(i18n("&Add"), watchEntry );
+ addButton->adjustSize();
+ addButton->setFixedWidth(addButton->width());
+
+ QBoxLayout * vbox = new QVBoxLayout();
+ vbox->addWidget( label );
+ vbox->addWidget( watchEntry );
+
+ QVBoxLayout *topLayout = new QVBoxLayout(this, 2);
+ topLayout->addWidget(varTree_, 10);
+ topLayout->addLayout( vbox );
+
+ connect( addButton, SIGNAL(clicked()), SLOT(slotAddWatchExpression()) );
+ connect( watchVarEditor_, SIGNAL(returnPressed()), SLOT(slotAddWatchExpression()) );
+}
+
+
+// **************************************************************************
+
+void VariableWidget::setEnabled(bool bEnabled)
+{
+ QWidget::setEnabled(bEnabled);
+ if (bEnabled && parentWidget() != 0) {
+ varTree_->setColumnWidth(0, parentWidget()->width()/2);
+ }
+}
+// **************************************************************************
+
+void VariableWidget::slotAddWatchExpression()
+{
+ QString watchVar(watchVarEditor_->currentText());
+ if (!watchVar.isEmpty()) {
+ slotAddWatchExpression(watchVar);
+ }
+}
+
+// **************************************************************************
+
+void VariableWidget::slotAddWatchExpression(const QString &ident)
+{
+ if (!ident.isEmpty()) {
+ watchVarEditor_->addToHistory(ident);
+ varTree_->slotAddWatchExpression(ident);
+ watchVarEditor_->clearEdit();
+ }
+}
+
+// **************************************************************************
+
+void VariableWidget::focusInEvent(QFocusEvent */*e*/)
+{
+ varTree_->setFocus();
+}
+
+void VariableWidget::restorePartialProjectSession(const QDomElement* el)
+{
+ varTree_->watchRoot()->restorePartialProjectSession(el);
+}
+
+void VariableWidget::savePartialProjectSession(QDomElement* el)
+{
+ varTree_->watchRoot()->savePartialProjectSession(el);
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+VariableTree::VariableTree(VariableWidget *parent, const char *name)
+ : KListView(parent, name),
+ QToolTip( viewport() ),
+ activationId_(0),
+ currentThread_(-1),
+ selectedFrame_(0),
+ watchRoot_(0),
+ globalRoot_(0)
+{
+ setRootIsDecorated(true);
+ setAllColumnsShowFocus(true);
+ setColumnWidthMode(0, Manual);
+ setSorting(VAR_NAME_COLUMN);
+ QListView::setSelectionMode(QListView::Single);
+
+ addColumn(i18n("Variable"), 100 );
+ addColumn(i18n("Value"), 100 );
+
+ connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ SLOT(slotContextMenu(KListView*, QListViewItem*)) );
+
+ connect( this, SIGNAL(pressed(QListViewItem*)),
+ this, SLOT(slotPressed(QListViewItem*)) );
+
+ watchRoot_ = new WatchRoot(this);
+}
+
+// **************************************************************************
+
+VariableTree::~VariableTree()
+{
+}
+
+// **************************************************************************
+
+void VariableTree::clear()
+{
+ QListViewItem *sibling = firstChild();
+ while (sibling != 0) {
+ QListViewItem * current = sibling;
+ sibling = sibling->nextSibling();
+ if (current->rtti() != RTTI_WATCH_ROOT) {
+ delete current;
+ }
+ }
+
+ globalRoot_ = 0;
+ selectedFrame_ = 0;
+ return;
+}
+
+// **************************************************************************
+
+void VariableTree::slotContextMenu(KListView *, QListViewItem *item)
+{
+ if (item == 0)
+ return;
+
+ setSelected(item, true); // Need to select this item.
+
+ if (item->parent() != 0) {
+ KPopupMenu popup(this);
+ popup.insertTitle(item->text(VAR_NAME_COLUMN));
+ int idRemoveWatch = -2;
+ if (item->rtti() == RTTI_WATCH_VAR_ITEM) {
+ idRemoveWatch = popup.insertItem( i18n("Remove Watch Expression") );
+ }
+
+ int idCopyToClipboard = popup.insertItem( i18n("Copy to Clipboard") );
+ int res = popup.exec(QCursor::pos());
+
+ if (res == idRemoveWatch) {
+ emit removeWatchExpression(((WatchVarItem*)item)->displayId());
+ delete item;
+ } else if (res == idCopyToClipboard) {
+ QClipboard *qb = KApplication::clipboard();
+ QString text = "{ \"" + item->text( VAR_NAME_COLUMN ) + "\", " +
+ "\"" + item->text( VALUE_COLUMN ) + "\" }";
+
+ qb->setText( text, QClipboard::Clipboard );
+ }
+ }
+}
+
+/***************************************************************************/
+
+void VariableTree::setSelected(QListViewItem * item, bool selected)
+{
+ // Save the last selected VarFrameRoot for slotPressed() to restore
+ if (item->rtti() == RTTI_VAR_FRAME_ROOT && selected) {
+ selectedFrame_ = (VarFrameRoot *) item;
+ }
+
+ QListView::setSelected(item, selected);
+}
+
+/***************************************************************************/
+
+// Makes sure that only VarFrameRoot items can be selected
+void VariableTree::slotPressed(QListViewItem * item)
+{
+ if (item == 0) {
+ return;
+ }
+
+ while (item->rtti() == RTTI_VAR_ITEM) {
+ item = item->parent();
+ }
+
+ if ( item->rtti() == RTTI_GLOBAL_ROOT
+ || item->rtti() == RTTI_WATCH_ROOT
+ || item->rtti() == RTTI_WATCH_VAR_ITEM )
+ {
+ if (selectedFrame_ != 0) {
+ setSelected(selectedFrame_, true);
+ }
+ return;
+ }
+
+ if (item->rtti() == RTTI_VAR_FRAME_ROOT) {
+ VarFrameRoot * frame = (VarFrameRoot*) item;
+ emit selectFrame(frame->frameNo(), frame->threadNo());
+ }
+
+ return;
+}
+
+// **************************************************************************
+
+void VariableTree::prune()
+{
+ QListViewItem *child = firstChild();
+
+ while (child != 0) {
+ QListViewItem *nextChild = child->nextSibling();
+
+ // Only prune var frames, not the watch or global root
+ if (child->rtti() == RTTI_VAR_FRAME_ROOT) {
+ if (((VarFrameRoot*) child)->isActive()) {
+ if (child->isOpen()) {
+ ((VarFrameRoot*) child)->prune();
+ }
+ } else {
+ delete child;
+ }
+ }
+
+ child = nextChild;
+ }
+}
+
+// **************************************************************************
+
+// The debugger has moved onto the next program pause, so invalidate
+// everything in the Variable Tree
+void VariableTree::nextActivationId()
+{
+ activationId_++;
+ globalRoot()->setActivationId();
+ watchRoot()->setActivationId();
+ // ..but that's only the Watch and Global roots
+}
+
+// **************************************************************************
+
+// VarFrameRoot frames in the Variable Tree from the previous program pause,
+// are set active here. Notified by the Frame Stack widget when it parses the
+// backtrace from the 'where' command after a pause.
+//
+// After that, any frames which aren't marked as active must have gone
+// out of scope and will end up pruned.
+void VariableTree::slotFrameActive(int frameNo, int threadNo, const QString& frameName)
+{
+ VarFrameRoot * frame = findFrame(frameNo, threadNo);
+ if (frameNo == 1) {
+ // If the current frame 1 doesn't exist, create it
+ if (frame == 0) {
+ frame = new VarFrameRoot(this, frameNo, threadNo);
+ }
+
+ frame->setFrameName(frameName);
+ }
+
+ if (frame != 0 && frame->text(VAR_NAME_COLUMN) == frameName) {
+ frame->setActivationId();
+ }
+}
+
+// **************************************************************************
+
+bool VariableTree::schedule()
+{
+ QListViewItem * child = firstChild();
+ VarFrameRoot * frame = 0;
+
+ while (child != 0) {
+ if (child->rtti() == RTTI_VAR_FRAME_ROOT) {
+ frame = (VarFrameRoot *) child;
+ Q_ASSERT( !frame->isWaitingForData() );
+
+ if (frame->needsVariables()) {
+ if (QApplication::overrideCursor() == 0) {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ }
+
+ // Tell the controller to fetch the variable values
+ emit selectFrame(frame->frameNo(), frame->threadNo());
+ return true;
+ }
+ }
+
+ child = child->nextSibling();
+ }
+
+ frame = findFrame(1, currentThread_);
+ Q_ASSERT( frame != 0 );
+ Q_ASSERT( !frame->needsVariables() );
+
+ // All over, nothing left to fetch.
+ // Return to frame 1, and prune the inactive items
+ // from the variable tree..
+ QApplication::restoreOverrideCursor();
+ emit selectFrame(1, currentThread_);
+ prune();
+
+ return false;
+}
+
+// **************************************************************************
+
+void VariableTree::slotAddWatchExpression(const QString &watchVar)
+{
+ new WatchVarItem(watchRoot(), watchVar, UNKNOWN_TYPE);
+ emit addWatchExpression(watchVar, true);
+}
+
+
+// **************************************************************************
+
+void VariableTree::setFetchGlobals(bool fetch)
+{
+ emit fetchGlobals(fetch);
+}
+
+// **************************************************************************
+
+VarFrameRoot *VariableTree::findFrame(int frameNo, int threadNo) const
+{
+ // frames only exist on the top level so we only need to
+ // check the siblings
+ QListViewItem *sibling = firstChild();
+ while (sibling != 0) {
+ if ( sibling->rtti() == RTTI_VAR_FRAME_ROOT
+ && ((VarFrameRoot*) sibling)->frameNo() == frameNo
+ && ((VarFrameRoot*) sibling)->threadNo() == threadNo )
+ {
+ return (VarFrameRoot*) sibling;
+ }
+
+ sibling = sibling->nextSibling();
+ }
+
+ return 0;
+}
+
+// **************************************************************************
+
+WatchRoot *VariableTree::watchRoot()
+{
+ return watchRoot_;
+}
+
+// **************************************************************************
+
+GlobalRoot *VariableTree::globalRoot()
+{
+ if (globalRoot_ == 0) {
+ globalRoot_ = new GlobalRoot(this);
+ }
+
+ return globalRoot_;
+}
+
+// **************************************************************************
+
+// Watch variables can be added before the start of a debugging session,
+// so tell the controller about any already in the tree at start.
+void VariableTree::resetWatchVars()
+{
+ for (QListViewItem *child = watchRoot()->firstChild(); child != 0; child = child->nextSibling()) {
+ ((WatchVarItem*) child)->setDisplayId(-1);
+ emit addWatchExpression(child->text(VAR_NAME_COLUMN), false);
+ }
+}
+
+// **************************************************************************
+
+void VariableTree::maybeTip(const QPoint &p)
+{
+ VarItem * item = dynamic_cast<VarItem*>( itemAt(p) );
+ if (item != 0) {
+ QRect r = itemRect(item);
+ if (r.isValid()) {
+ tip(r, item->tipText());
+ }
+ }
+}
+
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+LazyFetchItem::LazyFetchItem(VariableTree *parent)
+ : KListViewItem(parent),
+ activationId_(0),
+ waitingForData_(false)
+{
+ setActivationId();
+}
+
+// **************************************************************************
+
+LazyFetchItem::LazyFetchItem(LazyFetchItem *parent)
+ : KListViewItem(parent),
+ activationId_(0),
+ waitingForData_(false)
+{
+ setActivationId();
+}
+
+// **************************************************************************
+
+LazyFetchItem::~LazyFetchItem()
+{
+}
+
+// **************************************************************************
+
+void LazyFetchItem::paintCell(QPainter *p, const QColorGroup &cg,
+ int column, int width, int align)
+{
+ if (p == 0) {
+ return;
+ }
+
+ // make toplevel item (watch and frame items) names bold
+ if (column == VAR_NAME_COLUMN && parent() == 0) {
+ QFont f = p->font();
+ f.setBold(true);
+ p->setFont(f);
+ }
+
+ QListViewItem::paintCell( p, cg, column, width, align );
+}
+
+// **************************************************************************
+
+VarItem *LazyFetchItem::findItem(const QString &name) const
+{
+ QListViewItem *child = firstChild();
+
+ // Check the siblings on this branch
+ while (child != 0) {
+ if (child->text(VAR_NAME_COLUMN) == name) {
+ return (VarItem*) child;
+ }
+
+ child = child->nextSibling();
+ }
+
+ return 0;
+}
+
+// **************************************************************************
+
+void LazyFetchItem::prune()
+{
+ QListViewItem *child = firstChild();
+
+ while (child != 0) {
+ LazyFetchItem *item = (LazyFetchItem*) child;
+ child = child->nextSibling();
+ // Never prune a branch if we are waiting on data to arrive.
+ if (!waitingForData_) {
+ if (item->isActive()) {
+ item->prune();
+ } else {
+ delete item;
+ }
+ }
+ }
+}
+
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+VarItem::VarItem(LazyFetchItem *parent, const QString &varName, DataType dataType)
+ : LazyFetchItem (parent),
+ cache_(QCString()),
+ dataType_(dataType),
+ highlight_(false)
+{
+ setText(VAR_NAME_COLUMN, varName);
+ setSelectable(false);
+
+ // Order the VarItems so that globals are first, then
+ // constants, class variables, instance variables and
+ // finally local variables
+
+ // Matches either an array element or a string slice,
+ // Order on the array index or the first number in the
+ // range specifying the slice.
+ QRegExp arrayelement_re("\\[(\\d+)(\\.\\.\\d+)?\\]");
+ key_ = varName;
+
+ if (arrayelement_re.search(varName) != -1) {
+ key_.sprintf("%.6d", arrayelement_re.cap(1).toInt());
+ } else if (key_.startsWith("$")) {
+ key_.prepend("1001"); // Global variable
+ } else if (QRegExp("^[A-Z]").search(varName) != -1) {
+ key_.prepend("1002"); // Constant
+ } else if (key_.startsWith("@@")) {
+ key_.prepend("1003"); // Class variable
+ } else if (key_.startsWith("@")) {
+ key_.prepend("1004"); // Instance variable
+ } else {
+ key_.prepend("1005"); // Local variable or parameter
+ }
+
+// kdDebug(9012) << " ### VarItem::VarItem *CONSTR* " << varName << endl;
+}
+
+// **************************************************************************
+
+VarItem::~VarItem()
+{
+}
+
+QString VarItem::key(int /*column*/, bool /*ascending*/) const
+{
+ return key_;
+}
+
+// **************************************************************************
+
+// Returns the path of a ruby item. If it is an instance variable, assume
+// that there is an attr_accessor method for it.
+// For example, @foobar within instance obj is accessed as obj.foobar.
+// But don't strip off the @ for an instance variable with no path,
+// and leave a plain '@foobar' as it is.
+QString VarItem::fullName() const
+{
+ QString itemName = text(VAR_NAME_COLUMN);
+ QString vPath("");
+ const VarItem *item = this;
+
+ if (item->parent()->rtti() != RTTI_VAR_ITEM) {
+ return itemName;
+ }
+
+ // This stops at the root item (FrameRoot or GlobalRoot)
+ while (item->rtti() == RTTI_VAR_ITEM) {
+ QString itemName = item->text(VAR_NAME_COLUMN);
+
+ if (vPath.startsWith("[")) {
+ // If it's a Hash or an Array, then just insert the value. As
+ // in adding '[0]' to foo.bar to give foo.bar[0]
+ vPath.prepend(itemName);
+ } else {
+ if (vPath.isEmpty()) {
+ vPath = itemName;
+ } else {
+ vPath.prepend(itemName + ".");
+ }
+ }
+ item = (VarItem*) item->parent();
+ }
+
+ // Change 'self.@foobar' to '@foobar'
+ vPath.replace(QRegExp("^self\\.@"), "@");
+
+ // Use instance_variable_get() to access any '@var's in the middle of a path
+ QRegExp re_instance_var("\\.(@[^\\[.]+)");
+ int pos = re_instance_var.search(vPath);
+ while (pos != -1) {
+ vPath.replace( pos,
+ re_instance_var.matchedLength(),
+ QString(".instance_variable_get(:") + re_instance_var.cap(1) + ")" );
+ pos = re_instance_var.search(vPath, pos);
+ }
+
+ return vPath;
+}
+
+// **************************************************************************
+
+void VarItem::setText(int column, const QString &data)
+{
+ setActivationId();
+
+ if (column == VALUE_COLUMN) {
+ highlight_ = (!text(VALUE_COLUMN).isEmpty() && text(VALUE_COLUMN) != data);
+ }
+
+ QListViewItem::setText(column, data);
+ repaint();
+}
+
+// **************************************************************************
+
+void VarItem::expandValue(char *buf)
+{
+ LazyFetchItem::stopWaitingForData();
+ RDBParser::parseExpandedVariable(this, buf);
+}
+
+// **************************************************************************
+
+void VarItem::setOpen(bool open)
+{
+ QListViewItem::setOpen(open);
+
+ Q_ASSERT( dataType_ == REFERENCE_TYPE
+ || dataType_ == ARRAY_TYPE
+ || dataType_ == HASH_TYPE
+ || dataType_ == STRING_TYPE
+ || dataType_ == STRUCT_TYPE );
+
+ update();
+ return;
+}
+
+// **************************************************************************
+
+void VarItem::update()
+{
+ if (isOpen()) {
+ startWaitingForData();
+// emit ((VariableTree*)listView())->expandItem(this, fullName().latin1());
+ ((VariableTree*)listView())->expandItem(this, fullName().latin1());
+ }
+
+ return;
+}
+
+// **************************************************************************
+
+DataType VarItem::dataType() const
+{
+ return dataType_;
+}
+
+// **************************************************************************
+
+void VarItem::setDataType(DataType dataType)
+{
+ dataType_ = dataType;
+}
+
+// **************************************************************************
+
+// Overridden to highlight the changed items
+void VarItem::paintCell(QPainter *p, const QColorGroup &cg,
+ int column, int width, int align)
+{
+ if (p == 0) {
+ return;
+ }
+
+ if (column == VALUE_COLUMN) {
+ // Show color values as colors, and make the text color the same
+ // as the base color
+ if (dataType_ == COLOR_TYPE) {
+ QRegExp color_re("\\s(#.*)>");
+
+ if (color_re.search(text(column)) != -1) {
+ QColorGroup color_cg( cg.foreground(), cg.background(),
+ cg.light(), cg.dark(), cg.mid(),
+ QColor(color_re.cap(1)), QColor(color_re.cap(1)) );
+ QListViewItem::paintCell(p, color_cg, column, width, align);
+ return;
+ }
+ }
+
+ // Highlight recently changed items in red
+ if (highlight_) {
+ QColorGroup hl_cg( cg.foreground(), cg.background(),
+ cg.light(), cg.dark(), cg.mid(),
+ red, cg.base() );
+ QListViewItem::paintCell(p, hl_cg, column, width, align);
+ return;
+ }
+ }
+
+ QListViewItem::paintCell(p, cg, column, width, align);
+ return;
+}
+
+// **************************************************************************
+
+QString VarItem::tipText() const
+{
+ const unsigned int MAX_TOOLTIP_SIZE = 70;
+ QString tip = text(VALUE_COLUMN);
+
+ if (tip.length() < MAX_TOOLTIP_SIZE) {
+ return tip;
+ } else {
+ return tip.mid(0, MAX_TOOLTIP_SIZE - 1) + " [...]";
+ }
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+VarFrameRoot::VarFrameRoot(VariableTree *parent, int frameNo, int threadNo)
+ : LazyFetchItem(parent),
+ needsVariables_(true),
+ frameNo_(frameNo),
+ threadNo_(threadNo),
+ cache_("")
+{
+ setExpandable(true);
+}
+
+// **************************************************************************
+
+VarFrameRoot::~VarFrameRoot()
+{
+}
+
+// **************************************************************************
+
+void VarFrameRoot::addLocals(char *variables)
+{
+ cache_.append(variables);
+}
+
+// **************************************************************************
+
+void VarFrameRoot::setLocals()
+{
+ RDBParser::parseVariables(this, cache_.data());
+ cache_ = "";
+ needsVariables_ = false;
+ stopWaitingForData();
+ prune();
+
+ return;
+}
+
+// **************************************************************************
+
+// Override setOpen so that we can decide what to do when we do change
+// state.
+void VarFrameRoot::setOpen(bool open)
+{
+ bool localsViewChanged = (isOpen() != open);
+ QListViewItem::setOpen(open);
+
+ if (localsViewChanged) {
+ ((VariableTree*)listView())->selectFrame(frameNo_, threadNo_);
+ }
+
+ return;
+}
+
+void VarFrameRoot::setFrameName(const QString &frameName)
+{
+ setText(VAR_NAME_COLUMN, frameName);
+ setText(VALUE_COLUMN, "");
+
+ return;
+}
+
+void VarFrameRoot::setActivationId()
+{
+ LazyFetchItem::setActivationId();
+ stopWaitingForData();
+ needsVariables_ = true;
+ cache_ = "";
+}
+
+bool VarFrameRoot::needsVariables() const
+{
+ return ( text(VAR_NAME_COLUMN).contains("try_initialize") == 0
+ && isOpen()
+ && !isWaitingForData()
+ && needsVariables_ );
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+
+GlobalRoot::GlobalRoot(VariableTree *parent)
+ : LazyFetchItem(parent)
+{
+ setText(0, i18n("Global"));
+ setExpandable(true);
+ setOpen(false);
+ setSelectable(false);
+}
+
+// **************************************************************************
+
+GlobalRoot::~GlobalRoot()
+{
+}
+
+// **************************************************************************
+
+void GlobalRoot::setGlobals(char * globals)
+{
+ setActivationId();
+ RDBParser::parseVariables(this, globals);
+
+ return;
+}
+
+// **************************************************************************
+
+void GlobalRoot::setOpen(bool open)
+{
+ bool globalsViewChanged = (isOpen() != open);
+ QListViewItem::setOpen(open);
+
+ if (globalsViewChanged) {
+ ((VariableTree*)listView())->setFetchGlobals(isOpen());
+ }
+
+ return;
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+WatchVarItem::WatchVarItem( LazyFetchItem *parent, const QString &varName, DataType dataType, int displayId )
+ : VarItem(parent, varName, dataType),
+ displayId_(displayId)
+{
+}
+
+// **************************************************************************
+
+WatchVarItem::~WatchVarItem()
+{
+}
+
+// **************************************************************************
+
+void WatchVarItem::setDisplayId(int id)
+{
+ displayId_ = id;
+}
+
+// **************************************************************************
+
+int WatchVarItem::displayId()
+{
+ return displayId_;
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+WatchRoot::WatchRoot(VariableTree *parent)
+ : LazyFetchItem(parent)
+{
+ setText(VAR_NAME_COLUMN, i18n("Watch"));
+ setOpen(true);
+ setSelectable(false);
+}
+
+// **************************************************************************
+
+WatchRoot::~WatchRoot()
+{
+}
+
+// **************************************************************************
+
+// Sets the initial value of a new Watch item, along with the
+// display id
+void WatchRoot::setWatchExpression(char * buf, char * expression)
+{
+ QString expr(expression);
+ QRegExp display_re("^(\\d+):\\s([^\n]+)\n");
+
+ for ( QListViewItem *child = firstChild();
+ child != 0;
+ child = child->nextSibling() )
+ {
+ WatchVarItem *varItem = (WatchVarItem*) child;
+ if ( varItem->text(VAR_NAME_COLUMN) == expr
+ && varItem->displayId() == -1
+ && display_re.search(buf) >= 0 )
+ {
+ varItem->setDisplayId(display_re.cap(1).toInt());
+ // Skip over the 'thing = ' part of expr to get the value
+ varItem->setText( VALUE_COLUMN,
+ display_re.cap(2).mid(varItem->text(VAR_NAME_COLUMN).length() + strlen(" = ")) );
+ return;
+ }
+ }
+}
+
+// After a program pause, this updates the new value of a Watch item
+// expr is the thing = value part of "1: a = 1", id is the display number
+void WatchRoot::updateWatchExpression(int id, const QString& expr)
+{
+ for ( QListViewItem *child = firstChild();
+ child != 0;
+ child = child->nextSibling() )
+ {
+ WatchVarItem *varItem = (WatchVarItem*) child;
+ if (varItem->displayId() == id) {
+ Q_ASSERT( expr.startsWith(varItem->text(VAR_NAME_COLUMN)) );
+ // Skip over the 'thing = ' part of expr to get the value
+ varItem->setText( VALUE_COLUMN,
+ expr.mid(varItem->text(VAR_NAME_COLUMN).length() + strlen(" = ")) );
+ return;
+ }
+ }
+}
+
+void WatchRoot::savePartialProjectSession(QDomElement* el)
+{
+ QDomDocument domDoc = el->ownerDocument();
+ if (domDoc.isNull()) {
+ return;
+ }
+
+ QDomElement watchEl = domDoc.createElement("watchExpressions");
+
+ for ( QListViewItem *child = firstChild();
+ child != 0;
+ child = child->nextSibling() )
+ {
+ QDomElement subEl = domDoc.createElement("el");
+ subEl.appendChild(domDoc.createTextNode(child->text(VAR_NAME_COLUMN)));
+ watchEl.appendChild(subEl);
+ }
+
+ if (!watchEl.isNull()) {
+ el->appendChild(watchEl);
+ }
+
+ return;
+}
+
+void WatchRoot::restorePartialProjectSession(const QDomElement* el)
+{
+ QDomDocument domDoc = el->ownerDocument();
+ if (domDoc.isNull()) {
+ return;
+ }
+
+ QDomElement watchEl = el->namedItem("watchExpressions").toElement();
+ QDomElement subEl = watchEl.firstChild().toElement();
+
+ while (!subEl.isNull()) {
+ new WatchVarItem(this, subEl.firstChild().toText().data(), UNKNOWN_TYPE);
+
+ subEl = subEl.nextSibling().toElement();
+ }
+
+ return;
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+}
+
+
+#include "variablewidget.moc"
+