1 //========================================================= 2 // MusE 3 // Linux Music Editor 4 // 5 // snooper.h 6 // (C) Copyright 2019 Tim E. Real (terminator356 on sourceforge) 7 // 8 // This program is free software; you can redistribute it and/or 9 // modify it under the terms of the GNU General Public License 10 // as published by the Free Software Foundation; version 2 of 11 // the License, or (at your option) any later version. 12 // 13 // This program is distributed in the hope that it will be useful, 14 // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 // GNU General Public License for more details. 17 // 18 // You should have received a copy of the GNU General Public License 19 // along with this program; if not, write to the Free Software 20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 // 22 //========================================================= 23 24 #ifndef __SNOOPER_H__ 25 #define __SNOOPER_H__ 26 27 #include <QWidget> 28 #include <QDialog> 29 #include <QTimer> 30 #include <QTreeWidgetItem> 31 #include <QMetaObject> 32 #include <QShowEvent> 33 #include <QHideEvent> 34 #include <QCloseEvent> 35 #include <QMap> 36 #include <QSet> 37 #include <QColor> 38 39 #include "ui_snooperbase.h" 40 41 namespace MusEGui { 42 43 //--------------------------------------------------------- 44 // SnooperTreeWidgetItem 45 //--------------------------------------------------------- 46 47 class SnooperTreeWidgetItem : public QTreeWidgetItem 48 { 49 public: 50 enum Cols { Name = 0, Property, PropertyType, PropertyValue, EventType }; 51 enum ItemType { 52 NormalItem = Type, 53 ObjectItem = UserType, 54 PropertiesItem = ObjectItem + 1, 55 PropertyItem = PropertiesItem + 1 56 }; 57 enum ItemMode { NormalMode }; 58 59 private: 60 QObject* _object; 61 bool _isWindowBranch; 62 bool _isParentedTopLevelBranch; 63 int _metaPropertyIndex; 64 QMetaObject::Connection _metaConnection; 65 //QMap<int /*type*/, int /*hit_count*/> _hitMap; 66 QBrush _origBackground; 67 int _flashCounter; 68 bool _isFlashing; 69 70 void init(); 71 72 public: 73 // Overrides for QTreeWidgetItem constructor... 74 SnooperTreeWidgetItem(int type = NormalItem, QObject* obj = nullptr, int metaPropertyIndex = 0, 75 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(type)76 : QTreeWidgetItem(type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 77 _metaConnection(conn) { init(); } 78 79 SnooperTreeWidgetItem(const QStringList& strings, int type = NormalItem, 80 QObject* obj = nullptr, int metaPropertyIndex = 0, 81 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(strings,type)82 : QTreeWidgetItem(strings, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 83 _metaConnection(conn) { init(); } 84 85 SnooperTreeWidgetItem(QTreeWidget* parent, int type = NormalItem, QObject* obj = nullptr, 86 int metaPropertyIndex = 0, 87 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,type)88 : QTreeWidgetItem(parent, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 89 _metaConnection(conn) { init(); } 90 91 SnooperTreeWidgetItem(QTreeWidget* parent, const QStringList& strings, int type = NormalItem, 92 QObject* obj = nullptr, int metaPropertyIndex = 0, 93 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,strings,type)94 : QTreeWidgetItem(parent, strings, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 95 _metaConnection(conn) { init(); } 96 97 SnooperTreeWidgetItem(QTreeWidget* parent, QTreeWidgetItem* preceding, int type = NormalItem, 98 QObject* obj = nullptr, int metaPropertyIndex = 0, 99 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,preceding,type)100 : QTreeWidgetItem(parent, preceding, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 101 _metaConnection(conn) { init(); } 102 103 SnooperTreeWidgetItem(QTreeWidgetItem* parent, int type = NormalItem, QObject* obj = nullptr, 104 int metaPropertyIndex = 0, 105 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,type)106 : QTreeWidgetItem(parent, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 107 _metaConnection(conn) { init(); } 108 109 SnooperTreeWidgetItem(QTreeWidgetItem* parent, const QStringList& strings, int type = NormalItem, 110 QObject* obj = nullptr, int metaPropertyIndex = 0, 111 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,strings,type)112 : QTreeWidgetItem(parent, strings, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 113 _metaConnection(conn) { init(); } 114 115 SnooperTreeWidgetItem(QTreeWidgetItem* parent, QTreeWidgetItem* preceding, int type = NormalItem, 116 QObject* obj = nullptr, int metaPropertyIndex = 0, 117 const QMetaObject::Connection& conn = QMetaObject::Connection()) QTreeWidgetItem(parent,preceding,type)118 : QTreeWidgetItem(parent, preceding, type), _object(obj), _metaPropertyIndex(metaPropertyIndex), 119 _metaConnection(conn) { init(); } 120 object()121 QObject* object() { return _object; } cobject()122 const QObject* cobject() const { return _object; } 123 isParentedTopLevelBranch()124 bool isParentedTopLevelBranch() const { return _isParentedTopLevelBranch; } setIsParentedTopLevelBranch(bool v)125 void setIsParentedTopLevelBranch(bool v) { _isParentedTopLevelBranch = v; } isWindowBranch()126 bool isWindowBranch() const { return _isWindowBranch; } setIsWindowBranch(bool v)127 void setIsWindowBranch(bool v) { _isWindowBranch = v; } 128 connection()129 const QMetaObject::Connection& connection() const { return _metaConnection; } setConnection(const QMetaObject::Connection & conn)130 void setConnection(const QMetaObject::Connection& conn) { _metaConnection = conn; } 131 132 void startFlash(int interval, const QColor& color, const QEvent::Type& eventType = QEvent::None); isFlashing()133 bool isFlashing() const { return _isFlashing; } 134 // Driven from timer/divider. Returns true if the end was reached. 135 bool tickFlash(); 136 void resetFlash(); 137 }; 138 139 //--------------------------------------------------------- 140 // Snooper Dialog 141 //--------------------------------------------------------- 142 143 class SnooperDialog : public QDialog, public Ui::SnooperDialogBase { 144 145 Q_OBJECT 146 147 // An extra property required to support stylesheets (not enough colours). 148 Q_PROPERTY(QColor flashColor READ flashColor WRITE setFlashColor) 149 150 public: 151 typedef QMap<QEvent::Type /*event_type*/, int /*hit_count*/> HitMap; 152 typedef QMap<QObject* /*object*/, HitMap> HitBuffer; 153 154 protected: 155 void showEvent(QShowEvent*) override; 156 void hideEvent(QHideEvent*) override; 157 void closeEvent(QCloseEvent*) override; 158 bool eventFilter(QObject*, QEvent*) override; 159 160 private: 161 static QMap<int /*value*/, QString /*key*/> _eventTypeMap; 162 // In milliseconds. 163 static const int _updateTimerInterval; 164 QTimer* _updateTimer; 165 int _flashInterval; 166 QColor _flashColor; 167 // In milliseconds. 168 static const int _autoHideTimerInterval; 169 int _autoHideIntervalCounter; 170 171 HitBuffer _eventBuffer; 172 void putEventBuffer(QObject *obj, const QEvent::Type& eventType); 173 // Also returns the first item processed (so it can be scrolled to). 174 SnooperTreeWidgetItem* processEventBuffer(); 175 176 bool _captureMouseClicks; 177 bool _captureKeyPress; 178 179 QSet<SnooperTreeWidgetItem*> _flashingItems; 180 181 // Recursive! 182 // Return true if anything of relevance was added ie. whether the branch should (not) be discarded. 183 // If parentItem is given it adds to that item. Otherwise if null it adds as top level item. 184 bool addBranch(QObject* object, SnooperTreeWidgetItem* parentItem, 185 bool isParentedTopLevelBranch, bool isWindowBranch); 186 // Recursive! 187 bool filterBranch(bool parentIsRelevant, QTreeWidgetItem* parentItem); 188 // Recursive! 189 bool destroyBranch(QObject *obj, QTreeWidgetItem* parentItem, bool deleteBranchPending); 190 // Recursive! Finds a non-hidden item. 191 QTreeWidgetItem* findItem(const QObject *obj, QTreeWidgetItem* parentItem, 192 bool noHidden, bool parentedTopLevels); 193 const QTreeWidgetItem* cfindItem(const QObject *obj, const QTreeWidgetItem* parentItem, 194 bool noHidden, bool parentedTopLevels) const; 195 SnooperTreeWidgetItem* selectObject(const QObject *obj, const QEvent::Type& eventType = QEvent::None); 196 void disconnectAll(); 197 198 private slots: 199 void objectDestroyed(QObject *obj = nullptr); 200 201 void updateTimerTick(); 202 203 void updateTree(); 204 void filterItems(); 205 206 void updateTreeClicked(); 207 void filterToggled(bool); 208 void finishedLineEditing(); 209 void captureMouseClickToggled(bool); 210 void captureKeyPressToggled(bool); 211 void useFlashTimerToggled(bool); 212 void resetFlashTimerClicked(); 213 214 public: 215 SnooperDialog(QWidget* parent=0); 216 virtual ~SnooperDialog(); 217 218 static QString eventTypeString(const QEvent::Type& eventType); 219 220 // Finds a non-hidden item. 221 QTreeWidgetItem* findObject(const QObject* obj, bool noHidden, bool parentedTopLevels); 222 const QTreeWidgetItem* cfindObject(const QObject* obj, bool noHidden, bool parentedTopLevels) const; 223 captureMouseClicks()224 bool captureMouseClicks() const { return _captureMouseClicks; } captureKeyPress()225 bool captureKeyPress() const { return _captureKeyPress; } 226 setFlashInterval(int val)227 void setFlashInterval(int val) { _flashInterval = (1000 * val) / _updateTimerInterval; } 228 flashColor()229 QColor flashColor() const { return _flashColor; } setFlashColor(const QColor & c)230 void setFlashColor(const QColor& c) { _flashColor = c; } 231 }; 232 233 234 } // namespace MusEGui 235 236 #endif // __SNOOPER_H__ 237 238