diff --git a/.gitlab/ci/configure_fedora33_paraview.cmake b/.gitlab/ci/configure_fedora33_paraview.cmake index 3ca6e832f54943f75a6667fea04cd37c8a8eb764..bb77d5812a4bcb756346786f4f8b2ed8ad51cfff 100644 --- a/.gitlab/ci/configure_fedora33_paraview.cmake +++ b/.gitlab/ci/configure_fedora33_paraview.cmake @@ -3,6 +3,7 @@ set(SMTK_PLUGIN_CONTRACT_FILE_URLS "https://gitlab.kitware.com/cmb/plugins/adh-extensions/-/raw/master/CMake/adh-extensions.cmake" "https://gitlab.kitware.com/cmb/plugins/rgg-session/-/raw/master/CMake/rgg-session.cmake" "https://gitlab.kitware.com/cmb/plugins/truchas-extensions/-/raw/master/CMake/truchas-extensions.cmake" + "https://gitlab.kitware.com/cmb/cmb/-/raw/master/cmake/cmb.cmake" "https://gitlab.kitware.com/cmb/plugins/ace3p-extensions/-/raw/master/CMake/ace3p-extensions.cmake" "https://gitlab.kitware.com/cmb/plugins/xmsmeshoperation/-/raw/master/CMake/xms-mesh-operation.cmake" "https://gitlab.kitware.com/cmb/plugins/cmb-2d/-/raw/master/cmake/cmb-2d.cmake" diff --git a/.gitlab/ci/configure_fedora33_paraview59_compat.cmake b/.gitlab/ci/configure_fedora33_paraview59_compat.cmake index 96c1284750b456f63b82633a720d93036b88ec8a..2203fce351a48f185db83619f5b97f2480302047 100644 --- a/.gitlab/ci/configure_fedora33_paraview59_compat.cmake +++ b/.gitlab/ci/configure_fedora33_paraview59_compat.cmake @@ -2,6 +2,7 @@ set(SMTK_PLUGIN_CONTRACT_FILE_URLS "https://gitlab.kitware.com/cmb/plugins/adh-extensions/-/raw/master/CMake/adh-extensions.cmake" "https://gitlab.kitware.com/cmb/plugins/rgg-session/-/raw/master/CMake/rgg-session.cmake" "https://gitlab.kitware.com/cmb/plugins/truchas-extensions/-/raw/master/CMake/truchas-extensions.cmake" + "https://gitlab.kitware.com/cmb/cmb/-/raw/master/cmake/cmb.cmake" "https://gitlab.kitware.com/cmb/plugins/ace3p-extensions/-/raw/master/CMake/ace3p-extensions.cmake" "https://gitlab.kitware.com/cmb/plugins/xmsmeshoperation/-/raw/master/CMake/xms-mesh-operation.cmake" CACHE STRING "") diff --git a/ReadMe.md b/ReadMe.md index 634d839197117f528b4a489ace20dc4b148e58eb..8f1e3201a235fb93ebdc23594ed93b6fa0b91731 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/data/attribute/attribute_collection/layoutExamples.sbt b/data/attribute/attribute_collection/layoutExamples.sbt new file mode 100644 index 0000000000000000000000000000000000000000..dfb1cddf42403461b4f788941cd81cef7c962c67 --- /dev/null +++ b/data/attribute/attribute_collection/layoutExamples.sbt @@ -0,0 +1,238 @@ + + + + + + + + 1 + + + 1 + + + + + + + + + + + 2.71828 + 3.14159 + + + + + + + + + + + + + 1.1 + + 1.1,2.2,3.3 + + + + alpha + omega + + + + + 4.4,5.5,6.6 + + + + beta + gamma + + + + + + + + + + + 0.0 + + + + beta + gamma + + + + + + + + + + + + + + + All + + Int1 + Int2 + ReferenceItem + DateTime + FileItem + GroupItem + OptionalItem + VoidItem + + + No Children + + One Child + + Int1 + + + + Two Children + + Int1 + Int2 + + + + Reference Item + + ReferenceItem + + + + Date Time + + DateTime + + + + File Item + + FileItem + + + + Group Item + + GroupItem + + + + Optional Item + + OptionalItem + + + + Void Item (not optional) + + VoidItem + + + + + + + + + + 1 + + + + No Children + + One Child + + Int1 + + + + + + + + + 1 + 2 + + + No Children + + One Child + + Int3 + + + + Two Children + + Int3 + Int4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/release/index.rst b/doc/release/index.rst index 7af6aedc6f460fe896144a13ac952393ceb6e7d3..dc2277fb79e7cc3d89f7332a4ee7fcdf9b3fbe48 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/smtk-22.07.rst b/doc/release/smtk-22.07.rst new file mode 100644 index 0000000000000000000000000000000000000000..427661a0a50bcc8a202117de713ba8ff26515522 --- /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.) diff --git a/smtk/attribute/Categories.cxx b/smtk/attribute/Categories.cxx index 7daf4b2d04dc7494c31ee1fdbc3cca66472b746a..648c00846ab56907282990d8102cc19644e2520d 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::And) || (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 2fab03886d90de5f4b57a2a16fae42f43c7818af..970999bb7378a5f3868b77e107ae99036b26c7db 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,53 @@ namespace attribute class SMTKCORE_EXPORT Categories { public: + enum class CombinationMode + { + 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. /// /// 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 +122,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 +147,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 +190,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/DateTimeItem.cxx b/smtk/attribute/DateTimeItem.cxx index bc2cffc56b4f630d4a031fedcb8851360a3bd212..4c6d48209815b76e7db1c6f19f9f6c51967bd398 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 d40f11d77647a95894533f94ceb71922a393635d..4f9eefde4e1435574b68ca6acab30d2b29526876 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/Definition.cxx b/smtk/attribute/Definition.cxx index 5dddabcca320ba0e5100a836791035def6a308cb..b47850a1523579685b3f936e3ff2fea7ae13a5f7 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 96e4b0b37477a26498cda07f6238f996f28bed90..3c853ed626630f494c797ac13a038a4c741c81b6 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 1b24d5899fee76cba35b30dd90d95a5f96605937..705a256e10e6669a00aa4525ec8b1ac222c6b699 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 af387b4f5c679315fc72500c89bd3c1654c5817e..b8bc0b5a36c9685ec85bc7c78e73471056ddf623 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 57106d71d6f30da6cd732cf0731b916683adc4e2..4a6ca12613f0a58b2c67172a0ddcc21031fde1a9 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 d57ffbf7d96e70a3ebba6adfcf6f7cdd445483f4..d6e6591b93e5a68a152479e95fe2827b52cacb51 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 cc8e1352f9e8841b6ec532f1187d5cda1e1d69bb..f3ba974831740798aa9ea3b9452f8f0982ae4b61 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 b6fb52da78cda17f7c5475fa9aa32c6673b90663..cfb3720e1795e706fae31a052aa4218495e617cd 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 ce59d5f4cc87f5ba576cedf966e8ff9a7ac66018..772bba61396b921295a753ce7cd48995bcd756f6 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 c7d44d16c8adee66c6c4c4480d16fe6dfbde8516..6057bfdc0ae8e1d15a88ffad287b8d10ea517544 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 00ae39485063048220d68a2b52b2054029330d9e..3c281b7ee78a052a08f0efc6358a274f60708567 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 c519e6ce1a881211e71b5f6b591c20fe15321c86..fba4190daf4b74dcba2f5ee701d63cb0fe2aeac1 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 bb7a17d2e88524ee0d949d741ec60898949ea47c..d871b0869be71afd5414954ff32f9533aa815823 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 5ff47a3ee3a4b88c6c699281fe7a766dd8ffae4c..dc365dae6515b7388e1e5f016e12035c82849d97 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 27f91a23ed3f7da776a9322a9baeba5424e17a72..0864fca833b03dc3e106c0f8d565b79baf4ee0f8 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 8be5c03ad12cfc2c524d864a97d8983845d310d7..808818a614449a182cee945b65b494f4c55c7ac9 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 96da4dff9c19e7aca4bc5945ce4bdf4daa798535..981ecc72d2edb987fa02d5cf12604ab41f474d3a 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 8a9c1a56e8782cc055c8036efa60ea5d050a6b24..c849c7a16b9ce6e3efcb34bd053ae1274e10dfe4 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 d7662a7370efcc757291315059c6974ea90a1a44..b136d05fe2954cd87a6fbb7a079d140aafb9b005 100644 --- a/smtk/attribute/pybind11/PybindCategories.h +++ b/smtk/attribute/pybind11/PybindCategories.h @@ -26,12 +26,11 @@ 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("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 +61,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/PybindDateTimeItem.h b/smtk/attribute/pybind11/PybindDateTimeItem.h index 4fc91e01dcebe2a6ad0163e239d21e63b598a82c..a8865b287db8ffdacd5142cbfe6f93c048bd56a5 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/attribute/pybind11/PybindDefinition.h b/smtk/attribute/pybind11/PybindDefinition.h index c1d8a8a6539994895cb1d5ff644a4c40b9b72aa3..c1856bba9b10ed32cf1fa56bf21b7e3176513e41 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 51d3378fbad724815fc90af932d077f4700fe338..a4e8cbe7fcb5387c2265e2d4e4ef63c3b4a93ec5 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/categoryTest.cxx b/smtk/attribute/testing/cxx/categoryTest.cxx index a2127203df4a6bb63d20d1223f22941b5cf1478d..8a46320c7fb0cf65e7f9622e98003a1c3b4358e1 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/unitCategories.cxx b/smtk/attribute/testing/cxx/unitCategories.cxx index a4bc0ab61115c13ab17fd04315811d8f1ba661c8..aed7a9fd607da5d398647d536fff83a4252ee1e4 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 7505b5029a1cc47140cfc77925e4548cfdf798fa..cf098612392a24c54c7245d9f72fcc40dd87b67f 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/unitIsRelevant.cxx b/smtk/attribute/testing/cxx/unitIsRelevant.cxx index bc59abb9430a1ba69fea4a38081b985e88a73124..70568dea1433ab3e3d6a17b747ffbd3cb6baa456 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/attribute/testing/cxx/unitPassCategories.cxx b/smtk/attribute/testing/cxx/unitPassCategories.cxx index fd876c30534d1aa98a134c196d257eb3303904cb..84ad9fc9aaf9e1c757ab5cd9149e384caff43cd9 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/Color.cxx b/smtk/common/Color.cxx index bdf9a78ee71fedbe692896c418d1dce75641c8d2..52e8b735a21ee51bcf31aa8331353aa77e992169 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 916da089d4c42790bccc3cd5c21dc0db787bce51..9372d8c84229cf9b2fd0d5117e0ac9c9d3dfc12b 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); diff --git a/smtk/common/DateTimeZonePair.cxx b/smtk/common/DateTimeZonePair.cxx index 61e434650a767dcd17d1869f7d9661352b560e37..63ce15043983e7289418f5983dcfc8067e0361d8 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/Deprecation.h b/smtk/common/Deprecation.h index 2d37d471cba1cefc870a0c8027fbf20297c66746..23bae92a98d23b9204c879b0a169487127179b2d 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, 07) +#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/common/testing/cxx/UnitTestDateTimeZonePair.cxx b/smtk/common/testing/cxx/UnitTestDateTimeZonePair.cxx index 24f1fe5612e45c61121d54aba7f009b105e9d27b..8514d8cc111f3e487409be4d78d13c9aa8eae583 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/paraview/CMakeLists.txt b/smtk/extension/paraview/CMakeLists.txt index 98f275d648796e90912f8fe2969a107281358f18..9effc6fa0c9a54a55290e926859622165147e864 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/appcomponents/ApplicationConfiguration.cxx b/smtk/extension/paraview/appcomponents/ApplicationConfiguration.cxx index 26742c496565c17ecadfd7984d178bec0c4c7961..e2be502412ff8b9950b9da766b8f371aabd0bad7 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 9365a9e4374d648e30a4e698b9d804ce0514845c..61ccd629d32428b868a4dc8ffc5004ce98b6016c 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 { @@ -49,15 +49,19 @@ 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. * * 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 daf5c88b41b32ff8ff8aa6e1cef06bd707d6c2af..37774745e528a8eec8085682ea914d6c41aaab5f 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/VisibilityBadge.cxx b/smtk/extension/paraview/appcomponents/VisibilityBadge.cxx index 4d34a7b45a89ae3ad10370313b17bcc43fd89eeb..d45e023d8feaf5c4a0318b73d66fcd18bf34d37b 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 diff --git a/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt b/smtk/extension/paraview/appcomponents/plugin-gui/CMakeLists.txt index 7b005e3acaa75e59b3e5a74238d65ed2a59cd8eb..db67744587e908ff86a83ee61bf5e5892fce69e2 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 5ae2372ea4a5cd3de0b25ecb837502a687da13d0..bce3f10401ee32d8ece557fdbe0011eb156ab736 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 6682b23f5a34c470d8cbcc4ab52f5215829eb94f..0ad0a8cf0a304916b51b912a336a9c88ea27db22 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 bf06fdb77c7d282a69e84a061ac1778ddffcb86a..9b5e18312bff01d732679973017b1d02263f5bfe 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" @@ -21,7 +23,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)) @@ -39,6 +41,14 @@ smtk::view::Information DefaultConfiguration::panelConfiguration(const QDockWidg 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/plugin-panel-defaults/DefaultConfiguration.h b/smtk/extension/paraview/appcomponents/plugin-panel-defaults/DefaultConfiguration.h index 992df3374f93816ea53755e99ec60fbebbabc0b2..05b0db0c8d49bb51b1725a10c6a4bd5f380f2637 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 0000000000000000000000000000000000000000..2029932bdeedf0e73fb237c7748b4f2b2c815529 --- /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 d6c686768857840faa89b5dee408396db967943e..830a4b58acb1d53804eaa2b24a6425582c6d8879 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,10 @@ pqSMTKAttributePanel::pqSMTKAttributePanel(QWidget* parent) : Superclass(parent) { - this->setObjectName("attributeEditor"); + this->setObjectName("pqSMTKAttributePanel"); + this->setLayout(new QVBoxLayout); + this->layout()->setObjectName("pqSMTKAttributePanel_layout"); this->updateTitle(); - QWidget* w = new QWidget(this); - w->setObjectName("attributePanel"); - this->setWidget(w); - w->setLayout(new QVBoxLayout); auto* behavior = pqSMTKBehavior::instance(); QObject::connect( behavior, @@ -122,7 +122,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 +319,7 @@ 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); return qview != nullptr; } @@ -385,4 +385,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 5987d70b40462fac6e5396ffde69908c2f520c31..5cba1f7bef05fd75512a5f032c35bad38c639de4 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 48cddcc76dd987522511522d8fd35bf3aed5153e..11780bb7f450cc60d1b11510b99d717fa92d8dd6 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 0000000000000000000000000000000000000000..5dfc1496fcdca953e5a4a5ca499187546d683785 --- /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 0000000000000000000000000000000000000000..4c79f5ebe2020bbacb07e58f8af3dc0da26d80ac --- /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 0000000000000000000000000000000000000000..afc65877aa40cd67e4dbb4612d21ff3614eeb04b --- /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 08335536fe33a95644d127b99bf356dbe68ddc57..1998547798b3a5b1232ac4500041ab756f5e3a14 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 00dda063c79be6bd3eb9c9f0ccae9490b754fc5a..2c5d9babc7930baf2d4a63fc194c8cba47bac1fa 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 0000000000000000000000000000000000000000..2e3954fc1227714d96cf742bde5630d013a0898d --- /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 03a4331c637c2f083c0e790c568a0bcd2a0780c1..bdbbf9fbe1abfdc1ff91fdb9d710d2f777e2509a 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 411c5749b4eb6260184a6a4c30c7cfbc903d422d..e373a824fd8326101a4e694f817c3b3510ee8d8e 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 0000000000000000000000000000000000000000..3893c55c2e6d5c29f5bfdeac32bec3c6a5c3d0ff --- /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 73fc007de6acd5531f397e44fb8ed74d03dbfa1d..f0801194785fc463eab842a99a35db16b6ea087e 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 1a73d9a2d9f14baf1045b68d4ef575191a51e0f5..a08ce207ae5cda72be862ae65d5e3953579cabaa 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 f91523cc5f1a5e998f672d18b7a1bb3aa956734c..f47cae0ed2bea7c79284e53acc54e4de74af0d75 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 5a4eeb72c1a7826eb5e5961a527754e562ab7034..d5080fab77466effe662ea639944674fc0258f97 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 0000000000000000000000000000000000000000..6258af053cb7adb85132a0d2c91f8c9541f269a1 --- /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 cd1fa4d1e84921064cfed7db9d4a3f5c70b53246..a2a60e5f647590eed9ddd60c08d2ea47f63a3ea2 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" @@ -21,13 +22,35 @@ #include "smtk/view/ResourcePhraseModel.h" #include "smtk/view/json/jsonView.h" +#include + 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. @@ -104,8 +127,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 76af29e5c22bf0b6bf953a237ca5bfe6de61eea0..d3793d820ec78d7994736e94ffabc5c814297a76 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/pqSMTKSelectionFilterBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKSelectionFilterBehavior.cxx index 14a7ad85b9c4088db43a899ede9c7304178b9e46..1a2b965f8d72812042e83b4d00f72c3a92f88089 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 diff --git a/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h b/smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKAttributePanel.h index b6d1b8bb9cff902cae354e3ec15f586c306be637..903443f687287ef33a22fa45c02ae4831253e873 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 1e6f829ad51205bdd313a9fbbf37ebe2932a77d3..0816f447938ffa64540940f8abf9c2d50e843cac 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 d945da76239f8d005c0afa1b4ffe625956273873..c2b0028cce0be450d83458ce35f5db415ac9e0f0 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/operators/smtkDataSetInfoInspectorView.cxx b/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx index 798b5c111c84453848c465683c74f229f1926987..81dbbbea4bf4483ef882b71fe201318e12b92cf5 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/paraview/project/CMakeLists.txt b/smtk/extension/paraview/project/CMakeLists.txt index b846eab3304d1a48a7f5f6b3b1faea0a50da0d07..4a5d61c1ad43e21e8ac3657716cb3fcb2c27c37b 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-core/CMakeLists.txt b/smtk/extension/paraview/project/plugin-core/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5dce9bb80883d637adb4b9e9bb0b40c47eb90528 --- /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 0000000000000000000000000000000000000000..8cc954cd1854f5c3ca37a4a1f5ddc2fd7d78f030 --- /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 59% rename from smtk/extension/paraview/project/plugin/CMakeLists.txt rename to smtk/extension/paraview/project/plugin-gui/CMakeLists.txt index 73551e222e26556b6ccbd3b29d7c57dda89429b6..ad3126aef106ed8ebdcb426b08c978e5c6455b6c 100644 --- a/smtk/extension/paraview/project/plugin/CMakeLists.txt +++ b/smtk/extension/paraview/project/plugin-gui/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) @@ -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 aee5ac906c252951fb8f1787e08a71c377e838a9..7750c5575f88984bbf916ea3a77a9fa125deca4f 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 diff --git a/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx b/smtk/extension/paraview/project/pqSMTKProjectAutoStart.cxx index 55cff60a67cecf72feaebc3f70d5cf5978a77114..a5747d2a7ecfd831ce67b6f01c7281bd8a495306 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,17 +30,22 @@ 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()); - 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 diff --git a/smtk/extension/paraview/project/pqSMTKProjectBrowser.h b/smtk/extension/paraview/project/pqSMTKProjectBrowser.h index 09ae267bda2aac00fa9f94875d1d5465c45a1106..8b5e77c3c5f7703e967c4133eda75a1542243635 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 0000000000000000000000000000000000000000..48d2db87f78ea1eaa6a06ce341e3ea48e965f87a --- /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 1e5becd19f8d2c599bf4e384b3390b07ea099256..737c3e6ff379384b2367d46fc3c3096712645825 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 fa444f8986b5141c1f6fdf72dfbb3d655c5c57eb..b1cfb1c4d60d600ace0000adb546405d17ea0dc1 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 diff --git a/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx b/smtk/extension/paraview/server/vtkSMTKResourceRepresentation.cxx index bbe099a13a2435b1129f61d81491566dd2c2d4e1..80d8e4f9ea6318c341863e41bde2f132cb8c659a 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/qt/ResourcePanelConfiguration.json b/smtk/extension/qt/ResourcePanelConfiguration.json index c7292bbe87bc6fddb499214f81c965d924658d59..ff80db09db51b52a80549ad3e76e9677dcbd3e95 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/qtBaseAttributeView.cxx b/smtk/extension/qt/qtBaseAttributeView.cxx index 090f2e2d4365f5a9a805b5c90485600468f08a4d..d5db1e91017e5b2dbe3749e5d061d1a9bd816282 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/qtDateTimeItem.cxx b/smtk/extension/qt/qtDateTimeItem.cxx index 92521487dedfbef2286e4d972c44d25d2452d2c7..6caad8c3024fb4d8c21bf34931cc50c6e7fccc3c 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()) @@ -427,15 +490,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 +518,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/qtDateTimeItem.h b/smtk/extension/qt/qtDateTimeItem.h index afc5f051d3b61c20d3977b9f460c454229f2bd00..7fc738a510275a546e99bdd1218fc6d30ca78f67 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/qtDescriptivePhraseModel.cxx b/smtk/extension/qt/qtDescriptivePhraseModel.cxx index acbe02e3c0b05c218a0e40942a8985d17816d0b9..7c1f3c54ebfb0f3d1c2227e4d023631409cc5e85 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/extension/qt/qtDiscreteValueEditor.cxx b/smtk/extension/qt/qtDiscreteValueEditor.cxx index e7160657b39d87ad568eed8eceffa1d7f5f0a8b4..f3a6c0bff5e6704df884c977569a564b54ff52e1 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 @@ -32,10 +33,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 +48,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 +66,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); @@ -98,6 +99,7 @@ void qtDiscreteValueEditor::createWidget() this->Internals->clearChildItems(); QBoxLayout* wlayout = new QVBoxLayout(this); wlayout->setMargin(0); + wlayout->setAlignment(Qt::AlignTop); if (!item || !item->isDiscrete()) { return; @@ -125,29 +127,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()) @@ -166,6 +160,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(); @@ -208,10 +228,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++) @@ -352,9 +368,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 { @@ -368,8 +384,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); - 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; @@ -440,9 +469,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 { diff --git a/smtk/extension/qt/qtDoubleClickButton.cxx b/smtk/extension/qt/qtDoubleClickButton.cxx index e2fe2764c8106f899968ee61aa1a0249635e39a7..017d01eaad3b02cd5c346529754f1c8235eaeee1 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 887235fefc7ac1ae0d789a9a2c9c8d99d82df011..a624c28160b8a3652b96b5a814e17cdcc12cc60b 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/qtFileItem.cxx b/smtk/extension/qt/qtFileItem.cxx index 208d6ea9455c3a99642b6fe53fd3ad9f70e30483..a4ef6729a7e7d6cd4ea1e7e83d054873411d2719 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 @@ -351,10 +353,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 @@ -393,9 +393,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()); @@ -625,8 +672,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) @@ -940,15 +990,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); @@ -972,6 +1014,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/qtFileItem.h b/smtk/extension/qt/qtFileItem.h index 602053144c48a926a62477328f1c1410b78279b5..746149736dacef2f0a195f6b3667ef8036af693e 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/qtGroupItem.cxx b/smtk/extension/qt/qtGroupItem.cxx index 483f92aa5f4fecbb31373d97127cdc87ac4199e7..a501a491d58b8070002bfc23749246da75d31f39 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 20fbaa8312dd40efd9ebc317cafa21fbc4d16c1b..ead928f347db4fe5492c8b07058f44155b79579e 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" @@ -20,38 +36,29 @@ #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 -#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 #if defined(SMTK_MSVC) && _MSC_VER <= 1500 @@ -203,6 +210,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,7 +258,7 @@ 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); @@ -675,7 +692,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 +760,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 @@ -829,15 +857,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 +904,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); @@ -1371,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++) { @@ -1698,13 +1728,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: @@ -1794,21 +1817,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()); @@ -1817,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) @@ -2062,3 +2220,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 f6319c95d70b9bc23c89688629c378c55a498d3e..4d9f329a1f54ce2e7e71fac8c53649a947accd31 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(); @@ -108,6 +111,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 diff --git a/smtk/extension/qt/qtInstancedView.cxx b/smtk/extension/qt/qtInstancedView.cxx index 4a298bce36ec4e3b95bff597cdf837b8a888d6fa..a3133311096f745ae3f887925398b28117b55673 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(); diff --git a/smtk/extension/qt/qtOperationAction.cxx b/smtk/extension/qt/qtOperationAction.cxx index 3743f552b7dd2242e3181655d191b7fdbc8c5d42..9b7fb618081036fa687dae67e25292b6e43a8564 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/qtReferenceItemEditor.cxx b/smtk/extension/qt/qtReferenceItemEditor.cxx index 2fa5b10eb5a9edc499006301b6ae5e5f2285681b..dc0bb8a3b3b81ba36108ecf5c0aa45a7963f478c 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()) { @@ -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(); @@ -255,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); @@ -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/qtResourceBrowser.cxx b/smtk/extension/qt/qtResourceBrowser.cxx index 027f2fcb77e5c119d315a22e2735c6650b168a72..e901c776de42af51fe2e07c51bb434a8a8cbfff2 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; } @@ -445,7 +449,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)) { diff --git a/smtk/extension/qt/qtResourceBrowserP.cxx b/smtk/extension/qt/qtResourceBrowserP.cxx index 05139b6c25bf0b1af8081d81d53e9bff7bef56a7..42300f2e2d5a971c5abd7824149f3f7858e37a1e 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 ae5c58a7a85a5296484b3ed1a6db7f6601436dc7..f190cb7dc9c4dc3ea6d1bc0bf185d7ac4672aef4 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 diff --git a/smtk/extension/qt/qtVoidItem.cxx b/smtk/extension/qt/qtVoidItem.cxx index 0d1afd69e5fd70379ffaef67f2b6d8d06fd6fbe6..f67dfb5b8f27eeae15be7c705432fa31dee8d117 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"); diff --git a/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx b/smtk/extension/qt/testing/cxx/UnitTestDoubleClickButton.cxx index edfedc21eebe552671f3c4ecd04de6b62e7e274c..1361ecf15e46a96143eed842938c2a004d7cdbff 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); diff --git a/smtk/extension/vtk/geometry/Geometry.cxx b/smtk/extension/vtk/geometry/Geometry.cxx index 0a662ced3921951fa5f06483c3dbd0f8ce753aa4..6d6a09ed0e0414502802dd109e7c192a07261f1c 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()); } diff --git a/smtk/extension/vtk/operators/DataSetInfoInspector.cxx b/smtk/extension/vtk/operators/DataSetInfoInspector.cxx index e62ac003b26314f1e6381eb29f71b994e3d6ba50..cc48cddc1f40db24cb569d41622ef7a7eb99865c 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 5e7fd8a08f7f6e48c4432823ffee618aab97c2a6..4f0c3a37243c252b0baefb872b36cabe691c62b3 100644 --- a/smtk/extension/vtk/operators/DataSetInfoInspector.sbt +++ b/smtk/extension/vtk/operators/DataSetInfoInspector.sbt @@ -37,6 +37,9 @@ Return key toggles component visibility. + + + diff --git a/smtk/graph/ArcImplementation.h b/smtk/graph/ArcImplementation.h index 4ed3a9309a649f00a7b239623ea01bccd84eddc7..e3b09a2f07a0b56ac5d8aed08dcbc11037104571 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 3e05c5c5f1104ed998b87c1c308062520035950a..46a595a22aedb7e7e2f7c05f04d390a8980a55c4 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 @@ -12,6 +13,7 @@ set(graphHeaders ArcMap.h Component.h ExplicitArcs.h + NodeProperties.h NodeSet.h Resource.h ResourceBase.h @@ -21,6 +23,8 @@ set(graphHeaders filter/TypeName.h json/ArcSerializer.h json/ArcDeserializer.h + json/NodeSerializer.h + json/NodeDeserializer.h json/jsonResource.h ) diff --git a/smtk/graph/ExplicitArcs.h b/smtk/graph/ExplicitArcs.h index 479f57e5036511b5a62b77da85b34fd61b261a7e..6113c740ca6162df4bf9df6c358bb943750d81cd 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 0000000000000000000000000000000000000000..255d6074a2b62762fcb2a5498342f67ebbe3f2ee --- /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 8007603eb10720b5f1e86d50839e5994f63e4dec..8ada0a083918d9aea4412dedd3da7eb7b4adb933 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 diff --git a/smtk/io/AttributeReader.cxx b/smtk/io/AttributeReader.cxx index ddd54506701a23c9f07f084463f0e2b295a08bef..8ab83fb98d16278f9d6ea314ff282d73b92d5034 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 62afc7ed228a9898046a883d3dd763269a45ce86..855feee7c43c3dafeff6d2e05e58b8e0a75d4f89 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 93e2fcbc0e79f39ee44dd9f2194187b2623741cf..9ad6e7c0add5070a0742f124eb0acfa0354eca2e 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 d8870f9db00f2b0d0a7a2f9451b78a075f76fe8b..006b354c4fab940cc292b6a04eb397d36918c71f 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 58477ec3f139928e91013443d666b79354147229..6d97f4a0ea3ee23da1c506b86f537b828c39b1a0 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 04eaf2dfccc6617724b620d719a216f73abd35b3..31afa5264a68e2fbf248ec8f1202bcd3c9c8f207 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 0000000000000000000000000000000000000000..2893fe3338e941d1ede4d27d86fd3acc993e2252 --- /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 0000000000000000000000000000000000000000..1d59f2a54b6307d6aedc33911a45fb99a69c0245 --- /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 254a040ccaebe766637b98261631e65e308544f6..2f1b0f76cab1aca7fbc2b4682480ddc0af285b8a 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 7b39353fe0649bf99d722544a0c25a657cb31fe4..36abf247ef54b01c75c0dfd2684764f7a0f56a63 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 0000000000000000000000000000000000000000..6d12ac06ad24f4053fe66412104a57d36fd17d76 --- /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 0000000000000000000000000000000000000000..3b7831e5fd7f201db7ebcb9766c428ba4d30cac1 --- /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 diff --git a/smtk/operation/Manager.cxx b/smtk/operation/Manager.cxx index 936a868419e87ab13099e08dc3fd69ffc4b6b757..8d165dfbbc3c754998838f5d4f908cd6b013541d 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; diff --git a/smtk/operation/pybind11/PybindManager.h b/smtk/operation/pybind11/PybindManager.h index ff1cc51f902f6b7ec61245fccbf5b4b5f6d8ceaf..0eb5552a171f0568a2860555832597495371c0db 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; } diff --git a/smtk/smtk/attribute_builder.py b/smtk/smtk/attribute_builder.py index 7919d6bf0f8d643f8ea414de52777f616ab7b231..a2b68c15acf0055822e5019fdc5d466049f2805f 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 @@ -173,6 +175,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 +234,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 +284,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.""" diff --git a/smtk/view/ComponentPhraseContent.cxx b/smtk/view/ComponentPhraseContent.cxx index 91581f28cdf7ee991da71e02a30bbd6d9dea1350..8dd352cf2165a9d0dff408be99cef540fd17abc8 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) { diff --git a/smtk/view/PhraseModel.cxx b/smtk/view/PhraseModel.cxx index d3312230508ec3b96fa8942f76b5b37f142f5767..7db21f987e501e02e34007804bf1d6101d9dfbb8 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 + } } } diff --git a/smtk/view/SubphraseGenerator.cxx b/smtk/view/SubphraseGenerator.cxx index cc669db81bad4334bc805574608df1f90fe196a1..0142e3d30c2d95c2ab510159301e9417e671d0fc 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; diff --git a/version.txt b/version.txt index 559bf852f7fd4e57224e1e634141dbfd3673ce01..ad4c45159f195d2707dc98b6bb731e78da4fd5fe 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -22.05.0 +22.07.00