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