From 8130f783f811155d772f84b03210f75825aa2126 Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 31 May 2022 17:03:34 -0400 Subject: [PATCH 01/44] ENH: Moved Version to 22.05.100 --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 559bf852f7..4a680231e3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -22.05.0 +22.05.100 -- GitLab From 3a736b20e196f98407d71a37a1f558fc32119b98 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 27 May 2022 17:51:27 -0400 Subject: [PATCH 02/44] Fix crash in aeva/aeva#286. --- smtk/operation/Manager.cxx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/smtk/operation/Manager.cxx b/smtk/operation/Manager.cxx index 936a868419..8d165dfbbc 100644 --- a/smtk/operation/Manager.cxx +++ b/smtk/operation/Manager.cxx @@ -123,10 +123,13 @@ std::shared_ptr Manager::create(const std::string& typeName) } smtkInfoMacro(smtk::io::Logger::instance(), message.str()); } - if (auto managers = m_managers.lock()) + if (op) { - // Pass application's managers if available. - op->setManagers(managers); + if (auto managers = m_managers.lock()) + { + // Pass application's managers if available. + op->setManagers(managers); + } } return op; @@ -152,10 +155,13 @@ std::shared_ptr Manager::create(const Operation::Index& index) // issue by accessing the parameters as they are created by the manager. auto parameters = op->parameters(); } - if (auto managers = m_managers.lock()) + if (op) { - // Pass application's managers if available. - op->setManagers(managers); + if (auto managers = m_managers.lock()) + { + // Pass application's managers if available. + op->setManagers(managers); + } } return op; -- GitLab From b1e18ead505176e641f235e5f79feef20d050c80 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 27 May 2022 17:52:03 -0400 Subject: [PATCH 03/44] Include bounding box information in info inspector. This is part of aeva/aeva#280. --- .../smtkDataSetInfoInspectorView.cxx | 52 ++++++++++++++++++- .../vtk/operators/DataSetInfoInspector.cxx | 6 +++ .../vtk/operators/DataSetInfoInspector.sbt | 3 ++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx b/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx index 798b5c111c..81dbbbea4b 100644 --- a/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx +++ b/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx @@ -334,12 +334,18 @@ void nonEmptyCounters( } }; + bool haveBounds = false; std::set nonZeroCounts; std::map sortedComponents; for (std::size_t ii = 0; ii < datasets->numberOfGroups(); ++ii) { auto name = datasets->findAs(ii, "component")->value()->name(); sortedComponents[name] = ii; + if (!haveBounds) + { + auto boundsItem = datasets->findAs(ii, "bounds"); + haveBounds = boundsItem->isSet(); + } for (std::size_t jj = 0; jj < datasets->numberOfItemsPerGroup(); ++jj) { if (auto item = std::dynamic_pointer_cast(datasets->item(ii, jj))) @@ -357,6 +363,12 @@ void nonEmptyCounters( { compIndices.push_back(entry.second); } + if (haveBounds) + { + infoNames.push_back("Δx"); + infoNames.push_back("Δy"); + infoNames.push_back("Δz"); + } for (const auto& index : nonZeroCounts) { #if 0 @@ -388,14 +400,52 @@ void smtkDataSetInfoInspectorView::updateInfoTable(const smtk::attribute::Attrib nonEmptyCounters(datasets, compIndices, itemIndices, infoNames); m_p->m_summaryTable->clear(); m_p->m_summaryTable->setColumnCount(static_cast(compIndices.size())); - m_p->m_summaryTable->setRowCount(static_cast(itemIndices.size())); + m_p->m_summaryTable->setRowCount(static_cast(infoNames.size())); QStringList componentNames; int column = 0; for (const auto& compIndex : compIndices) { componentNames.push_back(QString::fromStdString( datasets->findAs(compIndex, "component")->value()->name())); + auto boundsItem = datasets->findAs(compIndex, "bounds"); int row = 0; + if (boundsItem && boundsItem->isSet()) + { + auto* itemWidget = + new QTableWidgetItem(tr("%1 (%2 → %3)") + .arg( + QString::number(boundsItem->value(1) - boundsItem->value(0)), + QString::number(boundsItem->value(0)), + QString::number(boundsItem->value(1)))); + itemWidget->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + m_p->m_summaryTable->setItem(row, column, itemWidget); + ++row; + + itemWidget = + new QTableWidgetItem(tr("%1 (%2 → %3)") + .arg( + QString::number(boundsItem->value(3) - boundsItem->value(2)), + QString::number(boundsItem->value(2)), + QString::number(boundsItem->value(3)))); + itemWidget->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + m_p->m_summaryTable->setItem(row, column, itemWidget); + ++row; + + itemWidget = + new QTableWidgetItem(tr("%1 (%2 → %3)") + .arg( + QString::number(boundsItem->value(5) - boundsItem->value(4)), + QString::number(boundsItem->value(4)), + QString::number(boundsItem->value(5)))); + itemWidget->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + m_p->m_summaryTable->setItem(row, column, itemWidget); + ++row; + } + else if (infoNames[0] == "Δx") + { + // This component doesn't have bounds, but some other one does. + row += 3; + } for (const auto& itemIndex : itemIndices) { auto countItem = diff --git a/smtk/extension/vtk/operators/DataSetInfoInspector.cxx b/smtk/extension/vtk/operators/DataSetInfoInspector.cxx index e62ac003b2..cc48cddc1f 100644 --- a/smtk/extension/vtk/operators/DataSetInfoInspector.cxx +++ b/smtk/extension/vtk/operators/DataSetInfoInspector.cxx @@ -39,6 +39,8 @@ #include "smtk/extension/vtk/operators/DataSetInfoInspector_xml.h" +#include + namespace smtk { namespace geometry @@ -65,6 +67,7 @@ struct DataSetInfo } if (auto* dataset = vtkDataSet::SafeDownCast(data)) { + dataset->GetBounds(this->bounds.data()); auto* it = dataset->NewCellIterator(); for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) { @@ -86,6 +89,7 @@ struct DataSetInfo vtkIdType numberOfPoints; std::vector arraySummaries; std::array cellCounts; + std::array bounds; }; // Given the associated components, fetch their renderable geometry and summarize it. @@ -131,6 +135,8 @@ void prepareResult(DataSetInfoInspector::Result& result, std::set& for (const auto& summary : summaries) { info->findAs(ii, "component")->setValue(summary.component); + auto boundsItem = info->findAs(ii, "bounds"); + boundsItem->setValues(summary.bounds.data(), summary.bounds.data() + 6); info->findAs(ii, "point count")->setValue(summary.numberOfPoints); int jj = 0; for (const auto& count : summary.cellCounts) diff --git a/smtk/extension/vtk/operators/DataSetInfoInspector.sbt b/smtk/extension/vtk/operators/DataSetInfoInspector.sbt index 5e7fd8a08f..4f0c3a3724 100644 --- a/smtk/extension/vtk/operators/DataSetInfoInspector.sbt +++ b/smtk/extension/vtk/operators/DataSetInfoInspector.sbt @@ -37,6 +37,9 @@ Return key toggles component visibility. + + + -- GitLab From d493815bf2546fd8b3c05fc0b88be1da95551c84 Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Thu, 26 May 2022 10:40:35 -0400 Subject: [PATCH 04/44] Refactor `Panels` so they can be reused and rearranged. `Panels` derive from `QWidget`, and are contained in a `pqSMTKDock` which is a template specialization for each dock. Each panel must implement the `titleChanged` signal. --- doc/release/notes/dockwidget_refactor.rst | 12 ++++ .../appcomponents/ApplicationConfiguration.h | 4 +- .../paraview/appcomponents/CMakeLists.txt | 6 ++ .../appcomponents/plugin-gui/CMakeLists.txt | 4 +- .../plugin-legacy-operations/CMakeLists.txt | 2 +- .../plugin-operations-panel/CMakeLists.txt | 4 +- .../DefaultConfiguration.cxx | 2 +- .../DefaultConfiguration.h | 2 +- .../appcomponents/pqSMTKAttributeDock.h | 26 +++++++ .../appcomponents/pqSMTKAttributePanel.cxx | 18 +++-- .../appcomponents/pqSMTKAttributePanel.h | 9 ++- .../pqSMTKDisplayAttributeOnLoadBehavior.cxx | 12 ++-- .../paraview/appcomponents/pqSMTKDock.cxx | 17 +++++ .../paraview/appcomponents/pqSMTKDock.h | 72 +++++++++++++++++++ .../appcomponents/pqSMTKOperationDock.h | 26 +++++++ .../appcomponents/pqSMTKOperationPanel.cxx | 6 +- .../appcomponents/pqSMTKOperationPanel.h | 9 ++- .../pqSMTKOperationParameterDock.h | 27 +++++++ .../pqSMTKOperationParameterPanel.cxx | 7 +- .../pqSMTKOperationParameterPanel.h | 21 +++--- .../pqSMTKOperationToolboxDock.h | 27 +++++++ .../pqSMTKOperationToolboxPanel.cxx | 21 +++--- .../pqSMTKOperationToolboxPanel.h | 19 +++-- .../pqSMTKPipelineSelectionBehavior.cxx | 19 ++--- .../appcomponents/pqSMTKResourceBrowser.h | 2 - .../appcomponents/pqSMTKResourceDock.h | 26 +++++++ .../appcomponents/pqSMTKResourcePanel.cxx | 18 ++++- .../appcomponents/pqSMTKResourcePanel.h | 13 +++- .../pybind11/PybindpqSMTKAttributePanel.h | 4 +- .../pybind11/PybindpqSMTKOperationPanel.h | 4 +- .../pybind11/PybindpqSMTKResourcePanel.h | 4 +- .../extension/paraview/project/CMakeLists.txt | 7 +- .../paraview/project/plugin/CMakeLists.txt | 2 +- .../project/pqSMTKProjectAutoStart.cxx | 10 ++- .../paraview/project/pqSMTKProjectBrowser.h | 2 - .../paraview/project/pqSMTKProjectDock.h | 26 +++++++ .../paraview/project/pqSMTKProjectPanel.cxx | 12 +++- .../paraview/project/pqSMTKProjectPanel.h | 14 +++- 38 files changed, 416 insertions(+), 100 deletions(-) create mode 100644 doc/release/notes/dockwidget_refactor.rst create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKDock.cxx create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKDock.h create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKOperationDock.h create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKOperationParameterDock.h create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxDock.h create mode 100644 smtk/extension/paraview/appcomponents/pqSMTKResourceDock.h create mode 100644 smtk/extension/paraview/project/pqSMTKProjectDock.h diff --git a/doc/release/notes/dockwidget_refactor.rst b/doc/release/notes/dockwidget_refactor.rst new file mode 100644 index 0000000000..5a9e11f0d1 --- /dev/null +++ b/doc/release/notes/dockwidget_refactor.rst @@ -0,0 +1,12 @@ +Panels separated from DockWidgets +--------------------------------- + +Previously, several `Panel` classes derived directly from `QDockWidget`, +so they could be docked by the user in whatever arrangement was desired. + +To allow re-use and rearrangement, these `Panel` classes now derive from +`QWidget`, and are placed inside a `pqSMTKDock` which derives from +`QDockWidget`. `pqSMTKDock` has a template parameter to allow it to create the +child `Panel` of the correct type. `Panel` classes must now implement `void +setTitle(QString title)` to provide the `pqSMTKDock` with the correct title, +and use `setWindowTitle()` to provide the initial dock window title. diff --git a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h index 9365a9e437..ba323d4fd9 100644 --- a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h +++ b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h @@ -19,7 +19,7 @@ #include #include -class QDockWidget; +class QWidget; namespace smtk { @@ -57,7 +57,7 @@ public: * Applications should dynamic-cast the \a panel to each of the panel types that * it supports and return view information. */ - virtual smtk::view::Information panelConfiguration(const QDockWidget* panel) = 0; + virtual smtk::view::Information panelConfiguration(const QWidget* panel) = 0; protected: /// A "slot" to be invoked when an interface implementation is available. diff --git a/smtk/extension/paraview/appcomponents/CMakeLists.txt b/smtk/extension/paraview/appcomponents/CMakeLists.txt index daf5c88b41..37774745e5 100644 --- a/smtk/extension/paraview/appcomponents/CMakeLists.txt +++ b/smtk/extension/paraview/appcomponents/CMakeLists.txt @@ -4,6 +4,7 @@ set(classes VisibilityBadge pqSMTKAttributePanel pqSMTKBehavior + pqSMTKDock pqSMTKOperationPanel pqSMTKOperationParameterPanel pqSMTKOperationToolboxPanel @@ -33,6 +34,11 @@ set(classes set(headers pqQtKeywordWrapping.h + pqSMTKAttributeDock.h + pqSMTKOperationDock.h + pqSMTKOperationParameterDock.h + pqSMTKOperationToolboxDock.h + pqSMTKResourceDock.h ) set(CMAKE_AUTOMOC 1) diff --git a/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt b/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt index 7b005e3aca..db67744587 100644 --- a/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt +++ b/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt @@ -11,12 +11,12 @@ paraview_plugin_add_toolbar( SOURCES toolbar_sources) paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKAttributePanel + CLASS_NAME pqSMTKAttributeDock DOCK_AREA Left INTERFACES attribute_dock_interfaces SOURCES attribute_dock_sources) paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKResourcePanel + CLASS_NAME pqSMTKResourceDock DOCK_AREA Left INTERFACES resource_dock_interfaces SOURCES resource_dock_sources) diff --git a/smtk/extension/paraview/appcomponents/plugin-legacy-operations/CMakeLists.txt b/smtk/extension/paraview/appcomponents/plugin-legacy-operations/CMakeLists.txt index 5ae2372ea4..bce3f10401 100644 --- a/smtk/extension/paraview/appcomponents/plugin-legacy-operations/CMakeLists.txt +++ b/smtk/extension/paraview/appcomponents/plugin-legacy-operations/CMakeLists.txt @@ -2,7 +2,7 @@ set(sources) set(interfaces) paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKOperationPanel + CLASS_NAME pqSMTKOperationDock DOCK_AREA Left INTERFACES operation_dock_interfaces SOURCES operation_dock_sources) diff --git a/smtk/extension/paraview/appcomponents/plugin-operations-panel/CMakeLists.txt b/smtk/extension/paraview/appcomponents/plugin-operations-panel/CMakeLists.txt index 6682b23f5a..0ad0a8cf0a 100644 --- a/smtk/extension/paraview/appcomponents/plugin-operations-panel/CMakeLists.txt +++ b/smtk/extension/paraview/appcomponents/plugin-operations-panel/CMakeLists.txt @@ -2,12 +2,12 @@ set(sources) set(interfaces) paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKOperationToolboxPanel + CLASS_NAME pqSMTKOperationToolboxDock DOCK_AREA Left INTERFACES operation_toolbox_dock_interfaces SOURCES operation_toolbox_dock_sources) paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKOperationParameterPanel + CLASS_NAME pqSMTKOperationParameterDock DOCK_AREA Left INTERFACES operation_parameter_dock_interfaces SOURCES operation_parameter_dock_sources) diff --git a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx index bf06fdb77c..338ad5acf3 100644 --- a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx +++ b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx @@ -21,7 +21,7 @@ DefaultConfiguration::DefaultConfiguration(QObject* parent) { } -smtk::view::Information DefaultConfiguration::panelConfiguration(const QDockWidget* panel) +smtk::view::Information DefaultConfiguration::panelConfiguration(const QWidget* panel) { smtk::view::Information result; if (const auto* toolbox = dynamic_cast(panel)) diff --git a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h index 992df3374f..05b0db0c8d 100644 --- a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h +++ b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h @@ -34,7 +34,7 @@ public: /**\brief Provide configuration information for panels. * */ - smtk::view::Information panelConfiguration(const QDockWidget* panel) override; + smtk::view::Information panelConfiguration(const QWidget* panel) override; }; #endif // smtk_extension_paraview_appcomponents_DefaultConfiguration_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h b/smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h new file mode 100644 index 0000000000..2029932bde --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h @@ -0,0 +1,26 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKAttributeDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKAttributeDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" + +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKAttributeDock : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKAttributeDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKAttributeDock", parent) + { + } + ~pqSMTKAttributeDock() override = default; +}; +#endif // smtk_extension_paraview_appcomponents_pqSMTKAttributeDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx index d6c6867688..bd27977973 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx @@ -18,6 +18,8 @@ #include "smtk/extension/paraview/server/vtkSMTKSettings.h" +#include "smtk/extension/qt/qtBaseView.h" + #include "smtk/io/Logger.h" #include "smtk/resource/Manager.h" @@ -47,12 +49,9 @@ pqSMTKAttributePanel::pqSMTKAttributePanel(QWidget* parent) : Superclass(parent) { - this->setObjectName("attributeEditor"); + this->setObjectName("pqSMTKAttributePanel"); this->updateTitle(); - QWidget* w = new QWidget(this); - w->setObjectName("attributePanel"); - this->setWidget(w); - w->setLayout(new QVBoxLayout); + this->setLayout(new QVBoxLayout); auto* behavior = pqSMTKBehavior::instance(); QObject::connect( behavior, @@ -122,7 +121,7 @@ void pqSMTKAttributePanel::resetPanel(smtk::resource::ManagerPtr rsrcMgr) m_propertyLinks.clear(); delete m_attrUIMgr; m_attrUIMgr = nullptr; - while (QWidget* w = this->widget()->findChild()) + while (QWidget* w = this->findChild()) { delete w; } @@ -319,7 +318,11 @@ bool pqSMTKAttributePanel::displayView(smtk::view::ConfigurationPtr view) smtkErrorMacro(smtk::io::Logger::instance(), "View passed but no resource indicated."); return false; } - auto* qview = m_attrUIMgr->setSMTKView(view, this->widget()); + auto* qview = m_attrUIMgr->setSMTKView(view, this); + if (qview) + { + this->layout()->addWidget(qview->widget()); + } return qview != nullptr; } @@ -385,4 +388,5 @@ void pqSMTKAttributePanel::updateTitle(const smtk::view::ConfigurationPtr& view) } } this->setWindowTitle(panelName.c_str()); + Q_EMIT titleChanged(panelName.c_str()); } diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h index 5987d70b40..5cba1f7bef 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h @@ -22,7 +22,7 @@ #include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" -#include +#include class pqServer; class pqPipelineSource; @@ -36,10 +36,10 @@ class pqPipelineSource; * This panel will create a new SMTK attribute UI manager each time the * resource to be displayed is switched for a different resource. */ -class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKAttributePanel : public QDockWidget +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKAttributePanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKAttributePanel(QWidget* parent = nullptr); @@ -47,6 +47,9 @@ public: smtk::extension::qtUIManager* attributeUIManager() const { return m_attrUIMgr; } +Q_SIGNALS: + void titleChanged(QString title); + public Q_SLOTS: /**\brief Populate the attribute panel with data from \a psrc * diff --git a/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx index 48cddcc76d..11780bb7f4 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx @@ -10,6 +10,7 @@ #include "smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.h" // SMTK +#include "smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h" #include "smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h" #include "smtk/extension/paraview/appcomponents/pqSMTKBehavior.h" #include "smtk/extension/paraview/appcomponents/pqSMTKResource.h" @@ -146,12 +147,15 @@ void pqSMTKDisplayAttributeOnLoadBehavior::handleResourceEvent( { return; } - Q_FOREACH (pqSMTKAttributePanel* attrPanel, mainWindow->findChildren()) + Q_FOREACH (pqSMTKAttributeDock* dock, mainWindow->findChildren()) { - panel = attrPanel; - if (panel) + if (dock) { - break; + panel = qobject_cast(dock->widget()); + if (panel) + { + break; + } } } if (!panel) diff --git a/smtk/extension/paraview/appcomponents/pqSMTKDock.cxx b/smtk/extension/paraview/appcomponents/pqSMTKDock.cxx new file mode 100644 index 0000000000..5dfc1496fc --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKDock.cxx @@ -0,0 +1,17 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" + +pqSMTKDockBase::pqSMTKDockBase(QWidget* parent) + : Superclass("baseDock", parent) +{ +} + +pqSMTKDockBase::~pqSMTKDockBase() = default; diff --git a/smtk/extension/paraview/appcomponents/pqSMTKDock.h b/smtk/extension/paraview/appcomponents/pqSMTKDock.h new file mode 100644 index 0000000000..4c79f5ebe2 --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKDock.h @@ -0,0 +1,72 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKDock_h + +#include "smtk/extension/paraview/appcomponents/smtkPQComponentsExtModule.h" + +#include "smtk/PublicPointerDefs.h" + +#include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" + +#include +#include + +/**\brief A dock widget that displays a panel. + * + */ +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKDockBase : public QDockWidget +{ + Q_OBJECT + typedef QDockWidget Superclass; + +public: + pqSMTKDockBase(QWidget* parent = nullptr); + ~pqSMTKDockBase() override; + +public Q_SLOTS: + /// change our title + void changeTitle(QString title) { this->setWindowTitle(title); } + +protected: + void setupPanel() + { + this->setWidget(m_panel); + this->setWindowTitle(m_panel->windowTitle()); + } + QPointer m_panel; +}; + +/**\brief A templated dock widget that displays the type of panel provided. + * + * Panels should implement the signal `void setTitle(QString title)` and + * call `this->setWindowTitle(title)` to pass this class the dock window + * title. + */ +template +class pqSMTKDock : public pqSMTKDockBase // don't _EXPORT because its templated. +{ + typedef pqSMTKDockBase Superclass; + +public: + pqSMTKDock(QString objName, QWidget* parent = nullptr) + : Superclass(parent) + { + this->setObjectName(objName); + auto* panel = new panelT(this); + m_panel = panel; + this->setupPanel(); + // panel must implement the setTitle signal. + QObject::connect(panel, &panelT::titleChanged, this, &pqSMTKDock::changeTitle); + } + ~pqSMTKDock() override = default; +}; + +#endif // smtk_extension_paraview_appcomponents_pqSMTKDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationDock.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationDock.h new file mode 100644 index 0000000000..afc65877aa --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationDock.h @@ -0,0 +1,26 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKOperationDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKOperationDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.h" + +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationDock : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKOperationDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKOperationDock", parent) + { + } + ~pqSMTKOperationDock() override = default; +}; +#endif // smtk_extension_paraview_appcomponents_pqSMTKOperationDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx index 08335536fe..1998547798 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx @@ -60,11 +60,9 @@ public: void setup(::pqSMTKOperationPanel* panel) { - QWidget* ww = new QWidget(panel); - panel->setObjectName("OperationPanel"); + this->setupUi(panel); + panel->setObjectName("pqSMTKOperationPanel"); panel->setWindowTitle("Operations"); - panel->setWidget(ww); - this->setupUi(ww); this->OperationEditor->setLayout(new QVBoxLayout(this->OperationEditor)); this->OperationList->setOperationSource(panel->availableOperations()); diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.h index 00dda063c7..2c5d9babc7 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.h @@ -20,7 +20,7 @@ #include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" -#include +#include class pqServer; class pqPipelineSource; @@ -44,10 +44,10 @@ class QListWidgetItem; * This panel will create a new SMTK attribute UI manager each time the * operation to be displayed is switched for a different resource. */ -class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationPanel : public QDockWidget +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationPanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKOperationPanel(QWidget* parent = nullptr); @@ -57,6 +57,9 @@ public: smtk::view::AvailableOperationsPtr availableOperations() const { return m_availableOperations; } +Q_SIGNALS: + void titleChanged(QString title); + public Q_SLOTS: /// Called when a new client-server connection is added. virtual void observeWrapper(pqSMTKWrapper*, pqServer*); diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterDock.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterDock.h new file mode 100644 index 0000000000..2e3954fc12 --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterDock.h @@ -0,0 +1,27 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKOperationParameterDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKOperationParameterDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.h" + +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationParameterDock + : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKOperationParameterDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKOperationParameterDock", parent) + { + } + ~pqSMTKOperationParameterDock() override = default; +}; +#endif // smtk_extension_paraview_appcomponents_pqSMTKOperationParameterDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx index 03a4331c63..bdbbf9fbe1 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx @@ -80,12 +80,15 @@ pqSMTKOperationParameterPanel::pqSMTKOperationParameterPanel(QWidget* parent) m_tabs->setTabsClosable(true); m_tabs->setMovable(true); m_tabs->setUsesScrollButtons(true); - this->setWidget(m_tabs); + m_layout = new QVBoxLayout; + m_layout->setObjectName("Layout"); + this->setLayout(m_layout); + m_layout->addWidget(m_tabs); QObject::connect( m_tabs, &QTabWidget::tabCloseRequested, this, &pqSMTKOperationParameterPanel::cancelEditing); } QVBoxLayout* layout = new QVBoxLayout(); - this->widget()->setLayout(layout); + m_tabs->setLayout(layout); auto* behavior = pqSMTKBehavior::instance(); QObject::connect( diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.h index 411c5749b4..e373a824fd 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.h @@ -20,19 +20,13 @@ #include "smtk/PublicPointerDefs.h" -#include +#include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" + #include +#include class QTabWidget; -// VTK's wrapper parser does not properly handle Qt macros on macos. -#if defined(__VTK_WRAP__) && !defined(Q_SLOTS) -#define Q_DISABLE_COPY(x) -#define Q_SLOTS -#define Q_SIGNALS public -#define Q_OBJECT -#endif - class pqModalShortcut; class pqPipelineSource; class pqServer; @@ -40,21 +34,25 @@ class pqServer; class pqSMTKWrapper; class QListWidgetItem; +class QVBoxLayout; /**\brief A panel that displays available operations in a "toolbox". * * The panel emits signals when users request an operation be * (a) immediately run or (b) run after editing parameters. */ -class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationParameterPanel : public QDockWidget +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationParameterPanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKOperationParameterPanel(QWidget* parent = nullptr); ~pqSMTKOperationParameterPanel() override; +Q_SIGNALS: + void titleChanged(QString title); + public Q_SLOTS: /// Called when a new client-server connection is added. virtual void observeWrapper(pqSMTKWrapper*, pqServer*); @@ -114,6 +112,7 @@ protected: QPointer m_view; }; QPointer m_tabs; + QPointer m_layout; pqSMTKWrapper* m_wrapper{ nullptr }; // NB: This ties us to a single pqServer (the active one). std::multimap m_views; int m_selectionValue{ 1 }; // What int/bits in the selection map should be tied to associations? diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxDock.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxDock.h new file mode 100644 index 0000000000..3893c55c2e --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxDock.h @@ -0,0 +1,27 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKOperationToolboxDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKOperationToolboxDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h" + +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationToolboxDock + : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKOperationToolboxDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKOperationToolboxDock", parent) + { + } + ~pqSMTKOperationToolboxDock() override = default; +}; +#endif // smtk_extension_paraview_appcomponents_pqSMTKOperationToolboxDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.cxx index 73fc007de6..f080119478 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.cxx @@ -64,12 +64,8 @@ pqSMTKOperationToolboxPanel::pqSMTKOperationToolboxPanel(QWidget* parent) : Superclass(parent) { this->setWindowTitle("Toolbox"); - if (!this->widget()) - { - this->setWidget(new QWidget); - } QVBoxLayout* layout = new QVBoxLayout(); - this->widget()->setLayout(layout); + this->setLayout(layout); // Default configuration. nlohmann::json jsonConfig = { @@ -160,7 +156,7 @@ void pqSMTKOperationToolboxPanel::unobserveWrapper(pqSMTKWrapper* wrapper, pqSer if (m_view) { // Empty the existing view. - while (QWidget* w = this->widget()->findChild()) + while (QWidget* w = this->findChild()) { delete w; } @@ -238,7 +234,7 @@ void pqSMTKOperationToolboxPanel::reconfigure() if (m_view) { // Empty the existing view. - while (QWidget* w = this->widget()->findChild()) + while (QWidget* w = this->findChild()) { delete w; } @@ -268,9 +264,10 @@ void pqSMTKOperationToolboxPanel::reconfigure() managers->insert_or_assign(s_defaultOperations); } smtk::view::Information viewInfo; - this->widget()->setToolTip("Click an operation to edit its parameters.\n" - "Double-click an operation to run it with default parameters."); - viewInfo.insert(this->widget()); + this->setToolTip("Click an operation to edit its parameters.\n" + "Double-click an operation to run it with default parameters."); + QWidget* ww = this; + viewInfo.insert(ww); viewInfo.insert(m_configuration); viewInfo.insert(managers); viewInfo.insert(m_uiMgr.data()); @@ -282,9 +279,9 @@ void pqSMTKOperationToolboxPanel::reconfigure() if (!m_findOperationShortcut) { m_findOperationShortcut = pqKeySequences::instance().addModalShortcut( - QKeySequence(Qt::CTRL + Qt::Key_Space), nullptr, this->widget()); + QKeySequence(Qt::CTRL + Qt::Key_Space), nullptr, this); // Make the shortcut application-wide: - m_findOperationShortcut->setContextWidget(this->widget(), Qt::ApplicationShortcut); + m_findOperationShortcut->setContextWidget(this, Qt::ApplicationShortcut); } QObject::connect( m_findOperationShortcut, diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h index 1a73d9a2d9..a08ce207ae 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h @@ -19,16 +19,10 @@ #include "smtk/PublicPointerDefs.h" -#include -#include +#include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" -// VTK's wrapper parser does not properly handle Qt macros on macos. -#if defined(__VTK_WRAP__) && !defined(Q_SLOTS) -#define Q_DISABLE_COPY(x) -#define Q_SLOTS -#define Q_SIGNALS public -#define Q_OBJECT -#endif +#include +#include class pqModalShortcut; class pqPipelineSource; @@ -51,10 +45,10 @@ class OperationDecorator; * The panel emits signals when users request an operation be * (a) immediately run or (b) run after editing parameters. */ -class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationToolboxPanel : public QDockWidget +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKOperationToolboxPanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKOperationToolboxPanel(QWidget* parent = nullptr); @@ -67,6 +61,9 @@ public: /// Return the toolbox view this dock-widget displays: QPointer toolbox() const { return m_view; } +Q_SIGNALS: + void titleChanged(QString title); + public Q_SLOTS: /// Called when a new client-server connection is added. virtual void observeWrapper(pqSMTKWrapper*, pqServer*); diff --git a/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx index f91523cc5f..f47cae0ed2 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx @@ -10,6 +10,7 @@ #include "smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.h" // SMTK +#include "smtk/extension/paraview/appcomponents/pqSMTKAttributeDock.h" #include "smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.h" #include "smtk/extension/paraview/appcomponents/pqSMTKBehavior.h" #include "smtk/extension/paraview/appcomponents/pqSMTKResource.h" @@ -149,25 +150,25 @@ void pqSMTKPipelineSelectionBehavior::observeSelectionOnServer( // Find the attribute panel. For now, only deal with one; // it doesn't make sense to switch multiple panels to display // the same attribute anyway. - pqSMTKAttributePanel* panel = nullptr; + // pqSMTKDockBase* dock = nullptr; QMainWindow* mainWindow = qobject_cast(pqCoreUtilities::mainWidget()); if (!mainWindow) { return; } Q_FOREACH ( - pqSMTKAttributePanel* attrPanel, mainWindow->findChildren()) + pqSMTKAttributeDock* dock, mainWindow->findChildren()) { - panel = attrPanel; - if (panel) + if (dock) { - break; + pqSMTKAttributePanel* panel = qobject_cast(dock->widget()); + if (panel) + { + panel->displayPipelineSource(rsrcSrc); + break; + } } } - if (panel) - { - panel->displayResource(attrResource); - } } } } diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h b/smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h index 5a4eeb72c1..d5080fab77 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h @@ -18,8 +18,6 @@ #include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" -#include - class QAbstractItemModel; class QItemSelection; diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResourceDock.h b/smtk/extension/paraview/appcomponents/pqSMTKResourceDock.h new file mode 100644 index 0000000000..6258af053c --- /dev/null +++ b/smtk/extension/paraview/appcomponents/pqSMTKResourceDock.h @@ -0,0 +1,26 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_appcomponents_pqSMTKResourceDock_h +#define smtk_extension_paraview_appcomponents_pqSMTKResourceDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h" + +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKResourceDock : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKResourceDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKResourceDock", parent) + { + } + ~pqSMTKResourceDock() override = default; +}; +#endif // smtk_extension_paraview_appcomponents_pqSMTKResourceDock_h diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx index cd1fa4d1e8..4ffea4499c 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx @@ -21,6 +21,8 @@ #include "smtk/view/ResourcePhraseModel.h" #include "smtk/view/json/jsonView.h" +#include + pqSMTKResourcePanel::pqSMTKResourcePanel(QWidget* parent) : Superclass(parent) { @@ -28,6 +30,7 @@ pqSMTKResourcePanel::pqSMTKResourcePanel(QWidget* parent) nlohmann::json j = nlohmann::json::parse(pqSMTKResourceBrowser::getJSONConfiguration()); smtk::view::ConfigurationPtr config = j[0]; this->setView(config); + this->setObjectName("pqSMTKResourcePanel"); auto* smtkBehavior = pqSMTKBehavior::instance(); // Now listen for future connections. @@ -104,8 +107,19 @@ void pqSMTKResourcePanel::resourceManagerAdded(pqSMTKWrapper* wrapper, pqServer* m_browser->widget()->setObjectName("pqSMTKResourceBrowser"); std::string title; m_view->details().attribute("Title", title); - this->setWindowTitle(title.empty() ? "Resources" : title.c_str()); - this->setWidget(m_browser->widget()); + if (title.empty()) + { + title = "Resources"; + } + this->setWindowTitle(title.c_str()); + Q_EMIT titleChanged(title.c_str()); + if (!m_layout) + { + m_layout = new QVBoxLayout; + m_layout->setObjectName("Layout"); + this->setLayout(m_layout); + } + m_layout->addWidget(m_browser->widget()); } void pqSMTKResourcePanel::resourceManagerRemoved(pqSMTKWrapper* mgr, pqServer* server) diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h index 76af29e5c2..d3793d820e 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h +++ b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h @@ -15,19 +15,21 @@ #include "smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h" #include "smtk/extension/qt/qtUIManager.h" -#include +#include +#include #include "smtk/extension/paraview/appcomponents/pqQtKeywordWrapping.h" class pqSMTKResourceBrowser; +class QVBoxLayout; /**\brief A panel that displays SMTK resources available to the application/user. * */ -class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKResourcePanel : public QDockWidget +class SMTKPQCOMPONENTSEXT_EXPORT pqSMTKResourcePanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKResourcePanel(QWidget* parent = nullptr); @@ -39,6 +41,9 @@ public: /// Access the underlying resource browser. pqSMTKResourceBrowser* resourceBrowser() const { return m_browser; } +Q_SIGNALS: + void titleChanged(QString title); + protected Q_SLOTS: virtual void resourceManagerAdded(pqSMTKWrapper* mgr, pqServer* server); virtual void resourceManagerRemoved(pqSMTKWrapper* mgr, pqServer* server); @@ -47,6 +52,8 @@ protected: pqSMTKResourceBrowser* m_browser{ nullptr }; smtk::view::ConfigurationPtr m_view; smtk::extension::qtUIManager* m_viewUIMgr{ nullptr }; + /// The central widget's layout. + QPointer m_layout; }; #endif // smtk_extension_paraview_appcomponents_pqSMTKResourcePanel_h diff --git a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h index b6d1b8bb9c..903443f687 100644 --- a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h +++ b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h @@ -17,9 +17,9 @@ namespace py = pybind11; -inline py::class_< pqSMTKAttributePanel, QDockWidget > pybind11_init_pqSMTKAttributePanel(py::module &m) +inline py::class_< pqSMTKAttributePanel, QWidget > pybind11_init_pqSMTKAttributePanel(py::module &m) { - py::class_< pqSMTKAttributePanel, QDockWidget > instance(m, "pqSMTKAttributePanel"); + py::class_< pqSMTKAttributePanel, QWidget > instance(m, "pqSMTKAttributePanel"); instance .def(py::init<::QWidget *>()) .def("attributeUIManager", &pqSMTKAttributePanel::attributeUIManager) diff --git a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKOperationPanel.h b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKOperationPanel.h index 1e6f829ad5..0816f44793 100644 --- a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKOperationPanel.h +++ b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKOperationPanel.h @@ -17,9 +17,9 @@ namespace py = pybind11; -inline py::class_< pqSMTKOperationPanel, QDockWidget > pybind11_init_pqSMTKOperationPanel(py::module &m) +inline py::class_< pqSMTKOperationPanel, QWidget > pybind11_init_pqSMTKOperationPanel(py::module &m) { - py::class_< pqSMTKOperationPanel, QDockWidget > instance(m, "pqSMTKOperationPanel"); + py::class_< pqSMTKOperationPanel, QWidget > instance(m, "pqSMTKOperationPanel"); instance .def(py::init<::QWidget *>()) .def("attributeUIManager", &pqSMTKOperationPanel::attributeUIManager) diff --git a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKResourcePanel.h b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKResourcePanel.h index d945da7623..c2b0028cce 100644 --- a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKResourcePanel.h +++ b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKResourcePanel.h @@ -17,9 +17,9 @@ namespace py = pybind11; -inline py::class_< pqSMTKResourcePanel, QDockWidget > pybind11_init_pqSMTKResourcePanel(py::module &m) +inline py::class_< pqSMTKResourcePanel, QWidget > pybind11_init_pqSMTKResourcePanel(py::module &m) { - py::class_< pqSMTKResourcePanel, QDockWidget > instance(m, "pqSMTKResourcePanel"); + py::class_< pqSMTKResourcePanel, QWidget > instance(m, "pqSMTKResourcePanel"); instance .def(py::init<::QWidget *>()) .def("resourceBrowser", &pqSMTKResourcePanel::resourceBrowser) diff --git a/smtk/extension/paraview/project/CMakeLists.txt b/smtk/extension/paraview/project/CMakeLists.txt index b846eab330..4a5d61c1ad 100644 --- a/smtk/extension/paraview/project/CMakeLists.txt +++ b/smtk/extension/paraview/project/CMakeLists.txt @@ -13,9 +13,14 @@ smtk_encode_file("${CMAKE_CURRENT_SOURCE_DIR}/ProjectPanelConfiguration.json" set(CMAKE_AUTOMOC 1) set(CMAKE_AUTOUIC 1) +set(headers + ${rpJsonHeader} + pqSMTKProjectDock.h +) + vtk_module_add_module(smtkPQProjectExt CLASSES ${classes} - HEADERS ${rpJsonHeader} + HEADERS ${headers} HEADERS_SUBDIR "smtk/extension/paraview/project" ) vtk_module_link(smtkPQProjectExt diff --git a/smtk/extension/paraview/project/plugin/CMakeLists.txt b/smtk/extension/paraview/project/plugin/CMakeLists.txt index 73551e222e..ff45755872 100644 --- a/smtk/extension/paraview/project/plugin/CMakeLists.txt +++ b/smtk/extension/paraview/project/plugin/CMakeLists.txt @@ -1,5 +1,5 @@ paraview_plugin_add_dock_window( - CLASS_NAME pqSMTKProjectPanel + CLASS_NAME pqSMTKProjectDock DOCK_AREA Left INTERFACES dock_interfaces SOURCES dock_sources) diff --git a/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx b/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx index 55cff60a67..db17c0fb5c 100644 --- a/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx +++ b/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx @@ -9,6 +9,7 @@ //========================================================================= #include "smtk/extension/paraview/project/pqSMTKProjectAutoStart.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKResourceDock.h" #include "smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h" #include "smtk/extension/paraview/project/pqSMTKProjectMenu.h" #include "smtk/project/Project.h" @@ -29,12 +30,15 @@ void setView() QMainWindow* mainWindow = dynamic_cast(w); if (mainWindow) { - pqSMTKResourcePanel* dock = mainWindow->findChild(); + pqSMTKResourceDock* dock = mainWindow->findChild(); + pqSMTKResourcePanel* panel = + dock ? qobject_cast(dock->widget()) : nullptr; // If the dock is not there, just try it again. - if (dock) + if (panel) { + auto phraseModel = std::dynamic_pointer_cast( - dock->resourceBrowser()->phraseModel()); + panel->resourceBrowser()->phraseModel()); if (phraseModel) { phraseModel->setFilter([](const smtk::resource::Resource& resource) { diff --git a/smtk/extension/paraview/project/pqSMTKProjectBrowser.h b/smtk/extension/paraview/project/pqSMTKProjectBrowser.h index 09ae267bda..8b5e77c3c5 100644 --- a/smtk/extension/paraview/project/pqSMTKProjectBrowser.h +++ b/smtk/extension/paraview/project/pqSMTKProjectBrowser.h @@ -16,8 +16,6 @@ #include "smtk/PublicPointerDefs.h" -#include - class QAbstractItemModel; class QItemSelection; diff --git a/smtk/extension/paraview/project/pqSMTKProjectDock.h b/smtk/extension/paraview/project/pqSMTKProjectDock.h new file mode 100644 index 0000000000..48d2db87f7 --- /dev/null +++ b/smtk/extension/paraview/project/pqSMTKProjectDock.h @@ -0,0 +1,26 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#ifndef smtk_extension_paraview_project_pqSMTKProjectDock_h +#define smtk_extension_paraview_project_pqSMTKProjectDock_h + +#include "smtk/extension/paraview/appcomponents/pqSMTKDock.h" +#include "smtk/extension/paraview/project/pqSMTKProjectPanel.h" + +class SMTKPQPROJECTEXT_EXPORT pqSMTKProjectDock : public pqSMTKDock +{ + Q_OBJECT +public: + pqSMTKProjectDock(QWidget* parent = nullptr) + : pqSMTKDock("pqSMTKProjectDock", parent) + { + } + ~pqSMTKProjectDock() override = default; +}; +#endif // smtk_extension_paraview_project_pqSMTKProjectDock_h diff --git a/smtk/extension/paraview/project/pqSMTKProjectPanel.cxx b/smtk/extension/paraview/project/pqSMTKProjectPanel.cxx index 1e5becd19f..737c3e6ff3 100644 --- a/smtk/extension/paraview/project/pqSMTKProjectPanel.cxx +++ b/smtk/extension/paraview/project/pqSMTKProjectPanel.cxx @@ -104,8 +104,16 @@ void pqSMTKProjectPanel::sourceAdded(pqSMTKWrapper* wrapper, pqServer* server) m_browser->widget()->setObjectName("pqSMTKProjectBrowser"); std::string title; m_view->details().attribute("Title", title); - this->setWindowTitle(title.empty() ? "Projects" : title.c_str()); - this->setWidget(m_browser->widget()); + if (title.empty()) + { + title = "Projects"; + } + this->setWindowTitle(title.c_str()); + Q_EMIT titleChanged(title.c_str()); + m_layout = new QVBoxLayout; + m_layout->setObjectName("Layout"); + this->setLayout(m_layout); + m_layout->addWidget(m_browser->widget()); } void pqSMTKProjectPanel::sourceRemoved(pqSMTKWrapper* mgr, pqServer* server) diff --git a/smtk/extension/paraview/project/pqSMTKProjectPanel.h b/smtk/extension/paraview/project/pqSMTKProjectPanel.h index fa444f8986..b1cfb1c4d6 100644 --- a/smtk/extension/paraview/project/pqSMTKProjectPanel.h +++ b/smtk/extension/paraview/project/pqSMTKProjectPanel.h @@ -15,15 +15,18 @@ #include "smtk/extension/paraview/project/pqSMTKProjectBrowser.h" #include "smtk/extension/qt/qtUIManager.h" -#include +#include +#include + +class QVBoxLayout; /**\brief A panel that displays SMTK projects available to the application/user. * */ -class SMTKPQPROJECTEXT_EXPORT pqSMTKProjectPanel : public QDockWidget +class SMTKPQPROJECTEXT_EXPORT pqSMTKProjectPanel : public QWidget { Q_OBJECT - typedef QDockWidget Superclass; + typedef QWidget Superclass; public: pqSMTKProjectPanel(QWidget* parent = nullptr); @@ -32,6 +35,9 @@ public: /// Let the panel display a custom view config, from json or xml. void setView(const smtk::view::ConfigurationPtr& view); +Q_SIGNALS: + void titleChanged(QString title); + protected Q_SLOTS: virtual void sourceAdded(pqSMTKWrapper* mgr, pqServer* server); virtual void sourceRemoved(pqSMTKWrapper* mgr, pqServer* server); @@ -40,6 +46,8 @@ protected: pqSMTKProjectBrowser* m_browser{ nullptr }; smtk::view::ConfigurationPtr m_view; smtk::extension::qtUIManager* m_viewUIMgr{ nullptr }; + /// The central widget's layout. + QPointer m_layout; }; #endif -- GitLab From 9d71bec0e890dbcb8f0bed8af0eb74c5e7153a40 Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Wed, 1 Jun 2022 15:52:35 -0400 Subject: [PATCH 05/44] BUG: Preventing Unwanted Subphrase Generation These changes prevent the qtDescriptivePhrase::index and qtDescriptivePhrase::rowCount functions from causing the underlying phrase model to generate subphrases while QSortFilterProxyModel reads its source model. The changes include: 1. qtDescriptivePhrase will check if DescriptivePhrase::areSubphrasesBuilt returns true before calling DescriptivePhrase::subphrases in functions declared const. Calling the DescriptivePhrase::subphrases without this check caused new subphrases to be built during the call to qtDescriptivePhrase::rowCount while QSortFilterProxyModel was creating mappings to its source model. QSortFilterProxyModel expects its source model to effectively be read-only during this process. In fact, the act of generating new data during QAbstractItemModel::index or QAbstractItemModel::rowCount violates the const-ness of those functions. 2. With the previously described check in place, we observed that ComponentPhraseModel would not insert any subphrases that are supposed to be under phrases on the root. As a result, the SubphraseGenerator::subphrasesForCreatedObjects method was modified to generate the subphrases, if they are not currently built, before proceeding. Not not sure if this was the best place to do this, but it did in fact populate the phrases on the root level as was expected originally. --- .../extension/qt/qtDescriptivePhraseModel.cxx | 24 ++++++++++++------- smtk/view/SubphraseGenerator.cxx | 7 ++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/smtk/extension/qt/qtDescriptivePhraseModel.cxx b/smtk/extension/qt/qtDescriptivePhraseModel.cxx index acbe02e3c0..7c1f3c54eb 100644 --- a/smtk/extension/qt/qtDescriptivePhraseModel.cxx +++ b/smtk/extension/qt/qtDescriptivePhraseModel.cxx @@ -185,14 +185,18 @@ QModelIndex qtDescriptivePhraseModel::index(int row, int column, const QModelInd } view::DescriptivePhrasePtr ownerPhrase = this->getItem(owner); - view::DescriptivePhrases& subphrases(ownerPhrase->subphrases()); - if (row >= 0 && row < static_cast(subphrases.size())) + // Only attempt to return a valid index if the subphrases are currently built + if (ownerPhrase->areSubphrasesBuilt()) { - view::DescriptivePhrasePtr entry = subphrases[row]; - if (entry) + view::DescriptivePhrases& subphrases(ownerPhrase->subphrases()); + if (row >= 0 && row < static_cast(subphrases.size())) { - this->P->ptrs[entry->phraseId()] = entry; - return this->createIndex(row, column, entry->phraseId()); + view::DescriptivePhrasePtr entry = subphrases[row]; + if (entry) + { + this->P->ptrs[entry->phraseId()] = entry; + return this->createIndex(row, column, entry->phraseId()); + } } } @@ -247,12 +251,14 @@ bool qtDescriptivePhraseModel::hasChildren(const QModelIndex& owner) const /// The number of rows in the table "underneath" \a owner. int qtDescriptivePhraseModel::rowCount(const QModelIndex& owner) const { + int count = 0; view::DescriptivePhrasePtr ownerPhrase = this->getItem(owner); - if (!ownerPhrase) + // Only attempt to fetch the subphrases if they are currently built + if (ownerPhrase && ownerPhrase->areSubphrasesBuilt()) { - return 0; + count = static_cast(ownerPhrase->subphrases().size()); } - return static_cast(ownerPhrase->subphrases().size()); + return count; } /// Return something to display in the table header. diff --git a/smtk/view/SubphraseGenerator.cxx b/smtk/view/SubphraseGenerator.cxx index cc669db81b..0142e3d30c 100644 --- a/smtk/view/SubphraseGenerator.cxx +++ b/smtk/view/SubphraseGenerator.cxx @@ -366,11 +366,8 @@ void SubphraseGenerator::subphrasesForCreatedObjects( // This search is O(m*n) where m = number of phrases in tree and n = number of // objects created. localRoot->visitChildren([&](DescriptivePhrasePtr parent, std::vector& parentPath) -> int { - // Terminate early if this phrase has not been expanded by user. - if (!parent->areSubphrasesBuilt()) - { - return 0; - } + // Make sure the parent's subphrases are built + parent->subphrases(); smtk::resource::ResourcePtr rsrc; smtk::resource::ComponentPtr comp; -- GitLab From e4cd0ddc5bcb601e94f085f45ea7362c51bdc35a Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Fri, 3 Jun 2022 10:55:44 -0400 Subject: [PATCH 06/44] Rename `clicked` signal to `singleClicked` to avoid Qt warnings. Debug Qt issues a warning about the `clicked` signal conflicting with the base class - rename to avoid the warning. --- smtk/extension/qt/qtDoubleClickButton.cxx | 2 +- smtk/extension/qt/qtDoubleClickButton.h | 2 +- smtk/extension/qt/qtOperationAction.cxx | 3 ++- smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/smtk/extension/qt/qtDoubleClickButton.cxx b/smtk/extension/qt/qtDoubleClickButton.cxx index e2fe2764c8..017d01eaad 100644 --- a/smtk/extension/qt/qtDoubleClickButton.cxx +++ b/smtk/extension/qt/qtDoubleClickButton.cxx @@ -54,5 +54,5 @@ void qtDoubleClickButton::configure() // that may eventually fire *our* clicked() signal. QObject::connect(this, &Superclass::clicked, this, &qtDoubleClickButton::startTimer); // If the timer fires before more clicks, it was a single-click. - QObject::connect(&m_timer, &QTimer::timeout, this, &qtDoubleClickButton::clicked); + QObject::connect(&m_timer, &QTimer::timeout, this, &qtDoubleClickButton::singleClicked); } diff --git a/smtk/extension/qt/qtDoubleClickButton.h b/smtk/extension/qt/qtDoubleClickButton.h index 887235fefc..a624c28160 100644 --- a/smtk/extension/qt/qtDoubleClickButton.h +++ b/smtk/extension/qt/qtDoubleClickButton.h @@ -36,7 +36,7 @@ public: static constexpr int timeout = 200; // milliseconds Q_SIGNALS: - void clicked(); + void singleClicked(); void doubleClicked(); protected Q_SLOTS: diff --git a/smtk/extension/qt/qtOperationAction.cxx b/smtk/extension/qt/qtOperationAction.cxx index 3743f552b7..9b7fb61808 100644 --- a/smtk/extension/qt/qtOperationAction.cxx +++ b/smtk/extension/qt/qtOperationAction.cxx @@ -155,7 +155,8 @@ QWidget* qtOperationAction::createWidget(QWidget* parent) w->addAction(this); // Provide a reference back to here. w->setObjectName(buttonText.c_str()); // w->installEventFilter(this); - QObject::connect(w, &qtDoubleClickButton::clicked, this, &qtOperationAction::editParameters); + QObject::connect( + w, &qtDoubleClickButton::singleClicked, this, &qtOperationAction::editParameters); QObject::connect( w, &qtDoubleClickButton::doubleClicked, this, &qtOperationAction::acceptDefaults); return w; diff --git a/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx b/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx index edfedc21ee..1361ecf15e 100644 --- a/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx +++ b/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx @@ -37,7 +37,7 @@ DoubleClickButtonTester::DoubleClickButtonTester() { m_window->setCentralWidget(m_widget); QObject::connect( - m_button, &qtDoubleClickButton::clicked, this, &DoubleClickButtonTester::singleClicked); + m_button, &qtDoubleClickButton::singleClicked, this, &DoubleClickButtonTester::singleClicked); QObject::connect( m_button, &qtDoubleClickButton::doubleClicked, this, &DoubleClickButtonTester::doubleClicked); m_widget->setLayout(m_layout); -- GitLab From a5e51e7472c19d150cdb54443a24008adaee021b Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 01:12:12 -0400 Subject: [PATCH 07/44] Install a missing header file. --- smtk/graph/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/smtk/graph/CMakeLists.txt b/smtk/graph/CMakeLists.txt index 3e05c5c5f1..8a26f7d401 100644 --- a/smtk/graph/CMakeLists.txt +++ b/smtk/graph/CMakeLists.txt @@ -12,6 +12,7 @@ set(graphHeaders ArcMap.h Component.h ExplicitArcs.h + NodeProperties.h NodeSet.h Resource.h ResourceBase.h -- GitLab From 7e1d0300d4299d6b7842dbad551b333febb28603 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 00:52:30 -0400 Subject: [PATCH 08/44] =?UTF-8?q?Support=20RGBA=20double=E2=86=92string=20?= =?UTF-8?q?color=20conversion.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/release/notes/common-color.rst | 5 +++++ smtk/common/Color.cxx | 27 +++++++++++++++++++++++++++ smtk/common/Color.h | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 doc/release/notes/common-color.rst diff --git a/doc/release/notes/common-color.rst b/doc/release/notes/common-color.rst new file mode 100644 index 0000000000..a7ffb3f23f --- /dev/null +++ b/doc/release/notes/common-color.rst @@ -0,0 +1,5 @@ +RGBA color conversion +--------------------- + +Now :smtk:`smtk::common::Color` includes methods to convert 4-tuples of floating-point +numbers into hexadecimal color specifiers (in addition to the 3-tuples it already handles). diff --git a/smtk/common/Color.cxx b/smtk/common/Color.cxx index bdf9a78ee7..52e8b735a2 100644 --- a/smtk/common/Color.cxx +++ b/smtk/common/Color.cxx @@ -9,6 +9,7 @@ //========================================================================= #include "smtk/common/Color.h" +#include #include #include #include @@ -92,6 +93,32 @@ bool Color::stringToFloatRGBA(double* rgba, const std::string& colorSpec, double return ok; } +std::string Color::floatRGBAToString(const double* rgba) +{ + std::array rgba_; + for (int i = 0; i < 4; i++) + { + rgba_[i] = int(255 * rgba[i]); + } + + char hexcol[10]; + snprintf(hexcol, sizeof hexcol, "#%02x%02x%02x%02x", rgba_[0], rgba_[1], rgba_[2], rgba_[3]); + return std::string(hexcol); +} + +std::string Color::floatRGBAToString(const float* rgba) +{ + std::array rgba_; + for (int i = 0; i < 4; i++) + { + rgba_[i] = int(255 * rgba[i]); + } + + char hexcol[10]; + snprintf(hexcol, sizeof hexcol, "#%02x%02x%02x%02x", rgba_[0], rgba_[1], rgba_[2], rgba_[3]); + return std::string(hexcol); +} + std::string Color::floatRGBToString(const double* rgb) { int rgb_[3]; diff --git a/smtk/common/Color.h b/smtk/common/Color.h index 916da089d4..9372d8c842 100644 --- a/smtk/common/Color.h +++ b/smtk/common/Color.h @@ -37,6 +37,8 @@ public: rgba.resize(4); return Color::stringToFloatRGBA(&rgba[0], colorSpec, defaultAlpha); } + static std::string floatRGBAToString(const double* rgb); + static std::string floatRGBAToString(const float* rgb); static std::string floatRGBToString(const double* rgb); static std::string floatRGBToString(const float* rgb); static double floatRGBToLightness(const double* rgb); -- GitLab From 9eac1a3d113b191f628d4ac5a83a6a38fd9cf1d2 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 00:55:56 -0400 Subject: [PATCH 09/44] Fix selection-filtering to pass graph nodes through. --- doc/release/notes/paraview-selection.rst | 11 ++ .../pqSMTKSelectionFilterBehavior.cxx | 113 +++++++++--------- 2 files changed, 67 insertions(+), 57 deletions(-) create mode 100644 doc/release/notes/paraview-selection.rst diff --git a/doc/release/notes/paraview-selection.rst b/doc/release/notes/paraview-selection.rst new file mode 100644 index 0000000000..a1423a917e --- /dev/null +++ b/doc/release/notes/paraview-selection.rst @@ -0,0 +1,11 @@ +Selection filtering for graph resources +--------------------------------------- + +A bug in the pqSMTKSelectionFilterBehavior class has been fixed. +It prevented the default selection-responder operation from adding +graph nodes to the selection (basically, anything that could not be +cast to a model entity was rejected). + +Now the selection filter toolbar buttons only apply to model and +mesh entities; graph-resource components will always be passed +through. diff --git a/smtk/extension/paraview/appcomponents/pqSMTKSelectionFilterBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKSelectionFilterBehavior.cxx index 14a7ad85b9..1a2b965f8d 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKSelectionFilterBehavior.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKSelectionFilterBehavior.cxx @@ -360,83 +360,82 @@ void pqSMTKSelectionFilterBehavior::installFilter() if (modelFlags) { auto modelEnt = dynamic_pointer_cast(comp); - if (!modelEnt) + if (modelEnt) { - return false; - } - auto entBits = modelEnt->entityFlags(); - // Is the entity of an acceptable type? - if ((modelFlags & smtk::model::MODEL_ENTITY) == smtk::model::MODEL_ENTITY) - { - smtk::model::EntityRef eref(modelEnt->modelResource(), modelEnt->id()); - smtk::model::Model model = eref.owningModel(); - smtk::model::EntityPtr suggestion; - if (model.isValid(&suggestion)) + auto entBits = modelEnt->entityFlags(); + // Is the entity of an acceptable type? + if ((modelFlags & smtk::model::MODEL_ENTITY) == smtk::model::MODEL_ENTITY) { - suggestions.insert(std::make_pair(suggestion, value)); + smtk::model::EntityRef eref(modelEnt->modelResource(), modelEnt->id()); + smtk::model::Model model = eref.owningModel(); + smtk::model::EntityPtr suggestion; + if (model.isValid(&suggestion)) + { + suggestions.insert(std::make_pair(suggestion, value)); + } } - } - else if ((modelFlags & smtk::model::VOLUME) == smtk::model::VOLUME) - { - smtk::model::CellEntity cell(modelEnt->modelResource(), modelEnt->id()); - smtk::model::Volumes vv; - if (cell.isValid()) + else if ((modelFlags & smtk::model::VOLUME) == smtk::model::VOLUME) { - switch (cell.dimension()) + smtk::model::CellEntity cell(modelEnt->modelResource(), modelEnt->id()); + smtk::model::Volumes vv; + if (cell.isValid()) { - case 0: + switch (cell.dimension()) { - smtk::model::Edges edges = cell.as().edges(); - for (const auto& edge : edges) + case 0: { - smtk::model::Faces faces = edge.faces(); + smtk::model::Edges edges = cell.as().edges(); + for (const auto& edge : edges) + { + smtk::model::Faces faces = edge.faces(); + for (const auto& face : faces) + { + smtk::model::Volumes tmp = face.volumes(); + vv.insert(vv.end(), tmp.begin(), tmp.end()); + } + } + } + break; + case 1: + { + smtk::model::Faces faces = cell.as().faces(); for (const auto& face : faces) { smtk::model::Volumes tmp = face.volumes(); vv.insert(vv.end(), tmp.begin(), tmp.end()); } } + break; + case 2: + vv = cell.as().volumes(); + break; + case 3: + vv.push_back(cell.as()); + break; + default: + break; } - break; - case 1: + } + smtk::model::EntityPtr suggestion; + for (const auto& vc : vv) + { + if (vc.isValid(&suggestion)) { - smtk::model::Faces faces = cell.as().faces(); - for (const auto& face : faces) - { - smtk::model::Volumes tmp = face.volumes(); - vv.insert(vv.end(), tmp.begin(), tmp.end()); - } + suggestions.insert(std::make_pair(suggestion, value)); } - break; - case 2: - vv = cell.as().volumes(); - break; - case 3: - vv.push_back(cell.as()); - break; - default: - break; } } - smtk::model::EntityPtr suggestion; - for (const auto& vc : vv) + else if ((entBits & smtk::model::ENTITY_MASK) & (modelFlags & smtk::model::ENTITY_MASK)) { - if (vc.isValid(&suggestion)) - { - suggestions.insert(std::make_pair(suggestion, value)); - } + // Ensure the dimension is acceptable, too: + return (entBits & smtk::model::AUX_GEOM_ENTITY) || + (entBits & smtk::model::INSTANCE_ENTITY) || + ((entBits & smtk::model::ANY_DIMENSION) & (modelFlags & smtk::model::ANY_DIMENSION)); + } + else + { + return false; } - } - else if ((entBits & smtk::model::ENTITY_MASK) & (modelFlags & smtk::model::ENTITY_MASK)) - { - // Ensure the dimension is acceptable, too: - return (entBits & smtk::model::AUX_GEOM_ENTITY) || - (entBits & smtk::model::INSTANCE_ENTITY) || - ((entBits & smtk::model::ANY_DIMENSION) & (modelFlags & smtk::model::ANY_DIMENSION)); - } - else - { - return false; } } return true; // If no filtering is requested, allow everything -- GitLab From 2b1a288dce7c0c4e5872c49499927339d33e60e8 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 01:10:42 -0400 Subject: [PATCH 10/44] Bring back coloring by field-data array. --- doc/release/notes/geometry-color.rst | 18 +++++++++++ .../server/vtkSMTKResourceRepresentation.cxx | 32 +++++++++++++++++-- smtk/extension/vtk/geometry/Geometry.cxx | 2 +- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 doc/release/notes/geometry-color.rst diff --git a/doc/release/notes/geometry-color.rst b/doc/release/notes/geometry-color.rst new file mode 100644 index 0000000000..a61d8771c1 --- /dev/null +++ b/doc/release/notes/geometry-color.rst @@ -0,0 +1,18 @@ +Coloring renderable geometry +---------------------------- + +Before the property system was in wide use, the geometry +subsystem expected component colors to be passed via a +single-tuple field-data array on the renderable geometry. +Support for this was broken when support for coloring +by a floating-point property was added. + +This commit fixes an issue (properly scaling floating-point +colors when generating an integer-valued color array) and +re-enables support for passing color by field-data. +Support for passing color by entity property is preserved, +but field-data arrays are preferred if present (because +presumably the geometry backend added this array). + +This feature is being revived to support components inheriting +color from other components. diff --git a/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx b/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx index bbe099a13a..80d8e4f9ea 100644 --- a/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx +++ b/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx @@ -78,12 +78,38 @@ void SetAttributeBlockColorToEntity( const smtk::common::UUID& uuid, const smtk::resource::ResourcePtr& res) { + // Fetch the color from \a block's field-data (preferred) or + // the component's "color" property. std::vector color = { { 1., 1., 1., 1. } }; + bool haveColor = false; + if (block) + { + auto* fieldData = block->GetFieldData(); + int idx; + auto* colorArray = fieldData->GetArray("entity color", idx); + if ( + colorArray && colorArray->GetNumberOfComponents() == 4 && colorArray->GetNumberOfTuples() > 0) + { + haveColor = true; + colorArray->GetTuple(0, color.data()); + // If colorArray is integer-valued, normalize to [0,1]: + if (colorArray->GetDataType() < VTK_FLOAT) + { + for (int ii = 0; ii < 4; ++ii) + { + color[ii] /= 255.0; + } + } + } + } - auto component = res->find(uuid); - if (component != nullptr && component->properties().contains>("color")) + if (!haveColor) { - color = component->properties().at>("color"); + auto component = res->find(uuid); + if (!!component && component->properties().contains>("color")) + { + color = component->properties().at>("color"); + } } atts->SetBlockColor(block, color.data()); diff --git a/smtk/extension/vtk/geometry/Geometry.cxx b/smtk/extension/vtk/geometry/Geometry.cxx index 0a662ced39..6d6a09ed0e 100644 --- a/smtk/extension/vtk/geometry/Geometry.cxx +++ b/smtk/extension/vtk/geometry/Geometry.cxx @@ -113,7 +113,7 @@ void Geometry::addColorArray( colorArray->SetName(arrayName.c_str()); for (int i = 0; i < 4; ++i) { - colorArray->FillComponent(i, rgba[i]); + colorArray->FillComponent(i, rgba[i] * 255.0); } data->GetFieldData()->AddArray(colorArray.GetPointer()); } -- GitLab From f7f2c85b7f40ee77d776925813625bce63b79eb6 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 01:11:48 -0400 Subject: [PATCH 11/44] Improve graphviz dump formatting. --- doc/release/notes/graph-dump.rst | 8 ++++++++ smtk/graph/ArcImplementation.h | 1 + smtk/graph/CMakeLists.txt | 1 + smtk/graph/ExplicitArcs.h | 1 + smtk/graph/evaluators/Dump.cxx | 23 +++++++++++++++++++++++ smtk/graph/evaluators/Dump.h | 29 ++++++++++++++++++++++++++++- 6 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 doc/release/notes/graph-dump.rst create mode 100644 smtk/graph/evaluators/Dump.cxx diff --git a/doc/release/notes/graph-dump.rst b/doc/release/notes/graph-dump.rst new file mode 100644 index 0000000000..870ae707e2 --- /dev/null +++ b/doc/release/notes/graph-dump.rst @@ -0,0 +1,8 @@ +Graph-resource Dump improvements +-------------------------------- + +While :smtk:`smtk::graph::Resource`'s dump() method is unchanged, +if you use ``resource->evaluateArcs()`` explicitly it is +now possible to set a color per arc type and to enable a +transparent background for the graph. +(This applies only to graphviz-formatted output.) diff --git a/smtk/graph/ArcImplementation.h b/smtk/graph/ArcImplementation.h index 4ed3a9309a..e3b09a2f07 100644 --- a/smtk/graph/ArcImplementation.h +++ b/smtk/graph/ArcImplementation.h @@ -13,6 +13,7 @@ #include "smtk/common/Visit.h" #include "smtk/graph/detail/TypeTraits.h" +#include "smtk/resource/Component.h" #include "smtk/string/Token.h" namespace smtk diff --git a/smtk/graph/CMakeLists.txt b/smtk/graph/CMakeLists.txt index 8a26f7d401..66e3130693 100644 --- a/smtk/graph/CMakeLists.txt +++ b/smtk/graph/CMakeLists.txt @@ -4,6 +4,7 @@ set(graphOperations set(graphSrcs Component.cxx NodeSet.cxx + evaluators/Dump.cxx ) set(graphHeaders diff --git a/smtk/graph/ExplicitArcs.h b/smtk/graph/ExplicitArcs.h index 479f57e503..6113c740ca 100644 --- a/smtk/graph/ExplicitArcs.h +++ b/smtk/graph/ExplicitArcs.h @@ -11,6 +11,7 @@ #ifndef smtk_graph_ExplicitArcs_h #define smtk_graph_ExplicitArcs_h +#include "smtk/common/UUID.h" #include "smtk/common/Visit.h" #include "smtk/graph/ArcProperties.h" #include "smtk/string/Token.h" diff --git a/smtk/graph/evaluators/Dump.cxx b/smtk/graph/evaluators/Dump.cxx new file mode 100644 index 0000000000..255d6074a2 --- /dev/null +++ b/smtk/graph/evaluators/Dump.cxx @@ -0,0 +1,23 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +#include "smtk/graph/evaluators/Dump.h" + +namespace smtk +{ +namespace graph +{ +namespace evaluators +{ + +std::unique_ptr> Dump::s_backgroundColor; + +} // namespace evaluators +} // namespace graph +} // namespace smtk diff --git a/smtk/graph/evaluators/Dump.h b/smtk/graph/evaluators/Dump.h index 8007603eb1..8ada0a0839 100644 --- a/smtk/graph/evaluators/Dump.h +++ b/smtk/graph/evaluators/Dump.h @@ -15,8 +15,12 @@ #include "smtk/string/Token.h" +#include "smtk/common/Color.h" + #include "nlohmann/json.hpp" +#include +#include #include #include @@ -32,7 +36,7 @@ using json = nlohmann::json; * * The only valid values for \a mimeType are "text/vnd.graphviz" or "text/plain". */ -struct Dump +struct SMTKCORE_EXPORT Dump { Dump() : m_mimeType("text/vnd.graphviz") @@ -60,6 +64,16 @@ struct Dump { } + void setArcColor(const smtk::string::Token& arcType, const std::array& color) + { + m_arcColors[arcType] = color; + } + + static void setBackground(const std::array& bgcolor) + { + s_backgroundColor = std::unique_ptr>(new std::array(bgcolor)); + } + template static void begin(ResourcePtr resource, std::ostream& stream, const Dump& self) { @@ -70,6 +84,11 @@ struct Dump if (self.m_mimeType == "text/vnd.graphviz") { stream << "digraph \"" << resource->name() << "\" {\n\n"; + if (s_backgroundColor) + { + stream << " bgcolor=\"" + << smtk::common::Color::floatRGBAToString(s_backgroundColor->data()) << "\"\n"; + }; if (self.m_includeNodes) { std::function&)> dumpNodes = @@ -124,6 +143,12 @@ struct Dump { stream << " edge [dir=\"none\"]\n"; } + auto colorIt = m_arcColors.find(arcType); + if (colorIt != m_arcColors.end()) + { + stream << " edge [color=\"" + << smtk::common::Color::floatRGBAToString(colorIt->second.data()) << "\"]\n"; + } } arcs->visitAllOutgoingNodes( resource, [&stream, &self](const typename ArcTraits::FromType* node) { @@ -180,6 +205,8 @@ struct Dump std::set m_includeArcs; std::set m_excludeArcs; bool m_includeNodes = true; + std::map> m_arcColors; + static std::unique_ptr> s_backgroundColor; }; } // namespace evaluators -- GitLab From dcc66ca3b945538243548096d1842afe8aa22799 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 11 Jun 2022 15:45:36 -0400 Subject: [PATCH 12/44] Fix a crash when deleting items. If the smtk::operation::DeleterGroup cannot find a valid operation, do not attempt to create one from a null index. This was causing a crash. --- smtk/extension/qt/qtResourceBrowser.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/smtk/extension/qt/qtResourceBrowser.cxx b/smtk/extension/qt/qtResourceBrowser.cxx index 027f2fcb77..9b68d913dc 100644 --- a/smtk/extension/qt/qtResourceBrowser.cxx +++ b/smtk/extension/qt/qtResourceBrowser.cxx @@ -445,7 +445,10 @@ bool qtResourceBrowser::eventFilter(QObject* obj, QEvent* evnt) if (!op) { auto index = deleters.matchingOperation(*object); - op = operationManager->create(index); + if (index) + { + op = operationManager->create(index); + } } if (op && op->parameters()->associate(object)) { -- GitLab From cad8c8c701bb4a511891fa473129bafd7bda985e Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Mon, 13 Jun 2022 16:51:50 -0400 Subject: [PATCH 13/44] BUG: Fix handleCreated When inserting Descriptive Phrases into a parent that already has subphrases generated, if the Descriptive Phrase would of had children phrases, they would not be generated. Now the new phrase's subphrases are always generated. --- smtk/view/PhraseModel.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smtk/view/PhraseModel.cxx b/smtk/view/PhraseModel.cxx index d331223050..7db21f987e 100644 --- a/smtk/view/PhraseModel.cxx +++ b/smtk/view/PhraseModel.cxx @@ -545,6 +545,10 @@ void PhraseModel::handleCreated(const smtk::resource::PersistentObjectSet& creat auto& children = parent->subphrases(); children.insert(children.begin() + path.back(), batch.begin(), batch.end()); this->trigger(parent, PhraseModelEvent::INSERT_FINISHED, idx, idx, insertRange); + for (const auto& childPhrase : batch) + { + childPhrase->subphrases(); // make sure the children subphrases are built + } } } -- GitLab From 8974873c50c4bbe36c6d0de7bc1f706a19815eb9 Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Tue, 14 Jun 2022 17:12:46 -0400 Subject: [PATCH 14/44] Fix display of AttributePanel when a scrollbar is requested. An extra call to `layout->addWidget()` was mistakenly added during the dock-widget refactor. --- .../paraview/appcomponents/pqSMTKAttributePanel.cxx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx index bd27977973..830a4b58ac 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx @@ -50,8 +50,9 @@ pqSMTKAttributePanel::pqSMTKAttributePanel(QWidget* parent) : Superclass(parent) { this->setObjectName("pqSMTKAttributePanel"); - this->updateTitle(); this->setLayout(new QVBoxLayout); + this->layout()->setObjectName("pqSMTKAttributePanel_layout"); + this->updateTitle(); auto* behavior = pqSMTKBehavior::instance(); QObject::connect( behavior, @@ -319,10 +320,6 @@ bool pqSMTKAttributePanel::displayView(smtk::view::ConfigurationPtr view) return false; } auto* qview = m_attrUIMgr->setSMTKView(view, this); - if (qview) - { - this->layout()->addWidget(qview->widget()); - } return qview != nullptr; } -- GitLab From 31919134677b08a218245a33ae89442e1b9bc868 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:18:58 -0400 Subject: [PATCH 15/44] Create file browser filter only when specified --- smtk/extension/qt/qtFileItem.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/smtk/extension/qt/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 208d6ea945..288f1dd2d3 100644 --- a/smtk/extension/qt/qtFileItem.cxx +++ b/smtk/extension/qt/qtFileItem.cxx @@ -625,8 +625,11 @@ bool qtFileItem::onLaunchFileBrowser() } m_internals->FileBrowser->setFileMode(mode); m_internals->FileBrowser->setWindowTitle(title); - QStringList name_filters = filters.split(";;"); - m_internals->FileBrowser->setNameFilters(name_filters); + if (!filters.isEmpty()) + { + QStringList name_filters = filters.split(";;"); + m_internals->FileBrowser->setNameFilters(name_filters); + } // This is needed for Macs since mode alone is not enough to allow the user to // chose a non-existent file if (mode == QFileDialog::AnyFile) -- GitLab From 4bbc921e3142e8aa24851d4fc838877fa0904408 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:21:41 -0400 Subject: [PATCH 16/44] Add pybind11 methods for operation manager * registered() * unregisterOperation() --- smtk/operation/pybind11/PybindManager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smtk/operation/pybind11/PybindManager.h b/smtk/operation/pybind11/PybindManager.h index ff1cc51f90..0eb5552a17 100644 --- a/smtk/operation/pybind11/PybindManager.h +++ b/smtk/operation/pybind11/PybindManager.h @@ -45,10 +45,12 @@ inline PySharedPtrClass< smtk::operation::Manager > pybind11_init_smtk_operation .def("metadataObservers", (smtk::operation::Metadata::Observers const & (smtk::operation::Manager::*)() const) &smtk::operation::Manager::metadataObservers) .def("observers", (smtk::operation::Observers & (smtk::operation::Manager::*)()) &smtk::operation::Manager::observers, pybind11::return_value_policy::reference_internal) .def("observers", (smtk::operation::Observers const & (smtk::operation::Manager::*)() const) &smtk::operation::Manager::observers, pybind11::return_value_policy::reference_internal) + .def("registered", (bool (smtk::operation::Manager::*)(const std::string&) const) &smtk::operation::Manager::registered, py::arg("typeName")) .def("registerResourceManager", &smtk::operation::Manager::registerResourceManager, py::arg("arg0")) .def("registerOperation", [](smtk::operation::Manager& manager, const std::string& moduleName, const std::string& opName){ return smtk::operation::ImportPythonOperation::importOperation(manager, moduleName, opName); }) + .def("unregisterOperation", (bool (smtk::operation::Manager::*)(const std::string&)) &smtk::operation::Manager::unregisterOperation, py::arg("typeName")) ; return instance; } -- GitLab From 606b946acf1c02ca11d8da908a82a4715df9d808 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:31:17 -0400 Subject: [PATCH 17/44] Allow instanced attributes to be declared multiple times --- smtk/smtk/attribute_builder.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/smtk/smtk/attribute_builder.py b/smtk/smtk/attribute_builder.py index 7919d6bf0f..0de1f36375 100644 --- a/smtk/smtk/attribute_builder.py +++ b/smtk/smtk/attribute_builder.py @@ -173,6 +173,7 @@ class AttributeBuilder: return self._post_message('Generating instanced attributes') + self.att_resource = att_resource self._recursive_create_instanced_atts(att_resource, top_view.details()) instanced_count = len(att_resource.attributes()) self._post_message( @@ -231,16 +232,23 @@ class AttributeBuilder: ent = model_resource.findEntity(uuid) self.pedigree_lookup[key] = ent - def _create_attribute(self, att_type, att_name=None): + def _create_attribute(self, att_type, att_name=None, exists_ok=False): """""" - self._post_message( - 'Create attribute type \"{}\", name \"{}\"'.format(att_type, att_name)) - # Make sure name not already used + # Check if name already used if att_name is not None: att = self.att_resource.findAttribute(att_name) - assert att is None, 'attribute name {} already used'.format( - att_name) + if att is not None: + if exists_ok: + message = 'Return existing attribute type \"{}\", name \"{}\"'.format( + att_type, att_name) + self._post_message(message) + return att + else: + assert False, 'attribute name {} already used'.format( + att_name) + self._post_message( + 'Create attribute type \"{}\", name \"{}\"'.format(att_type, att_name)) defn = self.att_resource.findDefinition(att_type) assert defn is not None, 'missing att definition {}'.format(att_type) @@ -274,7 +282,7 @@ class AttributeBuilder: att_comp = atts_comp.child(i) att_name = att_comp.attributes().get('Name') att_type = att_comp.attributes().get('Type') - self._create_attribute(att_type, att_name) + self._create_attribute(att_type, att_name, exists_ok=True) def _create_selector_view_att(self, att_resource, view): """Create attribute specified in selector view.""" -- GitLab From 3d5b56777aeb9d513b2ebd44d9a30bbf6d0fa81e Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:18:58 -0400 Subject: [PATCH 18/44] Create file browser filter only when specified --- smtk/extension/qt/qtFileItem.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/smtk/extension/qt/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 208d6ea945..288f1dd2d3 100644 --- a/smtk/extension/qt/qtFileItem.cxx +++ b/smtk/extension/qt/qtFileItem.cxx @@ -625,8 +625,11 @@ bool qtFileItem::onLaunchFileBrowser() } m_internals->FileBrowser->setFileMode(mode); m_internals->FileBrowser->setWindowTitle(title); - QStringList name_filters = filters.split(";;"); - m_internals->FileBrowser->setNameFilters(name_filters); + if (!filters.isEmpty()) + { + QStringList name_filters = filters.split(";;"); + m_internals->FileBrowser->setNameFilters(name_filters); + } // This is needed for Macs since mode alone is not enough to allow the user to // chose a non-existent file if (mode == QFileDialog::AnyFile) -- GitLab From f2adfeaf233a64fdc7eb4494958b64e63a24d114 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:21:41 -0400 Subject: [PATCH 19/44] Add pybind11 methods for operation manager * registered() * unregisterOperation() --- smtk/operation/pybind11/PybindManager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smtk/operation/pybind11/PybindManager.h b/smtk/operation/pybind11/PybindManager.h index ff1cc51f90..0eb5552a17 100644 --- a/smtk/operation/pybind11/PybindManager.h +++ b/smtk/operation/pybind11/PybindManager.h @@ -45,10 +45,12 @@ inline PySharedPtrClass< smtk::operation::Manager > pybind11_init_smtk_operation .def("metadataObservers", (smtk::operation::Metadata::Observers const & (smtk::operation::Manager::*)() const) &smtk::operation::Manager::metadataObservers) .def("observers", (smtk::operation::Observers & (smtk::operation::Manager::*)()) &smtk::operation::Manager::observers, pybind11::return_value_policy::reference_internal) .def("observers", (smtk::operation::Observers const & (smtk::operation::Manager::*)() const) &smtk::operation::Manager::observers, pybind11::return_value_policy::reference_internal) + .def("registered", (bool (smtk::operation::Manager::*)(const std::string&) const) &smtk::operation::Manager::registered, py::arg("typeName")) .def("registerResourceManager", &smtk::operation::Manager::registerResourceManager, py::arg("arg0")) .def("registerOperation", [](smtk::operation::Manager& manager, const std::string& moduleName, const std::string& opName){ return smtk::operation::ImportPythonOperation::importOperation(manager, moduleName, opName); }) + .def("unregisterOperation", (bool (smtk::operation::Manager::*)(const std::string&)) &smtk::operation::Manager::unregisterOperation, py::arg("typeName")) ; return instance; } -- GitLab From 25fe6c6903bd482000b7f2b70c583ff0520a60a6 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 7 Jun 2022 14:31:17 -0400 Subject: [PATCH 20/44] Allow instanced attributes to be declared multiple times --- smtk/smtk/attribute_builder.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/smtk/smtk/attribute_builder.py b/smtk/smtk/attribute_builder.py index 7919d6bf0f..0de1f36375 100644 --- a/smtk/smtk/attribute_builder.py +++ b/smtk/smtk/attribute_builder.py @@ -173,6 +173,7 @@ class AttributeBuilder: return self._post_message('Generating instanced attributes') + self.att_resource = att_resource self._recursive_create_instanced_atts(att_resource, top_view.details()) instanced_count = len(att_resource.attributes()) self._post_message( @@ -231,16 +232,23 @@ class AttributeBuilder: ent = model_resource.findEntity(uuid) self.pedigree_lookup[key] = ent - def _create_attribute(self, att_type, att_name=None): + def _create_attribute(self, att_type, att_name=None, exists_ok=False): """""" - self._post_message( - 'Create attribute type \"{}\", name \"{}\"'.format(att_type, att_name)) - # Make sure name not already used + # Check if name already used if att_name is not None: att = self.att_resource.findAttribute(att_name) - assert att is None, 'attribute name {} already used'.format( - att_name) + if att is not None: + if exists_ok: + message = 'Return existing attribute type \"{}\", name \"{}\"'.format( + att_type, att_name) + self._post_message(message) + return att + else: + assert False, 'attribute name {} already used'.format( + att_name) + self._post_message( + 'Create attribute type \"{}\", name \"{}\"'.format(att_type, att_name)) defn = self.att_resource.findDefinition(att_type) assert defn is not None, 'missing att definition {}'.format(att_type) @@ -274,7 +282,7 @@ class AttributeBuilder: att_comp = atts_comp.child(i) att_name = att_comp.attributes().get('Name') att_type = att_comp.attributes().get('Type') - self._create_attribute(att_type, att_name) + self._create_attribute(att_type, att_name, exists_ok=True) def _create_selector_view_att(self, att_resource, view): """Create attribute specified in selector view.""" -- GitLab From 20a6d976eea63a8a8ecc44b3c434ddbeef795ccf Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Wed, 8 Jun 2022 15:45:08 -0400 Subject: [PATCH 21/44] Hide QLabel when text is blank (space characters) * Could instead only create the QLabel for non-blank text, but not worth the added code complexity. * Also take out logic to use name if label empty (item already does that) --- .../attribute_collection/labelExamples.sbt | 301 ++++++++++++++++++ smtk/extension/qt/qtDateTimeItem.cxx | 15 +- smtk/extension/qt/qtFileItem.cxx | 16 +- smtk/extension/qt/qtGroupItem.cxx | 4 + smtk/extension/qt/qtInputsItem.cxx | 14 +- smtk/extension/qt/qtReferenceItemEditor.cxx | 16 +- smtk/extension/qt/qtVoidItem.cxx | 10 +- 7 files changed, 338 insertions(+), 38 deletions(-) create mode 100644 data/attribute/attribute_collection/labelExamples.sbt diff --git a/data/attribute/attribute_collection/labelExamples.sbt b/data/attribute/attribute_collection/labelExamples.sbt new file mode 100644 index 0000000000..6641271722 --- /dev/null +++ b/data/attribute/attribute_collection/labelExamples.sbt @@ -0,0 +1,301 @@ + + + + + + + + 1 + + + 1 + + + + + + + + + + + 2.71828 + 3.14159 + + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + 2.71828 + 3.14159 + + + + + + + + + + + + + + Nada + + + + + + + + + + One Child + + Int1 + + + + + + + + + + + + Two Children + + Int1 + Int2 + + + + + + + + + + + + Reference Item + + ReferenceItem + + + + + + + + + + + + Date Time + + DateTime + + + + + + + + + + + + File Item + + FileItem + + + + + + + + + + + + Group Item (one subgroup) + + GroupItem + + + + + + + + + + + + + All + + Int1 + Int2 + ReferenceItem + DateTime + FileItem + GroupItem + + + + No Children + + One Child + + Int1 + + + + Two Children + + Int1 + Int2 + + + + Reference Item + + ReferenceItem + + + + Date Time + + DateTime + + + + File Item + + FileItem + + + + Group Item + + GroupItem + + + + + + + + + + + + + All + + Int1 + Int2 + ReferenceItem + DateTime + FileItem + OptionalItem + VoidItem + + + No Children + + One Child + + Int1 + + + + Two Children + + Int1 + Int2 + + + + + + + + + + + + + + + + + + + + + diff --git a/smtk/extension/qt/qtDateTimeItem.cxx b/smtk/extension/qt/qtDateTimeItem.cxx index 92521487de..0b902938b1 100644 --- a/smtk/extension/qt/qtDateTimeItem.cxx +++ b/smtk/extension/qt/qtDateTimeItem.cxx @@ -427,15 +427,7 @@ void qtDateTimeItem::updateUI() } auto itemDef = dataObj->definitionAs(); - QString labelText; - if (!dataObj->label().empty()) - { - labelText = dataObj->label().c_str(); - } - else - { - labelText = dataObj->name().c_str(); - } + QString labelText = dataObj->label().c_str(); QLabel* label = new QLabel(labelText, m_widget); label->setObjectName("label"); label->setSizePolicy(sizeFixedPolicy); @@ -463,6 +455,11 @@ void qtDateTimeItem::updateUI() labelLayout->addWidget(label); this->Internals->theLabel = label; + if (label->text().trimmed().isEmpty()) + { + this->setLabelVisible(false); + } + this->loadInputValues(); // we need this layout so that for items with conditionan children, diff --git a/smtk/extension/qt/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 288f1dd2d3..697e11c31d 100644 --- a/smtk/extension/qt/qtFileItem.cxx +++ b/smtk/extension/qt/qtFileItem.cxx @@ -943,15 +943,7 @@ void qtFileItem::updateUI() } } - QString labelText; - if (!item->label().empty()) - { - labelText = item->label().c_str(); - } - else - { - labelText = item->name().c_str(); - } + QString labelText = item->label().c_str(); QLabel* label = new QLabel(labelText, m_widget); label->setObjectName("label"); label->setSizePolicy(sizeFixedPolicy); @@ -975,6 +967,12 @@ void qtFileItem::updateUI() } labelLayout->addWidget(label); m_internals->theLabel = label; + + if (label->text().trimmed().isEmpty()) + { + this->setLabelVisible(false); + } + top->addLayout(labelLayout); // Create a frame to hold the item's contents diff --git a/smtk/extension/qt/qtGroupItem.cxx b/smtk/extension/qt/qtGroupItem.cxx index 483f92aa5f..a501a491d5 100644 --- a/smtk/extension/qt/qtGroupItem.cxx +++ b/smtk/extension/qt/qtGroupItem.cxx @@ -155,6 +155,10 @@ void qtGroupItem::createWidget() m_internals->m_titleLabel = new QLabel(title, m_internals->m_titleFrame); m_internals->m_titleLabel->setObjectName("Title"); + if (title.trimmed().isEmpty()) + { + this->setLabelVisible(false); + } titleLayout->addWidget(m_internals->m_titleLabel); m_internals->m_alertLabel = new QLabel(m_internals->m_titleFrame); diff --git a/smtk/extension/qt/qtInputsItem.cxx b/smtk/extension/qt/qtInputsItem.cxx index 20fbaa8312..9810f2c52d 100644 --- a/smtk/extension/qt/qtInputsItem.cxx +++ b/smtk/extension/qt/qtInputsItem.cxx @@ -829,15 +829,7 @@ QFrame* qtInputsItem::createLabelFrame( } } - QString labelText; - if (!vitem->label().empty()) - { - labelText = vitem->label().c_str(); - } - else - { - labelText = vitem->name().c_str(); - } + QString labelText = vitem->label().c_str(); QLabel* label = new QLabel(labelText, m_widget); label->setObjectName("label"); label->setSizePolicy(sizeFixedPolicy); @@ -884,6 +876,10 @@ QFrame* qtInputsItem::createLabelFrame( } labelLayout->addWidget(label); m_internals->theLabel = label; + if (label->text().trimmed().isEmpty()) + { + this->setLabelVisible(false); + } if (vitem->allowsExpressions()) { m_internals->m_expressionButton = new QToolButton(m_widget); diff --git a/smtk/extension/qt/qtReferenceItemEditor.cxx b/smtk/extension/qt/qtReferenceItemEditor.cxx index 2fa5b10eb5..5da8cc356d 100644 --- a/smtk/extension/qt/qtReferenceItemEditor.cxx +++ b/smtk/extension/qt/qtReferenceItemEditor.cxx @@ -238,15 +238,7 @@ void qtReferenceItemEditor::createWidget() } auto itemDef = item->definitionAs(); - QString labelText; - if (!item->label().empty()) - { - labelText = item->label().c_str(); - } - else - { - labelText = item->name().c_str(); - } + QString labelText = item->label().c_str(); QLabel* label = new QLabel(labelText, comboFrame); label->setSizePolicy(sizeFixedPolicy); auto* iview = m_itemInfo.baseView(); @@ -272,6 +264,12 @@ void qtReferenceItemEditor::createWidget() label->setFont(m_itemInfo.uiManager()->advancedFont()); } labelLayout->addWidget(label); + + if (label->text().trimmed().isEmpty()) + { + label->setVisible(false); + } + m_internals->m_theLabel = label; m_internals->m_comboBox = new QComboBox(comboFrame); m_internals->m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); diff --git a/smtk/extension/qt/qtVoidItem.cxx b/smtk/extension/qt/qtVoidItem.cxx index 0d1afd69e5..f67dfb5b8f 100644 --- a/smtk/extension/qt/qtVoidItem.cxx +++ b/smtk/extension/qt/qtVoidItem.cxx @@ -56,7 +56,7 @@ void qtVoidItem::setLabelVisible(bool visible) return; } - QString txtLabel = dataObj->label().empty() ? dataObj->name().c_str() : dataObj->label().c_str(); + QString txtLabel = dataObj->label().c_str(); this->Internals->optionalCheck->setText(visible ? txtLabel : ""); } @@ -84,6 +84,7 @@ void qtVoidItem::createWidget() QSizePolicy sizeFixedPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QString txtLabel = dataObj->label().c_str(); + bool labelIsBlank = txtLabel.trimmed().isEmpty(); // If the item is optional then use a check-box else use a label if (dataObj->isOptional()) { @@ -112,10 +113,15 @@ void qtVoidItem::createWidget() optionalCheck->setText(txtLabel); QObject::connect(optionalCheck, SIGNAL(stateChanged(int)), this, SLOT(setOutputOptional(int))); this->Internals->optionalCheck = optionalCheck; + if (labelIsBlank) + { + this->setLabelVisible(false); + } + m_widget->layout()->addWidget(this->Internals->optionalCheck); this->updateItemData(); } - else + else if (!labelIsBlank) { auto* label = new QLabel(m_widget); label->setObjectName("label"); -- GitLab From cb4e1faf78abfb481bd55002773bbf9b21180265 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Sun, 12 Jun 2022 10:34:06 -0400 Subject: [PATCH 22/44] Change alignment to top for horizontal layouts --- data/attribute/attribute_collection/labelExamples.sbt | 4 ++-- smtk/extension/qt/qtDiscreteValueEditor.cxx | 3 +++ smtk/extension/qt/qtReferenceItemEditor.cxx | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/data/attribute/attribute_collection/labelExamples.sbt b/data/attribute/attribute_collection/labelExamples.sbt index 6641271722..09867147a7 100644 --- a/data/attribute/attribute_collection/labelExamples.sbt +++ b/data/attribute/attribute_collection/labelExamples.sbt @@ -261,8 +261,8 @@ ReferenceItem DateTime FileItem - OptionalItem + GroupItem + OptionalItem VoidItem diff --git a/smtk/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index e7160657b3..476d3ed29e 100644 --- a/smtk/extension/qt/qtDiscreteValueEditor.cxx +++ b/smtk/extension/qt/qtDiscreteValueEditor.cxx @@ -98,6 +98,7 @@ void qtDiscreteValueEditor::createWidget() this->Internals->clearChildItems(); QBoxLayout* wlayout = new QVBoxLayout(this); wlayout->setMargin(0); + wlayout->setAlignment(Qt::AlignTop); if (!item || !item->isDiscrete()) { return; @@ -369,6 +370,8 @@ void qtDiscreteValueEditor::updateContents() this->Internals->m_childrenFrame->setObjectName("ChildItemsFrame"); QSizePolicy sizeFixedPolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); QHBoxLayout* clayout = new QHBoxLayout(this->Internals->m_childrenFrame); + this->Internals->m_parentLayout->setAlignment(Qt::AlignTop); + clayout->setAlignment(Qt::AlignTop); clayout->setMargin(0); this->Internals->m_childrenFrame->setSizePolicy(sizeFixedPolicy); diff --git a/smtk/extension/qt/qtReferenceItemEditor.cxx b/smtk/extension/qt/qtReferenceItemEditor.cxx index 5da8cc356d..dc0bb8a3b3 100644 --- a/smtk/extension/qt/qtReferenceItemEditor.cxx +++ b/smtk/extension/qt/qtReferenceItemEditor.cxx @@ -209,21 +209,21 @@ void qtReferenceItemEditor::createWidget() m_internals->m_mainLayout = new QVBoxLayout(m_widget); m_internals->m_mainLayout->setMargin(0); m_internals->m_mainLayout->setSpacing(0); - m_internals->m_mainLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + m_internals->m_mainLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); QFrame* comboFrame = new QFrame(m_widget); comboFrame->setObjectName("Combo Frame"); QHBoxLayout* entryLayout = new QHBoxLayout(comboFrame); entryLayout->setMargin(0); entryLayout->setSpacing(0); - entryLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + entryLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); QSizePolicy sizeFixedPolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QHBoxLayout* labelLayout = new QHBoxLayout(); labelLayout->setMargin(0); labelLayout->setSpacing(0); - labelLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + labelLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); int padding = 0; if (item->isOptional()) { @@ -247,7 +247,7 @@ void qtReferenceItemEditor::createWidget() label->setFixedWidth(iview->fixedLabelWidth() - padding); } label->setWordWrap(true); - label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + label->setAlignment(Qt::AlignLeft | Qt::AlignTop); // qtOverlayFilter *filter = new qtOverlayFilter(this); // label->installEventFilter(filter); -- GitLab From 9e664fe290efb6ff0397092f61c449efc211ea35 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Sun, 12 Jun 2022 10:36:53 -0400 Subject: [PATCH 23/44] Rename childLayout -> parentLayout to eliminate confusion (it is not the childFrame layout) --- smtk/extension/qt/qtDiscreteValueEditor.cxx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/smtk/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index 476d3ed29e..3583e431cf 100644 --- a/smtk/extension/qt/qtDiscreteValueEditor.cxx +++ b/smtk/extension/qt/qtDiscreteValueEditor.cxx @@ -32,10 +32,10 @@ using namespace smtk::extension; class qtDiscreteValueEditorInternals { public: - qtDiscreteValueEditorInternals(qtInputsItem* item, int elementIdx, QLayout* childLayout) + qtDiscreteValueEditorInternals(qtInputsItem* item, int elementIdx, QLayout* parentLayout) : m_inputItem(item) , m_elementIndex(elementIdx) - , m_childrenLayout(childLayout) + , m_parentLayout(parentLayout) { m_hintChildWidth = 0; m_hintChildHeight = 0; @@ -47,7 +47,7 @@ public: QPointer m_childrenFrame; QList m_childItems; - QPointer m_childrenLayout; + QPointer m_parentLayout; int m_hintChildWidth; int m_hintChildHeight; std::map m_itemViewMap; @@ -65,11 +65,11 @@ public: qtDiscreteValueEditor::qtDiscreteValueEditor( qtInputsItem* item, int elementIdx, - QLayout* childLayout) + QLayout* parentLayout) : QWidget(item->widget()) , m_useSelectionManager(false) { - this->Internals = new qtDiscreteValueEditorInternals(item, elementIdx, childLayout); + this->Internals = new qtDiscreteValueEditorInternals(item, elementIdx, parentLayout); if (item != nullptr) { item->m_itemInfo.createNewDictionary(this->Internals->m_itemViewMap); @@ -353,9 +353,9 @@ void qtDiscreteValueEditor::updateContents() this->Internals->m_hintChildHeight = 0; if (this->Internals->m_childrenFrame) { - if (this->Internals->m_childrenLayout) + if (this->Internals->m_parentLayout) { - this->Internals->m_childrenLayout->removeWidget(this->Internals->m_childrenFrame); + this->Internals->m_parentLayout->removeWidget(this->Internals->m_childrenFrame); } else { @@ -443,9 +443,9 @@ void qtDiscreteValueEditor::updateContents() this->Internals->m_hintChildWidth = this->Internals->m_childrenFrame->width(); this->Internals->m_hintChildHeight = this->Internals->m_childrenFrame->height(); this->Internals->m_childrenFrame->setVisible(hasVisibleChildren); - if (this->Internals->m_childrenLayout) + if (this->Internals->m_parentLayout) { - this->Internals->m_childrenLayout->addWidget(this->Internals->m_childrenFrame); + this->Internals->m_parentLayout->addWidget(this->Internals->m_childrenFrame); } else { -- GitLab From e2d6a75f3e5a30c3b9d0fe20361280314618aad5 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Sun, 12 Jun 2022 11:24:46 -0400 Subject: [PATCH 24/44] Add logic for Layout="Vertical" option (ItemView) * qtInputsItem changes childLayout and grid position * qtDiscreteValueEditor changes its layout --- .../attribute_collection/labelExamples.sbt | 12 +++++----- smtk/extension/qt/qtDiscreteValueEditor.cxx | 19 +++++++++++---- smtk/extension/qt/qtInputsItem.cxx | 23 +++++++++++++++++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/data/attribute/attribute_collection/labelExamples.sbt b/data/attribute/attribute_collection/labelExamples.sbt index 09867147a7..c8271958ed 100644 --- a/data/attribute/attribute_collection/labelExamples.sbt +++ b/data/attribute/attribute_collection/labelExamples.sbt @@ -49,8 +49,8 @@ 3.14159 - - + + @@ -149,7 +149,7 @@ - + @@ -233,7 +233,7 @@ GroupItem - + diff --git a/smtk/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index 3583e431cf..51db12c2a8 100644 --- a/smtk/extension/qt/qtDiscreteValueEditor.cxx +++ b/smtk/extension/qt/qtDiscreteValueEditor.cxx @@ -369,10 +369,21 @@ void qtDiscreteValueEditor::updateContents() this->Internals->m_childrenFrame = new QFrame(this); this->Internals->m_childrenFrame->setObjectName("ChildItemsFrame"); QSizePolicy sizeFixedPolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - QHBoxLayout* clayout = new QHBoxLayout(this->Internals->m_childrenFrame); - this->Internals->m_parentLayout->setAlignment(Qt::AlignTop); - clayout->setAlignment(Qt::AlignTop); - clayout->setMargin(0); + + QBoxLayout* clayout = nullptr; + if (qobject_cast(this->Internals->m_parentLayout)) + { + clayout = new QHBoxLayout(this->Internals->m_childrenFrame); + this->Internals->m_parentLayout->setAlignment(Qt::AlignTop); + clayout->setAlignment(Qt::AlignTop); + clayout->setContentsMargins(0, 0, 0, 0); + } + else + { + clayout = new QVBoxLayout(this->Internals->m_childrenFrame); + } + + clayout->setObjectName("activeChildLayout"); this->Internals->m_childrenFrame->setSizePolicy(sizeFixedPolicy); QList activeChildDefs; diff --git a/smtk/extension/qt/qtInputsItem.cxx b/smtk/extension/qt/qtInputsItem.cxx index 9810f2c52d..9bdb15c425 100644 --- a/smtk/extension/qt/qtInputsItem.cxx +++ b/smtk/extension/qt/qtInputsItem.cxx @@ -246,6 +246,14 @@ qtInputsItem::qtInputsItem(const qtAttributeItemInfo& info) // See if we are suppose to override it m_itemInfo.component().attributeAsInt("EditPrecision", m_internals->m_editPrecision); + // Check for "Layout" ItemView + std::string layout; + bool found = info.component().attribute("Layout", layout); + if (found && layout == "Vertical") + { + m_internals->VectorItemOrient = Qt::Vertical; + } + this->createWidget(); } @@ -675,7 +683,16 @@ void qtInputsItem::addInputEditor(int i) QBoxLayout* childLayout = nullptr; if (item->isDiscrete()) { - childLayout = new QVBoxLayout; + if (m_internals->VectorItemOrient == Qt::Vertical) + { + childLayout = new QVBoxLayout; + } + else + { + childLayout = new QHBoxLayout; + childLayout->setContentsMargins(4, 0, 0, 0); + } + childLayout->setObjectName(QString("childLayout%1").arg(i)); childLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); } @@ -734,7 +751,9 @@ void qtInputsItem::addInputEditor(int i) // combo boxes. if (item->isDiscrete() && childLayout) { - m_internals->EntryLayout->addLayout(childLayout, row, 2); + int row = m_internals->VectorItemOrient == Qt::Vertical ? 2 : 1; + int col = m_internals->VectorItemOrient == Qt::Vertical ? 1 : 2; + m_internals->EntryLayout->addLayout(childLayout, row, col); } } else // going horizontal -- GitLab From 01d6e91560c817891133c52245734b4544491ccd Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Mon, 13 Jun 2022 17:53:54 -0400 Subject: [PATCH 25/44] Extend orientation code and move into new getOrientation() method Also add release note --- doc/release/notes/qtitem_layout.rst | 27 ++++++++ smtk/extension/qt/qtInputsItem.cxx | 95 ++++++++++++++++++++++++++--- smtk/extension/qt/qtInputsItem.h | 3 + 3 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 doc/release/notes/qtitem_layout.rst diff --git a/doc/release/notes/qtitem_layout.rst b/doc/release/notes/qtitem_layout.rst new file mode 100644 index 0000000000..7ba878c9c3 --- /dev/null +++ b/doc/release/notes/qtitem_layout.rst @@ -0,0 +1,27 @@ +qtItem changes +--------------- + +Several changes were made to the `qtItem` subclasses. + +1\. The new code hides the QLabel instance for an item if its label is +set to a (nonempty) blank string. Template writers use a whitespace +character to hide the label, however, a QFrame is still displayed and +takes up horizontal space. The new code essentially removes that unwanted +space. + +2\. The new code changes the Qt alignment for horizontal child-item layouts +from vertical-center to top, for aesthetic reasons. + +3\. The new code updates the logic for setting the layout direction +(horizontal or vertical) in `qtInputsItem` for various situations. + + * For ordinary value items, the default layout is horizontal, but can be + overridden by an ItemView ``. + * For extensible items, the layout is *always* vertical, and cannot be + overridden by an ItemView. + * For discrete value items with children items, the layout is either: + (a) horizontal, if each discrete value is assigned no child items or a + single child item having a blank string for its label; otherwise + (b) vertical. The discrete item layout can be overridden by an item + view, either `` or + ``. diff --git a/smtk/extension/qt/qtInputsItem.cxx b/smtk/extension/qt/qtInputsItem.cxx index 9bdb15c425..80e8468df8 100644 --- a/smtk/extension/qt/qtInputsItem.cxx +++ b/smtk/extension/qt/qtInputsItem.cxx @@ -51,6 +51,7 @@ #include "smtk/attribute/ValueItemTemplate.h" #include "smtk/common/CompilerInformation.h" +#include "smtk/common/StringUtil.h" #include @@ -203,6 +204,16 @@ class qtInputsItemInternals public: QPointer EntryLayout; QPointer theLabel; + + // VectorItemOrient stores the layout orientation (horizontal or vertical) for either + // item values or children items. Defaults are: + // 1. Ordinary value items => values layout is horizontal + // 2. Extensible values => values layout is vertical + // 3a. Discrete items with active children => children item layout is vertical EXCEPT: + // 3b. Discrete item with each value assigned 0 or 1 child item with empty label => + // children item layout is horizontal + // Cases 1, 3a, 3b can by overridden with an ItemView attribute Layout="Horizontal" + // or Layout="Vertical" Qt::Orientation VectorItemOrient; // for discrete items that with potential child widget @@ -241,19 +252,11 @@ qtInputsItem::qtInputsItem(const qtAttributeItemInfo& info) { m_internals = new qtInputsItemInternals; m_isLeafItem = true; - m_internals->VectorItemOrient = Qt::Horizontal; + m_internals->VectorItemOrient = this->getOrientation(info); m_internals->m_editPrecision = 0; // Use full precision by default // See if we are suppose to override it m_itemInfo.component().attributeAsInt("EditPrecision", m_internals->m_editPrecision); - // Check for "Layout" ItemView - std::string layout; - bool found = info.component().attribute("Layout", layout); - if (found && layout == "Vertical") - { - m_internals->VectorItemOrient = Qt::Vertical; - } - this->createWidget(); } @@ -2077,3 +2080,77 @@ bool qtInputsItem::isFixedWidth() const // larger than 0 then its fixed width return (widthValue > 0); } + +Qt::Orientation qtInputsItem::getOrientation(const qtAttributeItemInfo& info) +{ + // Carries out logic listed above for setting internals member VectorItemOrient. + auto valueItem = info.itemAs(); + if (valueItem == nullptr) // safety first + { + return Qt::Horizontal; + } + + // Extensible items are *always* vertical (cannot override) + if (valueItem->isExtensible()) + { + return Qt::Vertical; + } + + // Check for "Layout" ItemView + std::string layout; + bool hasLayoutSpec = info.component().attribute("Layout", layout); + if (hasLayoutSpec && layout == "Horizontal") + { + return Qt::Horizontal; + } + else if (hasLayoutSpec && layout == "Vertical") + { + return Qt::Vertical; + } + + // For non-discrete item, default layout is horizontal + if (!valueItem->isDiscrete()) + { + return Qt::Horizontal; + } + + // For discrete items, use horizontal layout (only) if + // * All children items have "blank" label (whitespace) + // * All discrete values have 0 or 1 child item + + // Check all children items for blank label. + auto valueItemDef = std::dynamic_pointer_cast( + info.item()->definition()); + const std::map& childrenDefs = + valueItemDef->childrenItemDefinitions(); + auto defIter = childrenDefs.begin(); + for (; defIter != childrenDefs.end(); ++defIter) + { + auto childDef = defIter->second; + std::string label = childDef->label(); + std::string trimmed = smtk::common::StringUtil::trim(label); + if (!trimmed.empty()) + { + return Qt::Vertical; + } + } // for (defIter) + + // Next check if all discrete values have 0 or 1 child item. + // If more than 1, use vertical layout. + std::string ename; + std::vector childItems; + std::size_t numValues = valueItemDef->numberOfDiscreteValues(); + for (std::size_t i = 0; i < numValues; ++i) + { + ename = valueItemDef->discreteEnum(i); + childItems = valueItemDef->conditionalItems(ename); + if (childItems.size() > 1) + { + return Qt::Vertical; + } + } // for (i) + + // If we reach this point, with all values having 0 or 1 child item with no label, + // use horizontal layout + return Qt::Horizontal; +} diff --git a/smtk/extension/qt/qtInputsItem.h b/smtk/extension/qt/qtInputsItem.h index f6319c95d7..dabd0e2998 100644 --- a/smtk/extension/qt/qtInputsItem.h +++ b/smtk/extension/qt/qtInputsItem.h @@ -108,6 +108,9 @@ protected: // background. void showExpressionResultWidgets(bool success, const QString& text, const QString& tooltip); + /** \brief Determines (horizontal/vertical) orientation for values or children items. */ + Qt::Orientation getOrientation(const qtAttributeItemInfo& info); + private: qtInputsItemInternals* m_internals; }; // class -- GitLab From 8ad78f7b2e9bac5dd262adde0919685de9f41fe0 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Tue, 14 Jun 2022 17:13:38 -0400 Subject: [PATCH 26/44] Recast labelExamples.sbt to show examples of each case --- .../attribute_collection/labelExamples.sbt | 255 +++++++----------- 1 file changed, 96 insertions(+), 159 deletions(-) diff --git a/data/attribute/attribute_collection/labelExamples.sbt b/data/attribute/attribute_collection/labelExamples.sbt index c8271958ed..dfb1cddf42 100644 --- a/data/attribute/attribute_collection/labelExamples.sbt +++ b/data/attribute/attribute_collection/labelExamples.sbt @@ -17,33 +17,7 @@ - - - 2.71828 - 3.14159 - - - - - - - - - - - 1 - - - 1 - - - - - - - - - + 2.71828 3.14159 @@ -56,132 +30,56 @@ - + - - - Nada - - - - - - - - - - One Child - - Int1 - - - - - - - - - - - - Two Children - - Int1 - Int2 - - - - - - - - - - - - Reference Item - - ReferenceItem - - - - - - - - - + + 1.1 + + 1.1,2.2,3.3 + + - - Date Time - - DateTime - - - - - - - - - - - - File Item - - FileItem - - + alpha + omega - - - - - + + + 4.4,5.5,6.6 + + - - Group Item (one subgroup) - - GroupItem - - + beta + gamma + + - - - - + + + + + + 0.0 + + - - Optional Item - - OptionalItem - - + beta + gamma + + - + + + + - + - - Void Item (not optional) - - VoidItem - - - - - - - - - - All @@ -191,8 +89,8 @@ DateTime FileItem GroupItem - + OptionalItem + VoidItem No Children @@ -248,51 +146,90 @@ - + + - + + 1 + - + + No Children - All + One Child Int1 - Int2 - ReferenceItem - DateTime - FileItem - GroupItem - OptionalItem - VoidItem + + + + + + + 1 + 2 + + No Children One Child - Int1 + Int3 Two Children - Int1 - Int2 + Int3 + Int4 - + + - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + -- GitLab From 4c4acfb8dbc3f8bcfb37fa1b3963d54c228d7855 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Thu, 16 Jun 2022 09:56:39 -0400 Subject: [PATCH 27/44] Rename labelExamples.sbt to layoutExamples.sbt --- .../{labelExamples.sbt => layoutExamples.sbt} | 0 doc/release/notes/qtitem_layout.rst | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename data/attribute/attribute_collection/{labelExamples.sbt => layoutExamples.sbt} (100%) diff --git a/data/attribute/attribute_collection/labelExamples.sbt b/data/attribute/attribute_collection/layoutExamples.sbt similarity index 100% rename from data/attribute/attribute_collection/labelExamples.sbt rename to data/attribute/attribute_collection/layoutExamples.sbt diff --git a/doc/release/notes/qtitem_layout.rst b/doc/release/notes/qtitem_layout.rst index 7ba878c9c3..c3cd02a726 100644 --- a/doc/release/notes/qtitem_layout.rst +++ b/doc/release/notes/qtitem_layout.rst @@ -23,5 +23,5 @@ from vertical-center to top, for aesthetic reasons. (a) horizontal, if each discrete value is assigned no child items or a single child item having a blank string for its label; otherwise (b) vertical. The discrete item layout can be overridden by an item - view, either `` or + view, either `` or ``. -- GitLab From 918da2827c525673c55a13567c9c3350351446ff Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Fri, 20 May 2022 13:26:56 -0400 Subject: [PATCH 28/44] Add a optional search bar to qtResourceBrowser. The search bar is added and a `QSortFilterProxyModel` is used if the "SearchBar" flag is set in the configuration attributes. Enable alphabetic sort in the resource browser, using the proxy model. --- doc/release/notes/resource-search-bar.rst | 7 ++++ .../qt/ResourcePanelConfiguration.json | 3 +- smtk/extension/qt/qtResourceBrowser.cxx | 6 ++- smtk/extension/qt/qtResourceBrowserP.cxx | 37 +++++++++++++++++-- smtk/extension/qt/qtResourceBrowserP.h | 9 ++++- 5 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 doc/release/notes/resource-search-bar.rst diff --git a/doc/release/notes/resource-search-bar.rst b/doc/release/notes/resource-search-bar.rst new file mode 100644 index 0000000000..59273ee902 --- /dev/null +++ b/doc/release/notes/resource-search-bar.rst @@ -0,0 +1,7 @@ +Resource panel search bar +------------------------- + +A search bar has been added to the resource panel by default. Users may search +for resource or components using a wildcard text-based search. The search bar +is specified in the JSON config by adding `"SearchBar": true` to the +`Attributes` group. diff --git a/smtk/extension/qt/ResourcePanelConfiguration.json b/smtk/extension/qt/ResourcePanelConfiguration.json index c7292bbe87..ff80db09db 100644 --- a/smtk/extension/qt/ResourcePanelConfiguration.json +++ b/smtk/extension/qt/ResourcePanelConfiguration.json @@ -7,7 +7,8 @@ "Attributes": { "Title": "Resources", "TopLevel": true, - "Widget": "ResourceTree" + "Widget": "ResourceTree", + "SearchBar": true }, "Children": [ { diff --git a/smtk/extension/qt/qtResourceBrowser.cxx b/smtk/extension/qt/qtResourceBrowser.cxx index 9b68d913dc..e901c776de 100644 --- a/smtk/extension/qt/qtResourceBrowser.cxx +++ b/smtk/extension/qt/qtResourceBrowser.cxx @@ -75,6 +75,7 @@ qtResourceBrowser::qtResourceBrowser(const smtk::view::Information& info) QAbstractItemModel* qtPhraseModel = nullptr; smtk::view::SelectionPtr selection; const auto& view = this->configuration(); + bool searchBar = false; if (view) { // empty Widget attribute is OK, will use default. @@ -83,8 +84,10 @@ qtResourceBrowser::qtResourceBrowser(const smtk::view::Information& info) phraseModel = manager->phraseModelFactory().createFromConfiguration(view.get()); qtPhraseModel = new smtk::extension::qtDescriptivePhraseModel; selection = this->uiManager()->selection(); + searchBar = view->details().attributeAsBool("SearchBar"); } - m_p->setup(this, phraseModel, modelViewType, qtPhraseModel, this->parentWidget(), selection); + m_p->setup( + this, phraseModel, modelViewType, qtPhraseModel, this->parentWidget(), selection, searchBar); this->Widget = m_p->m_container; } @@ -102,6 +105,7 @@ QTreeView* qtResourceBrowser::createDefaultView(QWidget* parent) view->setDragDropMode(QAbstractItemView::DragDrop); view->setSelectionMode(QAbstractItemView::ExtendedSelection); view->setSortingEnabled(true); + view->sortByColumn(0, Qt::AscendingOrder); return view; } diff --git a/smtk/extension/qt/qtResourceBrowserP.cxx b/smtk/extension/qt/qtResourceBrowserP.cxx index 05139b6c25..42300f2e2d 100644 --- a/smtk/extension/qt/qtResourceBrowserP.cxx +++ b/smtk/extension/qt/qtResourceBrowserP.cxx @@ -18,7 +18,9 @@ #include "smtk/io/Logger.h" #include +#include #include +#include #include #include @@ -51,7 +53,8 @@ void qtResourceBrowser::Internal::setup( const std::string& viewName, QAbstractItemModel* qmodel, QWidget* parent, - const std::shared_ptr& selection) + const std::shared_ptr& selection, + bool searchBar) { m_self = self; if (m_container) @@ -80,6 +83,25 @@ void qtResourceBrowser::Internal::setup( m_container->setObjectName("qtResourceBrowser"); m_layout = new QVBoxLayout(m_container); m_layout->setObjectName("m_layout"); + // Always use for sorting, but not always for search (filtering) + m_filter = new QSortFilterProxyModel(m_container); + m_filter->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_filter->setSortCaseSensitivity(Qt::CaseInsensitive); + // so we can see parents if children are matched. + m_filter->setRecursiveFilteringEnabled(true); + + if (searchBar) + { + m_search = new QLineEdit(m_container); + m_search->setObjectName("Search"); + m_search->setPlaceholderText("Search"); + auto* controlLayout = new QHBoxLayout(); + controlLayout->setObjectName("controlLayout"); + m_layout->addItem(controlLayout); + controlLayout->addWidget(m_search); + QObject::connect( + m_search, &QLineEdit::textChanged, m_filter, &QSortFilterProxyModel::setFilterWildcard); + } m_view = ctor(parent); @@ -111,7 +133,8 @@ void qtResourceBrowser::Internal::setup( m_delegate->setDrawSubtitle(false); m_delegate->setSelection(selection); // Used for badge actions - m_view->setModel(m_model); + m_filter->setSourceModel(m_model); + m_view->setModel(m_filter); m_view->setItemDelegate(m_delegate); m_view->setMouseTracking(true); // Needed to receive hover events. // Connect signals @@ -141,7 +164,15 @@ qtDescriptivePhraseModel* qtResourceBrowser::Internal::descriptivePhraseModel() void qtResourceBrowser::Internal::setDescriptivePhraseModel(QAbstractItemModel* qmodel) { m_model = qmodel; - m_view->setModel(m_model); + if (m_filter) + { + m_filter->setSourceModel(m_model); + m_view->setModel(m_filter); + } + else + { + m_view->setModel(m_model); + } QObject::connect( m_view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), diff --git a/smtk/extension/qt/qtResourceBrowserP.h b/smtk/extension/qt/qtResourceBrowserP.h index ae5c58a7a8..f190cb7dc9 100644 --- a/smtk/extension/qt/qtResourceBrowserP.h +++ b/smtk/extension/qt/qtResourceBrowserP.h @@ -19,6 +19,8 @@ class QAbstractItemModel; class QAbstractItemView; +class QLineEdit; +class QSortFilterProxyModel; class QTreeView; class QVBoxLayout; @@ -43,7 +45,8 @@ public: QAbstractItemModel* qmodel, QWidget* parent, const std::shared_ptr& selection = - std::shared_ptr()); + std::shared_ptr(), + bool searchBar = false); smtk::extension::qtDescriptivePhraseModel* descriptivePhraseModel() const; void setDescriptivePhraseModel(QAbstractItemModel* qmodel); @@ -66,6 +69,10 @@ public: std::string m_viewName; std::string m_resourceTreeType; // "default" or specific type. int m_resourceTreeStyle{ -1 }; // Which default subphrase generator should be used? + /// A proxy model for users to search by name. + QPointer m_filter; + /// An optional search bar for users. + QPointer m_search; // Set to true when inside sendSMTKSelectionToPanel. // Used to avoid updating the SMTK selection from the panel while -- GitLab From 3be0953e0173cd44acf27c5ac13b1a10c58db4fb Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Fri, 17 Jun 2022 11:19:18 -0400 Subject: [PATCH 29/44] BUG: Adding Missing Top Alignment for InstancedViews The issue is when Instanced Views contain a scroll area, expanding it caused internal widgets to spread out in order to fill the space. By adding top alignment to the layout, the widgets no longer change their vertical position when excess space is present. --- smtk/extension/qt/qtInstancedView.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/smtk/extension/qt/qtInstancedView.cxx b/smtk/extension/qt/qtInstancedView.cxx index 4a298bce36..a313331109 100644 --- a/smtk/extension/qt/qtInstancedView.cxx +++ b/smtk/extension/qt/qtInstancedView.cxx @@ -104,6 +104,7 @@ void qtInstancedView::createWidget() //create the layout for the tabs area QVBoxLayout* layout = new QVBoxLayout(this->Widget); layout->setMargin(0); + layout->setAlignment(Qt::AlignTop); this->Widget->setLayout(layout); this->updateUI(); -- GitLab From 83ecb67883bd804b546e58b51e67e442caa983d7 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Wed, 22 Jun 2022 15:37:09 -0400 Subject: [PATCH 30/44] Fix a race condition. When an operation that removes a component completes, it is possible for the component to be destroyed (if, for example, the operation's result does not properly hold shared-pointer references to keep it in memory until operation observers complete). Verify that components have not expired their weak pointer before derefencing our cached pointer to get the name. --- smtk/view/ComponentPhraseContent.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smtk/view/ComponentPhraseContent.cxx b/smtk/view/ComponentPhraseContent.cxx index 91581f28cd..8dd352cf21 100644 --- a/smtk/view/ComponentPhraseContent.cxx +++ b/smtk/view/ComponentPhraseContent.cxx @@ -101,7 +101,8 @@ bool ComponentPhraseContent::editable(ContentType contentType) const std::string ComponentPhraseContent::stringValue(ContentType contentType) const { - if (auto* component = m_rawComponent) + auto* component = m_rawComponent; + if (!m_component.expired() && component) { switch (contentType) { -- GitLab From 6542e09ea6f0ebf673e58100cdc5f384e690b094 Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Thu, 16 Jun 2022 15:55:23 -0400 Subject: [PATCH 31/44] Add a context menu to attribute input items to reset to default. Also don't reset the item to default if the item is unset during construction - leave it to the item to apply a default value. This includes file items, multiline string, spinboxes, DateTime. Also fix exception in DateTimeZonePair when invalid json is encountered, and add a test. --- doc/release/notes/qtitem_reset_to_default.rst | 16 ++ smtk/attribute/DateTimeItem.cxx | 11 ++ smtk/attribute/DateTimeItem.h | 1 + smtk/attribute/pybind11/PybindDateTimeItem.h | 1 + smtk/common/DateTimeZonePair.cxx | 15 +- .../testing/cxx/UnitTestDateTimeZonePair.cxx | 21 +++ smtk/extension/qt/qtDateTimeItem.cxx | 63 ++++++++ smtk/extension/qt/qtDateTimeItem.h | 1 + smtk/extension/qt/qtDiscreteValueEditor.cxx | 31 +++- smtk/extension/qt/qtFileItem.cxx | 49 ++++++ smtk/extension/qt/qtFileItem.h | 1 + smtk/extension/qt/qtInputsItem.cxx | 153 ++++++++++++++++-- smtk/extension/qt/qtInputsItem.h | 3 + 13 files changed, 351 insertions(+), 15 deletions(-) create mode 100644 doc/release/notes/qtitem_reset_to_default.rst diff --git a/doc/release/notes/qtitem_reset_to_default.rst b/doc/release/notes/qtitem_reset_to_default.rst new file mode 100644 index 0000000000..b0c9cdea8b --- /dev/null +++ b/doc/release/notes/qtitem_reset_to_default.rst @@ -0,0 +1,16 @@ +Attribute items have a "Reset to Default" context menu item +----------------------------------------------------------- + +All the widget used to input values for attribute items have +a context menu item added called "Reset to Default", which will +change the value back to the default, if one is specified. If +no default is specified, the menu entry is disabled. + +Int, Double, String, File, and DateTime items are all supported, +including spinbox and multi-line views. Resource items can't have +a default specified. + +As a result, `qtInputItem` no longer set themselves back to the +default value when constructed - the default value is only +applied by the `ValueItem` when created, or when the user +chooses "Reset to Default". diff --git a/smtk/attribute/DateTimeItem.cxx b/smtk/attribute/DateTimeItem.cxx index bc2cffc56b..4c6d482098 100644 --- a/smtk/attribute/DateTimeItem.cxx +++ b/smtk/attribute/DateTimeItem.cxx @@ -167,6 +167,17 @@ bool DateTimeItem::isUsingDefault() const return true; } +bool DateTimeItem::hasDefault() const +{ + const DateTimeItemDefinition* def = + static_cast(m_definition.get()); + if (!def) + { + return false; + } + return def->hasDefault(); +} + bool DateTimeItem::assign(ConstItemPtr& sourceItem, unsigned int options) { // Assigns my contents to be same as sourceItem diff --git a/smtk/attribute/DateTimeItem.h b/smtk/attribute/DateTimeItem.h index d40f11d776..4f9eefde4e 100644 --- a/smtk/attribute/DateTimeItem.h +++ b/smtk/attribute/DateTimeItem.h @@ -49,6 +49,7 @@ public: virtual bool isUsingDefault(std::size_t elementIndex) const; // This method tests all of the values of the items w/r the default value virtual bool isUsingDefault() const; + bool hasDefault() const; virtual bool isSet(std::size_t element = 0) const { return m_isSet.size() > element ? m_isSet[element] : false; diff --git a/smtk/attribute/pybind11/PybindDateTimeItem.h b/smtk/attribute/pybind11/PybindDateTimeItem.h index 4fc91e01dc..a8865b287d 100644 --- a/smtk/attribute/pybind11/PybindDateTimeItem.h +++ b/smtk/attribute/pybind11/PybindDateTimeItem.h @@ -30,6 +30,7 @@ inline PySharedPtrClass< smtk::attribute::DateTimeItem, smtk::attribute::Item > .def("isSet", &smtk::attribute::DateTimeItem::isSet, py::arg("element") = 0) .def("isUsingDefault", (bool (smtk::attribute::DateTimeItem::*)(::std::size_t) const) &smtk::attribute::DateTimeItem::isUsingDefault, py::arg("elementIndex")) .def("isUsingDefault", (bool (smtk::attribute::DateTimeItem::*)() const) &smtk::attribute::DateTimeItem::isUsingDefault) + .def("hasDefault", &smtk::attribute::DateTimeItem::hasDefault) .def("numberOfRequiredValues", &smtk::attribute::DateTimeItem::numberOfRequiredValues) .def("numberOfValues", &smtk::attribute::DateTimeItem::numberOfValues) .def("reset", &smtk::attribute::DateTimeItem::reset) diff --git a/smtk/common/DateTimeZonePair.cxx b/smtk/common/DateTimeZonePair.cxx index 61e434650a..63ce150439 100644 --- a/smtk/common/DateTimeZonePair.cxx +++ b/smtk/common/DateTimeZonePair.cxx @@ -11,6 +11,7 @@ #include "smtk/common/DateTimeZonePair.h" #include "nlohmann/json.hpp" #include // for snprintf() +#include #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf(buf, cnt, fmt, ...) _snprintf_s(buf, cnt, cnt, fmt, __VA_ARGS__) @@ -76,7 +77,19 @@ std::string DateTimeZonePair::serialize() const bool DateTimeZonePair::deserialize(const std::string& content) { - nlohmann::json inputJson = nlohmann::json::parse(content); + nlohmann::json inputJson; + try + { + inputJson = nlohmann::json::parse(content); + } + catch (...) + { + std::cerr << "Not valid json for DateTimeZonePair object: " << content << std::endl; + std::cerr << " Follow the form: " + "{\"datetime\":\"20220620T000000\",\"timezone-region\":\"America/New_York\"}" + << std::endl; + return false; + } if (inputJson.type() != nlohmann::json::value_t::object) { std::cerr << "Missing or invalid DateTimeZonePair object: " << content << std::endl; diff --git a/smtk/common/testing/cxx/UnitTestDateTimeZonePair.cxx b/smtk/common/testing/cxx/UnitTestDateTimeZonePair.cxx index 24f1fe5612..8514d8cc11 100644 --- a/smtk/common/testing/cxx/UnitTestDateTimeZonePair.cxx +++ b/smtk/common/testing/cxx/UnitTestDateTimeZonePair.cxx @@ -37,6 +37,26 @@ void verifyNotSet() test(!tzIn1.isSet(), "Failed to show timezone as not set"); } +void verifyParsers() +{ + std::cout << "verifyParsers()" << std::endl; + // Using DateTime::deserialize(): + sc::DateTimeZonePair dtzInvalid; + dtzInvalid.deserialize(""); + test(!dtzInvalid.dateTime().isSet(), "Failed to detect empty (invalid) iso string"); + test(!dtzInvalid.deserialize("20160231"), "failed to detect invalid json"); + + // Other forms are tested in UnitTestDateTime + sc::DateTimeZonePair dtzValid; + test( + !!dtzValid.deserialize( + "{\"datetime\":\"20220620T000000\",\"timezone-region\":\"America/New_York\"}"), + "Failed to deserialize valid json DateTimeZonePair"); + test( + !!dtzValid.dateTime().isSet() && !!dtzValid.timeZone().isSet(), + "Failed to return true for isSet()"); +} + void verifyNoTimeZone() { std::cout << "verifyNoTimeZone()" << std::endl; @@ -197,6 +217,7 @@ void verifyPosixTimeZone() int UnitTestDateTimeZonePair(int /*unused*/, char** const /*unused*/) { verifyNotSet(); + verifyParsers(); verifyTimeZoneOnly(); verifyNoTimeZone(); verifyUTC(); diff --git a/smtk/extension/qt/qtDateTimeItem.cxx b/smtk/extension/qt/qtDateTimeItem.cxx index 0b902938b1..6caad8c302 100644 --- a/smtk/extension/qt/qtDateTimeItem.cxx +++ b/smtk/extension/qt/qtDateTimeItem.cxx @@ -22,6 +22,7 @@ #include "smtk/common/TimeZone.h" #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include #include @@ -215,6 +218,10 @@ QWidget* qtDateTimeItem::createDateTimeWidget(int elementIdx) layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(dtEdit); + // add "Reset to Default" to context menu + // QDateTimeEdit don't provide their context menus - so we add an action after it's shown + dtEdit->installEventFilter(this); + if (def->useTimeZone()) { this->Internals->TimeZoneButton = new QToolButton(frame); @@ -247,6 +254,57 @@ QWidget* qtDateTimeItem::createDateTimeWidget(int elementIdx) return frame; } +bool qtDateTimeItem::eventFilter(QObject* filterObj, QEvent* ev) +{ + auto* dtEdit = qobject_cast(filterObj); + if (ev->type() == QEvent::ContextMenu && dtEdit) + { + int elementIdx = this->Internals->ElementIndexMap.value(dtEdit); + QPointer self(this); + // we want the default context menu, we just add something to it. + QTimer::singleShot(0, this, [this, self, elementIdx, dtEdit]() { + if (!self) + { + return; + } + // find the menu that was just displayed by name. + for (QWidget* w : QApplication::topLevelWidgets()) + { + auto* contextMenu = qobject_cast(w); + if (contextMenu && w->objectName() == "qt_edit_menu") + { + auto* resetDefault = new QAction("Reset to Default"); + auto item = self->m_itemInfo.itemAs(); + if (item && item->hasDefault()) + { + QObject::connect(resetDefault, &QAction::triggered, this, [self, elementIdx, dtEdit]() { + if (!self) + { + return; + } + auto item = self->m_itemInfo.itemAs(); + if (item && dtEdit) + { + item->setToDefault(elementIdx); + // do we really have to re-create the widget? + self->clearChildWidgets(); + self->updateItemData(); + return; + } + }); + } + else + { + resetDefault->setEnabled(false); + } + contextMenu->addAction(resetDefault); + } + } + }); + } + return QObject::eventFilter(filterObj, ev); +} + void qtDateTimeItem::setOutputOptional(int state) { auto item = m_itemInfo.itemAs(); @@ -394,6 +452,11 @@ void qtDateTimeItem::updateUI() return; } + if (m_widget) + { + delete m_widget; + } + m_widget = new QFrame(m_itemInfo.parentWidget()); m_widget->setObjectName(dataObj->name().c_str()); if (this->isReadOnly()) diff --git a/smtk/extension/qt/qtDateTimeItem.h b/smtk/extension/qt/qtDateTimeItem.h index afc5f051d3..7fc738a510 100644 --- a/smtk/extension/qt/qtDateTimeItem.h +++ b/smtk/extension/qt/qtDateTimeItem.h @@ -36,6 +36,7 @@ public: qtDateTimeItem(const qtAttributeItemInfo& info); ~qtDateTimeItem() override; void setLabelVisible(bool) override; + bool eventFilter(QObject* filterObj, QEvent* ev) override; public Q_SLOTS: void setOutputOptional(int); diff --git a/smtk/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index 51db12c2a8..0892a825cb 100644 --- a/smtk/extension/qt/qtDiscreteValueEditor.cxx +++ b/smtk/extension/qt/qtDiscreteValueEditor.cxx @@ -12,6 +12,7 @@ #include "smtk/extension/qt/qtInputsItem.h" +#include #include #include #include @@ -167,6 +168,32 @@ void qtDiscreteValueEditor::createWidget() } }, Qt::QueuedConnection); + // Add a context menu + auto* resetDefault = new QAction("Reset to Default", combo); + if (item->hasDefault()) + { + QObject::connect(resetDefault, &QAction::triggered, this, [guardedObject, combo]() { + if (!guardedObject) + { + return; + } + auto item = guardedObject->Internals->m_inputItem->itemAs(); + if (item) + { + int elementIdx = guardedObject->Internals->m_elementIndex; + item->setToDefault(elementIdx); + guardedObject->updateItemData(); + guardedObject->updateContents(); + } + }); + } + else + { + resetDefault->setEnabled(false); + } + combo->addAction(resetDefault); + combo->setContextMenuPolicy(Qt::ActionsContextMenu); + wlayout->addWidget(combo); this->Internals->m_combo = combo; this->updateItemData(); @@ -209,10 +236,6 @@ void qtDiscreteValueEditor::updateItemData() } return; } - if (setIndex < 0 && itemDef->hasDefault()) - { - setIndex = itemDef->defaultDiscreteIndex(); - } // We need to find the correct Item in the combo box int i, numItems = combo->count(); for (i = 0; i < numItems; i++) diff --git a/smtk/extension/qt/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 697e11c31d..22ac0e009b 100644 --- a/smtk/extension/qt/qtFileItem.cxx +++ b/smtk/extension/qt/qtFileItem.cxx @@ -14,6 +14,7 @@ #include "smtk/extension/qt/qtOverlay.h" #include "smtk/extension/qt/qtUIManager.h" +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -393,9 +395,56 @@ QWidget* qtFileItem::createFileBrowseWidget( QObject::connect(fileBrowserButton, SIGNAL(clicked()), this, SLOT(onLaunchFileBrowser())); + // add custom context menu item for reset to default + lineEdit->setContextMenuPolicy(Qt::CustomContextMenu); + QPointer self(this); + QObject::connect( + lineEdit, &QLineEdit::customContextMenuRequested, this, [self, elementIdx](const QPoint& pt) { + if (!self) + { + return; + } + self->showContextMenu(pt, elementIdx); + }); + return frame; } +void qtFileItem::showContextMenu(const QPoint& pt, int elementIdx) +{ + QLineEdit* const lineEdit = qobject_cast(QObject::sender()); + auto item = this->m_itemInfo.itemAs(); + if (!lineEdit || !item) + { + return; + } + QMenu* menu = lineEdit->createStandardContextMenu(); + auto* resetDefault = new QAction("Reset to Default"); + if (item->hasDefault()) + { + QPointer self(this); + QObject::connect(resetDefault, &QAction::triggered, this, [self, elementIdx, lineEdit]() { + if (!self) + { + return; + } + auto item = self->m_itemInfo.itemAs(); + if (item) + { + item->setToDefault(elementIdx); + self->updateEditorValue(elementIdx); + } + }); + } + else + { + resetDefault->setEnabled(false); + } + menu->addAction(resetDefault); + menu->exec(lineEdit->mapToGlobal(pt)); + delete menu; +} + void qtFileItem::onUpdateItemValue() { QWidget* editor = qobject_cast(sender()); diff --git a/smtk/extension/qt/qtFileItem.h b/smtk/extension/qt/qtFileItem.h index 602053144c..746149736d 100644 --- a/smtk/extension/qt/qtFileItem.h +++ b/smtk/extension/qt/qtFileItem.h @@ -105,6 +105,7 @@ public Q_SLOTS: void setOutputOptional(int); virtual bool onLaunchFileBrowser(); void updateItemData() override; + void showContextMenu(const QPoint& pt, int elementIdx); Q_SIGNALS: bool launchFileBrowser(); diff --git a/smtk/extension/qt/qtInputsItem.cxx b/smtk/extension/qt/qtInputsItem.cxx index 80e8468df8..e56bc2044c 100644 --- a/smtk/extension/qt/qtInputsItem.cxx +++ b/smtk/extension/qt/qtInputsItem.cxx @@ -20,20 +20,25 @@ #include "smtk/extension/qt/qtUIManager.h" #include "smtk/io/Logger.h" +#include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -1716,13 +1721,6 @@ QWidget* qtInputsItem::createEditBox(int elementIdx, QWidget* pWidget) QVariant vdata(elementIdx); QString tooltip; - // If the item is not set but has a default lets use it - if (!item->isSet(elementIdx) && item->hasDefault()) - { - item->setToDefault(elementIdx); - Q_EMIT this->modified(); - } - switch (item->type()) { case smtk::attribute::Item::DoubleType: @@ -1812,21 +1810,156 @@ QWidget* qtInputsItem::createEditBox(int elementIdx, QWidget* pWidget) { inputWidget->setToolTip(tooltip); } - if (QLineEdit* const editBox = qobject_cast(inputWidget)) + QPointer self(this); + if (QLineEdit* const lineEdit = qobject_cast(inputWidget)) { QObject::connect( - editBox, + lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onLineEditChanged()), Qt::QueuedConnection); QObject::connect( - editBox, SIGNAL(editingFinished()), this, SLOT(onLineEditFinished()), Qt::QueuedConnection); + lineEdit, SIGNAL(editingFinished()), this, SLOT(onLineEditFinished()), Qt::QueuedConnection); + lineEdit->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect( + lineEdit, &QLineEdit::customContextMenuRequested, this, [self, elementIdx](const QPoint& pt) { + if (!self) + { + return; + } + self->showContextMenu(pt, elementIdx); + }); + } + else if (QTextEdit* const textEdit = qobject_cast(inputWidget)) + { + textEdit->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect( + textEdit, &QTextEdit::customContextMenuRequested, this, [self, elementIdx](const QPoint& pt) { + if (!self) + { + return; + } + self->showContextMenu(pt, elementIdx); + }); + } + else if (auto* const spinbox = qobject_cast(inputWidget)) + { + // spin boxes don't provide their context menus - so we add an action after it's shown + spinbox->installEventFilter(this); } return inputWidget; } +void qtInputsItem::showContextMenu(const QPoint& pt, int elementIdx) +{ + QLineEdit* const lineEdit = qobject_cast(QObject::sender()); + QTextEdit* const textEdit = qobject_cast(QObject::sender()); + auto item = this->m_itemInfo.itemAs(); + if (!(textEdit || lineEdit) || !item) + { + return; + } + QMenu* menu = + (lineEdit ? lineEdit->createStandardContextMenu() : textEdit->createStandardContextMenu()); + auto* resetDefault = new QAction("Reset to Default"); + if (item->hasDefault()) + { + QPointer self(this); + QObject::connect( + resetDefault, &QAction::triggered, this, [self, elementIdx, lineEdit, textEdit]() { + if (!self) + { + return; + } + auto item = self->m_itemInfo.itemAs(); + if (item) + { + item->setToDefault(elementIdx); + if (lineEdit) + { + lineEdit->setText(item->valueAsString(elementIdx).c_str()); + } + else if (textEdit) + { + textEdit->setText(item->valueAsString(elementIdx).c_str()); + } + Q_EMIT self->modified(); + } + }); + } + else + { + resetDefault->setEnabled(false); + } + menu->addAction(resetDefault); + menu->exec(lineEdit ? lineEdit->mapToGlobal(pt) : textEdit->mapToGlobal(pt)); + delete menu; +} + +bool qtInputsItem::eventFilter(QObject* filterObj, QEvent* ev) +{ + auto* spinbox = qobject_cast(filterObj); + if (ev->type() == QEvent::ContextMenu && spinbox) + { + int elementIdx = spinbox->property("ElementIndex").toInt(); + QPointer self(this); + // we want the default context menu, we just add something to it. + QTimer::singleShot(0, this, [self, this, elementIdx, spinbox]() { + if (!self) + { + return; + } + // find the menu that was just displayed by name. + for (QWidget* w : QApplication::topLevelWidgets()) + { + auto* contextMenu = qobject_cast(w); + if (contextMenu && w->objectName() == "qt_edit_menu") + { + // create a reset to default action and append to the end. + auto* resetDefault = new QAction("Reset to Default"); + auto item = self->m_itemInfo.itemAs(); + if (item && item->hasDefault()) + { + QObject::connect( + resetDefault, &QAction::triggered, this, [self, elementIdx, spinbox]() { + if (!self) + { + return; + } + auto item = self->m_itemInfo.itemAs(); + auto* intBox = qobject_cast(spinbox); + if (item && intBox) + { + item->setToDefault(elementIdx); + intBox->setValue(item->value(elementIdx)); + Q_EMIT self->modified(); + return; + } + auto ditem = self->m_itemInfo.itemAs(); + auto* dblBox = qobject_cast(spinbox); + if (ditem && dblBox) + { + ditem->setToDefault(elementIdx); + dblBox->setValue(ditem->value(elementIdx)); + Q_EMIT self->modified(); + return; + } + }); + } + else + { + resetDefault->setEnabled(false); + } + contextMenu->addAction(resetDefault); + } + } + }); + } + return QObject::eventFilter(filterObj, ev); +} + void qtInputsItem::onTextEditChanged() { this->onInputValueChanged(QObject::sender()); diff --git a/smtk/extension/qt/qtInputsItem.h b/smtk/extension/qt/qtInputsItem.h index dabd0e2998..4d9f329a1f 100644 --- a/smtk/extension/qt/qtInputsItem.h +++ b/smtk/extension/qt/qtInputsItem.h @@ -24,6 +24,7 @@ class QBoxLayout; class QFrame; class QLayout; class QLineEdit; +class QPoint; namespace smtk { @@ -48,6 +49,7 @@ public: /// Used mainly by helper classes like qtDiscreteValueEditor void forceUpdate(); bool isFixedWidth() const override; + bool eventFilter(QObject* filterObj, QEvent* ev) override; public Q_SLOTS: void setOutputOptional(int); @@ -60,6 +62,7 @@ public Q_SLOTS: void intValueChanged(int newVal); void updateItemData() override; // void setUseSelectionManager(bool mode) override; + void showContextMenu(const QPoint& pt, int elementIdx); protected Q_SLOTS: virtual void onAddNewValue(); -- GitLab From 6af6ee367d4dc73636891fc256bb1077703b1ab6 Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Fri, 24 Jun 2022 10:55:08 -0400 Subject: [PATCH 32/44] Fix qtFileItem initialization when using recent files option. We should always populate the combo box choices when re-creating the qt widget. --- smtk/extension/qt/qtFileItem.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/smtk/extension/qt/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 697e11c31d..1fd7a2b200 100644 --- a/smtk/extension/qt/qtFileItem.cxx +++ b/smtk/extension/qt/qtFileItem.cxx @@ -351,10 +351,8 @@ QWidget* qtFileItem::createFileBrowseWidget( std::string valText = item.valueAsString(elementIdx); if (fileCombo) { - if (this->updateRecentValues(valText)) - { - this->updateFileComboLists(); - } + this->updateRecentValues(valText); + this->updateFileComboLists(); fileCombo->setCurrentIndex(fileCombo->findText(valText.c_str())); } else -- GitLab From 54468a4743b0dc5c5036e2e8fb75a8524528a2d0 Mon Sep 17 00:00:00 2001 From: Aron Helser Date: Fri, 24 Jun 2022 13:38:10 -0400 Subject: [PATCH 33/44] Split project plugin into core and gui. Clients can use the project functionality without loading the default project menu item and project view panel. --- smtk/extension/paraview/CMakeLists.txt | 3 ++- .../project/plugin-core/CMakeLists.txt | 26 +++++++++++++++++++ .../project/plugin-core/paraview.plugin | 4 +++ .../{plugin => plugin-gui}/CMakeLists.txt | 18 +++++-------- .../{plugin => plugin-gui}/paraview.plugin | 2 +- 5 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 smtk/extension/paraview/project/plugin-core/CMakeLists.txt create mode 100644 smtk/extension/paraview/project/plugin-core/paraview.plugin rename smtk/extension/paraview/project/{plugin => plugin-gui}/CMakeLists.txt (63%) rename smtk/extension/paraview/project/{plugin => plugin-gui}/paraview.plugin (50%) diff --git a/smtk/extension/paraview/CMakeLists.txt b/smtk/extension/paraview/CMakeLists.txt index 98f275d648..9effc6fa0c 100644 --- a/smtk/extension/paraview/CMakeLists.txt +++ b/smtk/extension/paraview/CMakeLists.txt @@ -39,7 +39,8 @@ if (TARGET ParaView::pqApplicationComponents) model/plugin/paraview.plugin mesh/plugin/paraview.plugin operators/paraview.plugin - project/plugin/paraview.plugin + project/plugin-core/paraview.plugin + project/plugin-gui/paraview.plugin ) if (ParaView_VERSION VERSION_GREATER_EQUAL "5.10.0") diff --git a/smtk/extension/paraview/project/plugin-core/CMakeLists.txt b/smtk/extension/paraview/project/plugin-core/CMakeLists.txt new file mode 100644 index 0000000000..5dce9bb808 --- /dev/null +++ b/smtk/extension/paraview/project/plugin-core/CMakeLists.txt @@ -0,0 +1,26 @@ +set(sources) + +set(interfaces) + +smtk_add_plugin(smtkProjectPlugin + REGISTRAR smtk::extension::paraview::project::Registrar + MANAGERS + smtk::common::Managers + smtk::operation::Manager + smtk::project::Manager + smtk::resource::Manager + smtk::view::Manager + PARAVIEW_PLUGIN_ARGS + VERSION "1.0" + UI_INTERFACES ${interfaces} + SOURCES ${sources} +) + +target_link_libraries(smtkProjectPlugin + PRIVATE + ParaView::pqApplicationComponents + smtkCore + smtkPQComponentsExt + smtkPQProjectExt + smtkPVServerExt +) diff --git a/smtk/extension/paraview/project/plugin-core/paraview.plugin b/smtk/extension/paraview/project/plugin-core/paraview.plugin new file mode 100644 index 0000000000..8cc954cd18 --- /dev/null +++ b/smtk/extension/paraview/project/plugin-core/paraview.plugin @@ -0,0 +1,4 @@ +NAME + smtkProjectPlugin +DESCRIPTION + SMTK project core plugin for ParaView diff --git a/smtk/extension/paraview/project/plugin/CMakeLists.txt b/smtk/extension/paraview/project/plugin-gui/CMakeLists.txt similarity index 63% rename from smtk/extension/paraview/project/plugin/CMakeLists.txt rename to smtk/extension/paraview/project/plugin-gui/CMakeLists.txt index ff45755872..ad3126aef1 100644 --- a/smtk/extension/paraview/project/plugin/CMakeLists.txt +++ b/smtk/extension/paraview/project/plugin-gui/CMakeLists.txt @@ -20,18 +20,11 @@ set(interfaces ${dock_interfaces} ) -smtk_add_plugin(smtkPQProjectPlugin - REGISTRAR smtk::extension::paraview::project::Registrar - MANAGERS - smtk::common::Managers - smtk::operation::Manager - smtk::project::Manager - smtk::resource::Manager - smtk::view::Manager - PARAVIEW_PLUGIN_ARGS - VERSION "1.0" - UI_INTERFACES ${interfaces} - SOURCES ${sources} +paraview_add_plugin(smtkPQProjectPlugin + VERSION "1.0" + REQUIRED_PLUGINS smtkProjectPlugin + UI_INTERFACES ${interfaces} + SOURCES ${sources} ) target_link_libraries(smtkPQProjectPlugin @@ -42,3 +35,4 @@ target_link_libraries(smtkPQProjectPlugin smtkPQProjectExt smtkPVServerExt ) +target_compile_definitions(smtkPQProjectPlugin PRIVATE QT_NO_KEYWORDS) diff --git a/smtk/extension/paraview/project/plugin/paraview.plugin b/smtk/extension/paraview/project/plugin-gui/paraview.plugin similarity index 50% rename from smtk/extension/paraview/project/plugin/paraview.plugin rename to smtk/extension/paraview/project/plugin-gui/paraview.plugin index aee5ac906c..7750c5575f 100644 --- a/smtk/extension/paraview/project/plugin/paraview.plugin +++ b/smtk/extension/paraview/project/plugin-gui/paraview.plugin @@ -1,4 +1,4 @@ NAME smtkPQProjectPlugin DESCRIPTION - SMTK project plugin for ParaView + SMTK project gui plugin for ParaView -- GitLab From 59a47edf524efc894e88339c1884437861b77587 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Sun, 3 Jul 2022 20:34:24 -0400 Subject: [PATCH 34/44] Fix AttributeBuilder.get_analysis_att() to check for analysis definition For atypical use-case putting analysis defintion in template file --- smtk/smtk/attribute_builder.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/smtk/smtk/attribute_builder.py b/smtk/smtk/attribute_builder.py index 0de1f36375..a2b68c15ac 100644 --- a/smtk/smtk/attribute_builder.py +++ b/smtk/smtk/attribute_builder.py @@ -155,9 +155,11 @@ class AttributeBuilder: if att is not None: return att - # Get definition and build attribute - defn_name = view_atts.get('AnalysisAttributeType') - defn = att_resource.analyses().buildAnalysesDefinition(att_resource, defn_name) + # Get analysis definition and attribute + defn_type = view_atts.get('AnalysisAttributeType') + defn = att_resource.findDefinition(defn_type) + if defn is None: + defn = att_resource.analyses().buildAnalysesDefinition(att_resource, defn_type) att = att_resource.createAttribute(att_name, defn) return att -- GitLab From 036fb61d114769a81e15aa38b2cbe0fff59f7345 Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 5 Jul 2022 16:59:40 -0400 Subject: [PATCH 35/44] ENH: qtInputsItem calling Signal Operator The instance will now call the Signal Operator when creating a new expression attribute. --- doc/release/notes/changesToQtInputsItem.rst | 4 +++ smtk/extension/qt/qtBaseAttributeView.cxx | 2 +- smtk/extension/qt/qtInputsItem.cxx | 39 ++++++++++++--------- 3 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 doc/release/notes/changesToQtInputsItem.rst diff --git a/doc/release/notes/changesToQtInputsItem.rst b/doc/release/notes/changesToQtInputsItem.rst new file mode 100644 index 0000000000..67ebe59c0d --- /dev/null +++ b/doc/release/notes/changesToQtInputsItem.rst @@ -0,0 +1,4 @@ +Changes to qtInputsItem +-------------------------- + +A qtInputsItem instance will now call the Signal Operator when creating a new expression attribute. diff --git a/smtk/extension/qt/qtBaseAttributeView.cxx b/smtk/extension/qt/qtBaseAttributeView.cxx index 090f2e2d43..d5db1e9101 100644 --- a/smtk/extension/qt/qtBaseAttributeView.cxx +++ b/smtk/extension/qt/qtBaseAttributeView.cxx @@ -241,7 +241,7 @@ void signalAttribute( const smtk::attribute::AttributePtr& attr, const char* itemName, std::vector items, - const std::string& source = "") + const std::string& source) { if (attr && uiManager && itemName && itemName[0]) { diff --git a/smtk/extension/qt/qtInputsItem.cxx b/smtk/extension/qt/qtInputsItem.cxx index e56bc2044c..ead928f347 100644 --- a/smtk/extension/qt/qtInputsItem.cxx +++ b/smtk/extension/qt/qtInputsItem.cxx @@ -10,8 +10,24 @@ #include "smtk/extension/qt/qtInputsItem.h" +#include "smtk/attribute/Attribute.h" #include "smtk/attribute/Definition.h" +#include "smtk/attribute/DoubleItem.h" +#include "smtk/attribute/DoubleItemDefinition.h" +#include "smtk/attribute/IntItem.h" +#include "smtk/attribute/IntItemDefinition.h" +#include "smtk/attribute/Resource.h" +#include "smtk/attribute/StringItem.h" +#include "smtk/attribute/StringItemDefinition.h" +#include "smtk/attribute/ValueItem.h" +#include "smtk/attribute/ValueItemDefinition.h" +#include "smtk/attribute/ValueItemTemplate.h" +#include "smtk/attribute/operators/Signal.h" #include "smtk/attribute/utility/Queries.h" + +#include "smtk/common/CompilerInformation.h" +#include "smtk/common/StringUtil.h" + #include "smtk/extension/qt/qtAttributeEditorDialog.h" #include "smtk/extension/qt/qtBaseAttributeView.h" #include "smtk/extension/qt/qtDiscreteValueEditor.h" @@ -43,21 +59,6 @@ #include #include -#include "smtk/attribute/Attribute.h" -#include "smtk/attribute/DoubleItem.h" -#include "smtk/attribute/DoubleItemDefinition.h" -#include "smtk/attribute/IntItem.h" -#include "smtk/attribute/IntItemDefinition.h" -#include "smtk/attribute/Resource.h" -#include "smtk/attribute/StringItem.h" -#include "smtk/attribute/StringItemDefinition.h" -#include "smtk/attribute/ValueItem.h" -#include "smtk/attribute/ValueItemDefinition.h" -#include "smtk/attribute/ValueItemTemplate.h" - -#include "smtk/common/CompilerInformation.h" -#include "smtk/common/StringUtil.h" - #include #if defined(SMTK_MSVC) && _MSC_VER <= 1500 @@ -1394,6 +1395,12 @@ void qtInputsItem::onExpressionReferenceChanged() // to the list of expression names and set the item to use it inputitem->setExpression(newAtt); itemsInComboBox.append(newAtt->name().c_str()); + + // Signal that a new attribute was created - since this instance is not + // observing the Operation Manager we don't need to set the source parameter + auto signalOp = this->uiManager()->operationManager()->create(); + signalOp->parameters()->findComponent("created")->appendValue(newAtt); + signalOp->operate(); } for (int index = 2; index < m_internals->m_expressionCombo->count(); index++) { @@ -1968,7 +1975,7 @@ void qtInputsItem::onTextEditChanged() void qtInputsItem::onLineEditChanged() { // Here we only handle changes when this is invoked from setText() - // which is normally used programatically, and the setText() will have + // which is normally used programmatically, and the setText() will have // modified flag reset to false; QLineEdit* const editBox = qobject_cast(QObject::sender()); if (!editBox) -- GitLab From 1503cb7d9801987fcce3f7b1d8bedad3b487c5a9 Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Thu, 23 Jun 2022 09:33:35 -0400 Subject: [PATCH 36/44] ENH: Enhancing Category Support Expanding SMTK Attribute Category Mechanism ------------------------------------------- Category Modeling in SMTK Attribute Resources has been enhanced to now support specialization as well as generalization. Previously, an Attribute or Item Definition's local categories could only expand (make more general) the categories it was inheriting (or choose to ignore them all together). With this release, SMTK now supports specializing (or making the category constraint mote restrictive). Previously category inheritance was controlled by using the Definition's setIsOkToInherit method which would either **Or** its local categories with those it was inheriting or **Replace** them. This method (as well as isOkToInherit method) has been deprecated. The new methods for setting and retrieving category inheritance are: * setCategoryInheritanceMode * categoryInheritanceMode The values that categoryInheritanceMode can be set to are: * smtk::attribute::Categories::CombinationMode::Or * smtk::attribute::Categories::CombinationMode::And * smtk::attribute::Categories::CombinationMode::LocalOnly Setting the mode to **Or** is the same as the previous setIsOkToInherit(true) - it will **or** the Definition's local categories with those that it is inheriting. Setting the mode to **And** will now **and** the Definition's local categories with those that it is inheriting. Setting the mode to **LocalOnly** will ignore the categories that the Definition is inheriting and is the same as the previous setIsOkToInherit(false). Changing the Default Category Inheritance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Previously the default mode was isOkToInherit = true which now corresponds to smtk::attribute::Categories::CombinationMode::Or. Upon discussing the new combination support of **And**, it was decided that the new default will be smtk::attribute::Categories::CombinationMode::And, meaning that a Definition will be more specialized category-wise than it's parent Definition. Change on Enum Categories ~~~~~~~~~~~~~~~~~~~~~~~~~ Previously, categories on a Discrete Value Item Definition's Enums would add their categories to the Definition. With this release it is assumed that the enums' categories will be **and'd** with it's Definition, there is no longer a reason for the enum categories to be combined with the Definition's local categories. File Version Changes ~~~~~~~~~~~~~~~~~~~~ Supporting these changes did require a new format for both Attribute XML and JSON files. The latest versions for both is now **6**. Older file formats will load in properly and should work based on the previous category rules. Developer changes ~~~~~~~~~~~~~~~~~~ The following methods and enums have been deprecated: * smtk::attributeCategories::Set::CombinationMode::Any -> please use smtk::attributeCategories::Set::CombinationMode::Or * smtk::attributeCategories::Set::CombinationMode::All -> please use smtk::attributeCategories::Set::CombinationMode::And * smtk::attribute::Definition::setIsOkToInherit -> please use smtk::attribute::Definition::setCategoryInheritanceMode * smtk::attribute::Definition::isOkToInherit -> please use smtk::attribute::Definition::categoryInheritanceMode * smtk::attribute::ItemDefinition::setIsOkToInherit -> please use smtk::attribute::ItemDefinition::setCategoryInheritanceMode * smtk::attribute::ItemDefinition::isOkToInherit -> please use smtk::attribute::ItemDefinition::categoryInheritanceMode A new class for supporting the new combination modes has been developed called smtk::attribute::Categories::Stack which represents the category expression formed when combining inherited and local categories since we now need to maintain the order in which they are combined. The method smtk::attribute::ValueItem:relevantEnums(bool includeCategories, bool includeReadAccess, unsigned int readAccessLevel) const was added in order to return the set of enums that passed the activce category and advance level checks (if specified). --- doc/release/notes/categoryChanges.rst | 47 +++ smtk/attribute/Categories.cxx | 282 ++++++++++++++---- smtk/attribute/Categories.h | 107 +++++-- smtk/attribute/Definition.cxx | 43 ++- smtk/attribute/Definition.h | 18 +- smtk/attribute/GroupItemDefinition.cxx | 15 +- smtk/attribute/GroupItemDefinition.h | 2 +- smtk/attribute/ItemDefinition.cxx | 37 ++- smtk/attribute/ItemDefinition.h | 22 +- smtk/attribute/ReferenceItemDefinition.cxx | 15 +- smtk/attribute/ReferenceItemDefinition.h | 2 +- smtk/attribute/Resource.cxx | 2 +- smtk/attribute/ValueItem.cxx | 24 ++ smtk/attribute/ValueItem.h | 5 + smtk/attribute/ValueItemDefinition.cxx | 65 +++- smtk/attribute/ValueItemDefinition.h | 9 +- smtk/attribute/json/jsonDefinition.cxx | 54 +++- smtk/attribute/json/jsonItemDefinition.cxx | 63 +++- smtk/attribute/json/jsonResource.cxx | 11 +- smtk/attribute/json/jsonValueItemDefinition.h | 35 +-- smtk/attribute/operators/Read.cxx | 4 +- smtk/attribute/pybind11/PybindCategories.h | 23 +- smtk/attribute/pybind11/PybindDefinition.h | 6 +- .../attribute/pybind11/PybindItemDefinition.h | 4 +- smtk/attribute/testing/cxx/unitCategories.cxx | 23 +- .../testing/cxx/unitExclusionCategories.cxx | 66 ++-- .../testing/cxx/unitPassCategories.cxx | 198 ++++++++++-- smtk/common/Deprecation.h | 6 + smtk/extension/qt/qtDiscreteValueEditor.cxx | 32 +- smtk/io/AttributeReader.cxx | 47 +-- smtk/io/AttributeWriter.cxx | 9 +- smtk/io/CMakeLists.txt | 4 + smtk/io/XmlDocV1Parser.cxx | 165 +++++----- smtk/io/XmlDocV1Parser.h | 4 + smtk/io/XmlDocV3Parser.cxx | 72 +---- smtk/io/XmlDocV6Parser.cxx | 159 ++++++++++ smtk/io/XmlDocV6Parser.h | 43 +++ smtk/io/XmlV2StringWriter.cxx | 15 +- smtk/io/XmlV3StringWriter.cxx | 9 +- smtk/io/XmlV6StringWriter.cxx | 46 +++ smtk/io/XmlV6StringWriter.h | 50 ++++ 41 files changed, 1358 insertions(+), 485 deletions(-) create mode 100644 doc/release/notes/categoryChanges.rst create mode 100644 smtk/io/XmlDocV6Parser.cxx create mode 100644 smtk/io/XmlDocV6Parser.h create mode 100644 smtk/io/XmlV6StringWriter.cxx create mode 100644 smtk/io/XmlV6StringWriter.h diff --git a/doc/release/notes/categoryChanges.rst b/doc/release/notes/categoryChanges.rst new file mode 100644 index 0000000000..f620282b96 --- /dev/null +++ b/doc/release/notes/categoryChanges.rst @@ -0,0 +1,47 @@ +Expanding SMTK Attribute Category Mechanism +------------------------------------------- + +Category Modeling in SMTK Attribute Resources has been enhanced to now support specialization as well as generalization. +Previously, an Attribute or Item Definition's local categories could only expand (make more general) the categories it was inheriting (or choose to ignore them all together). +With this release, SMTK now supports specializing (or making the category constraint more restrictive). + +Previously category inheritance was controlled by using the Definition's setIsOkToInherit method which would either **Or** its local categories with those it was inheriting or **Replace** them. This method (as well as isOkToInherit method) has been deprecated. The new methods for setting and retrieving category inheritance are: + +* setCategoryInheritanceMode +* categoryInheritanceMode + +The values that categoryInheritanceMode can be set to are: + +* smtk::attribute::Categories::CombinationMode::Or +* smtk::attribute::Categories::CombinationMode::And +* smtk::attribute::Categories::CombinationMode::LocalOnly + +Setting the mode to **Or** is the same as the previous setIsOkToInherit(true) - it will **or** the Definition's local categories with those that it is inheriting. Setting the mode to **And** will now **and** the Definition's local categories with those that it is inheriting. Setting the mode to **LocalOnly** will ignore the categories that the Definition is inheriting and is the same as the previous setIsOkToInherit(false). + +Changing the Default Category Inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously the default mode was isOkToInherit = true which now corresponds to smtk::attribute::Categories::CombinationMode::Or. Upon discussing the new combination support of **And**, it was decided that the new default will be smtk::attribute::Categories::CombinationMode::And, meaning that a Definition will be more specialized category-wise than it's parent Definition. + +Change on Enum Categories +~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, categories on a Discrete Value Item Definition's Enums would add their categories to the Definition. With this release it is assumed that the enums' categories will be **and'd** with it's Definition, there is no longer a reason for the enum categories to be combined with the Definition's local categories. + +File Version Changes +~~~~~~~~~~~~~~~~~~~~ +Supporting these changes did require a new format for both Attribute XML and JSON files. The latest versions for both is now **6**. Older file formats will load in properly and should work based on the previous category rules. + +Developer changes +~~~~~~~~~~~~~~~~~~ + +The following methods and enums have been deprecated: + +* smtk::attributeCategories::Set::CombinationMode::Any -> please use smtk::attributeCategories::Set::CombinationMode::Or +* smtk::attributeCategories::Set::CombinationMode::All -> please use smtk::attributeCategories::Set::CombinationMode::And +* smtk::attribute::Definition::setIsOkToInherit -> please use smtk::attribute::Definition::setCategoryInheritanceMode +* smtk::attribute::Definition::isOkToInherit -> please use smtk::attribute::Definition::categoryInheritanceMode +* smtk::attribute::ItemDefinition::setIsOkToInherit -> please use smtk::attribute::ItemDefinition::setCategoryInheritanceMode +* smtk::attribute::ItemDefinition::isOkToInherit -> please use smtk::attribute::ItemDefinition::categoryInheritanceMode + +A new class for supporting the new combination modes has been developed called smtk::attribute::Categories::Stack which represents the category expression formed when combining inherited and local categories since we now need to maintain the order in which they are combined. + +The method smtk::attribute::ValueItem:relevantEnums(bool includeCategories, bool includeReadAccess, unsigned int readAccessLevel) const was added in order to return the set of enums that passed the activce category and advance level checks (if specified). diff --git a/smtk/attribute/Categories.cxx b/smtk/attribute/Categories.cxx index 7daf4b2d04..ae7a1dea28 100644 --- a/smtk/attribute/Categories.cxx +++ b/smtk/attribute/Categories.cxx @@ -12,32 +12,30 @@ #include #include +#include using namespace smtk::attribute; -std::string Categories::Set::combinationModeAsString(const Set::CombinationMode mode) +std::string Categories::Set::combinationModeAsString(const CombinationMode mode) { - if (mode == Set::CombinationMode::All) - { - return "All"; - } - return "Any"; + return Categories::combinationModeAsString(mode); } -bool Categories::Set::combinationModeFromString(const std::string& val, Set::CombinationMode& mode) +bool Categories::Set::combinationModeFromString(const std::string& val, CombinationMode& mode) { - if (val == "All") - { - mode = Set::CombinationMode::All; - return true; - } - if (val == "Any") + return Categories::combinationModeFromString(val, mode); +} + +bool Categories::Set::setCombinationMode(const Set::CombinationMode& newMode) +{ + if (newMode != Set::CombinationMode::LocalOnly) { - mode = Set::CombinationMode::Any; + m_combinationMode = newMode; return true; } return false; } + bool Categories::Set::passes(const std::string& category) const { std::set categories; @@ -48,7 +46,7 @@ bool Categories::Set::passes(const std::string& category) const bool Categories::Set::passes(const std::set& categories) const { bool result; - if (m_combinationMode == Set::CombinationMode::All) + if (m_combinationMode == CombinationMode::And) { result = passesCheck(categories, m_includedCategories, m_includeMode) && !passesCheck(categories, m_excludedCategories, m_excludeMode); @@ -74,111 +72,285 @@ bool Categories::Set::passesCheck( return false; } - if (comboMode == Set::CombinationMode::Any) + if (comboMode == CombinationMode::Or) { return std::any_of(testSet.begin(), testSet.end(), [&categories](const std::string& cat) { return categories.find(cat) != categories.end(); }); } - // Ok we are doing an All check + // Ok we are doing an And check return std::all_of(testSet.begin(), testSet.end(), [&categories](const std::string& cat) { return categories.find(cat) != categories.end(); }); } -bool Categories::Set::operator<(const Set& rhs) const +int Categories::Set::compare(const Set& rhs) const { if (m_combinationMode != rhs.m_combinationMode) { - return m_combinationMode < rhs.m_combinationMode; + return (m_combinationMode < rhs.m_combinationMode) ? -1 : 1; } if (m_includeMode != rhs.m_includeMode) { - return m_includeMode < rhs.m_includeMode; + return (m_includeMode < rhs.m_includeMode) ? -1 : 1; } if (m_excludeMode != rhs.m_excludeMode) { - return m_excludeMode < rhs.m_excludeMode; + return (m_excludeMode < rhs.m_excludeMode) ? -1 : 1; + ; } if (m_includedCategories != rhs.m_includedCategories) { - return m_includedCategories < rhs.m_includedCategories; + return (m_includedCategories < rhs.m_includedCategories) ? -1 : 1; + } + if (m_excludedCategories != rhs.m_excludedCategories) + { + return (m_excludedCategories < rhs.m_excludedCategories) ? -1 : 1; + } + return 0; // they are identical +} + +std::string Categories::Set::convertToString(const std::string& prefix) const +{ + std::stringstream ss; + ss << prefix << "{"; + ss << Categories::combinationModeAsString(m_combinationMode) + << " Inclusion:" << Categories::combinationModeAsString(m_includeMode) << "{"; + for (const auto& c : m_includedCategories) + { + ss << "\"" << c << "\""; + } + ss << "}"; + + ss << " Exclusion:" << Categories::combinationModeAsString(m_excludeMode) << "{"; + for (const auto& c : m_excludedCategories) + { + ss << "\"" << c << "\""; + } + ss << "}}\n"; + return ss.str(); +} + +bool Categories::Stack::append(CombinationMode mode, const Set& categorySet) +{ + // if the mode is LocalOnly - clear the stack + if (mode == CombinationMode::LocalOnly) + { + m_stack.clear(); + } + + // check to see if the category set represents nothing - if it is don't add it + if (categorySet.empty()) + { + // If the mode was not LocalOnly then return false since this result in a nop + return (mode == CombinationMode::LocalOnly); + } + + // If the stack is empty then the mode is always LocalOnly since it marks the end + // of the stack for testing categories + if (m_stack.empty()) + { + std::pair p(CombinationMode::LocalOnly, categorySet); + m_stack.push_back(p); + return true; + } + // Else append the mode/categorySet + std::pair newPair(mode, categorySet); + m_stack.push_back(newPair); + return true; +} + +bool Categories::Stack::passes(const std::string& category) const +{ + std::set categories; + categories.insert(category); + return this->passes(categories); +} + +bool Categories::Stack::passes(const std::set& cats) const +{ + bool lastResult = false; + for (auto it = m_stack.crbegin(); it != m_stack.crend(); ++it) + { + lastResult = it->second.passes(cats); + if (lastResult) + { + if ((it->first == CombinationMode::Or) || (it->first == CombinationMode::LocalOnly)) + { + return true; + } + } + else if ((it->first == CombinationMode::All) || (it->first == CombinationMode::LocalOnly)) + { + return false; + } + } + return lastResult; +} + +std::string Categories::Stack::convertToString(const std::string& prefix) const +{ + std::stringstream ss; + for (auto it = m_stack.cbegin(); it != m_stack.cend(); it++) + { + ss << prefix << Categories::combinationModeAsString(it->first) << "\n"; + ss << prefix << it->second.convertToString(); + } + return ss.str(); +} + +std::set Categories::Stack::categoryNames() const +{ + std::set result; + for (auto it = m_stack.cbegin(); it != m_stack.cend(); it++) + { + result.insert( + it->second.includedCategoryNames().begin(), it->second.includedCategoryNames().end()); + result.insert( + it->second.excludedCategoryNames().begin(), it->second.excludedCategoryNames().end()); + } + return result; +} + +bool Categories::Stack::operator<(const Stack& rhs) const +{ + if (m_stack.size() != rhs.m_stack.size()) + { + return m_stack.size() < rhs.m_stack.size(); + } + auto rit = rhs.m_stack.crbegin(); + for (auto it = m_stack.crbegin(); it != m_stack.crend(); it++, rit++) + { + if (it->first != rit->first) + { + return it->first < rit->first; + } + int result = it->second.compare(rit->second); + if (result != 0) + { + return result < 0; + } + } + return false; // They are the same +} + +std::string Categories::combinationModeAsString(const CombinationMode mode) +{ + if (mode == CombinationMode::And) + { + return "And"; + } + if (mode == CombinationMode::Or) + { + return "Or"; } - return m_excludedCategories < rhs.m_excludedCategories; + return "LocalOnly"; } -void Categories::insert(const Set& set) +bool Categories::combinationModeFromString(const std::string& val, CombinationMode& mode) +{ + if ((val == "And") || (val == "All")) + { + mode = CombinationMode::And; + return true; + } + if ((val == "Or") || (val == "Any")) + { + mode = CombinationMode::Or; + return true; + } + if (val == "LocalOnly") + { + mode = CombinationMode::LocalOnly; + return true; + } + return false; +} + +bool Categories::insert(const Set& set) { // if the set is not empty, add it if (!set.empty()) { - m_sets.insert(set); + Stack newStack; + newStack.append(CombinationMode::LocalOnly, set); + m_stacks.insert(newStack); + return true; } + return false; +} + +bool Categories::insert(const Stack& stack) +{ + // if the stack is not empty, add it + if (!stack.empty()) + { + m_stacks.insert(stack); + return true; + } + return false; } void Categories::insert(const Categories& cats) { - for (const auto& set : cats.m_sets) + for (const auto& stack : cats.m_stacks) { - this->insert(set); + this->insert(stack); } } bool Categories::passes(const std::string& category) const { - // If there are no sets which means there are no categories + // If there are no stacks which means there are no categories // associated then fail - if (m_sets.empty()) + if (m_stacks.empty()) { return false; } - return std::any_of( - m_sets.begin(), m_sets.end(), [&category](const Set& set) { return set.passes(category); }); + return std::any_of(m_stacks.begin(), m_stacks.end(), [&category](const Stack& stack) { + return stack.passes(category); + }); } bool Categories::passes(const std::set& categories) const { - // If there are no sets which means there are no categories + // If there are no stacks which means there are no categories // associated then fail - if (m_sets.empty()) + if (m_stacks.empty()) { return false; } - return std::any_of( - m_sets.begin(), m_sets.end(), [&categories](const Set& set) { return set.passes(categories); }); + return std::any_of(m_stacks.begin(), m_stacks.end(), [&categories](const Stack& stack) { + return stack.passes(categories); + }); } std::set Categories::categoryNames() const { std::set result; - for (const auto& set : m_sets) + for (const auto& stack : m_stacks) { - result.insert(set.includedCategoryNames().begin(), set.includedCategoryNames().end()); + std::set sinfo = stack.categoryNames(); + result.insert(sinfo.begin(), sinfo.end()); } return result; } -void Categories::print() const +std::string Categories::convertToString() const { - std::cerr << "{"; - for (const auto& set : m_sets) + std::stringstream ss; + ss << "{"; + for (const auto& stack : m_stacks) { - std::cerr << " { " << Set::combinationModeAsString(set.combinationMode()) - << " Inclusion:" << Set::combinationModeAsString(set.inclusionMode()) << "{"; - for (const auto& c : set.includedCategoryNames()) - { - std::cerr << "\"" << c << "\""; - } - std::cerr << "}"; - - std::cerr << " Exclusion:" << Set::combinationModeAsString(set.exclusionMode()) << "{"; - for (const auto& c : set.excludedCategoryNames()) - { - std::cerr << "\"" << c << "\""; - } - std::cerr << "}}"; + ss << " { " << stack.convertToString("\t") << "}\n"; } - std::cerr << "}\n"; + ss << "}\n"; + return ss.str(); +} + +void Categories::print() const +{ + std::cerr << this->convertToString(); } diff --git a/smtk/attribute/Categories.h b/smtk/attribute/Categories.h index 2fab03886d..966f71bd30 100644 --- a/smtk/attribute/Categories.h +++ b/smtk/attribute/Categories.h @@ -14,8 +14,12 @@ #include "smtk/CoreExports.h" #include "smtk/SystemConfig.h" // quiet dll-interface warnings on windows +#include "smtk/common/Deprecation.h" + #include #include +#include +#include namespace smtk { @@ -30,37 +34,42 @@ namespace attribute class SMTKCORE_EXPORT Categories { public: + enum class CombinationMode + { + Or = 0, //!< Represents logical Or + Any SMTK_DEPRECATED_IN_22_07("Please use Or") = 0, + And = 1, //!< Represents logical And + All SMTK_DEPRECATED_IN_22_07("Please use And") = 1, + LocalOnly = 3 //!< Indicates no further processing of Category Set Pairs is required + }; + ///\brief Categories::Set represents a single category constraint used by the Categories class. /// /// A Set consists of two sets of category names representing the categories that should exist /// (inclusion) and the categories that should not exist (exclusion). Each set also has a - /// combination mode associated with it. For example if the inclusion mode is Any then the inclusion set's + /// combination mode associated with it. For example if the inclusion mode is Or then the inclusion set's /// constraint is satisfied if any of its categories names exists in a input set of category names. - /// Else the inclusion mode is All, then all of the inclusion set's names must exist in the input set. - /// In the case of the exclusion set , the result is the complement. So exclusion mode = Any means the - /// exclusion test fails if any of the excluded names are in the input while All means that only if all + /// Else the inclusion mode is And, then all of the inclusion set's names must exist in the input set. + /// In the case of the exclusion set , the result is the complement. So exclusion mode = Or means the + /// exclusion test fails if any of the excluded names are in the input while And means that only if all /// of the names in the exclusion set are in the input will the test fail. /// /// There is also a top level combination mode that determines how the inclusion and exclusion results are - /// combined. If the top mode is All then both the inclusion and exclusion checks must pass while Any means + /// combined. If the top mode is And then both the inclusion and exclusion checks must pass while Or means /// only one of the checks need to pass. /// /// Special notes: - /// If the top combination mode is All and the inclusion set is empty, then the passes check will always fail. - /// If the top combination mode is Any and the exclusion set is empty, then the passes check will always succeed. + /// If the top combination mode is And and the inclusion set is empty, then the passes check will always fail. + /// If the top combination mode is Or and the exclusion set is empty, then the passes check will always succeed. class SMTKCORE_EXPORT Set { public: - enum class CombinationMode - { - Any = 0, //!< Check passes if any of the set's categories are found - All = 1 //!< Check passes if all of the set's categories are found - }; + using CombinationMode = Categories::CombinationMode; Set() = default; ///@{ ///\brief Set/Get the how the sets of included and excluded categories are combined Set::CombinationMode combinationMode() const { return m_combinationMode; } - void setCombinationMode(const Set::CombinationMode& newMode) { m_combinationMode = newMode; } + bool setCombinationMode(const Set::CombinationMode& newMode); ///@} ///@{ ///\brief Set/Get the CombinationMode associated with the included categories. @@ -102,19 +111,24 @@ public: m_includedCategories.clear(); m_excludedCategories.clear(); } - ///\brief Returns true if both the inclusion and exclusion sets are empty. - bool empty() const { return m_includedCategories.empty() && m_excludedCategories.empty(); } + ///\brief Returns true if both the inclusion and exclusion sets are empty and the combination + /// mode is set to And since this would represent a set that matches nothing + bool empty() const + { + return m_includedCategories.empty() && m_excludedCategories.empty() && + (m_combinationMode == CombinationMode::And); + } ///\brief Returns the number of category names in the inclusion set. std::size_t inclusionSize() const { return m_includedCategories.size(); } ///\brief Returns the number of category names in the exclusion set. std::size_t exclusionSize() const { return m_excludedCategories.size(); } ///@{ - ///\brief Return true if the input set of categories satifies the Set's + ///\brief Return true if the input set of categories satisfies the Set's /// constraints. /// /// If the input set is empty then the method will return true. Else if - /// the instance's mode is Any then at least one of its category names must be in the - /// input set. If the mode is All then all of the instance's names must be in the input set. + /// the instance's mode is Or then at least one of its category names must be in the + /// input set. If the mode is And then all of the instance's names must be in the input set. bool passes(const std::set& cats) const; bool passes(const std::string& cat) const; ///@} @@ -122,16 +136,40 @@ public: const std::set& cats, const std::set& testSet, Set::CombinationMode comboMode); - ///\brief Comparison operator needed to create a set of Categories::Sets - bool operator<(const Set& rhs) const; + + SMTK_DEPRECATED_IN_22_07( + "Replaced by Categories::combinationModeAsString(CombinationMode mode).") static std::string combinationModeAsString(Set::CombinationMode mode); + SMTK_DEPRECATED_IN_22_07("Replaced by Categories::combinationModeFromString(const std::string& " + "val, CombinationMode& mode).") static bool combinationModeFromString(const std::string& val, Set::CombinationMode& mode); + ///\brief Compares with other set - returns -1 if this < rhs, 0 if they are equal, and 1 if this > rhs + int compare(const Set& rhs) const; + std::string convertToString(const std::string& prefix = "") const; private: - Set::CombinationMode m_includeMode{ CombinationMode::Any }, - m_excludeMode{ CombinationMode::Any }, m_combinationMode{ CombinationMode::All }; + Set::CombinationMode m_includeMode{ Set::CombinationMode::Or }, + m_excludeMode{ Set::CombinationMode::Or }, m_combinationMode{ Set::CombinationMode::And }; std::set m_includedCategories, m_excludedCategories; }; + + class SMTKCORE_EXPORT Stack + { + public: + bool append(CombinationMode mode, const Set& categorySet); + void clear() { m_stack.clear(); } + bool passes(const std::set& cats) const; + bool passes(const std::string& cat) const; + std::string convertToString(const std::string& prefix = "") const; + std::set categoryNames() const; + bool empty() const { return m_stack.empty(); } + ///\brief Comparison operator needed to create a set of Categories::Stacks + bool operator<(const Stack& rhs) const; + + protected: + std::vector> m_stack; + }; + Categories() = default; ///@{ /// \brief Returns true if atleast one of its sets passes its check @@ -141,22 +179,31 @@ public: ///@{ ///\brief Insert either a Categories::Set or the sets of another Categories instance into /// this instance. - void insert(const Set& set); + SMTK_DEPRECATED_IN_22_07("Replaced by Categories::insert(const Stack&).") + bool insert(const Set& set); + bool insert(const Stack& stack); void insert(const Categories& cats); ///@} - ///\brief Remove all sets from this instance. - void reset() { m_sets.clear(); } - ///\brief Return the number of sets in this instance. - std::size_t size() const { return m_sets.size(); } + ///\brief Remove all stacks from this instance. + void reset() { m_stacks.clear(); } + ///\brief Return the number of stacks in this instance. + std::size_t size() const { return m_stacks.size(); } ///\brief Return the sets contained in this instance. - const std::set& sets() const { return m_sets; } - ///\brief Return a set of all category names refrenced in all of te instance's sets. + SMTK_DEPRECATED_IN_22_07("Replaced by Categories::stacks().") + const std::set sets() const { return std::set(); } + ///\brief Return the stacks contained in this instance. + const std::set& stacks() const { return m_stacks; } + ///\brief Return a set of all category names referenced in all of the instance's stacks. std::set categoryNames() const; + ///\brief produce a formatted string representing the Categories' information. + std::string convertToString() const; ///\brief Print to cerr the current contents of the instance. void print() const; + static std::string combinationModeAsString(Set::CombinationMode mode); + static bool combinationModeFromString(const std::string& val, Set::CombinationMode& mode); private: - std::set m_sets; + std::set m_stacks; }; } // namespace attribute } // namespace smtk diff --git a/smtk/attribute/Definition.cxx b/smtk/attribute/Definition.cxx index 5dddabcca3..b47850a152 100644 --- a/smtk/attribute/Definition.cxx +++ b/smtk/attribute/Definition.cxx @@ -49,7 +49,7 @@ Definition::Definition( m_rootName = m_type; m_includeIndex = 0; m_prerequisiteUsageCount = 0; - m_isOkToInherit = true; + m_combinationMode = Categories::CombinationMode::And; if (myBaseDef) { m_baseItemOffset = myBaseDef->numberOfItemDefinitions(); @@ -749,19 +749,38 @@ std::set Definition::attributes( return atts; } -void Definition::applyCategories(smtk::attribute::Categories inherited) +bool Definition::isOkToInherit() const +{ + return m_combinationMode != Categories::CombinationMode::LocalOnly; +} + +void Definition::setIsOkToInherit(bool isOkToInheritValue) +{ + if (isOkToInheritValue) + { + m_combinationMode = Categories::CombinationMode::Or; + } + else + { + m_combinationMode = Categories::CombinationMode::LocalOnly; + } +} + +void Definition::applyCategories(smtk::attribute::Categories::Stack inherited) { smtk::attribute::Categories inheritedFromItems; - // First append the def's categories to those we have inherited - // Note that we want to not modify the original list which is why + m_categories.reset(); + + // First append the definition's local category info to + // what we are inheriting. Note that we want to not modify the original list which is why // its passed by value + inherited.append(m_combinationMode, m_localCategories); - // Is the definition not suppose to inherit information categories? - if (!m_isOkToInherit) + // Next append the def's categories to those we have inherited (if we are not only considering local Only) + if (m_baseDefinition && (m_combinationMode != Categories::CombinationMode::LocalOnly)) { - inherited.reset(); + m_categories.insert(m_baseDefinition->m_categories); } - inherited.insert(m_localCategories); // Lets go to each item and process its categories for (auto& item : m_itemDefs) @@ -773,14 +792,10 @@ void Definition::applyCategories(smtk::attribute::Categories inherited) // We start with all of the categories associated with the def's // base definition - note that we assume that the inherited set passed // in is contained within the base's categories - m_categories.reset(); - if (m_baseDefinition && m_isOkToInherit) + if (m_baseDefinition && (m_combinationMode != Categories::CombinationMode::LocalOnly)) { - m_categories.insert(m_baseDefinition->m_categories); } - - // Next we add all local categories - m_categories.insert(m_localCategories); + m_categories.insert(inherited); // We need to add all of the categories that were locally defined // on the items contained within the definition diff --git a/smtk/attribute/Definition.h b/smtk/attribute/Definition.h index 96e4b0b374..3c853ed626 100644 --- a/smtk/attribute/Definition.h +++ b/smtk/attribute/Definition.h @@ -138,9 +138,19 @@ public: ///\brief Indicates if the Definition can inherit categories based on it's /// parent Definition or its owning Attribute Definition. The default is true. - bool isOkToInherit() const { return m_isOkToInherit; } + ///@{ + SMTK_DEPRECATED_IN_22_07("Replaced by Definition::categoryInheritanceMode.") + bool isOkToInherit() const; + SMTK_DEPRECATED_IN_22_07("Replaced by Definition::setCategoryInheritanceMode.") + void setIsOkToInherit(bool isOkToInheritValue); + ///@} - void setIsOkToInherit(bool isOkToInheritValue) { m_isOkToInherit = isOkToInheritValue; } + ///\brief Determines how the Definition should combine its local category Set with the + /// category constraints being inherited from it's Base Definition (if one exists) + ///@{ + Categories::CombinationMode categoryInheritanceMode() const { return m_combinationMode; } + void setCategoryInheritanceMode(Categories::CombinationMode mode) { m_combinationMode = mode; } + ///@} ///\brief Returns the categories explicitly assigned to the Definition smtk::attribute::Categories::Set& localCategories() { return m_localCategories; } @@ -425,7 +435,7 @@ protected: ///\brief apply the local categories of the definition and its items. /// inherited is an initial set passed down from the definition's base. - void applyCategories(smtk::attribute::Categories inherited); + void applyCategories(smtk::attribute::Categories::Stack inherited); // This method updates derived definitions when this // definition's items have been changed @@ -444,7 +454,6 @@ protected: smtk::attribute::DefinitionPtr m_baseDefinition; std::string m_type; std::string m_label; - bool m_isOkToInherit; bool m_isNodal; attribute::Categories::Set m_localCategories; attribute::Categories m_categories; @@ -473,6 +482,7 @@ protected: std::string m_rootName; Tags m_tags; std::size_t m_includeIndex; + Categories::CombinationMode m_combinationMode; private: // These colors are returned for base definitions w/o set colors diff --git a/smtk/attribute/GroupItemDefinition.cxx b/smtk/attribute/GroupItemDefinition.cxx index 1b24d5899f..705a256e10 100644 --- a/smtk/attribute/GroupItemDefinition.cxx +++ b/smtk/attribute/GroupItemDefinition.cxx @@ -81,25 +81,22 @@ void GroupItemDefinition::buildGroup(GroupItem* groupItem, int subGroupPosition) } void GroupItemDefinition::applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) { + Categories::Stack myCats = inheritedFromParent; + + myCats.append(m_combinationMode, m_localCategories); m_categories.reset(); - m_categories.insert(m_localCategories); - if (m_isOkToInherit) - { - m_categories.insert(inheritedFromParent); - } smtk::attribute::Categories myChildrenCats; for (auto& item : m_itemDefs) { - item->applyCategories(m_categories, myChildrenCats); + item->applyCategories(myCats, myChildrenCats); } m_categories.insert(myChildrenCats); - inheritedToParent.insert(m_localCategories); - inheritedToParent.insert(myChildrenCats); + inheritedToParent.insert(m_categories); } void GroupItemDefinition::applyAdvanceLevels( diff --git a/smtk/attribute/GroupItemDefinition.h b/smtk/attribute/GroupItemDefinition.h index af387b4f5c..b8bc0b5a36 100644 --- a/smtk/attribute/GroupItemDefinition.h +++ b/smtk/attribute/GroupItemDefinition.h @@ -152,7 +152,7 @@ public: protected: GroupItemDefinition(const std::string& myname); void applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) override; void applyAdvanceLevels( const unsigned int& readLevelFromParent, diff --git a/smtk/attribute/ItemDefinition.cxx b/smtk/attribute/ItemDefinition.cxx index 57106d71d6..4a6ca12613 100644 --- a/smtk/attribute/ItemDefinition.cxx +++ b/smtk/attribute/ItemDefinition.cxx @@ -21,25 +21,38 @@ ItemDefinition::ItemDefinition(const std::string& myName) m_hasLocalAdvanceLevelInfo[0] = m_hasLocalAdvanceLevelInfo[1] = false; m_isOptional = false; m_isEnabledByDefault = false; - m_isOkToInherit = true; + m_combinationMode = Categories::CombinationMode::And; } ItemDefinition::~ItemDefinition() = default; +bool ItemDefinition::isOkToInherit() const +{ + return m_combinationMode != Categories::CombinationMode::LocalOnly; +} + +void ItemDefinition::setIsOkToInherit(bool isOkToInheritValue) +{ + if (isOkToInheritValue) + { + m_combinationMode = Categories::CombinationMode::Or; + } + else + { + m_combinationMode = Categories::CombinationMode::LocalOnly; + } +} + void ItemDefinition::applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) { - // The item's definition's categories are it's local categories and (if its ok to inherit - // categories from it's owning item definition/attribute definition) those inherited - // from its parent + Categories::Stack myCats = inheritedFromParent; + myCats.append(m_combinationMode, m_localCategories); + m_categories.reset(); - m_categories.insert(m_localCategories); - if (m_isOkToInherit) - { - m_categories.insert(inheritedFromParent); - } - inheritedToParent.insert(m_localCategories); + m_categories.insert(myCats); + inheritedToParent.insert(m_categories); } void ItemDefinition::setLocalAdvanceLevel(int mode, unsigned int level) @@ -86,7 +99,7 @@ void ItemDefinition::copyTo(ItemDefinitionPtr def) const def->setVersion(m_version); def->setIsOptional(m_isOptional); def->setIsEnabledByDefault(m_isEnabledByDefault); - def->setIsOkToInherit(m_isOkToInherit); + def->setCategoryInheritanceMode(m_combinationMode); def->localCategories() = m_localCategories; if (m_hasLocalAdvanceLevelInfo[0]) diff --git a/smtk/attribute/ItemDefinition.h b/smtk/attribute/ItemDefinition.h index d57ffbf7d9..d6e6591b93 100644 --- a/smtk/attribute/ItemDefinition.h +++ b/smtk/attribute/ItemDefinition.h @@ -103,10 +103,20 @@ public: } ///\brief Indicates if the Definition can inherit categories based on it's - /// parent Definition or its owning Attribute Definition. The default is true. - bool isOkToInherit() const { return m_isOkToInherit; } + /// owning ItemDefinition or its owning Attribute Definition. The default is true. + ///@{ + SMTK_DEPRECATED_IN_22_07("Replaced by ItemDefinition::categoryInheritanceMode.") + bool isOkToInherit() const; + SMTK_DEPRECATED_IN_22_07("Replaced by ItemDefinition::setCategoryInheritanceMode.") + void setIsOkToInherit(bool isOkToInheritValue); + ///@} - void setIsOkToInherit(bool isOkToInheritValue) { m_isOkToInherit = isOkToInheritValue; } + ///\brief Determines how the Definition should combine its local category Set with the + /// category constraints being inherited from it's owning Attribute or Item Definition + ///@{ + Categories::CombinationMode categoryInheritanceMode() const { return m_combinationMode; } + void setCategoryInheritanceMode(Categories::CombinationMode mode) { m_combinationMode = mode; } + ///@} //Get the item definition's advance level: //if mode is 1 then the write access level is returned; @@ -120,7 +130,7 @@ public: return (mode == 1 ? m_localAdvanceLevel[1] : m_localAdvanceLevel[0]); } void setLocalAdvanceLevel(int mode, unsigned int level); - // Convinence Method that sets both read and write to the same value + // Convenience Method that sets both read and write to the same value void setLocalAdvanceLevel(unsigned int level); // unsetAdvanceLevel causes the item to return its @@ -168,7 +178,7 @@ protected: ItemDefinition(const std::string& myname); void copyTo(ItemDefinitionPtr def) const; virtual void applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent); virtual void applyAdvanceLevels( const unsigned int& readLevelFromParent, @@ -176,7 +186,6 @@ protected: int m_version; bool m_isOptional; bool m_isEnabledByDefault; - bool m_isOkToInherit; std::string m_label; attribute::Categories::Set m_localCategories; attribute::Categories m_categories; @@ -186,6 +195,7 @@ protected: unsigned int m_localAdvanceLevel[2]; unsigned int m_advanceLevel[2]; attribute::Tags m_tags; + Categories::CombinationMode m_combinationMode; private: // constant value that should never be changed diff --git a/smtk/attribute/ReferenceItemDefinition.cxx b/smtk/attribute/ReferenceItemDefinition.cxx index cc8e1352f9..f3ba974831 100644 --- a/smtk/attribute/ReferenceItemDefinition.cxx +++ b/smtk/attribute/ReferenceItemDefinition.cxx @@ -406,16 +406,14 @@ const std::vector& ReferenceItemDefinition::conditionalItems(std::s } void ReferenceItemDefinition::applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) { + Categories::Stack myCats = inheritedFromParent; + myCats.append(m_combinationMode, m_localCategories); // Lets first determine the set of categories this item definition could inherit m_categories.reset(); - m_categories.insert(m_localCategories); - if (m_isOkToInherit) - { - m_categories.insert(inheritedFromParent); - } + m_categories.insert(myCats); smtk::attribute::Categories myChildrenCats; @@ -423,15 +421,14 @@ void ReferenceItemDefinition::applyCategories( // this item def will inherit from its children based on their local categories for (auto& i : m_itemDefs) { - i.second->applyCategories(m_categories, myChildrenCats); + i.second->applyCategories(myCats, myChildrenCats); } // Add the children categories to this one m_categories.insert(myChildrenCats); // update the set of categories being inherited by the owning item/attribute // definition - inheritedToParent.insert(m_localCategories); - inheritedToParent.insert(myChildrenCats); + inheritedToParent.insert(m_categories); } bool ReferenceItemDefinition::addItemDefinition(smtk::attribute::ItemDefinitionPtr cdef) diff --git a/smtk/attribute/ReferenceItemDefinition.h b/smtk/attribute/ReferenceItemDefinition.h index b6fb52da78..cfb3720e17 100644 --- a/smtk/attribute/ReferenceItemDefinition.h +++ b/smtk/attribute/ReferenceItemDefinition.h @@ -254,7 +254,7 @@ protected: bool checkCategories(const smtk::resource::Component* comp) const; void applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) override; bool m_useCommonLabel; diff --git a/smtk/attribute/Resource.cxx b/smtk/attribute/Resource.cxx index ce59d5f4cc..772bba6139 100644 --- a/smtk/attribute/Resource.cxx +++ b/smtk/attribute/Resource.cxx @@ -486,7 +486,7 @@ void Resource::finalizeDefinitions() // We need to process the definitions that don't have // a base definition std::vector baseDefs; - smtk::attribute::Categories initialCats; + smtk::attribute::Categories::Stack initialCats; this->findBaseDefinitions(baseDefs); // Lets apply their categories and their item definitions' categories for (auto& def : baseDefs) diff --git a/smtk/attribute/ValueItem.cxx b/smtk/attribute/ValueItem.cxx index c7d44d16c8..6057bfdc0a 100644 --- a/smtk/attribute/ValueItem.cxx +++ b/smtk/attribute/ValueItem.cxx @@ -606,3 +606,27 @@ smtk::attribute::ConstItemPtr ValueItem::findChild(const std::string& cname, Sea { return this->findInternal(cname, style); } + +std::vector ValueItem::relevantEnums( + bool includeCategories, + bool includeReadAccess, + unsigned int readAccessLevel) const +{ + const ValueItemDefinition* def = static_cast(m_definition.get()); + std::set dummy; + if (includeCategories) + { + // See if we can get the active categories of the related Resource, else ignore categories + auto myAttribute = this->attribute(); + if (myAttribute) + { + auto aResource = myAttribute->attributeResource(); + if (aResource && aResource->activeCategoriesEnabled()) + { + return def->relevantEnums( + true, aResource->activeCategories(), includeReadAccess, readAccessLevel); + } + } + } + return def->relevantEnums(false, dummy, includeReadAccess, readAccessLevel); +} diff --git a/smtk/attribute/ValueItem.h b/smtk/attribute/ValueItem.h index 00ae394850..3c281b7ee7 100644 --- a/smtk/attribute/ValueItem.h +++ b/smtk/attribute/ValueItem.h @@ -74,6 +74,11 @@ public: bool setDiscreteIndex(int value) { return this->setDiscreteIndex(0, value); } // Returns true if value is a valid index - else it returns false bool setDiscreteIndex(std::size_t elementIndex, int value); + + ///\brief Return the enum strings that pass the Resource's active categories and/or specified advance read access level. + std::vector + relevantEnums(bool includeCategories, bool includeReadAccess, unsigned int readAccessLevel) const; + /// Release the item's dependency on its parent attribute's Resource. void detachOwningResource() override; // Reset returns the item to its initial state. diff --git a/smtk/attribute/ValueItemDefinition.cxx b/smtk/attribute/ValueItemDefinition.cxx index c519e6ce1a..fba4190daf 100644 --- a/smtk/attribute/ValueItemDefinition.cxx +++ b/smtk/attribute/ValueItemDefinition.cxx @@ -238,16 +238,15 @@ std::vector ValueItemDefinition::conditionalItems(const std::string } void ValueItemDefinition::applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) { // Lets first determine the set of categories this item definition could inherit m_categories.reset(); - m_categories.insert(m_localCategories); - if (m_isOkToInherit) - { - m_categories.insert(inheritedFromParent); - } + Categories::Stack myCats = inheritedFromParent; + myCats.append(m_combinationMode, m_localCategories); + // Lets insert the combination of this Item's categories with those that were inherited + m_categories.insert(myCats); smtk::attribute::Categories myChildrenCats; @@ -255,21 +254,18 @@ void ValueItemDefinition::applyCategories( // this item def will inherit from its children based on their local categories for (auto& i : m_itemDefs) { - i.second->applyCategories(m_categories, myChildrenCats); + i.second->applyCategories(myCats, myChildrenCats); } - //Lets add the categories associated with its enums - for (const auto& enumCatInfo : m_valueToCategoryAssociations) - { - m_categories.insert(enumCatInfo.second); - } + // NOTE - concerning category information associated with enums - We assume that this + // information is used by the UI to show the user what values are available based on the + // active categories but they DO NOT effect the Item's validity or relevance. // Add the children categories to this one m_categories.insert(myChildrenCats); // update the set of categories being inherited by the owning item/attribute // definition - inheritedToParent.insert(m_localCategories); - inheritedToParent.insert(myChildrenCats); + inheritedToParent.insert(m_categories); } void ValueItemDefinition::applyAdvanceLevels( @@ -476,3 +472,44 @@ bool ValueItemDefinition::addItemDefinition(smtk::attribute::ItemDefinitionPtr c m_itemDefs[cdef->name()] = cdef; return true; } + +std::vector ValueItemDefinition::relevantEnums( + bool includeCategories, + const std::set& testCategories, + bool includeReadAccess, + unsigned int readAccessLevel) const +{ + std::vector result; + if (!(includeCategories || includeReadAccess)) + { + return m_discreteValueEnums; + } + + if (includeCategories) + { + for (std::size_t i = 0; i < m_discreteValueEnums.size(); i++) + { + const auto& cats = this->enumCategories(m_discreteValueEnums[i]); + if (cats.empty() || cats.passes(testCategories)) + { + if ( + (!includeReadAccess) || + (this->enumAdvanceLevel(m_discreteValueEnums[i]) <= readAccessLevel)) + { + result.push_back(m_discreteValueEnums[i]); + } + } + } + } + else + { + for (std::size_t i = 0; i < m_discreteValueEnums.size(); i++) + { + if (this->enumAdvanceLevel(m_discreteValueEnums[i]) <= readAccessLevel) + { + result.push_back(m_discreteValueEnums[i]); + } + } + } + return result; +} diff --git a/smtk/attribute/ValueItemDefinition.h b/smtk/attribute/ValueItemDefinition.h index bb7a17d2e8..d871b0869b 100644 --- a/smtk/attribute/ValueItemDefinition.h +++ b/smtk/attribute/ValueItemDefinition.h @@ -184,10 +184,17 @@ public: bool addConditionalItem(const std::string& enumValue, const std::string& itemName); std::vector conditionalItems(const std::string& enumValue) const; + ///\brief Return the enum strings that pass a set of categories and/or specified advance read access level. + std::vector relevantEnums( + bool includeCategories, + const std::set& testCategories, + bool includeReadAccess, + unsigned int readAccessLevel) const; + protected: void copyTo(ValueItemDefinitionPtr def, smtk::attribute::ItemDefinition::CopyInfo& info) const; void applyCategories( - const smtk::attribute::Categories& inheritedFromParent, + const smtk::attribute::Categories::Stack& inheritedFromParent, smtk::attribute::Categories& inheritedToParent) override; void applyAdvanceLevels( const unsigned int& readLevelFromParent, diff --git a/smtk/attribute/json/jsonDefinition.cxx b/smtk/attribute/json/jsonDefinition.cxx index 5ff47a3ee3..dc365dae65 100644 --- a/smtk/attribute/json/jsonDefinition.cxx +++ b/smtk/attribute/json/jsonDefinition.cxx @@ -76,14 +76,14 @@ SMTKCORE_EXPORT void to_json(nlohmann::json& j, const smtk::attribute::Definitio j["Nodal"] = true; } // Process Category Info - j["CategoryInfo"]["Combination"] = smtk::attribute::Categories::Set::combinationModeAsString( + j["CategoryInfo"]["Combination"] = smtk::attribute::Categories::combinationModeAsString( defPtr->localCategories().combinationMode()); // Inclusion Info if (!defPtr->localCategories().includedCategoryNames().empty()) { j["CategoryInfo"]["InclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString( + smtk::attribute::Categories::combinationModeAsString( defPtr->localCategories().inclusionMode()); j["CategoryInfo"]["IncludeCategories"] = defPtr->localCategories().includedCategoryNames(); } @@ -92,13 +92,14 @@ SMTKCORE_EXPORT void to_json(nlohmann::json& j, const smtk::attribute::Definitio if (!defPtr->localCategories().excludedCategoryNames().empty()) { j["CategoryInfo"]["ExclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString( + smtk::attribute::Categories::combinationModeAsString( defPtr->localCategories().exclusionMode()); j["CategoryInfo"]["ExcludeCategories"] = defPtr->localCategories().excludedCategoryNames(); } // Inheritance Option - j["CategoryInfo"]["Inherit"] = defPtr->isOkToInherit(); + j["CategoryInfo"]["InheritanceMode"] = + smtk::attribute::Categories::combinationModeAsString(defPtr->categoryInheritanceMode()); // Save Color Information if (defPtr->isNotApplicableColorSet()) @@ -238,23 +239,50 @@ SMTKCORE_EXPORT void from_json( defPtr->setIsUnique(*result); } // Process Category Info () + smtk::attribute::Categories::CombinationMode cmode; auto catInfo = j.find("CategoryInfo"); // Current Form auto categories = j.find("Categories"); // Old Deprecated Form if (catInfo != j.end()) { - auto okToInherit = catInfo->find("Inherit"); - if (okToInherit != catInfo->end()) + auto inheritanceMode = catInfo->find("InheritanceMode"); + if (inheritanceMode != catInfo->end()) { - defPtr->setIsOkToInherit(*okToInherit); + if (smtk::attribute::Categories::combinationModeFromString(*inheritanceMode, cmode)) + { + defPtr->setCategoryInheritanceMode(cmode); + } + else + { + smtkErrorMacro( + smtk::io::Logger::instance(), + "When converting json, definition " + << defPtr->label() + << " has an invalid category inheritance mode = " << *inheritanceMode); + } + } + else + { + auto okToInherit = catInfo->find("Inherit"); + if (okToInherit != catInfo->end()) + { + if (*okToInherit) + { + defPtr->setCategoryInheritanceMode(smtk::attribute::Categories::CombinationMode::Or); + } + else + { + defPtr->setCategoryInheritanceMode( + smtk::attribute::Categories::CombinationMode::LocalOnly); + } + } } attribute::Categories::Set& localCats = defPtr->localCategories(); auto combineMode = catInfo->find("Combination"); - smtk::attribute::Categories::Set::CombinationMode cmode; // If Combination is not specified - assume the default value; if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setCombinationMode(cmode); } @@ -270,7 +298,7 @@ SMTKCORE_EXPORT void from_json( combineMode = catInfo->find("InclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setInclusionMode(cmode); } @@ -294,7 +322,7 @@ SMTKCORE_EXPORT void from_json( combineMode = catInfo->find("ExclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setExclusionMode(cmode); } @@ -318,12 +346,12 @@ SMTKCORE_EXPORT void from_json( else if (categories != j.end()) // Deprecated { attribute::Categories::Set& localCats = defPtr->localCategories(); - smtk::attribute::Categories::Set::CombinationMode cmode; + smtk::attribute::Categories::CombinationMode cmode; auto categoryCheckMode = j.find("categoryCheckMode"); // If categoryCheckMode is not specified - assume the default value; if (categoryCheckMode != j.end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*categoryCheckMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*categoryCheckMode, cmode)) { localCats.setInclusionMode(cmode); } diff --git a/smtk/attribute/json/jsonItemDefinition.cxx b/smtk/attribute/json/jsonItemDefinition.cxx index 27f91a23ed..0864fca833 100644 --- a/smtk/attribute/json/jsonItemDefinition.cxx +++ b/smtk/attribute/json/jsonItemDefinition.cxx @@ -54,15 +54,17 @@ SMTKCORE_EXPORT void to_json( // Process Category Info auto& cats = itemDefPtr->localCategories(); j["CategoryInfo"]["Combination"] = - smtk::attribute::Categories::Set::combinationModeAsString(cats.combinationMode()); + smtk::attribute::Categories::combinationModeAsString(cats.combinationMode()); - j["CategoryInfo"]["Inherit"] = itemDefPtr->isOkToInherit(); + // Inheritance Option + j["CategoryInfo"]["InheritanceMode"] = + smtk::attribute::Categories::combinationModeAsString(itemDefPtr->categoryInheritanceMode()); // Inclusion Info if (!cats.includedCategoryNames().empty()) { j["CategoryInfo"]["InclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString(cats.inclusionMode()); + smtk::attribute::Categories::combinationModeAsString(cats.inclusionMode()); j["CategoryInfo"]["IncludeCategories"] = cats.includedCategoryNames(); } @@ -70,7 +72,7 @@ SMTKCORE_EXPORT void to_json( if (!cats.excludedCategoryNames().empty()) { j["CategoryInfo"]["ExclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString(cats.exclusionMode()); + smtk::attribute::Categories::combinationModeAsString(cats.exclusionMode()); j["CategoryInfo"]["ExcludeCategories"] = cats.excludedCategoryNames(); } @@ -163,18 +165,44 @@ SMTKCORE_EXPORT void from_json( if (catInfo != j.end()) { - smtk::attribute::Categories::Set::CombinationMode cmode; - auto okToInherit = catInfo->find("Inherit"); - if (okToInherit != catInfo->end()) + smtk::attribute::Categories::CombinationMode cmode; + auto inheritanceMode = catInfo->find("InheritanceMode"); + if (inheritanceMode != catInfo->end()) { - itemDefPtr->setIsOkToInherit(*okToInherit); + if (smtk::attribute::Categories::combinationModeFromString(*inheritanceMode, cmode)) + { + itemDefPtr->setCategoryInheritanceMode(cmode); + } + else + { + smtkErrorMacro( + smtk::io::Logger::instance(), + "When converting json, definition " + << itemDefPtr->label() + << " has an invalid category inheritance mode = " << *inheritanceMode); + } + } + else + { + auto okToInherit = catInfo->find("Inherit"); + if (okToInherit != catInfo->end()) + { + if (*okToInherit) + { + itemDefPtr->setCategoryInheritanceMode(Categories::CombinationMode::Or); + } + else + { + itemDefPtr->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); + } + } } attribute::Categories::Set& localCats = itemDefPtr->localCategories(); auto combineMode = catInfo->find("Combination"); // If Combination is not specified - assume the default value; if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setCombinationMode(cmode); } @@ -191,7 +219,7 @@ SMTKCORE_EXPORT void from_json( combineMode = catInfo->find("InclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setInclusionMode(cmode); } @@ -216,7 +244,7 @@ SMTKCORE_EXPORT void from_json( combineMode = catInfo->find("ExclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setExclusionMode(cmode); } @@ -241,12 +269,12 @@ SMTKCORE_EXPORT void from_json( else if (categories != j.end()) // Deprecated Format { smtk::attribute::Categories::Set& localCats = itemDefPtr->localCategories(); - smtk::attribute::Categories::Set::CombinationMode cmode; + smtk::attribute::Categories::CombinationMode cmode; result = j.find("categoryCheckMode"); // If categoryCheckMode is not specified - assume the default value; if (result != j.end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*result, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*result, cmode)) { localCats.setInclusionMode(cmode); } @@ -267,7 +295,14 @@ SMTKCORE_EXPORT void from_json( auto okToInherit = j.find("OkToInheritCategories"); if (okToInherit != j.end()) { - itemDefPtr->setIsOkToInherit(*okToInherit); + if (*okToInherit) + { + itemDefPtr->setCategoryInheritanceMode(Categories::CombinationMode::Or); + } + else + { + itemDefPtr->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); + } } result = j.find("Tags"); diff --git a/smtk/attribute/json/jsonResource.cxx b/smtk/attribute/json/jsonResource.cxx index 8be5c03ad1..808818a614 100644 --- a/smtk/attribute/json/jsonResource.cxx +++ b/smtk/attribute/json/jsonResource.cxx @@ -37,13 +37,12 @@ namespace attribute { using json = nlohmann::json; -/// \brief Provide a way to serialize an attribute::Resource. The current version is 4.0 but -/// but can also read in a resource in version 3.0 format. +/// \brief Provide a way to serialize an attribute::Resource. The current version is 6.0 but +/// but can also read in a resource from version 3.0 format or later. SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res) { smtk::resource::to_json(j, smtk::static_pointer_cast(res)); - // Set the version to 5.0 - j["version"] = "5.0"; + j["version"] = "6.0"; j["IsPrivate"] = res->isPrivate(); j["NameSeparator"] = res->defaultNameSeparator(); // Write out the active category information @@ -177,7 +176,7 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res) } j["Definitions"] = defsObj; - // Process Exceptions and Prerequistics + // Process Exceptions and Prerequisites std::vector defs; res->definitions(defs, true); for (const auto& def : defs) @@ -202,7 +201,7 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res) excsObj.push_back(types); } } - // Now the prerequistics + // Now the prerequisites auto prerequisitesTypes = def->prerequisiteTypeNames(); if (!prerequisitesTypes.empty()) { diff --git a/smtk/attribute/json/jsonValueItemDefinition.h b/smtk/attribute/json/jsonValueItemDefinition.h index 96da4dff9c..981ecc72d2 100644 --- a/smtk/attribute/json/jsonValueItemDefinition.h +++ b/smtk/attribute/json/jsonValueItemDefinition.h @@ -74,15 +74,13 @@ static void processDerivedValueDefToJson(json& j, ItemDefType defPtr) { // Process Category Info structureJson["CategoryInfo"]["Combination"] = - smtk::attribute::Categories::Set::combinationModeAsString( - categoryValues.combinationMode()); + smtk::attribute::Categories::combinationModeAsString(categoryValues.combinationMode()); // Inclusion Info if (!categoryValues.includedCategoryNames().empty()) { structureJson["CategoryInfo"]["InclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString( - categoryValues.inclusionMode()); + smtk::attribute::Categories::combinationModeAsString(categoryValues.inclusionMode()); structureJson["CategoryInfo"]["IncludeCategories"] = categoryValues.includedCategoryNames(); } @@ -91,8 +89,7 @@ static void processDerivedValueDefToJson(json& j, ItemDefType defPtr) if (!categoryValues.excludedCategoryNames().empty()) { structureJson["CategoryInfo"]["ExclusionCombination"] = - smtk::attribute::Categories::Set::combinationModeAsString( - categoryValues.exclusionMode()); + smtk::attribute::Categories::combinationModeAsString(categoryValues.exclusionMode()); structureJson["CategoryInfo"]["ExcludeCategories"] = categoryValues.excludedCategoryNames(); } @@ -210,11 +207,11 @@ static void processDerivedValueDefFromJson( { attribute::Categories::Set localCats; auto combineMode = catInfo->find("Combination"); - smtk::attribute::Categories::Set::CombinationMode cmode; + smtk::attribute::Categories::CombinationMode cmode; // If Combination is not specified - assume the default value; if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setCombinationMode(cmode); } @@ -231,7 +228,7 @@ static void processDerivedValueDefFromJson( combineMode = catInfo->find("InclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setInclusionMode(cmode); } @@ -256,7 +253,7 @@ static void processDerivedValueDefFromJson( combineMode = catInfo->find("ExclusionCombination"); if (combineMode != catInfo->end()) { - if (smtk::attribute::Categories::Set::combinationModeFromString(*combineMode, cmode)) + if (smtk::attribute::Categories::combinationModeFromString(*combineMode, cmode)) { localCats.setExclusionMode(cmode); } @@ -283,25 +280,17 @@ static void processDerivedValueDefFromJson( { smtk::attribute::Categories::Set localCats; auto ccm = structure->find("categoryCheckMode"); - smtk::attribute::Categories::Set::CombinationMode mode = - smtk::attribute::Categories::Set::CombinationMode::Any; + smtk::attribute::Categories::CombinationMode mode = + smtk::attribute::Categories::CombinationMode::Or; // If categoryCheckMode is not specified - assume the default value; if (ccm != structure->end()) { - if (*ccm == "All") - { - mode = smtk::attribute::Categories::Set::CombinationMode::All; - } - else if (*ccm == "Any") - { - mode = smtk::attribute::Categories::Set::CombinationMode::Any; - } - else + if (!smtk::attribute::Categories::combinationModeFromString(*ccm, mode)) { smtkErrorMacro( smtk::io::Logger::instance(), - "When converting json, Enum " << discreteEnum - << " has an invalid categoryCheckMode = " << *ccm); + "When converting json, Enum " + << discreteEnum << " has an invalid exclusion combination mode = " << *ccm); } } localCats.setInclusions(*catsValue, mode); diff --git a/smtk/attribute/operators/Read.cxx b/smtk/attribute/operators/Read.cxx index 8a9c1a56e8..c849c7a16b 100644 --- a/smtk/attribute/operators/Read.cxx +++ b/smtk/attribute/operators/Read.cxx @@ -80,9 +80,9 @@ Read::Result Read::operateInternal() VersionNumber version; try { - // Is this a supported version? Should be 3.0, 4.0, or 5.0. + // Is this a supported version? Should be 3.0, 4.0, 5.0, or 6.0. version = j.at("version"); - if (version >= VersionNumber(3) && version < VersionNumber(6)) + if (version >= VersionNumber(3) && version < VersionNumber(7)) { supportedVersion = true; } diff --git a/smtk/attribute/pybind11/PybindCategories.h b/smtk/attribute/pybind11/PybindCategories.h index d7662a7370..45e23979fc 100644 --- a/smtk/attribute/pybind11/PybindCategories.h +++ b/smtk/attribute/pybind11/PybindCategories.h @@ -26,12 +26,12 @@ inline py::class_< smtk::attribute::Categories > pybind11_init_smtk_attribute_Ca .def("passes", (bool (smtk::attribute::Categories::*)(const ::std::set<::std::string>&) const) &smtk::attribute::Categories::passes, py::arg("categories")) .def("passes", (bool (smtk::attribute::Categories::*)(const ::std::string&) const) &smtk::attribute::Categories::passes, py::arg("category")) .def("insert", (void (smtk::attribute::Categories::*)(const smtk::attribute::Categories&)) &smtk::attribute::Categories::insert, py::arg("categories")) - .def("insert", (void (smtk::attribute::Categories::*)(const smtk::attribute::Categories::Set&)) &smtk::attribute::Categories::insert, py::arg("categorySet")) + .def("insert", (bool (smtk::attribute::Categories::*)(const smtk::attribute::Categories::Set&)) &smtk::attribute::Categories::insert, py::arg("categorySet")) .def("reset", &smtk::attribute::Categories::reset) .def("size", &smtk::attribute::Categories::size) // NOTE that the Python form of this method is returning a copy since Python // doesn't support const references - .def("sets", &smtk::attribute::Categories::sets) + .def("stacks", &smtk::attribute::Categories::stacks) .def("categoryNames", &smtk::attribute::Categories::categoryNames) ; py::class_< smtk::attribute::Categories::Set >(instance, "Set") @@ -62,9 +62,22 @@ inline py::class_< smtk::attribute::Categories > pybind11_init_smtk_attribute_Ca .def("passes", (bool (smtk::attribute::Categories::Set::*)(const ::std::set<::std::string>&) const) &smtk::attribute::Categories::Set::passes, py::arg("categories")) .def("passes", (bool (smtk::attribute::Categories::Set::*)(const ::std::string&) const) &smtk::attribute::Categories::Set::passes, py::arg("category")) ; - py::enum_(instance, "CombinationMode") - .value("Any", smtk::attribute::Categories::Set::CombinationMode::Any) - .value("All", smtk::attribute::Categories::Set::CombinationMode::All) + py::class_< smtk::attribute::Categories::Stack >(instance, "Stack") + .def(py::init<>()) + .def("deepcopy", (smtk::attribute::Categories::Stack & (smtk::attribute::Categories::Stack::*)(::smtk::attribute::Categories::Stack const &)) &smtk::attribute::Categories::Stack::operator=) + + .def("append", &smtk::attribute::Categories::Stack::append) + .def("clear", &smtk::attribute::Categories::Stack::clear) + .def("empty", &smtk::attribute::Categories::Stack::empty) + .def("passes", (bool (smtk::attribute::Categories::Stack::*)(const ::std::set<::std::string>&) const) &smtk::attribute::Categories::Stack::passes, py::arg("categories")) + .def("passes", (bool (smtk::attribute::Categories::Stack::*)(const ::std::string&) const) &smtk::attribute::Categories::Stack::passes, py::arg("category")) + ; + py::enum_(instance, "CombinationMode") + .value("Any", smtk::attribute::Categories::CombinationMode::Or) + .value("All", smtk::attribute::Categories::CombinationMode::And) + .value("Or", smtk::attribute::Categories::CombinationMode::Or) + .value("And", smtk::attribute::Categories::CombinationMode::And) + .value("LocalOnly", smtk::attribute::Categories::CombinationMode::LocalOnly) .export_values(); return instance; } diff --git a/smtk/attribute/pybind11/PybindDefinition.h b/smtk/attribute/pybind11/PybindDefinition.h index c1d8a8a653..c1856bba9b 100644 --- a/smtk/attribute/pybind11/PybindDefinition.h +++ b/smtk/attribute/pybind11/PybindDefinition.h @@ -42,9 +42,9 @@ inline PySharedPtrClass< smtk::attribute::Definition > pybind11_init_smtk_attrib .def("isAbstract", &smtk::attribute::Definition::isAbstract) .def("setIsAbstract", &smtk::attribute::Definition::setIsAbstract, py::arg("isAbstractValue")) // NOTE that the Python form of this method is returning a copy since Python - // doesn't support const references - oly non-const method of localCategories supported - .def("isOkToInherit", &smtk::attribute::Definition::isOkToInherit) - .def("setIsOkToInherit", &smtk::attribute::Definition::setIsOkToInherit, py::arg("isOkToInheritCategoriesValue")) + // doesn't support const references - only non-const method of localCategories supported + .def("categoryInheritanceMode", &smtk::attribute::Definition::categoryInheritanceMode) + .def("setCategoryInheritanceMode", &smtk::attribute::Definition::setCategoryInheritanceMode, py::arg("categoryInheritanceModeValue")) .def("categories", &smtk::attribute::Definition::categories) .def("localCategories", (smtk::attribute::Categories::Set& (smtk::attribute::Definition::*)()) &smtk::attribute::Definition::localCategories) .def("setLocalCategories", &smtk::attribute::Definition::setLocalCategories, py::arg("catSet")) diff --git a/smtk/attribute/pybind11/PybindItemDefinition.h b/smtk/attribute/pybind11/PybindItemDefinition.h index 51d3378fba..a4e8cbe7fc 100644 --- a/smtk/attribute/pybind11/PybindItemDefinition.h +++ b/smtk/attribute/pybind11/PybindItemDefinition.h @@ -38,7 +38,7 @@ inline PySharedPtrClass< smtk::attribute::ItemDefinition > pybind11_init_smtk_at .def("createCopy", &smtk::attribute::ItemDefinition::createCopy, py::arg("info")) .def("detailedDescription", &smtk::attribute::ItemDefinition::detailedDescription) .def("isEnabledByDefault", &smtk::attribute::ItemDefinition::isEnabledByDefault) - .def("isOkToInherit", &smtk::attribute::ItemDefinition::isOkToInherit) + .def("categoryInheritanceMode", &smtk::attribute::ItemDefinition::categoryInheritanceMode) .def("isOptional", &smtk::attribute::ItemDefinition::isOptional) .def("label", &smtk::attribute::ItemDefinition::label) .def("name", &smtk::attribute::ItemDefinition::name) @@ -50,7 +50,7 @@ inline PySharedPtrClass< smtk::attribute::ItemDefinition > pybind11_init_smtk_at .def("setBriefDescription", &smtk::attribute::ItemDefinition::setBriefDescription, py::arg("text")) .def("setDetailedDescription", &smtk::attribute::ItemDefinition::setDetailedDescription, py::arg("text")) .def("setIsEnabledByDefault", &smtk::attribute::ItemDefinition::setIsEnabledByDefault, py::arg("isEnabledByDefaultValue")) - .def("setIsOkToInherit", &smtk::attribute::ItemDefinition::setIsOkToInherit, py::arg("isOkToInheritCategoriesValue")) + .def("setCategoryInheritanceMode", &smtk::attribute::ItemDefinition::setCategoryInheritanceMode, py::arg("categoryInheritanceModeValue")) .def("setIsOptional", &smtk::attribute::ItemDefinition::setIsOptional, py::arg("isOptionalValue")) .def("setLabel", &smtk::attribute::ItemDefinition::setLabel, py::arg("newLabel")) .def("setVersion", &smtk::attribute::ItemDefinition::setVersion, py::arg("myVersion")) diff --git a/smtk/attribute/testing/cxx/unitCategories.cxx b/smtk/attribute/testing/cxx/unitCategories.cxx index a4bc0ab611..aed7a9fd60 100644 --- a/smtk/attribute/testing/cxx/unitCategories.cxx +++ b/smtk/attribute/testing/cxx/unitCategories.cxx @@ -249,9 +249,11 @@ void setupAttributeResource(attribute::ResourcePtr& attRes) A->localCategories().insertInclusion("A"); GroupItemDefinitionPtr gItemDef0 = A->addItemDefinition("g1"); gItemDef0->localCategories().insertInclusion("g1"); + gItemDef0->setCategoryInheritanceMode(Categories::CombinationMode::Or); // Lets create a Discrete String Item with Enums having category and advance level info // assigned to some of them StringItemDefinitionPtr sItemDef0 = gItemDef0->addItemDefinition("s1"); + sItemDef0->setCategoryInheritanceMode(Categories::CombinationMode::Or); sItemDef0->localCategories().insertInclusion("s1"); sItemDef0->addDiscreteValue("a", "e1"); sItemDef0->addDiscreteValue("b", "e2"); @@ -262,31 +264,40 @@ void setupAttributeResource(attribute::ResourcePtr& attRes) sItemDef0->setEnumAdvanceLevel("e3", 10); StringItemDefinitionPtr sItemDef1 = sItemDef0->addItemDefinition("s2"); sItemDef1->localCategories().insertInclusion("s2"); - sItemDef1->setIsOkToInherit(false); + sItemDef1->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); VoidItemDefinitionPtr vItemDef = sItemDef1->addItemDefinition("v1"); vItemDef->localCategories().insertInclusion("v1"); + vItemDef->setCategoryInheritanceMode(Categories::CombinationMode::Or); GroupItemDefinitionPtr gItemDef1 = gItemDef0->addItemDefinition("g2"); gItemDef1->localCategories().insertInclusion("g2"); - gItemDef1->setIsOkToInherit(false); - sItemDef0 = gItemDef1->addItemDefinition("s3"); - sItemDef0->localCategories().insertInclusion("s3"); + gItemDef1->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); + StringItemDefinitionPtr sItemDef3 = gItemDef1->addItemDefinition("s3"); + sItemDef3->localCategories().insertInclusion("s3"); DefinitionPtr B = attRes->createDefinition("B", A); B->localCategories().insertInclusion("B"); + B->setCategoryInheritanceMode(Categories::CombinationMode::Or); vItemDef = B->addItemDefinition("v2"); vItemDef->localCategories().insertInclusion("v2"); + vItemDef->setCategoryInheritanceMode(Categories::CombinationMode::Or); DefinitionPtr C = attRes->createDefinition("C", A); C->localCategories().insertInclusion("C"); + C->setCategoryInheritanceMode(Categories::CombinationMode::Or); DefinitionPtr D = attRes->createDefinition("D", A); + D->setCategoryInheritanceMode(Categories::CombinationMode::Or); vItemDef = D->addItemDefinition("v3"); vItemDef->localCategories().insertInclusion("v3"); + vItemDef->setCategoryInheritanceMode(Categories::CombinationMode::Or); DefinitionPtr E = attRes->createDefinition("E"); E->localCategories().insertInclusion("E"); + E->setCategoryInheritanceMode(Categories::CombinationMode::Or); DefinitionPtr F = attRes->createDefinition("F"); vItemDef = F->addItemDefinition("v4"); + F->setCategoryInheritanceMode(Categories::CombinationMode::Or); DefinitionPtr G = attRes->createDefinition("G", A); - G->setIsOkToInherit(false); + G->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); vItemDef = G->addItemDefinition("v5"); vItemDef->localCategories().insertInclusion("v5"); + vItemDef->setCategoryInheritanceMode(Categories::CombinationMode::Or); attRes->finalizeDefinitions(); attRes->createAttribute("a", "A"); @@ -326,7 +337,7 @@ int unitCategories(int /*unused*/, char* /*unused*/[]) { "G", { "v5" } }, { "g1", { "A", "g1", "g2", "s1", "s2", "s3", "v1" } }, { "g2", { "g2", "s3" } }, - { "s1", { "A", "g1", "s1", "s2", "v1", "ec1", "ec2" } }, + { "s1", { "A", "g1", "s1", "s2", "v1" } }, { "s2", { "s2", "v1" } }, { "s3", { "g2", "s3" } }, { "v1", { "s2", "v1" } }, diff --git a/smtk/attribute/testing/cxx/unitExclusionCategories.cxx b/smtk/attribute/testing/cxx/unitExclusionCategories.cxx index 7505b5029a..cf09861239 100644 --- a/smtk/attribute/testing/cxx/unitExclusionCategories.cxx +++ b/smtk/attribute/testing/cxx/unitExclusionCategories.cxx @@ -70,15 +70,15 @@ bool testCategories( void setupAttributeResource(attribute::ResourcePtr& attRes) { // So we are going to create a bunch of items that will test out the various combinations - // of (a op1 b) op2 !(c op3 d) - where opx is either all or any. The items will be as follows: - // 0: all all all - // 1: all all any - // 2: all any all - // 3: all any any - // 4: any all all - // 5: any all any - // 6: any any all - // 7: any any any + // of (a op1 b) op2 !(c op3 d) - where opx is either And or Or. The items will be as follows: + // 0: And And And + // 1: And And Or + // 2: And Or And + // 3: And Or Or + // 4: Or And And + // 5: Or And Or + // 6: Or Or And + // 7: Or Or Or DefinitionPtr A = attRes->createDefinition("A"); Categories::Set testCats; @@ -88,51 +88,51 @@ void setupAttributeResource(attribute::ResourcePtr& attRes) testCats.insertExclusion("d"); StringItemDefinitionPtr sItemDef = A->addItemDefinition("s0"); - testCats.setInclusionMode(Categories::Set::CombinationMode::All); - testCats.setCombinationMode(Categories::Set::CombinationMode::All); - testCats.setExclusionMode(Categories::Set::CombinationMode::All); + testCats.setInclusionMode(Categories::CombinationMode::And); + testCats.setCombinationMode(Categories::CombinationMode::And); + testCats.setExclusionMode(Categories::CombinationMode::And); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s1"); - testCats.setInclusionMode(Categories::Set::CombinationMode::All); - testCats.setCombinationMode(Categories::Set::CombinationMode::All); - testCats.setExclusionMode(Categories::Set::CombinationMode::Any); + testCats.setInclusionMode(Categories::CombinationMode::And); + testCats.setCombinationMode(Categories::CombinationMode::And); + testCats.setExclusionMode(Categories::CombinationMode::Or); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s2"); - testCats.setInclusionMode(Categories::Set::CombinationMode::All); - testCats.setCombinationMode(Categories::Set::CombinationMode::Any); - testCats.setExclusionMode(Categories::Set::CombinationMode::All); + testCats.setInclusionMode(Categories::CombinationMode::And); + testCats.setCombinationMode(Categories::CombinationMode::Or); + testCats.setExclusionMode(Categories::CombinationMode::And); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s3"); - testCats.setInclusionMode(Categories::Set::CombinationMode::All); - testCats.setCombinationMode(Categories::Set::CombinationMode::Any); - testCats.setExclusionMode(Categories::Set::CombinationMode::Any); + testCats.setInclusionMode(Categories::CombinationMode::And); + testCats.setCombinationMode(Categories::CombinationMode::Or); + testCats.setExclusionMode(Categories::CombinationMode::Or); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s4"); - testCats.setInclusionMode(Categories::Set::CombinationMode::Any); - testCats.setCombinationMode(Categories::Set::CombinationMode::All); - testCats.setExclusionMode(Categories::Set::CombinationMode::All); + testCats.setInclusionMode(Categories::CombinationMode::Or); + testCats.setCombinationMode(Categories::CombinationMode::And); + testCats.setExclusionMode(Categories::CombinationMode::And); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s5"); - testCats.setInclusionMode(Categories::Set::CombinationMode::Any); - testCats.setCombinationMode(Categories::Set::CombinationMode::All); - testCats.setExclusionMode(Categories::Set::CombinationMode::Any); + testCats.setInclusionMode(Categories::CombinationMode::Or); + testCats.setCombinationMode(Categories::CombinationMode::And); + testCats.setExclusionMode(Categories::CombinationMode::Or); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s6"); - testCats.setInclusionMode(Categories::Set::CombinationMode::Any); - testCats.setCombinationMode(Categories::Set::CombinationMode::Any); - testCats.setExclusionMode(Categories::Set::CombinationMode::All); + testCats.setInclusionMode(Categories::CombinationMode::Or); + testCats.setCombinationMode(Categories::CombinationMode::Or); + testCats.setExclusionMode(Categories::CombinationMode::And); sItemDef->localCategories() = testCats; sItemDef = A->addItemDefinition("s7"); - testCats.setInclusionMode(Categories::Set::CombinationMode::Any); - testCats.setCombinationMode(Categories::Set::CombinationMode::Any); - testCats.setExclusionMode(Categories::Set::CombinationMode::Any); + testCats.setInclusionMode(Categories::CombinationMode::Or); + testCats.setCombinationMode(Categories::CombinationMode::Or); + testCats.setExclusionMode(Categories::CombinationMode::Or); sItemDef->localCategories() = testCats; attRes->finalizeDefinitions(); } diff --git a/smtk/attribute/testing/cxx/unitPassCategories.cxx b/smtk/attribute/testing/cxx/unitPassCategories.cxx index fd876c3053..84ad9fc9aa 100644 --- a/smtk/attribute/testing/cxx/unitPassCategories.cxx +++ b/smtk/attribute/testing/cxx/unitPassCategories.cxx @@ -31,11 +31,44 @@ using namespace smtk; namespace { +bool testEnumRelevance( + const ItemPtr item, + const std::set& cats, + const std::vector& result) +{ + // Cast the item's definition to a ValueItemDefinition + auto def = std::dynamic_pointer_cast(item->definition()); + if (!def) + { + std::cerr << " Testing Enums: Could not cast to ValueItemDefintion "; + return false; + } + auto res = def->relevantEnums(true, cats, false, 0); + if (res != result) + { + std::cerr << " Testing Enums: returned {"; + for (const auto& s : res) + { + std::cerr << "\"" << s << "\""; + } + std::cerr << "} should have been {"; + for (const auto& s : result) + { + std::cerr << "\"" << s << "\""; + } + std::cerr << "}"; + return false; + } + std::cerr << " Testing Enums: "; + return true; +} + bool testCategories( const AttributePtr& att, const ItemPtr s[], const std::set& cats, - bool result[]) + bool result[], + const std::vector& enumResults) { bool status = true; if (att->categories().passes(cats) == result[0]) @@ -47,7 +80,7 @@ bool testCategories( std::cerr << att->name() << ":failed "; status = false; } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 6; i++) { if (s[i]->categories().passes(cats) == result[i + 1]) { @@ -59,6 +92,16 @@ bool testCategories( status = false; } } + if (testEnumRelevance(s[3], cats, enumResults)) + { + std::cerr << ":passed "; + } + else + { + std::cerr << ":failed "; + status = false; + } + if (status) { std::cerr << " - PASSED\n"; @@ -87,7 +130,7 @@ bool testValidity( status = false; } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 6; i++) { if (s[i]->isValid(cats) == result[i + 1]) { @@ -115,14 +158,16 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi // Lets find the Attribute and its Items AttributePtr att = attRes->findAttribute("TestAtt"); smtkTest(att != nullptr, "Could not find attribute!"); - ItemPtr s[4]; - bool catResults[5], valResults[5]; + ItemPtr s[6]; + bool catResults[7], valResults[7]; std::set cats; bool status = true; s[0] = att->find("s0"); s[1] = att->find("s1"); s[2] = att->find("s2"); s[3] = att->find("s3"); + s[4] = att->find("s4"); + s[5] = att->find("s5"); std::cerr << "TestAtt Categories: "; att->categories().print(); @@ -135,17 +180,25 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi } // Passing Category checks - // s0 should pass if given A, a, b, or nothing - // s1 should pass if given b, c or nothing - // s2 should pass if only given nothing or A or (d and e) - // s3 should pass if only given nothing or A or (a and b) or (c or d) + // s0 should pass if given A, a, or b + // s1 should pass if given b, or c + // s2 should pass if only A or (d and e) + // s3 should pass if only A + // s4 should pass if A and (a or b) + // s5 should pass if A and d and e // Passing Validity checks // A should pass if given A or a or Z - only s0 has a default value // s0 should pass always // s1 should pass if not given b or c // s2 should pass if not given {A or (d and e)} - // s3 should pass if not given {A or (a and b) or (c or d)} + // s3 should pass if not given {A} + // s4 should always pass since when its relevant it has a value + // s5 should pass if not given {A or d or e} + + // s3's Relevant Enum Checks + // e1 if a and b + // e2 if c or d std::cerr << prefix << " Testing Categories with {} :"; catResults[0] = false; @@ -153,13 +206,17 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[2] = false; catResults[3] = false; catResults[4] = false; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, {})) ? status : false; std::cerr << prefix << " Testing Validity with {} :"; valResults[0] = true; valResults[1] = true; valResults[2] = true; valResults[3] = true; valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z} :"; @@ -169,13 +226,17 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[2] = false; catResults[3] = false; catResults[4] = false; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, {})) ? status : false; std::cerr << prefix << " Testing Validity with {Z} :"; valResults[0] = true; valResults[1] = true; valResults[2] = true; valResults[3] = true; valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,A} :"; @@ -185,13 +246,17 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[2] = false; catResults[3] = true; catResults[4] = true; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, {})) ? status : false; std::cerr << prefix << " Testing Validity with {Z,A} :"; valResults[0] = false; valResults[1] = true; valResults[2] = true; valResults[3] = false; valResults[4] = false; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,b} :"; @@ -202,13 +267,17 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[2] = true; catResults[3] = false; catResults[4] = false; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, {})) ? status : false; std::cerr << prefix << " Testing Validity with {Z,b} :"; valResults[0] = false; valResults[1] = true; valResults[2] = false; valResults[3] = true; valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,a,b} :"; @@ -217,14 +286,18 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[1] = true; catResults[2] = true; catResults[3] = false; - catResults[4] = true; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[4] = false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, { "e1" })) ? status : false; std::cerr << prefix << " Testing Validity with {Z,a,b} :"; valResults[0] = false; valResults[1] = true; valResults[2] = false; valResults[3] = true; - valResults[4] = false; + valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,c} :"; @@ -235,14 +308,18 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[1] = false; catResults[2] = true; catResults[3] = false; - catResults[4] = true; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[4] = false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, { "e2" })) ? status : false; std::cerr << prefix << " Testing Validity with {Z,c} :"; valResults[0] = false; valResults[1] = true; valResults[2] = false; valResults[3] = true; - valResults[4] = false; + valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,d} :"; @@ -252,14 +329,18 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[1] = false; catResults[2] = false; catResults[3] = false; - catResults[4] = true; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[4] = false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, { "e2" })) ? status : false; std::cerr << prefix << " Testing Validity with {Z,d} :"; valResults[0] = true; valResults[1] = true; valResults[2] = true; valResults[3] = true; - valResults[4] = false; + valResults[4] = true; + valResults[5] = true; + valResults[6] = true; status = (testValidity(att, s, cats, valResults)) ? status : false; std::cerr << prefix << " Testing Categories with {Z,d,e} :"; @@ -268,14 +349,63 @@ bool testResource(const attribute::ResourcePtr& attRes, const std::string& prefi catResults[1] = false; catResults[2] = false; catResults[3] = true; - catResults[4] = true; - status = (testCategories(att, s, cats, catResults)) ? status : false; + catResults[4] = false; + catResults[5] = false; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, { "e2" })) ? status : false; std::cerr << prefix << " Testing Validity with {Z,d,e} :"; valResults[0] = false; valResults[1] = true; valResults[2] = true; valResults[3] = false; + valResults[4] = true; + valResults[5] = true; + valResults[6] = true; + status = (testValidity(att, s, cats, valResults)) ? status : false; + + std::cerr << prefix << " Testing Categories with {A, a} :"; + cats.clear(); + cats.insert("A"); + cats.insert("a"); + catResults[0] = true; + catResults[1] = true; + catResults[2] = false; + catResults[3] = true; + catResults[4] = true; + catResults[5] = true; + catResults[6] = false; + status = (testCategories(att, s, cats, catResults, {})) ? status : false; + std::cerr << prefix << " Testing Validity with {A, a} :"; + valResults[0] = false; + valResults[1] = true; + valResults[2] = true; + valResults[3] = false; + valResults[4] = false; + valResults[5] = true; + valResults[6] = true; + status = (testValidity(att, s, cats, valResults)) ? status : false; + + std::cerr << prefix << " Testing Categories with {A, d, e} :"; + cats.clear(); + cats.insert("A"); + cats.insert("d"); + cats.insert("e"); + catResults[0] = true; + catResults[1] = true; + catResults[2] = false; + catResults[3] = true; + catResults[4] = true; + catResults[5] = false; + catResults[6] = true; + status = (testCategories(att, s, cats, catResults, { "e2" })) ? status : false; + std::cerr << prefix << " Testing Validity with {A, a} :"; + valResults[0] = false; + valResults[1] = true; + valResults[2] = true; + valResults[3] = false; valResults[4] = false; + valResults[5] = true; + valResults[6] = false; status = (testValidity(att, s, cats, valResults)) ? status : false; return status; @@ -286,30 +416,40 @@ void setupAttributeResource(attribute::ResourcePtr& attRes) DefinitionPtr A = attRes->createDefinition("A"); A->localCategories().insertInclusion("A"); StringItemDefinitionPtr sItemDef0 = A->addItemDefinition("s0"); + sItemDef0->setCategoryInheritanceMode(Categories::CombinationMode::Or); sItemDef0->localCategories().insertInclusion("a"); sItemDef0->localCategories().insertInclusion("b"); sItemDef0->setDefaultValue("foo"); StringItemDefinitionPtr sItemDef1 = A->addItemDefinition("s1"); sItemDef1->localCategories().insertInclusion("b"); sItemDef1->localCategories().insertInclusion("c"); - sItemDef1->setIsOkToInherit(false); + sItemDef1->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); StringItemDefinitionPtr sItemDef2 = A->addItemDefinition("s2"); + sItemDef2->setCategoryInheritanceMode(Categories::CombinationMode::Or); sItemDef2->localCategories().insertInclusion("d"); sItemDef2->localCategories().insertInclusion("e"); - sItemDef2->localCategories().setInclusionMode(Categories::Set::CombinationMode::All); + sItemDef2->localCategories().setInclusionMode(Categories::Set::CombinationMode::And); StringItemDefinitionPtr sItemDef3 = A->addItemDefinition("s3"); sItemDef3->addDiscreteValue("a", "e1"); sItemDef3->addDiscreteValue("b", "e2"); smtk::attribute::Categories::Set es; es.insertInclusion("a"); es.insertInclusion("b"); - es.setInclusionMode(Categories::Set::CombinationMode::All); + es.setInclusionMode(Categories::Set::CombinationMode::And); sItemDef3->setEnumCategories("e1", es); es.reset(); es.insertInclusion("c"); es.insertInclusion("d"); - es.setInclusionMode(Categories::Set::CombinationMode::Any); + es.setInclusionMode(Categories::Set::CombinationMode::Or); sItemDef3->setEnumCategories("e2", es); + StringItemDefinitionPtr sItemDef4 = A->addItemDefinition("s4"); + sItemDef4->localCategories().insertInclusion("a"); + sItemDef4->localCategories().insertInclusion("b"); + sItemDef4->setDefaultValue("foo"); + StringItemDefinitionPtr sItemDef5 = A->addItemDefinition("s5"); + sItemDef5->localCategories().insertInclusion("d"); + sItemDef5->localCategories().insertInclusion("e"); + sItemDef5->localCategories().setInclusionMode(Categories::Set::CombinationMode::And); attRes->finalizeDefinitions(); attRes->createAttribute("TestAtt", "A"); } diff --git a/smtk/common/Deprecation.h b/smtk/common/Deprecation.h index 2d37d471cb..a204968c84 100644 --- a/smtk/common/Deprecation.h +++ b/smtk/common/Deprecation.h @@ -56,6 +56,12 @@ #define SMTK_DEPRECATION_REASON(version_major, version_minor, reason) \ "SMTK Deprecated in " #version_major "." #version_minor ": " reason +#if SMTK_DEPRECATION_LEVEL >= SMTK_VERSION_CHECK(22, 06) +#define SMTK_DEPRECATED_IN_22_07(reason) SMTK_DEPRECATION(SMTK_DEPRECATION_REASON(22, 07, reason)) +#else +#define SMTK_DEPRECATED_IN_22_07(reason) +#endif + #if SMTK_DEPRECATION_LEVEL >= SMTK_VERSION_CHECK(22, 04) #define SMTK_DEPRECATED_IN_22_04(reason) SMTK_DEPRECATION(SMTK_DEPRECATION_REASON(22, 04, reason)) #else diff --git a/smtk/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index 51db12c2a8..094ff9e7aa 100644 --- a/smtk/extension/qt/qtDiscreteValueEditor.cxx +++ b/smtk/extension/qt/qtDiscreteValueEditor.cxx @@ -126,29 +126,21 @@ void qtDiscreteValueEditor::createWidget() // settings combo->addItem("Please Select", -1); combo->setItemData(0, QColor(Qt::red), Qt::ForegroundRole); - for (size_t i = 0; i < itemDef->numberOfDiscreteValues(); i++) + std::string defaultEnum; + if (itemDef->hasDefault()) { - std::string enumText = itemDef->discreteEnum(static_cast(i)); - // Check its categories and advance level if appropriate - const auto& cats = itemDef->enumCategories(enumText); - if (!cats.empty() && attResource && !attResource->passActiveCategoryCheck(cats)) - { - // enum failed category check - continue; - } - if ( - itemDef->hasEnumAdvanceLevel(enumText) && (uiManager != nullptr) && - !uiManager->passAdvancedCheck(itemDef->enumAdvanceLevel(enumText))) - { - // enum failed advance level check - continue; - } - if (itemDef->hasDefault() && static_cast(itemDef->defaultDiscreteIndex()) == i) + defaultEnum = itemDef->discreteEnum(itemDef->defaultDiscreteIndex()); + } + + std::vector validEnums = item->relevantEnums(true, true, uiManager->advanceLevel()); + for (size_t i = 0; i < validEnums.size(); i++) + { + if ((!defaultEnum.empty()) && (validEnums[i] == defaultEnum)) { - tooltip = "Default: " + QString(enumText.c_str()); - enumText += " (Default)"; + tooltip = "Default: " + QString(validEnums[i].c_str()); + validEnums[i] += " (Default)"; } - combo->addItem(enumText.c_str(), (int)i); + combo->addItem(validEnums[i].c_str(), (int)i); } if (!tooltip.isEmpty()) diff --git a/smtk/io/AttributeReader.cxx b/smtk/io/AttributeReader.cxx index ddd5450670..8ab83fb98d 100644 --- a/smtk/io/AttributeReader.cxx +++ b/smtk/io/AttributeReader.cxx @@ -15,6 +15,7 @@ #include "smtk/io/XmlDocV3Parser.h" #include "smtk/io/XmlDocV4Parser.h" #include "smtk/io/XmlDocV5Parser.h" +#include "smtk/io/XmlDocV6Parser.h" #include "smtk/attribute/Attribute.h" #include "smtk/attribute/Definition.h" @@ -117,14 +118,19 @@ void AttributeReaderInternals::print(smtk::attribute::ResourcePtr resource) // Returns the attribute resource root node in a pugi doc pugi::xml_node AttributeReaderInternals::getRootNode(pugi::xml_document& doc) { - if (XmlDocV1Parser::canParse(doc)) + if (XmlDocV6Parser::canParse(doc)) { - return XmlDocV1Parser::getRootNode(doc); + return XmlDocV6Parser::getRootNode(doc); } - if (XmlDocV2Parser::canParse(doc)) + if (XmlDocV5Parser::canParse(doc)) { - return XmlDocV2Parser::getRootNode(doc); + return XmlDocV5Parser::getRootNode(doc); + } + + if (XmlDocV4Parser::canParse(doc)) + { + return XmlDocV4Parser::getRootNode(doc); } if (XmlDocV3Parser::canParse(doc)) @@ -132,14 +138,14 @@ pugi::xml_node AttributeReaderInternals::getRootNode(pugi::xml_document& doc) return XmlDocV3Parser::getRootNode(doc); } - if (XmlDocV4Parser::canParse(doc)) + if (XmlDocV2Parser::canParse(doc)) { - return XmlDocV4Parser::getRootNode(doc); + return XmlDocV2Parser::getRootNode(doc); } - if (XmlDocV5Parser::canParse(doc)) + if (XmlDocV1Parser::canParse(doc)) { - return XmlDocV5Parser::getRootNode(doc); + return XmlDocV1Parser::getRootNode(doc); } pugi::xml_node temp; // no node found @@ -152,7 +158,7 @@ std::string AttributeReaderInternals::getDirectory( const std::string& fname, const std::vector& spaths) { - // Are we dealing with an absoulte path + // Are we dealing with an absolute path path p(fname); if (!p.root_path().empty()) { @@ -273,16 +279,23 @@ void AttributeReaderInternals::parseXml( } // Lets see if any of the parsers can process the node - if (XmlDocV1Parser::canParse(root)) + if (XmlDocV6Parser::canParse(root)) { - XmlDocV1Parser theReader(resource, logger); + XmlDocV6Parser theReader(resource, logger); theReader.setIncludeFileIndex(m_currentFileIndex); theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); theReader.process(root); } - else if (XmlDocV2Parser::canParse(root)) + else if (XmlDocV5Parser::canParse(root)) { - XmlDocV2Parser theReader(resource, logger); + XmlDocV5Parser theReader(resource, logger); + theReader.setIncludeFileIndex(m_currentFileIndex); + theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); + theReader.process(root); + } + else if (XmlDocV4Parser::canParse(root)) + { + XmlDocV4Parser theReader(resource, logger); theReader.setIncludeFileIndex(m_currentFileIndex); theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); theReader.process(root); @@ -294,16 +307,16 @@ void AttributeReaderInternals::parseXml( theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); theReader.process(root); } - else if (XmlDocV4Parser::canParse(root)) + else if (XmlDocV2Parser::canParse(root)) { - XmlDocV4Parser theReader(resource, logger); + XmlDocV2Parser theReader(resource, logger); theReader.setIncludeFileIndex(m_currentFileIndex); theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); theReader.process(root); } - else if (XmlDocV5Parser::canParse(root)) + else if (XmlDocV1Parser::canParse(root)) { - XmlDocV5Parser theReader(resource, logger); + XmlDocV1Parser theReader(resource, logger); theReader.setIncludeFileIndex(m_currentFileIndex); theReader.setReportDuplicateDefinitionsAsErrors(reportAsError); theReader.process(root); diff --git a/smtk/io/AttributeWriter.cxx b/smtk/io/AttributeWriter.cxx index 62afc7ed22..855feee7c4 100644 --- a/smtk/io/AttributeWriter.cxx +++ b/smtk/io/AttributeWriter.cxx @@ -11,12 +11,12 @@ #include "smtk/io/AttributeWriter.h" #include "smtk/io/Logger.h" #include "smtk/io/XmlStringWriter.h" -#include "smtk/io/XmlV5StringWriter.h" +#include "smtk/io/XmlV6StringWriter.h" #include #include -#define DEFAULT_FILE_VERSION 5 -#define MAX_FILE_VERSION 5 +#define DEFAULT_FILE_VERSION 6 +#define MAX_FILE_VERSION 6 //force to use filesystem version 3 #define BOOST_FILESYSTEM_VERSION 3 #include @@ -167,7 +167,8 @@ XmlStringWriter* AttributeWriter::newXmlStringWriter( case 3: case 4: case 5: - writer = new XmlV5StringWriter(resource, logger); + case 6: + writer = new XmlV6StringWriter(resource, logger); break; default: diff --git a/smtk/io/CMakeLists.txt b/smtk/io/CMakeLists.txt index 93e2fcbc0e..9ad6e7c0ad 100644 --- a/smtk/io/CMakeLists.txt +++ b/smtk/io/CMakeLists.txt @@ -13,10 +13,12 @@ set(ioSrcs XmlDocV3Parser.cxx XmlDocV4Parser.cxx XmlDocV5Parser.cxx + XmlDocV6Parser.cxx XmlV2StringWriter.cxx XmlV3StringWriter.cxx XmlV4StringWriter.cxx XmlV5StringWriter.cxx + XmlV6StringWriter.cxx ) set(ioHeaders @@ -33,11 +35,13 @@ set(ioHeaders XmlDocV3Parser.h XmlDocV4Parser.h XmlDocV5Parser.h + XmlDocV6Parser.h XmlStringWriter.h XmlV2StringWriter.h XmlV3StringWriter.h XmlV4StringWriter.h XmlV5StringWriter.h + XmlV6StringWriter.h ) # mesh-related I/O diff --git a/smtk/io/XmlDocV1Parser.cxx b/smtk/io/XmlDocV1Parser.cxx index d8870f9db0..006b354c4f 100644 --- a/smtk/io/XmlDocV1Parser.cxx +++ b/smtk/io/XmlDocV1Parser.cxx @@ -970,92 +970,47 @@ void XmlDocV1Parser::processAssociationDef(xml_node& node, DefinitionPtr def) def->setLocalAssociationRule(assocDef); } -void XmlDocV1Parser::processItemDef(xml_node& node, ItemDefinitionPtr idef) +void XmlDocV1Parser::processCategories( + xml_node& node, + Categories::Set& catSet, + Categories::CombinationMode& inheritanceMode) { - xml_attribute xatt; - xml_node catNodes, child; attribute::Categories::Set::CombinationMode catMode; - xatt = node.attribute("Label"); - if (xatt) - { - idef->setLabel(xatt.value()); - } - xatt = node.attribute("Version"); - if (xatt) - { - idef->setVersion(xatt.as_int()); - } - xatt = node.attribute("Optional"); - if (xatt) - { - idef->setIsOptional(xatt.as_bool()); - idef->setIsEnabledByDefault(node.attribute("IsEnabledByDefault").as_bool()); - } - // This is the old format for categories - xatt = node.attribute("OkToInheritCategories"); - if (xatt) + xml_node child; + + // The default inheritance mode is Or + inheritanceMode = Categories::CombinationMode::Or; + + // Check for old style + xml_attribute xatt = node.attribute("OkToInheritCategories"); + if (xatt && !xatt.as_bool()) { - idef->setIsOkToInherit(xatt.as_bool()); + inheritanceMode = Categories::CombinationMode::LocalOnly; } - // This is the old format for categories xatt = node.attribute("CategoryCheckMode"); if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) { - idef->localCategories().setInclusionMode(catMode); - } - // If using AdvanceLevel then we are setting - // both read and write - xatt = node.attribute("AdvanceLevel"); - if (xatt) - { - idef->setLocalAdvanceLevel(0, xatt.as_uint()); - idef->setLocalAdvanceLevel(1, xatt.as_uint()); - } - else - { - xatt = node.attribute("AdvanceReadLevel"); - if (xatt) - { - idef->setLocalAdvanceLevel(0, xatt.as_uint()); - } - xatt = node.attribute("AdvanceWriteLevel"); - if (xatt) - { - idef->setLocalAdvanceLevel(1, xatt.as_uint()); - } + catSet.setInclusionMode(catMode); } - child = node.child("BriefDescription"); - if (child) - { - idef->setBriefDescription(child.text().get()); - } - - child = node.child("DetailedDescription"); - if (child) - { - idef->setDetailedDescription(child.text().get()); - } - - // This is the old format for categories - catNodes = node.child("Categories"); + // This is old style + xml_node catNodes = node.child("Categories"); // This is the new format xml_node catInfoNode = node.child("CategoryInfo"); if (catInfoNode) { - auto& localCats = idef->localCategories(); // Are we inheriting categories? xatt = catInfoNode.attribute("Inherit"); - if (xatt) + if (xatt && !xatt.as_bool()) { - idef->setIsOkToInherit(xatt.as_bool()); + inheritanceMode = Categories::CombinationMode::LocalOnly; } // Lets get the overall combination mode xatt = catInfoNode.attribute("Combination"); if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) { - localCats.setCombinationMode(catMode); + catSet.setCombinationMode(catMode); } // Get the Include set (if one exists) xml_node catGroup; @@ -1066,11 +1021,11 @@ void XmlDocV1Parser::processItemDef(xml_node& node, ItemDefinitionPtr idef) xatt = catGroup.attribute("Combination"); if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) { - localCats.setInclusionMode(catMode); + catSet.setInclusionMode(catMode); } for (child = catGroup.first_child(); child; child = child.next_sibling()) { - localCats.insertInclusion(child.text().get()); + catSet.insertInclusion(child.text().get()); } } catGroup = catInfoNode.child("Exclude"); @@ -1080,11 +1035,11 @@ void XmlDocV1Parser::processItemDef(xml_node& node, ItemDefinitionPtr idef) xatt = catGroup.attribute("Combination"); if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) { - localCats.setExclusionMode(catMode); + catSet.setExclusionMode(catMode); } for (child = catGroup.first_child(); child; child = child.next_sibling()) { - localCats.insertExclusion(child.text().get()); + catSet.insertExclusion(child.text().get()); } } } @@ -1092,14 +1047,78 @@ void XmlDocV1Parser::processItemDef(xml_node& node, ItemDefinitionPtr idef) { for (child = catNodes.first_child(); child; child = child.next_sibling()) { - idef->localCategories().insertInclusion(child.text().get()); + catSet.insertInclusion(child.text().get()); } } - else if ( - !m_defaultCategory.empty() && !smtk::dynamic_pointer_cast(idef)) - { // group item definitions don't get categories +} +void XmlDocV1Parser::processItemDef(xml_node& node, ItemDefinitionPtr idef) +{ + xml_attribute xatt; + xml_node child; + xatt = node.attribute("Label"); + if (xatt) + { + idef->setLabel(xatt.value()); + } + xatt = node.attribute("Version"); + if (xatt) + { + idef->setVersion(xatt.as_int()); + } + xatt = node.attribute("Optional"); + if (xatt) + { + idef->setIsOptional(xatt.as_bool()); + idef->setIsEnabledByDefault(node.attribute("IsEnabledByDefault").as_bool()); + } + + // Process Category Information + Categories::CombinationMode inheritanceMode; + this->processCategories(node, idef->localCategories(), inheritanceMode); + idef->setCategoryInheritanceMode(inheritanceMode); + // If the definition's local categories are empty and is not a group definition + // and there is a default category defined - then use it + if ( + idef->localCategories().empty() && + !(m_defaultCategory.empty() || + smtk::dynamic_pointer_cast(idef))) + { idef->localCategories().insertInclusion(m_defaultCategory); } + + // If using AdvanceLevel then we are setting + // both read and write + xatt = node.attribute("AdvanceLevel"); + if (xatt) + { + idef->setLocalAdvanceLevel(0, xatt.as_uint()); + idef->setLocalAdvanceLevel(1, xatt.as_uint()); + } + else + { + xatt = node.attribute("AdvanceReadLevel"); + if (xatt) + { + idef->setLocalAdvanceLevel(0, xatt.as_uint()); + } + xatt = node.attribute("AdvanceWriteLevel"); + if (xatt) + { + idef->setLocalAdvanceLevel(1, xatt.as_uint()); + } + } + + child = node.child("BriefDescription"); + if (child) + { + idef->setBriefDescription(child.text().get()); + } + + child = node.child("DetailedDescription"); + if (child) + { + idef->setDetailedDescription(child.text().get()); + } } void XmlDocV1Parser::processDoubleDef(pugi::xml_node& node, attribute::DoubleItemDefinitionPtr idef) @@ -2643,7 +2662,7 @@ bool XmlDocV1Parser::getCategoryComboMode( if (xmlAtt) { std::string val = xmlAtt.value(); - if (smtk::attribute::Categories::Set::combinationModeFromString(val, mode)) + if (smtk::attribute::Categories::combinationModeFromString(val, mode)) { return true; } diff --git a/smtk/io/XmlDocV1Parser.h b/smtk/io/XmlDocV1Parser.h index 58477ec3f1..6d97f4a0ea 100644 --- a/smtk/io/XmlDocV1Parser.h +++ b/smtk/io/XmlDocV1Parser.h @@ -89,6 +89,10 @@ protected: void processAttributeInformation(pugi::xml_node& root); virtual void processViews(pugi::xml_node& root); virtual void processAssociationRules(pugi::xml_node&) {} + virtual void processCategories( + pugi::xml_node& node, + attribute::Categories::Set& catSet, + attribute::Categories::CombinationMode& inheritanceMode); void createDefinition(pugi::xml_node& defNode); virtual void processDefinitionInformation(pugi::xml_node& defNode); diff --git a/smtk/io/XmlDocV3Parser.cxx b/smtk/io/XmlDocV3Parser.cxx index 04eaf2dfcc..31afa5264a 100644 --- a/smtk/io/XmlDocV3Parser.cxx +++ b/smtk/io/XmlDocV3Parser.cxx @@ -469,75 +469,13 @@ void XmlDocV3Parser::processDefinitionInformation(xml_node& root) void XmlDocV3Parser::processDefinition(xml_node& defNode, DefinitionPtr def) { - Categories::Set::CombinationMode catMode; - //need to process Categories and Tags added in V3 + this->XmlDocV2Parser::processDefinition(defNode, def); - //This is the old style of category information - xml_attribute ccm = defNode.attribute("CategoryCheckMode"); - if (XmlDocV1Parser::getCategoryComboMode(ccm, catMode)) - { - def->localCategories().setInclusionMode(catMode); - } - xml_node catNodes = defNode.child("Categories"); - xml_node catInfoNode = defNode.child("CategoryInfo"); - xml_node child; - //Current Category Structure - if (catInfoNode) - { - catInfoNode.append_attribute("Inherit") = def->isOkToInherit(); - // Lets get the overall combination mode - ccm = catInfoNode.attribute("Combination"); - auto& localCats = def->localCategories(); - // Are we inheriting categories? - auto xatt = catInfoNode.attribute("Inherit"); - if (xatt) - { - def->setIsOkToInherit(xatt.as_bool()); - } - if (XmlDocV1Parser::getCategoryComboMode(ccm, catMode)) - { - localCats.setCombinationMode(catMode); - } - // Get the Include set (if one exists) - xml_node catGroup; - catGroup = catInfoNode.child("Include"); - if (catGroup) - { - // Lets get the include combination mode - ccm = catGroup.attribute("Combination"); - if (XmlDocV1Parser::getCategoryComboMode(ccm, catMode)) - { - localCats.setInclusionMode(catMode); - } - for (child = catGroup.first_child(); child; child = child.next_sibling()) - { - localCats.insertInclusion(child.text().get()); - } - } - catGroup = catInfoNode.child("Exclude"); - if (catGroup) - { - // Lets get the include combination mode - ccm = catGroup.attribute("Combination"); - if (XmlDocV1Parser::getCategoryComboMode(ccm, catMode)) - { - localCats.setExclusionMode(catMode); - } - for (child = catGroup.first_child(); child; child = child.next_sibling()) - { - localCats.insertExclusion(child.text().get()); - } - } - } - //Old Style - else if (catNodes) - { - for (xml_node child = catNodes.first_child(); child; child = child.next_sibling()) - { - def->localCategories().insertInclusion(child.text().get()); - } - } + // Process Category Information for the Definition + Categories::CombinationMode inheritanceMode; + this->processCategories(defNode, def->localCategories(), inheritanceMode); + def->setCategoryInheritanceMode(inheritanceMode); xml_node tagsNode = defNode.child("Tags"); if (tagsNode) diff --git a/smtk/io/XmlDocV6Parser.cxx b/smtk/io/XmlDocV6Parser.cxx new file mode 100644 index 0000000000..2893fe3338 --- /dev/null +++ b/smtk/io/XmlDocV6Parser.cxx @@ -0,0 +1,159 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= + +#include "smtk/io/XmlDocV6Parser.h" + +#include "smtk/common/StringUtil.h" + +#define PUGIXML_HEADER_ONLY +// NOLINTNEXTLINE(bugprone-suspicious-include) +#include "pugixml/src/pugixml.cpp" + +using namespace pugi; +using namespace smtk::attribute; +using namespace smtk::io; +using namespace smtk; + +XmlDocV6Parser::XmlDocV6Parser(smtk::attribute::ResourcePtr myResource, smtk::io::Logger& logger) + : XmlDocV5Parser(myResource, logger) +{ +} + +XmlDocV6Parser::~XmlDocV6Parser() = default; + +bool XmlDocV6Parser::canParse(pugi::xml_document& doc) +{ + // Get the attribute resource node + xml_node amnode = doc.child("SMTK_AttributeResource"); + if (amnode.empty()) + { + return false; + } + + pugi::xml_attribute xatt = amnode.attribute("Version"); + if (!xatt) + { + return false; + } + + int versionNum = xatt.as_int(); + return versionNum == 6; +} + +bool XmlDocV6Parser::canParse(pugi::xml_node& node) +{ + // Check the name of the node + std::string name = node.name(); + if (name != "SMTK_AttributeResource") + { + return false; + } + + pugi::xml_attribute xatt = node.attribute("Version"); + if (!xatt) + { + return false; + } + + int versionNum = xatt.as_int(); + return versionNum == 6; +} + +void XmlDocV6Parser::processCategories( + xml_node& node, + Categories::Set& catSet, + Categories::CombinationMode& inheritanceMode) +{ + attribute::Categories::Set::CombinationMode catMode; + xml_node child; + + // The default inheritance mode is And + inheritanceMode = Categories::CombinationMode::And; + + // Check for old style + xml_attribute xatt = node.attribute("OkToInheritCategories"); + if (xatt && !xatt.as_bool()) + { + inheritanceMode = Categories::CombinationMode::LocalOnly; + } + xatt = node.attribute("CategoryCheckMode"); + if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) + { + catSet.setInclusionMode(catMode); + } + + // This is old style + xml_node catNodes = node.child("Categories"); + // This is the new format + xml_node catInfoNode = node.child("CategoryInfo"); + if (catInfoNode) + { + // How are we inheriting categories + xatt = catInfoNode.attribute("InheritanceMode"); + if (xatt && XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) + { + inheritanceMode = catMode; + } + else // Check the old style + { + xatt = catInfoNode.attribute("Inherit"); + if (xatt) + { + // In teh old style inheriting meant or'ing + inheritanceMode = + xatt.as_bool() ? Categories::CombinationMode::Or : Categories::CombinationMode::LocalOnly; + } + } + + // Lets get the overall combination mode + xatt = catInfoNode.attribute("Combination"); + if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) + { + catSet.setCombinationMode(catMode); + } + // Get the Include set (if one exists) + xml_node catGroup; + catGroup = catInfoNode.child("Include"); + if (catGroup) + { + // Lets get the include combination mode + xatt = catGroup.attribute("Combination"); + if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) + { + catSet.setInclusionMode(catMode); + } + for (child = catGroup.first_child(); child; child = child.next_sibling()) + { + catSet.insertInclusion(child.text().get()); + } + } + catGroup = catInfoNode.child("Exclude"); + if (catGroup) + { + // Lets get the include combination mode + xatt = catGroup.attribute("Combination"); + if (XmlDocV1Parser::getCategoryComboMode(xatt, catMode)) + { + catSet.setExclusionMode(catMode); + } + for (child = catGroup.first_child(); child; child = child.next_sibling()) + { + catSet.insertExclusion(child.text().get()); + } + } + } + else if (catNodes) // Deprecated Format + { + for (child = catNodes.first_child(); child; child = child.next_sibling()) + { + catSet.insertInclusion(child.text().get()); + } + } +} diff --git a/smtk/io/XmlDocV6Parser.h b/smtk/io/XmlDocV6Parser.h new file mode 100644 index 0000000000..1d59f2a54b --- /dev/null +++ b/smtk/io/XmlDocV6Parser.h @@ -0,0 +1,43 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +// .NAME XmlDocV6Parser.h - +// .SECTION Description +// .SECTION See Also + +#ifndef __smtk_io_XmlDocV6Parser_h +#define __smtk_io_XmlDocV6Parser_h + +#include "smtk/io/XmlDocV5Parser.h" + +#include + +namespace smtk +{ +namespace io +{ +class SMTKCORE_EXPORT XmlDocV6Parser : public XmlDocV5Parser +{ +public: + XmlDocV6Parser(smtk::attribute::ResourcePtr resource, smtk::io::Logger& logger); + ~XmlDocV6Parser() override; + + static bool canParse(pugi::xml_node& node); + static bool canParse(pugi::xml_document& doc); + +protected: + void processCategories( + pugi::xml_node& node, + attribute::Categories::Set& catSet, + attribute::Categories::CombinationMode& inheritanceMode) override; +}; +} // namespace io +} // namespace smtk + +#endif /* __smtk_io_XmlDocV6Parser_h */ diff --git a/smtk/io/XmlV2StringWriter.cxx b/smtk/io/XmlV2StringWriter.cxx index 254a040cca..2f1b0f76ca 100644 --- a/smtk/io/XmlV2StringWriter.cxx +++ b/smtk/io/XmlV2StringWriter.cxx @@ -127,14 +127,14 @@ void processDerivedValueDef(pugi::xml_node& node, ItemDefType idef) xml_node catInfoNode = snode.append_child("CategoryInfo"); xml_node catGroupNode; catInfoNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(cats.combinationMode()).c_str()); + .set_value(Categories::combinationModeAsString(cats.combinationMode()).c_str()); // Inclusion Categories if (!cats.includedCategoryNames().empty()) { catGroupNode = catInfoNode.append_child("Include"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(cats.inclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(cats.inclusionMode()).c_str()); for (const auto& str : cats.includedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); @@ -145,7 +145,7 @@ void processDerivedValueDef(pugi::xml_node& node, ItemDefType idef) { catGroupNode = catInfoNode.append_child("Exclude"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(cats.exclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(cats.exclusionMode()).c_str()); for (const auto& str : cats.excludedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); @@ -718,16 +718,17 @@ void XmlV2StringWriter::processItemDefinitionAttributes(xml_node& node, ItemDefi // Lets write out the category stuff auto& localCats = idef->localCategories(); catInfoNode = node.append_child("CategoryInfo"); - catInfoNode.append_attribute("Inherit") = idef->isOkToInherit(); + catInfoNode.append_attribute("InheritanceMode") + .set_value(Categories::combinationModeAsString(idef->categoryInheritanceMode()).c_str()); catInfoNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.combinationMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.combinationMode()).c_str()); // Inclusion Categories if (!localCats.includedCategoryNames().empty()) { catGroupNode = catInfoNode.append_child("Include"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.inclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.inclusionMode()).c_str()); for (const auto& str : localCats.includedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); @@ -738,7 +739,7 @@ void XmlV2StringWriter::processItemDefinitionAttributes(xml_node& node, ItemDefi { catGroupNode = catInfoNode.append_child("Exclude"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.exclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.exclusionMode()).c_str()); for (const auto& str : localCats.excludedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); diff --git a/smtk/io/XmlV3StringWriter.cxx b/smtk/io/XmlV3StringWriter.cxx index 7b39353fe0..36abf247ef 100644 --- a/smtk/io/XmlV3StringWriter.cxx +++ b/smtk/io/XmlV3StringWriter.cxx @@ -253,16 +253,17 @@ void XmlV3StringWriter::processDefinitionInternal(xml_node& definition, Definiti auto& localCats = def->localCategories(); // Lets write out the category stuff xml_node catGroupNode, catInfoNode = definition.append_child("CategoryInfo"); - catInfoNode.append_attribute("Inherit") = def->isOkToInherit(); + catInfoNode.append_attribute("InheritanceMode") + .set_value(Categories::combinationModeAsString(def->categoryInheritanceMode()).c_str()); catInfoNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.combinationMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.combinationMode()).c_str()); // Inclusion Categories if (!localCats.includedCategoryNames().empty()) { catGroupNode = catInfoNode.append_child("Include"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.inclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.inclusionMode()).c_str()); for (const auto& str : localCats.includedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); @@ -273,7 +274,7 @@ void XmlV3StringWriter::processDefinitionInternal(xml_node& definition, Definiti { catGroupNode = catInfoNode.append_child("Exclude"); catGroupNode.append_attribute("Combination") - .set_value(Categories::Set::combinationModeAsString(localCats.exclusionMode()).c_str()); + .set_value(Categories::combinationModeAsString(localCats.exclusionMode()).c_str()); for (const auto& str : localCats.excludedCategoryNames()) { catGroupNode.append_child("Cat").text().set(str.c_str()); diff --git a/smtk/io/XmlV6StringWriter.cxx b/smtk/io/XmlV6StringWriter.cxx new file mode 100644 index 0000000000..6d12ac06ad --- /dev/null +++ b/smtk/io/XmlV6StringWriter.cxx @@ -0,0 +1,46 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= + +#include "smtk/io/XmlV6StringWriter.h" + +#define PUGIXML_HEADER_ONLY +// NOLINTNEXTLINE(bugprone-suspicious-include) +#include "pugixml/src/pugixml.cpp" + +using namespace pugi; +using namespace smtk; +using namespace smtk::attribute; + +namespace smtk +{ +namespace io +{ + +XmlV6StringWriter::XmlV6StringWriter( + const attribute::ResourcePtr myResource, + smtk::io::Logger& logger) + : XmlV5StringWriter(myResource, logger) +{ +} + +XmlV6StringWriter::~XmlV6StringWriter() = default; + +std::string XmlV6StringWriter::className() const +{ + return std::string("XmlV6StringWriter"); +} + +unsigned int XmlV6StringWriter::fileVersion() const +{ + return 6; +} + +} // namespace io +} // namespace smtk diff --git a/smtk/io/XmlV6StringWriter.h b/smtk/io/XmlV6StringWriter.h new file mode 100644 index 0000000000..3b7831e5fd --- /dev/null +++ b/smtk/io/XmlV6StringWriter.h @@ -0,0 +1,50 @@ +//========================================================================= +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//========================================================================= +// .NAME XmlV6StringWriter.h - +// .SECTION Description +// .SECTION See Also + +#ifndef __smtk_io_XmlV6StringWriter_h +#define __smtk_io_XmlV6StringWriter_h +#include "smtk/CoreExports.h" +#include "smtk/PublicPointerDefs.h" +#include "smtk/io/XmlV5StringWriter.h" + +#include "smtk/attribute/Resource.h" + +#include + +namespace pugi +{ +class xml_node; +} + +namespace smtk +{ +namespace io +{ +class SMTKCORE_EXPORT XmlV6StringWriter : public XmlV5StringWriter +{ +public: + XmlV6StringWriter(smtk::attribute::ResourcePtr resource, smtk::io::Logger& logger); + ~XmlV6StringWriter() override; + +protected: + // Override methods + // Three virtual methods for writing contents + std::string className() const override; + unsigned int fileVersion() const override; + +private: +}; +} // namespace io +} // namespace smtk + +#endif // __smtk_io_XmlV6StringWriter_h -- GitLab From 7ac7fc5f176402d136375af02f050997784f2c66 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 24 Jun 2022 02:27:57 -0400 Subject: [PATCH 37/44] Fix a crash on start; check before dereferencing. --- .../paraview/project/pqSMTKProjectAutoStart.cxx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx b/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx index db17c0fb5c..a5747d2a7e 100644 --- a/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx +++ b/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx @@ -36,14 +36,16 @@ void setView() // If the dock is not there, just try it again. if (panel) { - - auto phraseModel = std::dynamic_pointer_cast( - panel->resourceBrowser()->phraseModel()); - if (phraseModel) + if (auto* browser = panel->resourceBrowser()) { - phraseModel->setFilter([](const smtk::resource::Resource& resource) { - return !resource.isOfType(smtk::common::typeName()); - }); + auto phraseModel = + std::dynamic_pointer_cast(browser->phraseModel()); + if (phraseModel) + { + phraseModel->setFilter([](const smtk::resource::Resource& resource) { + return !resource.isOfType(smtk::common::typeName()); + }); + } } } else -- GitLab From 3419d4a14a6d6d47b4e6111c567cb8d0bfa46008 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 24 Jun 2022 02:28:35 -0400 Subject: [PATCH 38/44] Make resource panel ask application for configuration. ... and make the default application configuration provide one. --- doc/release/notes/paraview-resource-panel.rst | 8 ++++++ .../ApplicationConfiguration.cxx | 5 ++-- .../appcomponents/ApplicationConfiguration.h | 6 +++- .../DefaultConfiguration.cxx | 10 +++++++ .../appcomponents/pqSMTKResourcePanel.cxx | 28 ++++++++++++++++--- 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 doc/release/notes/paraview-resource-panel.rst diff --git a/doc/release/notes/paraview-resource-panel.rst b/doc/release/notes/paraview-resource-panel.rst new file mode 100644 index 0000000000..c671fbc9f6 --- /dev/null +++ b/doc/release/notes/paraview-resource-panel.rst @@ -0,0 +1,8 @@ +ParaView resource panel +----------------------- + +The :smtk:`pqSMTKResourcePanel` class now asks any :smtk:`smtk::view::ApplicationConfiguration` +present for view configuration before using a default. This makes it simpler for applications +to provide a custom phrase model, subphrase generator, or set of badges. +(Before this change, applications would have to wait for the panel to become ready and then +reconfigure it.) diff --git a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.cxx b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.cxx index 26742c4965..e2be502412 100644 --- a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.cxx +++ b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.cxx @@ -27,7 +27,7 @@ QMetaObject::Connection g_trackerConnection; std::vector ApplicationConfiguration::s_uiComponents; -void ApplicationConfiguration::notify(ConfigurationObserver observer) +bool ApplicationConfiguration::notify(ConfigurationObserver observer) { // Queue the observer in the list of UI components to be initialized. s_uiComponents.push_back(observer); @@ -43,7 +43,7 @@ void ApplicationConfiguration::notify(ConfigurationObserver observer) { if (ApplicationConfiguration::found(dynamic_cast(iface))) { - return; + return true; } } } @@ -56,6 +56,7 @@ void ApplicationConfiguration::notify(ConfigurationObserver observer) }); } } + return false; } bool ApplicationConfiguration::found(QObject* iface) diff --git a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h index ba323d4fd9..61ccd629d3 100644 --- a/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h +++ b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.h @@ -49,8 +49,12 @@ public: * or later upon the `pqInterfaceTracker::interfaceRegistered()` signal.) * Once found, the observer is invoked so it can configure components as needed by * calling methods on the interface. + * + * This method returns true if the configuration instance was invoked immediately + * and false if a signal is queued to fire should a configuration instance be + * registered later. */ - static void notify(ConfigurationObserver observer); + static bool notify(ConfigurationObserver observer); /**\brief Method for applications to provide configuration information for panels. * diff --git a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx index 338ad5acf3..9b5e18312b 100644 --- a/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx +++ b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.cxx @@ -10,6 +10,8 @@ #include "smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h" #include "smtk/extension/paraview/appcomponents/pqSMTKOperationToolboxPanel.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h" +#include "smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.h" #include "smtk/view/Configuration.h" #include "smtk/view/Information.h" #include "smtk/view/json/jsonView.h" @@ -39,6 +41,14 @@ smtk::view::Information DefaultConfiguration::panelConfiguration(const QWidget* std::shared_ptr viewConfig = jsonConfig; result.insert_or_assign(viewConfig); } + else if (const auto* browser = dynamic_cast(panel)) + { + (void)browser; + // Use the default JSON configuration for the resource-browser panel. + auto jsonConfig = nlohmann::json::parse(pqSMTKResourceBrowser::getJSONConfiguration())[0]; + std::shared_ptr viewConfig = jsonConfig; + result.insert_or_assign(viewConfig); + } else { smtkWarningMacro( diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx index 4ffea4499c..a2a60e5f64 100644 --- a/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx +++ b/smtk/extension/paraview/appcomponents/pqSMTKResourcePanel.cxx @@ -11,6 +11,7 @@ #include "smtk/extension/paraview/appcomponents/pqSMTKResourceBrowser.h" +#include "smtk/extension/paraview/appcomponents/ApplicationConfiguration.h" #include "smtk/extension/paraview/appcomponents/pqSMTKBehavior.h" #include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h" @@ -26,12 +27,31 @@ pqSMTKResourcePanel::pqSMTKResourcePanel(QWidget* parent) : Superclass(parent) { - // Parse a json representation of our default config, save it. - nlohmann::json j = nlohmann::json::parse(pqSMTKResourceBrowser::getJSONConfiguration()); - smtk::view::ConfigurationPtr config = j[0]; - this->setView(config); this->setObjectName("pqSMTKResourcePanel"); + // Either we get the application's configuration or we use a default + // until the application's configuration plugin is loaded. + bool immediatelyConfigured = false; + smtk::paraview::ApplicationConfiguration::notify( + [this, &immediatelyConfigured](smtk::paraview::ApplicationConfiguration& configurator) { + auto viewInfo = configurator.panelConfiguration(this); + // Extract just the view configuration. + auto viewConfig = viewInfo.get(); + if (viewConfig) + { + this->setView(viewConfig); + immediatelyConfigured = true; + } + }); + if (!immediatelyConfigured) + { + // Parse a json representation of our default config, and use it + // since the application can't immediately configure us. + nlohmann::json j = nlohmann::json::parse(pqSMTKResourceBrowser::getJSONConfiguration()); + smtk::view::ConfigurationPtr config = j[0]; + this->setView(config); + } + auto* smtkBehavior = pqSMTKBehavior::instance(); // Now listen for future connections. QObject::connect( -- GitLab From e86c2b0157854650c4a7f5729da16b76e8a17f9c Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 24 Jun 2022 02:30:08 -0400 Subject: [PATCH 39/44] Install missing header files. --- smtk/graph/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smtk/graph/CMakeLists.txt b/smtk/graph/CMakeLists.txt index 66e3130693..46a595a22a 100644 --- a/smtk/graph/CMakeLists.txt +++ b/smtk/graph/CMakeLists.txt @@ -23,6 +23,8 @@ set(graphHeaders filter/TypeName.h json/ArcSerializer.h json/ArcDeserializer.h + json/NodeSerializer.h + json/NodeDeserializer.h json/jsonResource.h ) -- GitLab From dbd1d0a8f4a47f1598d7f9289cf321f04a14442a Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 12 Jul 2022 11:06:26 -0400 Subject: [PATCH 40/44] BUG: Fixing Visibility Badge Update Needed to call triggerDataChangedFor the component whose visibility was being modified. --- smtk/extension/paraview/appcomponents/VisibilityBadge.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/smtk/extension/paraview/appcomponents/VisibilityBadge.cxx b/smtk/extension/paraview/appcomponents/VisibilityBadge.cxx index 4d34a7b45a..d45e023d8f 100644 --- a/smtk/extension/paraview/appcomponents/VisibilityBadge.cxx +++ b/smtk/extension/paraview/appcomponents/VisibilityBadge.cxx @@ -525,6 +525,11 @@ void VisibilityBadge::componentVisibilityChanged(smtk::resource::ComponentPtr co { // The visibility should change for every row displaying the same \a comp: m_visibleThings[comp->id()] = visible; + auto* model = this->phraseModel(); + if (model) + { + model->triggerDataChangedFor(comp); + } } } // namespace appcomponents } // namespace paraview -- GitLab From 4e23e9b669f6bda869b2456aa59cc21f0b508a8a Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 12 Jul 2022 15:10:30 -0400 Subject: [PATCH 41/44] Compile release notes for 22.07.00 --- ReadMe.md | 2 +- doc/release/index.rst | 1 + doc/release/notes/categoryChanges.rst | 47 ---- doc/release/notes/changesToQtInputsItem.rst | 4 - doc/release/notes/common-color.rst | 5 - doc/release/notes/dockwidget_refactor.rst | 12 -- doc/release/notes/geometry-color.rst | 18 -- doc/release/notes/graph-dump.rst | 8 - doc/release/notes/paraview-resource-panel.rst | 8 - doc/release/notes/paraview-selection.rst | 11 - doc/release/notes/qtitem_layout.rst | 27 --- doc/release/notes/qtitem_reset_to_default.rst | 16 -- doc/release/notes/resource-search-bar.rst | 7 - doc/release/smtk-22.07.rst | 200 ++++++++++++++++++ 14 files changed, 202 insertions(+), 164 deletions(-) delete mode 100644 doc/release/notes/categoryChanges.rst delete mode 100644 doc/release/notes/changesToQtInputsItem.rst delete mode 100644 doc/release/notes/common-color.rst delete mode 100644 doc/release/notes/dockwidget_refactor.rst delete mode 100644 doc/release/notes/geometry-color.rst delete mode 100644 doc/release/notes/graph-dump.rst delete mode 100644 doc/release/notes/paraview-resource-panel.rst delete mode 100644 doc/release/notes/paraview-selection.rst delete mode 100644 doc/release/notes/qtitem_layout.rst delete mode 100644 doc/release/notes/qtitem_reset_to_default.rst delete mode 100644 doc/release/notes/resource-search-bar.rst create mode 100644 doc/release/smtk-22.07.rst diff --git a/ReadMe.md b/ReadMe.md index 634d839197..8f1e3201a2 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -62,7 +62,7 @@ See [CONTRIBUTING.md][] for instructions to contribute. Latest Release Notes ==================== -Can be found [here](doc/release/smtk-22.05.rst). +Can be found [here](doc/release/smtk-22.07.rst). License ======= diff --git a/doc/release/index.rst b/doc/release/index.rst index 7af6aedc6f..dc2277fb79 100644 --- a/doc/release/index.rst +++ b/doc/release/index.rst @@ -5,6 +5,7 @@ Release notes .. toctree:: :maxdepth: 2 + smtk-22.07.rst smtk-22.05.rst smtk-22.04.rst smtk-22.02.rst diff --git a/doc/release/notes/categoryChanges.rst b/doc/release/notes/categoryChanges.rst deleted file mode 100644 index f620282b96..0000000000 --- a/doc/release/notes/categoryChanges.rst +++ /dev/null @@ -1,47 +0,0 @@ -Expanding SMTK Attribute Category Mechanism -------------------------------------------- - -Category Modeling in SMTK Attribute Resources has been enhanced to now support specialization as well as generalization. -Previously, an Attribute or Item Definition's local categories could only expand (make more general) the categories it was inheriting (or choose to ignore them all together). -With this release, SMTK now supports specializing (or making the category constraint more restrictive). - -Previously category inheritance was controlled by using the Definition's setIsOkToInherit method which would either **Or** its local categories with those it was inheriting or **Replace** them. This method (as well as isOkToInherit method) has been deprecated. The new methods for setting and retrieving category inheritance are: - -* setCategoryInheritanceMode -* categoryInheritanceMode - -The values that categoryInheritanceMode can be set to are: - -* smtk::attribute::Categories::CombinationMode::Or -* smtk::attribute::Categories::CombinationMode::And -* smtk::attribute::Categories::CombinationMode::LocalOnly - -Setting the mode to **Or** is the same as the previous setIsOkToInherit(true) - it will **or** the Definition's local categories with those that it is inheriting. Setting the mode to **And** will now **and** the Definition's local categories with those that it is inheriting. Setting the mode to **LocalOnly** will ignore the categories that the Definition is inheriting and is the same as the previous setIsOkToInherit(false). - -Changing the Default Category Inheritance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Previously the default mode was isOkToInherit = true which now corresponds to smtk::attribute::Categories::CombinationMode::Or. Upon discussing the new combination support of **And**, it was decided that the new default will be smtk::attribute::Categories::CombinationMode::And, meaning that a Definition will be more specialized category-wise than it's parent Definition. - -Change on Enum Categories -~~~~~~~~~~~~~~~~~~~~~~~~~ -Previously, categories on a Discrete Value Item Definition's Enums would add their categories to the Definition. With this release it is assumed that the enums' categories will be **and'd** with it's Definition, there is no longer a reason for the enum categories to be combined with the Definition's local categories. - -File Version Changes -~~~~~~~~~~~~~~~~~~~~ -Supporting these changes did require a new format for both Attribute XML and JSON files. The latest versions for both is now **6**. Older file formats will load in properly and should work based on the previous category rules. - -Developer changes -~~~~~~~~~~~~~~~~~~ - -The following methods and enums have been deprecated: - -* smtk::attributeCategories::Set::CombinationMode::Any -> please use smtk::attributeCategories::Set::CombinationMode::Or -* smtk::attributeCategories::Set::CombinationMode::All -> please use smtk::attributeCategories::Set::CombinationMode::And -* smtk::attribute::Definition::setIsOkToInherit -> please use smtk::attribute::Definition::setCategoryInheritanceMode -* smtk::attribute::Definition::isOkToInherit -> please use smtk::attribute::Definition::categoryInheritanceMode -* smtk::attribute::ItemDefinition::setIsOkToInherit -> please use smtk::attribute::ItemDefinition::setCategoryInheritanceMode -* smtk::attribute::ItemDefinition::isOkToInherit -> please use smtk::attribute::ItemDefinition::categoryInheritanceMode - -A new class for supporting the new combination modes has been developed called smtk::attribute::Categories::Stack which represents the category expression formed when combining inherited and local categories since we now need to maintain the order in which they are combined. - -The method smtk::attribute::ValueItem:relevantEnums(bool includeCategories, bool includeReadAccess, unsigned int readAccessLevel) const was added in order to return the set of enums that passed the activce category and advance level checks (if specified). diff --git a/doc/release/notes/changesToQtInputsItem.rst b/doc/release/notes/changesToQtInputsItem.rst deleted file mode 100644 index 67ebe59c0d..0000000000 --- a/doc/release/notes/changesToQtInputsItem.rst +++ /dev/null @@ -1,4 +0,0 @@ -Changes to qtInputsItem --------------------------- - -A qtInputsItem instance will now call the Signal Operator when creating a new expression attribute. diff --git a/doc/release/notes/common-color.rst b/doc/release/notes/common-color.rst deleted file mode 100644 index a7ffb3f23f..0000000000 --- a/doc/release/notes/common-color.rst +++ /dev/null @@ -1,5 +0,0 @@ -RGBA color conversion ---------------------- - -Now :smtk:`smtk::common::Color` includes methods to convert 4-tuples of floating-point -numbers into hexadecimal color specifiers (in addition to the 3-tuples it already handles). diff --git a/doc/release/notes/dockwidget_refactor.rst b/doc/release/notes/dockwidget_refactor.rst deleted file mode 100644 index 5a9e11f0d1..0000000000 --- a/doc/release/notes/dockwidget_refactor.rst +++ /dev/null @@ -1,12 +0,0 @@ -Panels separated from DockWidgets ---------------------------------- - -Previously, several `Panel` classes derived directly from `QDockWidget`, -so they could be docked by the user in whatever arrangement was desired. - -To allow re-use and rearrangement, these `Panel` classes now derive from -`QWidget`, and are placed inside a `pqSMTKDock` which derives from -`QDockWidget`. `pqSMTKDock` has a template parameter to allow it to create the -child `Panel` of the correct type. `Panel` classes must now implement `void -setTitle(QString title)` to provide the `pqSMTKDock` with the correct title, -and use `setWindowTitle()` to provide the initial dock window title. diff --git a/doc/release/notes/geometry-color.rst b/doc/release/notes/geometry-color.rst deleted file mode 100644 index a61d8771c1..0000000000 --- a/doc/release/notes/geometry-color.rst +++ /dev/null @@ -1,18 +0,0 @@ -Coloring renderable geometry ----------------------------- - -Before the property system was in wide use, the geometry -subsystem expected component colors to be passed via a -single-tuple field-data array on the renderable geometry. -Support for this was broken when support for coloring -by a floating-point property was added. - -This commit fixes an issue (properly scaling floating-point -colors when generating an integer-valued color array) and -re-enables support for passing color by field-data. -Support for passing color by entity property is preserved, -but field-data arrays are preferred if present (because -presumably the geometry backend added this array). - -This feature is being revived to support components inheriting -color from other components. diff --git a/doc/release/notes/graph-dump.rst b/doc/release/notes/graph-dump.rst deleted file mode 100644 index 870ae707e2..0000000000 --- a/doc/release/notes/graph-dump.rst +++ /dev/null @@ -1,8 +0,0 @@ -Graph-resource Dump improvements --------------------------------- - -While :smtk:`smtk::graph::Resource`'s dump() method is unchanged, -if you use ``resource->evaluateArcs()`` explicitly it is -now possible to set a color per arc type and to enable a -transparent background for the graph. -(This applies only to graphviz-formatted output.) diff --git a/doc/release/notes/paraview-resource-panel.rst b/doc/release/notes/paraview-resource-panel.rst deleted file mode 100644 index c671fbc9f6..0000000000 --- a/doc/release/notes/paraview-resource-panel.rst +++ /dev/null @@ -1,8 +0,0 @@ -ParaView resource panel ------------------------ - -The :smtk:`pqSMTKResourcePanel` class now asks any :smtk:`smtk::view::ApplicationConfiguration` -present for view configuration before using a default. This makes it simpler for applications -to provide a custom phrase model, subphrase generator, or set of badges. -(Before this change, applications would have to wait for the panel to become ready and then -reconfigure it.) diff --git a/doc/release/notes/paraview-selection.rst b/doc/release/notes/paraview-selection.rst deleted file mode 100644 index a1423a917e..0000000000 --- a/doc/release/notes/paraview-selection.rst +++ /dev/null @@ -1,11 +0,0 @@ -Selection filtering for graph resources ---------------------------------------- - -A bug in the pqSMTKSelectionFilterBehavior class has been fixed. -It prevented the default selection-responder operation from adding -graph nodes to the selection (basically, anything that could not be -cast to a model entity was rejected). - -Now the selection filter toolbar buttons only apply to model and -mesh entities; graph-resource components will always be passed -through. diff --git a/doc/release/notes/qtitem_layout.rst b/doc/release/notes/qtitem_layout.rst deleted file mode 100644 index c3cd02a726..0000000000 --- a/doc/release/notes/qtitem_layout.rst +++ /dev/null @@ -1,27 +0,0 @@ -qtItem changes ---------------- - -Several changes were made to the `qtItem` subclasses. - -1\. The new code hides the QLabel instance for an item if its label is -set to a (nonempty) blank string. Template writers use a whitespace -character to hide the label, however, a QFrame is still displayed and -takes up horizontal space. The new code essentially removes that unwanted -space. - -2\. The new code changes the Qt alignment for horizontal child-item layouts -from vertical-center to top, for aesthetic reasons. - -3\. The new code updates the logic for setting the layout direction -(horizontal or vertical) in `qtInputsItem` for various situations. - - * For ordinary value items, the default layout is horizontal, but can be - overridden by an ItemView ``. - * For extensible items, the layout is *always* vertical, and cannot be - overridden by an ItemView. - * For discrete value items with children items, the layout is either: - (a) horizontal, if each discrete value is assigned no child items or a - single child item having a blank string for its label; otherwise - (b) vertical. The discrete item layout can be overridden by an item - view, either `` or - ``. diff --git a/doc/release/notes/qtitem_reset_to_default.rst b/doc/release/notes/qtitem_reset_to_default.rst deleted file mode 100644 index b0c9cdea8b..0000000000 --- a/doc/release/notes/qtitem_reset_to_default.rst +++ /dev/null @@ -1,16 +0,0 @@ -Attribute items have a "Reset to Default" context menu item ------------------------------------------------------------ - -All the widget used to input values for attribute items have -a context menu item added called "Reset to Default", which will -change the value back to the default, if one is specified. If -no default is specified, the menu entry is disabled. - -Int, Double, String, File, and DateTime items are all supported, -including spinbox and multi-line views. Resource items can't have -a default specified. - -As a result, `qtInputItem` no longer set themselves back to the -default value when constructed - the default value is only -applied by the `ValueItem` when created, or when the user -chooses "Reset to Default". diff --git a/doc/release/notes/resource-search-bar.rst b/doc/release/notes/resource-search-bar.rst deleted file mode 100644 index 59273ee902..0000000000 --- a/doc/release/notes/resource-search-bar.rst +++ /dev/null @@ -1,7 +0,0 @@ -Resource panel search bar -------------------------- - -A search bar has been added to the resource panel by default. Users may search -for resource or components using a wildcard text-based search. The search bar -is specified in the JSON config by adding `"SearchBar": true` to the -`Attributes` group. diff --git a/doc/release/smtk-22.07.rst b/doc/release/smtk-22.07.rst new file mode 100644 index 0000000000..427661a0a5 --- /dev/null +++ b/doc/release/smtk-22.07.rst @@ -0,0 +1,200 @@ +.. _release-notes-22.07: + +========================= +SMTK 22.07 Release Notes +========================= + +See also :ref:`release-notes-22.05` for previous changes. + + +SMTK Common Changes +======================== + +RGBA color conversion +--------------------- + +Now :smtk:`smtk::common::Color` includes methods to convert 4-tuples of floating-point +numbers into hexadecimal color specifiers (in addition to the 3-tuples it already handles). + + +SMTK Attribute Resource Changes +=============================== + +Expanding SMTK Attribute Category Mechanism +------------------------------------------- + +Category Modeling in SMTK Attribute Resources has been enhanced to now support specialization as well as generalization. +Previously, an Attribute or Item Definition's local categories could only expand (make more general) the categories it was inheriting (or choose to ignore them all together). +With this release, SMTK now supports specializing (or making the category constraint more restrictive). + +Previously category inheritance was controlled by using the Definition's setIsOkToInherit method which would either **Or** its local categories with those it was inheriting or **Replace** them. This method (as well as isOkToInherit method) has been deprecated. The new methods for setting and retrieving category inheritance are: + +* setCategoryInheritanceMode +* categoryInheritanceMode + +The values that categoryInheritanceMode can be set to are: + +* smtk::attribute::Categories::CombinationMode::Or +* smtk::attribute::Categories::CombinationMode::And +* smtk::attribute::Categories::CombinationMode::LocalOnly + +Setting the mode to **Or** is the same as the previous setIsOkToInherit(true) - it will **or** the Definition's local categories with those that it is inheriting. Setting the mode to **And** will now **and** the Definition's local categories with those that it is inheriting. Setting the mode to **LocalOnly** will ignore the categories that the Definition is inheriting and is the same as the previous setIsOkToInherit(false). + +Changing the Default Category Inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously the default mode was isOkToInherit = true which now corresponds to smtk::attribute::Categories::CombinationMode::Or. Upon discussing the new combination support of **And**, it was decided that the new default will be smtk::attribute::Categories::CombinationMode::And, meaning that a Definition will be more specialized category-wise than it's parent Definition. + +Change on Enum Categories +~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, categories on a Discrete Value Item Definition's Enums would add their categories to the Definition. With this release it is assumed that the enums' categories will be **and'd** with it's Definition, there is no longer a reason for the enum categories to be combined with the Definition's local categories. + +File Version Changes +~~~~~~~~~~~~~~~~~~~~ +Supporting these changes did require a new format for both Attribute XML and JSON files. The latest versions for both is now **6**. Older file formats will load in properly and should work based on the previous category rules. + +Developer changes +~~~~~~~~~~~~~~~~~~ + +The following methods and enums have been deprecated: + +* smtk::attributeCategories::Set::CombinationMode::Any -> please use smtk::attributeCategories::Set::CombinationMode::Or +* smtk::attributeCategories::Set::CombinationMode::All -> please use smtk::attributeCategories::Set::CombinationMode::And +* smtk::attribute::Definition::setIsOkToInherit -> please use smtk::attribute::Definition::setCategoryInheritanceMode +* smtk::attribute::Definition::isOkToInherit -> please use smtk::attribute::Definition::categoryInheritanceMode +* smtk::attribute::ItemDefinition::setIsOkToInherit -> please use smtk::attribute::ItemDefinition::setCategoryInheritanceMode +* smtk::attribute::ItemDefinition::isOkToInherit -> please use smtk::attribute::ItemDefinition::categoryInheritanceMode + +A new class for supporting the new combination modes has been developed called smtk::attribute::Categories::Stack which represents the category expression formed when combining inherited and local categories since we now need to maintain the order in which they are combined. + +The method smtk::attribute::ValueItem:relevantEnums(bool includeCategories, bool includeReadAccess, unsigned int readAccessLevel) const was added in order to return the set of enums that passed the activce category and advance level checks (if specified). + + +SMTK QT Changes +================ + +Attribute items have a "Reset to Default" context menu item +----------------------------------------------------------- + +All the widgets used to input values for attribute items have +a context menu item added called "Reset to Default", which will +change the value back to the default, if one is specified. If +no default is specified, the menu entry is disabled. + +Int, Double, String, File, and DateTime items are all supported, +including spinbox and multi-line views. Resource items can't have +a default specified. + +As a result, `qtInputItem` no longer set themselves back to the +default value when constructed - the default value is only +applied by the `ValueItem` when created, or when the user +chooses "Reset to Default". + +qtItem changes +--------------- + +Several changes were made to the `qtItem` subclasses. + +1. The new code hides the QLabel instance for an item if its label is +set to a (nonempty) blank string. Template writers use a whitespace +character to hide the label, however, a QFrame is still displayed and +takes up horizontal space. The new code essentially removes that unwanted +space. + +2. The new code changes the Qt alignment for horizontal child-item layouts +from vertical-center to top, for aesthetic reasons. + +3. The new code updates the logic for setting the layout direction +(horizontal or vertical) in `qtInputsItem` for various situations. + +* For ordinary value items, the default layout is horizontal, but can be overridden by an ItemView ``. +* For extensible items, the layout is *always* vertical, and cannot be overridden by an ItemView. +* For discrete value items with children items, the layout is either: + + * **horizontal** - if each discrete value is assigned no child items or a + single child item having a blank string for its label + * **vertical** (otherwise) + * The discrete item layout can be overridden by an item + view, either `` or + ``. + +Changes to qtInputsItem +-------------------------- + +A qtInputsItem instance will now call the Signal Operator when creating a new expression attribute. + + +SMTK ParaView Extensions Changes +================================ + +Panels separated from DockWidgets +--------------------------------- + +Previously, several `Panel` classes derived directly from `QDockWidget`, +so they could be docked by the user in whatever arrangement was desired. + +To allow re-use and rearrangement, these `Panel` classes now derive from +`QWidget`, and are placed inside a `pqSMTKDock` which derives from +`QDockWidget`. `pqSMTKDock` has a template parameter to allow it to create the +child `Panel` of the correct type. `Panel` classes must now implement `void +setTitle(QString title)` to provide the `pqSMTKDock` with the correct title, +and use `setWindowTitle()` to provide the initial dock window title. + +ParaView resource panel +----------------------- + +The :smtk:`pqSMTKResourcePanel` class now asks any :smtk:`smtk::view::ApplicationConfiguration` +present for view configuration before using a default. This makes it simpler for applications +to provide a custom phrase model, subphrase generator, or set of badges. +(Before this change, applications would have to wait for the panel to become ready and then +reconfigure it.) + +Coloring renderable geometry +---------------------------- + +Before the property system was in wide use, the geometry +subsystem expected component colors to be passed via a +single-tuple field-data array on the renderable geometry. +Support for this was broken when support for coloring +by a floating-point property was added. + +This commit fixes an issue (properly scaling floating-point +colors when generating an integer-valued color array) and +re-enables support for passing color by field-data. +Support for passing color by entity property is preserved, +but field-data arrays are preferred if present (because +presumably the geometry backend added this array). + +This feature is being revived to support components inheriting +color from other components. + +Resource panel search bar +------------------------- + +A search bar has been added to the resource panel by default. Users may search +for resource or components using a wildcard text-based search. The search bar +is specified in the JSON config by adding `"SearchBar": true` to the +`Attributes` group. + +Selection filtering for graph resources +--------------------------------------- + +A bug in the pqSMTKSelectionFilterBehavior class has been fixed. +It prevented the default selection-responder operation from adding +graph nodes to the selection (basically, anything that could not be +cast to a model entity was rejected). + +Now the selection filter toolbar buttons only apply to model and +mesh entities; graph-resource components will always be passed +through. + +SMTK Graph Session Changes +========================== + +Graph-resource Dump improvements +-------------------------------- + +While :smtk:`smtk::graph::Resource`'s dump() method is unchanged, +if you use ``resource->evaluateArcs()`` explicitly it is +now possible to set a color per arc type and to enable a +transparent background for the graph. +(This applies only to graphviz-formatted output.) -- GitLab From 73a434657577da5121cd15736a90101e5fffb8b6 Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 12 Jul 2022 15:36:53 -0400 Subject: [PATCH 42/44] STYLE: Fixing Deprecation Warnings These files generated warnings when setting the new version to 22.07.00 Also corrected deprecation format for Windows and the deprecation macro for 22.07 --- smtk/attribute/Categories.cxx | 2 +- smtk/attribute/Categories.h | 21 ++++++++++++---- smtk/attribute/pybind11/PybindCategories.h | 1 - smtk/attribute/testing/cxx/categoryTest.cxx | 24 ++----------------- smtk/attribute/testing/cxx/unitIsRelevant.cxx | 2 +- smtk/common/Deprecation.h | 2 +- 6 files changed, 21 insertions(+), 31 deletions(-) diff --git a/smtk/attribute/Categories.cxx b/smtk/attribute/Categories.cxx index ae7a1dea28..648c00846a 100644 --- a/smtk/attribute/Categories.cxx +++ b/smtk/attribute/Categories.cxx @@ -180,7 +180,7 @@ bool Categories::Stack::passes(const std::set& cats) const return true; } } - else if ((it->first == CombinationMode::All) || (it->first == CombinationMode::LocalOnly)) + else if ((it->first == CombinationMode::And) || (it->first == CombinationMode::LocalOnly)) { return false; } diff --git a/smtk/attribute/Categories.h b/smtk/attribute/Categories.h index 966f71bd30..970999bb73 100644 --- a/smtk/attribute/Categories.h +++ b/smtk/attribute/Categories.h @@ -36,11 +36,22 @@ class SMTKCORE_EXPORT Categories public: enum class CombinationMode { - Or = 0, //!< Represents logical Or - Any SMTK_DEPRECATED_IN_22_07("Please use Or") = 0, - And = 1, //!< Represents logical And - All SMTK_DEPRECATED_IN_22_07("Please use And") = 1, - LocalOnly = 3 //!< Indicates no further processing of Category Set Pairs is required + Or = 0, //!< Represents logical Or + And = 1, //!< Represents logical And + LocalOnly = 2, //!< Indicates no further processing of Category Set Pairs is required + +#ifdef _MSC_VER + /* + * MSVC doesn't have a way to deprecate enum variants other than through + * `#pragma`. Just let other platforms handle it. + */ + Any = Or, + All = And +#else + Any SMTK_DEPRECATED_IN_22_07("Please use Or") = Or, + All SMTK_DEPRECATED_IN_22_07("Please use And") = And +#endif + }; ///\brief Categories::Set represents a single category constraint used by the Categories class. diff --git a/smtk/attribute/pybind11/PybindCategories.h b/smtk/attribute/pybind11/PybindCategories.h index 45e23979fc..b136d05fe2 100644 --- a/smtk/attribute/pybind11/PybindCategories.h +++ b/smtk/attribute/pybind11/PybindCategories.h @@ -26,7 +26,6 @@ inline py::class_< smtk::attribute::Categories > pybind11_init_smtk_attribute_Ca .def("passes", (bool (smtk::attribute::Categories::*)(const ::std::set<::std::string>&) const) &smtk::attribute::Categories::passes, py::arg("categories")) .def("passes", (bool (smtk::attribute::Categories::*)(const ::std::string&) const) &smtk::attribute::Categories::passes, py::arg("category")) .def("insert", (void (smtk::attribute::Categories::*)(const smtk::attribute::Categories&)) &smtk::attribute::Categories::insert, py::arg("categories")) - .def("insert", (bool (smtk::attribute::Categories::*)(const smtk::attribute::Categories::Set&)) &smtk::attribute::Categories::insert, py::arg("categorySet")) .def("reset", &smtk::attribute::Categories::reset) .def("size", &smtk::attribute::Categories::size) // NOTE that the Python form of this method is returning a copy since Python diff --git a/smtk/attribute/testing/cxx/categoryTest.cxx b/smtk/attribute/testing/cxx/categoryTest.cxx index a2127203df..8a46320c7f 100644 --- a/smtk/attribute/testing/cxx/categoryTest.cxx +++ b/smtk/attribute/testing/cxx/categoryTest.cxx @@ -80,18 +80,8 @@ int main() // Lets see what categories the attribute definitions think they are if (expDef->categories().size()) { - const smtk::attribute::Categories& categories = expDef->categories(); std::cout << "ERROR: ExpDef's categories: "; - int i = 0; - for (const auto& catSet : categories.sets()) - { - std::cout << "Category Set: " << i++ << " = "; - for (const auto& catName : catSet.includedCategoryNames()) - { - std::cout << "\"" << catName << "\" "; - } - std::cout << std::endl; - } + std::cout << expDef->categories().convertToString() << std::endl; } else { @@ -99,18 +89,8 @@ int main() } if (def2->categories().size()) { - const smtk::attribute::Categories& categories = def2->categories(); std::cout << "Def2's categories: "; - int i = 0; - for (const auto& catSet : categories.sets()) - { - std::cout << "Category Set: " << i++ << " = "; - for (const auto& catName : catSet.includedCategoryNames()) - { - std::cout << "\"" << catName << "\" "; - } - std::cout << std::endl; - } + std::cout << def2->categories().convertToString() << std::endl; } else { diff --git a/smtk/attribute/testing/cxx/unitIsRelevant.cxx b/smtk/attribute/testing/cxx/unitIsRelevant.cxx index bc59abb943..70568dea14 100644 --- a/smtk/attribute/testing/cxx/unitIsRelevant.cxx +++ b/smtk/attribute/testing/cxx/unitIsRelevant.cxx @@ -180,7 +180,7 @@ void setupAttributeResource(attribute::ResourcePtr& attRes) vItemDef->setLocalAdvanceLevel(2); auto gItemDef = A->addItemDefinition("g3"); // let make sure this group has no categories - gItemDef->setIsOkToInherit(false); + gItemDef->setCategoryInheritanceMode(Categories::CombinationMode::LocalOnly); vItemDef = gItemDef->addItemDefinition("g0i0"); attRes->finalizeDefinitions(); diff --git a/smtk/common/Deprecation.h b/smtk/common/Deprecation.h index a204968c84..23bae92a98 100644 --- a/smtk/common/Deprecation.h +++ b/smtk/common/Deprecation.h @@ -56,7 +56,7 @@ #define SMTK_DEPRECATION_REASON(version_major, version_minor, reason) \ "SMTK Deprecated in " #version_major "." #version_minor ": " reason -#if SMTK_DEPRECATION_LEVEL >= SMTK_VERSION_CHECK(22, 06) +#if SMTK_DEPRECATION_LEVEL >= SMTK_VERSION_CHECK(22, 07) #define SMTK_DEPRECATED_IN_22_07(reason) SMTK_DEPRECATION(SMTK_DEPRECATION_REASON(22, 07, reason)) #else #define SMTK_DEPRECATED_IN_22_07(reason) -- GitLab From c2e8cc424f2957ec29b60b2e63ac72224714eb6f Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 12 Jul 2022 15:38:35 -0400 Subject: [PATCH 43/44] Update version number to 22.07.00 --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 4a680231e3..ad4c45159f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -22.05.100 +22.07.00 -- GitLab From 2d352e461d1e5b74a35c7db2fce89cf643f2d5bf Mon Sep 17 00:00:00 2001 From: Robert O'Bara Date: Tue, 12 Jul 2022 15:39:48 -0400 Subject: [PATCH 44/44] Update cdash-groups.json to track the release group --- .gitlab/ci/cdash-groups.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.gitlab/ci/cdash-groups.json b/.gitlab/ci/cdash-groups.json index 3e09d97981..48c032df9e 100644 --- a/.gitlab/ci/cdash-groups.json +++ b/.gitlab/ci/cdash-groups.json @@ -1,62 +1,62 @@ { - "latest-master": [ + "latest-release": [ { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_asan" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_coverage" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_nodata" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_paraview" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_paraview59_compat" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_plain" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_tidy" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_ubsan" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "fedora33_vtk_python3" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "macos_arm64" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "macos_x86_64" }, { - "group": "master", + "group": "release", "site": "gitlab-ci", "buildname": "windows_vs2019_ninja" } -- GitLab