1 /*
2     SPDX-FileCopyrightText: 2011 Andi Fischer <andi.fischer@hispeed.ch>
3     SPDX-FileCopyrightText: 2012 Ralf Habacker <ralf.habacker@freenet.de>
4 
5     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7 
8 #include "debug_utils.h"
9 
10 #include <KLocalizedString>
11 
12 #include <QFileInfo>
13 
14 #if QT_VERSION >= 0x050000
15 Q_LOGGING_CATEGORY(UMBRELLO, "umbrello")
16 #endif
17 
18 Tracer* Tracer::m_instance = nullptr;
19 Tracer::MapType *Tracer::m_classes = nullptr;
20 Tracer::StateMap *Tracer::m_states = nullptr;
21 
instance()22 Tracer* Tracer::instance()
23 {
24     if (m_instance == nullptr) {
25         m_instance = new Tracer();
26     }
27     return m_instance;
28 }
29 
30 /**
31  * Constructor.
32  * @param parent   the parent widget
33  */
Tracer(QWidget * parent)34 Tracer::Tracer(QWidget *parent)
35   : QTreeWidget(parent)
36 {
37     // in case no one called registerClass() before
38     if (!m_classes)
39         m_classes = new Tracer::MapType;
40     if (!m_states)
41         m_states = new Tracer::StateMap;
42     setRootIsDecorated(true);
43     setAlternatingRowColors(true);
44     setHeaderLabel(i18n("Class Name"));
45     setContextMenuPolicy(Qt::CustomContextMenu);
46     connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotItemClicked(QTreeWidgetItem*,int)));
47 }
48 
49 /**
50  * Destructor.
51  */
~Tracer()52 Tracer::~Tracer()
53 {
54     clear();
55     delete m_classes;
56     m_classes = nullptr;
57     delete m_states;
58     m_states = nullptr;
59 }
60 
61 /**
62  * Return debugging state for a given class
63  * @param name   the class name to check
64  */
isEnabled(const QString & name) const65 bool Tracer::isEnabled(const QString& name) const
66 {
67     return (*m_classes)[name].state;
68 }
69 
70 /**
71  * Enable debug output for the given class.
72  * @param name   class name
73  */
enable(const QString & name)74 void Tracer::enable(const QString& name)
75 {
76     (*m_classes)[name].state = true;
77     update(name);
78 }
79 
80 /**
81  * Disable debug output for the given class.
82  * @param name   class name
83  */
disable(const QString & name)84 void Tracer::disable(const QString& name)
85 {
86     (*m_classes)[name].state = false;
87     update(name);
88 }
89 
enableAll()90 void Tracer::enableAll()
91 {
92     //:TODO:
93 }
94 
disableAll()95 void Tracer::disableAll()
96 {
97     //:TODO:
98 }
99 
100 /**
101  * Register class for debug output
102  * @param name   class name
103  * @param state  initial enabled state
104  */
registerClass(const QString & name,bool state,const QString & filePath)105 void Tracer::registerClass(const QString& name, bool state, const QString &filePath)
106 {
107     if (!m_classes)
108         m_classes = new MapType;
109     QFileInfo fi(filePath);
110     QString dirName = fi.absolutePath();
111     QFileInfo f(dirName);
112     QString path = f.fileName();
113     (*m_classes)[name] = MapEntry(path, state);
114 }
115 
116 /**
117  * Transfer class state into tree widget.
118  * @param name   class name
119  */
update(const QString & name)120 void Tracer::update(const QString &name)
121 {
122     if (!isVisible())
123         return;
124     QList<QTreeWidgetItem*> items = findItems(name, Qt::MatchFixedString);
125     foreach(QTreeWidgetItem* item, items) {
126         item->setCheckState(0, (*m_classes)[name].state ? Qt::Checked : Qt::Unchecked);
127     }
128 }
129 
130 /**
131  * Update check box of parent items.
132  *
133  * @param parent parent widget item
134  */
updateParentItemCheckBox(QTreeWidgetItem * parent)135 void Tracer::updateParentItemCheckBox(QTreeWidgetItem* parent)
136 {
137     int selectedCount = 0;
138     for(int i = 0; i < parent->childCount(); i++) {
139         if (parent->child(i)->checkState(0) == Qt::Checked)
140             selectedCount++;
141     }
142     if (selectedCount == parent->childCount())
143         parent->setCheckState(0, Qt::Checked);
144     else if (selectedCount == 0)
145         parent->setCheckState(0, Qt::Unchecked);
146     else
147         parent->setCheckState(0, Qt::PartiallyChecked);
148 
149     (*m_states)[parent->text(0)] = parent->checkState(0);
150 }
151 
152 /**
153  * Fill tree widget with collected classes.
154  */
showEvent(QShowEvent * e)155 void Tracer::showEvent(QShowEvent* e)
156 {
157     Q_UNUSED(e);
158 
159     clear();
160     MapType::const_iterator i = m_classes->constBegin();
161     for(; i != m_classes->constEnd(); i++) {
162         QList<QTreeWidgetItem*> items = findItems(i.value().filePath, Qt::MatchFixedString);
163         QTreeWidgetItem* topLevel = nullptr;
164         if (items.size() == 0) {
165             topLevel = new QTreeWidgetItem(QStringList(i.value().filePath));
166             topLevel->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
167             updateParentItemCheckBox(topLevel);
168             addTopLevelItem(topLevel);
169         }
170         else
171             topLevel = items.first();
172 
173         QTreeWidgetItem* item = new QTreeWidgetItem(topLevel, QStringList(i.key()));
174         item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
175         item->setCheckState(0, i.value().state ? Qt::Checked : Qt::Unchecked);
176     }
177 
178     for(int i = 0; i < topLevelItemCount(); i++)
179         updateParentItemCheckBox(topLevelItem(i));
180 }
181 
182 /**
183  */
slotParentItemClicked(QTreeWidgetItem * parent)184 void Tracer::slotParentItemClicked(QTreeWidgetItem* parent)
185 {
186     // @TODO parent->checkState(0) do not return the correct state
187     // Qt::CheckState state = parent->checkState(0);
188     Qt::CheckState state = (*m_states)[parent->text(0)];
189     if (state == Qt::PartiallyChecked || state == Qt::Unchecked) {
190         for(int i = 0; i < parent->childCount(); i++) {
191             QString text = parent->child(i)->text(0);
192             (*m_classes)[text].state = true;
193             parent->child(i)->setCheckState(0, (*m_classes)[text].state ? Qt::Checked : Qt::Unchecked);
194         }
195     } else if (state == Qt::Checked) {
196         for(int i = 0; i < parent->childCount(); i++) {
197             QString text = parent->child(i)->text(0);
198             (*m_classes)[text].state = false;
199             parent->child(i)->setCheckState(0, (*m_classes)[text].state ? Qt::Checked : Qt::Unchecked);
200         }
201     }
202     updateParentItemCheckBox(parent);
203 }
204 
205 /**
206  * handle tree widget item selection signal
207  * @param item tree widget item
208  * @param column selected column
209  */
slotItemClicked(QTreeWidgetItem * item,int column)210 void Tracer::slotItemClicked(QTreeWidgetItem* item, int column)
211 {
212     Q_UNUSED(column);
213 
214     if (item->parent()) {
215         (*m_classes)[item->text(0)].state = !(*m_classes)[item->text(0)].state;
216         item->setCheckState(0, (*m_classes)[item->text(0)].state ? Qt::Checked : Qt::Unchecked);
217         updateParentItemCheckBox(item->parent());
218         return;
219     }
220     slotParentItemClicked(item);
221 }
222