Commit da25ac93 authored by David Thompson's avatar David Thompson
Browse files

Use the attribute system to specify operators.

Remove the `smtk/model/{Parameter,OperatorResult}` classes.
They are replaced by adding a `specification()` method to
the `Operator` class that returns an `AttributePtr` (typedef'd
to `OperatorSpecification`). The `OperatorResult` class is
also replaced by an `AttributePtr`.

The attributes and their definitions are held by an
attribute `Manager` owned by the `Bridge` whose model
entities the operators can have as operands.

Since the attribute system will be used for operators,
it will be possible to determine operator names and
parameters without instantiating an operator. (Instead,
the attribute manager for the bridge can be asked for
definitions.) Because of this, `Operator`s now use the
same auto-init utilities as the `Bridge` classes.
Upon an operator's static initialization, it registers
itself with the proper subclass of `smtk::model::Bridge`,
providing its name, a constructor function, and an XML
definition of its parameters and another definition of
its result values.
When an instance of a Bridge subclass is constructed,
each registered operator's XML definition is loaded into
the bridge's attribute manager.
Thus, bridges no longer keep a list of Operator instances;
instead their attribute manager tracks available definitions.

Operators now have a "specification" that is an AttributePtr
specifying parameter values.
The specification is null by default but can be set to an
attribute with the proper definition (matching the one in the bridge's
attribute manager).

ImportJSON and ExportJSON provide methods for transporting attribute
definitions.
Since the XML reader does not provide a list of
the toplevel attributes it reads, the JSON
we export/import must store a copy of attribute
name alongside the XML.

This commit also adds smtkTypeMacro() to a large number
of smtk::attribute classes so that templated methods operating
on subclasses of Item and ItemDefinition can refer to
shared pointers more easily.

This commit makes the Bridge class's `operatorManager()`
attribute manager held by pointer rather than by value.
Because subclasses of DefaultBridge (like the TestForwardingBridge
in the unitDefaultBridge test) are constructed by calling all
subclass constructors, they would being initialized with the
wrong static list of operator constructors if the manager
was held by value. Now, when each Bridge
subclass calls `initializeOperatorManager()` in its constructor,
any previous subclass initialization is blown away by deleting
the old `operatorManager()` and constructing a new one before
populating it. It would be nice to have a `reset()` method on
attribute::Manager. Sigh.

Finally, this adds some helper methods to bridges and operators
for obtaining the class name of an instance. The tests use this
to aid in debugging.

Silence silly shiboken signals: ignore warnings generated by
shiboken-generated-code... at least for GNU and clang C++ compilers.

A CMake function named smtk_operator_xml() is installed so that
external projects (namely CMB) can use it. This function encodes
an XML file as a C++ string for use in associating an `Operator`'s
C++ implementation with its XML definition.
parent 76728495
function(encodeStringAsCVariable rawString encodedVarName stringOut)
string(REPLACE "\\" "\\\\" str1 "${${rawString}}")
string(REPLACE "\"" "\\\"" str2 "${str1}")
string(REPLACE "\n" "\\n" str3 "${str2}")
string(CONFIGURE
"\nstatic const char ${encodedVarName}[] = \"${str3}\";\n\n"
escaped ESCAPE_QUOTES)
set(${stringOut} "${escaped}" PARENT_SCOPE)
endfunction()
function(configureFileAsCVariable srcFileName dstFileName encodedVarName)
if (EXISTS ${srcFileName})
file(READ ${srcFileName} fileContents)
encodeStringAsCVariable(fileContents ${encodedVarName} encodedContents)
if (EXISTS ${dstFileName})
file(READ ${dstFileName} already)
endif()
message("Writing ${dstFileName}")
if (NOT "${encodedContents}" STREQUAL "${already}")
file(WRITE ${dstFileName} "${encodedContents}")
endif()
else()
file(REMOVE ${dstFileName})
endif()
endfunction()
# Example:
# configureFileAsCVariable("foo.xml" "bar.cxx" "operatorSpec")
# would read "foo.xml", escape it as a C string, and write the
# assigment:
# static const char operatorSpec[] = "...";
# into bar.cxx (where "..." is the encoded contents of "foo.xml").
#
# When srcFileName does not exist, then dstFileName will be
# removed so that missing files are more easily spotted.
# Note that since this configuration is done when CMake runs
# you must re-run CMake in order to regenerate the file.
#
# The dstFileName file will not be overwritten unless the encoded
# string or variable name differs, in order to avoid recompiling
# dependent files unneccessarily.
......@@ -98,6 +98,7 @@ function(smtk_prepend_string prefix result)
set(${result} ${newNames} PARENT_SCOPE)
endfunction(smtk_prepend_string)
include(SMTKOperatorXML)
# Builds source groups for the smtk files so that they show up nicely in
# Visual Studio.
......
# Given a list of filenames (opSpecs) containing XML descriptions of
# operators, configure C++ source that encodes the XML as a string.
# The resulting files are placed in the current binary directory and
# appended to genFiles.
include(EncodeCStringFunctions)
function(smtk_operator_xml opSpecs genFiles)
foreach (opSpec ${opSpecs})
get_filename_component(genFileBase "${opSpec}" NAME_WE)
set(genFile "${CMAKE_CURRENT_BINARY_DIR}/${genFileBase}_xml.h")
#message("Writing ${genFileBase}_xml.cxx (${opSpec})")
configureFileAsCVariable("${opSpec}" "${genFile}" "${genFileBase}_xml")
set(${genFiles} ${${genFiles}} "${genFile}" PARENT_SCOPE)
endforeach()
endfunction()
......@@ -281,6 +281,11 @@ function(sbk_wrap_library NAME)
${SHIBOKEN_LIBRARY}
${_extra_link_libraries}
)
# Avoid generating warnings from generated code.
if (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_target_properties(${_pyname} PROPERTIES COMPILE_FLAGS " -Wno-cast-qual -Wno-missing-field-initializers -Wno-unused-function -Wno-unused-parameter -Wno-overloaded-virtual")
endif()
INSTALL(TARGETS ${_pyname} RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
......
......@@ -197,6 +197,14 @@ mark_as_advanced(
EXECUTABLE_OUTPUT_PATH
LIBRARY_OUTPUT_PATH)
# Install rules for SMTK macros usable by external packages:
install(
FILES
${PROJECT_SOURCE_DIR}/CMake/EncodeCStringFunctions.cmake
${PROJECT_SOURCE_DIR}/CMake/SMTKOperatorXML.cmake
DESTINATION
lib/cmake/SMTK
)
################################################################################
# Build third party libraries
......
......@@ -89,7 +89,6 @@ namespace smtk
class Model;
class ModelEntity;
class Operator;
class OperatorResult;
class Parameter;
class PropertyValuePhrase;
class PropertyListPhrase;
......@@ -207,6 +206,11 @@ namespace smtk
// definition of the mask type for model entities. enum is in smtk/model/Item.h
typedef unsigned long MaskType;
// Model-related typedefs (dependent on attribute classes)
typedef smtk::shared_ptr< smtk::attribute::Definition > OperatorDefinition;
typedef smtk::shared_ptr< smtk::attribute::Attribute > OperatorSpecification;
typedef smtk::shared_ptr< smtk::attribute::Attribute > OperatorResult;
};
namespace attribute
......@@ -248,6 +252,25 @@ namespace smtk
typedef smtk::shared_ptr< smtk::attribute::VoidItem > VoidItemPtr;
typedef smtk::shared_ptr< smtk::attribute::VoidItemDefinition > VoidItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::DirectoryItem > ConstDirectoryItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::DirectoryItemDefinition > ConstDirectoryItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::DoubleItem > ConstDoubleItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::DoubleItemDefinition > ConstDoubleItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::FileItem > ConstFileItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::FileItemDefinition > ConstFileItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::GroupItem > ConstGroupItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::GroupItemDefinition > ConstGroupItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::IntItem > ConstIntItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::IntItemDefinition > ConstIntItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::StringItem > ConstStringItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::StringItemDefinition > ConstStringItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::ModelEntityItem > ConstModelEntityItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::ModelEntityItemDefinition > ConstModelEntityItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::VoidItem > ConstVoidItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::VoidItemDefinition > ConstVoidItemDefinitionPtr;
typedef smtk::shared_ptr< const smtk::attribute::RefItem > ConstRefItemPtr;
typedef smtk::shared_ptr< const smtk::attribute::RefItemDefinition > ConstRefItemDefinitionPtr;
// Note used by SMTK but added for completeness
typedef smtk::shared_ptr< smtk::attribute::Manager > ManagerPtr;
};
......
......@@ -23,10 +23,19 @@ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/RefItem.h"
#include "smtk/attribute/ValueItem.h"
#include "smtk/attribute/GroupItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/DoubleItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/DirectoryItem.h"
#include "smtk/attribute/Item.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/Manager.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Cursor.h"
#include "smtk/model/Item.h"
......@@ -125,6 +134,105 @@ bool Attribute::isMemberOf(const std::vector<std::string> &categories) const
{
return this->m_definition->isMemberOf(categories);
}
namespace {
template<typename T>
bool isInvalid(T itemPtr)
{
if (!itemPtr)
return true;
std::size_t actual = itemPtr->numberOfValues();
std::size_t minNum = itemPtr->numberOfRequiredValues();
if (
actual < minNum ||
(minNum && actual > minNum))
return true;
for (std::size_t i = 0; i < actual; ++i)
if (!itemPtr->isSet(i))
return true;
return false;
}
template<>
bool isInvalid<ValueItemPtr>(ValueItemPtr itemPtr)
{
if (!itemPtr)
return true;
std::size_t actual = itemPtr->numberOfValues();
std::size_t minNum = itemPtr->numberOfRequiredValues();
std::size_t maxNum = itemPtr->maxNumberOfValues();
if (
actual < minNum ||
actual > maxNum ||
(maxNum == 0 && actual > minNum && !itemPtr->isExtensible()))
return true;
for (std::size_t i = 0; i < actual; ++i)
if (!itemPtr->isSet(i))
return true;
return false;
}
}
/**\brief Validate the attribute against its definition.
*
* This method will only return true when every (required) item in the
* attribute is set and considered a valid value by its definition.
* This can be used to ensure that an attribute is in a good state
* before using it to perform some operation.
*/
bool Attribute::isValid()
{
std::vector<smtk::attribute::ItemPtr> items;
this->references(items);
std::vector<smtk::attribute::ItemPtr>::iterator it;
for (it = items.begin(); it != items.end(); ++it)
{
switch ((*it)->type())
{
case Item::ATTRIBUTE_REF:
{
smtk::attribute::RefItemPtr ri =
smtk::dynamic_pointer_cast<smtk::attribute::RefItem>(*it);
if (isInvalid(ri))
return false;
}
break;
case Item::MODEL_ENTITY:
{
smtk::attribute::ModelEntityItemPtr mei =
smtk::dynamic_pointer_cast<smtk::attribute::ModelEntityItem>(*it);
if (isInvalid(mei))
return false;
}
break;
case Item::GROUP:
break;
case Item::VOID:
break;
case Item::DOUBLE:
case Item::INT:
case Item::STRING:
case Item::FILE:
case Item::DIRECTORY:
case Item::COLOR:
{
smtk::attribute::ValueItemPtr vi =
smtk::dynamic_pointer_cast<smtk::attribute::ValueItem>(*it);
if (isInvalid(vi))
return false;
}
break;
default:
break;
}
}
return true;
}
//----------------------------------------------------------------------------
Manager *Attribute::manager() const
{
......@@ -312,3 +420,42 @@ smtk::attribute::ItemPtr Attribute::find(const std::string &inName)
return (i < 0) ? smtk::attribute::ItemPtr() : this->m_items[static_cast<std::size_t>(i)];
}
//-----------------------------------------------------------------------------
smtk::attribute::IntItemPtr Attribute::findInt(const std::string &name)
{ return smtk::dynamic_pointer_cast<IntItem>(this->find(name)); }
smtk::attribute::ConstIntItemPtr Attribute::findInt(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const IntItem>(this->find(name)); }
smtk::attribute::DoubleItemPtr Attribute::findDouble(const std::string &name)
{ return smtk::dynamic_pointer_cast<DoubleItem>(this->find(name)); }
smtk::attribute::ConstDoubleItemPtr Attribute::findDouble(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const DoubleItem>(this->find(name)); }
smtk::attribute::StringItemPtr Attribute::findString(const std::string &name)
{ return smtk::dynamic_pointer_cast<StringItem>(this->find(name)); }
smtk::attribute::ConstStringItemPtr Attribute::findString(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const StringItem>(this->find(name)); }
smtk::attribute::FileItemPtr Attribute::findFile(const std::string &name)
{ return smtk::dynamic_pointer_cast<FileItem>(this->find(name)); }
smtk::attribute::ConstFileItemPtr Attribute::findFile(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const FileItem>(this->find(name)); }
smtk::attribute::DirectoryItemPtr Attribute::findDirectory(const std::string &name)
{ return smtk::dynamic_pointer_cast<DirectoryItem>(this->find(name)); }
smtk::attribute::ConstDirectoryItemPtr Attribute::findDirectory(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const DirectoryItem>(this->find(name)); }
smtk::attribute::GroupItemPtr Attribute::findGroup(const std::string &name)
{ return smtk::dynamic_pointer_cast<GroupItem>(this->find(name)); }
smtk::attribute::ConstGroupItemPtr Attribute::findGroup(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const GroupItem>(this->find(name)); }
smtk::attribute::RefItemPtr Attribute::findRef(const std::string &name)
{ return smtk::dynamic_pointer_cast<RefItem>(this->find(name)); }
smtk::attribute::ConstRefItemPtr Attribute::findRef(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const RefItem>(this->find(name)); }
smtk::attribute::ModelEntityItemPtr Attribute::findModelEntity(const std::string &name)
{ return smtk::dynamic_pointer_cast<ModelEntityItem>(this->find(name)); }
smtk::attribute::ConstModelEntityItemPtr Attribute::findModelEntity(const std::string &name) const
{ return smtk::dynamic_pointer_cast<const ModelEntityItem>(this->find(name)); }
......@@ -100,6 +100,30 @@ namespace smtk
std::size_t numberOfItems() const
{return this->m_items.size();}
smtk::attribute::IntItemPtr findInt(const std::string &name);
smtk::attribute::ConstIntItemPtr findInt(const std::string &name) const;
smtk::attribute::DoubleItemPtr findDouble(const std::string &name);
smtk::attribute::ConstDoubleItemPtr findDouble(const std::string &name) const;
smtk::attribute::StringItemPtr findString(const std::string &name);
smtk::attribute::ConstStringItemPtr findString(const std::string &name) const;
smtk::attribute::FileItemPtr findFile(const std::string &name);
smtk::attribute::ConstFileItemPtr findFile(const std::string &name) const;
smtk::attribute::DirectoryItemPtr findDirectory(const std::string &name);
smtk::attribute::ConstDirectoryItemPtr findDirectory(const std::string &name) const;
smtk::attribute::GroupItemPtr findGroup(const std::string &name);
smtk::attribute::ConstGroupItemPtr findGroup(const std::string &name) const;
smtk::attribute::RefItemPtr findRef(const std::string &name);
smtk::attribute::ConstRefItemPtr findRef(const std::string &name) const;
smtk::attribute::ModelEntityItemPtr findModelEntity(const std::string &name);
smtk::attribute::ConstModelEntityItemPtr findModelEntity(const std::string &name) const;
void references(std::vector<smtk::attribute::ItemPtr> &list) const;
// These methods are for the old model storage:
......@@ -135,6 +159,8 @@ namespace smtk
void setAppliesToInteriorNodes(bool appliesValue)
{this->m_appliesToInteriorNodes = appliesValue;}
bool isValid();
smtk::attribute::Manager *manager() const;
smtk::model::ManagerPtr modelManager() const;
......
......@@ -32,6 +32,7 @@ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#include "smtk/SMTKCoreExports.h"
#include "smtk/PublicPointerDefs.h"
#include "smtk/util/SharedFromThis.h" // For smtkTypeMacro.
#include <map>
#include <string>
#include <set>
......@@ -53,6 +54,7 @@ namespace smtk
class SMTKCORE_EXPORT Definition
{
public:
smtkTypeMacro(Definition);
virtual ~Definition();
// Description:
......
......@@ -42,6 +42,7 @@ namespace smtk
{
friend class DirectoryItemDefinition;
public:
smtkTypeMacro(DirectoryItem);
virtual ~DirectoryItem();
virtual Item::Type type() const;
bool shouldBeRelative() const;
......
......@@ -41,6 +41,7 @@ namespace smtk
public ItemDefinition
{
public:
smtkTypeMacro(DirectoryItemDefinition);
static smtk::attribute::DirectoryItemDefinitionPtr New(const std::string &myName)
{ return smtk::attribute::DirectoryItemDefinitionPtr(new DirectoryItemDefinition(myName));}
......
......@@ -41,6 +41,7 @@ namespace smtk
{
friend class DoubleItemDefinition;
public:
smtkTypeMacro(DoubleItem);
virtual ~DoubleItem();
virtual Item::Type type() const;
virtual void copyFrom(const smtk::attribute::ItemPtr sourceItem,
......
......@@ -37,6 +37,7 @@ namespace smtk
public ValueItemDefinitionTemplate<double>
{
public:
smtkTypeMacro(DoubleItemDefinition);
static smtk::attribute::DoubleItemDefinitionPtr New(const std::string &myName)
{ return smtk::attribute::DoubleItemDefinitionPtr(new DoubleItemDefinition(myName));}
......
......@@ -42,6 +42,7 @@ namespace smtk
{
friend class FileItemDefinition;
public:
smtkTypeMacro(FileItem);
virtual ~FileItem();
virtual Item::Type type() const;
bool shouldBeRelative() const;
......
......@@ -41,6 +41,7 @@ namespace smtk
public ItemDefinition
{
public:
smtkTypeMacro(FileItemDefinition);
static smtk::attribute::FileItemDefinitionPtr New(const std::string &myName)
{ return smtk::attribute::FileItemDefinitionPtr(new FileItemDefinition(myName));}
......
......@@ -39,6 +39,7 @@ namespace smtk
{
friend class GroupItemDefinition;
public:
smtkTypeMacro(GroupItem);
virtual ~GroupItem();
virtual Item::Type type() const;
std::size_t numberOfRequiredGroups() const;
......
......@@ -41,6 +41,7 @@ namespace smtk
public ItemDefinition
{
public:
smtkTypeMacro(GroupItemDefinition);
static smtk::attribute::GroupItemDefinitionPtr New(const std::string &myName)
{ return smtk::attribute::GroupItemDefinitionPtr(new GroupItemDefinition(myName));}
......
......@@ -41,6 +41,7 @@ namespace smtk
{
friend class IntItemDefinition;
public:
smtkTypeMacro(IntItem);
virtual ~IntItem();
virtual Item::Type type() const;
virtual void copyFrom(const smtk::attribute::ItemPtr sourceItem,
......
......@@ -37,6 +37,7 @@ namespace smtk
public ValueItemDefinitionTemplate<int>
{
public:
smtkTypeMacro(IntItemDefinition);
static smtk::attribute::IntItemDefinitionPtr New(const std::string &myName)
{ return smtk::attribute::IntItemDefinitionPtr(new IntItemDefinition(myName));}
......
......@@ -290,7 +290,7 @@ Item::Type Item::string2Type(const std::string &s)
{
return VOID;
}
if (s == "MODEL_ENTITY")
if (s == "ModelEntity")
{
return MODEL_ENTITY;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment