Commit 8bbd0e75 authored by David E. DeMarle's avatar David E. DeMarle

new catalyst/cinema export GUI.

The idea is a central panel for the user to declare what they want to
export, separated from the action of doing the export. The export
configuration is saveable and restorable in state files. Combined these
make it easier for the user to make Catalyst exports, avoid
some annoying behaviors, and open up paths to some new features.

The implementation uses savescreenshot and writerproxies instead of Catalyst
specific export proxies. We use standard proxies rather than Catalyst specific
ones to support new "export now" and "export batch script that will export"
use cases. The proxies are managed in something called an ExportProxyDepot for
more convenient access by the code.
parent e5e4066f
......@@ -81,6 +81,7 @@ void vtkPVInitializePythonModules();
#include "pqPythonDebugLeaksView.h"
#include "pqPythonShell.h"
typedef pqPythonDebugLeaksView DebugLeaksViewType;
#include "pqCatalystExportInspector.h"
#else
#include "vtkQtDebugLeaksView.h"
typedef vtkQtDebugLeaksView DebugLeaksViewType;
......@@ -137,6 +138,15 @@ ParaViewMainWindow::ParaViewMainWindow()
}
#endif
#ifdef PARAVIEW_ENABLE_PYTHON
pqCatalystExportInspector* catalystInspector = new pqCatalystExportInspector(this);
this->Internals->catalystInspectorDock->setWidget(catalystInspector);
this->Internals->catalystInspectorDock->hide();
#else
delete this->Internals->catalystInspectorDock;
this->Internals->catalystInspectorDock = nullptr;
#endif
// show output widget if we received an error message.
this->connect(this->Internals->outputWidget, SIGNAL(messageDisplayed(const QString&, int)),
SLOT(handleMessage(const QString&, int)));
......@@ -260,7 +270,8 @@ ParaViewMainWindow::ParaViewMainWindow()
pqParaViewMenuBuilders::buildToolsMenu(*this->Internals->menuTools);
// Populate Catalyst menu.
pqParaViewMenuBuilders::buildCatalystMenu(*this->Internals->menu_Catalyst);
pqParaViewMenuBuilders::buildCatalystMenu(
*this->Internals->menu_Catalyst, this->Internals->catalystInspectorDock);
// setup the context menu for the pipeline browser.
pqParaViewMenuBuilders::buildPipelineBrowserContextMenu(
......
......@@ -266,6 +266,17 @@
</attribute>
<widget class="pqLightsInspector" name="lightInspectorPanel"/>
</widget>
<widget class="QDockWidget" name="catalystInspectorDock">
<property name="allowedAreas">
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>Catalyst Export Inspector</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
</widget>
<widget class="QDockWidget" name="colorMapEditorDock">
<property name="allowedAreas">
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
......@@ -494,6 +505,12 @@
<header>pqLightsInspector.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>pqCatalystExportInspector</class>
<extends>QWidget</extends>
<header>pqCatalystExportInspector.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../Qt/Components/Resources/pqComponents.qrc"/>
......
......@@ -59,6 +59,7 @@ set (Module_SRCS
vtkSMDoubleVectorProperty.cxx
vtkSMEnumerationDomain.cxx
vtkSMExtentDomain.cxx
vtkSMExportProxyDepot.cxx
vtkSMFieldDataDomain.cxx
vtkSMFileListDomain.cxx
vtkSMInputFileNameDomain.cxx
......
/*=========================================================================
Program: ParaView
Module: vtkSMExportProxyDepot.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 "vtkSMExportProxyDepot.h"
#include "vtkCollection.h"
#include "vtkCollectionIterator.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPVXMLElement.h"
#include "vtkSMParaViewPipelineController.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMProxy.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMWriterFactory.h"
#include "vtkSMWriterProxy.h"
#include "vtkSmartPointer.h"
class vtkSMExportProxyDepot::Internal
{
public:
Internal() {}
~Internal() {}
vtkSmartPointer<vtkCollection> WriterCollection = vtkSmartPointer<vtkCollection>::New();
vtkSmartPointer<vtkCollectionIterator> WriterIterator =
vtkSmartPointer<vtkCollectionIterator>::New();
vtkSmartPointer<vtkCollection> ScreenshotCollection = vtkSmartPointer<vtkCollection>::New();
vtkSmartPointer<vtkCollectionIterator> ScreenshotIterator =
vtkSmartPointer<vtkCollectionIterator>::New();
};
vtkStandardNewMacro(vtkSMExportProxyDepot);
//-----------------------------------------------------------------------------
vtkSMExportProxyDepot::vtkSMExportProxyDepot()
{
this->Session = nullptr;
this->Internals = new Internal;
}
//-----------------------------------------------------------------------------
vtkSMExportProxyDepot::~vtkSMExportProxyDepot()
{
delete this->Internals;
}
//-----------------------------------------------------------------------------
void vtkSMExportProxyDepot::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//-----------------------------------------------------------------------------
vtkSMProxy* vtkSMExportProxyDepot::GetGlobalOptions()
{
if (!this->Session)
{
return nullptr;
}
vtkSMProxy* globalProxy = this->Session->GetProxy("export_global", "catalyst");
if (!globalProxy)
{
globalProxy = this->Session->NewProxy("coprocessing", "CatalystGlobalOptions");
vtkNew<vtkSMParaViewPipelineController> controller;
controller->PreInitializeProxy(globalProxy);
controller->PostInitializeProxy(globalProxy);
this->Session->RegisterProxy("export_global", "catalyst", globalProxy);
globalProxy->Delete();
}
return globalProxy;
}
//-----------------------------------------------------------------------------
bool vtkSMExportProxyDepot::HasWriterProxy(const char* filtername, const char* format)
{
if (!this->Session)
{
return false;
}
std::string filterhash = filtername;
filterhash += "_";
filterhash += format;
vtkSMSourceProxy* writerProxy =
vtkSMSourceProxy::SafeDownCast(this->Session->GetProxy("export_writers", filterhash.c_str()));
if (!writerProxy)
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
vtkSMSourceProxy* vtkSMExportProxyDepot::GetWriterProxy(
vtkSMSourceProxy* filter, const char* filtername, const char* format)
{
if (!this->Session)
{
return nullptr;
}
std::string filterhash = filtername;
filterhash += "_";
filterhash += format;
vtkSMSourceProxy* writerProxy =
vtkSMSourceProxy::SafeDownCast(this->Session->GetProxy("export_writers", filterhash.c_str()));
if (!writerProxy)
{
// first time accessed, make it
vtkSmartPointer<vtkSMWriterFactory> wf = vtkSmartPointer<vtkSMWriterFactory>::New();
wf->UpdateAvailableWriters();
writerProxy =
vtkSMWriterProxy::SafeDownCast(wf->CreateWriter(format, filter, 0, true, "CatalystApproved"));
vtkPVXMLElement* hint = writerProxy->GetHints();
std::string extension = "";
// use first entry in the hint to choose a default fileextension
if (hint != nullptr)
{
vtkPVXMLElement* factory = hint->FindNestedElementByName("WriterFactory");
if (factory != nullptr)
{
const char* exts = factory->GetAttribute("extensions");
if (exts)
{
std::string asstr = exts;
extension = asstr;
size_t pos = asstr.find(" ");
if (pos != std::string::npos)
{
extension = asstr.substr(0, pos);
}
}
}
}
// swap the generic ".ext" extension from XML with a better one
std::string fname = vtkSMPropertyHelper(writerProxy, "CatalystFilePattern").GetAsString();
if (fname.substr(fname.length() - 3, fname.length()) == "ext")
{
fname = fname.substr(0, fname.length() - 3) + extension;
vtkSMPropertyHelper(writerProxy, "CatalystFilePattern").Set(fname.c_str());
}
this->Session->RegisterProxy("export_writers", filterhash.c_str(), writerProxy);
writerProxy->Delete();
}
return writerProxy;
}
//-----------------------------------------------------------------------------
void vtkSMExportProxyDepot::InitNextWriterProxy()
{
this->Session->GetProxies("export_writers", this->Internals->WriterCollection);
this->Internals->WriterIterator.TakeReference(this->Internals->WriterCollection->NewIterator());
};
//-----------------------------------------------------------------------------
vtkSMSourceProxy* vtkSMExportProxyDepot::GetNextWriterProxy()
{
vtkSMSourceProxy* ret =
vtkSMSourceProxy::SafeDownCast(this->Internals->WriterIterator->GetCurrentObject());
this->Internals->WriterIterator->GoToNextItem();
return ret;
};
//-----------------------------------------------------------------------------
bool vtkSMExportProxyDepot::HasScreenshotProxy(const char* viewname, const char* format)
{
if (!this->Session)
{
return false;
}
std::string viewhash = viewname;
viewhash += "_";
viewhash += format;
vtkSMProxy* ssProxy = this->Session->GetProxy("export_screenshots", viewhash.c_str());
if (!ssProxy)
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
vtkSMProxy* vtkSMExportProxyDepot::GetScreenshotProxy(
vtkSMProxy* view, const char* viewname, const char* format)
{
if (!this->Session)
{
return nullptr;
}
std::string viewhash = viewname;
viewhash += "_";
viewhash += format;
vtkSMProxy* ssProxy = this->Session->GetProxy("export_screenshots", viewhash.c_str());
if (!ssProxy)
{
// first time accessed, make it
ssProxy = this->Session->NewProxy("misc", "SaveScreenshot");
if (!ssProxy)
{
return nullptr;
}
std::string formatS = format;
int dotP = formatS.find_first_of(".") + 1;
int rparenP = formatS.find_last_of(")");
std::string extension = formatS.substr(dotP, rparenP - dotP);
vtkNew<vtkSMParaViewPipelineController> controller;
controller->PreInitializeProxy(ssProxy);
vtkSMPropertyHelper(ssProxy, "View").Set(view);
// swap the generic ".ext" extension from XML with a better one
std::string fname = vtkSMPropertyHelper(ssProxy, "CatalystFilePattern").GetAsString();
fname = fname.substr(0, fname.length() - 3) + extension;
vtkSMPropertyHelper(ssProxy, "CatalystFilePattern").Set(fname.c_str());
controller->PostInitializeProxy(ssProxy);
this->Session->RegisterProxy("export_screenshots", viewhash.c_str(), ssProxy);
ssProxy->Delete();
}
return ssProxy;
}
//-----------------------------------------------------------------------------
void vtkSMExportProxyDepot::InitNextScreenshotProxy()
{
this->Session->GetProxies("export_screenshots", this->Internals->ScreenshotCollection);
this->Internals->ScreenshotIterator.TakeReference(
this->Internals->ScreenshotCollection->NewIterator());
};
//-----------------------------------------------------------------------------
vtkSMProxy* vtkSMExportProxyDepot::GetNextScreenshotProxy()
{
vtkSMProxy* ret =
vtkSMProxy::SafeDownCast(this->Internals->ScreenshotIterator->GetCurrentObject());
this->Internals->ScreenshotIterator->GoToNextItem();
return ret;
};
/*=========================================================================
Program: ParaView
Module: vtkSMCatalystOptionsProxy.h
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.
=========================================================================*/
/**
* @class vtkSMExportProxyDepot
* @brief access proxies that define catalyst export state
*
* vtkSMExportProxyDepot is a container for export proxies. These include
* Writer proxies, SaveScreenShot proxies and the global Catalyst Options Proxy.
* It is a helper class for the SMSessionProxyManager intended to standardize an
* API for working with them.
*/
#ifndef vtkSMExportProxyDepot_h
#define vtkSMExportProxyDepot_h
#include "vtkObject.h"
#include "vtkPVServerManagerCoreModule.h" //needed for exports
class vtkSMProxy;
class vtkSMSessionProxyManager;
class vtkSMSourceProxy;
class VTKPVSERVERMANAGERCORE_EXPORT vtkSMExportProxyDepot : public vtkObject
{
public:
static vtkSMExportProxyDepot* New();
vtkTypeMacro(vtkSMExportProxyDepot, vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Global options for the entire catalyst export.
*/
vtkSMProxy* GetGlobalOptions();
//@{
/**
* Options for exporting a source proxy.
*/
bool HasWriterProxy(const char* group, const char* format);
vtkSMSourceProxy* GetWriterProxy(vtkSMSourceProxy* filter, const char* group, const char* format);
//@}
//@{
/**
* Iterate through source proxy exports.
*/
void InitNextWriterProxy();
vtkSMSourceProxy* GetNextWriterProxy();
//@}
//@{
/**
* Options for exporting a screen shot.
*/
bool HasScreenshotProxy(const char* group, const char* format);
vtkSMProxy* GetScreenshotProxy(vtkSMProxy* view, const char* group, const char* format);
//@}
//@{
/**
* Iterate through screen shot exports.
*/
void InitNextScreenshotProxy();
vtkSMProxy* GetNextScreenshotProxy();
//@}
protected:
vtkSMExportProxyDepot();
~vtkSMExportProxyDepot() override;
private:
vtkSMExportProxyDepot(const vtkSMExportProxyDepot&) = delete;
void operator=(const vtkSMExportProxyDepot&) = delete;
friend class vtkSMSessionProxyManager;
vtkSMSessionProxyManager* Session;
class Internal;
Internal* Internals;
};
#endif
......@@ -30,6 +30,7 @@
#include "vtkSMCoreUtilities.h"
#include "vtkSMDeserializerProtobuf.h"
#include "vtkSMDocumentation.h"
#include "vtkSMExportProxyDepot.h"
#include "vtkSMGlobalPropertiesLinkUndoElement.h"
#include "vtkSMPipelineState.h"
#include "vtkSMPropertyIterator.h"
......@@ -158,6 +159,9 @@ vtkSMSessionProxyManager::vtkSMSessionProxyManager(vtkSMSession* session)
this->PipelineState = vtkSMPipelineState::New();
this->PipelineState->SetSession(this->Session);
this->ExportDepot = vtkSMExportProxyDepot::New();
this->ExportDepot->Session = this;
// setup event forwarder so that it forwards all events fired by this class via
// the global proxy manager.
vtkNew<vtkSMProxyManagerForwarder> forwarder;
......@@ -181,6 +185,9 @@ vtkSMSessionProxyManager::~vtkSMSessionProxyManager()
this->PipelineState->Delete();
this->PipelineState = NULL;
this->ExportDepot->Delete();
this->ExportDepot = nullptr;
}
//----------------------------------------------------------------------------
......
......@@ -122,6 +122,7 @@ class vtkEventForwarderCommand;
class vtkPVXMLElement;
class vtkSMCompoundSourceProxy;
class vtkSMDocumentation;
class vtkSMExportProxyDepot;
class vtkSMLink;
class vtkSMProperty;
class vtkSMProxy;
......@@ -573,6 +574,11 @@ public:
*/
vtkSMProxy* FindProxy(const char* reggroup, const char* xmlgroup, const char* xmltype);
/**
* Get access the the export depot.
*/
vtkGetObjectMacro(ExportDepot, vtkSMExportProxyDepot);
protected:
vtkSMSessionProxyManager(vtkSMSession*);
~vtkSMSessionProxyManager() override;
......@@ -638,6 +644,8 @@ private:
vtkSMProxyManagerObserver* Observer;
bool InLoadXMLState;
vtkSMExportProxyDepot* ExportDepot;
#ifndef __WRAP__
static vtkSMSessionProxyManager* New() { return NULL; }
#endif
......
......@@ -85,7 +85,7 @@ public:
}
// Returns true if the data from the given output port can be written.
bool CanWrite(vtkSMSourceProxy* source, unsigned int port)
bool CanWrite(vtkSMSourceProxy* source, unsigned int port, const char* RequiredHint = nullptr)
{
vtkSMSessionProxyManager* pxm = source->GetSession()->GetSessionProxyManager();
vtkSMProxy* prototype = pxm->GetPrototypeProxy(this->Group.c_str(), this->Name.c_str());
......@@ -121,10 +121,27 @@ public:
{
if (writer->GetParallelOnly())
{
return false;
if (!RequiredHint ||
strcmp("CatalystApproved", RequiredHint) !=
0) // Catalyst export can access parallel defs in serial
{
return false;
}
}
}
}
if (RequiredHint && writer)
{
if (!writer->GetHints())
{
return false;
}
if (!writer->GetHints()->FindNestedElementByName(RequiredHint))
{
return false;
}
}
vtkSMInputProperty* pp = vtkSMInputProperty::SafeDownCast(prototype->GetProperty("Input"));
if (!pp)
{
......@@ -273,8 +290,8 @@ void vtkSMWriterFactory::UpdateAvailableWriters()
}
//----------------------------------------------------------------------------
vtkSMProxy* vtkSMWriterFactory::CreateWriter(
const char* filename, vtkSMSourceProxy* source, unsigned int outputport)
vtkSMProxy* vtkSMWriterFactory::CreateWriter(const char* filename, vtkSMSourceProxy* source,
unsigned int outputport, bool proxybyname, const char* RequiredHint)
{
if (!filename || filename[0] == 0)
{
......@@ -283,13 +300,21 @@ vtkSMProxy* vtkSMWriterFactory::CreateWriter(
}
std::string extension = vtksys::SystemTools::GetFilenameExtension(filename);
if (extension.size() > 0)
if (!proxybyname)
{
// Find characters after last "."
std::string::size_type found = extension.find_last_of(".");
if (found != std::string::npos)
if (extension.size() > 0)
{
extension = extension.substr(found + 1);
// Find characters after last "."
std::string::size_type found = extension.find_last_of(".");
if (found != std::string::npos)
{
extension = extension.substr(found + 1);
}
else
{
vtkErrorMacro("No extension. Cannot determine writer to create.");
return NULL;
}
}
else
{
......@@ -297,11 +322,6 @@ vtkSMProxy* vtkSMWriterFactory::CreateWriter(
return NULL;
}
}
else
{
vtkErrorMacro("No extension. Cannot determine writer to create.");
return NULL;
}
// Get ProxyManager
vtkSMSessionProxyManager* pxm = source->GetSession()->GetSessionProxyManager();
......@@ -314,9 +334,17 @@ vtkSMProxy* vtkSMWriterFactory::CreateWriter(
++iter)
{
iter->second.FillInformation(source->GetSession());
if (iter->second.CanCreatePrototype(source) && iter->second.ExtensionTest(extension.c_str()) &&
iter->second.CanWrite(source, outputport))
if (iter->second.CanCreatePrototype(source) &&
(proxybyname || iter->second.ExtensionTest(extension.c_str())) &&
iter->second.CanWrite(source, outputport, RequiredHint))
{
if (proxybyname)
{
if (strcmp(filename, iter->second.Name.c_str()) != 0)
{
continue;
}
}
vtkSMProxy* proxy = pxm->NewProxy(iter->second.Group.c_str(), iter->second.Name.c_str());
vtkNew<vtkSMParaViewPipelineController> controller;
controller->PreInitializeProxy(proxy);
......@@ -380,6 +408,41 @@ const char* vtkSMWriterFactory::GetSupportedFileTypes(
return this->Internals->SupportedFileTypes.c_str();
}
//----------------------------------------------------------------------------
void vtkSMWriterFactory::GetSupportedWriterProxies(
vtkSMSourceProxy* source, unsigned int outputport, std::string& output, const char* RequiredHint)
{
std::set<std::string> sorted_types;
vtkInternals::PrototypesType::iterator iter;
for (iter = this->Internals->Prototypes.begin(); iter != this->Internals->Prototypes.end();
++iter)
{
if (iter->second.CanCreatePrototype(source) &&
iter->second.CanWrite(source, outputport, RequiredHint))
{
iter->second.FillInformation(source->GetSession());
if (iter->second.Extensions.size() > 0)
{
std::ostringstream stream;
stream << iter->second.Name;
sorted_types.insert(stream.str());
}
}
}
std::ostringstream all_types;
std::set<std::string>::iterator iter2;
for (iter2 = sorted_types.begin(); iter2 != sorted_types.end(); ++iter2)
{
if (iter2 != sorted_types.begin())
{
all_types << ";";
}
all_types << (*iter2);
}
output = all_types.str();
}
//----------------------------------------------------------------------------
bool vtkSMWriterFactory::CanWrite(vtkSMSourceProxy* source, unsigned int outputport)
{
......
......@@ -71,8 +71,12 @@ public:
* in order to prevent a double pipeline execution when you want to write a
* given timestep, you should call updatePipeline( time ) before the
* CreateWriter call.
* The proxybyname flag tells the factory to use the proxy name rather than
* a filename.extension to lookup the right proxy.
* The RequiredHint restricts to proxies with the XML hint, for example "CatalystApproved".
*/
vtkSMProxy* CreateWriter(const char* filename, vtkSMSourceProxy*, unsigned int outputport);
vtkSMProxy* CreateWriter(const char* filename, vtkSMSourceProxy*, unsigned int outputport,
bool proxyname = false, const char* RequiredHint = nullptr);
vtkSMProxy* CreateWriter(const char* filename, vtkSMSourceProxy* pxy)
{
return this->CreateWriter(filename, pxy, 0);
......@@ -90,6 +94,11 @@ public:
{
return this->GetSupportedFileTypes(source, 0);
}
/**
* A variation on GetSupportedFileTypes that obtains a list of prototype proxy names.
*/
void GetSupportedWriterProxies(vtkSMSourceProxy* source, unsigned int outputport,
std::string& output, const char* RequiredHint = nullptr);
// Returns the number of registered prototypes.
unsigned int GetNumberOfRegisteredPrototypes();
......
......@@ -140,6 +140,7 @@ protected:
*/
vtkSMProxy* GetFormatProxy(const std::string& filename);
friend class pqCatalystExportReaction; // access to GetView,FormatProxy
private:
vtkSMSaveScreenshotProxy(const vtkSMSaveScreenshotProxy&) = delete;
void operator=(const vtkSMSaveScreenshotProxy&) = delete;
......
......@@ -85,6 +85,17 @@
<Property name="TransportMethod" />
<Property name="TransportMethodArguments" />
</PropertyGroup>
<SubProxy>
<Proxy name="CatalystOptions"
proxygroup="misc"
proxyname="CatalystOptions"></Proxy>
<ExposedProperties>
<PropertyGroup label="Catalyst Options">
<Property name="CatalystWriteFrequency" />
<Property name="CatalystFilePattern" />
</PropertyGroup>
</ExposedProperties>
</SubProxy>
<Hints>
<Property name="Input" show="0" />
<Property name="TransportMethod" show="1" />
......@@ -92,6 +103,7 @@
<Property name="CompressionMethod" show="1" />
<WriterFactory extensions="vta"
file_description="VTK ADIOS File" />
<CatalystApproved/>
</Hints>
<!-- End of ADIOSWriter -->
</WriterProxy>
......
......@@ -2842,6 +2842,35 @@
input.</Documentation>
</ProxyProperty>
</Proxy>