xmlpatterns filetree example: make app a bundle on Mac
[qt:matteos-kde-qt.git] / src / 3rdparty / phonon / mmf / mmfphonondebug / objectdump.cpp
1 /*  This file is part of the KDE project.
2
3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5 This library is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 2.1 or 3 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along 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
28 QT_BEGIN_NAMESPACE
29
30 namespace ObjectDump
31 {
32
33 //-----------------------------------------------------------------------------
34 // QObjectAnnotator
35 //-----------------------------------------------------------------------------
36
37 QAnnotator::~QAnnotator()
38 {
39
40 }
41
42
43 //-----------------------------------------------------------------------------
44 // Annotators
45 //-----------------------------------------------------------------------------
46
47 QList<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
69 QList<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
103 class QDumperBase
104 {
105 public:
106     QDumperBase();
107     ~QDumperBase();
108
109     void setPrefix(const QString& prefix);
110     void addAnnotator(QAnnotator* annotator);
111
112 protected:
113     QByteArray m_prefix;
114     QList<QAnnotator*> m_annotators;
115
116 };
117
118 QDumperBase::QDumperBase()
119 {
120
121 }
122
123 QDumperBase::~QDumperBase()
124 {
125     QAnnotator* annotator;
126     foreach(annotator, m_annotators)
127         delete annotator;
128 }
129
130 void QDumperBase::setPrefix(const QString& prefix)
131 {
132     m_prefix = prefix.count()
133         ? (prefix + " ").toAscii()
134         : prefix.toAscii();
135 }
136
137 void 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
150 class QDumperPrivate : public QDumperBase
151 {
152 public:
153     QDumperPrivate();
154     ~QDumperPrivate();
155
156     void dumpObject(const QObject& object);
157
158 };
159
160
161 QDumperPrivate::QDumperPrivate()
162 {
163
164 }
165
166 QDumperPrivate::~QDumperPrivate()
167 {
168
169 }
170
171 void 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
187 QDumper::QDumper()
188     : d_ptr(new QDumperPrivate)
189 {
190
191 }
192
193 QDumper::~QDumper()
194 {
195
196 }
197
198 void QDumper::setPrefix(const QString& prefix)
199 {
200     d_func()->setPrefix(prefix);
201 }
202
203 void QDumper::addAnnotator(QAnnotator* annotator)
204 {
205     d_func()->addAnnotator(annotator);
206 }
207
208 void QDumper::dumpObject(const QObject& object)
209 {
210     d_func()->dumpObject(object);
211 }
212
213
214 //-----------------------------------------------------------------------------
215 // QVisitor
216 //-----------------------------------------------------------------------------
217
218 class QVisitorPrivate : public QDumperBase
219 {
220 public:
221     QVisitorPrivate();
222     ~QVisitorPrivate();
223
224     void setIndent(unsigned indent);
225
226     void visitNode(const QObject& object);
227     void visitComplete();
228
229 private:
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
242 private:
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
248 private:
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
258 static const unsigned DefaultIndent = 2;
259
260 QVisitorPrivate::QVisitorPrivate()
261     :   m_indent(DefaultIndent)
262 {
263
264 }
265
266 QVisitorPrivate::~QVisitorPrivate()
267 {
268
269 }
270
271 void 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
278 void 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
307 void 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
315 QVisitorPrivate::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
321 QByteArray 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
358 void 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
383 void 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; // TODO
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
409 QVisitorPrivate::Node::Node()
410 {
411
412 }
413
414 QVisitorPrivate::Node::~Node()
415 {
416     Node* child;
417     foreach(child, m_children)
418         delete child;
419 }
420
421
422 // QVisitor
423
424 QVisitor::QVisitor()
425     : d_ptr(new QVisitorPrivate)
426 {
427
428 }
429
430 QVisitor::~QVisitor()
431 {
432
433 }
434
435 void QVisitor::setPrefix(const QString& prefix)
436 {
437     d_func()->setPrefix(prefix);
438 }
439
440 void QVisitor::setIndent(unsigned indent)
441 {
442     d_func()->setIndent(indent);
443 }
444
445 void QVisitor::addAnnotator(QAnnotator* annotator)
446 {
447     d_func()->addAnnotator(annotator);
448 }
449
450 void QVisitor::visitPrepare()
451 {
452     // Do nothing
453 }
454
455 void QVisitor::visitNode(const QObject& object)
456 {
457     d_func()->visitNode(object);
458 }
459
460 void QVisitor::visitComplete()
461 {
462     d_func()->visitComplete();
463 }
464
465
466 //-----------------------------------------------------------------------------
467 // Utility functions
468 //-----------------------------------------------------------------------------
469
470 void addDefaultAnnotators_sys(QDumper& visitor);
471 void addDefaultAnnotators_sys(QVisitor& visitor);
472
473 void 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
482 void 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
491 void 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
500 void 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
512 void 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
524 QT_END_NAMESPACE
525
526
527