1 /*=========================================================================
2 
3   Library:   CTK
4 
5   Copyright (c) Kitware Inc.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11       http://www.apache.org/licenses/LICENSE-2.0.txt
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 =========================================================================*/
20 
21 // Qt includes
22 #include <QDebug>
23 #include <QAbstractItemModel>
24 #include <QStandardItemModel>
25 
26 // CTK includes
27 #include "ctkErrorLogWidget.h"
28 #include "ui_ctkErrorLogWidget.h"
29 #include <ctkErrorLogModel.h>
30 
31 class ctkErrorLogWidgetPrivate : public Ui_ctkErrorLogWidget
32 {
33   Q_DECLARE_PUBLIC(ctkErrorLogWidget);
34 protected:
35   ctkErrorLogWidget* const q_ptr;
36 public:
37   typedef ctkErrorLogWidgetPrivate Self;
38   ctkErrorLogWidgetPrivate(ctkErrorLogWidget& object);
39 
40   ctkErrorLogLevel::LogLevels ErrorButtonFilter;
41   ctkErrorLogLevel::LogLevels WarningButtonFilter;
42   ctkErrorLogLevel::LogLevels InfoButtonFilter;
43 
44   void init();
45 
46   QSharedPointer<QItemSelectionModel> SelectionModel;
47 };
48 
49 // --------------------------------------------------------------------------
50 // ctkErrorLogWidgetPrivate methods
51 
52 // --------------------------------------------------------------------------
ctkErrorLogWidgetPrivate(ctkErrorLogWidget & object)53 ctkErrorLogWidgetPrivate::ctkErrorLogWidgetPrivate(ctkErrorLogWidget& object)
54   : q_ptr(&object)
55 {
56   this->ErrorButtonFilter = ctkErrorLogLevel::Error | ctkErrorLogLevel::Critical | ctkErrorLogLevel::Fatal;
57   this->WarningButtonFilter = ctkErrorLogLevel::Warning;
58   this->InfoButtonFilter = ctkErrorLogLevel::Info | ctkErrorLogLevel::Debug | ctkErrorLogLevel::Trace | ctkErrorLogLevel::Status;
59 }
60 
61 // --------------------------------------------------------------------------
init()62 void ctkErrorLogWidgetPrivate::init()
63 {
64   Q_Q(ctkErrorLogWidget);
65 
66   // this->ShowAllEntryButton->setIcon();
67   this->ShowErrorEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxCritical));
68   this->ShowWarningEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxWarning));
69   this->ShowInfoEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxInformation));
70   this->ClearButton->setIcon(q->style()->standardIcon(QStyle::SP_DialogDiscardButton));
71 
72   QObject::connect(this->ShowAllEntryButton, SIGNAL(clicked()),
73                    q, SLOT(setAllEntriesVisible()));
74 
75   QObject::connect(this->ShowErrorEntryButton, SIGNAL(clicked(bool)),
76                    q, SLOT(setErrorEntriesVisible(bool)));
77 
78   QObject::connect(this->ShowWarningEntryButton, SIGNAL(clicked(bool)),
79                    q, SLOT(setWarningEntriesVisible(bool)));
80 
81   QObject::connect(this->ShowInfoEntryButton, SIGNAL(clicked(bool)),
82                    q, SLOT(setInfoEntriesVisible(bool)));
83 
84   QObject::connect(this->ClearButton, SIGNAL(clicked()),
85                    q, SLOT(removeEntries()));
86 }
87 
88 // --------------------------------------------------------------------------
89 // ctkErrorLogWidget methods
90 
91 //------------------------------------------------------------------------------
ctkErrorLogWidget(QWidget * newParent)92 ctkErrorLogWidget::ctkErrorLogWidget(QWidget * newParent)
93   : Superclass(newParent)
94   , d_ptr(new ctkErrorLogWidgetPrivate(*this))
95 {
96   Q_D(ctkErrorLogWidget);
97 
98   d->setupUi(this);
99   d->init();
100 
101   this->setErrorLogModel(new ctkErrorLogModel(d->ErrorLogTableView));
102 }
103 
104 //------------------------------------------------------------------------------
~ctkErrorLogWidget()105 ctkErrorLogWidget::~ctkErrorLogWidget()
106 {
107 }
108 
109 //------------------------------------------------------------------------------
errorLogModel() const110 ctkErrorLogModel* ctkErrorLogWidget::errorLogModel()const
111 {
112   Q_D(const ctkErrorLogWidget);
113   QAbstractItemModel* model = d->ErrorLogTableView->model();
114   ctkErrorLogModel * errorLogModel = qobject_cast<ctkErrorLogModel*>(model);
115   Q_ASSERT(model ? errorLogModel != 0 : true);
116   return errorLogModel;
117 }
118 
119 //------------------------------------------------------------------------------
setErrorLogModel(ctkErrorLogModel * newErrorLogModel)120 void ctkErrorLogWidget::setErrorLogModel(ctkErrorLogModel * newErrorLogModel)
121 {
122   Q_D(ctkErrorLogWidget);
123 
124   if (newErrorLogModel == this->errorLogModel())
125     {
126     return;
127     }
128 
129   if (this->errorLogModel())
130     {
131     disconnect(this->errorLogModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
132                this, SLOT(onRowsInserted(QModelIndex,int,int)));
133 
134     disconnect(this->errorLogModel(), SIGNAL(logLevelFilterChanged()),
135                this, SLOT(onLogLevelFilterChanged()));
136 
137     disconnect(d->SelectionModel.data(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
138                this, SLOT(onSelectionChanged(QItemSelection,QItemSelection)));
139 
140     d->SelectionModel.clear();
141     }
142 
143   d->ErrorLogTableView->setModel(newErrorLogModel);
144 
145   if (newErrorLogModel)
146     {
147     connect(this->errorLogModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
148             this, SLOT(onRowsInserted(QModelIndex,int,int)));
149 
150     connect(this->errorLogModel(), SIGNAL(logLevelFilterChanged()),
151             this, SLOT(onLogLevelFilterChanged()));
152 
153     ctkErrorLogLevel::LogLevels logLevelFilter = newErrorLogModel->logLevelFilter();
154     this->setErrorEntriesVisible(logLevelFilter & d->ErrorButtonFilter);
155     this->setWarningEntriesVisible(logLevelFilter & d->WarningButtonFilter);
156     this->setInfoEntriesVisible(logLevelFilter & d->InfoButtonFilter);
157     this->errorLogModel()->filterEntry(logLevelFilter & ctkErrorLogLevel::Unknown);
158 
159     // Setup selection model
160     d->SelectionModel = QSharedPointer<QItemSelectionModel>(new QItemSelectionModel(this->errorLogModel()));
161     d->SelectionModel->reset();
162 
163     connect(d->SelectionModel.data(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
164             this, SLOT(onSelectionChanged(QItemSelection,QItemSelection)));
165 
166     d->ErrorLogTableView->setSelectionModel(d->SelectionModel.data());
167 
168     // Resize time column only if there are rows
169     if (this->errorLogModel()->rowCount() > 0)
170       {
171       d->ErrorLogTableView->resizeColumnToContents(ctkErrorLogModel::TimeColumn);
172       }
173     }
174   else
175     {
176     this->setAllEntriesVisible(0);
177     }
178 
179   d->ErrorLogTableView->setColumnHidden(ctkErrorLogModel::ThreadIdColumn, true);
180 }
181 
182 // --------------------------------------------------------------------------
setColumnHidden(int columnId,bool hidden) const183 void ctkErrorLogWidget::setColumnHidden(int columnId, bool hidden) const
184 {
185   Q_D(const ctkErrorLogWidget);
186   d->ErrorLogTableView->setColumnHidden(columnId, hidden);
187 }
188 
189 // --------------------------------------------------------------------------
setAllEntriesVisible(bool visibility)190 void ctkErrorLogWidget::setAllEntriesVisible(bool visibility)
191 {
192   this->setErrorEntriesVisible(visibility);
193   this->setWarningEntriesVisible(visibility);
194   this->setInfoEntriesVisible(visibility);
195   this->setUnknownEntriesVisible(visibility);
196 }
197 
198 // --------------------------------------------------------------------------
setErrorEntriesVisible(bool visibility)199 void ctkErrorLogWidget::setErrorEntriesVisible(bool visibility)
200 {
201   Q_D(ctkErrorLogWidget);
202   if (!this->errorLogModel())
203     {
204     return;
205     }
206   this->errorLogModel()->filterEntry(d->ErrorButtonFilter, /* disableFilter= */ !visibility);
207 }
208 
209 // --------------------------------------------------------------------------
setWarningEntriesVisible(bool visibility)210 void ctkErrorLogWidget::setWarningEntriesVisible(bool visibility)
211 {
212   Q_D(ctkErrorLogWidget);
213   if (!this->errorLogModel())
214     {
215     return;
216     }
217   this->errorLogModel()->filterEntry(d->WarningButtonFilter, /* disableFilter= */ !visibility);
218 }
219 
220 // --------------------------------------------------------------------------
setInfoEntriesVisible(bool visibility)221 void ctkErrorLogWidget::setInfoEntriesVisible(bool visibility)
222 {
223   Q_D(ctkErrorLogWidget);
224   if (!this->errorLogModel())
225     {
226     return;
227     }
228   this->errorLogModel()->filterEntry(d->InfoButtonFilter, /* disableFilter= */ !visibility);
229 }
230 
231 // --------------------------------------------------------------------------
setUnknownEntriesVisible(bool visibility)232 void ctkErrorLogWidget::setUnknownEntriesVisible(bool visibility)
233 {
234   if (!this->errorLogModel())
235     {
236     return;
237     }
238   this->errorLogModel()->filterEntry(ctkErrorLogLevel::Unknown,
239       /* disableFilter= */ !visibility);
240 }
241 
242 // --------------------------------------------------------------------------
onRowsInserted(const QModelIndex &,int,int)243 void ctkErrorLogWidget::onRowsInserted(const QModelIndex &/*parent*/, int /*first*/, int /*last*/)
244 {
245   Q_D(ctkErrorLogWidget);
246   if (d->ErrorLogTableView->model()->rowCount() == 1)
247     {
248     // For performance reason, resize first column only when first entry is added
249     d->ErrorLogTableView->resizeColumnToContents(ctkErrorLogModel::TimeColumn);
250     }
251 }
252 
253 // --------------------------------------------------------------------------
onLogLevelFilterChanged()254 void ctkErrorLogWidget::onLogLevelFilterChanged()
255 {
256   Q_D(ctkErrorLogWidget);
257   Q_ASSERT(this->errorLogModel());
258   ctkErrorLogLevel::LogLevels logLevelFilter = this->errorLogModel()->logLevelFilter();
259   d->ShowErrorEntryButton->setChecked(logLevelFilter & d->ErrorButtonFilter);
260   d->ShowWarningEntryButton->setChecked(logLevelFilter & d->WarningButtonFilter);
261   d->ShowInfoEntryButton->setChecked(logLevelFilter & d->InfoButtonFilter);
262 }
263 
264 // --------------------------------------------------------------------------
removeEntries()265 void ctkErrorLogWidget::removeEntries()
266 {
267   Q_ASSERT(this->errorLogModel());
268   this->errorLogModel()->clear();
269 }
270 
271 // --------------------------------------------------------------------------
onSelectionChanged(const QItemSelection & selected,const QItemSelection & deselected)272 void ctkErrorLogWidget::onSelectionChanged(const QItemSelection & selected,
273                                            const QItemSelection & deselected)
274 {
275   // QTime start = QTime::currentTime();
276 
277   Q_D(ctkErrorLogWidget);
278   Q_UNUSED(selected);
279   Q_UNUSED(deselected);
280 
281   QModelIndexList selectedRows =
282       d->SelectionModel->selectedRows(ctkErrorLogModel::DescriptionColumn);
283 
284   qSort(selectedRows.begin(), selectedRows.end());
285 
286   QStringList descriptions;
287 
288   foreach(const QModelIndex& index, selectedRows)
289     {
290     descriptions << index.data(ctkErrorLogModel::DescriptionTextRole).toString();
291     }
292 
293   d->ErrorLogDescription->setText(descriptions.join("\n"));
294 
295   // fprintf(stdout, "onSelectionChanged: %d\n", start.msecsTo(QTime::currentTime()));
296 }
297