File indexing completed on 2024-12-01 09:50:26
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2006 Matt Broadstone (mbroadst@gmail.com) 0004 * (C) 2007 Maks Orlovich <maksim@kde.org> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0019 */ 0020 0021 #include "localvariabledock.h" 0022 0023 #include <QVBoxLayout> 0024 #include <QTreeWidget> 0025 #include <QEventLoop> 0026 #include <QStringList> 0027 0028 #include <kjs/interpreter.h> 0029 #include <kjs/PropertyNameArray.h> 0030 #include <kjs/context.h> 0031 #include <kjs/scope_chain.h> 0032 #include <kjs/JSVariableObject.h> 0033 #include <kjs/object.h> 0034 #include "khtml_debug.h" 0035 #include <klocalizedstring.h> 0036 0037 #include "value2string.h" 0038 0039 namespace KJSDebugger 0040 { 0041 0042 LocalVariablesDock::LocalVariablesDock(QWidget *parent) 0043 : QDockWidget(i18n("Local Variables"), parent), m_execState(0) 0044 { 0045 setFeatures(DockWidgetMovable | DockWidgetFloatable); 0046 m_view = new QTreeWidget(this); 0047 0048 m_view->setColumnCount(2); 0049 0050 QStringList headers; 0051 headers << i18n("Reference"); 0052 headers << i18n("Value"); 0053 m_view->setHeaderLabels(headers); 0054 0055 connect(m_view, SIGNAL(itemExpanded(QTreeWidgetItem*)), 0056 this, SLOT(slotItemExpanded(QTreeWidgetItem*))); 0057 0058 setWidget(m_view); 0059 } 0060 0061 LocalVariablesDock::~LocalVariablesDock() 0062 { 0063 } 0064 0065 void LocalVariablesDock::updateValue(KJS::ExecState *exec, KJS::JSValue *val, 0066 QTreeWidgetItem *item, bool recurse) 0067 { 0068 // Note: parent is responsible for setting our name.. 0069 item->setText(1, valueToString(val)); 0070 if (recurse) { 0071 if (val->isObject()) { 0072 updateObjectProperties(exec, val, item); 0073 } else { 0074 // It has no kids, so treeview item better not, either 0075 QList<QTreeWidgetItem *> kids = item->takeChildren(); 0076 qDeleteAll(kids); 0077 } 0078 } 0079 } 0080 0081 void LocalVariablesDock::updateObjectProperties(KJS::ExecState *exec, KJS::JSValue *val, 0082 QTreeWidgetItem *item, bool globalObject) 0083 { 0084 bool root = (item == m_view->invisibleRootItem()); 0085 0086 // We have to be careful here -- we don't want to recurse if we're not open; 0087 // except for root since we may want the + there 0088 bool recurse = item->isExpanded() || root; 0089 0090 QStringList props; 0091 KJS::JSObject *obj = 0; 0092 0093 // Get the list of all relevant properties.. 0094 // Note: val may be null for root case.. 0095 if (val) { 0096 assert(val->isObject()); 0097 0098 obj = val->getObject(); 0099 KJS::PropertyNameArray jsProps; 0100 0101 // We use getOwnPropertyNames and not getPropertyNames here 0102 // to not include things from the prototype 0103 obj->getOwnPropertyNames(exec, jsProps, KJS::PropertyMap::ExcludeDontEnumProperties); 0104 0105 for (int pos = 0; pos < jsProps.size(); ++pos) { 0106 // For global (window) objects, we only show hash table properties, 0107 // for less cluttered display. 0108 if (globalObject && !obj->getDirect(jsProps[pos])) { 0109 continue; 0110 } 0111 0112 props.append(jsProps[pos].ustring().qstring()); 0113 } 0114 } 0115 0116 // If we're not an activation, also list the prototype, as __proto__ 0117 if (val && !val->getObject()->isActivation()) { 0118 props << QLatin1String("__proto__"); 0119 } 0120 0121 // If we're the root, also pretend 'this' is there. 0122 if (root && exec) { 0123 props << QLatin1String("this"); 0124 } 0125 0126 // Sort them, to make updates easier. 0127 props.sort(); 0128 0129 // Do we need more or less nodes? 0130 while (props.size() < item->childCount()) { 0131 delete item->takeChild(item->childCount() - 1); 0132 } 0133 0134 while (props.size() > item->childCount()) { 0135 item->addChild(new QTreeWidgetItem); 0136 } 0137 0138 // Update names and values. 0139 for (int pos = 0; pos < props.size(); ++pos) { 0140 QString propName = props[pos]; 0141 QTreeWidgetItem *kid = item->child(pos); 0142 kid->setText(0, propName); 0143 0144 if (root && propName == "this") { 0145 updateValue(exec, exec->thisValue(), kid, true); 0146 } else { 0147 updateValue(exec, obj->get(exec, KJS::Identifier(KJS::UString(props[pos]))), kid, recurse); 0148 } 0149 } 0150 } 0151 0152 void LocalVariablesDock::slotItemExpanded(QTreeWidgetItem *item) 0153 { 0154 Q_UNUSED(item); 0155 updateDisplay(m_execState); 0156 } 0157 0158 void LocalVariablesDock::updateDisplay(KJS::ExecState *exec) 0159 { 0160 m_execState = exec; 0161 0162 // Find out out scope object... 0163 KJS::JSObject *scopeObject = 0; 0164 KJS::Context *context = 0; 0165 0166 if (exec) { 0167 context = exec->context(); 0168 } 0169 0170 // Find the nearest local scope, or 0171 // failing that the topmost scope 0172 if (context) { 0173 KJS::ScopeChain chain = context->scopeChain(); 0174 for (KJS::ScopeChainIterator iter = chain.begin(); 0175 iter != chain.end(); ++iter) { 0176 scopeObject = *iter; 0177 if (scopeObject->isActivation()) { 0178 break; 0179 } 0180 } 0181 } 0182 0183 updateObjectProperties(exec, scopeObject, m_view->invisibleRootItem(), 0184 scopeObject && !scopeObject->isActivation()); 0185 } 0186 0187 } 0188 0189 #include "moc_localvariabledock.cpp"