1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkQtDebugLeaksView.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkQtDebugLeaksView.h"
16 #include "vtkObjectBase.h"
17 #include "vtkQtDebugLeaksModel.h"
18 
19 #include <QCheckBox>
20 #include <QDesktopServices>
21 #include <QHBoxLayout>
22 #include <QHeaderView>
23 #include <QItemSelectionModel>
24 #include <QLineEdit>
25 #include <QPushButton>
26 #include <QSortFilterProxyModel>
27 #include <QSplitter>
28 #include <QTableView>
29 #include <QUrl>
30 #include <QVBoxLayout>
31 
32 //------------------------------------------------------------------------------
33 class vtkQtDebugLeaksView::qInternal
34 {
35 public:
36   vtkQtDebugLeaksModel* Model;
37   QSortFilterProxyModel* ProxyModel;
38   QTableView* TableView;
39   QTableView* ReferenceTableView;
40   QCheckBox* FilterCheckBox;
41   QLineEdit* FilterLineEdit;
42 };
43 
44 //------------------------------------------------------------------------------
vtkQtDebugLeaksView(QWidget * p)45 vtkQtDebugLeaksView::vtkQtDebugLeaksView(QWidget* p)
46   : QWidget(p)
47 {
48   this->Internal = new qInternal;
49 
50   this->Internal->Model = new vtkQtDebugLeaksModel(this);
51   this->Internal->ProxyModel = new QSortFilterProxyModel(this->Internal->Model);
52   this->Internal->ProxyModel->setSourceModel(this->Internal->Model);
53   this->Internal->ProxyModel->setDynamicSortFilter(true);
54   this->Internal->ProxyModel->setFilterKeyColumn(0);
55 
56   this->Internal->TableView = new QTableView;
57   this->Internal->TableView->setSortingEnabled(true);
58   this->Internal->TableView->setModel(this->Internal->ProxyModel);
59   this->Internal->TableView->setObjectName("ClassTable");
60   this->Internal->ReferenceTableView = new QTableView;
61   this->Internal->ReferenceTableView->setObjectName("ReferenceTable");
62 
63   this->Internal->FilterCheckBox = new QCheckBox("Filter RegExp");
64   this->Internal->FilterCheckBox->setChecked(true);
65   this->Internal->FilterLineEdit = new QLineEdit();
66 
67   QVBoxLayout* mainLayout = new QVBoxLayout(this);
68   QSplitter* splitter = new QSplitter();
69   QPushButton* filterHelpButton = new QPushButton("RegExp Help");
70   QHBoxLayout* filterLayout = new QHBoxLayout();
71 
72   filterLayout->addWidget(this->Internal->FilterCheckBox);
73   filterLayout->addWidget(this->Internal->FilterLineEdit);
74   filterLayout->addWidget(filterHelpButton);
75   mainLayout->addLayout(filterLayout);
76   mainLayout->addWidget(splitter);
77 
78   splitter->setOrientation(Qt::Vertical);
79   splitter->addWidget(this->Internal->TableView);
80   splitter->addWidget(this->Internal->ReferenceTableView);
81   QList<int> sizes;
82   sizes << 1 << 0;
83   splitter->setSizes(sizes);
84 
85   this->connect(this->Internal->FilterLineEdit, SIGNAL(textChanged(const QString&)),
86     SLOT(onFilterTextChanged(const QString&)));
87 
88   this->connect(this->Internal->FilterCheckBox, SIGNAL(stateChanged(int)), SLOT(onFilterToggled()));
89 
90   this->connect(filterHelpButton, SIGNAL(clicked()), SLOT(onFilterHelp()));
91 
92   vtkQtDebugLeaksView::connect(this->Internal->TableView->selectionModel(),
93     SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this,
94     SLOT(onCurrentRowChanged(const QModelIndex&)));
95 
96   vtkQtDebugLeaksView::connect(this->Internal->TableView, SIGNAL(doubleClicked(const QModelIndex&)),
97     this, SLOT(onRowDoubleClicked(const QModelIndex&)));
98 
99   vtkQtDebugLeaksView::connect(this->Internal->ReferenceTableView,
100     SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(onRowDoubleClicked(const QModelIndex&)));
101 
102   this->resize(400, 600);
103   this->setWindowTitle("VTK Debug Leaks View");
104   this->Internal->TableView->setColumnWidth(0, 200);
105   this->Internal->TableView->horizontalHeader()->setStretchLastSection(true);
106   this->Internal->TableView->verticalHeader()->setVisible(false);
107   this->Internal->TableView->setSelectionMode(QAbstractItemView::SingleSelection);
108   this->Internal->TableView->setSelectionBehavior(QAbstractItemView::SelectRows);
109 
110   this->Internal->ReferenceTableView->setSelectionMode(QAbstractItemView::SingleSelection);
111   this->Internal->ReferenceTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
112 
113   this->setAttribute(Qt::WA_QuitOnClose, false);
114 }
115 
116 //------------------------------------------------------------------------------
~vtkQtDebugLeaksView()117 vtkQtDebugLeaksView::~vtkQtDebugLeaksView()
118 {
119   this->Internal->ReferenceTableView->setModel(nullptr);
120   this->Internal->TableView->setModel(nullptr);
121   delete this->Internal->Model;
122   delete this->Internal;
123 }
124 
125 //------------------------------------------------------------------------------
model()126 vtkQtDebugLeaksModel* vtkQtDebugLeaksView::model()
127 {
128   return this->Internal->Model;
129 }
130 
131 //------------------------------------------------------------------------------
onFilterHelp()132 void vtkQtDebugLeaksView::onFilterHelp()
133 {
134   QDesktopServices::openUrl(QUrl("http://doc.trolltech.com/4.6/qregexp.html#introduction"));
135 }
136 
137 //------------------------------------------------------------------------------
onCurrentRowChanged(const QModelIndex & current)138 void vtkQtDebugLeaksView::onCurrentRowChanged(const QModelIndex& current)
139 {
140   QStandardItemModel* newModel = nullptr;
141   QAbstractItemModel* previousModel = this->Internal->ReferenceTableView->model();
142 
143   QModelIndex index = this->Internal->ProxyModel->mapToSource(current);
144   if (index.isValid())
145   {
146     QModelIndex classNameIndex = this->Internal->Model->index(index.row(), 0);
147     QString className = this->Internal->Model->data(classNameIndex).toString();
148     newModel = this->Internal->Model->referenceCountModel(className);
149   }
150 
151   if (newModel != previousModel)
152   {
153     this->Internal->ReferenceTableView->setModel(newModel);
154     this->Internal->ReferenceTableView->resizeColumnsToContents();
155     this->Internal->ReferenceTableView->horizontalHeader()->setStretchLastSection(true);
156     delete previousModel;
157   }
158 }
159 
160 //------------------------------------------------------------------------------
onFilterTextChanged(const QString & text)161 void vtkQtDebugLeaksView::onFilterTextChanged(const QString& text)
162 {
163   if (this->filterEnabled())
164   {
165 #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
166     this->Internal->ProxyModel->setFilterRegularExpression(text);
167 #else
168     this->Internal->ProxyModel->setFilterRegExp(text);
169 #endif
170   }
171 }
172 
173 //------------------------------------------------------------------------------
onFilterToggled()174 void vtkQtDebugLeaksView::onFilterToggled()
175 {
176   QString text = this->filterText();
177   if (!this->filterEnabled())
178   {
179     text = "";
180   }
181 
182 #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
183   this->Internal->ProxyModel->setFilterRegularExpression(text);
184 #else
185   this->Internal->ProxyModel->setFilterRegExp(text);
186 #endif
187 }
188 
189 //------------------------------------------------------------------------------
filterEnabled() const190 bool vtkQtDebugLeaksView::filterEnabled() const
191 {
192   return this->Internal->FilterCheckBox->isChecked();
193 }
194 
195 //------------------------------------------------------------------------------
setFilterEnabled(bool value)196 void vtkQtDebugLeaksView::setFilterEnabled(bool value)
197 {
198   this->Internal->FilterCheckBox->setChecked(value);
199 }
200 
201 //------------------------------------------------------------------------------
filterText() const202 QString vtkQtDebugLeaksView::filterText() const
203 {
204   return this->Internal->FilterLineEdit->text();
205 }
206 
207 //------------------------------------------------------------------------------
setFilterText(const QString & text)208 void vtkQtDebugLeaksView::setFilterText(const QString& text)
209 {
210   this->Internal->FilterLineEdit->setText(text);
211 }
212 
213 //------------------------------------------------------------------------------
214 Q_DECLARE_METATYPE(vtkObjectBase*);
215 
216 //------------------------------------------------------------------------------
onRowDoubleClicked(const QModelIndex & index)217 void vtkQtDebugLeaksView::onRowDoubleClicked(const QModelIndex& index)
218 {
219   if (index.model() == this->Internal->ReferenceTableView->model())
220   {
221     QModelIndex objectIndex = this->Internal->ReferenceTableView->model()->index(index.row(), 0);
222     QVariant objectVariant =
223       this->Internal->ReferenceTableView->model()->data(objectIndex, Qt::UserRole);
224     vtkObjectBase* object = objectVariant.value<vtkObjectBase*>();
225     this->onObjectDoubleClicked(object);
226   }
227   else
228   {
229     QModelIndex sourceIndex = this->Internal->ProxyModel->mapToSource(index);
230     if (sourceIndex.isValid())
231     {
232       QString className =
233         this->Internal->Model->data(this->Internal->Model->index(sourceIndex.row(), 0)).toString();
234       this->onClassNameDoubleClicked(className);
235     }
236   }
237 }
238 
239 //------------------------------------------------------------------------------
onObjectDoubleClicked(vtkObjectBase * object)240 void vtkQtDebugLeaksView::onObjectDoubleClicked(vtkObjectBase* object)
241 {
242   Q_UNUSED(object);
243 }
244 
245 //------------------------------------------------------------------------------
onClassNameDoubleClicked(const QString & className)246 void vtkQtDebugLeaksView::onClassNameDoubleClicked(const QString& className)
247 {
248   Q_UNUSED(className);
249 }
250