KDevelop API Documentation

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.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:46 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003