...
 
Commits (13)
# 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.
# By default, Bob owns everything.
# This is overridden below.
* bob.obara@kitware.com
# 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 haocheng.liu@kitware.com tj.corona@kitware.com
smtk/io/ bob.obara@kitware.com tj.corona@kitware.com david.thompson@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 david.thompson@kitware.com bob.obara@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
#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.
......@@ -3,3 +3,31 @@ This view has the same syntax as an Attribute View but only allows the user to c
#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
......@@ -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
......
......@@ -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"
......@@ -1008,3 +1010,106 @@ void Resource::disassociateAllAttributes(const smtk::resource::PersistentObjectP
}
}
}
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);
......@@ -227,6 +234,7 @@ 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::CompareByName> >
......@@ -239,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)
......@@ -80,6 +83,8 @@ PySharedPtrClass< smtk::attribute::Resource, smtk::resource::Resource > pybind11
.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;
}
......@@ -168,6 +168,21 @@ pqSMTKNewResourceBehavior::pqSMTKNewResourceBehavior(QObject* parent)
pqActiveObjects* activeObjects = &pqActiveObjects::instance();
QObject::connect(
activeObjects, SIGNAL(serverChanged(pqServer*)), this, SLOT(updateNewMenu()));
pqServer* server = pqActiveObjects::instance().activeServer();
pqSMTKWrapper* wrapper = pqSMTKBehavior::instance()->resourceManagerForServer(server);
if (wrapper != nullptr)
{
wrapper->smtkOperationManager()->groupObservers().insert(
[this](const smtk::operation::Operation::Index&, const std::string& groupName, bool) {
if (groupName == smtk::operation::CreatorGroup::type_name)
{
this->updateNewMenu();
}
});
// Access the creator group.
auto creatorGroup = smtk::operation::CreatorGroup(wrapper->smtkOperationManager());
}
}
});
}
......
......@@ -21,6 +21,7 @@
#include "pqActiveObjects.h"
#include "pqApplicationCore.h"
#include "pqServerManagerModel.h"
#include "vtkPVXMLParser.h"
#include "vtkSMProxyDefinitionManager.h"
#include "vtkSMSessionProxyManager.h"
......@@ -83,14 +84,23 @@ void extensionsAndDescriptionsFromFileFilters(const std::string& fileFilters,
}
}
std::string proxyName(
const std::string& resource, const std::string&, const std::string& description)
{
std::size_t hash = std::hash<std::string>{}(resource + description);
std::stringstream s;
s << "SMTKModelImporter_" << hash;
return s.str();
}
std::string xmlForSMTKImporter(
const std::string& resource, const std::string& extensions, const std::string& description)
{
std::size_t hash = std::hash<std::string>{}(resource + description);
std::stringstream s;
s << "<ServerManagerConfiguration>\n";
s << " <ProxyGroup name=\"sources\">\n";
s << " <SourceProxy name=\"SMTKModelImporter_" << hash << " \" class=\"vtkSMTKSource\" ";
s << " <SourceProxy name=\"" << proxyName(resource, extensions, description)
<< "\" class=\"vtkSMTKSource\" ";
s << "label=\"SMTK importer for " << description << " into " << resource << "\">\n";
s << " <Documentation>\n";
s << " short_help=\"Import a " << description << " as an SMTK " << resource << ".\"\n";
......@@ -138,11 +148,36 @@ void registerSMTKImporter(
extensionsAndDescriptionsFromFileFilters(fileFilters, extensionsAndDescriptions);
for (auto& token : extensionsAndDescriptions)
{
server->proxyManager()->GetProxyDefinitionManager()->LoadConfigurationXMLFromString(
xmlForSMTKImporter(resource, token.first, token.second).c_str());
vtkNew<vtkPVXMLParser> parser;
if (parser->Parse(xmlForSMTKImporter(resource, token.first, token.second).c_str()) != 0)
{
server->proxyManager()->GetProxyDefinitionManager()->LoadConfigurationXML(
parser->GetRootElement());
}
}
}
}
// TODO: Once ParaView has the ability to unregister configurations for
// readers, the logic below can be used to ensure that removed operations are
// safely removed from ParaView's File->Open() interface.
#if 0
void unregisterSMTKImporter(
pqServer* server, const std::string& resource, const std::string& fileFilters)
{
auto app = pqApplicationCore::instance();
if (app)
{
std::vector<std::pair<std::string, std::string> > extensionsAndDescriptions;
extensionsAndDescriptionsFromFileFilters(fileFilters, extensionsAndDescriptions);
for (auto& token : extensionsAndDescriptions)
{
// TODO: ParaView's vtkSIProxyDefinitionManager needs the ability to
// remove a configuration.
}
}
}
#endif
}
static pqSMTKRegisterImportersBehavior* g_instance = nullptr;
......@@ -181,14 +216,14 @@ pqSMTKRegisterImportersBehavior::~pqSMTKRegisterImportersBehavior()
}
void pqSMTKRegisterImportersBehavior::constructModelImporters(
pqSMTKWrapper* rsrcMgr, pqServer* server)
pqSMTKWrapper* wrapper, pqServer* server)
{
if (!rsrcMgr)
if (!wrapper)
{
return;
}
auto importerGroup = smtk::operation::ImporterGroup(rsrcMgr->smtkOperationManager());
auto importerGroup = smtk::operation::ImporterGroup(wrapper->smtkOperationManager());
for (auto& resourceName : importerGroup.supportedResources())
{
for (auto index : importerGroup.operationsForResource(resourceName))
......@@ -197,4 +232,52 @@ void pqSMTKRegisterImportersBehavior::constructModelImporters(
registerSMTKImporter(server, resourceName, fileItemDef->getFileFilters());
}
}
std::weak_ptr<smtk::operation::Manager> opManager = wrapper->smtkOperationManager();
wrapper->smtkOperationManager()->groupObservers().insert([opManager, server](
const smtk::operation::Operation::Index& index, const std::string& groupName, bool adding) {
if (!adding)
{
return;
}
if (auto operationManager = opManager.lock())
{
if (groupName == smtk::operation::ImporterGroup::type_name)
{
auto importerGroup = smtk::operation::ImporterGroup(operationManager);
assert(importerGroup.has(index));
auto fileItemDef = importerGroup.fileItemDefinitionForOperation(index);
registerSMTKImporter(
server, importerGroup.resourceForOperation(index), fileItemDef->getFileFilters());
}
}
});
// TODO: Once ParaView has the ability to unregister configurations for
// readers, the logic below can be used to ensure that removed operations are
// safely removed from ParaView's File->Open() interface.
#if 0
wrapper->smtkOperationManager()->groupObservers().insert(
[opManager, server](const smtk::operation::Operation::Index& index,
const std::string& groupName, bool adding)
{
if (adding)
{
return;
}
if (auto operationManager = opManager.lock())
{
if (groupName == smtk::operation::ImporterGroup::type_name)
{
auto importerGroup = smtk::operation::ImporterGroup(operationManager);
assert(importerGroup.has(index));
auto fileItemDef = importerGroup.fileItemDefinitionForOperation(index);
unregisterSMTKImporter(server, importerGroup.resourceForOperation(index),
fileItemDef->getFileFilters());
}
}
});
#endif
}
......@@ -71,8 +71,7 @@ private:
{
bool operator()(const RegisterFunction& lhs, const RegisterFunction& rhs) const
{
return lhs.target<bool (*)(const std::weak_ptr<PluginClientBase>&)>() <
rhs.target<bool (*)(const std::weak_ptr<PluginClientBase>&)>();
return &lhs < &rhs;
}
};
......
......@@ -57,7 +57,7 @@ void PluginManager::setRegistryStatus(const std::shared_ptr<Manager>& manager, b
// ...then we also construct a functor for registering this manager to
// future plugins. It accepts as input the plugin client and returns true is
// the manager has not yet expired.
std::weak_ptr<Manager> weakMgr;
std::weak_ptr<Manager> weakMgr = manager;
auto registerToFuturePlugins = [=](const std::weak_ptr<PluginClientBase>& pluginClient) {
if (auto manager = weakMgr.lock())
{
......
......@@ -1816,6 +1816,42 @@
</PropertyGroup>
</Proxy>
<!-- Axis-aligned box widget -->
<Proxy
name="SMTKAxisAlignedBoxWidget"
class="vtkPVBox"
>
<DoubleVectorProperty command="SetBounds"
default_values="0 1 0 1 0 1"
name="Bounds"
number_of_elements="6"></DoubleVectorProperty>
<DoubleVectorProperty animateable="1"
command="SetPosition"
default_values="0.0 0.0 0.0"
name="Position"
number_of_elements="3">
<DoubleRangeDomain name="range" />
<Documentation>
Set the position of the box.
</Documentation>
</DoubleVectorProperty>
<DoubleVectorProperty animateable="1"
command="SetScale"
default_values="1.0 1.0 1.0"
name="Scale"
number_of_elements="3">
<DoubleRangeDomain name="range" />
<Documentation>
Set the size of the box via a scale factor.
</Documentation>
</DoubleVectorProperty>
<PropertyGroup panel_widget="InteractiveBox" label="Box Parameters">
<Property function="Position" name="Position" />
<Property function="Scale" name="Scale" />
<Property function="PlaceWidget" name="Bounds" />
</PropertyGroup>
</Proxy>
</ProxyGroup>
<ProxyGroup name="settings">
......
......@@ -39,16 +39,29 @@ public:
static qtItem* createBoxItemWidget(const AttributeItemInfo& info);
bool createProxyAndWidget(vtkSMProxy*& proxy, pqInteractivePropertyWidget*& widget) override;
/// Retrieve property values from ParaView proxy and store them in the attribute's Item.
void updateItemFromWidget() override;
/// Retrieve property values from the attribute's Item and update the ParaView proxy.
void updateWidgetFromItem() override;
protected:
/// Describe how an attribute's items specify a bounding box.
enum class ItemBindings
{
AxisAlignedBounds, //!< 1 item with 6 values (xmin, xmax, ymin, ymax, zmin, zmax)
AxisAlignedMinMax, //!< 2 items with 3 values each (xlo, ylo, zlo), (xhi, yhi, zhi)
AxisAlignedCenterDeltas, //!< 2 items with 3 values each (xc, yc, zc), (dx, dy, dz)
EulerAngleMinMax, //!< 3 items with 3 values each (xlo, ylo, zlo), (xhi, yhi, zhi), (roll, pitch, yaw)
EulerAngleCenterDeltas //!< 3 items with 3 values each (xc, yc, zc), (dx, dy, dz), (roll, pitch, yaw)
/// 1 item with 6 values (xmin, xmax, ymin, ymax, zmin, zmax)
AxisAlignedBounds,
/// 2 items with 3 values each (xlo, ylo, zlo), (xhi, yhi, zhi)
AxisAlignedMinMax,
/// 2 items with 3 values each (xc, yc, zc), (dx, dy, dz)
AxisAlignedCenterDeltas,
/// 1 item with 6 values (min/max as above), 1 item with (roll, pitch, yaw)
EulerAngleBounds,
/// 3 items with 3 values each (xlo, ylo, zlo), (xhi, yhi, zhi), (roll, pitch, yaw)
EulerAngleMinMax,
/// 3 items with 3 values each (xc, yc, zc), (dx, dy, dz), (roll, pitch, yaw)
EulerAngleCenterDeltas,
/// No consistent set of items detected.
Invalid
};
/**\brief Starting with the widget's assigned item (which may
* be a GroupItem or a DoubleItem), determine and return bound items.
......@@ -56,15 +69,14 @@ protected:
* If errors are encountered, this method returns false.
* If the name of a DoubleItem is provided, then the AxisAlignedBounds binding
* is assumed and that item is returned as the sole entry of \items.
* Otherwise, the named item must be a Group holding items called out as one
* of the following:
* + AxisAlignedMinMax: "Min", "Max" with numberOfValues == 3
* + AxisAlignedCenterDeltas: "Center", "Deltas", with numberOfValues == 3
* + EulerAngleMinMax: "Angles", "Min", "Max" with numberOfValues == 3
* + EulerAngleCenterDeltas: "Angles, "Center", "Deltas" with numberOfValues == 3
* Otherwise, the named item must be a Group holding items called out as via
* one of the remaining valid ItemBindings enumerants.
*
* Euler angles must be provided in degrees and are roll, pitch, and yaw
* (i.e., rotation about the x, y, and z axes, respectively).
* Angles must be provided in degrees and are Tait-Bryan angles
* as used by VTK (i.e., rotations about y then x then z axes).
* These are similar to Euler angles and sometimes called as such.
* See https://en.wikipedia.org/wiki/Euler_angles#Intrinsic_rotations
* for more information. VTK uses the Y_1 X_2 Z_3 ordering.
*/
bool fetchBoxItems(ItemBindings& binding, std::vector<smtk::attribute::DoubleItemPtr>& items);
};
......
......@@ -13,9 +13,9 @@ set(QAttrLibSrcs
qtCollapsibleGroupWidget.cxx
qtComponentItem.cxx
qtDescriptivePhraseDelegate.cxx
qtDescriptivePhraseEditor.cxx
qtDescriptivePhraseModel.cxx
qtGroupView.cxx
qtAnalysisView.cxx
qtAssociationView.cxx
qtAttributeView.cxx
qtInstancedView.cxx
......@@ -80,9 +80,9 @@ set(QAttrLibMocHeaders
qtComponentItem.h
qtEmittingStringBuffer.h
qtDescriptivePhraseDelegate.h
qtDescriptivePhraseEditor.h
qtDescriptivePhraseModel.h
qtGroupView.h
qtAnalysisView.h
qtAssociationView.h
qtAttributeView.h
qtInstancedView.h
......
//=========================================================================
// 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/qt/qtAnalysisView.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/GroupItem.h"
#include "smtk/extension/qt/qtAttribute.h"
#include "smtk/extension/qt/qtUIManager.h"
#include "smtk/io/AttributeWriter.h"
#include "smtk/io/Logger.h"
#include "smtk/view/View.h"
#include <QApplication>
#include <QFile>
#include <QFont>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QScrollArea>
#include <QSize>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QVariant>
#include <algorithm>
using namespace smtk::attribute;
using namespace smtk::extension;
qtBaseView* qtAnalysisView::createViewWidget(const ViewInfo& info)
{
qtAnalysisView* view = new qtAnalysisView(info);
view->buildUI();
return view;
}
qtAnalysisView::qtAnalysisView(const ViewInfo& info)
: qtBaseView(info)
{
}
qtAnalysisView::~qtAnalysisView()
{
}
void qtAnalysisView::createWidget()
{
smtk::view::ViewPtr view = this->getObject();
if (!view)
{
return;
}
this->Widget = new QFrame(this->parentWidget());
//create the layout for the frame area
QVBoxLayout* layout = new QVBoxLayout(this->Widget);
layout->setMargin(0);
this->Widget->setLayout(layout);
auto attRes = this->uiManager()->attResource();
std::string attName, defName;
view->details().attribute("AnalysisAttributeName", attName);
view->details().attribute("AnalysisAttributeType", defName);
// Lets see if we need to create the analysis
// attribute or its definition?
auto attDef = attRes->findDefinition(defName);
if (!attDef)
{
attDef = attRes->buildAnalysesDefinition(defName);
}
m_analysisAttribute = attRes->findAttribute(attName);
if (!m_analysisAttribute)
{
m_analysisAttribute = attRes->createAttribute(attName, attDef);
}
// OK Now lets create a qtAttribute for the Analysis Attribute
// Tell the UI Manager not to filter
this->uiManager()->disableCategoryChecks();
int labelWidth =
this->uiManager()->getWidthOfAttributeMaxLabel(attDef, this->uiManager()->advancedFont());
this->setFixedLabelWidth(labelWidth);
smtk::view::View::Component comp; // Right now not being used
qtAttribute* attInstance = new qtAttribute(m_analysisAttribute, comp, this->widget(), this);
attInstance->createBasicLayout(true);
this->uiManager()->enableCategoryChecks();
layout->addWidget(attInstance->widget());
QObject::connect(attInstance, SIGNAL(modified()), this, SLOT(analysisChanged()));
// OK - lets apply the initial state.
this->analysisChanged();
}
void qtAnalysisView::processAnalysisItem(
smtk::attribute::ConstItemPtr item, std::set<std::string>& cats)
{
// If the item is not active there is nothing to do
if (!item->isEnabled())
{
return;
}
auto attRes = this->uiManager()->attResource();
auto myCats = attRes->analysisCategories(item->name());
cats.insert(myCats.begin(), myCats.end());
auto gitem = std::dynamic_pointer_cast<const GroupItem>(item);
if (gitem == nullptr)
{
return;
}
std::size_t i, n = gitem->numberOfItemsPerGroup();
for (i = 0; i < n; i++)
{
this->processAnalysisItem(gitem->item(i), cats);
}
}
void qtAnalysisView::analysisChanged()
{
// Lets iterate over the items in the analysis attribute and set
// the categories accordingly
std::set<std::string> cats;
std::size_t i, n = m_analysisAttribute->numberOfItems();
for (i = 0; i < n; i++)
{
this->processAnalysisItem(m_analysisAttribute->item(i), cats);
}
this->uiManager()->setToLevelCategories(cats);
}
//=========================================================================
// 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_qtAnalysisView_h
#define __smtk_extension_qtAnalysisView_h
#include "smtk/extension/qt/Exports.h"
#include "smtk/extension/qt/qtBaseView.h"
#include <set>
/**\brief Provides the QT UI for an Analysis View.
*
* 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:
* <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)
*
* \sa qtBaseView
*/
namespace smtk
{
namespace extension
{
class SMTKQTEXT_EXPORT qtAnalysisView : public qtBaseView
{
Q_OBJECT
public:
static qtBaseView* createViewWidget(const ViewInfo& info);
qtAnalysisView(const ViewInfo& info);
virtual ~qtAnalysisView();
public slots:
void analysisChanged();
protected:
void createWidget() override;
void processAnalysisItem(smtk::attribute::ConstItemPtr item, std::set<std::string>& cats);
private:
smtk::attribute::AttributePtr m_analysisAttribute;
}; // class
}; // namespace attribute
}; // namespace smtk
#endif
......@@ -40,14 +40,57 @@ using namespace smtk::extension;
class qtAssociationViewInternals : public Ui::qtAssociationView
{
public:
const QList<smtk::attribute::DefinitionPtr> getCurrentDefs(const QString strCategory) const
QList<smtk::attribute::DefinitionPtr> getCurrentDefs(
smtk::extension::qtUIManager* uiManager) const
{
if (uiManager->categoryEnabled())
{
auto currentCat = uiManager->currentCategory();
if (this->AttDefMap.keys().contains(currentCat.c_str()))
{
return this->AttDefMap[currentCat.c_str()];
}
return this->AllDefs;
}
else if (!uiManager->topLevelCategoriesSet())
{
return this->AllDefs;
}
QList<smtk::attribute::DefinitionPtr> defs;
foreach (DefinitionPtr attDef, this->AllDefs)
{
if (uiManager->passAttributeCategoryCheck(attDef))
{
defs.push_back(attDef);
}
}
return defs;
}
if (this->AttDefMap.keys().contains(strCategory))
bool currentDefsIsEmpty(smtk::extension::qtUIManager* uiManager) const
{
if (uiManager->categoryEnabled())
{
auto currentCat = uiManager->currentCategory();
if (this->AttDefMap.keys().contains(currentCat.c_str()))
{
return (this->AttDefMap[currentCat.c_str()].size() == 0);
}
return (this->AllDefs.size() == 0);
}
else if (!uiManager->topLevelCategoriesSet())
{
return (this->AllDefs.size() == 0);
}
QList<smtk::attribute::DefinitionPtr> defs;
foreach (DefinitionPtr attDef, this->AllDefs)
{
return this->AttDefMap[strCategory];
if (uiManager->passAttributeCategoryCheck(attDef))
{
return false;
}
}
return this->AllDefs;
return true;
}
QPointer<qtAssociationWidget> AssociationsWidget;
......@@ -154,7 +197,7 @@ void qtAssociationView::displayAttributes()
}
QList<smtk::attribute::DefinitionPtr> currentDefs =
this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str());
this->Internals->getCurrentDefs(this->uiManager());
std::set<AttributePtr, Attribute::CompareByName> atts;
// Get all of the attributes that match the list of definitions
foreach (attribute::DefinitionPtr attDef, currentDefs)
......@@ -262,7 +305,15 @@ void qtAssociationView::getAllDefinitions()
}
}
// The criterea used for this view is the same as that used in the attribute view
// - are there any definitions that pass the category check. Alternatively it could
// have been - are there any attributes available to select. However there is a problem
// with this since this view potentially depends on a view to create attributes. If the view's
// visibility depends on whether it is empty or not, then there would need to be a way to ask
// the top level view to redraw based on an attribute view changing things - in the current
// implementation, both the attribute view and the association view would either be visible or
// hidden at the same time.
bool qtAssociationView::isEmpty() const
{
return (this->Internals->attributes->count() == 0);
return this->Internals->currentDefsIsEmpty(this->uiManager());
}
......@@ -63,15 +63,33 @@ using namespace smtk::extension;
class qtAttributeViewInternals
{
public:
const QList<smtk::attribute::DefinitionPtr> getCurrentDefs(const QString strCategory) const
const QList<smtk::attribute::DefinitionPtr> getCurrentDefs(
smtk::extension::qtUIManager* uiManager) const
{
if (this->AttDefMap.keys().contains(strCategory))
if (uiManager->categoryEnabled())
{
auto currentCat = uiManager->currentCategory();
if (this->AttDefMap.keys().contains(currentCat.c_str()))
{
return this->AttDefMap[currentCat.c_str()];
}
return this->AllDefs;
}
else if (!uiManager->topLevelCategoriesSet())
{
return this->AttDefMap[strCategory];
return this->AllDefs;
}
return this->AllDefs;
QList<smtk::attribute::DefinitionPtr> defs;
foreach (DefinitionPtr attDef, this->AllDefs)
{
if (uiManager->passAttributeCategoryCheck(attDef))
{
defs.push_back(attDef);
}
}
return defs;
}
qtTableWidget* ListTable;
qtTableWidget* ValuesTable;
......@@ -655,8 +673,7 @@ void qtAttributeView::onCreateNew()
{
strDef = this->Internals->DefsCombo->currentText();
}
foreach (attribute::DefinitionPtr attDef,
this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str()))
foreach (attribute::DefinitionPtr attDef, this->Internals->getCurrentDefs(this->uiManager()))
{
std::string txtDef = attDef->displayedTypeName();
if (strDef == QString::fromUtf8(txtDef.c_str()))
......@@ -778,7 +795,7 @@ void qtAttributeView::onViewBy(int viewBy)
}
QList<smtk::attribute::DefinitionPtr> currentDefs =
this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str());
this->Internals->getCurrentDefs(this->uiManager());
this->Internals->AddButton->setEnabled(currentDefs.count() > 0);
bool viewAtt = (viewBy == VIEWBY_Attribute);
......@@ -1477,6 +1494,6 @@ void qtAttributeView::showAdvanceLevelOverlay(bool show)
bool qtAttributeView::isEmpty() const
{
QList<smtk::attribute::DefinitionPtr> currentDefs =
this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str());
this->Internals->getCurrentDefs(this->uiManager());
return currentDefs.isEmpty();
}
......@@ -517,3 +517,30 @@ bool qtBaseView::isEmpty() const
{
return false;
}
void qtBaseView::setTopLevelCategories(const std::set<std::string>& categories)
{
if ((!m_isTopLevel) || (this->Internals->ShowCategoryCombo == nullptr))
{
this->onShowCategory();
return;
}
auto current = this->Internals->ShowCategoryCombo->currentText();
this->Internals->ShowCategoryCombo->blockSignals(true);
this->Internals->ShowCategoryCombo->clear();
for (auto cat : categories)
{
this->Internals->ShowCategoryCombo->addItem(cat.c_str());
}
this->Internals->ShowCategoryCombo->blockSignals(false);
int pos = this->Internals->ShowCategoryCombo->findText(current);
if (pos > -1)
{
this->Internals->ShowCategoryCombo->setCurrentIndex(pos);
}
else
{
this->Internals->ShowCategoryCombo->setCurrentIndex(0);
}
this->onShowCategory();
}
......@@ -96,6 +96,7 @@ public:
void setInitialCategory();
bool isTopLevel() const { return m_isTopLevel; }
void setTopLevelCategories(const std::set<std::string>& categories);
//Returns true if the view does not contain any information to display - the default
// behavior is to return false
......
......@@ -9,11 +9,11 @@
//=========================================================================
#include "smtk/extension/qt/qtDescriptivePhraseDelegate.h"
#include "smtk/extension/qt/qtDescriptivePhraseEditor.h"
#include "smtk/extension/qt/qtDescriptivePhraseModel.h"
#include <QAbstractProxyModel>
#include <QApplication>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPainter>
......@@ -279,7 +279,7 @@ QWidget* qtDescriptivePhraseDelegate::createEditor(
// Otherwise, edit the title if the item says we can.
if (idx.data(qtDescriptivePhraseModel::TitleTextMutableRole).toBool())
{
smtk::extension::qtDescriptivePhraseEditor* editor = new qtDescriptivePhraseEditor(owner);
QLineEdit* editor = new QLineEdit(owner);
return editor;
}
return nullptr;
......@@ -336,24 +336,20 @@ void qtDescriptivePhraseDelegate::updateEditorGeometry(
void qtDescriptivePhraseDelegate::setEditorData(QWidget* editor, const QModelIndex& idx) const
{
smtk::extension::qtDescriptivePhraseEditor* entityEditor =
qobject_cast<smtk::extension::qtDescriptivePhraseEditor*>(editor);
if (entityEditor)
QLineEdit* titleEditor = qobject_cast<QLineEdit*>(editor);
if (titleEditor)
{
entityEditor->setTitle(idx.data(qtDescriptivePhraseModel::TitleTextRole).toString());
// TODO: editor should also allow adjusting entity type?
titleEditor->setText(idx.data(qtDescriptivePhraseModel::TitleTextRole).toString());
}
}
void qtDescriptivePhraseDelegate::setModelData(
QWidget* editor, QAbstractItemModel* model, const QModelIndex& idx) const
{
smtk::extension::qtDescriptivePhraseEditor* entityEditor =
qobject_cast<smtk::extension::qtDescriptivePhraseEditor*>(editor);
if (entityEditor)
QLineEdit* titleEditor = qobject_cast<QLineEdit*>(editor);
if (titleEditor)
{
// TODO: editor should also allow adjusting entity type?
model->setData(idx, entityEditor->title(), qtDescriptivePhraseModel::TitleTextRole);
model->setData(idx, titleEditor->text(), qtDescriptivePhraseModel::TitleTextRole);
}
}
......
......@@ -48,6 +48,8 @@ public:
{
}
QList<smtk::extension::qtBaseView*> ChildViews;
QList<QWidget*> PageWidgets;
QList<QIcon> PageIcons;
QList<QLabel*> Labels;
qtGroupViewInternals::Style m_style;
std::vector<smtk::view::ViewPtr> m_views;
......@@ -176,6 +178,7 @@ void qtGroupView::createWidget()
if (!v)
{
// No such View by that name in attribute resource
std::cerr << "Skipping Child: " << t << " could not be found in attribute resource\n";
continue;
}
......@@ -259,6 +262,8 @@ void qtGroupView::clearChildViews()
}
this->Internals->ChildViews.clear();
this->Internals->Labels.clear();
this->Internals->PageWidgets.clear();
this->Internals->PageIcons.clear();
}
void qtGroupView::updateUI()
......@@ -284,6 +289,35 @@ void qtGroupView::updateUI()
}
}
}
else if (this->Internals->m_style == qtGroupViewInternals::TABBED)
{
QTabWidget* tabWidget = dynamic_cast<QTabWidget*>(this->Widget);
if (!tabWidget)
{
return;
}
tabWidget->clear();
int i, size = this->Internals->ChildViews.size();
for (i = 0; i < size; i++)
{
auto child = this->Internals->ChildViews.at(i);
child->updateUI();
if (child->isEmpty())
{
continue;
}
this->Internals->PageWidgets.at(i)->show();
if (this->Internals->PageIcons.at(i).isNull())
{
QString secTitle = child->getObject()->label().c_str();
tabWidget->addTab(this->Internals->PageWidgets.at(i), secTitle);
}
else
{
tabWidget->addTab(this->Internals->PageWidgets.at(i), this->Internals->PageIcons.at(i), "");
}
}
}
else
{
foreach (qtBaseView* childView, this->Internals->ChildViews)
......@@ -316,6 +350,35 @@ void qtGroupView::onShowCategory()
}
}
}
else if (this->Internals->m_style == qtGroupViewInternals::TABBED)
{
QTabWidget* tabWidget = dynamic_cast<QTabWidget*>(this->Widget);
if (!tabWidget)
{
return;
}
tabWidget->clear();
int i, size = this->Internals->ChildViews.size();
for (i = 0; i < size; i++)
{
auto child = this->Internals->ChildViews.at(i);
child->onShowCategory();
if (child->isEmpty())
{
continue;
}
this->Internals->PageWidgets.at(i)->show();
if (this->Internals->PageIcons.at(i).isNull())
{
QString secTitle = child->getObject()->label().c_str();
tabWidget->addTab(this->Internals->PageWidgets.at(i), secTitle);
}
else
{
tabWidget->addTab(this->Internals->PageWidgets.at(i), this->Internals->PageIcons.at(i), "");
}
}
}
else
{
foreach (qtBaseView* childView, this->Internals->ChildViews)
......@@ -337,29 +400,27 @@ void qtGroupView::showAdvanceLevelOverlay(bool show)
void qtGroupView::addTabEntry(qtBaseView* child)
{
QTabWidget* tabWidget = static_cast<QTabWidget*>(this->Widget);
QTabWidget* tabWidget = dynamic_cast<QTabWidget*>(this->Widget);
if (!tabWidget || !child || !child->getObject())
{
return;
}
QWidget* tabPage = new QWidget();
tabPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
QWidget* content = new QWidget();
content->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
QScrollArea* s = new QScrollArea(tabWidget);
s->setWidgetResizable(true);
s->setFrameShape(QFrame::NoFrame);
QScrollArea* tabPage = new QScrollArea(tabWidget);
tabPage->setWidgetResizable(true);
tabPage->setFrameShape(QFrame::NoFrame);
QString secTitle = child->getObject()->label().c_str();
QString name = "tab" + QString(secTitle);
s->setObjectName(name);
s->setWidget(tabPage);
tabPage->setObjectName(name);
tabPage->setWidget(content);
QVBoxLayout* vLayout = new QVBoxLayout(tabPage);
QVBoxLayout* vLayout = new QVBoxLayout(content);
vLayout->setMargin(0);
vLayout->addWidget(child->widget());
int index = tabWidget->addTab(s, secTitle);
tabWidget->setTabToolTip(index, secTitle);
QIcon icon;
//using the ui label name find if we have an icon resource
QString resourceName = QApplication::applicationDirPath().append("/../Resources/Icons/");
//QString resourceName = ":/SimBuilder/Icons/";
......@@ -375,7 +436,6 @@ void qtGroupView::addTabEntry(qtBaseView* child)
if (QFile::exists(resourceName))
{
QPixmap image(resourceName);
QIcon icon;
QMatrix transform;
if (tabWidget->tabPosition() == QTabWidget::East)
{
......@@ -386,8 +446,29 @@ void qtGroupView::addTabEntry(qtBaseView* child)
transform.rotate(90);
}
icon = image.transformed(transform);
tabWidget->setTabIcon(index, icon);
tabWidget->setTabText(index, "");