Salome HOME
Copyright update 2022
[modules/paravis.git] / src / PVGUI / PVGUI_DataModel.cxx
index 1d90214f484c4df9d0163d35ac2aafac7701e75f..994e1fde6ff558aba58552fe00ed6dcf61579a8c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2015  CEA/DEN, EDF R&D
+// Copyright (C) 2010-2022  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // Author : Adrien Bruneton (CEA)
 //
 
+//Local includes
 #include "PVGUI_DataModel.h"
 #include "PVGUI_Module.h"
 
+// GUI includes
+#include <LightApp_Study.h>
+#include <LightApp_Module.h>
+#include <LightApp_Application.h>
+#include <LightApp_DataModel.h>
+#include <CAM_DataObject.h>
+#include <SUIT_Tools.h>
+#include <SUIT_Session.h>
+#include <SUIT_ResourceMgr.h>
+
+// KERNEL
+#include <utilities.h>
+
+// Qt includes
 #include <QFile>
+#include <QFileInfo>
 #include <QTextStream>
+#include <QDomNode>
+
+// ParaView include
+#include <pqApplicationCore.h>
+#include <pqServer.h>
+#include <vtkOutputWindow.h>
+
+const QString PVGUI_DataModel::RESTORE_FLAG_FILE = "do_restore_paravis_references.par";
+
+/*!
+ * XML processing functions to handle the PV state file.
+ */
+namespace {
+
+  QStringList multiFormats()
+  {
+    static QStringList formats;
+    if ( formats.isEmpty() )
+      formats << "vtm" << "lata" << "pvd";
+    return formats;
+  }
+  void warning( const QString& message )
+  {
+    vtkOutputWindow* vtkWindow = vtkOutputWindow::GetInstance();
+    if ( vtkWindow )
+    {
+      vtkWindow->DisplayWarningText( qPrintable( message ) );
+    }
+  }
+
+  void processElements(QDomNode& thePropertyNode, QStringList& theFileNames,
+                       const QString& theNewPath, bool theRestore)
+  {
+    QDomElement aProperty = thePropertyNode.toElement();
+    int aNbElements = aProperty.attribute("number_of_elements").toInt();
+    if ( aNbElements > 1 )
+      warning( QString("You save data file with number of entities > 1 (%1); some data may be lost!").arg(aNbElements) );
+    QDomNode aElementNode = thePropertyNode.firstChild();
+    while (aElementNode.isElement()) {
+      QDomElement aElement = aElementNode.toElement();
+      if (aElement.tagName() == "Element") {
+        QString aIndex = aElement.attribute("index");
+        if (aIndex == "0") {
+          QString aValue = aElement.attribute("value");
+          if (!aValue.isNull()) {
+            if (theNewPath.isEmpty()) {
+              QFileInfo aFInfo(aValue);
+              if (aFInfo.exists()) {
+                QString ext = aFInfo.suffix();
+                if ( multiFormats().contains(aFInfo.suffix()) )
+                  warning( QString("You save data in multiple file format (%1); some data may be not saved!").arg(ext) );
+                theFileNames<<aValue;
+                aElement.setAttribute("value", aFInfo.fileName());
+              }
+              break;
+            } else {
+              if (theRestore)
+                aElement.setAttribute("value", QString(theNewPath) + aValue);
+            }
+          }
+        }
+      }
+      aElementNode = aElementNode.nextSibling();
+    }
+  }
+
+  void processProperties(QDomNode& theProxyNode, QStringList& theFileNames,
+                         const QString& theNewPath, bool theRestore)
+  {
+    QDomNode aPropertyNode = theProxyNode.firstChild();
+    while (aPropertyNode.isElement()) {
+      QDomElement aProperty = aPropertyNode.toElement();
+      QString aName = aProperty.attribute("name");
+      if ((aName == "FileName") || (aName == "FileNameInfo") || (aName == "FileNames")) {
+        processElements(aPropertyNode, theFileNames, theNewPath, theRestore);
+      }
+      aPropertyNode = aPropertyNode.nextSibling();
+    }
+  }
+
+
+  void processProxies(QDomNode& theNode, QStringList& theFileNames,
+                      const QString& theNewPath, bool theRestore)
+  {
+    QDomNode aProxyNode = theNode.firstChild();
+    while (aProxyNode.isElement()) {
+      QDomElement aProxy = aProxyNode.toElement();
+      if (aProxy.tagName() == "Proxy") {
+        QString aGroup = aProxy.attribute("group");
+        if (aGroup == "sources") {
+          processProperties(aProxyNode, theFileNames, theNewPath, theRestore);
+        }
+      }
+      aProxyNode = aProxyNode.nextSibling();
+    }
+  }
+
+  bool processAllFilesInState(const QString& aFileName, QStringList& theFileNames,
+                              const QString& theNewPath, bool theRestore)
+  {
+    QFile aFile(aFileName);
+    if (!aFile.open(QFile::ReadOnly)) {
+      MESSAGE("Can't open state file "<<aFileName.toStdString());
+      return false;
+    }
+    QDomDocument aDoc;
+    bool aRes = aDoc.setContent(&aFile);
+    aFile.close();
+
+    if (!aRes) {
+      MESSAGE("File "<<aFileName.toStdString()<<" is not XML document");
+      return false;
+    }
+
+    QDomElement aRoot = aDoc.documentElement();
+    if ( aRoot.isNull() ) {
+      MESSAGE( "Invalid XML root" );
+      return false;
+    }
+
+    QDomNode aNode = aRoot.firstChild();
+    while (aRes  && !aNode.isNull() ) {
+      aRes = aNode.isElement();
+      if ( aRes ) {
+        QDomElement aSection = aNode.toElement();
+        if (aSection.tagName() == "ServerManagerState") {
+          processProxies(aNode, theFileNames, theNewPath, theRestore);
+        }
+      }
+      aNode = aNode.nextSibling();
+    }
+    if (!aFile.open(QFile::WriteOnly | QFile::Truncate)) {
+      MESSAGE("Can't open state file "<<aFileName.toStdString()<<" for writing");
+      return false;
+    }
+    QTextStream out(&aFile);
+    aDoc.save(out, 2);
+    aFile.close();
+
+    return true;
+  }
+}
+
 
 PVGUI_DataModel::PVGUI_DataModel( PVGUI_Module* theModule ):
-  LightApp_DataModel(theModule)
+  LightApp_DataModel(theModule),
+  myStudyURL("")
 {}
 
 PVGUI_DataModel::~PVGUI_DataModel()
 {}
 
+bool PVGUI_DataModel::create( CAM_Study* theStudy) {
+  bool res = LightApp_DataModel::create(theStudy);
+  publishComponent(theStudy);
+  return res;
+}
+
+void PVGUI_DataModel::publishComponent( CAM_Study* theStudy ) {
+  LightApp_Study* study = dynamic_cast<LightApp_Study*>( theStudy );
+  CAM_ModuleObject *aModelRoot = dynamic_cast<CAM_ModuleObject*>( root());
+  if( study && aModelRoot == NULL ) {
+    aModelRoot = createModuleObject( theStudy->root() );
+    aModelRoot->setDataModel( this );
+    setRoot(aModelRoot);
+  }
+}
+
 bool PVGUI_DataModel::dumpPython( const QString& path, CAM_Study* std,
-            bool multiFile, QStringList& listOfFiles)
+            bool isMultiFile, QStringList& listOfFiles)
 {
-  QString tmpFile("/tmp/kikou.py");
-  listOfFiles.push_back(tmpFile);
-  QFile file(tmpFile);
+
+  LightApp_Study* study = dynamic_cast<LightApp_Study*>( std );
+  if(!study)
+    return false;
+
+  std::string aTmpDir = study->GetTmpDir( path.toLatin1().constData(), isMultiFile );
+  std::string aFile = aTmpDir + "paravis_dump.tmp";
+
+  listOfFiles.append(aTmpDir.c_str());
+  listOfFiles.append("paravis_dump.tmp");
+
+  QFile file(aFile.c_str());
   if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
     return false;
 
-  //MESSAGE("[PARAVIS] dumpPython()")
   PVGUI_Module * mod = (PVGUI_Module *) getModule();
   QString trace(mod->getTraceString());
 
-  if (multiFile)
+  if (isMultiFile)
     {
       QStringList abuffer;
-      abuffer.push_back(QString("def RebuildData( theStudy ):"));
+      abuffer.push_back(QString("def RebuildData():"));
       QStringList lst(trace.split("\n"));
       foreach(QString elem, lst)
         {
@@ -66,3 +250,168 @@ bool PVGUI_DataModel::dumpPython( const QString& path, CAM_Study* std,
   return true;
 }
 
+/*!
+  \brief Open data model (read ParaView pipeline state from the files).
+  \param theName study file path
+  \param theStudy study pointer
+  \param theList list of the (temporary) files with data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool PVGUI_DataModel::open( const QString& theName, CAM_Study* theStudy, QStringList theList)
+{
+  bool ret = false;
+  LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( theStudy );
+  if ( !aDoc )
+    return false;
+
+  LightApp_DataModel::open( theName, aDoc, theList );
+  publishComponent(theStudy);
+
+  // The first list item contains path to a temporary
+  // directory, where the persistent files was placed
+  if ( theList.count() > 0 ) {
+    QString aTmpDir ( theList[0] );
+
+    if ( theList.size() >= 2 ) {
+      myStudyURL = theName;
+      QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + theList[1];
+//      std::cout << "open: tmp dir is" << aFullPath.toStdString() << std::endl;
+      PVGUI_Module * mod = dynamic_cast<PVGUI_Module *>(getModule());
+      if (mod)
+        {
+          bool doRestore = false;
+          QStringList srcFilesEmpty;
+          createAndCheckRestoreFlag(aTmpDir, srcFilesEmpty, /*out*/doRestore);
+          if(doRestore)
+            {
+              // Update state file so that it points to new dir:
+              processAllFilesInState(aFullPath, srcFilesEmpty, aTmpDir.toStdString().c_str(), true);
+            }
+
+          mod->loadParaviewState(aFullPath);
+          ret = true;
+        }
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+/*!
+ * Create an empty file indicating whether source files in the pipeline should be restored.
+ */
+bool PVGUI_DataModel::createAndCheckRestoreFlag(const QString& tmpdir, QStringList& listOfFiles, bool & alreadyThere)
+{
+  QString aFullPath = SUIT_Tools::addSlash( tmpdir ) + RESTORE_FLAG_FILE;
+  QFile f(aFullPath);
+  if (f.exists())
+    {
+    alreadyThere = true;
+    return true;
+    }
+  else
+    {
+      bool ret = f.open(QFile::WriteOnly);
+      if (ret)
+        {
+        f.close();
+        listOfFiles << RESTORE_FLAG_FILE;
+        }
+      return ret;
+    }
+}
+
+
+/*!
+  \brief Save data model (write ParaView pipeline to the files).
+  \param theListOfFiles returning list of the (temporary) files with saved data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool PVGUI_DataModel::save( QStringList& theListOfFiles)
+{
+  bool isMultiFile = false; // TODO: decide, how to access this parameter
+  bool ret = false;
+
+  LightApp_DataModel::save( theListOfFiles );
+
+  LightApp_Study* study = dynamic_cast<LightApp_Study*>( getModule()->getApp()->activeStudy() );
+  QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
+//  std::cout << "save: tmp dir is" << aTmpDir.toStdString() << std::endl;
+
+  QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_PARAVIS.pvsm";
+  QString aFullPath = aTmpDir + aFileName;
+
+  PVGUI_Module * mod = dynamic_cast<PVGUI_Module *>(getModule());
+  QStringList srcFiles;
+  if (mod)
+    {
+      // Create ParaView state file:
+      mod->saveParaviewState(aFullPath.toStdString().c_str());
+
+      // add this to the list to be saved:
+      theListOfFiles << aTmpDir;
+      theListOfFiles << aFileName;
+
+      // Potentially save referenced files:
+      SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
+      int aSavingType = aResourceMgr->integerValue( "PARAVIS", "savestate_type", 0 );
+
+      bool unused;
+      bool isBuiltIn = false;
+      pqServer* aServer;
+      QString nullS;
+
+      switch (aSavingType) {
+        case 0: // Save referenced files when they are accessible
+          createAndCheckRestoreFlag(aTmpDir, theListOfFiles ,unused);
+          processAllFilesInState(aFullPath, srcFiles, nullS, false);
+          break;
+        case 1: // Save referenced files only if this is the builtin server
+          aServer = pqApplicationCore::instance()->getActiveServer();
+          if (aServer)
+            isBuiltIn = !aServer->isRemote();
+          if(isBuiltIn)
+            {
+              createAndCheckRestoreFlag(aTmpDir, theListOfFiles, unused);
+              processAllFilesInState(aFullPath, srcFiles, nullS, false);
+            }
+          break;
+        case 2: // Do not save referenced file
+          break;
+        default:
+          break;
+      }
+
+      ret = true;
+    }
+  // Copying valid source files to the temp directory and adding them to the list
+  foreach(QString fName, srcFiles)
+  {
+    QFile fSrc(fName);
+    if (fSrc.exists())
+      {
+        QFileInfo inf(fSrc);
+        QString newPth(SUIT_Tools::addSlash( aTmpDir ) + inf.fileName());
+        if (fSrc.copy(newPth))
+          {
+            theListOfFiles << inf.fileName();
+          }
+      }
+  }
+
+  return ret;
+}
+
+/*!
+  \brief Save data model (write ParaView pipeline state to the files).
+  \param url study file path
+  \param study study pointer
+  \param theListOfFiles returning list of the (temporary) files with saved data
+  \return operation status (\c true on success and \c false on error)
+*/
+bool PVGUI_DataModel::saveAs( const QString& url, CAM_Study* /*study*/, QStringList& theListOfFiles)
+{
+  myStudyURL = url;
+  return save( theListOfFiles );
+}