File indexing completed on 2024-03-24 05:45:33
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 }