|
|
|
// **************************************************************************
|
|
|
|
// begin : Sun Aug 8 1999
|
|
|
|
// copyright : (C) 1999 by John Birch
|
|
|
|
// email : jbb@tdevelop.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, TQT_SIGNAL(clicked()), TQT_SLOT(slotAddWatchExpression()) );
|
|
|
|
connect( watchVarEditor_, TQT_SIGNAL(returnPressed()), TQT_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, TQT_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)),
|
|
|
|
TQT_SLOT(slotContextMenu(TDEListView*, TQListViewItem*)) );
|
|
|
|
|
|
|
|
connect( this, TQT_SIGNAL(pressed(TQListViewItem*)),
|
|
|
|
this, TQT_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"
|
|
|
|
|