mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
2542 lines
76 KiB
C++
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);
|
|
}
|
|
}
|