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 "vtkQtDebugLeaksModel.h"
17 #include "vtkObjectBase.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 <QVBoxLayout>
30 #include <QUrl>
31 
32 //-----------------------------------------------------------------------------
33 class vtkQtDebugLeaksView::qInternal
34 {
35 public:
36 
37   vtkQtDebugLeaksModel*    Model;
38   QSortFilterProxyModel*   ProxyModel;
39   QTableView*              TableView;
40   QTableView*              ReferenceTableView;
41   QCheckBox*               FilterCheckBox;
42   QLineEdit*               FilterLineEdit;
43 };
44 
45 //----------------------------------------------------------------------------
vtkQtDebugLeaksView(QWidget * p)46 vtkQtDebugLeaksView::vtkQtDebugLeaksView(QWidget *p) : 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)),
89                 SLOT(onFilterToggled()));
90 
91   this->connect(filterHelpButton, SIGNAL(clicked()), SLOT(onFilterHelp()));
92 
93   this->connect(this->Internal->TableView->selectionModel(),
94                 SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)),
95                 this, SLOT(onCurrentRowChanged(const QModelIndex&)));
96 
97   this->connect(this->Internal->TableView,
98                 SIGNAL(doubleClicked(const QModelIndex&)),
99                 this, SLOT(onRowDoubleClicked(const QModelIndex&)));
100 
101   this->connect(this->Internal->ReferenceTableView,
102                 SIGNAL(doubleClicked(const QModelIndex&)),
103                 this, SLOT(onRowDoubleClicked(const QModelIndex&)));
104 
105   this->resize(400, 600);
106   this->setWindowTitle("VTK Debug Leaks View");
107   this->Internal->TableView->setColumnWidth(0, 200);
108   this->Internal->TableView->horizontalHeader()->setStretchLastSection(true);
109   this->Internal->TableView->verticalHeader()->setVisible(false);
110   this->Internal->TableView->setSelectionMode(QAbstractItemView::SingleSelection);
111   this->Internal->TableView->setSelectionBehavior(QAbstractItemView::SelectRows);
112 
113   this->Internal->ReferenceTableView->setSelectionMode(QAbstractItemView::SingleSelection);
114   this->Internal->ReferenceTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
115 
116   this->setAttribute(Qt::WA_QuitOnClose, false);
117 }
118 
119 //-----------------------------------------------------------------------------
~vtkQtDebugLeaksView()120 vtkQtDebugLeaksView::~vtkQtDebugLeaksView()
121 {
122   this->Internal->ReferenceTableView->setModel(0);
123   this->Internal->TableView->setModel(0);
124   delete this->Internal->Model;
125   delete this->Internal;
126 }
127 
128 //-----------------------------------------------------------------------------
model()129 vtkQtDebugLeaksModel* vtkQtDebugLeaksView::model()
130 {
131   return this->Internal->Model;
132 }
133 
134 //-----------------------------------------------------------------------------
onFilterHelp()135 void vtkQtDebugLeaksView::onFilterHelp()
136 {
137   QDesktopServices::openUrl(QUrl("http://doc.trolltech.com/4.6/qregexp.html#introduction"));
138 }
139 
140 //-----------------------------------------------------------------------------
onCurrentRowChanged(const QModelIndex & current)141 void vtkQtDebugLeaksView::onCurrentRowChanged(const QModelIndex& current)
142 {
143   QStandardItemModel* newModel = 0;
144   QAbstractItemModel* previousModel = this->Internal->ReferenceTableView->model();
145 
146   QModelIndex index = this->Internal->ProxyModel->mapToSource(current);
147   if (index.isValid())
148     {
149     QModelIndex classNameIndex = this->Internal->Model->index(index.row(), 0);
150     QString className = this->Internal->Model->data(classNameIndex).toString();
151     newModel = this->Internal->Model->referenceCountModel(className);
152     }
153 
154   if (newModel != previousModel)
155     {
156     this->Internal->ReferenceTableView->setModel(newModel);
157     this->Internal->ReferenceTableView->resizeColumnsToContents();
158     this->Internal->ReferenceTableView->horizontalHeader()->setStretchLastSection(true);
159     delete previousModel;
160     }
161 }
162 
163 //-----------------------------------------------------------------------------
onFilterTextChanged(const QString & text)164 void vtkQtDebugLeaksView::onFilterTextChanged(const QString& text)
165 {
166   if (this->filterEnabled())
167     {
168     this->Internal->ProxyModel->setFilterRegExp(text);
169     }
170 }
171 
172 //-----------------------------------------------------------------------------
onFilterToggled()173 void vtkQtDebugLeaksView::onFilterToggled()
174 {
175   QString text = this->filterText();
176   if (!this->filterEnabled())
177     {
178     text = "";
179     }
180 
181   this->Internal->ProxyModel->setFilterRegExp(text);
182 }
183 
184 //-----------------------------------------------------------------------------
filterEnabled() const185 bool vtkQtDebugLeaksView::filterEnabled() const
186 {
187   return this->Internal->FilterCheckBox->isChecked();
188 }
189 
190 //-----------------------------------------------------------------------------
setFilterEnabled(bool value)191 void vtkQtDebugLeaksView::setFilterEnabled(bool value)
192 {
193   this->Internal->FilterCheckBox->setChecked(value);
194 }
195 
196 //-----------------------------------------------------------------------------
filterText() const197 QString vtkQtDebugLeaksView::filterText() const
198 {
199   return this->Internal->FilterLineEdit->text();
200 }
201 
202 //-----------------------------------------------------------------------------
setFilterText(const QString & text)203 void vtkQtDebugLeaksView::setFilterText(const QString& text)
204 {
205   this->Internal->FilterLineEdit->setText(text);
206 }
207 
208 //-----------------------------------------------------------------------------
209 Q_DECLARE_METATYPE(vtkObjectBase*);
210 
211 //-----------------------------------------------------------------------------
onRowDoubleClicked(const QModelIndex & index)212 void vtkQtDebugLeaksView::onRowDoubleClicked(const QModelIndex& index)
213 {
214   if (index.model() == this->Internal->ReferenceTableView->model())
215     {
216     QModelIndex objectIndex = this->Internal->ReferenceTableView->model()->index(index.row(), 0);
217     QVariant objectVariant = this->Internal->ReferenceTableView->model()->data(objectIndex, Qt::UserRole);
218     vtkObjectBase* object = objectVariant.value<vtkObjectBase*>();
219     this->onObjectDoubleClicked(object);
220     }
221   else
222     {
223     QModelIndex sourceIndex = this->Internal->ProxyModel->mapToSource(index);
224     if (sourceIndex.isValid())
225       {
226       QString className = this->Internal->Model->data(
227         this->Internal->Model->index(sourceIndex.row(), 0)).toString();
228       this->onClassNameDoubleClicked(className);
229       }
230     }
231 }
232 
233 //-----------------------------------------------------------------------------
onObjectDoubleClicked(vtkObjectBase * object)234 void vtkQtDebugLeaksView::onObjectDoubleClicked(vtkObjectBase* object)
235 {
236   Q_UNUSED(object);
237 }
238 
239 //-----------------------------------------------------------------------------
onClassNameDoubleClicked(const QString & className)240 void vtkQtDebugLeaksView::onClassNameDoubleClicked(const QString& className)
241 {
242   Q_UNUSED(className);
243 }
244