File indexing completed on 2024-04-21 13:19:25

0001 /*
0002  *   Copyright 2014 by Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU Library General Public License as
0006  *   published by the Free Software Foundation; either version 2, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details
0013  *
0014  *   You should have received a copy of the GNU Library General Public
0015  *   License along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018  */
0019 
0020 #include "objectdebug.h"
0021 #include "objecttimetracker.h"
0022 #include "objectwatcher.h"
0023 
0024 #include <QChildEvent>
0025 #include <QDebug>
0026 
0027 
0028 class ObjectDecorator
0029 {
0030     QHash<QObject*, ObjectDebug*> m_debugs;
0031 
0032 public:
0033     void setDebugForObject(QObject* object, ObjectDebug* dbg, bool anyway = false)
0034     {
0035         Q_ASSERT(m_debugs.value(object) == nullptr || anyway);
0036         m_debugs[object] = dbg;
0037     }
0038 
0039     ObjectDebug* debugForObject(QObject* object)
0040     {
0041         return m_debugs.value(object);
0042     }
0043 
0044     void forgetObject(QObject* object) {
0045         if (!object)
0046             return;
0047         Q_ASSERT(m_debugs.value(object) != nullptr);
0048         m_debugs[object] = nullptr;
0049     }
0050 };
0051 
0052 Q_GLOBAL_STATIC(ObjectDecorator, ourDecorator)
0053 
0054 ObjectDebug::ObjectDebug(QObject* object)
0055     : m_object(object)
0056 {
0057     ourDecorator->setDebugForObject(object, this);
0058     connect(object, &QObject::destroyed, this, &QObject::deleteLater);
0059 }
0060 
0061 ObjectDebug::~ObjectDebug()
0062 {
0063     ourDecorator->forgetObject(m_object);
0064 
0065     qDeleteAll(m_children);
0066     delete m_timeTracker;
0067     delete m_watcher;
0068 }
0069 
0070 void ObjectDebug::setTimeTracker(bool timeTracker)
0071 {
0072     if (timeTracker == bool(m_timeTracker))
0073         return;
0074 
0075     if (!m_timeTracker) {
0076         m_timeTracker = QPointer<ObjectTimeTracker>{ new ObjectTimeTracker(m_object) };
0077     } else {
0078         delete m_timeTracker;
0079     }
0080     Q_EMIT timeTrackerChanged(m_timeTracker);
0081 }
0082 
0083 void ObjectDebug::setWatch(bool watch)
0084 {
0085     if (watch == bool(m_watcher))
0086         return;
0087 
0088     if (!m_watcher) {
0089         m_watcher = QPointer<ObjectWatcher>(new ObjectWatcher(m_object));
0090     } else {
0091         delete m_watcher;
0092     }
0093     Q_EMIT watchChanged(m_watcher);
0094 }
0095 
0096 bool ObjectDebug::timeTracker() const
0097 {
0098     return m_timeTracker;
0099 }
0100 
0101 bool ObjectDebug::watch() const
0102 {
0103     return m_watcher;
0104 }
0105 
0106 bool ObjectDebug::inherit() const
0107 {
0108     return m_inherit;
0109 }
0110 
0111 void ObjectDebug::setInherit(bool inherit)
0112 {
0113     if (inherit == m_inherit)
0114         return;
0115 
0116     m_inherit = inherit;
0117     Q_ASSERT(m_object);
0118     if (inherit) {
0119         for(auto o: m_object->children())
0120             addChild(o);
0121 
0122         m_object->installEventFilter(this);
0123     } else {
0124         qDeleteAll(m_children);
0125         m_children.clear();
0126 
0127         m_object->removeEventFilter(this);
0128     }
0129 }
0130 
0131 void ObjectDebug::childDestroyed(QObject* object)
0132 {
0133     auto od = dynamic_cast<ObjectDebug*>(object);
0134     if (!od) {
0135         return;
0136     }
0137 
0138     m_children.remove(od);
0139 }
0140 
0141 void ObjectDebug::addChild(QObject* child)
0142 {
0143     auto od = ObjectDebug::qmlAttachedProperties(child);
0144     od->setTimeTracker(timeTracker());
0145     od->setWatch(watch());
0146     od->setInherit(true);
0147     connect(this, &ObjectDebug::timeTrackerChanged, od, &ObjectDebug::setTimeTracker);
0148     connect(this, &ObjectDebug::watchChanged, od, &ObjectDebug::setWatch);
0149     connect(od, &QObject::destroyed, this, &ObjectDebug::childDestroyed);
0150     connect(od, &ObjectDebug::independence, this, &ObjectDebug::childDestroyed);
0151     m_children << od;
0152 }
0153 
0154 bool ObjectDebug::eventFilter(QObject* watched, QEvent* event)
0155 {
0156     Q_ASSERT(m_inherit);
0157     Q_ASSERT(watched == m_object);
0158 
0159     if (event->type() == QEvent::ChildAdded) {
0160         QChildEvent* childEvent = static_cast<QChildEvent*>(event);
0161 
0162         addChild(childEvent->child());
0163     }
0164     return QObject::eventFilter(watched, event);
0165 }
0166 
0167 ObjectDebug* ObjectDebug::qmlAttachedProperties(QObject* object)
0168 {
0169     ObjectDebug* od = ourDecorator->debugForObject(object);
0170     if (!od) {
0171         od = new ObjectDebug(object);
0172     } else {
0173         Q_EMIT od->independence(od);
0174         ourDecorator->setDebugForObject(object, od, true);
0175     }
0176     return od;
0177 }