...
 
Commits (39)
# This file specifies people who "own" specific
# pieces of code in SMTK. It is used to suggest
# reviewers for merge requests based on the set
# of files changed in the MR.
# Subsystems have specific owners
conda/ tj.corona@kitware.com john.tourtellott@kitware.com
doc/tutorials/ david.thompson@kitware.com
doc/userguide/ david.thompson@kitware.com
smtk/attribute/ bob.obara@kitware.com
smtk/common/ david.thompson@kitware.com
smtk/extension/opencv/ jacob.becker@kitware.com
smtk/extension/paraview/ david.thompson@kitware.com
smtk/extension/qt/ bob.obara@kitware.com
smtk/extension/vtk/ david.thompson@kitware.com tj.corona@kitware.com
smtk/io/ bob.obara@kitware.com
smtk/mesh/ tj.corona@kitware.com
smtk/model/ david.thompson@kitware.com
smtk/operation/ tj.corona@kitware.com
smtk/plugin/ tj.corona@kitware.com
smtk/project/ john.tourtellott@kitware.com
smtk/pybind11/ tj.corona@kitware.com
smtk/resource/ tj.corona@kitware.com
smtk/session/discrete/ bob.obara@kitware.com
smtk/session/multiscale/ tj.corona@kitware.com
smtk/session/oscillator/ david.thompson@kitware.com
smtk/session/polygon/ david.thompson@kitware.com
smtk/session/vtk/ david.thompson@kitware.com
smtk/simulation/ john.tourtellott@kitware.com
smtk/smtk/ tj.corona@kitware.com david.thompson@kitware.com
smtk/view/ david.thompson@kitware.com
utilities/ ben.boeckel@kitware.com
......@@ -8,7 +8,7 @@
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "smtk/plugin/InitializeDefaultPlugins.h"
#include "Initialize@PLUGIN_LIBRARY_TARGET@.h"
#include "vtkPVPlugin.h"
#include "vtkPVPluginLoader.h"
......@@ -40,15 +40,15 @@ namespace extension
{
namespace paraview
{
void initializeDefaultPlugins()
void initialize@PLUGIN_LIBRARY_TARGET@()
{
vtkPVPluginLoader::RegisterLoadPluginCallback(loadPlugins);
vtkPVPluginTracker::SetStaticPluginSearchFunction(searchPlugins);
}
void loadDefaultPlugins()
void load@PLUGIN_LIBRARY_TARGET@()
{
@SMTK_PLUGIN_IMPORT@
@SMTK_PLUGIN_IMPORT@
}
}
}
......
......@@ -7,10 +7,10 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef __smtk_InitializeDefaultPlugins_h
#define __smtk_InitializeDefaultPlugins_h
#ifndef __smtk_@PLUGIN_LIBRARY_TARGET@_InitializePlugins_h
#define __smtk_@PLUGIN_LIBRARY_TARGET@_InitializePlugins_h
#include "smtk/plugin/Exports.h"
#include "@PLUGIN_LIBRARY_TARGET@Export.h"
namespace smtk
{
......@@ -18,8 +18,8 @@ namespace extension
{
namespace paraview
{
SMTKDEFAULTPLUGINS_EXPORT void initializeDefaultPlugins();
SMTKDEFAULTPLUGINS_EXPORT void loadDefaultPlugins();
@SMTK_PLUGIN_LIBRARY_EXPORT@ void initialize@PLUGIN_LIBRARY_TARGET@();
@SMTK_PLUGIN_LIBRARY_EXPORT@ void load@PLUGIN_LIBRARY_TARGET@();
}
}
}
......
......@@ -6,22 +6,72 @@
#
#=========================================================================
# SMTK plugins are extensions of ParaView plugins that allow for the automatic
# registration of components to SMTK managers. They are created using the
# function "add_smtk_plugin", which requires the developer to explicitly list
# a registration class "known as a Registrar" and a list of SMTK manager types
# to which the plugin registers. SMTK plugins can be introduced to a
# ParaView-based application in several ways. The consuming project can
#
# 1) list the plugins in a configuration file that is subsequently read at
# runtime, deferring the inclusion of plugins to the application's runtime. This
# approach requires plugins to reside in certain locations that the application
# is expected to look, but facilitates the presentation of a plugin to the user
# without automatically loading the plugin. For this approach, a consuming
# project can call "generate_smtk_plugin_config_file" to convert the list of
# smtk plugin targets (which can be a part of the project or imported from
# another project) described by the global property "SMTK_PLUGINS" into a
# configuration file. The consuming project can also
#
# 2) directly link plugins into the application. This approach pushes the
# requirement of locating plugins to be a build-time dependency, which can be
# advantageous for packaging. Plugins that are directly linked to an application
# cannot be disabled, however (i.e. the target property ENABLED_BY_DEFAULT is
# ignored, as it is true for all plugins). To use this approach, a consuming
# project can call "generate_smtk_plugin_library" to to use the list of smtk
# plugin targets (which can be a part of the project or imported from another
# project) described by the global property "SMTK_PLUGINS" to generate a library
# against which the application can link to directly incorporate the associated
# plugins.
define_property(GLOBAL PROPERTY SMTK_PLUGINS
BRIEF_DOCS "Global property for aggregating smtk plugin targets"
FULL_DOCS "Global property for aggregating smtk plugin targets")
define_property(TARGET PROPERTY ENABLED_BY_DEFAULT
BRIEF_DOCS "Option to enable plugin by default"
FULL_DOCS "Option to enable plugin by default")
# Enable an SMTK plugin by default
#
# enable_smtk_plugin_by_default(target choice)
function(enable_smtk_plugin_by_default target choice)
# Append a property to the plugin target that conveys whether or not the
# plugin should be loaded by default
set_property(TARGET ${target} PROPERTY ENABLED_BY_DEFAULT ${choice})
# Mark the property for export (so consuming libraries can access it)
set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES ENABLED_BY_DEFAULT)
endfunction(enable_smtk_plugin_by_default)
# create a plugin
# ENABLED_BY_DEFAULT is an option to indicate whether or not the plugin should
# be loaded by default. This only applies when plugins are loaded via a
# plugin list at runtime (as opposed to directly linking to plugins).
# REGISTRAR is used to register the plugin
# REGISTRAR_HEADER is the include file for the registrar (if unset, a file name
# is inferred from the REGISTRAR value)
# is inferred from the REGISTRAR value)
# MANAGERS is a list of managers to which the plugin can register
# LIBRARIES is a list of libraries against which the plugin must link
# LIBRARIES_PRIVATE is a list of libraries against which the plugin must
# privately link
# privately link
#
# All other arguments are forwarded to add_paraview_plugin()
#
# add_smtk_plugin(Name Version
# [ENABLED_BY_DEFAULT]
# [REGISTRAR registrar]
# [REGISTRAR_HEADER headerfile]
# [MANAGERS list of managers used]
......@@ -29,7 +79,7 @@ define_property(GLOBAL PROPERTY SMTK_PLUGINS
# [LIBRARIES list of required private libraries]
# )
function(add_smtk_plugin SMTK_PLUGIN_NAME SMTK_PLUGIN_VERSION)
set(options)
set(options ENABLED_BY_DEFAULT)
set(oneValueArgs REGISTRAR REGISTRAR_HEADER)
set(multiValueArgs MANAGERS LIBRARIES LIBRARIES_PRIVATE)
cmake_parse_arguments(SMTK_PLUGIN
......@@ -65,6 +115,8 @@ function(add_smtk_plugin SMTK_PLUGIN_NAME SMTK_PLUGIN_VERSION)
${SMTK_PLUGIN_UNPARSED_ARGUMENTS}
)
enable_smtk_plugin_by_default(${SMTK_PLUGIN_NAME} ${SMTK_PLUGIN_ENABLED_BY_DEFAULT})
target_link_libraries(${SMTK_PLUGIN_NAME}
LINK_PUBLIC
${SMTK_PLUGIN_LIBRARIES}
......@@ -76,3 +128,121 @@ function(add_smtk_plugin SMTK_PLUGIN_NAME SMTK_PLUGIN_VERSION)
)
endfunction(add_smtk_plugin)
# create a plugin config file including all of the plugins generated by this
# project.
# PLUGIN_CONFIG_FILE_NAME is the name of the file to create
# RELATIVE_DIRECTORY is a directory relative to which plugin locations should
# be described.
function(generate_smtk_plugin_config_file PLUGIN_CONFIG_FILE_NAME)
set(options)
set(oneValueArgs RELATIVE_DIRECTORY)
set(multiValueArgs)
cmake_parse_arguments(SMTK_PLUGIN_CONFIG
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}
)
set(plugins_file ${PLUGIN_CONFIG_FILE_NAME})
set(SMTK_PLUGINS_FILE_CONTENTS)
foreach (plugin IN LISTS SMTK_PLUGINS)
get_property(${plugin}_location TARGET ${plugin} PROPERTY LOCATION)
if (SMTK_PLUGIN_CONFIG_RELATIVE_DIRECTORY)
file(RELATIVE_PATH ${plugin}_location
${SMTK_PLUGIN_CONFIG_RELATIVE_DIRECTORY} ${${plugin}_location})
endif ()
get_property(${plugin}_enabled_by_default TARGET ${plugin} PROPERTY ENABLED_BY_DEFAULT)
set(${plugin}_enabled_by_default_val 0)
if (${plugin}_enabled_by_default)
set(${plugin}_enabled_by_default_val 1)
endif ()
string(APPEND SMTK_PLUGINS_FILE_CONTENTS
" <"
"Plugin name=\"${plugin}\" "
"filename=\"${${plugin}_location}\" "
"auto_load=\"${${plugin}_enabled_by_default_val}\" "
"/>\n")
endforeach ()
configure_file(${smtk_cmake_dir}/plugins.xml.in ${plugins_file} @ONLY)
endfunction(generate_smtk_plugin_config_file)
# create a library that directly links smtk plugins into a consuming
# application. The function creates a library target ${PLUGIN_LIBRARY_TARGET}
# and two header files (defined at parent scope in the list
# ${${PLUGIN_LIBRARY_TARGET}_HEADERS}). All targets contained in the
# ${SMTK_PLUGINS} list will be linked into the target library, and these plugins
# can be loaded by a consuming application by including the generated header
# file Initialize${PLUGIN_LIBRARY_TARGET}.h and by calling the generated methods
# smtk::extension::paraview::initialize${PLUGIN_LIBRARY_TARGET}() and
# smtk::extension::paraview::load${PLUGIN_LIBRARY_TARGET}().
function(generate_smtk_plugin_library PLUGIN_LIBRARY_TARGET)
include(${PARAVIEW_USE_FILE})
include(ParaViewPlugins)
# We need to add the current value of VTK_MODULES_DIR to the module path
# so that when the plugins are built all the modules can be found. Otherwise,
# modules that aren't loaded as direct dependencies of CMB modules will
# not be found.
list(APPEND CMAKE_MODULE_PATH "${VTK_MODULES_DIR}")
# Construct fields to populate the generated source files for the plugin
# library.
foreach (name IN LISTS SMTK_PLUGINS)
set(SMTK_PLUGIN_IMPORT_INIT "${SMTK_PLUGIN_IMPORT_INIT}PV_PLUGIN_IMPORT_INIT(${name});\n")
set(SMTK_PLUGIN_IMPORT "${SMTK_PLUGIN_IMPORT}PV_PLUGIN_IMPORT(${name});\n")
set(SMTK_PLUGIN_QUERY "${SMTK_PLUGIN_QUERY}queryPlugin(${name});\n")
endforeach()
# Generate a unique export symbol for the plugin library.
string(TOUPPER ${PLUGIN_LIBRARY_TARGET} SMTK_PLUGIN_LIBRARY_EXPORT)
string(APPEND SMTK_PLUGIN_LIBRARY_EXPORT "_EXPORT")
# Generate the header file that declares the two methods defined in the plugin
# library.
configure_file(${smtk_cmake_dir}/InitializePlugins.h.in
${CMAKE_CURRENT_BINARY_DIR}/Initialize${PLUGIN_LIBRARY_TARGET}.h @ONLY)
# Generate the source file that implements the abovementioned methods.
configure_file(${smtk_cmake_dir}/InitializePlugins.cxx.in
${CMAKE_CURRENT_BINARY_DIR}/Initialize${PLUGIN_LIBRARY_TARGET}.cxx @ONLY)
# Include the components from ParaView necessary for directly linking plugins
# into an application.
vtk_module_dep_includes(vtkPVClientServerCoreCore)
include_directories(${vtkPVClientServerCoreCore_INCLUDE_DIRS}
${vtkPVClientServerCoreCore_DEPENDS_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR})
# Construct the library.
add_library(${PLUGIN_LIBRARY_TARGET}
${CMAKE_CURRENT_BINARY_DIR}/Initialize${PLUGIN_LIBRARY_TARGET}.cxx)
# During the build phase, include the binary directory that contains the
# generated header file.
target_include_directories(${PLUGIN_LIBRARY_TARGET}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
# Link against all of the smtk plugins.
target_link_libraries(${PLUGIN_LIBRARY_TARGET}
LINK_PRIVATE ${SMTK_PLUGINS} vtkPVClientServerCoreCore)
# Generate an export header using the symbol defined in
# ${SMTK_PLUGIN_LIBRARY_EXPORT}.
include(GenerateExportHeader)
generate_export_header(${PLUGIN_LIBRARY_TARGET}
EXPORT_MACRO_NAME ${SMTK_PLUGIN_LIBRARY_EXPORT}
EXPORT_FILE_NAME ${PLUGIN_LIBRARY_TARGET}Export.h)
# Construct a list of generated headers for the plugin library that is
# accessible at parent scope. That way, consuming applications can install
# these header files where appropriate.
set(${PLUGIN_LIBRARY_TARGET}_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/Initialize${PLUGIN_LIBRARY_TARGET}.h
${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_LIBRARY_TARGET}Export.h
PARENT_SCOPE)
endfunction(generate_smtk_plugin_library)
<?xml version="1.0"?>
<Plugins>
@SMTK_PLUGINS_FILE_CONTENTS@
</Plugins>
......@@ -21,7 +21,7 @@ if(IS_DIRECTORY "${smtk_module_dir}")
endif()
unset(smtk_module_dir)
set(smtk_cmake_dir ${CMAKE_CURRENT_LIST_DIR})
set(smtk_cmake_dir @SMTK_MODULE_DIR@)
#When building documentation internally we re-import ourselves, which
#doesnt work and generates CMake warnings. So we will only look for SMTK
......@@ -29,13 +29,19 @@ set(smtk_cmake_dir ${CMAKE_CURRENT_LIST_DIR})
if(TARGET smtkCore)
else()
find_package(Boost 1.64.0
find_package(Boost @SMTK_MINIMUM_BOOST_VERSION@
COMPONENTS @required_boost_components@ REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(MOAB REQUIRED)
set(SMTK_ENABLE_QT_SUPPORT @SMTK_ENABLE_QT_SUPPORT@)
if(SMTK_ENABLE_QT_SUPPORT)
find_package(Qt5 REQUIRED COMPONENTS Core OpenGL Widgets)
endif()
set(SMTK_ENABLE_PARAVIEW_SUPPORT @SMTK_ENABLE_PARAVIEW_SUPPORT@)
if(SMTK_ENABLE_PARAVIEW_SUPPORT)
find_package(Qt5 REQUIRED COMPONENTS OpenGL)
find_package(ParaView)
endif()
......@@ -62,6 +68,9 @@ else()
set(SMTK_PYTHON_EXECUTABLE "@smtk_python_executable@")
set(SMTK_PYTHON_LIBRARY "@smtk_python_library@")
set(SMTK_PYTHON_INCLUDE_DIR "@smtk_python_include_dir@")
# SMTK_PYTHON_MDOULEDIR is the location of the smtk python module relative
# to the location of this file.
set(SMTK_PYTHON_MODULEDIR "@smtk_python_moduledir@")
if (SMTK_PYTHON_EXECUTABLE AND NOT PYTHON_EXECUTABLE)
set(PYTHON_EXECUTABLE ${SMTK_PYTHON_EXECUTABLE})
......
......@@ -287,7 +287,8 @@ else()
list(APPEND required_boost_components regex)
endif()
find_package(Boost 1.64.0
set(SMTK_MINIMUM_BOOST_VERSION 1.64.0)
find_package(Boost ${SMTK_MINIMUM_BOOST_VERSION}
COMPONENTS ${required_boost_components} REQUIRED)
if(WIN32 AND MSVC)
......@@ -648,6 +649,9 @@ install(
FILES
${PROJECT_SOURCE_DIR}/CMake/SMTKMacros.cmake
${PROJECT_SOURCE_DIR}/CMake/EncodeStringFunctions.cmake
${PROJECT_SOURCE_DIR}/CMake/InitializePlugins.cxx.in
${PROJECT_SOURCE_DIR}/CMake/InitializePlugins.h.in
${PROJECT_SOURCE_DIR}/CMake/plugins.xml.in
${PROJECT_SOURCE_DIR}/CMake/SMTKOperationXML.cmake
${PROJECT_SOURCE_DIR}/CMake/SMTKPluginMacros.cmake
${PROJECT_SOURCE_DIR}/CMake/serverSource.cxx.in
......@@ -740,6 +744,7 @@ if (SMTK_ENABLE_PYTHON_WRAPPING)
set(smtk_python_executable ${PYTHON_EXECUTABLE})
set(smtk_python_library ${PYTHON_LIBRARIES})
set(smtk_python_include_dir ${PYTHON_INCLUDE_DIRS})
set(smtk_python_moduledir)
endif ()
set(SMTK_VTK_MODULE_DIR "${CMAKE_BINARY_DIR}/lib/cmake/${PROJECT_NAME}/${PROJECT_VERSION}")
......@@ -774,6 +779,9 @@ if (SMTK_RELOCATABLE_INSTALL)
set(smtk_python_executable)
set(smtk_python_library)
set(smtk_python_include_dir)
file(RELATIVE_PATH smtk_python_moduledir
${CMAKE_INSTALL_PREFIX}/${SMTK_INSTALL_CONFIG_DIR}
${CMAKE_INSTALL_PREFIX}/${SMTK_PYTHON_MODULEDIR})
endif ()
endif()
......
#Changes to Attribute Resource
* Added the concept of Parent Analysis. The parent relationship is used to determine the categories associated with an analysis.
* Added the concept of Top Level Analyses - these are analyses that do not have a parent.
* Added the ability to create an attribute definition to represent the analysis structure.
* IO (both JSON and XML) have been changed to support Analysis Parent Relationships.
#New View Type - Associations
This view has the same syntax as an Attribute View but only allows the user to change the association information of the attribute resulting in taking up less screen Real Estate
#Changes to Attribute View
* added a new XML attribute "HideAssociations". If set to true the view will not display the association editing widget save screen Real Estate
#New View Type - Analysis
An Analysis View is a specialized view for choosing the types of analyses the user wants to perform. These choices are persistent and can be used by an export operation instead of having the operator ask the user what types of analyses should be performed.
Unlike other views the Analysis View will construct both an Attribute Definition and corresponding Attribute when needed. The Attribute Definition is based on the Analysis Information stored in the Attribute Resource. Any Analysis that is referred to by another will be represented as a Group Item. All other Analyses will be represented as a Void Item.
The View also controls which categories are permitted to be displayed and/or selected. The set is union of all of the selected Analyses' categories.
The following is an example of a Analysis View:
```xml
<View Type="Analysis" Title="Analysis" AnalysisAttributeName="truchasAnalysis"
AnalysisAttributeType="truchasAnalysisDefinition">
</View>
```
* AnalysisAttributeType is the name of the Attribute Definition the view will create to represent the Analysis Structure (if needed)
* AnalysisAttributeName is the name of the Attribute the view will create to represent the Analysis (if needed)
#Changes to Group View
* View no longer displays empty tabs
# Changes to BaseView
* Added the concept of top level categories that represents a set of categories (that can be a subset of those defined in the attribute resource) that can be used to display or filter attribute information.
#Changes to UIManager
* Added the ability to enable/disable category filtering
* Added support for top-level categories
#Changes to Attribute Association Related API
* attribute::Attribute
* Removed functionality to maintain model::resource's attribute association back-store (no longer needed)
* Added a protected method forceDisassociate that will bypass disassociation checks. This is used by the attribute::Resource when disassociating all attributes from an object.
* Added association checks to the associate method.
* attribute::Resource
* Added hasAttributes method to check to see if an object has attributes associated to it
* Added disassociateAllAttributes method to remove all attribute associations from an object
* model::Entity
* Removed functionality to maintain model::resource's attribute association back-store (no longer needed)
* model::EntityRef
* Removed functionality to maintain model::resource's attribute association back-store (no longer needed) and replaced it with link-based functionality
* Added hasAttributes(smtk::attribute::ConstResourcePtr attRes) const
* Added disassociation methods that don't take in the reverse bool parameter. The original API which does take in the reverse parameter is marked for depreciation (via comment) and calls the new API
#Track attribute resource id, associations in xml I/O
In order for an attribute resource to be reliably written/read to/from
XML, its ID is now stored in its generated .sbi file. Additionally, an
attribute's associations are stored in XML with enough information to
recreate their underlying links.
#General Changes to smtk::model
* Added Pybind11 Registrar methods for smtk::model
## Add logic in the PV layer to force observers to fire on main thread
Qt requires that all methods that affect the GUI be performed on the application's main thread. Many of the registered Observer functions for both operations and resources are designed to affect the GUI. Rather than connect GUI-modifying logic to a signal triggered by an observer, we mutate the behavior of the operation and resource Observer calling logic to ensure that all Observer functors are called on the main thread, regardless of which thread performs the observation.
To support this pattern, SMTK's Observer pattern has been generalized to a single description (smtk::common::Observers) that adopts a run-time configurable type of polymorphism where consuming code can change the class's behavior, allowing consuming code to redefine the context in which the Observer functors are executed.
# ParaView Extensions
## Widgets
The box widget now accepts a single DoubleItem (with 6 entries)
specifying an axis-aligned bounding box or a GroupItem
containing multiple DoubleItems that configure a bounding box
in different ways depending on how they are used.
See the pqSMTKBoxItemWidget header for details.
Add cmake logic to generate a plugin config file
ParaView-derived applications currently ingest plugins in one of two
ways: the plugins are either linked directly into the application, or
they are loaded at runtime. For the latter case, plugin discovery is
performed by reading xml files that describe the plugin's name,
location and whether or not it should be automatically loaded.
When SMTK (and SMTK-derived) plugins are intended to be loaded at
runtime, it is convenient to have the plugin config file generated
using the CMake target properties from the plugins themselves. This
change introduces the exported plugin target property
`ENABLED_BY_DEFAULT` and adds the CMake function
`generate_smtk_plugin_config_file` for ParaView-derived applications
that consume SMTK plugins to generate a plugins file.
When SMTK (and SMTK-derived) plugins are intended to be directly
linked into an application , it is convenient to have a plugin library
generated using the CMake target properties from the plugins
themselves. This change adds the CMake function
`generate_smtk_plugin_library` for ParaView-derived applications
that consume SMTK plugins to generate a plugin library.
......@@ -45,6 +45,7 @@ simulation domain.
extension/index.rst
workflow/index.rst
bindings/index.rst
plugin/index.rst
administration.rst
contributing.rst
......
.. _smtk-plugin-sys:
-----------------------
SMTK's Plugin System
-----------------------
SMTK's functionality can be extended by consuming projects via the
generation of *plugins*.
.. toctree::
:maxdepth: 3
plugins.rst
Plugins
========
SMTK plugins are extensions of ParaView plugins that allow for the automatic
registration of components to SMTK managers. They are created using the
CMake function "add_smtk_plugin", which requires the developer to explicitly list
a registration class "known as a Registrar" and a list of SMTK manager types
to which the plugin registers. SMTK plugins can be introduced to a
ParaView-based application in several ways. The consuming project can
1) list the plugins in a configuration file that is subsequently read at
runtime, deferring the inclusion of plugins to the application's runtime. This
approach requires plugins to reside in certain locations that the application
is expected to look, but facilitates the presentation of a plugin to the user
without automatically loading the plugin. For this approach, a consuming
project can call "generate_smtk_plugin_config_file" to convert the list of
smtk plugin targets (which can be a part of the project or imported from
another project) described by the global property "SMTK_PLUGINS" into a
configuration file. The consuming project can also
2) directly link plugins into the application. This approach pushes the
requirement of locating plugins to be a build-time dependency, which can be
advantageous for packaging. Plugins that are directly linked to an application
cannot be disabled, however (i.e. the target property ENABLED_BY_DEFAULT is
ignored, as it is true for all plugins). To use this approach, a consuming
project can call "generate_smtk_plugin_library" to to use the list of smtk
plugin targets (which can be a part of the project or imported from another
project) described by the global property "SMTK_PLUGINS" to generate a library
against which the application can link to directly incorporate the associated
plugins.
......@@ -333,15 +333,6 @@ bool Attribute::removeAllAssociations(bool partialRemovalOk)
return false;
}
}
// If we are here then there are no prerequisite issues to deal with
for (auto oit = m_associatedObjects->begin(); oit != m_associatedObjects->end(); ++oit)
{
auto modelEnt = dynamic_pointer_cast<smtk::model::Entity>(*oit);
if (modelEnt)
{
modelEnt->modelResource()->disassociateAttribute(nullptr, this->id(), modelEnt->id(), false);
}
}
m_associatedObjects->reset();
return true;
}
......@@ -405,7 +396,7 @@ bool Attribute::isObjectAssociated(const smtk::resource::PersistentObjectPtr& co
*/
bool Attribute::isEntityAssociated(const smtk::common::UUID& entity) const
{
return m_associatedObjects ? m_associatedObjects->has(entity) : false;
return this->isObjectAssociated(entity);
}
/**\brief Is the model entity of the \a entityref associated with this attribute?
......@@ -457,26 +448,29 @@ smtk::common::UUIDs Attribute::associatedModelEntityIds() const
bool Attribute::associate(smtk::resource::PersistentObjectPtr obj)
{
bool res = this->isObjectAssociated(obj);
if (res)
if (this->isObjectAssociated(obj))
{
return res;
return true;
}
// Lets see if we have any conflicts
res = m_associatedObjects ? m_associatedObjects->appendObjectValue(obj) : false;
if (!res)
if (m_definition->checkForConflicts(obj) != nullptr)
{
return res;
return false;
}
// What about missing prerequisites?
if (m_definition->checkForPrerequisites(obj) != nullptr)
{
return false;
}
auto modelEnt = std::dynamic_pointer_cast<smtk::model::Entity>(obj);
if (modelEnt)
// Did it pass the association rules?
if ((m_associatedObjects != nullptr) && m_associatedObjects->appendObjectValue(obj))
{
res = modelEnt->modelResource()->associateAttribute(nullptr, this->id(), modelEnt->id());
return true;
}
return res;
// Failed the association rules
return false;
}
/**\brief Associate a new-style model ID (a UUID) with this attribute.
......@@ -530,14 +524,6 @@ bool Attribute::associateEntity(const smtk::model::EntityRef& entityRef)
res =
(m_associatedObjects) ? m_associatedObjects->appendObjectValue(entityRef.component()) : false;
if (!res)
return res;
smtk::model::ResourcePtr modelMgr = entityRef.resource();
if (modelMgr)
{
res = modelMgr->associateAttribute(nullptr, this->id(), entityRef.entity());
}
return res;
}
......@@ -659,8 +645,7 @@ bool Attribute::disassociate(smtk::resource::PersistentObjectPtr obj, bool rever
return this->disassociate(obj, foo, reverse);
}
bool Attribute::disassociate(
smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt, bool reverse)
bool Attribute::disassociate(smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt, bool)
{
if (!this->canBeDisassociated(obj, probAtt))
{
......@@ -673,18 +658,17 @@ bool Attribute::disassociate(
return true;
}
m_associatedObjects->removeValue(idx);
if (reverse)
{
auto modelEnt = std::dynamic_pointer_cast<smtk::model::Entity>(obj);
if (modelEnt)
{
modelEnt->modelResource()->disassociateAttribute(
this->attributeResource(), this->id(), modelEnt->id(), false);
}
}
return true;
}
void Attribute::forceDisassociate(smtk::resource::PersistentObjectPtr obj)
{
std::ptrdiff_t idx = m_associatedObjects->find(obj);
if (idx >= 0)
{
m_associatedObjects->removeValue(idx);
}
}
/**\brief Return the item with the given \a inName, searching in the given \a style.
*
* The search style dictates whether children of conditional items are included
......
......@@ -50,8 +50,14 @@ class SMTKCORE_EXPORT Attribute : public resource::Component
public:
smtkTypeMacro(smtk::attribute::Attribute);
struct SMTKCORE_EXPORT WeakAttributePtrCompare
struct SMTKCORE_EXPORT CompareByName
{
bool operator()(
const smtk::attribute::AttributePtr& lhs, const smtk::attribute::AttributePtr& rhs) const
{
return lhs->name() < rhs->name();
}
bool operator()(const smtk::attribute::WeakAttributePtr& lhs,
const smtk::attribute::WeakAttributePtr& rhs) const
{
......@@ -283,6 +289,10 @@ protected:
Attribute(const std::string& myName, smtk::attribute::DefinitionPtr myDefinition);
void removeAllItems();
/// Used to disassociate an attribute from an object without checking constraints.
/// Typical use is either when all attributes are being disassocaited from the same
/// object or if the attribute is being deleted.
void forceDisassociate(smtk::resource::PersistentObjectPtr);
void addItem(smtk::attribute::ItemPtr iPtr) { m_items.push_back(iPtr); }
void setName(const std::string& newname) { m_name = newname; }
......
......@@ -203,6 +203,7 @@ smtk_public_headers(smtkCore ${attributeHeaders})
if (SMTK_ENABLE_PARAVIEW_SUPPORT)
add_smtk_plugin(
smtkAttributePlugin "1.0"
ENABLED_BY_DEFAULT
REGISTRAR smtk::attribute::Registrar
MANAGERS smtk::operation::Manager smtk::resource::Manager
LIBRARIES smtkCore)
......
......@@ -286,9 +286,13 @@ smtk::attribute::ItemPtr GroupItem::find(std::size_t element, const std::string&
const GroupItemDefinition* def =
static_cast<const GroupItemDefinition*>(this->definition().get());
int i = def->findItemPosition(inName);
if (i < 0)
{
return smtk::attribute::ItemPtr();
}
assert(m_items.size() > element);
assert(m_items[element].size() > static_cast<std::size_t>(i));
return (i < 0) ? smtk::attribute::ItemPtr() : m_items[element][static_cast<std::size_t>(i)];
return m_items[element][static_cast<std::size_t>(i)];
}
smtk::attribute::ConstItemPtr GroupItem::find(std::size_t element, const std::string& inName) const
......
......@@ -470,7 +470,15 @@ smtk::resource::PersistentObjectPtr ReferenceItem::objectValue(const ReferenceIt
// We can resolve the linked object.
return linkedObject;
}
// If we cannot resolve the linked object, let's check to see if the object
// is held by the same resource as this ReferenceItem. There's no need for
// resource management in this event.
else if (!key.first.isNull() &&
this->attribute()->resource()->links().data().at(key.first).resolve(
this->attribute()->resource()))
{
return this->attribute()->links().linkedObject(key);
}
return PersistentObjectPtr();
}
......@@ -501,6 +509,7 @@ bool ReferenceItem::resolve()
}
}
}
return allResolved;
}
}
......
......@@ -44,6 +44,10 @@ void Registrar::registerTo(const smtk::operation::Manager::Ptr& operationManager
void Registrar::unregisterFrom(const smtk::operation::Manager::Ptr& operationManager)
{
smtk::operation::ReaderGroup(operationManager).unregisterOperation<smtk::attribute::Read>();
smtk::operation::WriterGroup(operationManager).unregisterOperation<smtk::attribute::Write>();
operationManager->unregisterOperations<OperationList>();
}
......
......@@ -14,10 +14,12 @@
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/GroupItemDefinition.h"
#include "smtk/attribute/RefItem.h"
#include "smtk/attribute/RefItemDefinition.h"
#include "smtk/attribute/ValueItem.h"
#include "smtk/attribute/ValueItemDefinition.h"
#include "smtk/attribute/VoidItemDefinition.h"
#include "smtk/model/Resource.h"
......@@ -971,3 +973,143 @@ std::set<AttributePtr> Resource::attributes(
}
return result;
}
bool Resource::hasAttributes(const smtk::resource::ConstPersistentObjectPtr& object) const
{
// See if the object has any attributes - Note that the
// linkedFrom method takes in a const shared pointer to a non-const resource even though the method
// does not change the resource's state. The reason for this is due to issues of auto casting shared pointers to
// non-const objects to shared pointers to const objects.
auto objs = object->links().linkedFrom(
const_cast<Resource*>(this)->shared_from_this(), Resource::AssociationRole);
for (auto obj : objs)
{
auto entry = std::dynamic_pointer_cast<Attribute>(obj);
if (entry)
{ //If we find even one attribute report yes
return true;
}
}
return false;
}
void Resource::disassociateAllAttributes(const smtk::resource::PersistentObjectPtr& object)
{
// Get the attributes associated with this object - Note that the
// linkedFrom method takes in a const shared pointer to a non-const resource even though the method
// does not change the resource's state. The reason for this is due to issues of auto casting shared pointers to
// non-const objects to shared pointers to const objects.
auto objs = object->links().linkedFrom(
const_cast<Resource*>(this)->shared_from_this(), Resource::AssociationRole);
for (auto obj : objs)
{
auto entry = std::dynamic_pointer_cast<Attribute>(obj);
if (entry)
{ // Never insert a failed dynamic cast (null pointer)
entry->forceDisassociate(object);
}
}
}
bool Resource::setAnalysisParent(const std::string& analysisName, const std::string& analysisParent)
{
// First verify that both the analysis and the parent actually are defined
if ((m_analyses.find(analysisName) == m_analyses.end()) ||
(m_analyses.find(analysisParent) == m_analyses.end()))
{
return false;
}
m_analysisParent[analysisName] = analysisParent;
m_analysisChildren[analysisParent].insert(analysisName);
return true;
}
std::string Resource::analysisParent(const std::string& analysisName) const
{
auto it = m_analysisParent.find(analysisName);
if (it == m_analysisParent.end())
{
return "";
}
return it->second;
}
std::set<std::string> Resource::analysisChildren(const std::string& analysisName) const
{
auto it = m_analysisChildren.find(analysisName);
if (it == m_analysisChildren.end())
{
std::set<std::string> empty;
return empty;
}
return it->second;
}
std::set<std::string> Resource::topLevelAnalyses() const
{
std::set<std::string> res;
for (auto const& analysis : m_analyses)
{
if (m_analysisParent.find(analysis.first) == m_analysisParent.end())
{
res.insert(res.end(), analysis.first);
}
}
return res;
}
void Resource::buildAnalysisChildren(GroupItemDefinitionPtr& gitem, const std::string& analysis)
{
auto children = this->analysisChildren(analysis);
if (children.size())
{
auto aitem = gitem->addItemDefinition<GroupItemDefinition>(analysis);
aitem->setIsOptional(true);
for (auto child : children)
{
this->buildAnalysisChildren(aitem, child);
}
}
else
{
auto aitem = gitem->addItemDefinition<VoidItemDefinition>(analysis);
aitem->setIsOptional(true);
}
}
DefinitionPtr Resource::buildAnalysesDefinition(const std::string& type)
{
// First see if the defintion already exists
auto def = this->findDefinition(type);
if (def)
{
return smtk::attribute::DefinitionPtr();
}
// Ok lets build a definition with the following rules:
// 1. All items are optional and each respresents an Analysis
// 2. An Analysis with no children is a void item
// 3. An Analsyis with children is a group item
def = this->createDefinition(type);
auto topAnalyses = this->topLevelAnalyses();
for (auto analysis : topAnalyses)
{
auto children = this->analysisChildren(analysis);
if (children.size())
{
auto aitem = def->addItemDefinition<GroupItemDefinition>(analysis);
aitem->setIsOptional(true);
for (auto child : children)
{
this->buildAnalysisChildren(aitem, child);
}
}
else
{
auto aitem = def->addItemDefinition<VoidItemDefinition>(analysis);
aitem->setIsOptional(true);
}
}
return def;
}
......@@ -143,10 +143,17 @@ public:
smtk::attribute::ConstDefinitionPtr attDef) const;
bool rename(AttributePtr att, const std::string& newName);
// Analysis Methods
bool defineAnalysis(const std::string& analysisName, const std::set<std::string>& categories);
std::size_t numberOfAnalyses() const { return m_analyses.size(); }
std::set<std::string> analysisCategories(const std::string& analysisType) const;
const std::map<std::string, std::set<std::string> >& analyses() const { return m_analyses; }
bool setAnalysisParent(const std::string& analysisName, const std::string& analysisParent);
std::string analysisParent(const std::string& analysisName) const;
std::set<std::string> analysisChildren(const std::string& analysisName) const;
std::set<std::string> topLevelAnalyses() const;
DefinitionPtr buildAnalysesDefinition(const std::string& type);
std::size_t numberOfAdvanceLevels() const { return m_advLevels.size(); }
void addAdvanceLevel(int level, std::string label, const double* l_color = 0);
......@@ -187,7 +194,12 @@ public:
// Return the attributes that are associated on a PersistentObject
std::set<AttributePtr> attributes(const smtk::resource::ConstPersistentObjectPtr& object) const;
bool hasAttributes() { return m_attributes.size() > 0; }
// true if the PersistentObject has attributes associated with it
bool hasAttributes(const smtk::resource::ConstPersistentObjectPtr& object) const;
bool hasAttributes() const { return m_attributes.size() > 0; }
void disassociateAllAttributes(const smtk::resource::PersistentObjectPtr& object);
// When a definition's items has changed use this method to update derived def
// item offsets which is used by the find item method
......@@ -222,10 +234,10 @@ protected:
attribute::DefinitionPtr def, std::vector<smtk::attribute::AttributePtr>& result) const;
bool copyDefinitionImpl(const smtk::attribute::DefinitionPtr sourceDef,
smtk::attribute::ItemDefinition::CopyInfo& info);
void buildAnalysisChildren(GroupItemDefinitionPtr& gitem, const std::string& analysis);
std::map<std::string, smtk::attribute::DefinitionPtr> m_definitions;
std::map<std::string,
std::set<smtk::attribute::AttributePtr, Attribute::WeakAttributePtrCompare> >
std::map<std::string, std::set<smtk::attribute::AttributePtr, Attribute::CompareByName> >
m_attributeClusters;
std::map<std::string, smtk::attribute::AttributePtr> m_attributes;
std::map<smtk::common::UUID, smtk::attribute::AttributePtr> m_attributeIdMap;
......@@ -235,6 +247,8 @@ protected:
m_derivedDefInfo;
std::set<std::string> m_categories;
std::map<std::string, std::set<std::string> > m_analyses;
std::map<std::string, std::set<std::string> > m_analysisChildren;
std::map<std::string, std::string> m_analysisParent;
std::map<std::string, smtk::view::ViewPtr> m_views;
// Advance levels, <int-level, <string-label, color[4]>
......
......@@ -48,7 +48,21 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
}
if (res->numberOfAnalyses())
{
j["Analyses"] = res->analyses();
auto analyses = res->analyses();
j["Analyses"] = analyses;
std::map<std::string, std::string> parentInfo;
for (auto analysis : analyses)
{
auto parent = res->analysisParent(analysis.first);
if (parent != "")
{
parentInfo[analysis.first] = parent;
}
}
if (parentInfo.size())
{
j["AnalysesParentInfo"] = parentInfo;
}
}
// Write out the advance levels information
......@@ -202,16 +216,23 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::ResourcePtr& res)
// Process Analysis Info
// nlohmman's get function does not support nested map, so iterator is used
try
if (j.find("Analyses") != j.end())
{
json analyses = j.at("Analyses");
for (json::iterator iterAna = analyses.begin(); iterAna != analyses.end(); iterAna++)
{
res->defineAnalysis(iterAna.key(), iterAna.value());
}
}
catch (std::exception& /*e*/)
{
// Do we have parent infomation to deal with?
if (j.find("AnalysesParentInfo") != j.end())
{
json parentInfo = j.at("AnalysesParentInfo");
for (json::iterator iterAna = parentInfo.begin(); iterAna != parentInfo.end(); iterAna++)
{
res->setAnalysisParent(iterAna.key(), iterAna.value());
}
}
}
//Process AdvanceLevel info
......
......@@ -35,11 +35,14 @@ PySharedPtrClass< smtk::attribute::Resource, smtk::resource::Resource > pybind11
.def("advanceLevels", &smtk::attribute::Resource::advanceLevels)
.def("analyses", &smtk::attribute::Resource::analyses)
.def("analysisCategories", &smtk::attribute::Resource::analysisCategories, py::arg("analysisType"))
.def("analysisChildren", &smtk::attribute::Resource::analysisChildren, py::arg("analysisType"))
.def("analysisParent", &smtk::attribute::Resource::analysisParent, py::arg("analysisType"))
.def("associations", &smtk::attribute::Resource::associations)
.def("associate", &smtk::attribute::Resource::associate)
.def("attributes", (std::set<smtk::attribute::AttributePtr> (smtk::attribute::Resource::*)(const smtk::resource::ConstPersistentObjectPtr&) const) &smtk::attribute::Resource::attributes, py::arg("object"))
.def("attributes", (void (smtk::attribute::Resource::*)(std::vector<smtk::attribute::AttributePtr>&) const) &smtk::attribute::Resource::attributes, py::arg("result"))
.def("attributes", [](const smtk::attribute::Resource& sys){ std::vector<smtk::attribute::AttributePtr> result; sys.attributes(result); return result; })
.def("buildAnalysesDefinition", &smtk::attribute::Resource::analysisCategories, py::arg("analysisDefinitionType"))
.def("categories", &smtk::attribute::Resource::categories)
.def("copyAttribute", &smtk::attribute::Resource::copyAttribute, py::arg("att"), py::arg("copyModelAssociations") = false, py::arg("options") = 0)
.def("copyDefinition", &smtk::attribute::Resource::copyDefinition, py::arg("def"), py::arg("options") = 0)
......@@ -72,13 +75,16 @@ PySharedPtrClass< smtk::attribute::Resource, smtk::resource::Resource > pybind11
.def("findTopLevelViews", &smtk::attribute::Resource::findTopLevelViews)
.def("findView", &smtk::attribute::Resource::findView, py::arg("title"))
.def("findViewByType", &smtk::attribute::Resource::findViewByType, py::arg("vtype"))
.def("hasAttributes", &smtk::attribute::Resource::hasAttributes)
.def("hasAttributes", (bool (smtk::attribute::Resource::*) () const) &smtk::attribute::Resource::hasAttributes)
.def("hasAttributes", (bool (smtk::attribute::Resource::*) (const smtk::resource::ConstPersistentObjectPtr&) const) &smtk::attribute::Resource::hasAttributes, py::arg("object"))
.def("numberOfAdvanceLevels", &smtk::attribute::Resource::numberOfAdvanceLevels)
.def("numberOfAnalyses", &smtk::attribute::Resource::numberOfAnalyses)
.def("numberOfCategories", &smtk::attribute::Resource::numberOfCategories)
.def("removeAttribute", &smtk::attribute::Resource::removeAttribute, py::arg("att"))
.def("rename", &smtk::attribute::Resource::rename, py::arg("att"), py::arg("newName"))
.def("setAdvanceLevelColor", &smtk::attribute::Resource::setAdvanceLevelColor, py::arg("level"), py::arg("l_color"))
.def("setAnalysisParent", &smtk::attribute::Resource::setAnalysisParent, py::arg("analysisType"), py::arg("analysisParentType"))
.def("topLevelAnalyses", &smtk::attribute::Resource::topLevelAnalyses)
.def("updateCategories", &smtk::attribute::Resource::updateCategories)
.def("updateDerivedDefinitionIndexOffsets", &smtk::attribute::Resource::updateDerivedDefinitionIndexOffsets, py::arg("def"))
.def("views", &smtk::attribute::Resource::views)
......
......@@ -74,6 +74,7 @@ set(unit_tests
unitAttributeBasics
unitAttributeAssociation
unitAttributeAssociationConstraints
unitAttributeAnalysis
unitComponentItem.cxx
unitDateTimeItem.cxx
unitJsonItemDefinitions.cxx
......
//=========================================================================
// 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/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/GroupItemDefinition.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/VoidItemDefinition.h"
#include "smtk/attribute/operators/Read.h"
#include "smtk/attribute/operators/Write.h"
#include "smtk/io/AttributeReader.h"
#include "smtk/io/AttributeWriter.h"
#include "smtk/io/Logger.h"
#include "smtk/common/testing/cxx/helpers.h"
using namespace smtk::attribute;
using namespace smtk::common;
using namespace smtk;
namespace
{
void testLoadedAttributeResource(attribute::ResourcePtr& attRes, const std::string& prefix)
{
smtkTest((attRes->analysisParent("a1") == "a"), prefix << "a1's parent not a");
smtkTest((attRes->analysisParent("b") == ""), prefix << "b has a parent");
}
}
int unitAttributeAnalysis(int, char* [])
{
// ----
// I. Let's create an attribute resource and some analyses
attribute::ResourcePtr attRes = attribute::Resource::create();
std::set<std::string> cats;
cats.insert("foo");
attRes->defineAnalysis("a", cats);
attRes->defineAnalysis("b", cats);
attRes->defineAnalysis("c", cats);
attRes->defineAnalysis("a1", cats);
// Lets try to set the parent to something that doesn't exists
smtkTest(!(attRes->setAnalysisParent("z", "x")), "Succeded in setting z's parent to x");
smtkTest(!(attRes->setAnalysisParent("z", "a")), "Succeded in setting z's parent to a");
smtkTest(!(attRes->setAnalysisParent("a", "x")), "Succeded in setting a's parent to x");
// This should work
smtkTest(attRes->setAnalysisParent("a1", "a"), "Was not able to set a1's parent to a");
// Lets test out the attribute definition building method
// Definition should have 1 group (a), and 2 void (b, c) items. group a should have 1 void item (a1)
auto def = attRes->buildAnalysesDefinition("Analysis");
smtkTest((def != nullptr), "Could not build definition");
smtkTest((def->numberOfItemDefinitions() == 3), "Definition does not have 3 items") int pos =
def->findItemPosition("a");
smtkTest(pos > -1, "Could not find item a");
auto gitem =
std::dynamic_pointer_cast<smtk::attribute::GroupItemDefinition>(def->itemDefinition(pos));
smtkTest((gitem != nullptr), "a is not a group item");
pos = def->findItemPosition("b");
smtkTest(pos > -1, "Could not find item b");
auto vitem =
std::dynamic_pointer_cast<smtk::attribute::VoidItemDefinition>(def->itemDefinition(pos));
smtkTest((vitem != nullptr), "b is not a void item");
pos = def->findItemPosition("c");
smtkTest(pos > -1, "Could not find item c");
vitem = std::dynamic_pointer_cast<smtk::attribute::VoidItemDefinition>(def->itemDefinition(pos));
smtkTest((vitem != nullptr), "c is not a void item");
pos = def->findItemPosition("a1");
smtkTest(pos == -1, "Could find item a1 in Definition");
smtkTest((gitem->numberOfItemDefinitions() == 1), "a's group item does not have 1 item") pos =
gitem->findItemPosition("a1");
smtkTest(pos == 0, "Could not find item a1 in group item a");
vitem =
std::dynamic_pointer_cast<smtk::attribute::VoidItemDefinition>(gitem->itemDefinition(pos));
smtkTest((vitem != nullptr), "a1 is not a void item");
// Should fail if we try to create another with the same type name
def = attRes->buildAnalysesDefinition("Analysis");
smtkTest((def == nullptr), "CWas able to build second definition");
def = nullptr;
vitem = nullptr;
gitem = nullptr;
testLoadedAttributeResource(attRes, "Analysis Test (Original)");
io::AttributeWriter writer;
io::AttributeReader reader;
io::Logger logger;
std::string writeRroot(SMTK_SCRATCH_DIR);
std::string fname = writeRroot + "/unitAttributeAnalysisTest.sbi";
std::string rname = writeRroot + "/unitAttributeAnalysisTest.smtk";
//Test JSON File I/O
attRes->setLocation(rname);
smtk::attribute::Write::Ptr writeOp = smtk::attribute::Write::create();
writeOp->parameters()->associate(attRes);
auto opresult = writeOp->operate();
smtkTest(opresult->findInt("outcome")->value() ==
static_cast<int>(smtk::operation::Operation::Outcome::SUCCEEDED),
"JSON Write operation failed\n"
<< writeOp->log().convertToString());
attRes = nullptr;
smtk::attribute::Read::Ptr readOp = smtk::attribute::Read::create();
readOp->parameters()->findFile("filename")->setValue(rname);
opresult = readOp->operate();
smtkTest(opresult->findInt("outcome")->value() ==
static_cast<int>(smtk::operation::Operation::Outcome::SUCCEEDED),
"JSON Read operation failed\n"
<< writeOp->log().convertToString());
attRes = std::dynamic_pointer_cast<smtk::attribute::Resource>(
opresult->findResource("resource")->objectValue());
//Test the resource created using JSON
testLoadedAttributeResource(attRes, "Analysis Test (JSON)");
//Test XML File I/O
writer.write(attRes, fname, logger);
smtkTest(!logger.hasErrors(), "Error Generated when XML writing file ("
<< fname << "):\n"
<< logger.convertToString());
attRes = attribute::Resource::create();
reader.read(attRes, fname, logger);
smtkTest(!logger.hasErrors(), "Error Generated when XML reading file ("
<< fname << "):\n"
<< logger.convertToString());
//Test the resource created using XML
testLoadedAttributeResource(attRes, "Analysis Test (XML)");
return 0;
}
......@@ -33,16 +33,15 @@ int unitAttributeAssociation(int, char* [])
// ----
// I. First see how things work when Resource is not yet set.
attribute::ResourcePtr resptr = attribute::Resource::create();
attribute::Resource& res(*resptr.get());
smtkTest(
res.associations().empty() == true, "Resource should not have model storage by default.");
resptr->associations().empty() == true, "Resource should not have model storage by default.");
DefinitionPtr def = res.createDefinition("testDef");
DefinitionPtr def = resptr->createDefinition("testDef");
auto arule = def->createLocalAssociationRule();
def->setLocalAssociationMask(smtk::model::VERTEX);
arule->setIsExtensible(true);
arule->setMaxNumberOfValues(2);
AttributePtr att = res.createAttribute("testAtt", "testDef");
AttributePtr att = resptr->createAttribute("testAtt", "testDef");
UUID fakeEntityId = UUID::random();
smtkTest(!att->associateEntity(fakeEntityId),
......@@ -56,9 +55,9 @@ int unitAttributeAssociation(int, char* [])
// II. Now see how things work when the attribute resource has
// a valid model modelMgr pointer.
model::Resource::Ptr modelMgr = model::Resource::create();
res.associate(modelMgr);
smtkTest(
*res.associations().begin() == modelMgr, "Could not set attribute resource's model-resource.");
resptr->associate(modelMgr);