source: trunk/src/scripttools/debugging/qscriptdebuggerlocalsmodel.cpp@ 570

Last change on this file since 570 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 31.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtSCriptTools module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptdebuggerlocalsmodel_p.h"
43#include "qscriptdebuggercommandschedulerjob_p.h"
44#include "qscriptdebuggervalue_p.h"
45#include "qscriptdebuggerresponse_p.h"
46#include "qscriptdebuggerevent_p.h"
47#include "qscriptdebuggervalueproperty_p.h"
48#include "qscriptdebuggercommandschedulerinterface_p.h"
49#include "qscriptdebuggercommandschedulerfrontend_p.h"
50#include "qscriptdebuggerjobschedulerinterface_p.h"
51#include "qscriptdebuggerobjectsnapshotdelta_p.h"
52
53#include "private/qabstractitemmodel_p.h"
54
55#include <QtCore/qdebug.h>
56#include <QtCore/qcoreapplication.h>
57#include <QtGui/qbrush.h>
58#include <QtGui/qfont.h>
59
60Q_DECLARE_METATYPE(QScriptDebuggerObjectSnapshotDelta)
61
62QT_BEGIN_NAMESPACE
63
64struct QScriptDebuggerLocalsModelNode
65{
66 enum PopulationState {
67 NotPopulated,
68 Populating,
69 Populated
70 };
71
72 QScriptDebuggerLocalsModelNode()
73 : parent(0), populationState(NotPopulated), snapshotId(-1), changed(false) {}
74
75 QScriptDebuggerLocalsModelNode(
76 const QScriptDebuggerValueProperty &prop,
77 QScriptDebuggerLocalsModelNode *par)
78 : property(prop), parent(par),
79 populationState(NotPopulated), snapshotId(-1), changed(false)
80 {
81 parent->children.append(this);
82 }
83
84 ~QScriptDebuggerLocalsModelNode() { qDeleteAll(children); }
85
86 QScriptDebuggerLocalsModelNode *findChild(const QString &name)
87 {
88 for (int i = 0; i < children.size(); ++i) {
89 QScriptDebuggerLocalsModelNode *child = children.at(i);
90 if (child->property.name() == name)
91 return child;
92 }
93 return 0;
94 }
95
96 QScriptDebuggerValueProperty property;
97 QScriptDebuggerLocalsModelNode *parent;
98 QList<QScriptDebuggerLocalsModelNode*> children;
99 PopulationState populationState;
100 int snapshotId;
101 bool changed;
102};
103
104class QScriptDebuggerLocalsModelPrivate
105 : public QAbstractItemModelPrivate
106{
107 Q_DECLARE_PUBLIC(QScriptDebuggerLocalsModel)
108public:
109 QScriptDebuggerLocalsModelPrivate();
110 ~QScriptDebuggerLocalsModelPrivate();
111
112 static QScriptDebuggerLocalsModelPrivate *get(QScriptDebuggerLocalsModel *q);
113
114 QModelIndex addTopLevelObject(const QString &name, const QScriptDebuggerValue &object);
115
116 QScriptDebuggerLocalsModelNode *nodeFromIndex(const QModelIndex &index) const;
117 QModelIndex indexFromNode(QScriptDebuggerLocalsModelNode *node) const;
118 bool isTopLevelNode(QScriptDebuggerLocalsModelNode *node) const;
119
120 void populateIndex(const QModelIndex &index);
121 void reallyPopulateIndex(const QModelIndex &index,
122 const QScriptDebuggerValuePropertyList &props);
123 void syncIndex(const QModelIndex &index);
124 void reallySyncIndex(const QModelIndex &index,
125 const QScriptDebuggerObjectSnapshotDelta &delta);
126 void syncTopLevelNodes();
127 void removeTopLevelNodes();
128 void emitScopeObjectAvailable(const QModelIndex &index);
129
130 void emitDataChanged(const QModelIndex &tl, const QModelIndex &br);
131 void removeChild(const QModelIndex &parentIndex,
132 QScriptDebuggerLocalsModelNode *parentNode, int row);
133 void depopulate(QScriptDebuggerLocalsModelNode *node);
134 void repopulate(QScriptDebuggerLocalsModelNode *node);
135 void addChildren(const QModelIndex &parentIndex,
136 QScriptDebuggerLocalsModelNode *parentNode,
137 const QScriptDebuggerValuePropertyList &props);
138
139 void deleteObjectSnapshots(const QList<qint64> &snapshotIds);
140 void deleteAllObjectSnapshots();
141
142 QScriptDebuggerJobSchedulerInterface *jobScheduler;
143 QScriptDebuggerCommandSchedulerInterface *commandScheduler;
144 QScriptDebuggerLocalsModelNode *invisibleRootNode;
145 int frameIndex;
146};
147
148QScriptDebuggerLocalsModelPrivate::QScriptDebuggerLocalsModelPrivate()
149{
150 invisibleRootNode = new QScriptDebuggerLocalsModelNode();
151 frameIndex = -1;
152}
153
154QScriptDebuggerLocalsModelPrivate::~QScriptDebuggerLocalsModelPrivate()
155{
156 delete invisibleRootNode;
157}
158
159void QScriptDebuggerLocalsModelPrivate::emitDataChanged(const QModelIndex &tl, const QModelIndex &br)
160{
161 q_func()->dataChanged(tl, br);
162}
163
164static QList<qint64> findSnapshotIdsRecursively(QScriptDebuggerLocalsModelNode *root)
165{
166 QList<qint64> result;
167 if (root->snapshotId == -1) {
168 Q_ASSERT(root->children.isEmpty());
169 return result;
170 }
171 QList<QScriptDebuggerLocalsModelNode*> nodeStack;
172 nodeStack.append(root);
173 while (!nodeStack.isEmpty()) {
174 QScriptDebuggerLocalsModelNode *node = nodeStack.takeFirst();
175 result.append(node->snapshotId);
176 for (int i = 0; i < node->children.count(); ++i) {
177 QScriptDebuggerLocalsModelNode *child = node->children.at(i);
178 if (child->snapshotId != -1)
179 nodeStack.prepend(child);
180 }
181 }
182 return result;
183}
184
185void QScriptDebuggerLocalsModelPrivate::removeChild(const QModelIndex &parentIndex,
186 QScriptDebuggerLocalsModelNode *parentNode,
187 int row)
188{
189 Q_Q(QScriptDebuggerLocalsModel);
190 q->beginRemoveRows(parentIndex, row, row);
191 QScriptDebuggerLocalsModelNode *child = parentNode->children.takeAt(row);
192 QList<qint64> snapshotIds = findSnapshotIdsRecursively(child);
193 delete child;
194 q->endRemoveRows();
195 deleteObjectSnapshots(snapshotIds);
196}
197
198void QScriptDebuggerLocalsModelPrivate::depopulate(QScriptDebuggerLocalsModelNode *node)
199{
200 Q_Q(QScriptDebuggerLocalsModel);
201 bool hasChildren = !node->children.isEmpty();
202 if (hasChildren)
203 q->beginRemoveRows(indexFromNode(node), 0, node->children.count() - 1);
204 QList<qint64> snapshotIds = findSnapshotIdsRecursively(node);
205 qDeleteAll(node->children);
206 node->children.clear();
207 node->snapshotId = -1;
208 node->populationState = QScriptDebuggerLocalsModelNode::NotPopulated;
209 if (hasChildren)
210 q->endRemoveRows();
211 deleteObjectSnapshots(snapshotIds);
212}
213
214void QScriptDebuggerLocalsModelPrivate::repopulate(QScriptDebuggerLocalsModelNode *node)
215{
216 if (node->populationState != QScriptDebuggerLocalsModelNode::Populated)
217 return;
218 depopulate(node);
219 if (node->property.value().type() == QScriptDebuggerValue::ObjectValue)
220 populateIndex(indexFromNode(node));
221}
222
223void QScriptDebuggerLocalsModelPrivate::addChildren(const QModelIndex &parentIndex,
224 QScriptDebuggerLocalsModelNode *parentNode,
225 const QScriptDebuggerValuePropertyList &props)
226{
227 Q_Q(QScriptDebuggerLocalsModel);
228 if (props.isEmpty())
229 return;
230 int first = parentNode->children.size();
231 int last = first + props.size() - 1;
232 q->beginInsertRows(parentIndex, first, last);
233 for (int i = 0; i < props.size(); ++i)
234 new QScriptDebuggerLocalsModelNode(props.at(i), parentNode);
235 q->endInsertRows();
236}
237
238void QScriptDebuggerLocalsModelPrivate::deleteObjectSnapshots(const QList<qint64> &snapshotIds)
239{
240 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler, 0);
241 for (int i = 0; i < snapshotIds.size(); ++i)
242 frontend.scheduleDeleteScriptObjectSnapshot(snapshotIds.at(i));
243}
244
245void QScriptDebuggerLocalsModelPrivate::deleteAllObjectSnapshots()
246{
247 QList<qint64> snapshotIds;
248 for (int i = 0; i < invisibleRootNode->children.count(); ++i)
249 snapshotIds += findSnapshotIdsRecursively(invisibleRootNode->children.at(i));
250 deleteObjectSnapshots(snapshotIds);
251}
252
253QScriptDebuggerLocalsModelPrivate *QScriptDebuggerLocalsModelPrivate::get(QScriptDebuggerLocalsModel *q)
254{
255 return q->d_func();
256}
257
258namespace {
259
260class SetPropertyJob : public QScriptDebuggerCommandSchedulerJob
261{
262public:
263 SetPropertyJob(const QPersistentModelIndex &index,
264 const QString &expression,
265 QScriptDebuggerCommandSchedulerInterface *scheduler)
266 : QScriptDebuggerCommandSchedulerJob(scheduler),
267 m_index(index), m_expression(expression), m_state(0) {}
268
269 QScriptDebuggerLocalsModelPrivate *model() const
270 {
271 if (!m_index.isValid())
272 return 0;
273 QAbstractItemModel *m = const_cast<QAbstractItemModel*>(m_index.model());
274 QScriptDebuggerLocalsModel *lm = qobject_cast<QScriptDebuggerLocalsModel*>(m);
275 return QScriptDebuggerLocalsModelPrivate::get(lm);
276 }
277
278 void start()
279 {
280 if (!m_index.isValid()) {
281 // nothing to do, the node has been removed
282 return;
283 }
284 QScriptDebuggerLocalsModelNode *node = model()->nodeFromIndex(m_index);
285 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
286 frontend.scheduleEvaluate(model()->frameIndex, m_expression,
287 QString::fromLatin1("set property '%0' (%1)")
288 .arg(node->property.name())
289 .arg(QDateTime::currentDateTime().toString()));
290 }
291
292 void handleResponse(const QScriptDebuggerResponse &, int)
293 {
294 switch (m_state) {
295 case 0:
296 hibernateUntilEvaluateFinished();
297 ++m_state;
298 break;
299 case 1:
300 finish();
301 break;
302 }
303 }
304
305 void evaluateFinished(const QScriptDebuggerValue &result)
306 {
307 if (!m_index.isValid()) {
308 // nothing to do, the node has been removed
309 return;
310 }
311 QScriptDebuggerLocalsModelNode *node = model()->nodeFromIndex(m_index);
312 Q_ASSERT(node->parent != 0);
313 QScriptDebuggerValue object = node->parent->property.value();
314 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
315 frontend.scheduleSetScriptValueProperty(object, node->property.name(), result);
316 }
317