Files
ThirdParty-6/ParaView-5.0.1/ParaViewCore/ServerManager/Core/vtkSMProxy.cxx

2542 lines
76 KiB
C++

/*=========================================================================
Program: ParaView
Module: vtkSMProxy.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 "vtkSMProxy.h"
#include "vtkSMProxyInternals.h"
#include "vtkClientServerStream.h"
#include "vtkCommand.h"
#include "vtkDebugLeaks.h"
#include "vtkGarbageCollector.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkProcessModule.h"
#include "vtkPVInstantiator.h"
#include "vtkPVOptions.h"
#include "vtkPVXMLElement.h"
#include "vtkSIProxyDefinitionManager.h"
#include "vtkSIProxy.h"
#include "vtkSmartPointer.h"
#include "vtkSMDocumentation.h"
#include "vtkSMInputProperty.h"
#include "vtkSMMessage.h"
#include "vtkSMPropertyGroup.h"
#include "vtkSMPropertyIterator.h"
#include "vtkSMProxyLocator.h"
#include "vtkSMProxyManager.h"
#include "vtkSMSession.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMStateLocator.h"
#include <algorithm>
#include <assert.h>
#include <set>
#include <string>
#include <vector>
#include <sstream>
#include <vtksys/RegularExpression.hxx>
//---------------------------------------------------------------------------
// Observer for modified event of the property
class vtkSMProxyObserver : public vtkCommand
{
public:
static vtkSMProxyObserver *New()
{ return new vtkSMProxyObserver; }
virtual void Execute(vtkObject* obj, unsigned long event, void* data)
{
if (this->Proxy)
{
if (!this->PropertyName.empty())
{
// This is observing a property.
this->Proxy->SetPropertyModifiedFlag(this->PropertyName.c_str(), 1);
}
else
{
this->Proxy->ExecuteSubProxyEvent(vtkSMProxy::SafeDownCast(obj),
event, data);
}
}
}
void SetPropertyName(const char* name)
{
this->PropertyName = (name? name : "");
}
// Note that Proxy is not reference counted. Since the Proxy has a reference
// to the Property and the Property has a reference to the Observer, making
// Proxy reference counted would cause a loop.
void SetProxy(vtkSMProxy* proxy)
{
this->Proxy = proxy;
}
protected:
std::string PropertyName;
vtkSMProxy* Proxy;
};
vtkStandardNewMacro(vtkSMProxy);
vtkCxxSetObjectMacro(vtkSMProxy, XMLElement, vtkPVXMLElement);
vtkCxxSetObjectMacro(vtkSMProxy, Hints, vtkPVXMLElement);
vtkCxxSetObjectMacro(vtkSMProxy, Deprecated, vtkPVXMLElement);
//---------------------------------------------------------------------------
vtkSMProxy::vtkSMProxy()
{
this->Internals = new vtkSMProxyInternals;
this->SIClassName = 0;
this->SetSIClassName("vtkSIProxy");
// By default, all objects are created on data server.
this->Location = vtkProcessModule::DATA_SERVER;
this->VTKClassName = 0;
this->XMLGroup = 0;
this->XMLName = 0;
this->XMLLabel = 0;
this->XMLSubProxyName = 0;
this->ObjectsCreated = 0;
this->XMLElement = 0;
this->DoNotUpdateImmediately = 0;
this->DoNotModifyProperty = 0;
this->InUpdateVTKObjects = 0;
this->PropertiesModified = 0;
this->SubProxyObserver = vtkSMProxyObserver::New();
this->SubProxyObserver->SetProxy(this);
this->Documentation = vtkSMDocumentation::New();
this->InMarkModified = 0;
this->NeedsUpdate = true;
this->Hints = 0;
this->Deprecated = 0;
this->State = new vtkSMMessage();
}
//---------------------------------------------------------------------------
vtkSMProxy::~vtkSMProxy()
{
this->RemoveAllObservers();
// ensure that the properties are destroyed before we delete this->Internals.
this->Internals->Properties.clear();
delete this->Internals;
this->SetVTKClassName(0);
this->SetXMLGroup(0);
this->SetXMLName(0);
this->SetXMLLabel(0);
this->SetXMLSubProxyName(0);
this->SetXMLElement(0);
if (this->SubProxyObserver)
{
this->SubProxyObserver->SetProxy(0);
this->SubProxyObserver->Delete();
}
this->Documentation->Delete();
this->SetHints(0);
this->SetDeprecated(0);
this->SetSIClassName(0);
if(this->State)
{
delete this->State;
this->State = 0;
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::SetLocation(vtkTypeUInt32 location)
{
this->Superclass::SetLocation(location);
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->SetLocation(location);
}
}
//---------------------------------------------------------------------------
vtkObjectBase* vtkSMProxy::GetClientSideObject()
{
if (this->Session)
{
this->CreateVTKObjects();
vtkTypeUInt32 gid = this->GetGlobalID();
vtkSIProxy* siProxy =
vtkSIProxy::SafeDownCast(this->Session->GetSIObject(gid));
if (siProxy)
{
return siProxy->GetVTKObject();
}
}
return NULL;
}
//---------------------------------------------------------------------------
const char* vtkSMProxy::GetPropertyName(vtkSMProperty* prop)
{
const char* result = 0;
vtkSMPropertyIterator* piter = this->NewPropertyIterator();
for(piter->Begin(); !piter->IsAtEnd(); piter->Next())
{
if (prop == piter->GetProperty())
{
result = piter->GetKey();
break;
}
}
piter->Delete();
return result;
}
//---------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::GetProperty(const char* name, int selfOnly)
{
if (!name)
{
return 0;
}
vtkSMProxyInternals::PropertyInfoMap::iterator it =
this->Internals->Properties.find(name);
if (it != this->Internals->Properties.end())
{
return it->second.Property.GetPointer();
}
if (!selfOnly)
{
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator eiter =
this->Internals->ExposedProperties.find(name);
if (eiter == this->Internals->ExposedProperties.end())
{
// no such property is being exposed.
return 0;
}
const char* subproxy_name = eiter->second.SubProxyName.c_str();
const char* property_name = eiter->second.PropertyName.c_str();
vtkSMProxy * sp = this->GetSubProxy(subproxy_name);
if (sp)
{
return sp->GetProperty(property_name, 0);
}
// indicates that the internal dbase for exposed properties is
// corrupt.. when a subproxy was removed, the exposed properties
// for that proxy should also have been cleaned up.
// Flag an error so that it can be debugged.
vtkWarningMacro("Subproxy required for the exposed property is missing."
"No subproxy with name : " << subproxy_name);
}
return 0;
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveAllObservers()
{
vtkSMProxyInternals::PropertyInfoMap::iterator it;
for (it = this->Internals->Properties.begin();
it != this->Internals->Properties.end();
++it)
{
vtkSMProperty* prop = it->second.Property.GetPointer();
if (it->second.ObserverTag > 0)
{
prop->RemoveObserver(it->second.ObserverTag);
}
}
vtkSMProxyInternals::ProxyMap::iterator it2;
for (it2 = this->Internals->SubProxies.begin();
it2 != this->Internals->SubProxies.end();
++it2)
{
it2->second.GetPointer()->RemoveObserver(this->SubProxyObserver);
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::AddProperty(const char* name, vtkSMProperty* prop)
{
if (!prop)
{
return;
}
if (!name)
{
vtkErrorMacro("Can not add a property without a name.");
return;
}
// Check if the property already exists. If it does, we will
// replace it (and remove the observer from it)
vtkSMProxyInternals::PropertyInfoMap::iterator it =
this->Internals->Properties.find(name);
if (it != this->Internals->Properties.end())
{
vtkWarningMacro("Property " << name << " already exists. Replacing");
vtkSMProperty* oldProp = it->second.Property.GetPointer();
if (it->second.ObserverTag > 0)
{
oldProp->RemoveObserver(it->second.ObserverTag);
}
oldProp->SetParent(0);
}
unsigned int tag=0;
vtkSMProxyObserver* obs = vtkSMProxyObserver::New();
obs->SetProxy(this);
obs->SetPropertyName(name);
// We have to store the tag in order to be able to remove
// the observer later.
tag = prop->AddObserver(vtkCommand::ModifiedEvent, obs);
obs->Delete();
prop->SetParent(this);
vtkSMProxyInternals::PropertyInfo newEntry;
newEntry.Property = prop;
newEntry.ObserverTag = tag;
this->Internals->Properties[name] = newEntry;
// BUG: Hmm, if this replaces an existing property, are we ending up with that
// name being pushed in twice in the PropertyNamesInOrder list?
// => this vector is used by the OrderedProperty iterator which mean's
// that the iterator will go several time on the same property.
// Add the property name to the vector of property names.
// This vector keeps track of the order in which properties
// were added.
this->Internals->PropertyNamesInOrder.push_back(name);
}
//---------------------------------------------------------------------------
bool vtkSMProxy::UpdateProperty(const char* name, int force)
{
vtkSMProxyInternals::PropertyInfoMap::iterator it =
this->Internals->Properties.find(name);
if (it == this->Internals->Properties.end())
{
// Search exposed subproxy properties.
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator eiter =
this->Internals->ExposedProperties.find(name);
if (eiter == this->Internals->ExposedProperties.end())
{
return false;
}
const char* subproxy_name = eiter->second.SubProxyName.c_str();
const char* property_name = eiter->second.PropertyName.c_str();
vtkSMProxy * sp = this->GetSubProxy(subproxy_name);
if (sp && sp->UpdateProperty(property_name, force))
{
this->MarkModified(this);
return true;
}
return false;
}
if (!it->second.ModifiedFlag && !force)
{
return false;
}
if (it->second.Property->GetInformationOnly())
{
// cannot update information only properties.
return false;
}
this->CreateVTKObjects();
// In case this property is a self property and causes
// another UpdateVTKObjects(), make sure that it does
// not cause recursion. If this is not set, UpdateVTKObjects()
// that is caused by UpdateProperty() can end up calling trying
// to push the same property.
it->second.ModifiedFlag = 0;
vtkSMMessage message;
// Make sure the local state is updated as well
if(this->State)
{
vtkSMMessage oldState;
oldState.CopyFrom(*this->State);
this->State->ClearExtension(ProxyState::property);
int nbProps = oldState.ExtensionSize(ProxyState::property);
for(int cc=0; cc < nbProps; cc++)
{
const ProxyState_Property *oldProperty =
&oldState.GetExtension(ProxyState::property, cc);
if(oldProperty->name() == it->second.Property->GetXMLName())
{
it->second.Property->WriteTo(this->State);
}
else
{
ProxyState_Property *newProperty = this->State->AddExtension(ProxyState::property);
newProperty->CopyFrom(oldState.GetExtension(ProxyState::property, cc));
}
}
}
it->second.Property->WriteTo(&message);
this->PushState(&message);
// Fire event to let everyone know that a property has been updated.
this->InvokeEvent(vtkCommand::UpdatePropertyEvent,
const_cast<char*>(name));
this->MarkModified(this);
return true;
}
//---------------------------------------------------------------------------
void vtkSMProxy::SetPropertyModifiedFlag(const char* name, int flag)
{
if (this->DoNotModifyProperty)
{
return;
}
vtkSMProxyInternals::PropertyInfoMap::iterator it =
this->Internals->Properties.find(name);
if (it == this->Internals->Properties.end())
{
return;
}
this->InvokeEvent(vtkCommand::PropertyModifiedEvent, (void*)name);
vtkSMProperty* prop = it->second.Property.GetPointer();
if (prop->GetInformationOnly())
{
// Information only property is modified...nothing much to do.
return;
}
it->second.ModifiedFlag = flag;
if (flag && !this->DoNotUpdateImmediately && prop->GetImmediateUpdate())
{
this->UpdateProperty(it->first.c_str());
}
else
{
this->PropertiesModified = 1;
}
}
//-----------------------------------------------------------------------------
void vtkSMProxy::MarkAllPropertiesAsModified()
{
vtkSMProxyInternals::PropertyInfoMap::iterator it;
for (it = this->Internals->Properties.begin();
it != this->Internals->Properties.end(); it++)
{
// Not the most efficient way to set the flag, but probably the safest.
this->SetPropertyModifiedFlag(it->first.c_str(), 1);
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::ResetPropertiesToXMLDefaults()
{
this->ResetPropertiesToDefault(vtkSMProxy::ONLY_XML);
}
//---------------------------------------------------------------------------
void vtkSMProxy::ResetPropertiesToDomainDefaults()
{
this->ResetPropertiesToDefault(vtkSMProxy::ONLY_DOMAIN);
}
//---------------------------------------------------------------------------
void vtkSMProxy::ResetPropertiesToDefault(ResetPropertiesMode mode)
{
vtkSmartPointer<vtkSMPropertyIterator> iter;
iter.TakeReference(this->NewPropertyIterator());
// iterate over properties and reset them to default.
for (iter->Begin(); !iter->IsAtEnd(); iter->Next())
{
vtkSMProperty* smproperty = iter->GetProperty();
if (!smproperty->GetInformationOnly())
{
vtkPVXMLElement* propHints = iter->GetProperty()->GetHints();
if (propHints && propHints->FindNestedElementByName("NoDefault"))
{
// Don't reset properties that request overriding of the default mechanism.
continue;
}
switch(mode)
{
case vtkSMProxy::ONLY_XML:
{
iter->GetProperty()->ResetToXMLDefaults();
break;
}
case vtkSMProxy::ONLY_DOMAIN:
{
iter->GetProperty()->ResetToDomainDefaults();
break;
}
default:
{
iter->GetProperty()->ResetToDefault();
break;
}
}
}
}
this->UpdateVTKObjects();
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdatePropertyInformation(vtkSMProperty* prop)
{
// If property does not belong to this proxy do nothing.
int found = 0;
vtkSMProxyInternals::PropertyInfoMap::iterator it;
for (it = this->Internals->Properties.begin();
it != this->Internals->Properties.end();
++it)
{
if (prop == it->second.Property.GetPointer())
{
found = 1;
break;
}
}
if (!found)
{
// Check if the property is an exposed property
const char *exposed_name = this->GetPropertyName(prop);
if (exposed_name)
{
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator eiter =
this->Internals->ExposedProperties.find(exposed_name);
if (eiter != this->Internals->ExposedProperties.end())
{
const char* subproxy_name = eiter->second.SubProxyName.c_str();
const char* property_name = eiter->second.PropertyName.c_str();
vtkSMProxy * sp = this->GetSubProxy(subproxy_name);
if (sp)
{
sp->UpdatePropertyInformation(sp->GetProperty(property_name));
}
}
}
return;
}
this->UpdatePropertyInformationInternal(prop);
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdatePropertyInformation()
{
this->UpdatePropertyInformationInternal(NULL);
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->UpdatePropertyInformation();
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdatePropertyInformationInternal(
vtkSMProperty* single_property/*=NULL*/)
{
this->CreateVTKObjects();
// If no location, it means no state...
if (!this->ObjectsCreated || this->Location == 0)
{
return;
}
bool some_thing_to_fetch = false;
vtkSMMessage message;
Variant* var = message.AddExtension(PullRequest::arguments);
var->set_type(Variant::STRING);
vtkSMProxyInternals::PropertyInfoMap::iterator it;
if (single_property != NULL)
{
if (single_property->GetInformationOnly())
{
var->add_txt(single_property->GetXMLName());
some_thing_to_fetch = true;
}
}
else
{
// Update all information properties.
for (it = this->Internals->Properties.begin();
it != this->Internals->Properties.end(); ++it)
{
vtkSMProperty* prop = it->second.Property.GetPointer();
if (prop->GetInformationOnly())
{
var->add_txt(it->first.c_str());
some_thing_to_fetch = true;
}
}
}
if (!some_thing_to_fetch)
{
return;
}
// Hmm, this changes message itself. Funky.
this->PullState(&message);
// Update internal values
this->LoadState(&message, this->Session->GetProxyLocator());
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdateVTKObjects()
{
this->CreateVTKObjects();
if (!this->ObjectsCreated || this->InUpdateVTKObjects ||
!this->ArePropertiesModified() || this->Location == 0)
{
return;
}
if (this->PropertiesModified)
{
this->InUpdateVTKObjects = 1;
// Save previous property values and clear the State properties
vtkSMMessage oldState;
oldState.CopyFrom(*this->State);
this->State->ClearExtension(ProxyState::property);
// iterate over all properties and push modified ones.
vtkSMMessage message;
vtkSMProxyInternals::PropertyInfoMap::iterator iter;
int cc = 0;
for (iter = this->Internals->Properties.begin();
iter != this->Internals->Properties.end(); ++iter)
{
vtkSMProperty* property = iter->second.Property;
if (property && !property->GetInformationOnly())
{
if (property->GetIsInternal() || property->IsStateIgnored() ||
strcmp(property->GetClassName(), "vtkSMProperty") == 0)
{
// Push only modified properties
if (iter->second.ModifiedFlag)
{
// Write to message because vtkSMProperty do not have state
property->WriteTo(&message);
// the property is no longer dirty.
iter->second.ModifiedFlag = 0;
// Fire event to let everyone know that a property has been updated.
// This is currently used by vtkSMLink. Need to see if we can avoid this
// as firing these events ain't inexpensive.
this->InvokeEvent(vtkCommand::UpdatePropertyEvent,
const_cast<char*>(iter->first.c_str()));
}
}
else
{
// Push only modified properties
if(iter->second.ModifiedFlag)
{
// Write to state
property->WriteTo(this->State);
// the property is no longer dirty.
iter->second.ModifiedFlag = 0;
// Write to Push message
ProxyState_Property *prop = message.AddExtension(ProxyState::property);
prop->CopyFrom(this->State->GetExtension(ProxyState::property, cc));
// Fire event to let everyone know that a property has been updated.
// This is currently used by vtkSMLink. Need to see if we can avoid this
// as firing these events ain't inexpensive.
this->InvokeEvent(vtkCommand::UpdatePropertyEvent,
const_cast<char*>(iter->first.c_str()));
}
else
{
// Just copy the previous old value to the state
ProxyState_Property *prop = this->State->AddExtension(ProxyState::property);
prop->CopyFrom(oldState.GetExtension(ProxyState::property, cc));
}
// One more property
++cc;
}
}
}
this->InUpdateVTKObjects = 0;
this->PropertiesModified = false;
// Send the message
this->PushState(&message);
}
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for (; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->UpdateVTKObjects();
}
this->MarkModified(this);
this->InvokeEvent(vtkCommand::UpdateEvent, 0);
}
//---------------------------------------------------------------------------
bool vtkSMProxy::ArePropertiesModified()
{
if (this->PropertiesModified)
{
return true;
}
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
if (it2->second.GetPointer()->ArePropertiesModified())
{
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
void vtkSMProxy::CreateVTKObjects()
{
if (this->ObjectsCreated && this->State && this->Location == 0)
{
return;
}
this->WarnIfDeprecated();
assert( "Test Proxy definition"
&& this->GetClassName() && this->GetSIClassName()
&& this->GetXMLGroup() && this->GetXMLName() );
vtkSMMessage message;
message.SetExtension(DefinitionHeader::client_class, this->GetClassName());
message.SetExtension(DefinitionHeader::server_class, this->GetSIClassName());
message.SetExtension(ProxyState::xml_group, this->GetXMLGroup());
message.SetExtension(ProxyState::xml_name, this->GetXMLName());
if(this->XMLSubProxyName)
{
message.SetExtension(ProxyState::xml_sub_proxy_name, this->XMLSubProxyName);
}
// Create sub-proxies first.
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->CreateVTKObjects();
ProxyState_SubProxy *subproxy = message.AddExtension(ProxyState::subproxy);
subproxy->set_name(it2->first.c_str());
subproxy->set_global_id(it2->second.GetPointer()->GetGlobalID());
}
// Save to state
this->State->CopyFrom(message);
// Add Empty property into state to keep track of index later on
vtkSMProxyInternals::PropertyInfoMap::iterator iter;
for (iter = this->Internals->Properties.begin();
iter != this->Internals->Properties.end(); ++iter)
{
vtkSMProperty* property = iter->second.Property;
if (property && !property->GetInformationOnly())
{
if (property->GetIsInternal() || property->IsStateIgnored() ||
strcmp(property->GetClassName(), "vtkSMProperty") == 0)
{
// No state for vtkSMProperty
}
else
{
// Write empty property inside state
property->WriteTo(this->State);
}
}
}
// Even if the Proxy was marked as Created, we went so far to build correctly
// the state and this is the same case for prototype.
if(this->ObjectsCreated)
{
return;
}
this->ObjectsCreated = 1;
if(this->Location == 0)
{
return;
}
// Push the state
this->PushState(&message);
// Update assigned id/location while the push
this->State->set_global_id(this->GetGlobalID());
// Using the real location and not the filtered one allow us to store
// the correct location in full state that is used in Undo/Redo.
this->State->set_location(this->Location);
bool oldPushState = this->Internals->EnableAnnotationPush;
this->Internals->EnableAnnotationPush = false;
this->UpdateAndPushAnnotationState();
this->Internals->EnableAnnotationPush = oldPushState;
}
//---------------------------------------------------------------------------
bool vtkSMProxy::GatherInformation(vtkPVInformation* information)
{
assert(information);
if (this->GetSession() && this->Location != 0)
{
// ensure that the proxy is created.
this->CreateVTKObjects();
return this->GetSession()->GatherInformation(this->Location,
information, this->GetGlobalID());
}
return false;
}
//---------------------------------------------------------------------------
bool vtkSMProxy::GatherInformation(
vtkPVInformation* information, vtkTypeUInt32 location)
{
assert(information);
vtkTypeUInt32 realLocation = (this->Location & location);
if (this->GetSession() && realLocation != 0)
{
// ensure that the proxy is created.
this->CreateVTKObjects();
return this->GetSession()->GatherInformation(
realLocation, information, this->GetGlobalID());
}
if ((this->Location != 0) && (realLocation == 0) && (location != 0))
{
vtkWarningMacro("GatherInformation was called with location "
"on which the proxy does not exist. Ignoring.");
}
return false;
}
//---------------------------------------------------------------------------
bool vtkSMProxy::WarnIfDeprecated()
{
if (this->Deprecated)
{
vtkWarningMacro("Proxy (" << this->XMLGroup << ", " << this->XMLName
<< ") has been deprecated in ParaView " <<
this->Deprecated->GetAttribute("deprecated_in") <<
" and will be removed by ParaView " <<
this->Deprecated->GetAttribute("to_remove_in") << ". " <<
(this->Deprecated->GetCharacterData()?
this->Deprecated->GetCharacterData() : ""));
return true;
}
return false;
}
//---------------------------------------------------------------------------
unsigned int vtkSMProxy::GetNumberOfSubProxies()
{
return static_cast<unsigned int>(this->Internals->SubProxies.size());
}
//---------------------------------------------------------------------------
const char* vtkSMProxy::GetSubProxyName(unsigned int index)
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for(unsigned int idx = 0;
it2 != this->Internals->SubProxies.end();
it2++, idx++)
{
if (idx == index)
{
return it2->first.c_str();
}
}
return 0;
}
//---------------------------------------------------------------------------
const char* vtkSMProxy::GetSubProxyName(vtkSMProxy* proxy)
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for(;it2 != this->Internals->SubProxies.end(); it2++)
{
if (it2->second.GetPointer() == proxy)
{
return it2->first.c_str();
}
}
return 0;
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetSubProxy(unsigned int index)
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for(unsigned int idx = 0;
it2 != this->Internals->SubProxies.end();
it2++, idx++)
{
if (idx == index)
{
return it2->second.GetPointer();
}
}
return 0;
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetSubProxy(const char* name)
{
vtkSMProxyInternals::ProxyMap::iterator it =
this->Internals->SubProxies.find(name);
if (it == this->Internals->SubProxies.end())
{
return 0;
}
return it->second.GetPointer();
}
//---------------------------------------------------------------------------
bool vtkSMProxy::GetIsSubProxy()
{
return this->ParentProxy != NULL;
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetParentProxy()
{
return this->ParentProxy.GetPointer();
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetTrueParentProxy()
{
vtkSMProxy* self = this;
while (self->GetParentProxy())
{
self = self->GetParentProxy();
}
return self;
}
//---------------------------------------------------------------------------
void vtkSMProxy::AddSubProxy( const char* name, vtkSMProxy* proxy,
int override)
{
// Check if the proxy already exists. If it does, we will replace it
vtkSMProxyInternals::ProxyMap::iterator it =
this->Internals->SubProxies.find(name);
if (it != this->Internals->SubProxies.end())
{
if (!override)
{
vtkWarningMacro("Proxy " << name << " already exists. Replacing");
}
// needed to remove any observers.
this->RemoveSubProxy(name);
}
this->Internals->SubProxies[name] = proxy;
proxy->ParentProxy = this;
proxy->AddObserver(vtkCommand::PropertyModifiedEvent,this->SubProxyObserver);
proxy->AddObserver(vtkCommand::UpdatePropertyEvent, this->SubProxyObserver);
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveSubProxy(const char* name)
{
if (!name)
{
return;
}
vtkSMProxyInternals::ProxyMap::iterator it =
this->Internals->SubProxies.find(name);
vtkSmartPointer<vtkSMProxy> subProxy;
if (it != this->Internals->SubProxies.end())
{
subProxy = it->second; // we keep the proxy since we need it to remove links.
it->second.GetPointer()->RemoveObserver(this->SubProxyObserver);
// Note, we are assuming here that a proxy cannot be added
// twice as a subproxy to the same proxy.
this->Internals->SubProxies.erase(it);
}
// Now, remove any exposed properties for this subproxy.
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator iter =
this->Internals->ExposedProperties.begin();
while ( iter != this->Internals->ExposedProperties.end())
{
if (iter->second.SubProxyName == name)
{
this->Internals->ExposedProperties.erase(iter);
// start again.
iter = this->Internals->ExposedProperties.begin();
}
else
{
iter++;
}
}
if (subProxy.GetPointer())
{
subProxy->ParentProxy = NULL;
// Now, remove any shared property links for the subproxy.
vtkSMProxyInternals::SubProxyLinksType::iterator iter2 =
this->Internals->SubProxyLinks.begin();
while (iter2 != this->Internals->SubProxyLinks.end())
{
iter2->GetPointer()->RemoveLinkedProxy(subProxy.GetPointer());
if (iter2->GetPointer()->GetNumberOfLinkedProxies() <= 1)
{
// link is useless, remove it.
this->Internals->SubProxyLinks.erase(iter2);
iter2 = this->Internals->SubProxyLinks.begin();
}
else
{
iter2++;
}
}
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::ExecuteSubProxyEvent(vtkSMProxy* subproxy,
unsigned long event, void* data)
{
if (subproxy &&
(event == vtkCommand::PropertyModifiedEvent ||
event == vtkCommand::UpdatePropertyEvent))
{
// A Subproxy has been modified.
const char* name = reinterpret_cast<const char*>(data);
const char* exposed_name = 0;
if (name)
{
// Check if the property from the subproxy was exposed.
// If so, we invoke this event with the exposed name.
// First determine the name for this subproxy.
vtkSMProxyInternals::ProxyMap::iterator proxy_iter =
this->Internals->SubProxies.begin();
const char* subproxy_name = 0;
for (; proxy_iter != this->Internals->SubProxies.end(); ++proxy_iter)
{
if (proxy_iter->second.GetPointer() == subproxy)
{
subproxy_name = proxy_iter->first.c_str();
break;
}
}
if (subproxy_name)
{
// Now locate the exposed property name.
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator iter =
this->Internals->ExposedProperties.begin();
for (; iter != this->Internals->ExposedProperties.end(); ++iter)
{
if (iter->second.SubProxyName == subproxy_name &&
iter->second.PropertyName == name)
{
// This property is indeed exposed. Set the corrrect exposed name.
exposed_name = iter->first.c_str();
break;
}
}
}
}
if (event == vtkCommand::PropertyModifiedEvent)
{
// Let the world know that one of the subproxies of this proxy has
// been modified. If the subproxy exposed the modified property, we
// provide the name of the property. Otherwise, 0, indicating
// some internal property has changed.
this->InvokeEvent(vtkCommand::PropertyModifiedEvent, (void*)exposed_name);
}
else if (exposed_name && event == vtkCommand::UpdatePropertyEvent)
{
// UpdatePropertyEvent is fired only for exposed properties.
this->InvokeEvent(vtkCommand::UpdatePropertyEvent, (void*)exposed_name);
this->MarkModified(subproxy);
}
}
// Note we are not throwing vtkCommand::UpdateEvent fired by subproxies.
// Since doing so would imply that this proxy (as well as all its subproxies)
// are updated, which is not necessarily true when a subproxy fires
// an UpdateEvent.
}
//---------------------------------------------------------------------------
void vtkSMProxy::AddConsumer(vtkSMProperty* property, vtkSMProxy* proxy)
{
int found=0;
std::vector<vtkSMProxyInternals::ConnectionInfo>::iterator i =
this->Internals->Consumers.begin();
for(; i != this->Internals->Consumers.end(); i++)
{
if ( i->Property == property && i->Proxy == proxy )
{
found = 1;
break;
}
}
if (!found)
{
vtkSMProxyInternals::ConnectionInfo info(property, proxy);
this->Internals->Consumers.push_back(info);
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveConsumer(vtkSMProperty* property, vtkSMProxy*)
{
std::vector<vtkSMProxyInternals::ConnectionInfo>::iterator i =
this->Internals->Consumers.begin();
for(; i != this->Internals->Consumers.end(); i++)
{
if ( i->Property == property )
{
this->Internals->Consumers.erase(i);
break;
}
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveAllConsumers()
{
this->Internals->Consumers.erase(this->Internals->Consumers.begin(),
this->Internals->Consumers.end());
}
//---------------------------------------------------------------------------
unsigned int vtkSMProxy::GetNumberOfConsumers()
{
return static_cast<unsigned int>(this->Internals->Consumers.size());
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetConsumerProxy(unsigned int idx)
{
return this->Internals->Consumers[idx].Proxy;
}
//---------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::GetConsumerProperty(unsigned int idx)
{
return this->Internals->Consumers[idx].Property;
}
//---------------------------------------------------------------------------
void vtkSMProxy::AddProducer(vtkSMProperty* property, vtkSMProxy* proxy)
{
int found=0;
std::vector<vtkSMProxyInternals::ConnectionInfo>::iterator i =
this->Internals->Producers.begin();
for(; i != this->Internals->Producers.end(); i++)
{
if ( i->Property == property && i->Proxy == proxy )
{
found = 1;
break;
}
}
if (!found)
{
vtkSMProxyInternals::ConnectionInfo info(property, proxy);
this->Internals->Producers.push_back(info);
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveProducer(vtkSMProperty* property, vtkSMProxy* proxy)
{
std::vector<vtkSMProxyInternals::ConnectionInfo>::iterator i =
this->Internals->Producers.begin();
for(; i != this->Internals->Producers.end(); i++)
{
if ( i->Property == property && i->Proxy == proxy )
{
this->Internals->Producers.erase(i);
break;
}
}
}
//---------------------------------------------------------------------------
unsigned int vtkSMProxy::GetNumberOfProducers()
{
return static_cast<unsigned int>(this->Internals->Producers.size());
}
//---------------------------------------------------------------------------
vtkSMProxy* vtkSMProxy::GetProducerProxy(unsigned int idx)
{
return this->Internals->Producers[idx].Proxy;
}
//---------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::GetProducerProperty(unsigned int idx)
{
return this->Internals->Producers[idx].Property;
}
//----------------------------------------------------------------------------
void vtkSMProxy::PostUpdateData()
{
unsigned int numProducers = this->GetNumberOfProducers();
for (unsigned int i=0; i<numProducers; i++)
{
if (this->GetProducerProxy(i)->NeedsUpdate)
{
this->GetProducerProxy(i)->PostUpdateData();
}
}
if (this->NeedsUpdate)
{
// this->NeedsUpdate must be set to false before firing this event otherwise
// if the event handler results in other view updates, we end up
// unnecessarily thinking that this proxy needs update.
this->NeedsUpdate = false;
this->InvokeEvent(vtkCommand::UpdateDataEvent, 0);
}
}
//----------------------------------------------------------------------------
void vtkSMProxy::MarkModified(vtkSMProxy* modifiedProxy)
{
/*
* UpdatePropertyInformation() is now explicitly called in
* UpdatePipelineInformation(). The calling on UpdatePropertyInformation()
* was not really buying us much as far as keeping dependent domains updated
* was concerned, for unless UpdatePipelineInformation was called on the
* reader/filter, updating infor properties was not going to yeild any
* changed values. Removing this also allows for linking for info properties
* and properties using property links.
* A side effect of this may be that the 3DWidgets information properties wont get
* updated on setting "action" properties such as PlaceWidget.
if (this->ObjectsCreated)
{
// If not created yet, don't worry syncing the info properties.
this->UpdatePropertyInformation();
}
*/
if (!this->InMarkModified)
{
this->InMarkModified = 1;
this->InvokeEvent(vtkCommand::ModifiedEvent, (void*)modifiedProxy);
this->MarkDirty(modifiedProxy);
this->InMarkModified = 0;
}
}
//----------------------------------------------------------------------------
void vtkSMProxy::MarkDirty(vtkSMProxy* modifiedProxy)
{
if (this->NeedsUpdate)
{
return;
}
this->MarkConsumersAsDirty(modifiedProxy);
this->NeedsUpdate = true;
}
//----------------------------------------------------------------------------
void vtkSMProxy::MarkConsumersAsDirty(vtkSMProxy* modifiedProxy)
{
unsigned int numConsumers = this->GetNumberOfConsumers();
for (unsigned int i=0; i<numConsumers; i++)
{
vtkSMProxy* cons = this->GetConsumerProxy(i);
if (cons)
{
cons->MarkDirty(modifiedProxy);
}
}
}
//----------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::NewProperty(const char* name)
{
vtkSMProperty* property = this->GetProperty(name);
if (property)
{
return property;
}
vtkPVXMLElement* element = this->XMLElement;
if (!element)
{
return 0;
}
vtkPVXMLElement* propElement = 0;
for(unsigned int i=0; i < element->GetNumberOfNestedElements(); ++i)
{
propElement = element->GetNestedElement(i);
if (strcmp(propElement->GetName(), "SubProxy") != 0)
{
const char* pname = propElement->GetAttribute("name");
if (pname && strcmp(name, pname) == 0)
{
break;
}
}
propElement = 0;
}
if (!propElement)
{
return 0;
}
return this->NewProperty(name, propElement);
}
//----------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::NewProperty(const char* name,
vtkPVXMLElement* propElement)
{
vtkSMProperty* property = this->GetProperty(name);
if (property)
{
return property;
}
if (!propElement)
{
return 0;
}
// Patch XML to remove InformationHelper and set right si_class
vtkSIProxyDefinitionManager::PatchXMLProperty(propElement);
vtkObject* object = 0;
std::ostringstream cname;
cname << "vtkSM" << propElement->GetName() << ends;
object = vtkPVInstantiator::CreateInstance(cname.str().c_str());
property = vtkSMProperty::SafeDownCast(object);
if (property)
{
int old_val = this->DoNotUpdateImmediately;
int old_val2 = this->DoNotModifyProperty;
this->DoNotUpdateImmediately = 1;
// Internal properties should not be created as modified.
// Otherwise, properties like ForceUpdate get pushed and
// cause problems.
int is_internal;
if (property->GetIsInternal() || property->IsStateIgnored() ||
strcmp(property->GetClassName(), "vtkSMProperty") == 0)
{
this->DoNotModifyProperty = 1;
}
if (propElement->GetScalarAttribute("is_internal", &is_internal))
{
if (is_internal)
{
this->DoNotModifyProperty = 1;
}
}
this->AddProperty(name, property);
if (!property->ReadXMLAttributes(this, propElement))
{
vtkErrorMacro("Could not parse property: " << propElement->GetName());
this->DoNotUpdateImmediately = old_val;
return 0;
}
this->DoNotUpdateImmediately = old_val;
this->DoNotModifyProperty = old_val2;
// Properties should be created as modified unless they
// are internal.
// if (!property->GetIsInternal())
// {
// this->Internals->Properties[name].ModifiedFlag = 1;
// }
property->Delete();
}
else
{
vtkErrorMacro("Could not instantiate property: " << propElement->GetName());
}
return property;
}
//---------------------------------------------------------------------------
class vtkSMProxyPropertyLinkObserver : public vtkCommand
{
public:
vtkWeakPointer<vtkSMProperty> Output;
typedef vtkCommand Superclass;
virtual const char* GetClassNameInternal() const
{ return "vtkSMProxyPropertyLinkObserver"; }
static vtkSMProxyPropertyLinkObserver* New()
{
return new vtkSMProxyPropertyLinkObserver();
}
virtual void Execute(vtkObject* caller, unsigned long event, void* calldata)
{
(void)event;
(void)calldata;
vtkSMProperty* input = vtkSMProperty::SafeDownCast(caller);
if (input && this->Output)
{
// this will copy both checked and unchecked property values.
this->Output->Copy(input);
}
}
};
//---------------------------------------------------------------------------
void vtkSMProxy::LinkProperty(vtkSMProperty* input, vtkSMProperty* output)
{
if (input == output || input == NULL || output == NULL)
{
vtkErrorMacro("Invalid call to vtkSMProxy::LinkProperty. Check arguments.");
return;
}
vtkSMProxyPropertyLinkObserver* observer = vtkSMProxyPropertyLinkObserver::New();
observer->Output = output;
input->AddObserver(vtkCommand::PropertyModifiedEvent, observer);
input->AddObserver(vtkCommand::UncheckedPropertyModifiedEvent, observer);
observer->FastDelete();
}
//---------------------------------------------------------------------------
vtkSMPropertyGroup* vtkSMProxy::NewPropertyGroup(vtkPVXMLElement* groupElem)
{
vtkSMPropertyGroup *group = vtkSMPropertyGroup::New();
if (!group->ReadXMLAttributes(this, groupElem))
{
group->Delete();
return NULL;
}
// FIXME: should we use group-name as the "key" for the property groups?
this->Internals->PropertyGroups.push_back(group);
group->Delete();
return group;
}
//---------------------------------------------------------------------------
int vtkSMProxy::ReadXMLAttributes( vtkSMSessionProxyManager* pm,
vtkPVXMLElement* element)
{
this->SetXMLElement(element);
// Read the common attributes.
const char* className = element->GetAttribute("class");
if(className)
{
this->SetVTKClassName(className);
}
const char* kernelClass = element->GetAttribute("si_class");
if (kernelClass)
{
this->SetSIClassName(kernelClass);
}
const char* xmllabel = element->GetAttribute("label");
if (xmllabel)
{
this->SetXMLLabel(xmllabel);
}
else
{
this->SetXMLLabel(this->GetXMLName());
}
const char* processes = element->GetAttribute("processes");
if (processes)
{
vtkTypeUInt32 uiprocesses = 0;
std::string strprocesses = processes;
if (strprocesses.find("client") != std::string::npos)
{
uiprocesses |= vtkProcessModule::CLIENT;
}
if (strprocesses.find("renderserver") != std::string::npos)
{
uiprocesses |= vtkProcessModule::RENDER_SERVER;
}
if (strprocesses.find("dataserver") != std::string::npos)
{
uiprocesses |= vtkProcessModule::DATA_SERVER;
}
this->SetLocation(uiprocesses);
}
// Locate documentation.
for (unsigned int cc=0; cc < element->GetNumberOfNestedElements(); ++cc)
{
vtkPVXMLElement* subElem = element->GetNestedElement(cc);
if (strcmp(subElem->GetName(), "Documentation") == 0)
{
this->Documentation->SetDocumentationElement(subElem);
}
else if (strcmp(subElem->GetName(), "Hints") == 0)
{
this->SetHints(subElem);
}
else if (strcmp(subElem->GetName(), "Deprecated") == 0)
{
this->SetDeprecated(subElem);
}
}
// Create all properties
int old_value = this->DoNotModifyProperty; // FIXME COLLAB: Prevent sending default values
this->DoNotModifyProperty = 1; // FIXME COLLAB: Prevent sending default values
if (!this->CreateSubProxiesAndProperties(pm, element))
{
return 0;
}
this->DoNotModifyProperty = old_value; // FIXME COLLAB: Prevent sending default values
this->SetXMLElement(0);
return 1;
}
//---------------------------------------------------------------------------
int vtkSMProxy::CreateSubProxiesAndProperties(vtkSMSessionProxyManager* pm,
vtkPVXMLElement *element)
{
if (!element || !pm)
{
return 0;
}
// Just build once
static vtksys::RegularExpression END_WITH_PROPERTY(".*Property$");
for(unsigned int i=0; i < element->GetNumberOfNestedElements(); ++i)
{
vtkPVXMLElement* propElement = element->GetNestedElement(i);
if (strcmp(propElement->GetName(), "SubProxy") == 0)
{
vtkPVXMLElement* subElement = propElement->GetNestedElement(0);
if (subElement)
{
const char* name = subElement->GetAttribute("name");
const char* pname = subElement->GetAttribute("proxyname");
const char* gname = subElement->GetAttribute("proxygroup");
int override = 0;
if (!subElement->GetScalarAttribute("override", &override))
{
override = 0;
}
if (pname && !gname)
{
vtkErrorMacro("proxygroup not specified. Subproxy cannot be created.");
return 0;
}
if (gname && !pname)
{
vtkErrorMacro("proxyname not specified. Subproxy cannot be created.");
return 0;
}
if (name)
{
vtkSMProxy* subproxy = 0;
if (pname && gname)
{
subproxy = pm->NewProxy(gname, pname);
}
else
{
gname = this->XMLGroup;
pname = this->XMLName;
subproxy = pm->NewProxy(subElement, gname, pname, name);
}
if (!subproxy)
{
vtkErrorMacro( "Failed to create subproxy: "
<< (pname?pname:"(none"));
return 0;
}
// Here, we turn on DoNotModifyProperty to ensure that we don't mark
// the properties modified as we are processing them e.g. setting
// panel-visibilities, etc.
subproxy->DoNotModifyProperty = 1;
this->AddSubProxy(name, subproxy, override);
this->SetupSharedProperties(subproxy, propElement);
this->SetupExposedProperties(name, propElement);
subproxy->DoNotModifyProperty = 0;
subproxy->Delete();
}
}
}
else if ( END_WITH_PROPERTY.find(propElement->GetName()) &&
propElement->GetAttribute("name") )
{
// Make sure that attribute value won't get corrupted inside the comming call
std::string propName = propElement->GetAttribute("name");
this->NewProperty(propName.c_str(), propElement);
}
else if (strcmp(propElement->GetName(), "PropertyGroup") == 0)
{
// Create a property group.
this->NewPropertyGroup(propElement);
}
}
return 1;
}
//---------------------------------------------------------------------------
vtkSMProperty* vtkSMProxy::SetupExposedProperty(vtkPVXMLElement* propertyElement,
const char* subproxy_name)
{
const char* name = propertyElement->GetAttribute("name");
if (!name || !name[0])
{
vtkErrorMacro("Attribute name is required!");
return 0;
}
const char* exposed_name = propertyElement->GetAttribute("exposed_name");
if (!exposed_name)
{
// use the property name as the exposed name.
exposed_name = name;
}
int override = 0;
if (!propertyElement->GetScalarAttribute("override", &override))
{
override = 0;
}
if (propertyElement->GetAttribute("default_values"))
{
vtkSMProxy *subproxy = this->GetSubProxy(subproxy_name);
vtkSMProperty* prop = subproxy->GetProperty(name);
if (!prop)
{
vtkWarningMacro("Failed to locate property '" << name
<< "' on subproxy '" << subproxy_name << "'");
return 0;
}
const std::string propertyName(prop->GetXMLName());
if (!prop->ReadXMLAttributes(subproxy, propertyElement))
{
prop->SetXMLName(propertyName.c_str());
return 0;
}
prop->SetXMLName(propertyName.c_str());
// Since we are not processing ExposedProperties elements on the SIProxy
// side, the SIProxy doesn't have the information about updated defaults for
// the properties. Hence, we need to push those values in the next
// UpdateVTKObjects(). To ensure that, we have to mark this Property
// modified.
int old_val = subproxy->DoNotModifyProperty;
subproxy->DoNotModifyProperty = 0;
prop->Modified();
subproxy->DoNotModifyProperty = old_val;
}
this->ExposeSubProxyProperty(subproxy_name, name, exposed_name, override);
vtkSMProxy* subproxy = this->GetSubProxy(subproxy_name);
vtkSMProperty *prop = subproxy->GetProperty(name);
if (!prop)
{
vtkWarningMacro("Failed to locate property '" << name
<< "' on subproxy '" << subproxy_name << "': " << this->XMLName);
return 0;
}
// override panel_visibility with that of the exposed property
const char *panel_visibility = propertyElement->GetAttribute("panel_visibility");
if(panel_visibility)
{
prop->SetPanelVisibility(panel_visibility);
}
// override panel_visibility_default_for_representation with that of the exposed property
const char *panel_visibility_default_for_representation =
propertyElement->GetAttribute("panel_visibility_default_for_representation");
if(panel_visibility_default_for_representation)
{
prop->SetPanelVisibilityDefaultForRepresentation(
panel_visibility_default_for_representation);
}
// override panel_widget with that of the exposed property
const char *panel_widget = propertyElement->GetAttribute("panel_widget");
if(panel_widget)
{
prop->SetPanelWidget(panel_widget);
}
// override label with that of the exposed property
const char *label = propertyElement->GetAttribute("label");
if(label)
{
prop->SetXMLLabel(label);
}
return prop;
}
//---------------------------------------------------------------------------
void vtkSMProxy::SetupExposedProperties(const char* subproxy_name,
vtkPVXMLElement *element)
{
if (!subproxy_name || !element)
{
return;
}
unsigned int i,j;
for ( i = 0; i < element->GetNumberOfNestedElements(); i++)
{
vtkPVXMLElement* exposedElement = element->GetNestedElement(i);
if (!(strcmp(exposedElement->GetName(), "ExposedProperties") == 0 ||
strcmp(exposedElement->GetName(), "PropertyGroup") == 0))
{
continue;
}
for ( j = 0; j < exposedElement->GetNumberOfNestedElements(); j++)
{
vtkPVXMLElement* propertyElement = exposedElement->GetNestedElement(j);
if (strcmp(propertyElement->GetName(), "Property") == 0)
{
this->SetupExposedProperty(propertyElement, subproxy_name);
}
else if(strcmp(propertyElement->GetName(), "PropertyGroup") == 0)
{
// Process properties exposed under this element first.
vtkPVXMLElement *groupElement = propertyElement;
for (unsigned int k = 0; k < groupElement->GetNumberOfNestedElements(); k++)
{
vtkPVXMLElement* subElem = groupElement->GetNestedElement(k);
if (strcmp(subElem->GetName(), "Hints") == 0)
{
continue;
}
this->SetupExposedProperty(subElem, subproxy_name);
}
// Now create the group.
this->NewPropertyGroup(groupElement);
}
else
{
vtkErrorMacro("<ExposedProperties> can contain <Property> or <PropertyGroup> elements.");
continue;
}
}
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::SetupSharedProperties(vtkSMProxy* subproxy,
vtkPVXMLElement *element)
{
if (!subproxy || !element)
{
return;
}
for (unsigned int i=0; i < element->GetNumberOfNestedElements(); i++)
{
vtkPVXMLElement* propElement = element->GetNestedElement(i);
if (strcmp(propElement->GetName(), "ShareProperties")==0)
{
const char* name = propElement->GetAttribute("subproxy");
if (!name || !name[0])
{
continue;
}
vtkSMProxy* src_subproxy = this->GetSubProxy(name);
if (!src_subproxy)
{
vtkErrorMacro("Subproxy " << name << " must be defined before "
"its properties can be shared with another subproxy.");
continue;
}
vtkSMProxyLink* sharingLink = vtkSMProxyLink::New();
sharingLink->PropagateUpdateVTKObjectsOff();
// Read the exceptions.
for (unsigned int j=0; j < propElement->GetNumberOfNestedElements(); j++)
{
vtkPVXMLElement* exceptionProp = propElement->GetNestedElement(j);
if (strcmp(exceptionProp->GetName(), "Exception") != 0)
{
continue;
}
const char* exp_name = exceptionProp->GetAttribute("name");
if (!exp_name)
{
vtkErrorMacro("Exception tag must have the attribute 'name'.");
continue;
}
sharingLink->AddException(exp_name);
}
sharingLink->AddLinkedProxy(src_subproxy, vtkSMLink::INPUT);
sharingLink->AddLinkedProxy(subproxy, vtkSMLink::OUTPUT);
this->Internals->SubProxyLinks.push_back(sharingLink);
sharingLink->Delete();
}
}
}
//---------------------------------------------------------------------------
vtkSMPropertyIterator* vtkSMProxy::NewPropertyIterator()
{
vtkSMPropertyIterator* iter = vtkSMPropertyIterator::New();
iter->SetProxy(this);
return iter;
}
//---------------------------------------------------------------------------
void vtkSMProxy::Copy(vtkSMProxy* src)
{
this->Copy(src, 0,
vtkSMProxy::COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE);
}
//---------------------------------------------------------------------------
void vtkSMProxy::Copy(vtkSMProxy* src, const char* exceptionClass)
{
this->Copy(src, exceptionClass,
vtkSMProxy::COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE);
}
//---------------------------------------------------------------------------
void vtkSMProxy::Copy(vtkSMProxy* src, const char* exceptionClass,
int proxyPropertyCopyFlag)
{
if (!src)
{
return;
}
if (proxyPropertyCopyFlag != COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE)
{
vtkWarningMacro("COPY_PROXY_PROPERTY_VALUES_BY_CLONING is no longer supported."
" Using COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE instead.");
proxyPropertyCopyFlag = COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE;
}
vtkSMPropertyIterator* iter = this->NewPropertyIterator();
for(iter->Begin(); !iter->IsAtEnd(); iter->Next())
{
const char* key = iter->GetKey();
vtkSMProperty* dest = iter->GetProperty();
if (key && dest)
{
vtkSMProperty* source = src->GetProperty(key);
if (source)
{
if (!exceptionClass || !dest->IsA(exceptionClass))
{
vtkSMProxyProperty* pp = vtkSMProxyProperty::SafeDownCast(dest);
if (!pp || proxyPropertyCopyFlag ==
vtkSMProxy::COPY_PROXY_PROPERTY_VALUES_BY_REFERENCE)
{
dest->Copy(source);
}
}
}
}
}
iter->Delete();
}
//---------------------------------------------------------------------------
void vtkSMProxy::ExposeSubProxyProperty(const char* subproxy_name,
const char* property_name, const char* exposed_name,
int override)
{
if (!subproxy_name || !property_name || !exposed_name)
{
vtkErrorMacro("Either subproxy name, property name, or exposed name is NULL.");
return;
}
vtkSMProxyInternals::ExposedPropertyInfoMap::iterator iter =
this->Internals->ExposedProperties.find(exposed_name);
if (iter != this->Internals->ExposedProperties.end())
{
if (!override)
{
vtkWarningMacro("An exposed property with the name \"" << exposed_name
<< "\" already exists. It will be replaced.");
}
}
vtkSMProxyInternals::ExposedPropertyInfo info;
info.SubProxyName = subproxy_name;
info.PropertyName = property_name;
this->Internals->ExposedProperties[exposed_name] = info;
// Add the exposed property name to the vector of property names.
// This vector keeps track of the order in which properties
// were added.
this->Internals->PropertyNamesInOrder.push_back(exposed_name);
}
//---------------------------------------------------------------------------
void vtkSMProxy::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "VTKClassName: "
<< (this->VTKClassName ? this->VTKClassName : "(null)")
<< endl;
os << indent << "XMLName: "
<< (this->XMLName ? this->XMLName : "(null)")
<< endl;
os << indent << "XMLGroup: "
<< (this->XMLGroup ? this->XMLGroup : "(null)")
<< endl;
os << indent << "XMLLabel: "
<< (this->XMLLabel? this->XMLLabel : "(null)")
<< endl;
os << indent << "Documentation: " << this->Documentation << endl;
os << indent << "ObjectsCreated: " << this->ObjectsCreated << endl;
os << indent << "Hints: " ;
if (this->Hints)
{
this->Hints->PrintSelf(os, indent);
}
else
{
os << "(null)" << endl;
}
vtkSMPropertyIterator* iter = this->NewPropertyIterator();
if (iter)
{
for (iter->Begin(); !iter->IsAtEnd(); iter->Next())
{
const char* key = iter->GetKey();
vtkSMProperty* property = iter->GetProperty();
if (key)
{
os << indent << "Property (" << key << "): ";
if (property)
{
os << endl;
property->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << "(none)" << endl;
}
}
}
iter->Delete();
}
}
//---------------------------------------------------------------------------
vtkPVXMLElement* vtkSMProxy::SaveXMLState(vtkPVXMLElement* root)
{
vtkSMPropertyIterator *iter = this->NewPropertyIterator();
vtkPVXMLElement* result = this->SaveXMLState(root, iter);
iter->Delete();
return result;
}
//---------------------------------------------------------------------------
vtkPVXMLElement* vtkSMProxy::SaveXMLState(vtkPVXMLElement* root,
vtkSMPropertyIterator *iter)
{
if( iter == NULL)
{
return this->SaveXMLState(root);
}
vtkPVXMLElement *proxyXml = vtkPVXMLElement::New();
proxyXml->SetName("Proxy");
proxyXml->AddAttribute( "group", this->XMLGroup);
proxyXml->AddAttribute( "type", this->XMLName);
proxyXml->AddAttribute( "id",
static_cast<unsigned int>(this->GetGlobalID()));
proxyXml->AddAttribute( "servers",
static_cast<unsigned int>(this->GetLocation()));
for (iter->Begin(); !iter->IsAtEnd(); iter->Next())
{
if (!iter->GetProperty())
{
vtkWarningMacro("Missing property with name: " << iter->GetKey()
<< " on " << this->GetXMLName());
continue;
}
if (!iter->GetProperty()->GetIsInternal())
{
std::ostringstream propID;
propID << this->GetGlobalID() << "." << iter->GetKey() << ends;
iter->GetProperty()->SaveState( proxyXml,
iter->GetKey(),
propID.str().c_str());
}
}
// Add proxy annotation in XML state
vtkSMProxyInternals::AnnotationMap::iterator annotationIterator =
this->Internals->Annotations.begin();
while(annotationIterator != this->Internals->Annotations.end())
{
vtkNew<vtkPVXMLElement> annotation;
annotation->SetName("Annotation");
annotation->AddAttribute("key", annotationIterator->first.c_str());
annotation->AddAttribute("value", annotationIterator->second.c_str());
proxyXml->AddNestedElement(annotation.GetPointer());
// move forward
annotationIterator++;
}
if (root)
{
root->AddNestedElement(proxyXml);
proxyXml->FastDelete();
}
return proxyXml;
}
//---------------------------------------------------------------------------
int vtkSMProxy::LoadXMLState( vtkPVXMLElement* proxyElement,
vtkSMProxyLocator* locator)
{
unsigned int numElems = proxyElement->GetNumberOfNestedElements();
for (unsigned int i=0; i<numElems; i++)
{
vtkPVXMLElement* currentElement = proxyElement->GetNestedElement(i);
const char* name = currentElement->GetName();
if (!name)
{
continue;
}
if (strcmp(name, "Property") == 0)
{
const char* prop_name = currentElement->GetAttribute("name");
if (!prop_name)
{
vtkErrorMacro("Cannot load property without a name.");
continue;
}
vtkSMProperty* property = this->GetProperty(prop_name);
if (!property)
{
vtkDebugMacro("Property " << prop_name<< " does not exist.");
continue;
}
if (property->GetInformationOnly())
{
// don't load state for information only property.
continue;
}
if (!property->LoadState(currentElement, locator))
{
return 0;
}
}
if (strcmp(name, "Annotation") == 0)
{
this->SetAnnotation( currentElement->GetAttribute("key"),
currentElement->GetAttribute("value"));
}
}
return 1;
}
//---------------------------------------------------------------------------
const vtkSMMessage* vtkSMProxy::GetFullState()
{
return this->State;
}
//---------------------------------------------------------------------------
void vtkSMProxy::LoadState( const vtkSMMessage* message,
vtkSMProxyLocator* locator )
{
// Update globalId. This will fails if that one is already set with a different value
if(this->HasGlobalID() && this->GetGlobalID() != message->global_id())
{
vtkErrorMacro("Try to load a state on a proxy which has a different ID" <<
"(" << this->GetGlobalID() << " != " << message->global_id() << ")");
}
else
{
this->SetGlobalID(message->global_id());
}
// We try to extract some message informations that we might not get from
// proxy definition in the XML. This is specially true in collaboration.
if(message->HasExtension(DefinitionHeader::server_class))
{
this->SetSIClassName(message->GetExtension(DefinitionHeader::server_class).c_str());
}
if(message->HasExtension(ProxyState::xml_group))
{
this->SetXMLGroup(message->GetExtension(ProxyState::xml_group).c_str());
}
if(message->HasExtension(ProxyState::xml_name))
{
this->SetXMLName(message->GetExtension(ProxyState::xml_name).c_str());
}
if(message->HasExtension(ProxyState::xml_sub_proxy_name))
{
this->SetXMLSubProxyName(message->GetExtension(ProxyState::xml_sub_proxy_name).c_str());
}
// Manage its sub-proxy state
int nbSubProxy = message->ExtensionSize(ProxyState::subproxy);
std::vector<vtkSMMessage> subProxyStateToLoad;
for(int idx=0; idx < nbSubProxy; idx++)
{
const ProxyState_SubProxy *subProxyMsg =
&message->GetExtension(ProxyState::subproxy, idx);
vtkSMProxy* subProxy = this->GetSubProxy(subProxyMsg->name().c_str());
if(subProxy == NULL)
{
vtkWarningMacro("State provide a sub-proxy information althoug the proxy"
<< "does not find that sub-proxy."
<< " - Proxy: "
<< this->XMLGroup << " - " << this->XMLName << endl
<< " - Sub-Proxy: " << subProxyMsg->name().c_str()
<< " " << subProxyMsg->global_id());
continue;
}
// Make sure we do not try to load a state to a proxy that has already
// sub-proxy with IDs that differ from the message state
if(subProxy->HasGlobalID() &&
(subProxy->GlobalID != subProxyMsg->global_id() ||
!this->Session->GetRemoteObject(subProxyMsg->global_id())))
{
vtkErrorMacro("Invalid Proxy for message " << endl
<< "Parent Proxy : (" << this->XMLGroup << "," << this->XMLName << ")" << endl
<< "SubProxy - XMLName: " << subProxy->GetXMLName()
<< " - SubProxyName: " << subProxyMsg->name().c_str()
<< " - Id: " << subProxy->GlobalID << endl
<< message->DebugString().c_str() << endl);
}
// Update sub-proxy state if possible
if(!subProxy->HasGlobalID())
{
vtkSMMessage subProxyState;
subProxy->SetGlobalID(subProxyMsg->global_id());
if(this->GetSession()->GetStateLocator()->FindState(
subProxy->GetGlobalID(), &subProxyState))
{
subProxyStateToLoad.push_back(subProxyState);
}
}
}
// Load deferred sub-proxy state
// Deferring sub-proxy loading IS VERY IMPORTANT, specialy for compound proxy
// that define pipeline connectivity.
// If not done while loading the pipeline connection, this will failed because
// the sub-proxy involved might not have a GlobalID yet !
for(size_t i = 0; i < subProxyStateToLoad.size(); i++)
{
vtkSMProxy* proxy =
vtkSMProxy::SafeDownCast(
this->Session->GetRemoteObject(subProxyStateToLoad[i].global_id()));
proxy->LoadState(&subProxyStateToLoad[i], locator);
}
// Manage properties
vtkSMProxyInternals::PropertyInfoMap::iterator it;
for (int i=0; i < message->ExtensionSize(ProxyState::property); ++i)
{
const ProxyState_Property *prop_message =
&message->GetExtension(ProxyState::property, i);
const char* pname = prop_message->name().c_str();
it = this->Internals->Properties.find(pname);
if (it != this->Internals->Properties.end())
{
if (it->second.Property->GetIsInternal())
{
// skip internal properties. Their state is never updated.
continue;
}
// Some view properties need some special treatment and some
// of there properties MUST NOT be updated in case of collaborative
// notification.
if( this->Session->IsProcessingRemoteNotification() &&
it->second.Property->GetIgnoreSynchronization() )
{
continue;
}
it->second.Property->ReadFrom(message, i, locator);
}
}
// We don't need to do anything special to update domains that may have
// changed as a consequence of the information properties being updated since
// the vtkSMProperty automatically called vtkSMProperty::UpdateDomains() when
// the property changes.
// Manage annotation
if(message->GetExtension(ProxyState::has_annotation))
{
int nbAnnotation = message->ExtensionSize(ProxyState::annotation);
bool previousAnnotationPush = this->Internals->EnableAnnotationPush;
this->RemoveAllAnnotations();
for(int idx=0; idx < nbAnnotation; idx++)
{
const ProxyState_Annotation *annotation =
&message->GetExtension(ProxyState::annotation, idx);
this->SetAnnotation(annotation->key().c_str(), annotation->value().c_str());
}
this->Internals->EnableAnnotationPush = previousAnnotationPush;
}
}
//---------------------------------------------------------------------------
vtkSMPropertyGroup* vtkSMProxy::GetPropertyGroup(size_t index) const
{
assert(index < this->Internals->PropertyGroups.size());
return this->Internals->PropertyGroups[index];
}
//---------------------------------------------------------------------------
size_t vtkSMProxy::GetNumberOfPropertyGroups() const
{
return this->Internals->PropertyGroups.size();
}
//---------------------------------------------------------------------------
void vtkSMProxy::PrototypeOn()
{
this->SetPrototype(true);
}
//---------------------------------------------------------------------------
void vtkSMProxy::PrototypeOff()
{
this->SetPrototype(false);
}
//---------------------------------------------------------------------------
void vtkSMProxy::SetPrototype(bool proto)
{
this->Superclass::SetPrototype(proto);
for(unsigned int cc=0; cc < this->GetNumberOfSubProxies(); cc++)
{
this->GetSubProxy(cc)->SetPrototype(proto);
}
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdateSelfAndAllInputs()
{
vtkSMPropertyIterator* iter = this->NewPropertyIterator();
while (!iter->IsAtEnd())
{
iter->GetProperty()->UpdateAllInputs();
iter->Next();
}
iter->Delete();
this->UpdateVTKObjects();
}
//---------------------------------------------------------------------------
void vtkSMProxy::InitializeAndCopyFromProxy(vtkSMProxy* fromP)
{
if (this->ObjectsCreated)
{
vtkWarningMacro("Cannot Initialize since proxy already created.");
return;
}
if (this->GetSession() != fromP->GetSession())
{
vtkErrorMacro("Proxies on different sessions.");
return;
}
fromP->CreateVTKObjects();
this->SetLocation(fromP->GetLocation());
this->UpdateVTKObjects();
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< SIPROXY(this)
<< "SetVTKObject"
<< VTKOBJECT(fromP)
<< vtkClientServerStream::End;
this->ExecuteStream(stream);
}
//---------------------------------------------------------------------------
void vtkSMProxy::ExecuteStream(const vtkClientServerStream& stream,
bool ignore_errors/*=false*/, vtkTypeUInt32 location/*=0*/)
{
if (location == 0)
{
location = this->Location;
}
if (location == 0 || stream.GetNumberOfMessages() == 0)
{
return;
}
if (this->GetSession())
{
this->GetSession()->ExecuteStream(location, stream, ignore_errors);
}
// if no session, nothing to do.
}
//---------------------------------------------------------------------------
const vtkClientServerStream& vtkSMProxy::GetLastResult()
{
return this->GetLastResult(this->Location);
}
//---------------------------------------------------------------------------
const vtkClientServerStream& vtkSMProxy::GetLastResult(vtkTypeUInt32 location)
{
return this->Session->GetLastResult(location);
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdatePipelineInformation()
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->UpdatePipelineInformation();
}
this->UpdatePropertyInformation();
}
//---------------------------------------------------------------------------
void vtkSMProxy::EnableLocalPushOnly()
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->EnableLocalPushOnly();
}
this->Superclass::EnableLocalPushOnly();
}
//---------------------------------------------------------------------------
void vtkSMProxy::DisableLocalPushOnly()
{
vtkSMProxyInternals::ProxyMap::iterator it2 =
this->Internals->SubProxies.begin();
for( ; it2 != this->Internals->SubProxies.end(); it2++)
{
it2->second.GetPointer()->DisableLocalPushOnly();
}
this->Superclass::DisableLocalPushOnly();
}
//---------------------------------------------------------------------------
vtkClientServerStream& operator<< (vtkClientServerStream& stream,
const VTKOBJECT& manipulator)
{
vtkClientServerStream substream;
substream << vtkClientServerStream::Invoke
<< vtkClientServerID(1) // ID for the vtkSMSessionCore helper.
<< "GetVTKObject"
<< manipulator.Reference->GetGlobalID()
<< vtkClientServerStream::End;
stream << substream;
return stream;
}
//---------------------------------------------------------------------------
// Annotation management
//---------------------------------------------------------------------------
void vtkSMProxy::SetAnnotation(const char* key, const char* value)
{
assert("We expect a valid key for proxy annotation." && key);
if(value)
{
this->Internals->Annotations[key] = value;
this->UpdateAndPushAnnotationState();
}
else
{
this->RemoveAnnotation(key);
}
}
//---------------------------------------------------------------------------
const char* vtkSMProxy::GetAnnotation(const char* key)
{
vtkSMProxyInternals::AnnotationMap::iterator iter =
this->Internals->Annotations.find(key);
if(iter != this->Internals->Annotations.end())
{
return iter->second.c_str();
}
return NULL;
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveAnnotation(const char* key)
{
this->Internals->Annotations.erase(key);
this->UpdateAndPushAnnotationState();
}
//---------------------------------------------------------------------------
void vtkSMProxy::RemoveAllAnnotations()
{
this->Internals->Annotations.clear();
this->UpdateAndPushAnnotationState();
}
//---------------------------------------------------------------------------
bool vtkSMProxy::HasAnnotation(const char* key)
{
return ( this->Internals->Annotations.find(key) !=
this->Internals->Annotations.end() );
}
//---------------------------------------------------------------------------
int vtkSMProxy::GetNumberOfAnnotations()
{
return static_cast<int>(this->Internals->Annotations.size());
}
//---------------------------------------------------------------------------
const char* vtkSMProxy::GetAnnotationKeyAt(int index)
{
vtkSMProxyInternals::AnnotationMap::iterator iter =
this->Internals->Annotations.begin();
int searchIndex = 0;
while(searchIndex < index && iter != this->Internals->Annotations.end())
{
iter++;
searchIndex++;
}
if(searchIndex == index && iter != this->Internals->Annotations.end())
{
return iter->first.c_str();
}
return NULL;
}
//---------------------------------------------------------------------------
void vtkSMProxy::UpdateAndPushAnnotationState()
{
if (!this->ObjectsCreated)
{
return;
}
// Update state
vtkSMMessage localAnnotationState;
localAnnotationState.SetExtension(ProxyState::has_annotation, true);
this->State->ClearExtension(ProxyState::annotation);
this->State->SetExtension(ProxyState::has_annotation, true);
vtkSMProxyInternals::AnnotationMap::iterator iter =
this->Internals->Annotations.begin();
ProxyState_Annotation* annotation = NULL;
while(iter != this->Internals->Annotations.end())
{
// Add in full state
annotation = this->State->AddExtension(ProxyState::annotation);
annotation->set_key(iter->first);
annotation->set_value(iter->second);
// Add in local tmp state
annotation = localAnnotationState.AddExtension(ProxyState::annotation);
annotation->set_key(iter->first);
annotation->set_value(iter->second);
// move forward
iter++;
}
// Push annotation state to the session
if(this->Internals->EnableAnnotationPush)
{
this->PushState(&localAnnotationState);
}
}