Ver código fonte

ENH: Add ctkActionsWidget a tree view that can be populated by QActions

Julien Finet 15 anos atrás
pai
commit
83bb1ccb17

+ 3 - 0
Libs/Widgets/CMakeLists.txt

@@ -12,6 +12,8 @@ SET(KIT_include_directories
 
 # Source files
 SET(KIT_SRCS
+  ctkActionsWidget.cpp
+  ctkActionsWidget.h
   ctkAddRemoveComboBox.cpp
   ctkAddRemoveComboBox.h
   ctkButtonGroup.cpp
@@ -76,6 +78,7 @@ SET(KIT_SRCS
 
 # Headers that should run through moc
 SET(KIT_MOC_SRCS
+  ctkActionsWidget.h
   ctkAddRemoveComboBox.h
   ctkButtonGroup.h
   ctkCheckableHeaderView.h

+ 2 - 0
Libs/Widgets/Testing/Cpp/CMakeLists.txt

@@ -1,6 +1,7 @@
 SET(KIT ${PROJECT_NAME})
 
 CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cxx
+  ctkActionsWidgetTest1.cpp
   ctkAddRemoveComboBoxTest1.cpp
   ctkButtonGroupTest1.cpp
   ctkCheckBoxPixmapsTest1.cpp
@@ -44,6 +45,7 @@ ENDMACRO( SIMPLE_TEST  )
 # Add Tests
 #
 
+SIMPLE_TEST( ctkActionsWidgetTest1 )
 SIMPLE_TEST( ctkAddRemoveComboBoxTest1 )
 SIMPLE_TEST( ctkButtonGroupTest1 )
 SIMPLE_TEST( ctkCheckBoxPixmapsTest1 )

+ 92 - 0
Libs/Widgets/Testing/Cpp/ctkActionsWidgetTest1.cpp

@@ -0,0 +1,92 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  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 <QAction>
+#include <QDebug>
+#include <QIcon>
+#include <QStandardItem>
+#include <QStyle>
+
+// CTK includes
+#include "ctkActionsWidget.h"
+#include "ctkTestApplication.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+QCTK_DECLARE_TEST(ctkActionsWidgetTest1)
+{
+  ctkActionsWidget* actionsWidget = new ctkActionsWidget(0);
+  actionsWidget->show();
+  QWidget widget;
+  QIcon informationIcon = actionsWidget->style()->standardIcon(QStyle::SP_MessageBoxInformation);
+
+  actionsWidget->addAction(new QAction(0));
+  actionsWidget->addAction(new QAction(qApp));
+  actionsWidget->addAction(new QAction("Action Text", qApp));
+  actionsWidget->addAction(new QAction(informationIcon, "Action Text", qApp));
+
+  actionsWidget->addAction(new QAction(0), "category 1");
+  actionsWidget->addAction(new QAction(qApp), "category 1");
+  actionsWidget->addAction(new QAction("Action Text", &widget), "category 1");
+  actionsWidget->addAction(new QAction(informationIcon, "Action Text", qApp), "category 1");
+
+  actionsWidget->addAction(new QAction(0), "category 2");
+  actionsWidget->addAction(new QAction(qApp), "category 3");
+  actionsWidget->addAction(new QAction("Action Text", &widget), "category 4");
+  actionsWidget->addAction(new QAction(informationIcon, "Action Text", qApp), "category 5");
+
+  if (actionsWidget->groupItem("category 1") == 0 || 
+      actionsWidget->groupItem("category 1")->rowCount() != 4)
+    {
+    qDebug() << "Invalid Category 1";
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  // check shortcut
+  QAction* action = new QAction("custom action", 0);
+  action->setShortcut(Qt::Key_F1);
+  action->setToolTip("custom tooltip");
+  actionsWidget->addAction(action);
+  QStandardItem* actionItem = actionsWidget->model()->item(9);
+  if (!actionItem || actionItem->text() != "custom action")
+    {
+    qDebug() << "Invalid custom action" << actionItem->text();
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+  qDebug() << "oui" ;
+  // check update on change 
+  action->setText("new custom action");
+  QStandardItem* changedActionItem = actionsWidget->model()->item(9);
+  if (changedActionItem != actionItem ||
+      changedActionItem->text() != "new custom action")
+    {
+    qDebug() << "Invalid action update" << changedActionItem->text();
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+  widget.addAction(action);
+  //QCTK_EXIT_TEST(EXIT_SUCCESS);
+  //QTimer::singleShot(500, QApplication::instance(), SLOT(quit()));
+}
+
+QCTK_RUN_TEST(ctkActionsWidgetTest1);

+ 200 - 0
Libs/Widgets/ctkActionsWidget.cpp

@@ -0,0 +1,200 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  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 <QAction>
+#include <QDebug>
+#include <QStandardItem>
+#include <QStandardItemModel>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+// CTK includes
+#include "ctkActionsWidget.h"
+
+//-----------------------------------------------------------------------------
+class ctkActionsWidgetPrivate:public ctkPrivate<ctkActionsWidget>
+{
+public:
+  ctkActionsWidgetPrivate();
+  void setupUI();
+  void updateItems(QList<QStandardItem*>& items, QAction* action);
+
+  QStandardItemModel* ActionsModel;
+  QTreeView*          ActionsTreeView;
+  bool                ShowActionsWithNoShortcut;
+};
+
+//-----------------------------------------------------------------------------
+ctkActionsWidgetPrivate::ctkActionsWidgetPrivate()
+{
+  this->ActionsTreeView = 0;
+  this->ShowActionsWithNoShortcut = false;
+}
+
+//-----------------------------------------------------------------------------
+void ctkActionsWidgetPrivate::setupUI()
+{
+  CTK_P(ctkActionsWidget);
+
+  this->ActionsModel = new QStandardItemModel(p);
+  this->ActionsModel->setColumnCount(4);
+  QStringList headers;
+  headers << "Action" << "Shortcut" << "Context" << "Details";
+  this->ActionsModel->setHorizontalHeaderLabels(headers);
+
+  this->ActionsTreeView = new QTreeView(p);
+  QVBoxLayout* layout = new QVBoxLayout(p);
+  layout->addWidget(this->ActionsTreeView);
+  p->setLayout(layout);
+  this->ActionsTreeView->setModel(this->ActionsModel);
+  this->ActionsTreeView->setAlternatingRowColors(true);
+}
+
+//-----------------------------------------------------------------------------
+void ctkActionsWidgetPrivate
+::updateItems(QList<QStandardItem*>& items, QAction* action)
+{
+  Q_ASSERT(items.size() == 4);
+  // Name
+  items[0]->setText(action->text());
+  items[0]->setIcon(action->icon());
+  // Shortcut
+  items[1]->setText(action->shortcut().toString(QKeySequence::NativeText));
+  // Context
+  QString shortcutContext;
+  switch (action->shortcutContext())
+    {
+    case Qt::WidgetShortcut:
+    case Qt::WidgetWithChildrenShortcut:
+      shortcutContext = "Widget";
+      break;
+    case Qt::WindowShortcut:
+    case Qt::ApplicationShortcut:
+    default:
+      shortcutContext = "Application";
+    }
+  items[2]->setText(shortcutContext);
+  items[3]->setText(action->toolTip() != action->text()
+    ? action->toolTip() : QString(""));
+}
+
+//-----------------------------------------------------------------------------
+ctkActionsWidget::ctkActionsWidget(QWidget* parentWidget)
+  :QWidget(parentWidget)
+{
+  CTK_INIT_PRIVATE(ctkActionsWidget);
+  CTK_D(ctkActionsWidget);
+  d->setupUI();
+}
+
+//-----------------------------------------------------------------------------
+void ctkActionsWidget::addAction(QAction* action, const QString& group)
+{
+  CTK_D(ctkActionsWidget);
+  QStandardItem* actionGroupItem = this->groupItem(group);
+  Q_ASSERT(actionGroupItem);
+  QList<QStandardItem*> actionItems;
+  for (int i = 0; i < 4; ++i)
+    {
+    QStandardItem* item = new QStandardItem;
+    item->setData(qVariantFromValue(qobject_cast<QObject*>(action)));
+    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+    actionItems << item;
+    }
+
+  d->updateItems(actionItems, action);
+  bool expandGroupItem = (actionGroupItem->rowCount() == 0);
+  actionGroupItem->appendRow(actionItems);
+  if (expandGroupItem)
+    {
+    d->ActionsTreeView->expand(
+      d->ActionsModel->indexFromItem(actionGroupItem));
+    }
+  connect(action, SIGNAL(changed()), this, SLOT(updateAction()));
+}
+
+//-----------------------------------------------------------------------------
+void ctkActionsWidget::addActions(QList<QAction*> actions, const QString& group)
+{
+  foreach(QAction* action, actions)
+    {
+    this->addAction(action, group);
+    }
+}
+
+//-----------------------------------------------------------------------------
+QStandardItem* ctkActionsWidget::groupItem(const QString& group)
+{
+  CTK_D(ctkActionsWidget);
+  if (group.isEmpty())
+    {
+    return d->ActionsModel->invisibleRootItem();
+    }
+  // check if the group already exists
+  QList<QStandardItem *> foundGroup =
+    d->ActionsModel->findItems(group);
+  if (foundGroup.size() > 0)
+    {
+    return foundGroup[0];
+    }
+  QStandardItem* groupItem = new QStandardItem(group);
+  d->ActionsModel->appendRow(groupItem);
+  return groupItem;
+}
+
+//-----------------------------------------------------------------------------
+QStandardItemModel* ctkActionsWidget::model()const
+{
+  CTK_D(const ctkActionsWidget);
+  return d->ActionsModel;
+}
+
+//-----------------------------------------------------------------------------
+void ctkActionsWidget::updateAction()
+{
+  CTK_D(ctkActionsWidget);
+  QAction* action = qobject_cast<QAction*>(this->sender());
+  Q_ASSERT(action);
+  QModelIndexList foundAction = 
+    d->ActionsModel->match(d->ActionsModel->index(0,0),
+    Qt::UserRole + 1, qVariantFromValue(qobject_cast<QObject*>(action)),
+    1, Qt::MatchExactly | Qt::MatchRecursive);
+  Q_ASSERT(foundAction.size());
+  QModelIndex parentIndex = foundAction[0].parent();
+  QStandardItem* parent = parentIndex.isValid()
+    ? d->ActionsModel->itemFromIndex(parentIndex)
+    : d->ActionsModel->invisibleRootItem();
+  int actionRow = foundAction[0].row();
+  Q_ASSERT(actionRow >= 0);
+  QList<QStandardItem*> actionItems;
+  for(int i = 0; i < 4; ++i)
+    {
+    actionItems << parent->child(actionRow, i);
+    }
+  d->updateItems(actionItems, action);
+}
+
+//-----------------------------------------------------------------------------
+QTreeView* ctkActionsWidget::view()const
+{
+  CTK_D(const ctkActionsWidget);
+  return d->ActionsTreeView;
+}

+ 61 - 0
Libs/Widgets/ctkActionsWidget.h

@@ -0,0 +1,61 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  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 __ctkActionsWidget_h
+#define __ctkActionsWidget_h
+
+// Qt includes
+#include <QWidget>
+
+// CTK includes
+#include "ctkPimpl.h"
+#include "CTKWidgetsExport.h"
+class ctkActionsWidgetPrivate;
+
+class QAction;
+class QStandardItemModel;
+class QStandardItem;
+class QTreeView;
+
+class CTK_WIDGETS_EXPORT ctkActionsWidget : public QWidget
+{
+  Q_OBJECT
+  //Q_PROPERTY(bool showActionsWithNoShortcut read showActionsWithNoShortcut write setShowActionsWithNoShortcut)
+public:
+  explicit ctkActionsWidget(QWidget* parent = 0);
+  
+  void addAction(QAction* action, const QString& category = QString());
+  void addActions(QList<QAction*> actions, const QString& category = QString());
+
+  QStandardItem* groupItem(const QString& category);
+
+  //void setShowActionsWithNoShortcut(bool show);
+  //bool showActionsWithNoShortcut()const;
+
+  QStandardItemModel* model()const;
+  QTreeView* view()const;
+protected slots:
+  void updateAction();
+
+private:
+  CTK_DECLARE_PRIVATE(ctkActionsWidget);
+};
+
+#endif