00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "variablewidget.h"
00019 #include "jdbparser.h"
00020
00021 #include <kdebug.h>
00022 #include <kpopupmenu.h>
00023 #include <klineedit.h>
00024
00025 #include <qheader.h>
00026 #include <qlabel.h>
00027 #include <qlayout.h>
00028 #include <qpainter.h>
00029 #include <qpushbutton.h>
00030 #include <qregexp.h>
00031 #include <qcursor.h>
00032 #include <klocale.h>
00033
00034 #if defined(DBG_MONITOR)
00035 #define DBG_DISPLAY(X) {emit rawData(QString(X));}
00036 #else
00037 #define DBG_DISPLAY(X) {;}
00038 #endif
00039
00040
00041
00042 namespace JAVADebugger
00043 {
00044
00046 static JDBParser *parser = 0;
00047
00048 static JDBParser *getParser()
00049 {
00050 if (!parser)
00051 parser = new JDBParser;
00052
00053 return parser;
00054 }
00055
00056
00057
00058
00059
00060
00061 VariableWidget::VariableWidget(QWidget *parent, const char *name)
00062 : QWidget(parent, name)
00063 {
00064 varTree_ = new VariableTree(this);
00065 QLabel *label = new QLabel(i18n("Watch:"), this);
00066 watchVarEntry_ = new KLineEdit(this);
00067 QPushButton *addButton = new QPushButton(i18n("Add"), this);
00068
00069 QBoxLayout *watchEntry = new QHBoxLayout();
00070 watchEntry->addWidget(watchVarEntry_);
00071 watchEntry->addWidget(label);
00072 watchEntry->addWidget(addButton);
00073
00074 QVBoxLayout *topLayout = new QVBoxLayout(this, 2);
00075 topLayout->addWidget(varTree_, 10);
00076 topLayout->addLayout(watchEntry);
00077
00078 connect( addButton, SIGNAL(clicked()), SLOT(slotAddWatchVariable()) );
00079 connect( watchVarEntry_, SIGNAL(returnPressed()), SLOT(slotAddWatchVariable()) );
00080 }
00081
00082
00083
00084 void VariableWidget::clear()
00085 {
00086 varTree_->clear();
00087 }
00088
00089
00090
00091 void VariableWidget::slotAddWatchVariable()
00092 {
00093 QString watchVar(watchVarEntry_->text());
00094 if (!watchVar.isEmpty())
00095 varTree_->slotAddWatchVariable(watchVar);
00096 }
00097
00098
00099
00100
00101
00102 VariableTree::VariableTree(VariableWidget *parent, const char *name)
00103 : KListView(parent, name),
00104 activeFlag_(0)
00105 {
00106 setRootIsDecorated(true);
00107 setAllColumnsShowFocus(true);
00108 setSorting(-1);
00109 addColumn(i18n("Variable"));
00110 addColumn(i18n("Value"));
00111
00112 header()->hide();
00113 setMultiSelection(false);
00114
00115 connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
00116 SLOT(slotContextMenu(KListView*, QListViewItem*)) );
00117 }
00118
00119
00120
00121 VariableTree::~VariableTree()
00122 {
00123 }
00124
00125
00126
00127 void VariableTree::slotContextMenu(KListView *, QListViewItem *item)
00128 {
00129 if (!item)
00130 return;
00131
00132 setSelected(item, true);
00133
00134 if (item->parent()) {
00135 KPopupMenu popup(item->text(VarNameCol), this);
00136 int idRemoveWatch = -1;
00137 if (dynamic_cast<WatchRoot*>(findRoot(item)))
00138 idRemoveWatch = popup.insertItem( i18n("Remove Watch Variable") );
00139 int idToggleWatch = popup.insertItem( i18n("Toggle Watchpoint") );
00140
00141 int res = popup.exec(QCursor::pos());
00142
00143 if (res == idRemoveWatch)
00144 delete item;
00145 else if (res == idToggleWatch) {
00146 if (VarItem *item = dynamic_cast<VarItem*>(currentItem()))
00147 emit toggleWatchpoint(item->fullName());
00148 }
00149 }
00150 }
00151
00152
00153
00154 void VariableTree::slotAddWatchVariable(const QString &watchVar)
00155 {
00156 kdDebug(9012) << "Add watch variable: " << watchVar << endl;
00157 VarItem *varItem = new VarItem(findWatch(), watchVar, typeUnknown);
00158 emit expandItem(varItem);
00159 }
00160
00161
00162
00163 void VariableTree::setLocalViewState(bool localsOn, int frameNo)
00164 {
00165
00166
00167 if (!localsOn) {
00168 QListViewItem *sibling = firstChild();
00169 while (sibling) {
00170 FrameRoot *frame = dynamic_cast<FrameRoot*> (sibling);
00171 if (frame && frame->isOpen()) {
00172 localsOn = true;
00173 break;
00174 }
00175
00176 sibling = sibling->nextSibling();
00177 }
00178 }
00179
00180 emit setLocalViewState(localsOn);
00181 emit selectFrame(frameNo);
00182 }
00183
00184
00185
00186
00187 QListViewItem *VariableTree::findRoot(QListViewItem *item) const
00188 {
00189 while (item->parent())
00190 item = item->parent();
00191
00192 return item;
00193 }
00194
00195
00196
00197 FrameRoot *VariableTree::findFrame(int frameNo) const
00198 {
00199 QListViewItem *sibling = firstChild();
00200
00201
00202
00203 while (sibling) {
00204 FrameRoot *frame = dynamic_cast<FrameRoot*> (sibling);
00205 if (frame && frame->getFrameNo() == frameNo)
00206 return frame;
00207
00208 sibling = sibling->nextSibling();
00209 }
00210
00211 return 0;
00212 }
00213
00214
00215
00216 WatchRoot *VariableTree::findWatch()
00217 {
00218 QListViewItem *sibling = firstChild();
00219
00220 while (sibling) {
00221 if (WatchRoot *watch = dynamic_cast<WatchRoot*> (sibling))
00222 return watch;
00223
00224 sibling = sibling->nextSibling();
00225 }
00226
00227 return new WatchRoot(this);
00228 }
00229
00230
00231
00232 void VariableTree::trim()
00233 {
00234 QListViewItem *child = firstChild();
00235
00236 while (child) {
00237 QListViewItem *nextChild = child->nextSibling();
00238
00239
00240 if (!(dynamic_cast<WatchRoot*> (child))) {
00241 if (TrimmableItem *item = dynamic_cast<TrimmableItem*> (child)) {
00242 if (item->isActive())
00243 item->trim();
00244 else
00245 delete item;
00246 }
00247 }
00248 child = nextChild;
00249 }
00250 }
00251
00252
00253
00254 void VariableTree::trimExcessFrames()
00255 {
00256 QListViewItem *child = firstChild();
00257
00258 while (child) {
00259 QListViewItem *nextChild = child->nextSibling();
00260 if (FrameRoot *frame = dynamic_cast<FrameRoot*> (child)) {
00261 if (frame->getFrameNo() != 0)
00262 delete frame;
00263 }
00264 child = nextChild;
00265 }
00266 }
00267
00268
00269
00270 QListViewItem *VariableTree::lastChild() const
00271 {
00272 QListViewItem *child = firstChild();
00273 if (child)
00274 while (QListViewItem *nextChild = child->nextSibling())
00275 child = nextChild;
00276
00277 return child;
00278 }
00279
00280
00281
00282
00283
00284 TrimmableItem::TrimmableItem(VariableTree *parent)
00285 : QListViewItem (parent, parent->lastChild()),
00286 activeFlag_(0)
00287 {
00288 setActive();
00289 }
00290
00291
00292
00293 TrimmableItem::TrimmableItem(TrimmableItem *parent)
00294 : QListViewItem (parent, parent->lastChild()),
00295 activeFlag_(0),
00296 waitingForData_(false)
00297 {
00298 setActive();
00299 }
00300
00301
00302
00303 TrimmableItem::~TrimmableItem()
00304 {
00305 }
00306
00307
00308
00309 int TrimmableItem::rootActiveFlag() const
00310 {
00311 return ((VariableTree*)listView())->activeFlag();
00312 }
00313
00314
00315
00316 bool TrimmableItem::isTrimmable() const
00317 {
00318 return !waitingForData_;
00319 }
00320
00321
00322
00323 QListViewItem *TrimmableItem::lastChild() const
00324 {
00325 QListViewItem *child = firstChild();
00326 if (child)
00327 while (QListViewItem *nextChild = child->nextSibling())
00328 child = nextChild;
00329
00330 return child;
00331 }
00332
00333
00334
00335 TrimmableItem *TrimmableItem::findMatch(const QString &match, DataType type) const
00336 {
00337 QListViewItem *child = firstChild();
00338
00339
00340 while (child) {
00341 if (child->text(VarNameCol) == match) {
00342 if (TrimmableItem *item = dynamic_cast<TrimmableItem*> (child))
00343 if (item->getDataType() == type)
00344 return item;
00345 }
00346
00347 child = child->nextSibling();
00348 }
00349
00350 return 0;
00351 }
00352
00353
00354
00355 void TrimmableItem::trim()
00356 {
00357 QListViewItem *child = firstChild();
00358
00359 while (child) {
00360 QListViewItem *nextChild = child->nextSibling();
00361 if (TrimmableItem *item = dynamic_cast<TrimmableItem*>(child)) {
00362
00363 if (isTrimmable()) {
00364 if (item->isActive())
00365 item->trim();
00366 else
00367 delete item;
00368 }
00369 }
00370 child = nextChild;
00371 }
00372 }
00373
00374
00375
00376 DataType TrimmableItem::getDataType() const
00377 {
00378 return typeUnknown;
00379 }
00380
00381
00382
00383 void TrimmableItem::setCache(const QCString&)
00384 {
00385 Q_ASSERT(false);
00386 }
00387
00388
00389
00390 QCString TrimmableItem::getCache()
00391 {
00392 Q_ASSERT(false);
00393 return QCString();
00394 }
00395
00396
00397
00398 void TrimmableItem::updateValue(char* )
00399 {
00400 waitingForData_ = false;
00401 }
00402
00403
00404
00405 QString TrimmableItem::key (int, bool) const
00406 {
00407 return QString::null;
00408 }
00409
00410
00411
00412
00413
00414 VarItem::VarItem(TrimmableItem *parent, const QString &varName, DataType dataType)
00415 : TrimmableItem (parent),
00416 cache_(QCString()),
00417 dataType_(dataType),
00418 highlight_(false)
00419 {
00420 setText(VarNameCol, varName);
00421 }
00422
00423
00424
00425 VarItem::~VarItem()
00426 {
00427 }
00428
00429
00430
00431 QString VarItem::varPath() const
00432 {
00433 QString vPath("");
00434 const VarItem *item = this;
00435
00436
00437 while ((item = dynamic_cast<const VarItem*> (item->parent()))) {
00438 if (item->getDataType() != typeArray) {
00439 if ((item->text(VarNameCol))[0] != '<') {
00440 QString itemName = item->text(VarNameCol);
00441 if (vPath.isEmpty())
00442 vPath = itemName.replace(QRegExp("^static "), "");
00443 else
00444 vPath = itemName.replace(QRegExp("^static "), "") + "." + vPath;
00445 }
00446 }
00447 }
00448
00449 return vPath;
00450 }
00451
00452
00453
00454 QString VarItem::fullName() const
00455 {
00456 QString itemName(getName());
00457 Q_ASSERT (!itemName.isNull());
00458 QString vPath = varPath();
00459 if (itemName[0] == '<')
00460 return vPath;
00461
00462 if (vPath.isEmpty())
00463 return itemName.replace(QRegExp("^static "), "");
00464
00465 return varPath() + "." + itemName.replace(QRegExp("^static "), "");
00466 }
00467
00468
00469
00470 void VarItem::setText(int column, const QString &data)
00471 {
00472 if (!isActive() && isOpen() && dataType_ == typePointer) {
00473 waitingForData();
00474 ((VariableTree*)listView())->expandItem(this);
00475 }
00476
00477 setActive();
00478 if (column == ValueCol) {
00479 QString oldValue(text(column));
00480 if (!oldValue.isEmpty())
00481 highlight_ = (oldValue != QString(data));
00482 }
00483
00484 QListViewItem::setText(column, data);
00485 repaint();
00486 }
00487
00488
00489
00490 void VarItem::updateValue(char *buf)
00491 {
00492 TrimmableItem::updateValue(buf);
00493
00494
00495 if ((strncmp(buf, "There is no member named len.", 29) == 0) ||
00496 (strncmp(buf, "There is no member or method named len.", 39) == 0))
00497 return;
00498
00499 if (*buf == '$') {
00500 if (char *end = strchr(buf, '='))
00501 buf = end+2;
00502 }
00503
00504 if (dataType_ == typeUnknown) {
00505 dataType_ = getParser()->determineType(buf);
00506 if (dataType_ == typeArray)
00507 buf++;
00508
00509
00510
00511 QString varName = getName();
00512 if (dataType_ == typePointer && varName[0] == '/')
00513 dataType_ = typeValue;
00514 }
00515
00516 getParser()->parseData(this, buf, true, false);
00517 setActive();
00518 }
00519
00520
00521
00522 void VarItem::setCache(const QCString &value)
00523 {
00524 cache_ = value;
00525 setExpandable(true);
00526 checkForRequests();
00527 if (isOpen())
00528 setOpen(true);
00529 setActive();
00530 }
00531
00532
00533
00534 void VarItem::setOpen(bool open)
00535 {
00536 if (open) {
00537 if (cache_) {
00538 QCString value = cache_;
00539 cache_ = QCString();
00540 getParser()->parseData(this, value.data(), false, false);
00541 trim();
00542 } else {
00543 if (dataType_ == typePointer || dataType_ == typeReference) {
00544 waitingForData();
00545 emit ((VariableTree*)listView())->expandItem(this);
00546 }
00547 }
00548 }
00549
00550 QListViewItem::setOpen(open);
00551 }
00552
00553
00554
00555 QCString VarItem::getCache()
00556 {
00557 return cache_;
00558 }
00559
00560
00561
00562 void VarItem::checkForRequests()
00563 {
00565
00566
00567 if (strncmp(cache_, "<QArrayT<char>> = {<QGArray> = {shd = ", 38) == 0) {
00568 waitingForData();
00569 emit ((VariableTree*)listView())->expandUserItem(this,
00570 fullName().latin1()+QCString(".shd.data"));
00571 }
00572
00573
00574 if (strncmp(cache_, "dPath = {<QArrayT<char>> = {<QGArray> = {shd", 44) == 0) {
00575 waitingForData();
00576 emit ((VariableTree*)listView())->expandUserItem(this,
00577 fullName().latin1()+QCString(".dPath.shd.data"));
00578 }
00579
00580
00583 if (strncmp(cache_, "d = 0x", 6) == 0) {
00584 waitingForData();
00585 emit ((VariableTree*)listView())->expandUserItem(this,
00586 QCString().sprintf("(($len=($data=%s.d).len)?$data.unicode.rw@($len>100?200:$len*2):\"\")",
00587 fullName().latin1()));
00588 }
00589
00590
00591 if (strncmp(cache_, "<QArray<char>> = {<QGArray> = {shd = ", 37) == 0) {
00592 waitingForData();
00593 emit ((VariableTree*)listView())->expandUserItem(this,
00594 fullName().latin1()+QCString(".shd.data"));
00595 }
00596
00597
00598 if (strncmp(cache_, "dPath = {d = 0x", 15) == 0) {
00599 waitingForData();
00600 ((VariableTree*)listView())->expandUserItem(this,
00601 QCString().sprintf("(($len=($data=%s.dPath.d).len)?$data.unicode.rw@($len>100?200:$len*2):\"\")",
00602 fullName().latin1()));
00603 }
00604 }
00605
00606
00607
00608 DataType VarItem::getDataType() const
00609 {
00610 return dataType_;
00611 }
00612
00613
00614
00615
00616 void VarItem::paintCell(QPainter *p, const QColorGroup &cg,
00617 int column, int width, int align)
00618 {
00619 if ( !p )
00620 return;
00621
00622 if (column == ValueCol && highlight_) {
00623 QColorGroup hl_cg( cg.foreground(), cg.background(), cg.light(),
00624 cg.dark(), cg.mid(), red, cg.base());
00625 QListViewItem::paintCell( p, hl_cg, column, width, align );
00626 } else
00627 QListViewItem::paintCell( p, cg, column, width, align );
00628 }
00629
00630
00631
00632
00633
00634 FrameRoot::FrameRoot(VariableTree *parent, int frameNo)
00635 : TrimmableItem (parent),
00636 needLocals_(true),
00637 frameNo_(frameNo),
00638 params_(QCString()),
00639 locals_(QCString())
00640 {
00641 setExpandable(true);
00642 }
00643
00644
00645
00646 FrameRoot::~FrameRoot()
00647 {
00648 }
00649
00650
00651
00652 void FrameRoot::addLocal(QString name, QString , QString )
00653 {
00654 setText( VarNameCol, name);
00655 }
00656
00657
00658 void FrameRoot::setLocals(char *locals)
00659 {
00660 Q_ASSERT(isActive());
00661
00662
00663 bool noLocals = (locals && (strncmp(locals, "No ", 3) == 0));
00664 setExpandable(!params_.isEmpty() || !noLocals);
00665
00666 if (noLocals) {
00667 locals_ = "";
00668 if (locals)
00669 if (char *end = strchr(locals, '\n'))
00670 *end = 0;
00671 } else
00672 locals_ = locals;
00673
00674 if (!isExpandable() && noLocals)
00675 setText( ValueCol, locals );
00676
00677 needLocals_ = false;
00678 if (isOpen())
00679 setOpen(true);
00680 }
00681
00682
00683
00684 void FrameRoot::setParams(const QCString ¶ms)
00685 {
00686 setActive();
00687 params_ = params;
00688 needLocals_ = true;
00689 }
00690
00691
00692
00693
00694
00695 void FrameRoot::setOpen(bool open)
00696 {
00697 bool localStateChange = (isOpen() != open);
00698 QListViewItem::setOpen(open);
00699
00700 if (localStateChange)
00701 ((VariableTree*)listView())->setLocalViewState(open, frameNo_);
00702
00703 if (!open)
00704 return;
00705
00706 getParser()->parseData(this, params_.data(), false, true);
00707 getParser()->parseData(this, locals_.data(), false, false);
00708
00709 locals_ = QCString();
00710 params_ = QCString();
00711 }
00712
00713
00714
00715
00716
00717
00718 WatchRoot::WatchRoot(VariableTree *parent)
00719 : TrimmableItem(parent)
00720 {
00721 setText(0, i18n("Watch"));
00722 setOpen(true);
00723 }
00724
00725
00726
00727 WatchRoot::~WatchRoot()
00728 {
00729 }
00730
00731
00732
00733 void WatchRoot::requestWatchVars()
00734 {
00735 for (QListViewItem *child = firstChild(); child; child = child->nextSibling())
00736 if (VarItem *varItem = dynamic_cast<VarItem*>(child))
00737 emit ((VariableTree*)listView())->expandItem(varItem);
00738 }
00739
00740
00741
00742
00743
00744 }
00745
00746 #include "variablewidget.moc"