/*========================================================================= Program: ParaView Module: vtkSMProperty.cxx Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkSMProperty.h" #include "vtkClientServerStream.h" #include "vtkCommand.h" #include "vtkObjectFactory.h" #include "vtkProcessModule.h" #include "vtkPVInstantiator.h" #include "vtkPVXMLElement.h" #include "vtkSmartPointer.h" #include "vtkSMDocumentation.h" #include "vtkSMDomain.h" #include "vtkSMDomainIterator.h" #include "vtkSMMessage.h" #include "vtkSMProperty.h" #include "vtkSMPropertyLink.h" #include "vtkSMProxy.h" #include #include #include "vtkSMPropertyInternals.h" vtkStandardNewMacro(vtkSMProperty); vtkCxxSetObjectMacro(vtkSMProperty, InformationProperty, vtkSMProperty); vtkCxxSetObjectMacro(vtkSMProperty, Documentation, vtkSMDocumentation); vtkCxxSetObjectMacro(vtkSMProperty, Hints, vtkPVXMLElement); //--------------------------------------------------------------------------- vtkSMProperty::vtkSMProperty() { this->StateIgnored = false; this->Command = 0; this->ImmediateUpdate = 0; this->Animateable = 2; // By default Animateable in advanced mode only. this->PInternals = new vtkSMPropertyInternals; this->XMLName = 0; this->XMLLabel = 0; this->PanelVisibility = 0; this->PanelVisibilityDefaultForRepresentation = 0; this->PanelWidget = 0; this->DomainIterator = vtkSMDomainIterator::New(); this->DomainIterator->SetProperty(this); this->Proxy = 0; this->InformationOnly = 0; this->InformationProperty = 0; this->IsInternal = 0; this->NoCustomDefault = 0; this->Documentation = 0; this->Repeatable = 0; this->IgnoreSynchronization = 0; this->Links = NULL; this->Hints = 0; this->BlockModifiedEvents = false; this->PendingModifiedEvents = false; // by default, properties are set to show only in advanced mode this->SetPanelVisibility("default"); this->Proxy = 0; // Whenever the property fires UncheckedPropertyModifiedEvent, we update any // dependent domains. this->AddObserver(vtkCommand::UncheckedPropertyModifiedEvent, this, &vtkSMProperty::UpdateDomains); } //--------------------------------------------------------------------------- vtkSMProperty::~vtkSMProperty() { this->RemoveFromSourceLink(); this->SetCommand(0); delete this->PInternals; this->SetXMLName(0); this->SetXMLLabel(0); this->DomainIterator->Delete(); this->SetInformationProperty(0); this->SetDocumentation(0); this->SetHints(0); this->SetParent(0); this->SetPanelVisibility(0); this->SetPanelVisibilityDefaultForRepresentation(0); this->SetPanelWidget(0); if (this->Links) { this->Links->Delete(); this->Links = NULL; } } //----------------------------------------------------------------------------- // UnRegister is overloaded because the object has a reference to itself // through the domain iterator. void vtkSMProperty::UnRegister(vtkObjectBase* obj) { if (this->ReferenceCount == 2) { this->Superclass::UnRegister(obj); vtkSMDomainIterator *tmp = this->DomainIterator; tmp->Register(0); tmp->SetProperty(0); tmp->UnRegister(0); return; } this->Superclass::UnRegister(obj); } //--------------------------------------------------------------------------- int vtkSMProperty::IsInDomains() { return this->IsInDomains(NULL); } //--------------------------------------------------------------------------- int vtkSMProperty::IsInDomains(vtkSMDomain** ptr) { this->DomainIterator->Begin(); while(!this->DomainIterator->IsAtEnd()) { if (!this->DomainIterator->GetDomain()->IsInDomain(this)) { if (ptr) { *ptr = this->DomainIterator->GetDomain(); } return 0; } this->DomainIterator->Next(); } return 1; } //--------------------------------------------------------------------------- void vtkSMProperty::AddDomain(const char* name, vtkSMDomain* domain) { // Check if the proxy already exists. If it does, we will // replace it vtkSMPropertyInternals::DomainMap::iterator it = this->PInternals->Domains.find(name); if (it != this->PInternals->Domains.end()) { vtkWarningMacro("Domain " << name << " already exists. Replacing"); it->second->SetProperty(NULL); } this->PInternals->Domains[name] = domain; if (domain) { domain->SetProperty(this); // doesn't change reference count. domain->AddObserver(vtkCommand::DomainModifiedEvent, this, &vtkSMProperty::InvokeDomainModifiedEvent); } } //--------------------------------------------------------------------------- void vtkSMProperty::AddLinkedProperty(vtkSMProperty* targetProperty) { if (!targetProperty) { return; } // This sets up the target property to take on the value of this property // whenever it is updated. if (!this->Links) { this->Links = vtkSMPropertyLink::New(); this->Links->AddLinkedProperty(this->GetParent(), this->GetXMLName(), vtkSMLink::INPUT); } this->Links->AddLinkedProperty(targetProperty->GetParent(), targetProperty->GetXMLName(), vtkSMLink::OUTPUT); targetProperty->PInternals->LinkSourceProperty = this; } //--------------------------------------------------------------------------- void vtkSMProperty::RemoveLinkedProperty(vtkSMProperty* targetProperty) { if (!targetProperty || !this->Links) { return; } this->Links->RemoveLinkedProperty(targetProperty->GetParent(), targetProperty->GetXMLName()); } //--------------------------------------------------------------------------- void vtkSMProperty::RemoveFromSourceLink() { if (this->PInternals->LinkSourceProperty) { // Remove this instance as a subscriber to the source proxy this->PInternals->LinkSourceProperty->RemoveLinkedProperty(this); this->PInternals->LinkSourceProperty = NULL; } } //--------------------------------------------------------------------------- void vtkSMProperty::InvokeDomainModifiedEvent() { this->InvokeEvent(vtkCommand::DomainModifiedEvent); } //--------------------------------------------------------------------------- vtkSMDomain* vtkSMProperty::GetDomain(const char* name) { vtkSMPropertyInternals::DomainMap::iterator it = this->PInternals->Domains.find(name); if (it == this->PInternals->Domains.end()) { return 0; } return it->second.GetPointer(); } //--------------------------------------------------------------------------- vtkSMDomain* vtkSMProperty::FindDomain(const char* classname) { vtkSmartPointer iter; iter.TakeReference(this->NewDomainIterator()); for (iter->Begin(); !iter->IsAtEnd(); iter->Next()) { if (iter->GetDomain()->IsA(classname)) { return iter->GetDomain(); } } return 0; } //--------------------------------------------------------------------------- unsigned int vtkSMProperty::GetNumberOfDomains() { return static_cast(this->PInternals->Domains.size()); } //--------------------------------------------------------------------------- vtkSMDomainIterator* vtkSMProperty::NewDomainIterator() { vtkSMDomainIterator* iter = vtkSMDomainIterator::New(); iter->SetProperty(this); return iter; } //--------------------------------------------------------------------------- void vtkSMProperty::AddDependent(vtkSMDomain* dom) { this->PInternals->Dependents.push_back(dom); } //--------------------------------------------------------------------------- void vtkSMProperty::RemoveAllDependents() { vtkSMPropertyInternals::DependentsVector::iterator iter = this->PInternals->Dependents.begin(); for (; iter != this->PInternals->Dependents.end(); iter++) { iter->GetPointer()->RemoveRequiredProperty(this); } this->PInternals->Dependents.erase( this->PInternals->Dependents.begin(), this->PInternals->Dependents.end()); } //--------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void vtkSMProperty::UpdateDependentDomains() { } #endif //--------------------------------------------------------------------------- void vtkSMProperty::UpdateDomains() { // I genuinely doubt when a property changes, its domain should change!! //// Update own domains //this->DomainIterator->Begin(); //while(!this->DomainIterator->IsAtEnd()) // { // this->DomainIterator->GetDomain()->Update(0); // this->DomainIterator->Next(); // } // Update other dependent domains vtkSMPropertyInternals::DependentsVector::iterator iter = this->PInternals->Dependents.begin(); for (; iter != this->PInternals->Dependents.end(); iter++) { iter->GetPointer()->Update(this); } } //--------------------------------------------------------------------------- vtkSMProperty* vtkSMProperty::NewProperty(const char* name) { if (!this->Proxy) { return 0; } return this->Proxy->NewProperty(name); } //--------------------------------------------------------------------------- void vtkSMProperty::CreatePrettyLabel(const char* xmlname) { // Add space before every capital letter not preceeded by a capital letter // or space hence: // "MySpace" ==> "My Space" // "MySPACE" ==> "My SPACE" // "My Space" ==> "My Space" int max = static_cast(strlen(xmlname)); char* label = new char[2*max+10]; char* ptr = label; bool previous_capital = false; *ptr = xmlname[0]; ptr++; for (int cc=1; cc < max; ++cc) { if (xmlname[cc] >= 'A' && xmlname[cc] <= 'Z') { if (!previous_capital && *(ptr-1) != ' ') { *ptr = ' '; ptr++; } previous_capital = true; } else { previous_capital = false; } *ptr = xmlname[cc]; ptr++; } *ptr = 0; this->SetXMLLabel(label); delete [] label; } //--------------------------------------------------------------------------- int vtkSMProperty::ReadXMLAttributes(vtkSMProxy* proxy, vtkPVXMLElement* element) { // TODO: some of the attributes are no longer necessary on the proxy-side, // eg. "Command". We will remove those once we've verified that they are // present on the PMProperty side. const char* xmlname = element->GetAttribute("name"); if(xmlname) { this->SetXMLName(xmlname); } const char* xmllabel = element->GetAttribute("label"); if (xmllabel) { this->SetXMLLabel(xmllabel); } else { this->CreatePrettyLabel(xmlname); } const char* command = element->GetAttribute("command"); if(command) { this->SetCommand(command); } int repeatable; int retVal = 1; if( element->GetScalarAttribute("repeatable", &repeatable) || element->GetScalarAttribute("repeat_command", &repeatable)) { this->Repeatable = repeatable; } const char* information_property = element->GetAttribute("information_property"); if(information_property) { this->SetInformationProperty(this->NewProperty(information_property)); } int immediate_update; retVal = element->GetScalarAttribute("immediate_update", &immediate_update); if(retVal) { this->SetImmediateUpdate(immediate_update); } int state_ignored; retVal = element->GetScalarAttribute("state_ignored", &state_ignored); if(retVal) { this->SetStateIgnored( state_ignored != 0 ); } else { this->StateIgnoredOff(); // Default value } int information_only; retVal = element->GetScalarAttribute("information_only", &information_only); if(retVal) { this->SetInformationOnly(information_only); } int ignore_synch; retVal = element->GetScalarAttribute("ignore_synchronization", &ignore_synch); if(retVal) { this->SetIgnoreSynchronization(ignore_synch); } int animateable; retVal = element->GetScalarAttribute("animateable", &animateable); if (retVal) { this->SetAnimateable(animateable); } int is_internal; if (element->GetScalarAttribute("is_internal", &is_internal)) { this->SetIsInternal(is_internal); } int no_custom_default; if (element->GetScalarAttribute("no_custom_default", &no_custom_default)) { this->SetNoCustomDefault(no_custom_default); } const char *panel_visibility = element->GetAttribute("panel_visibility"); if(panel_visibility) { this->SetPanelVisibility(panel_visibility); } const char *panel_visibility_default_for_representation = element->GetAttribute("panel_visibility_default_for_representation"); if(panel_visibility_default_for_representation) { this->SetPanelVisibilityDefaultForRepresentation( panel_visibility_default_for_representation); } const char *panel_widget = element->GetAttribute("panel_widget"); if(panel_widget) { this->SetPanelWidget(panel_widget); } // Manage deprecated XML definition int deprecated_attr_value; if(element->GetScalarAttribute("update_self", &deprecated_attr_value)) { std::ostringstream proxyXML; element->GetParent()->PrintXML(proxyXML, vtkIndent(1)); vtkWarningMacro(<< "Attribute update_self is not managed anymore." << "It is deprecated. " << endl << "Please FIX the decalaration of the following Proxy." << endl << proxyXML.str().c_str()); } // Read and create domains. for(unsigned int i=0; i < element->GetNumberOfNestedElements(); ++i) { vtkPVXMLElement* domainEl = element->GetNestedElement(i); // These are not domain elements. if (strcmp(domainEl->GetName(),"Documentation") == 0) { vtkSMDocumentation* doc = vtkSMDocumentation::New(); doc->SetDocumentationElement(domainEl); this->SetDocumentation(doc); doc->Delete(); continue; } else if (strcmp(domainEl->GetName(), "Hints") == 0) { this->SetHints(domainEl); continue; } else if ( std::string(domainEl->GetName()).find("InformationHelper") != std::string::npos) { // InformationHelper are used to extract information from VTK object // therefore they are not used on the proxy side (SM). continue; } else if ( std::string(domainEl->GetName()).find("StringArrayHelper") != std::string::npos) { // InformationHelper are used to extract information from VTK object // therefore they are not used on the proxy side (SM). continue; } // Everything else is assumed to be a domain element. vtkObject* object = 0; std::ostringstream name; name << "vtkSM" << domainEl->GetName() << ends; object = vtkPVInstantiator::CreateInstance(name.str().c_str()); if (object) { vtkSMDomain* domain = vtkSMDomain::SafeDownCast(object); if (domain) { domain->SetSession(proxy->GetSession()); if (domain->ReadXMLAttributes(this, domainEl)) { const char* dname = domainEl->GetAttribute("name"); if (dname) { domain->SetXMLName(dname); this->AddDomain(dname, domain); } } } else { vtkErrorMacro("Object created (type: " << name.str().c_str() << ") is not of a recognized type."); } object->Delete(); } else { vtkErrorMacro("Could not create object of type: " << name.str().c_str() << ". Did you specify wrong xml element?"); } } return 1; } //--------------------------------------------------------------------------- void vtkSMProperty::Copy(vtkSMProperty* ) { } //--------------------------------------------------------------------------- void vtkSMProperty::WriteTo(vtkSMMessage* msg) { ProxyState_Property *prop = msg->AddExtension(ProxyState::property); prop->set_name(this->GetXMLName()); } //--------------------------------------------------------------------------- bool vtkSMProperty::ResetToDomainDefaults(bool use_unchecked_values) { if (vtkProcessModule::GetProcessModule() && vtkProcessModule::GetProcessModule()->GetSymmetricMPIMode()) { // when using symmetric mpi, we disable domains since they don't always have // the most updated information. return false; } this->DomainIterator->Begin(); while (!this->DomainIterator->IsAtEnd()) { if (this->DomainIterator->GetDomain()->SetDefaultValues(this, use_unchecked_values)) { return true; } this->DomainIterator->Next(); } return false; } //--------------------------------------------------------------------------- void vtkSMProperty::ResetToDefault() { if (!this->ResetToDomainDefaults(false)) { this->ResetToXMLDefaults(); } } //--------------------------------------------------------------------------- void vtkSMProperty::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Proxy: " << this->Proxy << endl; os << indent << "Command: " << (this->Command ? this->Command : "(null)") << endl; os << indent << "ImmediateUpdate:" << this->ImmediateUpdate << endl; os << indent << "InformationOnly:" << this->InformationOnly << endl; os << indent << "XMLName:" << (this->XMLName ? this->XMLName : "(null)") << endl; os << indent << "XMLLabel: " << (this->XMLLabel? this->XMLLabel : "(null)") << endl; os << indent << "InformationProperty: " << this->InformationProperty << endl; os << indent << "Animateable: " << this->Animateable << endl; os << indent << "Internal: " << this->IsInternal << endl; os << indent << "Repeatable: " << this->Repeatable << endl; os << indent << "Documentation: " << this->Documentation << endl; os << indent << "Hints: " ; if (this->Hints) { this->Hints->PrintSelf(os, indent); } else { os << "(none)" << endl; } if (this->Links) { os << indent << "Links: " << endl; this->Links->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Links: none" << endl; } } //--------------------------------------------------------------------------- void vtkSMProperty::SaveState(vtkPVXMLElement* parent, const char* property_name, const char* uid, int saveDomains/*=1*/) { vtkPVXMLElement* propertyElement = vtkPVXMLElement::New(); propertyElement->SetName("Property"); propertyElement->AddAttribute("name", property_name); propertyElement->AddAttribute("id", uid); this->SaveStateValues(propertyElement); if (saveDomains) { this->SaveDomainState(propertyElement, uid); } parent->AddNestedElement(propertyElement); propertyElement->Delete(); } //--------------------------------------------------------------------------- void vtkSMProperty::SaveStateValues(vtkPVXMLElement* /*propertyElement*/) { // Concreate class should overide it !!! } //--------------------------------------------------------------------------- void vtkSMProperty::SaveDomainState(vtkPVXMLElement* propertyElement, const char* uid) { this->DomainIterator->Begin(); while(!this->DomainIterator->IsAtEnd()) { std::ostringstream dname; dname << uid << "." << this->DomainIterator->GetKey() << ends; this->DomainIterator->GetDomain()->SaveState(propertyElement, dname.str().c_str()); this->DomainIterator->Next(); } } //--------------------------------------------------------------------------- int vtkSMProperty::LoadState(vtkPVXMLElement* propertyElement, vtkSMProxyLocator* loader) { // Process the domains. unsigned int numElems = propertyElement->GetNumberOfNestedElements(); for (unsigned int cc=0; cc < numElems; cc++) { vtkPVXMLElement* child = propertyElement->GetNestedElement(cc); if (!child->GetName()) { continue; } if (strcmp(child->GetName(),"Domain") == 0) { const char* name = child->GetAttribute("name"); vtkSMDomain* domain = name? this->GetDomain(name) : 0; if (domain) { domain->LoadState(child, loader); } } } return 1; } //--------------------------------------------------------------------------- void vtkSMProperty::SetParent(vtkSMProxy *proxy) { this->Proxy = proxy; } //--------------------------------------------------------------------------- vtkSMProxy* vtkSMProperty::GetParent() { return this->Proxy.GetPointer(); } //--------------------------------------------------------------------------- bool vtkSMProperty::HasDomainsWithRequiredProperties() { for (vtkSMPropertyInternals::DomainMap::iterator iter = this->PInternals->Domains.begin(); iter != this->PInternals->Domains.end(); ++iter) { if (iter->second->GetNumberOfRequiredProperties() > 0) { return true; } } return false; }