You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/languages/ruby/debugger/variablewidget.cpp

1019 lines
28 KiB

// **************************************************************************
// 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 <tdepopupmenu.h>
#include <klineedit.h>
#include <tdeversion.h>
#include <tqheader.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqhbox.h>
#include <tqpainter.h>
#include <tqpushbutton.h>
#include <tqregexp.h>
#include <tqcursor.h>
#include <tdelocale.h>
#include <tqpoint.h>
#include <tqclipboard.h>
#include <tdeapplication.h>
// **************************************************************************
// **************************************************************************
// **************************************************************************
namespace RDBDebugger
{
VariableWidget::VariableWidget(TQWidget *parent, const char *name)
: TQWidget(parent, name)
{
varTree_ = new VariableTree(this);
TQLabel *label = new TQLabel(i18n("E&xpression to watch:"), this);
TQHBox *watchEntry = new TQHBox( this );
watchVarEditor_ = new KHistoryCombo( watchEntry, "var-to-watch editor");
label->setBuddy(watchVarEditor_);
TQPushButton *addButton = new TQPushButton(i18n("&Add"), watchEntry );
addButton->adjustSize();
addButton->setFixedWidth(addButton->width());
TQBoxLayout * vbox = new TQVBoxLayout();
vbox->addWidget( label );
vbox->addWidget( watchEntry );
TQVBoxLayout *topLayout = new TQVBoxLayout(this, 2);
topLayout->addWidget(varTree_, 10);
topLayout->addLayout( vbox );
connect( addButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotAddWatchExpression()) );
connect( watchVarEditor_, TQ_SIGNAL(returnPressed()), TQ_SLOT(slotAddWatchExpression()) );
}
// **************************************************************************
void VariableWidget::setEnabled(bool bEnabled)
{
TQWidget::setEnabled(bEnabled);
if (bEnabled && parentWidget() != 0) {
varTree_->setColumnWidth(0, parentWidget()->width()/2);
}
}
// **************************************************************************
void VariableWidget::slotAddWatchExpression()
{
TQString watchVar(watchVarEditor_->currentText());
if (!watchVar.isEmpty()) {
slotAddWatchExpression(watchVar);
}
}
// **************************************************************************
void VariableWidget::slotAddWatchExpression(const TQString &ident)
{
if (!ident.isEmpty()) {
watchVarEditor_->addToHistory(ident);
varTree_->slotAddWatchExpression(ident);
watchVarEditor_->clearEdit();
}
}
// **************************************************************************
void VariableWidget::focusInEvent(TQFocusEvent */*e*/)
{
varTree_->setFocus();
}
void VariableWidget::restorePartialProjectSession(const TQDomElement* el)
{
varTree_->watchRoot()->restorePartialProjectSession(el);
}
void VariableWidget::savePartialProjectSession(TQDomElement* el)
{
varTree_->watchRoot()->savePartialProjectSession(el);
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
VariableTree::VariableTree(VariableWidget *parent, const char *name)
: TDEListView(parent, name),
TQToolTip( viewport() ),
activationId_(0),
currentThread_(-1),
selectedFrame_(0),
watchRoot_(0),
globalRoot_(0)
{
setRootIsDecorated(true);
setAllColumnsShowFocus(true);
setColumnWidthMode(0, Manual);
setSorting(VAR_NAME_COLUMN);
TQListView::setSelectionMode(TQListView::Single);
addColumn(i18n("Variable"), 100 );
addColumn(i18n("Value"), 100 );
connect( this, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)),
TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*)) );
connect( this, TQ_SIGNAL(pressed(TQListViewItem*)),
this, TQ_SLOT(slotPressed(TQListViewItem*)) );
watchRoot_ = new WatchRoot(this);
}
// **************************************************************************
VariableTree::~VariableTree()
{
}
// **************************************************************************
void VariableTree::clear()
{
TQListViewItem *sibling = firstChild();
while (sibling != 0) {
TQListViewItem * current = sibling;
sibling = sibling->nextSibling();
if (current->rtti() != RTTI_WATCH_ROOT) {
delete current;
}
}
globalRoot_ = 0;
selectedFrame_ = 0;
return;
}
// **************************************************************************
void VariableTree::slotContextMenu(TDEListView *, TQListViewItem *item)
{
if (item == 0)
return;
setSelected(item, true); // Need to select this item.
if (item->parent() != 0) {
TDEPopupMenu 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(TQCursor::pos());
if (res == idRemoveWatch) {
emit removeWatchExpression(((WatchVarItem*)item)->displayId());
delete item;
} else if (res == idCopyToClipboard) {
TQClipboard *qb = TDEApplication::clipboard();
TQString text = "{ \"" + item->text( VAR_NAME_COLUMN ) + "\", " +
"\"" + item->text( VALUE_COLUMN ) + "\" }";
qb->setText( text, TQClipboard::Clipboard );
}
}
}
/***************************************************************************/
void VariableTree::setSelected(TQListViewItem * item, bool selected)
{
// Save the last selected VarFrameRoot for slotPressed() to restore
if (item->rtti() == RTTI_VAR_FRAME_ROOT && selected) {
selectedFrame_ = (VarFrameRoot *) item;
}
TQListView::setSelected(item, selected);
}
/***************************************************************************/
// Makes sure that only VarFrameRoot items can be selected
void VariableTree::slotPressed(TQListViewItem * 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()
{
TQListViewItem *child = firstChild();
while (child != 0) {
TQListViewItem *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 TQString& 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()
{
TQListViewItem * 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 (TQApplication::overrideCursor() == 0) {
TQApplication::setOverrideCursor(TQCursor(TQt::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..
TQApplication::restoreOverrideCursor();
emit selectFrame(1, currentThread_);
prune();
return false;
}
// **************************************************************************
void VariableTree::slotAddWatchExpression(const TQString &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
TQListViewItem *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 (TQListViewItem *child = watchRoot()->firstChild(); child != 0; child = child->nextSibling()) {
((WatchVarItem*) child)->setDisplayId(-1);
emit addWatchExpression(child->text(VAR_NAME_COLUMN), false);
}
}
// **************************************************************************
void VariableTree::maybeTip(const TQPoint &p)
{
VarItem * item = dynamic_cast<VarItem*>( itemAt(p) );
if (item != 0) {
TQRect r = itemRect(item);
if (r.isValid()) {
tip(r, item->tipText());
}
}
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
LazyFetchItem::LazyFetchItem(VariableTree *parent)
: TDEListViewItem(parent),
activationId_(0),
waitingForData_(false)
{
setActivationId();
}
// **************************************************************************
LazyFetchItem::LazyFetchItem(LazyFetchItem *parent)
: TDEListViewItem(parent),
activationId_(0),
waitingForData_(false)
{
setActivationId();
}
// **************************************************************************
LazyFetchItem::~LazyFetchItem()
{
}
// **************************************************************************
void LazyFetchItem::paintCell(TQPainter *p, const TQColorGroup &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) {
TQFont f = p->font();
f.setBold(true);
p->setFont(f);
}
TQListViewItem::paintCell( p, cg, column, width, align );
}
// **************************************************************************
VarItem *LazyFetchItem::findItem(const TQString &name) const
{
TQListViewItem *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()
{
TQListViewItem *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 TQString &varName, DataType dataType)
: LazyFetchItem (parent),
cache_(TQCString()),
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.
TQRegExp 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 (TQRegExp("^[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()
{
}
TQString 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.
TQString VarItem::fullName() const
{
TQString itemName = text(VAR_NAME_COLUMN);
TQString 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) {
TQString 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(TQRegExp("^self\\.@"), "@");
// Use instance_variable_get() to access any '@var's in the middle of a path
TQRegExp re_instance_var("\\.(@[^\\[.]+)");
int pos = re_instance_var.search(vPath);
while (pos != -1) {
vPath.replace( pos,
re_instance_var.matchedLength(),
TQString(".instance_variable_get(:") + re_instance_var.cap(1) + ")" );
pos = re_instance_var.search(vPath, pos);
}
return vPath;
}
// **************************************************************************
void VarItem::setText(int column, const TQString &data)
{
setActivationId();
if (column == VALUE_COLUMN) {
highlight_ = (!text(VALUE_COLUMN).isEmpty() && text(VALUE_COLUMN) != data);
}
TQListViewItem::setText(column, data);
repaint();
}
// **************************************************************************
void VarItem::expandValue(char *buf)
{
LazyFetchItem::stopWaitingForData();
RDBParser::parseExpandedVariable(this, buf);
}
// **************************************************************************
void VarItem::setOpen(bool open)
{
TQListViewItem::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(TQPainter *p, const TQColorGroup &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) {
TQRegExp color_re("\\s(#.*)>");
if (color_re.search(text(column)) != -1) {
TQColorGroup color_cg( cg.foreground(), cg.background(),
cg.light(), cg.dark(), cg.mid(),
TQColor(color_re.cap(1)), TQColor(color_re.cap(1)) );
TQListViewItem::paintCell(p, color_cg, column, width, align);
return;
}
}
// Highlight recently changed items in red
if (highlight_) {
TQColorGroup hl_cg( cg.foreground(), cg.background(),
cg.light(), cg.dark(), cg.mid(),
red, cg.base() );
TQListViewItem::paintCell(p, hl_cg, column, width, align);
return;
}
}
TQListViewItem::paintCell(p, cg, column, width, align);
return;
}
// **************************************************************************
TQString VarItem::tipText() const
{
const unsigned int MAX_TOOLTIP_SIZE = 70;
TQString 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);
TQListViewItem::setOpen(open);
if (localsViewChanged) {
((VariableTree*)listView())->selectFrame(frameNo_, threadNo_);
}
return;
}
void VarFrameRoot::setFrameName(const TQString &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);
TQListViewItem::setOpen(open);
if (globalsViewChanged) {
((VariableTree*)listView())->setFetchGlobals(isOpen());
}
return;
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
// **************************************************************************
WatchVarItem::WatchVarItem( LazyFetchItem *parent, const TQString &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)
{
TQString expr(expression);
TQRegExp display_re("^(\\d+):\\s([^\n]+)\n");
for ( TQListViewItem *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 TQString& expr)
{
for ( TQListViewItem *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(TQDomElement* el)
{
TQDomDocument domDoc = el->ownerDocument();
if (domDoc.isNull()) {
return;
}
TQDomElement watchEl = domDoc.createElement("watchExpressions");
for ( TQListViewItem *child = firstChild();
child != 0;
child = child->nextSibling() )
{
TQDomElement 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 TQDomElement* el)
{
TQDomDocument domDoc = el->ownerDocument();
if (domDoc.isNull()) {
return;
}
TQDomElement watchEl = el->namedItem("watchExpressions").toElement();
TQDomElement subEl = watchEl.firstChild().toElement();
while (!subEl.isNull()) {
new WatchVarItem(this, subEl.firstChild().toText().data(), UNKNOWN_TYPE);
subEl = subEl.nextSibling().toElement();
}
return;
}
// **************************************************************************
// **************************************************************************
// **************************************************************************
}
#include "variablewidget.moc"