source: trunk/src/3rdparty/phonon/mmf/objectdump.cpp

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1/* This file is part of the KDE project.
2
3Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5This library is free software: you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation, either version 2.1 or 3 of the License.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along with this library. If not, see <http://www.gnu.org/licenses/>.
16
17*/
18
19#include <QByteArray>
20#include <QDebug>
21#include <QHash>
22#include <QTextStream>
23#include <QWidget>
24
25#include "objectdump.h"
26#include "objecttree.h"
27
28QT_BEGIN_NAMESPACE
29
30namespace ObjectDump
31{
32
33//-----------------------------------------------------------------------------
34// QObjectAnnotator
35//-----------------------------------------------------------------------------
36
37QAnnotator::~QAnnotator()
38{
39
40}
41
42
43//-----------------------------------------------------------------------------
44// Annotators
45//-----------------------------------------------------------------------------
46
47QList<QByteArray> QAnnotatorBasic::annotation(const QObject& object)
48{
49 QList<QByteArray> result;
50
51 QByteArray array;
52 QTextStream stream(&array);
53
54 stream << '[' << &object << ']';
55 stream << ' ';
56 stream << object.metaObject()->className();
57
58 if (object.objectName() != "")
59 stream << " \"" << object.objectName() << '"';
60
61 if (object.isWidgetType())
62 stream << " isWidget";
63
64 stream.flush();
65 result.append(array);
66 return result;
67}
68
69QList<QByteArray> QAnnotatorWidget::annotation(const QObject& object)
70{
71 QList<QByteArray> result;
72
73 const QWidget* widget = qobject_cast<const QWidget*>(&object);
74 if (widget) {
75
76 QByteArray array;
77 QTextStream stream(&array);
78
79 stream << "widget: ";
80
81 if (widget->isVisible())
82 stream << "visible ";
83 else
84 stream << "invisible ";
85
86 stream << widget->x() << ',' << widget->y() << ' ';
87 stream << widget->size().width() << 'x'<< widget->size().height() << ' ';
88
89 stream << "hint " << widget->sizeHint().width() << 'x' << widget->sizeHint().height();
90
91 stream.flush();
92 result.append(array);
93 }
94
95 return result;
96}
97
98
99//-----------------------------------------------------------------------------
100// Base class for QDumperPrivate, QVisitorPrivate
101//-----------------------------------------------------------------------------
102
103class QDumperBase
104{
105public:
106 QDumperBase();
107 ~QDumperBase();
108
109 void setPrefix(const QString& prefix);
110 void addAnnotator(QAnnotator* annotator);
111
112protected:
113 QByteArray m_prefix;
114 QList<QAnnotator*> m_annotators;
115
116};
117
118QDumperBase::QDumperBase()
119{
120
121}
122
123QDumperBase::~QDumperBase()
124{
125 QAnnotator* annotator;
126 foreach(annotator, m_annotators)
127 delete annotator;
128}
129
130void QDumperBase::setPrefix(const QString& prefix)
131{
132 m_prefix = prefix.count()
133 ? (prefix + " ").toAscii()
134 : prefix.toAscii();
135}
136
137void QDumperBase::addAnnotator(QAnnotator* annotator)
138{
139 // Protect against an exception occurring during QList::append
140 QScopedPointer<QAnnotator> holder(annotator);
141 m_annotators.append(annotator);
142 holder.take();
143}
144
145
146//-----------------------------------------------------------------------------
147// QDumper
148//-----------------------------------------------------------------------------
149
150class QDumperPrivate : public QDumperBase
151{
152public:
153 QDumperPrivate();
154 ~QDumperPrivate();
155
156 void dumpObject(const QObject& object);
157
158};
159
160
161QDumperPrivate::QDumperPrivate()
162{
163
164}
165
166QDumperPrivate::~QDumperPrivate()
167{
168
169}
170
171void QDumperPrivate::dumpObject(const QObject& object)
172{
173 QAnnotator* annotator;
174 foreach(annotator, m_annotators) {
175
176 const QList<QByteArray> annotations = annotator->annotation(object);
177 QByteArray annotation;
178 foreach(annotation, annotations) {
179 QByteArray buffer(m_prefix);
180 buffer.append(annotation);
181 qDebug() << buffer.constData();
182 }
183 }
184}
185
186
187QDumper::QDumper()
188 : d_ptr(new QDumperPrivate)
189{
190
191}
192
193QDumper::~QDumper()
194{
195
196}
197
198void QDumper::setPrefix(const QString& prefix)
199{
200 d_func()->setPrefix(prefix);
201}
202
203void QDumper::addAnnotator(QAnnotator* annotator)
204{
205 d_func()->addAnnotator(annotator);
206}
207
208void QDumper::dumpObject(const QObject& object)
209{
210 d_func()->dumpObject(object);
211}
212
213
214//-----------------------------------------------------------------------------
215// QVisitor
216//-----------------------------------------------------------------------------
217
218class QVisitorPrivate : public QDumperBase
219{
220public:
221 QVisitorPrivate();
222 ~QVisitorPrivate();
223
224 void setIndent(unsigned indent);
225
226 void visitNode(const QObject& object);
227 void visitComplete();
228
229private:
230 class Node
231 {
232 public:
233 Node();
234 ~Node();
235
236 QList<QByteArray> m_annotation;
237 QList<Node*> m_children;
238
239 typedef QList<Node*>::const_iterator child_iterator;
240 };
241
242private:
243 Node* findNode(const QObject* object) const;
244 QByteArray branchBuffer(const QList<bool>& branches, bool isNodeLine, bool isLastChild) const;
245 void dumpRecursive(const Node& node, QList<bool> branches, bool isLastChild);
246 void dumpNode(const Node& node, const QList<bool>& branches, bool isLastChild);
247
248private:
249 unsigned m_indent;
250
251 QScopedPointer<Node> m_root;
252
253 // Hash table used to associate internal nodes with QObjects
254 typedef QHash<const QObject*, Node*> Hash;
255 Hash m_hash;
256};
257
258static const unsigned DefaultIndent = 2;
259
260QVisitorPrivate::QVisitorPrivate()
261 : m_indent(DefaultIndent)
262{
263
264}
265
266QVisitorPrivate::~QVisitorPrivate()
267{
268
269}
270
271void QVisitorPrivate::setIndent(unsigned indent)
272{
273 m_indent = indent;
274}
275
276// Builds up a mirror of the object tree, rooted in m_root, with each node
277// storing annotations generated by
278void QVisitorPrivate::visitNode(const QObject& object)
279{
280 QObject* const objectParent = object.parent();
281 Node* const nodeParent = objectParent ? findNode(objectParent) : 0;
282
283 // Create a new node and store in scoped pointer for exception safety
284 Node* node = new Node;
285 QScopedPointer<Node> nodePtr(node);
286
287 // Associate node with QObject
288 m_hash.insert(&object, node);
289
290 // Insert node into internal tree
291 if (nodeParent)
292 {
293 nodeParent->m_children.append(nodePtr.take());
294 }
295 else
296 {
297 Q_ASSERT(m_root.isNull());
298 m_root.reset(nodePtr.take());
299 }
300
301 // Generate and store annotations
302 QAnnotator* annotator;
303 foreach(annotator, m_annotators)
304 node->m_annotation.append( annotator->annotation(object) );
305}
306
307void QVisitorPrivate::visitComplete()
308{
309 QList<bool> branches;
310 static const bool isLastChild = true;
311 dumpRecursive(*m_root, branches, isLastChild);
312 m_root.reset(0);
313}
314
315QVisitorPrivate::Node* QVisitorPrivate::findNode(const QObject* object) const
316{
317 Hash::const_iterator i = m_hash.find(object);
318 return (m_hash.end() == i) ? 0 : *i;
319}
320
321QByteArray QVisitorPrivate::branchBuffer
322 (const QList<bool>& branches, bool isNodeLine, bool isLastChild) const
323{
324 const int depth = branches.count();
325
326 const QByteArray indent(m_indent, ' ');
327 const QByteArray horiz(m_indent, '-');
328
329 QByteArray buffer;
330 QTextStream stream(&buffer);
331
332 for (int i=0; i<depth-1; ++i) {
333 if (branches[i])
334 stream << '|';
335 else
336 stream << ' ';
337 stream << indent;
338 }
339
340 if (depth) {
341 if (isNodeLine)
342 stream << '+' << horiz;
343 else {
344 if (!isLastChild)
345 stream << '|';
346 else
347 stream << ' ';
348 stream << indent;
349 }
350 }
351
352 stream.flush();
353 buffer.push_front(m_prefix);
354
355 return buffer;
356}
357
358void QVisitorPrivate::dumpRecursive
359 (const Node& node, QList<bool> branches, bool isLastChild)
360{
361 dumpNode(node, branches, isLastChild);
362
363 // Recurse down tree
364 const Node::child_iterator begin = node.m_children.begin();
365 const Node::child_iterator end = node.m_children.end();
366 for (Node::child_iterator i = begin; end != i; ++i) {
367
368 isLastChild = (end == i + 1);
369
370 if (begin == i)
371 branches.push_back(!isLastChild);
372 else
373 branches.back() = !isLastChild;
374
375 static const bool isNodeLine = false;
376 const QByteArray buffer = branchBuffer(branches, isNodeLine, false);
377 qDebug() << buffer.constData();
378
379 dumpRecursive(**i, branches, isLastChild);
380 }
381}
382
383void QVisitorPrivate::dumpNode
384 (const Node& node, const QList<bool>& branches, bool isLastChild)
385{
386 const QList<QByteArray>::const_iterator
387 begin = node.m_annotation.begin(), end = node.m_annotation.end();
388
389 if (begin == end) {
390 // No annotations - just dump the object pointer
391 const bool isNodeLine = true;
392 QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild);
393 qDebug() << 0;
394 }
395 else {
396 // Dump annotations
397 for (QList<QByteArray>::const_iterator i = begin; end != i; ++i) {
398 const bool isNodeLine = (begin == i);
399 QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild);
400 buffer.append(*i);
401 qDebug() << buffer.constData();
402 }
403 }
404}
405
406
407// QVisitorPrivate::Node
408
409QVisitorPrivate::Node::Node()
410{
411
412}
413
414QVisitorPrivate::Node::~Node()
415{
416 Node* child;
417 foreach(child, m_children)
418 delete child;
419}
420
421
422// QVisitor
423
424QVisitor::QVisitor()
425 : d_ptr(new QVisitorPrivate)
426{
427
428}
429
430QVisitor::~QVisitor()
431{
432
433}
434
435void QVisitor::setPrefix(const QString& prefix)
436{
437 d_func()->setPrefix(prefix);
438}
439
440void QVisitor::setIndent(unsigned indent)
441{
442 d_func()->setIndent(indent);
443}
444
445void QVisitor::addAnnotator(QAnnotator* annotator)
446{
447 d_func()->addAnnotator(annotator);
448}
449
450void QVisitor::visitPrepare()
451{
452 // Do nothing
453}
454
455void QVisitor::visitNode(const QObject& object)
456{
457 d_func()->visitNode(object);
458}
459
460void QVisitor::visitComplete()
461{
462 d_func()->visitComplete();
463}
464
465
466//-----------------------------------------------------------------------------
467// Utility functions
468//-----------------------------------------------------------------------------
469
470void addDefaultAnnotators_sys(QDumper& visitor);
471void addDefaultAnnotators_sys(QVisitor& visitor);
472
473void addDefaultAnnotators(QDumper& dumper)
474{
475 dumper.addAnnotator(new QAnnotatorBasic);
476 dumper.addAnnotator(new QAnnotatorWidget);
477
478 // Add platform-specific annotators
479 addDefaultAnnotators_sys(dumper);
480}
481
482void addDefaultAnnotators(QVisitor& visitor)
483{
484 visitor.addAnnotator(new QAnnotatorBasic);
485 visitor.addAnnotator(new QAnnotatorWidget);
486
487 // Add platform-specific annotators
488 addDefaultAnnotators_sys(visitor);
489}
490
491void dumpTreeFromRoot(const QObject& root, QVisitor& visitor)
492{
493 // Set up iteration range
494 ObjectTree::DepthFirstConstIterator begin(root), end;
495
496 // Invoke generic visitor algorithm
497 ObjectTree::visit(begin, end, visitor);
498}
499
500void dumpTreeFromLeaf(const QObject& leaf, QVisitor& visitor)
501{
502 // Walk up to root
503 const QObject* root = &leaf;
504 while(root->parent())
505 {
506 root = root->parent();
507 }
508
509 dumpTreeFromRoot(*root, visitor);
510}
511
512void dumpAncestors(const QObject& leaf, QVisitor& visitor)
513{
514 // Set up iteration range
515 ObjectTree::AncestorConstIterator begin(leaf), end;
516
517 // Invoke generic visitor algorithm
518 ObjectTree::visit(begin, end, visitor);
519}
520
521
522} // namespace ObjectDump
523
524QT_END_NAMESPACE
525
Note: See TracBrowser for help on using the repository browser.