KDevelop API Documentation

languages/java/debugger/variablewidget.cpp

Go to the documentation of this file.
00001 // ************************************************************************** 00002 // vartree.cpp - description 00003 // ------------------- 00004 // begin : Sun Aug 8 1999 00005 // copyright : (C) 1999 by John Birch 00006 // email : jbb@kdevelop.org 00007 // ************************************************************************** 00008 00009 // ************************************************************************** 00010 // * * 00011 // * This program is free software; you can redistribute it and/or modify * 00012 // * it under the terms of the GNU General Public License as published by * 00013 // * the Free Software Foundation; either version 2 of the License, or * 00014 // * (at your option) any later version. * 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 // This may be a matter of taste... 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); // Need to select this item. 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 // When they want to _close_ a frame then we need to check the state of 00166 // all other frames to determine whether we still need the locals. 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 // frames only exist on th top level so we only need to 00202 // check the siblings 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 // don't trim the watch root 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 // Check the siblings on this branch 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 // Never trim a branch if we are waiting on data to arrive. 00363 if (isTrimmable()) { 00364 if (item->isActive()) 00365 item->trim(); // recurse 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* /* buf */) 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 // This stops at the root item (FrameRoot or WatchRoot) 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()) // Don't highlight new items 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 // Hack due to my bad QString implementation - this just tidies up the display 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 // Try fixing a format string here by overriding the dataType calculated 00510 // from this data 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 // Signature for a QT1.44 QString 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 // Signature for a QT1.44 QDir 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 // Signature for a QT2.0.x QT2.1 QString 00583 if (strncmp(cache_, "d = 0x", 6) == 0) { // Eeeek - too small 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 // Signature for a QT2.0.x QT2.1 QCString 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 // Signature for a QT2.0.x QT2.1 QDir 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 // Overridden to highlight the changed items 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 /*type*/, QString /*value*/) 00653 { 00654 setText( VarNameCol, name); 00655 } 00656 00657 00658 void FrameRoot::setLocals(char *locals) 00659 { 00660 Q_ASSERT(isActive()); 00661 00662 // "No symbol table info available" or "No locals." 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; // clobber the new line 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 &params) 00685 { 00686 setActive(); 00687 params_ = params; 00688 needLocals_ = true; 00689 } 00690 00691 // ************************************************************************** 00692 00693 // Override setOpen so that we can decide what to do when we do change 00694 // state. This 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"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:02 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003