瀏覽代碼

Add ctkErrorLogWidget

This widget associated with ctkErrorLogModel allows to display the corresponding
log entries.

Il also provides a way to filter the entries depending on their log level
Jean-Christophe Fillion-Robin 14 年之前
父節點
當前提交
9ff50020a6

+ 4 - 0
Libs/Widgets/CMakeLists.txt

@@ -48,6 +48,8 @@ SET(KIT_SRCS
   ctkDoubleSlider.h
   ctkDynamicSpacer.cpp
   ctkDynamicSpacer.h
+  ctkErrorLogWidget.cpp
+  ctkErrorLogWidget.h
   ctkFileDialog.cpp
   ctkFileDialog.h
   ctkFittedTextBrowser.cpp
@@ -164,6 +166,7 @@ SET(KIT_MOC_SRCS
   ctkDoubleRangeSlider.h
   ctkDoubleSlider.h
   ctkDynamicSpacer.h
+  ctkErrorLogWidget.h
   ctkFileDialog.h
   ctkFittedTextBrowser.h
   ctkFlowLayout.h
@@ -218,6 +221,7 @@ SET(KIT_UI_FORMS
   Resources/UI/ctkAddRemoveComboBox.ui
   Resources/UI/ctkRangeWidget.ui
   Resources/UI/ctkDateRangeWidget.ui
+  Resources/UI/ctkErrorLogWidget.ui
   Resources/UI/ctkMaterialPropertyWidget.ui
   Resources/UI/ctkModalityWidget.ui
   Resources/UI/ctkScreenshotDialog.ui

+ 104 - 0
Libs/Widgets/Resources/UI/ctkErrorLogWidget.ui

@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkErrorLogWidget</class>
+ <widget class="QWidget" name="ctkErrorLogWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>754</width>
+    <height>429</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="ShowAllEntryButton">
+       <property name="text">
+        <string>&amp;All</string>
+       </property>
+       <property name="checked">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="ShowErrorEntryButton">
+       <property name="text">
+        <string>&amp;Errors</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="ShowWarningEntryButton">
+       <property name="text">
+        <string>&amp;Warnings</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="ShowInfoEntryButton">
+       <property name="text">
+        <string>&amp;Messages</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="ClearButton">
+       <property name="text">
+        <string>&amp;Clear</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QTableView" name="ErrorLogTableView">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionBehavior">
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <property name="cornerButtonEnabled">
+      <bool>false</bool>
+     </property>
+     <attribute name="horizontalHeaderVisible">
+      <bool>false</bool>
+     </attribute>
+     <attribute name="horizontalHeaderStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <attribute name="verticalHeaderVisible">
+      <bool>false</bool>
+     </attribute>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTextBrowser" name="ErrorLogDescription"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 276 - 0
Libs/Widgets/ctkErrorLogWidget.cpp

@@ -0,0 +1,276 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QDebug>
+#include <QAbstractItemModel>
+#include <QStandardItemModel>
+
+// CTK includes
+#include "ctkErrorLogWidget.h"
+#include "ui_ctkErrorLogWidget.h"
+#include <ctkErrorLogModel.h>
+
+class ctkErrorLogWidgetPrivate : public Ui_ctkErrorLogWidget
+{
+  Q_DECLARE_PUBLIC(ctkErrorLogWidget);
+protected:
+  ctkErrorLogWidget* const q_ptr;
+public:
+  typedef ctkErrorLogWidgetPrivate Self;
+  ctkErrorLogWidgetPrivate(ctkErrorLogWidget& object);
+
+  ctkErrorLogModel::LogLevels ErrorButtonFilter;
+  ctkErrorLogModel::LogLevels WarningButtonFilter;
+  ctkErrorLogModel::LogLevels InfoButtonFilter;
+
+  void init();
+
+  QSharedPointer<QItemSelectionModel> SelectionModel;
+};
+
+// --------------------------------------------------------------------------
+// ctkErrorLogWidgetPrivate methods
+
+// --------------------------------------------------------------------------
+ctkErrorLogWidgetPrivate::ctkErrorLogWidgetPrivate(ctkErrorLogWidget& object)
+  : q_ptr(&object)
+{
+  this->ErrorButtonFilter = ctkErrorLogModel::Error | ctkErrorLogModel::Critical | ctkErrorLogModel::Fatal;
+  this->WarningButtonFilter = ctkErrorLogModel::Warning;
+  this->InfoButtonFilter = ctkErrorLogModel::Info | ctkErrorLogModel::Debug | ctkErrorLogModel::Trace | ctkErrorLogModel::Status;
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidgetPrivate::init()
+{
+  Q_Q(ctkErrorLogWidget);
+
+  // this->ShowAllEntryButton->setIcon();
+  this->ShowErrorEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxCritical));
+  this->ShowWarningEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxWarning));
+  this->ShowInfoEntryButton->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxInformation));
+  this->ClearButton->setIcon(q->style()->standardIcon(QStyle::SP_DialogDiscardButton));
+
+  QObject::connect(this->ShowAllEntryButton, SIGNAL(clicked()),
+                   q, SLOT(setAllEntriesVisible()));
+
+  QObject::connect(this->ShowErrorEntryButton, SIGNAL(clicked(bool)),
+                   q, SLOT(setErrorEntriesVisible(bool)));
+
+  QObject::connect(this->ShowWarningEntryButton, SIGNAL(clicked(bool)),
+                   q, SLOT(setWarningEntriesVisible(bool)));
+
+  QObject::connect(this->ShowInfoEntryButton, SIGNAL(clicked(bool)),
+                   q, SLOT(setInfoEntriesVisible(bool)));
+
+  QObject::connect(this->ClearButton, SIGNAL(clicked()),
+                   q, SLOT(removeEntries()));
+}
+
+// --------------------------------------------------------------------------
+// ctkErrorLogWidget methods
+
+//------------------------------------------------------------------------------
+ctkErrorLogWidget::ctkErrorLogWidget(QWidget * newParent)
+  : Superclass(newParent)
+  , d_ptr(new ctkErrorLogWidgetPrivate(*this))
+{
+  Q_D(ctkErrorLogWidget);
+
+  d->setupUi(this);
+  d->init();
+
+  this->setErrorLogModel(new ctkErrorLogModel(d->ErrorLogTableView));
+}
+
+//------------------------------------------------------------------------------
+ctkErrorLogWidget::~ctkErrorLogWidget()
+{
+}
+
+//------------------------------------------------------------------------------
+ctkErrorLogModel* ctkErrorLogWidget::errorLogModel()const
+{
+  Q_D(const ctkErrorLogWidget);
+  QAbstractItemModel* model = d->ErrorLogTableView->model();
+  ctkErrorLogModel * errorLogModel = qobject_cast<ctkErrorLogModel*>(model);
+  Q_ASSERT(model ? errorLogModel != 0 : true);
+  return errorLogModel;
+}
+
+//------------------------------------------------------------------------------
+void ctkErrorLogWidget::setErrorLogModel(ctkErrorLogModel * newErrorLogModel)
+{
+  Q_D(ctkErrorLogWidget);
+
+  if (newErrorLogModel == this->errorLogModel())
+    {
+    return;
+    }
+
+  if (this->errorLogModel())
+    {
+    disconnect(this->errorLogModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
+               this, SLOT(onRowsInserted(const QModelIndex&, int, int)));
+
+    disconnect(this->errorLogModel(), SIGNAL(logLevelFilterChanged()),
+               this, SLOT(onLogLevelFilterChanged()));
+
+    disconnect(d->SelectionModel.data(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+               this, SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
+
+    d->SelectionModel.clear();
+    }
+
+  d->ErrorLogTableView->setModel(newErrorLogModel);
+
+  if (newErrorLogModel)
+    {
+    connect(this->errorLogModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
+            this, SLOT(onRowsInserted(const QModelIndex&, int, int)));
+
+    connect(this->errorLogModel(), SIGNAL(logLevelFilterChanged()),
+            this, SLOT(onLogLevelFilterChanged()));
+
+    ctkErrorLogModel::LogLevels logLevelFilter = newErrorLogModel->logLevelFilter();
+    this->setErrorEntriesVisible(logLevelFilter & d->ErrorButtonFilter);
+    this->setWarningEntriesVisible(logLevelFilter & d->WarningButtonFilter);
+    this->setInfoEntriesVisible(logLevelFilter & d->InfoButtonFilter);
+    this->errorLogModel()->filterEntry(logLevelFilter & ctkErrorLogModel::Unknown);
+
+    // Setup selection model
+    d->SelectionModel = QSharedPointer<QItemSelectionModel>(new QItemSelectionModel(this->errorLogModel()));
+    d->SelectionModel->reset();
+
+    connect(d->SelectionModel.data(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+            this, SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
+
+    d->ErrorLogTableView->setSelectionModel(d->SelectionModel.data());
+
+    // Resize time column only if there are rows
+    if (this->errorLogModel()->rowCount() > 0)
+      {
+      d->ErrorLogTableView->resizeColumnToContents(ctkErrorLogModel::TimeColumn);
+      }
+    }
+  else
+    {
+    this->setAllEntriesVisible(0);
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::setAllEntriesVisible(bool visibility)
+{
+  this->setErrorEntriesVisible(visibility);
+  this->setWarningEntriesVisible(visibility);
+  this->setInfoEntriesVisible(visibility);
+  this->errorLogModel()->filterEntry(ctkErrorLogModel::Unknown, /* disableFilter= */ !visibility);
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::setErrorEntriesVisible(bool visibility)
+{
+  Q_D(ctkErrorLogWidget);
+  if (!this->errorLogModel())
+    {
+    return;
+    }
+  this->errorLogModel()->filterEntry(d->ErrorButtonFilter, /* disableFilter= */ !visibility);
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::setWarningEntriesVisible(bool visibility)
+{
+  Q_D(ctkErrorLogWidget);
+  if (!this->errorLogModel())
+    {
+    return;
+    }
+  this->errorLogModel()->filterEntry(d->WarningButtonFilter, /* disableFilter= */ !visibility);
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::setInfoEntriesVisible(bool visibility)
+{
+  Q_D(ctkErrorLogWidget);
+  if (!this->errorLogModel())
+    {
+    return;
+    }
+  this->errorLogModel()->filterEntry(d->InfoButtonFilter, /* disableFilter= */ !visibility);
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::onRowsInserted(const QModelIndex &/*parent*/, int /*first*/, int /*last*/)
+{
+  Q_D(ctkErrorLogWidget);
+  if (d->ErrorLogTableView->model()->rowCount() == 1)
+    {
+    // For performance reason, resize first column only when first entry is added
+    d->ErrorLogTableView->resizeColumnToContents(ctkErrorLogModel::TimeColumn);
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::onLogLevelFilterChanged()
+{
+  Q_D(ctkErrorLogWidget);
+  Q_ASSERT(this->errorLogModel());
+  ctkErrorLogModel::LogLevels logLevelFilter = this->errorLogModel()->logLevelFilter();
+  d->ShowErrorEntryButton->setChecked(logLevelFilter & d->ErrorButtonFilter);
+  d->ShowWarningEntryButton->setChecked(logLevelFilter & d->WarningButtonFilter);
+  d->ShowInfoEntryButton->setChecked(logLevelFilter & d->InfoButtonFilter);
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::removeEntries()
+{
+  Q_ASSERT(this->errorLogModel());
+  this->errorLogModel()->clear();
+}
+
+// --------------------------------------------------------------------------
+void ctkErrorLogWidget::onSelectionChanged(const QItemSelection & selected,
+                                           const QItemSelection & deselected)
+{
+  // QTime start = QTime::currentTime();
+
+  Q_D(ctkErrorLogWidget);
+  Q_UNUSED(selected);
+  Q_UNUSED(deselected);
+
+  QModelIndexList selectedRows =
+      d->SelectionModel->selectedRows(ctkErrorLogModel::DescriptionColumn);
+
+  qSort(selectedRows.begin(), selectedRows.end());
+
+  QStringList descriptions;
+
+  foreach(const QModelIndex& index, selectedRows)
+    {
+    descriptions << index.data(ctkErrorLogModel::DescriptionTextRole).toString();
+    }
+
+  d->ErrorLogDescription->setText(descriptions.join("\n"));
+
+  // fprintf(stdout, "onSelectionChanged: %d\n", start.msecsTo(QTime::currentTime()));
+}

+ 73 - 0
Libs/Widgets/ctkErrorLogWidget.h

@@ -0,0 +1,73 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkErrorLogWidget_h
+#define __ctkErrorLogWidget_h
+
+// Qt includes
+#include <QWidget>
+
+// CTK includes
+#include "ctkWidgetsExport.h"
+
+class ctkErrorLogModel;
+class ctkErrorLogWidgetPrivate;
+class QAbstractButton;
+class QItemSelection;
+class QModelIndex;
+
+class CTK_WIDGETS_EXPORT ctkErrorLogWidget : public QWidget
+{
+  Q_OBJECT
+public:
+  typedef QWidget Superclass;
+  explicit ctkErrorLogWidget(QWidget* parentWidget = 0);
+  virtual ~ctkErrorLogWidget();
+
+  ctkErrorLogModel* errorLogModel()const;
+  void setErrorLogModel(ctkErrorLogModel * newErrorLogModel);
+
+public slots:
+  void setAllEntriesVisible(bool visibility = true);
+
+  void setErrorEntriesVisible(bool visibility);
+
+  void setWarningEntriesVisible(bool visibility);
+
+  void setInfoEntriesVisible(bool visibility);
+
+protected slots:
+  void onRowsInserted(const QModelIndex &parent, int first, int last);
+
+  void onLogLevelFilterChanged();
+
+  void removeEntries();
+
+  void onSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected);
+
+protected:
+  QScopedPointer<ctkErrorLogWidgetPrivate> d_ptr;
+
+private:
+  Q_DECLARE_PRIVATE(ctkErrorLogWidget);
+  Q_DISABLE_COPY(ctkErrorLogWidget);
+};
+
+#endif