Переглянути джерело

Improved invalid module handling. Added module filter capabilities.

Sascha Zelzer 12 роки тому
батько
коміт
eb2eb743fc

+ 4 - 10
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp

@@ -36,6 +36,7 @@
 #include <ctkCmdLineModuleBackendLocalProcess.h>
 #include <ctkCmdLineModuleBackendFunctionPointer.h>
 #include <ctkException.h>
+#include <ctkCmdLineModuleXmlException.h>
 
 #include <ctkSettingsDialog.h>
 
@@ -44,7 +45,6 @@
 #include <QMessageBox>
 #include <QFutureSynchronizer>
 #include <QCloseEvent>
-#include <QDebug>
 
 
 ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
@@ -63,7 +63,9 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtWebKit;
   defaultModuleFrontendFactory = moduleFrontendFactories.front();
 
-  ui->modulesTreeWidget->setModuleFrontendFactories(moduleFrontendFactories);
+  ui->modulesTreeWidget->setModuleFrontendFactories(moduleFrontendFactories, moduleFrontendFactories.front());
+  ui->modulesSearchBox->setClearIcon(QIcon(":/icons/clear.png"));
+  connect(ui->modulesSearchBox, SIGNAL(textChanged(QString)), ui->modulesTreeWidget, SLOT(setFilter(QString)));
 
   // Backends
   ctkCmdLineModuleBackendFunctionPointer* backendFunctionPointer = new ctkCmdLineModuleBackendFunctionPointer;
@@ -86,8 +88,6 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   // If a module is registered via the ModuleManager, add it to the tree
   connect(&moduleManager, SIGNAL(moduleRegistered(ctkCmdLineModuleReference)), ui->modulesTreeWidget, SLOT(addModuleItem(ctkCmdLineModuleReference)));
   connect(&moduleManager, SIGNAL(moduleUnregistered(ctkCmdLineModuleReference)), ui->modulesTreeWidget, SLOT(removeModuleItem(ctkCmdLineModuleReference)));
-  // Double-clicking on an item in the tree creates a new tab with the default frontend
-  connect(ui->modulesTreeWidget, SIGNAL(moduleDoubleClicked(ctkCmdLineModuleReference)), this, SLOT(addModuleTab(ctkCmdLineModuleReference)));
   // React to specific frontend creations
   connect(ui->modulesTreeWidget, SIGNAL(moduleFrontendCreated(ctkCmdLineModuleFrontend*)), tabList.data(), SLOT(addTab(ctkCmdLineModuleFrontend*)));
   // React to tab-changes
@@ -308,9 +308,3 @@ void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend
     currentFutureWatcher.setFuture(module->future());
   }
 }
-
-void ctkCLModuleExplorerMainWindow::addModuleTab(const ctkCmdLineModuleReference &moduleRef)
-{
-  ctkCmdLineModuleFrontend* moduleFrontend = this->defaultModuleFrontendFactory->create(moduleRef);
-  this->tabList->addTab(moduleFrontend);
-}

+ 0 - 2
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h

@@ -74,8 +74,6 @@ protected Q_SLOTS:
   void currentModuleFinished();
 
   void moduleTabActivated(ctkCmdLineModuleFrontend* module);
-
-  void addModuleTab(const ctkCmdLineModuleReference& moduleRef);
   
 private:
 

+ 24 - 12
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui

@@ -99,19 +99,26 @@
    </attribute>
    <widget class="QWidget" name="dockWidgetContents">
     <layout class="QVBoxLayout" name="verticalLayout">
+     <property name="spacing">
+      <number>2</number>
+     </property>
      <property name="margin">
       <number>0</number>
      </property>
      <item>
+      <widget class="ctkSearchBox" name="modulesSearchBox"/>
+     </item>
+     <item>
       <widget class="ctkCmdLineModuleExplorerTreeWidget" name="modulesTreeWidget">
-       <attribute name="headerVisible">
-        <bool>false</bool>
-       </attribute>
-       <column>
-        <property name="text">
-         <string notr="true">1</string>
-        </property>
-       </column>
+       <property name="editTriggers">
+        <set>QAbstractItemView::NoEditTriggers</set>
+       </property>
+       <property name="textElideMode">
+        <enum>Qt::ElideMiddle</enum>
+       </property>
+       <property name="headerHidden">
+        <bool>true</bool>
+       </property>
       </widget>
      </item>
     </layout>
@@ -191,7 +198,7 @@
              <x>0</x>
              <y>0</y>
              <width>250</width>
-             <height>110</height>
+             <height>213</height>
             </rect>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_5">
@@ -342,9 +349,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>ctkCmdLineModuleExplorerTreeWidget</class>
-   <extends>QTreeWidget</extends>
-   <header>ctkCmdLineModuleExplorerTreeWidget.h</header>
+   <class>ctkSearchBox</class>
+   <extends>QLineEdit</extends>
+   <header>ctkSearchBox.h</header>
   </customwidget>
   <customwidget>
    <class>ctkCmdLineModuleExplorerOutputText</class>
@@ -357,6 +364,11 @@
    <header>ctkCmdLineModuleExplorerProgressListWidget.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>ctkCmdLineModuleExplorerTreeWidget</class>
+   <extends>QTreeView</extends>
+   <header>ctkCmdLineModuleExplorerTreeWidget.h</header>
+  </customwidget>
  </customwidgets>
  <resources>
   <include location="resources/ctkCmdLineModuleExplorer.qrc"/>

+ 131 - 51
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp

@@ -25,37 +25,46 @@
 #include <ctkCmdLineModuleBackend.h>
 #include <ctkCmdLineModuleFrontendFactory.h>
 #include <ctkCmdLineModuleDescription.h>
+#include <ctkCmdLineModuleXmlException.h>
 
+#include <QStandardItemModel>
+#include <QSortFilterProxyModel>
 #include <QContextMenuEvent>
 #include <QMenu>
 #include <QDebug>
 #include <QUrl>
 #include <QApplication>
+#include <QMessageBox>
 
 QString ctkCmdLineModuleExplorerTreeWidget::CATEGORY_UNKNOWN = "Uncategorized";
 
-class ctkCmdLineModuleTreeWidgetItem : public QTreeWidgetItem
+class ctkCmdLineModuleTreeWidgetItem : public QStandardItem
 {
 public:
 
-  static const int CmdLineModuleType = 1001;
-
   ctkCmdLineModuleTreeWidgetItem(const ctkCmdLineModuleReference& moduleRef)
-    : QTreeWidgetItem(CmdLineModuleType), ModuleRef(moduleRef)
-  {
-    init();
-  }
-
-  ctkCmdLineModuleTreeWidgetItem(QTreeWidget* parent, const ctkCmdLineModuleReference& moduleRef)
-    : QTreeWidgetItem(parent, CmdLineModuleType), ModuleRef(moduleRef)
+    : QStandardItem()
+    , ModuleRef(moduleRef)
   {
-    init();
-  }
+    QString title;
+    try
+    {
+      title = ModuleRef.description().title();
+    }
+    catch (const ctkCmdLineModuleXmlException&)
+    {
+      title = ModuleRef.location().toString();
+    }
 
-  ctkCmdLineModuleTreeWidgetItem(QTreeWidgetItem* parent, const ctkCmdLineModuleReference& moduleRef)
-    : QTreeWidgetItem(parent, CmdLineModuleType), ModuleRef(moduleRef)
-  {
-    init();
+    this->setText(title + " [" + ModuleRef.backend()->name() + "]");
+    this->setData(QVariant::fromValue(ModuleRef));
+    QString toolTip = ModuleRef.location().toString();
+    if (!ModuleRef.xmlValidationErrorString().isEmpty())
+    {
+      this->setIcon(QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning));
+      toolTip += "\n\nWarning:\n\n" + ModuleRef.xmlValidationErrorString();
+    }
+    this->setToolTip(toolTip);
   }
 
   ctkCmdLineModuleReference moduleReference() const
@@ -65,25 +74,13 @@ public:
 
 private:
 
-  void init()
-  {
-    this->setText(0, ModuleRef.description().title() + " [" + ModuleRef.backend()->name() + "]");
-    this->setData(0, Qt::UserRole, QVariant::fromValue(ModuleRef));
-    QString toolTip = ModuleRef.location().toString();
-    if (!ModuleRef.xmlValidationErrorString().isEmpty())
-    {
-      this->setIcon(0, QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning));
-      toolTip += "\n\nWarning:\n\n" + ModuleRef.xmlValidationErrorString();
-    }
-    this->setToolTip(0, toolTip);
-  }
-
   ctkCmdLineModuleReference ModuleRef;
 
 };
 
 ctkCmdLineModuleExplorerTreeWidget::ctkCmdLineModuleExplorerTreeWidget(QWidget *parent)
-  : QTreeWidget(parent)
+  : QTreeView(parent)
+  , DefaultFrontendFactory(NULL)
 {
   this->ContextMenu = new QMenu(this);
   this->ShowFrontendMenu = this->ContextMenu->addMenu("Create Frontend");
@@ -91,11 +88,21 @@ ctkCmdLineModuleExplorerTreeWidget::ctkCmdLineModuleExplorerTreeWidget(QWidget *
   this->ContextMenu->addAction("Properties");
 
   connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(moduleDoubleClicked(QModelIndex)));
+
+  TreeModel = new QStandardItemModel(this);
+
+  FilterProxyModel = new ModuleSortFilterProxyModel(this);
+  FilterProxyModel->setSourceModel(TreeModel);
+  FilterProxyModel->setDynamicSortFilter(true);
+  FilterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+  this->setModel(FilterProxyModel);
 }
 
-void ctkCmdLineModuleExplorerTreeWidget::setModuleFrontendFactories(const QList<ctkCmdLineModuleFrontendFactory *> &frontendFactories)
+void ctkCmdLineModuleExplorerTreeWidget::setModuleFrontendFactories(const QList<ctkCmdLineModuleFrontendFactory *> &frontendFactories,
+                                                                    ctkCmdLineModuleFrontendFactory* defaultFactory)
 {
   this->FrontendFactories = frontendFactories;
+  this->DefaultFrontendFactory = defaultFactory;
 
   this->ShowFrontendMenu->clear();
   foreach(ctkCmdLineModuleFrontendFactory* factory, this->FrontendFactories)
@@ -108,9 +115,17 @@ void ctkCmdLineModuleExplorerTreeWidget::setModuleFrontendFactories(const QList<
 
 void ctkCmdLineModuleExplorerTreeWidget::addModuleItem(const ctkCmdLineModuleReference &moduleRef)
 {
-  QString category = moduleRef.description().category();
+  QString category;
+  try
+  {
+    category = moduleRef.description().category();
+  }
+  catch (const ctkCmdLineModuleXmlException&)
+  {
+    category = CATEGORY_UNKNOWN;
+  }
 
-  QTreeWidgetItem* rootItem = NULL;
+  QStandardItem* rootItem = NULL;
 
   if (category.isEmpty())
   {
@@ -121,43 +136,54 @@ void ctkCmdLineModuleExplorerTreeWidget::addModuleItem(const ctkCmdLineModuleRef
   if (rootItem == NULL)
   {
     // lazily create the root item for the category
-    rootItem = new QTreeWidgetItem(this);
-    rootItem->setText(0, category);
+    rootItem = new QStandardItem(category);
     TreeWidgetCategories[category] = rootItem;
+    TreeModel->appendRow(rootItem);
   }
-  TreeWidgetItems[moduleRef] = new ctkCmdLineModuleTreeWidgetItem(rootItem, moduleRef);
+  QStandardItem* moduleItem =  new ctkCmdLineModuleTreeWidgetItem(moduleRef);
+  TreeWidgetItems[moduleRef] = moduleItem;
+  rootItem->appendRow(moduleItem);
 }
 
 void ctkCmdLineModuleExplorerTreeWidget::removeModuleItem(const ctkCmdLineModuleReference &moduleRef)
 {
-  QString category = moduleRef.description().category();
+  QString category;
+  try
+  {
+    category = moduleRef.description().category();
+  }
+  catch (const ctkCmdLineModuleXmlException&)
+  {
+    category = CATEGORY_UNKNOWN;
+  }
+
   if (category.isEmpty())
   {
     category = CATEGORY_UNKNOWN;
   }
 
 
-  QTreeWidgetItem* treeWidgetItem = TreeWidgetItems.take(moduleRef);
+  QStandardItem* treeWidgetItem = TreeWidgetItems.take(moduleRef);
   if (treeWidgetItem == NULL) return;
 
-  this->removeItemWidget(treeWidgetItem, 0);
-  delete treeWidgetItem;
+  QStandardItem* rootItem = TreeWidgetCategories[category];
+  Q_ASSERT(rootItem);
 
-  QTreeWidgetItem* rootItem = TreeWidgetCategories[category];
-  if (rootItem && rootItem->childCount() == 0)
+  rootItem->removeRow(treeWidgetItem->row());
+
+  if (rootItem->rowCount() == 0)
   {
-    this->removeItemWidget(rootItem, 0);
+    TreeModel->removeRow(rootItem->row());
     TreeWidgetCategories.remove(category);
-    delete rootItem;
   }
 }
 
 void ctkCmdLineModuleExplorerTreeWidget::contextMenuEvent(QContextMenuEvent *event)
 {
-  QTreeWidgetItem* item = this->itemAt(this->viewport()->mapFromGlobal(event->globalPos()));
-  if (item != NULL && item->type() == ctkCmdLineModuleTreeWidgetItem::CmdLineModuleType)
+  QModelIndex index = this->indexAt(this->viewport()->mapFromGlobal(event->globalPos()));
+  if (index.isValid() && index.data(Qt::UserRole+1).isValid())
   {
-    this->ContextReference = item->data(0, Qt::UserRole).value<ctkCmdLineModuleReference>();
+    this->ContextReference = index.data(Qt::UserRole+1).value<ctkCmdLineModuleReference>();
     this->ContextMenu->exec(event->globalPos());
     event->accept();
   }
@@ -170,18 +196,72 @@ void ctkCmdLineModuleExplorerTreeWidget::contextMenuEvent(QContextMenuEvent *eve
 
 void ctkCmdLineModuleExplorerTreeWidget::moduleDoubleClicked(const QModelIndex &index)
 {
-  QVariant data = index.data(Qt::UserRole);
+  if (this->DefaultFrontendFactory == NULL) return;
+
+  QVariant data = index.data(Qt::UserRole+1);
   if (!data.isValid()) return;
 
   ctkCmdLineModuleReference moduleRef = data.value<ctkCmdLineModuleReference>();
   if (!moduleRef) return;
 
-  emit moduleDoubleClicked(moduleRef);
+  this->createFrontend(moduleRef, this->DefaultFrontendFactory);
 }
 
 void ctkCmdLineModuleExplorerTreeWidget::frontendFactoryActionTriggered()
 {
   ctkCmdLineModuleFrontendFactory* frontendFactory = this->ActionsToFrontendFactoryMap[static_cast<QAction*>(this->sender())];
-  ctkCmdLineModuleFrontend* frontend = frontendFactory->create(this->ContextReference);
-  emit moduleFrontendCreated(frontend);
+  this->createFrontend(this->ContextReference, frontendFactory);
+}
+
+
+void ctkCmdLineModuleExplorerTreeWidget::setFilter(const QString &filter)
+{
+  this->FilterProxyModel->setFilterWildcard(filter);
+}
+
+ctkCmdLineModuleFrontend* ctkCmdLineModuleExplorerTreeWidget::createFrontend(const ctkCmdLineModuleReference &moduleRef,
+                                                                             ctkCmdLineModuleFrontendFactory* frontendFactory)
+{
+  try
+  {
+    moduleRef.description();
+    ctkCmdLineModuleFrontend* moduleFrontend = frontendFactory->create(moduleRef);
+    emit moduleFrontendCreated(moduleFrontend);
+    return moduleFrontend;
+  }
+  catch (const ctkException& e)
+  {
+    QMessageBox::information(this, "Frontend creation failed", "Creating a " + frontendFactory->name()
+                             + " frontend failed:\n\n" + e.what());
+    return NULL;
+  }
+}
+
+
+bool ModuleSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+  QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+
+  QModelIndex childIndex = index.child(0, 0);
+  if (childIndex.isValid())
+  {
+    int i = 0;
+    bool accept = false;
+    while(childIndex.isValid())
+    {
+      accept = this->filterAcceptsRow(childIndex.row(), index);
+      if (accept) return true;
+
+      childIndex = index.child(++i, 0);
+    }
+    return false;
+  }
+
+  return (sourceModel()->data(index).toString().contains(filterRegExp()));
+}
+
+
+ModuleSortFilterProxyModel::ModuleSortFilterProxyModel(QObject *parent)
+  : QSortFilterProxyModel(parent)
+{
 }

+ 31 - 6
Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h

@@ -24,16 +24,33 @@
 
 #include <ctkCmdLineModuleReference.h>
 
-#include <QTreeWidget>
+#include <QSortFilterProxyModel>
+#include <QTreeView>
 
 class ctkCmdLineModuleFrontend;
 struct ctkCmdLineModuleFrontendFactory;
 
+class QStandardItem;
+class QStandardItemModel;
+
+class ModuleSortFilterProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+
+public:
+
+  ModuleSortFilterProxyModel(QObject *parent = 0);
+
+protected:
+
+  bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+};
+
 /**
  * \class ctkCmdLineModuleExplorerTreeWidget
  * \brief Example application tree widget.
  */
-class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget
+class ctkCmdLineModuleExplorerTreeWidget : public QTreeView
 {
   Q_OBJECT
 
@@ -41,20 +58,24 @@ public:
 
   explicit ctkCmdLineModuleExplorerTreeWidget(QWidget* parent = 0);
 
-  void setModuleFrontendFactories(const QList<ctkCmdLineModuleFrontendFactory*>& frontendFactories);
+  void setModuleFrontendFactories(const QList<ctkCmdLineModuleFrontendFactory*>& frontendFactories, ctkCmdLineModuleFrontendFactory *defaultFactory);
 
   Q_SLOT void addModuleItem(const ctkCmdLineModuleReference& moduleRef);
   Q_SLOT void removeModuleItem(const ctkCmdLineModuleReference& moduleRef);
 
-  Q_SIGNAL void moduleDoubleClicked(ctkCmdLineModuleReference moduleRef);
   Q_SIGNAL void moduleFrontendCreated(ctkCmdLineModuleFrontend* moduleFrontend);
 
+  Q_SLOT void setFilter(const QString& filter);
+
 protected:
 
   void contextMenuEvent(QContextMenuEvent* event);
 
 private:
 
+  ctkCmdLineModuleFrontend* createFrontend(const ctkCmdLineModuleReference &moduleRef,
+                                           ctkCmdLineModuleFrontendFactory* frontendFactory);
+
   Q_SLOT void moduleDoubleClicked(const QModelIndex& index);
   Q_SLOT void frontendFactoryActionTriggered();
 
@@ -65,9 +86,13 @@ private:
 
   ctkCmdLineModuleReference ContextReference;
   QList<ctkCmdLineModuleFrontendFactory*> FrontendFactories;
-  QHash<QString, QTreeWidgetItem*> TreeWidgetCategories;
-  QHash<ctkCmdLineModuleReference, QTreeWidgetItem*> TreeWidgetItems;
+  ctkCmdLineModuleFrontendFactory* DefaultFrontendFactory;
+  QHash<QString, QStandardItem*> TreeWidgetCategories;
+  QHash<ctkCmdLineModuleReference, QStandardItem*> TreeWidgetItems;
   QHash<QAction*, ctkCmdLineModuleFrontendFactory*> ActionsToFrontendFactoryMap;
+
+  QStandardItemModel* TreeModel;
+  QSortFilterProxyModel* FilterProxyModel;
 };
 
 #endif // CTKCMDLINEMODULEEXPLORERTREEWIDGET_H

BIN
Applications/ctkCommandLineModuleExplorer/resources/clear.png


+ 1 - 0
Applications/ctkCommandLineModuleExplorer/resources/ctkCmdLineModuleExplorer.qrc

@@ -3,5 +3,6 @@
         <file>run.png</file>
         <file>stop.png</file>
         <file>pause.png</file>
+        <file>clear.png</file>
     </qresource>
 </RCC>