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