Salome HOME
Merge from BR_PARAVIS_DEV 29Dec09
[modules/paravis.git] / src / PVGUI / PVGUI_Trace.cxx
1 #include "PVGUI_Trace.h"
2 #include "PVGUI_Module.h"
3
4 #include <vtkSMPythonTraceObserver.h>
5 #include <vtkSMSourceProxy.h>
6 #include <vtkSMViewProxy.h>
7 #include <vtkSMProxy.h>
8 #include <vtkSMProperty.h>
9 #include <vtkSMProxyProperty.h>
10 #include <vtkSMProxyIterator.h>
11 #include <pqServer.h>
12 #include <vtkSMProxyManager.h>
13 #include <vtkSMDomain.h>
14 #include <vtkSMProxyListDomain.h>
15 #include <vtkSMProxyGroupDomain.h>
16 #include <vtkSMPropertyIterator.h>
17 #include <vtkCallbackCommand.h>
18 #include <vtkSMStringVectorProperty.h>
19 #include <vtkSMIntVectorProperty.h>
20 #include <vtkSMIdTypeVectorProperty.h>
21 #include <vtkSMDoubleVectorProperty.h>
22 #include <vtkSMEnumerationDomain.h>
23 #include <vtkSMDomainIterator.h>
24 #include <vtkSMInputProperty.h>
25
26 #include <QFile>
27 #include <QTextStream>
28
29 extern PVGUI_Module* ParavisModule;
30
31 static trace_globals globals;
32 static bool myInitialised = false;
33
34
35 //********************************************************************
36 QString pyvariable_from_proxy_name(const QString& proxy_name)
37 {
38   QString aName = proxy_name;
39   return make_name_valid(aName.replace(".", "_"));
40 }
41
42 //********************************************************************
43 proxy_trace_info::proxy_trace_info(vtkSMProxy* proxy, 
44                                    const QString& proxyGroup, 
45                                    const QString& proxyName) 
46 {
47   Proxy = proxy;
48   Group = proxyGroup;
49   ProxyName = proxyName;
50   PyVariable = pyvariable_from_proxy_name(proxyName);
51   ignore_next_unregister = false;
52 }
53   
54 //********************************************************************
55 prop_trace_info::prop_trace_info(const proxy_trace_info_ptr proxyTraceInfo, vtkSMProperty* prop) 
56 {
57   Prop = prop;
58   // Determine python variable name
59   PyVariable = prop->GetXMLLabel();
60   // For non-self properties, use the xml name instead of xml label:
61   if (prop->GetParent() != proxyTraceInfo->Proxy)
62     PyVariable = proxyTraceInfo->Proxy->GetPropertyName(prop);
63   PyVariable = make_name_valid(PyVariable);
64 }
65
66
67 //********************************************************************
68 QString make_name_valid(const QString& theName)
69 {
70   QString name = theName;
71   if (name.isNull())
72     return QString("");
73   if ((name.indexOf('(') >= 0) || (name.indexOf(')') >=0))
74     return QString("");
75   name = name.replace(" ","");
76   name = name.replace("-","");
77   name = name.replace(":","");
78   name = name.replace(".","");
79   if (!name.at(0).isLetter())
80     name = "a" + name;
81   return name;
82 }
83
84 //********************************************************************
85 vtkSMPythonTraceObserver* trace_observer()
86 {
87   return globals.observer;
88 }
89
90 //********************************************************************
91 QStringList ignoredViewProperties()
92 {
93   return globals.ignored_view_properties;
94 }
95
96 //********************************************************************
97 QStringList ignoredRepresentationProperties()
98 {
99   return globals.ignored_representation_properties;
100 }
101
102 //********************************************************************
103 bool propIsIgnored(const proxy_trace_info_ptr info, const QString& propName)
104 {
105   QStringList aIgnoredList = ignoredViewProperties();
106   if ((info->Group == "views") && (aIgnoredList.contains(propName))) 
107     return true;
108   aIgnoredList = ignoredRepresentationProperties();
109   if ((info->Group == "representations") && (aIgnoredList.contains(propName)))
110     return true;
111   return false;
112 }
113
114 //********************************************************************
115 bool operator < (const QStringList& list1, const QStringList& list2) {
116   QString s1 = list1.join(":");
117   QString s2 = list2.join(":");
118   return (s1 < s2);
119 }
120
121 //********************************************************************
122 void GetProxiesInGroup(const char* theName, QMap<QStringList,vtkSMProxy*>& proxies) 
123 {
124   pqServer* aServer = ParavisModule->getActiveServer();
125
126   vtkSMProxyIterator* aIt = vtkSMProxyIterator::New();
127   aIt->SetConnectionID(aServer->GetConnectionID());
128   aIt->SetModeToOneGroup();
129   for (aIt->Begin(theName); !aIt->IsAtEnd(); aIt->Next()) {
130     vtkSMProxy* aProxy = aIt->GetProxy();
131     QStringList aKey;
132     aKey << aIt->GetKey() << aProxy->GetSelfIDAsString();
133     proxies[aKey] = aProxy;
134   }
135   aIt->Delete();
136 }
137
138 //********************************************************************
139 void track_existing_sources()
140 {
141   QMap<QStringList, vtkSMProxy*> existing_sources;
142   GetProxiesInGroup("sources", existing_sources);
143
144   QMap<QStringList, vtkSMProxy*>::const_iterator aIt;
145   for (aIt = existing_sources.constBegin(); aIt!=existing_sources.constEnd(); ++aIt) {
146     QStringList aKey = aIt.key();
147     vtkSMProxy* aProxy = aIt.value();
148     track_existing_source_proxy(aProxy, "");
149   }
150 }
151
152 //********************************************************************
153 proxy_trace_info_ptr track_existing_source_proxy(vtkSMProxy* proxy, const QString& proxy_name)
154 {
155   proxy_trace_info_ptr proxy_info(new proxy_trace_info(proxy, "sources", proxy_name));
156   globals.registered_proxies.append(proxy_info);
157   if ((!globals.last_active_source) && (proxy == globals.active_source_at_start)) {
158     globals.last_active_source = proxy;
159     globals.trace_output.append(QString("%1 = GetActiveSource()").arg(proxy_info->PyVariable));
160   } else {
161     globals.trace_output.append(QString("%1 = FindSource(\"%2\")").arg(proxy_info->PyVariable).arg(proxy_name));
162   }
163   return proxy_info;
164 }
165
166 //********************************************************************
167 QList<vtkSMProxy*> GetRenderViews() 
168 {
169   QList<vtkSMProxy*> render_modules;
170
171   pqServer* aServer = ParavisModule->getActiveServer();
172
173   vtkSMProxyIterator* aIt = vtkSMProxyIterator::New();
174   aIt->SetConnectionID(aServer->GetConnectionID());
175   for (aIt->Begin(); !aIt->IsAtEnd(); aIt->Next()) {
176     vtkSMProxy* aProxy = aIt->GetProxy();
177     if (aProxy->IsA("vtkSMRenderViewProxy"))
178       render_modules.append(aProxy);
179   }
180   aIt->Delete();
181   return render_modules;
182 }
183
184 //********************************************************************
185 proxy_trace_info_ptr track_existing_view_proxy(vtkSMProxy* proxy, const QString& proxy_name)
186 {
187   proxy_trace_info_ptr proxy_info(new proxy_trace_info(proxy, "views", proxy_name));
188   globals.registered_proxies.append(proxy_info);
189   if ((!globals.last_active_view) && (proxy == globals.active_view_at_start)) {
190     globals.last_active_view = proxy;
191     globals.trace_output.append(QString("%1 = GetRenderView()").arg(proxy_info->PyVariable));
192   } else {
193     QList<vtkSMProxy*> all_views = GetRenderViews();
194     if (all_views.contains(proxy)) {
195       int view_index = all_views.indexOf(proxy);
196       if (view_index != -1)
197         globals.trace_output.append(QString("%1 = GetRenderViews()[%2]").arg(proxy_info->PyVariable).arg(view_index));
198     }
199   }
200   return proxy_info;
201 }
202
203 //********************************************************************
204 proxy_trace_info_ptr track_existing_representation_proxy(vtkSMProxy* proxy, 
205                                                          const QString& proxy_name)
206 {
207   vtkSMProxyProperty* input_property = dynamic_cast<vtkSMProxyProperty*>(proxy->GetProperty("Input"));
208   if (!input_property) return proxy_trace_info_ptr();
209   
210   if (input_property->GetNumberOfProxies() > 0) {
211     vtkSMProxy* input_proxy = input_property->GetProxy(0);
212     proxy_trace_info_ptr input_proxy_info = get_proxy_info(input_proxy);
213     if (input_proxy_info.get()) {
214       proxy_trace_info_ptr proxy_info(new proxy_trace_info(proxy, "representations", proxy_name));
215       globals.registered_proxies.append(proxy_info);
216       globals.trace_output.append(QString("%1 = GetDisplayProperties(%2)").arg(proxy_info->PyVariable).arg(input_proxy_info->PyVariable));
217       return proxy_info;
218     }
219   }
220   return proxy_trace_info_ptr();
221 }
222
223 //********************************************************************
224 proxy_trace_info_ptr track_existing_proxy(vtkSMProxy* proxy)
225 {
226   QString proxy_name = get_source_proxy_registration_name(proxy);
227   if (!proxy_name.isNull())
228     return track_existing_source_proxy(proxy, proxy_name);
229
230   proxy_name = get_representation_proxy_registration_name(proxy);
231   if (!proxy_name.isNull())
232     return track_existing_representation_proxy(proxy, proxy_name);
233
234   proxy_name = get_view_proxy_registration_name(proxy);
235   if (!proxy_name.isNull())
236     return track_existing_view_proxy(proxy, proxy_name);
237   return proxy_trace_info_ptr();
238 }
239
240 //********************************************************************
241 proxy_trace_info_ptr get_proxy_info(const QString& p, bool search_existing)
242 {
243   foreach(proxy_trace_info_ptr info, globals.last_registered_proxies) {
244     if (info->PyVariable == p) return info;
245   }
246   foreach(proxy_trace_info_ptr info, globals.registered_proxies) {
247     if (info->PyVariable == p) return info;
248   }
249
250   if(search_existing) return proxy_trace_info_ptr();
251
252   return proxy_trace_info_ptr();
253 }
254
255 //********************************************************************
256 proxy_trace_info_ptr get_proxy_info(vtkSMProxy* p, bool search_existing)
257 {
258   foreach(proxy_trace_info_ptr info, globals.last_registered_proxies) {
259     if (info->Proxy == p) return info;
260   }
261   foreach(proxy_trace_info_ptr info, globals.registered_proxies) {
262     if (info->Proxy == p) return info;
263   }
264   // It must be a proxy that existed before trace started
265   if (search_existing) return track_existing_proxy(p);
266
267   return proxy_trace_info_ptr();
268 }
269
270 //********************************************************************
271 void ensure_active_source(const proxy_trace_info_ptr proxy_info)
272 {
273   if (proxy_info && (proxy_info->Proxy != globals.last_active_source)) {
274     globals.trace_output.append(QString("SetActiveSource(%1)").arg(proxy_info->PyVariable));
275     globals.last_active_source = proxy_info->Proxy;
276   }
277 }
278
279 //********************************************************************
280 void ensure_active_view(const proxy_trace_info_ptr proxy_info)
281 {
282   if (proxy_info && (proxy_info->Proxy != globals.last_active_view)) {
283     globals.trace_output.append(QString("SetActiveView(%1)").arg(proxy_info->PyVariable));
284     globals.last_active_view = proxy_info->Proxy;
285   }
286 }
287
288 //********************************************************************
289 proxy_trace_info_ptr get_input_proxy_info_for_rep(const proxy_trace_info_ptr rep_info)
290 {
291   if (rep_info->CurrentProps.contains("Input")) {
292     QString input_proxy_pyvariable = rep_info->CurrentProps["Input"];
293     return get_proxy_info(input_proxy_pyvariable);
294   }
295   return proxy_trace_info_ptr();
296 }
297  
298 //********************************************************************
299 proxy_trace_info_ptr get_view_proxy_info_for_rep(const proxy_trace_info_ptr rep_info)
300 {
301   QList<proxy_trace_info_ptr> aTmpList;
302   aTmpList.append(globals.registered_proxies);
303   aTmpList.append(globals.last_registered_proxies);
304   foreach (proxy_trace_info_ptr p, aTmpList) {
305     // If the proxy is a view, check for rep_info.Proxy in the
306     // view's 'Representation' property
307     if (p->Group == "views") {
308       vtkSMProxyProperty* rep_prop = 
309         dynamic_cast<vtkSMProxyProperty*>(p->Proxy->GetProperty("Representations"));
310       if (rep_prop) {
311         for (int i = 0; i < rep_prop->GetNumberOfProxies(); i++) {
312           if (rep_info->Proxy == rep_prop->GetProxy(i)) 
313             return p;
314         }
315       }
316     }
317   }
318   return proxy_trace_info_ptr();
319 }
320
321 //********************************************************************
322 QString get_source_proxy_registration_name(vtkSMProxy* proxy)
323 {
324   return vtkSMObject::GetProxyManager()->GetProxyName("sources", proxy);
325 }
326
327 //********************************************************************
328 QString get_view_proxy_registration_name(vtkSMProxy* proxy)
329 {
330   return vtkSMObject::GetProxyManager()->GetProxyName("views", proxy);
331 }
332
333 //********************************************************************
334 QString get_representation_proxy_registration_name(vtkSMProxy* proxy)
335 {
336   return vtkSMObject::GetProxyManager()->GetProxyName("representations", proxy);
337 }
338
339 //********************************************************************
340 QString make_comma_separated_string(QStringList values)
341 {
342   QString ret=values.join(", ");
343   if(ret!="")
344     ret = QString(" %1 ").arg(ret);
345   return ret;
346 }
347
348 QStringList wrap_property(vtkSMProxy* proxy, vtkSMProperty* smproperty)
349 {
350   QStringList propertyList;
351   if(smproperty->IsA("vtkSMVectorProperty")) {
352     vtkSMVectorProperty* property = dynamic_cast<vtkSMVectorProperty*>(smproperty);
353     int nElem = property->GetNumberOfElements();
354     int di = 1;
355     vtkSMDomain* dom = NULL;
356     if(property->IsA("vtkSMStringVectorProperty")) {
357       dom = property->GetDomain("array_list");
358       if(dom!=NULL && dom->IsA("vtkSMArraySelectionDomain") && property->GetRepeatable()) {
359         if(nElem%2 != 0) {
360           cerr << "!!!Error: The SMProperty with XML label" << smproperty->GetXMLLabel() << "has a size that is not a multiple of 2." << endl;
361           nElem=0;
362         } else {
363           di=2;
364         }
365       }
366     } else if(property->IsA("vtkSMIntVectorProperty")) {
367       dom = property->GetDomain("enum");
368     }
369     for(int i = 0; i < nElem; i+=di) {
370       bool ap=true;
371       if(di!=1) {
372         if(dynamic_cast<vtkSMStringVectorProperty*>(property)->GetElement(i+1) == "0") {
373           ap=false;
374         }
375       }
376       if(ap) {
377         if(property->IsA("vtkSMStringVectorProperty"))
378           propertyList.append(QString("'%1'").arg(dynamic_cast<vtkSMStringVectorProperty*>(property)->GetElement(i)));
379         if(property->IsA("vtkSMIntVectorProperty")) {
380           if(dom == NULL) {
381             propertyList.append(QString("%1").arg(dynamic_cast<vtkSMIntVectorProperty*>(property)->GetElement(i)));
382           } else {
383             for(int j = 0; j < dynamic_cast<vtkSMEnumerationDomain*>(dom)->GetNumberOfEntries(); j++) {
384               if(dynamic_cast<vtkSMEnumerationDomain*>(dom)->GetEntryValue(j) == dynamic_cast<vtkSMIntVectorProperty*>(property)->GetElement(i)) {
385                 propertyList.append(QString("'%1'").arg(dynamic_cast<vtkSMEnumerationDomain*>(dom)->GetEntryText(j)));
386                 break;
387               }
388             }
389           }
390         }
391         if(property->IsA("vtkSMIdTypeVectorProperty"))
392           propertyList.append(QString("%1").arg(dynamic_cast<vtkSMIdTypeVectorProperty*>(property)->GetElement(i)));
393         if(property->IsA("vtkSMDoubleVectorProperty"))
394           propertyList.append(QString("%1").arg(dynamic_cast<vtkSMDoubleVectorProperty*>(property)->GetElement(i)));
395       }
396     }
397   }
398   return propertyList;
399 }
400
401 //********************************************************************
402 QString vector_smproperty_tostring(const proxy_trace_info_ptr proxyInfo, 
403                                    const prop_trace_info_ptr propInfo)
404 {
405   vtkSMProxy* proxy = proxyInfo->Proxy;
406   vtkSMProperty* prop = propInfo->Prop;
407   QStringList propList = wrap_property(proxy, prop);
408   QString pythonProp;
409   if (propList.size() == 0) 
410     pythonProp = "[]";
411   if (propList.size() == 1) 
412     return propList.first();
413   if (propList.size() > 1) {
414     pythonProp = make_comma_separated_string(propList);
415     pythonProp = QString("[%1]").arg(pythonProp);
416   }
417   return pythonProp;
418 }
419
420 //********************************************************************
421 QString get_property_value_from_list_domain(const proxy_trace_info_ptr proxyInfo, 
422                                             const prop_trace_info_ptr propInfo)
423 {
424   vtkSMProxy* proxy = proxyInfo->Proxy;
425   vtkSMProxyProperty* prop = dynamic_cast<vtkSMProxyProperty*>(propInfo->Prop);
426   vtkSMProxyListDomain* listdomain = dynamic_cast<vtkSMProxyListDomain*>(prop->GetDomain("proxy_list"));
427   if (listdomain != NULL && prop->GetNumberOfProxies() == 1) {
428     vtkSMProxy* proxyPropertyValue = prop->GetProxy(0);   
429     for (int i = 0; i < listdomain->GetNumberOfProxies(); i++) {
430       if (listdomain->GetProxy(i) == proxyPropertyValue) {
431         proxy_trace_info_ptr info = get_proxy_info(proxyPropertyValue);
432         if (!info) {
433           proxy_trace_info_ptr infotmp(new proxy_trace_info(proxyPropertyValue, "helpers", listdomain->GetProxy(i)->GetXMLLabel()));
434           info = infotmp;
435         }
436         info->PyVariable = QString("%1.%2").arg(proxyInfo->PyVariable).arg(propInfo->PyVariable);
437         globals.registered_proxies.append(info);
438         return QString("\"%1\"").arg(listdomain->GetProxy(i)->GetXMLLabel());
439       }
440     }
441   }
442   return QString();
443 }
444
445 //********************************************************************
446 QString proxy_smproperty_tostring(const proxy_trace_info_ptr proxyInfo, 
447                                   const prop_trace_info_ptr propInfo)
448 {
449   QString strValue = get_property_value_from_list_domain(proxyInfo, propInfo);
450   if (!strValue.isNull()) 
451     return strValue;
452   vtkSMProxy* proxy = proxyInfo->Proxy;
453   vtkSMProxyProperty* prop = dynamic_cast<vtkSMProxyProperty*>(propInfo->Prop);
454   // Create a list of the python variables for each proxy in the property vector
455   QStringList nameList;
456   for (int i = 0; i < prop->GetNumberOfProxies(); i++) {
457     vtkSMProxy* inputProxy = prop->GetProxy(i);
458     proxy_trace_info_ptr info = get_proxy_info(inputProxy);
459     if (info && (!info->PyVariable.isNull())) 
460       nameList.append(info->PyVariable);
461   }
462   if (nameList.size() == 0) 
463     return "[]";
464   if (nameList.size() == 1) 
465     return nameList.first();
466   if (nameList.size() > 1) {
467     QString nameListStr = make_comma_separated_string(nameList);
468     return QString("[%1]").arg(nameListStr);
469   }
470 }
471
472 //********************************************************************
473 QString input_smproperty_tostring(const proxy_trace_info_ptr proxyInfo, 
474                                   const prop_trace_info_ptr propInfo)
475 {
476   return proxy_smproperty_tostring(proxyInfo, propInfo);
477 }
478
479 //********************************************************************
480 void trace_proxy_rename(const proxy_trace_info_ptr proxy_info, const char* new_name)
481 {
482   if ((!proxy_info) || (proxy_info->Group != "sources"))
483     return;
484   QString old_pyvariable = proxy_info->PyVariable;
485   proxy_info->PyVariable = pyvariable_from_proxy_name(new_name);
486   proxy_info->ignore_next_unregister = true;
487   QString newName(new_name);
488   QString name_to_set = newName.replace("\"", "");
489   globals.trace_output.append(QString("RenameSource(\"%1\", %2)").arg(name_to_set).arg(old_pyvariable));
490   globals.trace_output.append(QString("%1 = %2").arg(proxy_info->PyVariable).arg(old_pyvariable));
491   globals.trace_output.append(QString("del %1").arg(old_pyvariable));
492 }
493
494 //********************************************************************
495 proxy_trace_info_ptr trace_proxy_registered(vtkSMProxy* proxy, 
496                                          const QString& proxyGroup, 
497                                          const char* proxyName)
498 {
499   //if trace_globals.verbose:
500   //  print "Proxy '%s' registered in group '%s'" % (proxyName, proxyGroup)
501   if (!globals.traced_proxy_groups.contains(proxyGroup))
502     return proxy_trace_info_ptr();
503
504   proxy_trace_info_ptr info(new proxy_trace_info(proxy, proxyGroup, proxyName));
505   globals.last_registered_proxies.append(info);
506   if (globals.capture_all_properties) {
507     vtkSMPropertyIterator* itr = proxy->NewPropertyIterator();
508     for (itr->Begin(); !itr->IsAtEnd(); itr->Next()) { 
509       vtkSMProperty* prop = itr->GetProperty();
510       if (prop->GetInformationOnly() || prop->GetIsInternal()) continue;
511       trace_property_modified(info, prop);
512     }
513   }
514   return info;
515 }
516
517 //********************************************************************
518 prop_trace_info_ptr trace_property_modified(proxy_trace_info_ptr info, vtkSMProperty* prop)
519 {
520   prop_trace_info_ptr propInfo(new prop_trace_info(info, prop));
521   //if (globals.verbose)
522   //  print "Property '%s' modifed on proxy '%s'" % (propInfo.PyVariable, info.ProxyName)
523   QString propValue;
524   if (prop->IsA("vtkSMVectorProperty"))
525     propValue = vector_smproperty_tostring(info, propInfo);
526   else if (prop->IsA("vtkSMInputProperty"))
527     propValue = input_smproperty_tostring(info, propInfo);
528   else if (prop->IsA("vtkSMProxyProperty"))
529     propValue = proxy_smproperty_tostring(info, propInfo);
530   if (!propValue.isNull()) {
531     info->Props[prop] = propValue;
532     info->ModifiedProps[propInfo->PyVariable] = propValue;
533     info->CurrentProps[propInfo->PyVariable] = propValue;
534   }
535   return propInfo;
536 }
537
538 //********************************************************************
539 QList<proxy_trace_info_ptr> sort_proxy_info_by_group(const QList<proxy_trace_info_ptr>& infoList)
540 {
541   QList<proxy_trace_info_ptr> views;
542   QList<proxy_trace_info_ptr> sources;
543   QList<proxy_trace_info_ptr> representations;
544   QList<proxy_trace_info_ptr> other;
545   foreach (proxy_trace_info_ptr i, infoList) {
546     if (i->Group == "views") views.append(i);
547     else if (i->Group == "sources") sources.append(i);
548     else if (i->Group == "representations") representations.append(i);
549     else other.append(i);
550   }
551   views.append(sources);
552   views.append(other);
553   views.append(representations);  
554   return views;
555 }
556
557 //********************************************************************
558 void append_trace()
559 {
560   // Get the list of last registered proxies in sorted order
561   QList<proxy_trace_info_ptr> modified_proxies = 
562     sort_proxy_info_by_group(globals.last_registered_proxies);
563
564   // Now append the existing proxies to the list
565   foreach (proxy_trace_info_ptr p, globals.registered_proxies)
566     modified_proxies.append(p);
567
568   foreach(proxy_trace_info_ptr info, modified_proxies) {
569     QString traceOutput = "";
570
571     // Generate list of tuples : (propName, propValue)
572     QMap<QString, QString> propNameValues;
573     QMap<QString, QString>::const_iterator aIt;
574     for (aIt = info->ModifiedProps.constBegin(); aIt!=info->ModifiedProps.constEnd(); ++aIt) {
575       QString propName = aIt.key();
576       QString propValue = aIt.value();
577       if (propIsIgnored(info, propName))
578         continue;
579
580       // Note, the 'Input' property is ignored for representations, so we are
581       // only dealing with filter proxies here.  If the 'Input' property is a
582       // single value (not a multi-input filter), then ensure the input is
583       // the active source and leave the 'Input' property out of the
584       // propNameValues list.
585       if ((propName == "Input") && (!propValue.contains("["))) {
586         proxy_trace_info_ptr inputProxyInfo = get_proxy_info(propValue);
587         ensure_active_source(inputProxyInfo);
588         continue;
589       }
590       propNameValues[propName] = propValue;
591     }
592
593     // Clear the modified prop list
594     info->ModifiedProps.clear();
595
596     // If info is in the last_registered_proxies list, then we need to add the
597     // proxy's constructor call to the trace
598     if(globals.last_registered_proxies.contains(info)) {
599       // Determine the function call to construct the proxy
600       bool setPropertiesInCtor = true;
601       QStringList ctorArgs;
602       QString extraCtorCommands = "";
603       QString ctorMethod = make_name_valid(info->Proxy->GetXMLLabel());
604       if (info->Group == "sources") {
605         // track it as the last active source now
606         globals.last_active_source = info->Proxy;
607         // maybe append the guiName property
608         if (globals.use_gui_name)
609           ctorArgs.append(QString("guiName=\"%1\"").arg(info->ProxyName));
610       }
611       if (info->Group == "representations") {
612         ctorMethod = "Show";
613         setPropertiesInCtor = false;
614         // Ensure the input proxy is the active source:
615         proxy_trace_info_ptr input_proxy_info = get_input_proxy_info_for_rep(info);
616         if (input_proxy_info)
617           ensure_active_source(input_proxy_info);
618         
619         // Ensure the view is the active view:
620         proxy_trace_info_ptr view_proxy_info = get_view_proxy_info_for_rep(info);
621         if (view_proxy_info) {
622           ensure_active_view(view_proxy_info);
623         }
624       }
625       if (info->Group == "scalar_bars") {
626         ctorMethod = "CreateScalarBar";
627         extraCtorCommands = 
628           QString("GetRenderView().Representations.append(%1)").arg(info->PyVariable);
629       }
630       if (info->Group == "views") {
631         ctorMethod = "CreateRenderView";
632         // Now track it as the last active view
633         globals.last_active_view = info->Proxy;
634         setPropertiesInCtor = false;
635       }
636       if (info->Group == "lookup_tables")
637         ctorMethod = "CreateLookupTable";
638
639
640       if (setPropertiesInCtor) {
641         QMap<QString, QString>::const_iterator aIt1;
642         for (aIt1 = propNameValues.constBegin(); aIt1!=propNameValues.constEnd(); ++aIt1) {
643           QString propName = aIt1.key();
644           QString propValue = aIt1.value();
645           ctorArgs.append(QString("%1=%2").arg(propName).arg(propValue));
646         }
647         propNameValues.clear();
648       }
649       QString ctorArgString = make_comma_separated_string(ctorArgs);
650       traceOutput = 
651         QString("%1 = %2(%3)\n%4").arg(info->PyVariable).arg(ctorMethod).arg(ctorArgString).arg(extraCtorCommands);
652     }
653     // Set properties on the proxy
654
655     QMap<QString, QString>::const_iterator aIt2;
656     for (aIt2 = propNameValues.constBegin(); aIt2!=propNameValues.constEnd(); ++aIt2) {
657       QString propName = aIt2.key();
658       QString propValue = aIt2.value();
659       traceOutput += QString("%1.%2 = %3\n").arg(info->PyVariable).arg(propName).arg(propValue);
660     }
661     if (traceOutput.length() > 0){
662       globals.trace_output.append(traceOutput);
663     }
664   }
665   foreach (proxy_trace_info_ptr p, globals.last_registered_proxies) {
666     globals.registered_proxies.append(p);
667   }
668   while (globals.last_registered_proxies.size() > 0)
669     globals.last_registered_proxies.removeLast();
670 }
671
672 //********************************************************************
673 QString get_trace_string()
674 {
675   append_trace();
676   QString s = globals.trace_output.join("\n");
677   s += globals.trace_output_endblock + "\n";
678
679   return s;
680 }
681
682 //********************************************************************
683 void save_trace(const QString& fileName)
684 {
685   QFile file(fileName);
686   if(!file.open(QFile::WriteOnly))
687     return;
688
689   QString trace = get_trace_string();
690   QTextStream out(&file);
691   out << trace;
692   file.close();
693 }
694
695 //********************************************************************
696 //QString print_trace()
697
698 //********************************************************************
699 void on_proxy_registered(vtkObject* obj, unsigned long , void* , void *)
700 {
701   vtkSMPythonTraceObserver* o = dynamic_cast<vtkSMPythonTraceObserver*>(obj);
702   if (!o) return;
703
704   vtkSMProxy* p = o->GetLastProxyRegistered();
705   const char* pGroup = o->GetLastProxyRegisteredGroup();
706   const char* pName = o->GetLastProxyRegisteredName();
707   if (p && pGroup && pName) {
708     proxy_trace_info_ptr proxy_info = get_proxy_info(p, false);
709     // handle source proxy rename, no-op if proxy isn't a source
710     if (proxy_info) 
711       trace_proxy_rename(proxy_info, pName);
712     else
713       trace_proxy_registered(p, pGroup, pName);
714   }
715 }
716
717 //********************************************************************
718 void on_proxy_unregistered(vtkObject* obj, unsigned long , void* , void*)
719 {
720   vtkSMPythonTraceObserver* o = dynamic_cast<vtkSMPythonTraceObserver*>(obj);
721   if (!o) return;
722
723   vtkSMProxy* p = o->GetLastProxyUnRegistered();
724   const char* pGroup = o->GetLastProxyUnRegisteredGroup();
725   const char* pName = o->GetLastProxyUnRegisteredName();
726   if (p && pGroup && pName) {
727     proxy_trace_info_ptr proxy_info = get_proxy_info(p);
728     if (proxy_info != NULL && proxy_info->Proxy != NULL) {
729       if (proxy_info->ignore_next_unregister) {
730         proxy_info->ignore_next_unregister = false;
731         return;
732       }
733       globals.trace_output.append(QString("Delete(%1)").arg(proxy_info->PyVariable));
734       if (globals.last_registered_proxies.contains(proxy_info)) {
735         int aInd = globals.last_registered_proxies.indexOf(proxy_info);
736         globals.last_registered_proxies.removeAt(aInd);
737       }
738       if (globals.registered_proxies.contains(proxy_info)) {
739         int aInd = globals.registered_proxies.indexOf(proxy_info);
740         globals.registered_proxies.removeAt(aInd);
741       }
742     }
743   }
744 }
745
746 //********************************************************************
747 void on_property_modified(vtkObject* obj, unsigned long , void* , void*)
748 {
749   vtkSMPythonTraceObserver* o = dynamic_cast<vtkSMPythonTraceObserver*>(obj);
750   if (!o) return;
751
752   const char* propName = o->GetLastPropertyModifiedName();
753   vtkSMProxy* proxy = o->GetLastPropertyModifiedProxy();
754   if ((propName != NULL) && (proxy != NULL)) {
755     vtkSMProperty* prop = proxy->GetProperty(propName);
756     if (prop->GetInformationOnly() || prop->GetIsInternal()) return;
757
758     // small hack here: some view properties are modified before the view
759     // is registered.  We don't want to call get_proxy_info until after
760     // the view is registered, so for now lets ignore these properties:
761     QStringList ignoredViewProp = ignoredViewProperties();
762     if (ignoredViewProp.contains(propName)) return;
763
764     proxy_trace_info_ptr info = get_proxy_info(proxy);
765     if ((info != NULL && info->Proxy != NULL) && (prop != NULL))
766       trace_property_modified(info, prop);
767   }
768 }
769
770 //********************************************************************
771 void on_update_information(vtkObject*, unsigned long , void* , void*)
772 {
773   append_trace();
774 }
775
776 //********************************************************************
777 void add_observers()
778 {
779   vtkCallbackCommand *aCommand = NULL;
780   vtkSMPythonTraceObserver* o = trace_observer();
781   aCommand = vtkCallbackCommand::New();
782   aCommand->SetCallback(on_proxy_registered);
783   o->AddObserver("RegisterEvent", aCommand);
784   aCommand->Delete();
785   aCommand = vtkCallbackCommand::New();
786   aCommand->SetCallback(on_proxy_unregistered);
787   o->AddObserver("UnRegisterEvent", aCommand);
788   aCommand->Delete();
789   aCommand = vtkCallbackCommand::New();
790   aCommand->SetCallback(on_property_modified);
791   o->AddObserver("PropertyModifiedEvent", aCommand);
792   aCommand->Delete();
793   aCommand = vtkCallbackCommand::New();
794   aCommand->SetCallback(on_update_information);
795   o->AddObserver("UpdateInformationEvent", aCommand);
796   aCommand->Delete();
797   globals.observer_active = true;
798 }
799
800 //********************************************************************
801 void reset_trace_observer()
802 {
803   if (myInitialised) 
804     globals.observer->Delete();
805   globals.observer = vtkSMPythonTraceObserver::New();
806   globals.observer_active = false;
807   myInitialised = true;
808 }
809
810 //********************************************************************
811 void reset_trace_globals()
812 {
813   globals.capture_all_properties = false;
814   globals.use_gui_name = false;
815   globals.verbose = false;
816   globals.active_source_at_start = 0;
817   globals.active_view_at_start = 0;
818   globals.last_active_view = 0;
819   globals.last_active_source = 0;
820   globals.last_registered_proxies.clear();
821   globals.registered_proxies.clear();
822   globals.trace_output.clear();
823   globals.trace_output << "try: pvsimple\nexcept: from pvsimple import *\n";
824   globals.trace_output_endblock = "Render()";
825   globals.traced_proxy_groups.clear();
826   globals.traced_proxy_groups << "sources"<<"representations"<<"views"<<"lookup_tables"<<"scalar_bars";
827   globals.ignored_view_properties.clear();
828   globals.ignored_view_properties << "ViewSize"<<"GUISize"<<"ViewPosition"<<"ViewTime"<<"Representations";
829   globals.ignored_representation_properties.clear();
830   globals.ignored_representation_properties << "Input";
831   reset_trace_observer();
832 }
833
834 //********************************************************************
835 void clear_trace()
836 {
837   reset_trace_globals();
838 }
839
840 //********************************************************************
841 void stop_trace()
842 {
843   reset_trace_observer();
844 }
845
846 //********************************************************************
847 void start_trace(bool CaptureAllProperties, bool UseGuiName, bool Verbose)
848 {
849   clear_trace();
850   add_observers();
851   // VSV: Has to be defined
852   //globals.active_source_at_start = simple.GetActiveSource()
853   //globals.active_view_at_start = simple.GetActiveView()
854   //globals.capture_all_properties = CaptureAllProperties
855   //globals.use_gui_name = UseGuiName
856   //globals.verbose = Verbose
857 }