Salome HOME
Merge 'master' branch into V9_dev
[modules/paravis.git] / src / PVGUI / PVGUI_DataModel.cxx
1 // Copyright (C) 2010-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Adrien Bruneton (CEA)
20 //
21
22 //Local includes
23 #include "PVGUI_DataModel.h"
24 #include "PVGUI_Module.h"
25
26 // GUI includes
27 #include <LightApp_Study.h>
28 #include <LightApp_Module.h>
29 #include <LightApp_Application.h>
30 #include <LightApp_DataModel.h>
31 #include <CAM_DataObject.h>
32 #include <SUIT_Tools.h>
33 #include <SUIT_Session.h>
34 #include <SUIT_ResourceMgr.h>
35
36 // KERNEL
37 #include <utilities.h>
38
39 // Qt includes
40 #include <QFile>
41 #include <QFileInfo>
42 #include <QTextStream>
43 #include <QDomNode>
44
45 // ParaView include
46 #include <pqApplicationCore.h>
47 #include <pqServer.h>
48
49 const QString PVGUI_DataModel::RESTORE_FLAG_FILE = "do_restore_paravis_references.par";
50
51 /*!
52  * XML processing functions to handle the PV state file.
53  */
54 namespace {
55
56   void processElements(QDomNode& thePropertyNode, QStringList& theFileNames,
57                        const QString& theNewPath, bool theRestore)
58   {
59     QDomNode aElementNode = thePropertyNode.firstChild();
60     while (aElementNode.isElement()) {
61       QDomElement aElement = aElementNode.toElement();
62       if (aElement.tagName() == "Element") {
63         QString aIndex = aElement.attribute("index");
64         if (aIndex == "0") {
65           QString aValue = aElement.attribute("value");
66           if (!aValue.isNull()) {
67             if (theNewPath.isEmpty()) {
68               QFileInfo aFInfo(aValue);
69               if (aFInfo.exists()) {
70                 theFileNames<<aValue;
71                 aElement.setAttribute("value", aFInfo.fileName());
72               }
73               break;
74             } else {
75               if (theRestore)
76                 aElement.setAttribute("value", QString(theNewPath) + aValue);
77             }
78           }
79         }
80       }
81       aElementNode = aElementNode.nextSibling();
82     }
83   }
84
85   void processProperties(QDomNode& theProxyNode, QStringList& theFileNames,
86                          const QString& theNewPath, bool theRestore)
87   {
88     QDomNode aPropertyNode = theProxyNode.firstChild();
89     while (aPropertyNode.isElement()) {
90       QDomElement aProperty = aPropertyNode.toElement();
91       QString aName = aProperty.attribute("name");
92       if ((aName == "FileName") || (aName == "FileNameInfo") || (aName == "FileNames")) {
93         processElements(aPropertyNode, theFileNames, theNewPath, theRestore);
94       }
95       aPropertyNode = aPropertyNode.nextSibling();
96     }
97   }
98
99
100   void processProxies(QDomNode& theNode, QStringList& theFileNames,
101                       const QString& theNewPath, bool theRestore)
102   {
103     QDomNode aProxyNode = theNode.firstChild();
104     while (aProxyNode.isElement()) {
105       QDomElement aProxy = aProxyNode.toElement();
106       if (aProxy.tagName() == "Proxy") {
107         QString aGroup = aProxy.attribute("group");
108         if (aGroup == "sources") {
109           processProperties(aProxyNode, theFileNames, theNewPath, theRestore);
110         }
111       }
112       aProxyNode = aProxyNode.nextSibling();
113     }
114   }
115
116   bool processAllFilesInState(const QString& aFileName, QStringList& theFileNames,
117                               const QString& theNewPath, bool theRestore)
118   {
119     QFile aFile(aFileName);
120     if (!aFile.open(QFile::ReadOnly)) {
121       MESSAGE("Can't open state file "<<aFileName.toStdString());
122       return false;
123     }
124     QDomDocument aDoc;
125     bool aRes = aDoc.setContent(&aFile);
126     aFile.close();
127
128     if (!aRes) {
129       MESSAGE("File "<<aFileName.toStdString()<<" is not XML document");
130       return false;
131     }
132
133     QDomElement aRoot = aDoc.documentElement();
134     if ( aRoot.isNull() ) {
135       MESSAGE( "Invalid XML root" );
136       return false;
137     }
138
139     QDomNode aNode = aRoot.firstChild();
140     while (aRes  && !aNode.isNull() ) {
141       aRes = aNode.isElement();
142       if ( aRes ) {
143         QDomElement aSection = aNode.toElement();
144         if (aSection.tagName() == "ServerManagerState") {
145           processProxies(aNode, theFileNames, theNewPath, theRestore);
146         }
147       }
148       aNode = aNode.nextSibling();
149     }
150     if (!aFile.open(QFile::WriteOnly | QFile::Truncate)) {
151       MESSAGE("Can't open state file "<<aFileName.toStdString()<<" for writing");
152       return false;
153     }
154     QTextStream out(&aFile);
155     aDoc.save(out, 2);
156     aFile.close();
157
158     return true;
159   }
160 }
161
162
163 PVGUI_DataModel::PVGUI_DataModel( PVGUI_Module* theModule ):
164   LightApp_DataModel(theModule),
165   myStudyURL("")
166 {}
167
168 PVGUI_DataModel::~PVGUI_DataModel()
169 {}
170
171 bool PVGUI_DataModel::create( CAM_Study* theStudy) {
172   bool res = LightApp_DataModel::create(theStudy);
173   publishComponent(theStudy);
174   return res;
175 }
176
177 void PVGUI_DataModel::publishComponent( CAM_Study* theStudy ) {
178   LightApp_Study* study = dynamic_cast<LightApp_Study*>( theStudy );
179   CAM_ModuleObject *aModelRoot = dynamic_cast<CAM_ModuleObject*>( root());
180   if( study && aModelRoot == NULL ) {
181     aModelRoot = createModuleObject( theStudy->root() );
182     aModelRoot->setDataModel( this );
183     setRoot(aModelRoot);
184   }
185 }
186
187 bool PVGUI_DataModel::dumpPython( const QString& path, CAM_Study* std,
188             bool isMultiFile, QStringList& listOfFiles)
189 {
190
191   LightApp_Study* study = dynamic_cast<LightApp_Study*>( std );
192   if(!study)
193     return false;
194
195   std::string aTmpDir = study->GetTmpDir( path.toLatin1().constData(), isMultiFile );
196   std::string aFile = aTmpDir + "paravis_dump.tmp";
197
198   listOfFiles.append(aTmpDir.c_str());
199   listOfFiles.append("paravis_dump.tmp");
200
201   QFile file(aFile.c_str());
202   if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
203     return false;
204
205   PVGUI_Module * mod = (PVGUI_Module *) getModule();
206   QString trace(mod->getTraceString());
207
208   if (isMultiFile)
209     {
210       QStringList abuffer;
211       abuffer.push_back(QString("def RebuildData():"));
212       QStringList lst(trace.split("\n"));
213       foreach(QString elem, lst)
214         {
215           QString s = "  " + elem;
216           abuffer.push_back(s);
217         }
218       abuffer.push_back(QString("  pass"));
219       trace = abuffer.join("\n");
220     }
221   QTextStream out(&file);
222   out << trace.toStdString().c_str() << "\n";
223   out.flush();
224   file.close();
225
226   return true;
227 }
228
229 /*!
230   \brief Open data model (read ParaView pipeline state from the files).
231   \param theName study file path
232   \param theStudy study pointer
233   \param theList list of the (temporary) files with data
234   \return operation status (\c true on success and \c false on error)
235 */
236 bool PVGUI_DataModel::open( const QString& theName, CAM_Study* theStudy, QStringList theList)
237 {
238   bool ret = false;
239   LightApp_Study* aDoc = dynamic_cast<LightApp_Study*>( theStudy );
240   if ( !aDoc )
241     return false;
242
243   LightApp_DataModel::open( theName, aDoc, theList );
244   publishComponent(theStudy);
245
246   // The first list item contains path to a temporary
247   // directory, where the persistent files was placed
248   if ( theList.count() > 0 ) {
249     QString aTmpDir ( theList[0] );
250
251     if ( theList.size() >= 2 ) {
252       myStudyURL = theName;
253       QString aFullPath = SUIT_Tools::addSlash( aTmpDir ) + theList[1];
254 //      std::cout << "open: tmp dir is" << aFullPath.toStdString() << std::endl;
255       PVGUI_Module * mod = dynamic_cast<PVGUI_Module *>(getModule());
256       if (mod)
257         {
258           bool doRestore = false;
259           QStringList srcFilesEmpty;
260           createAndCheckRestoreFlag(aTmpDir, srcFilesEmpty, /*out*/doRestore);
261           if(doRestore)
262             {
263               // Update state file so that it points to new dir:
264               processAllFilesInState(aFullPath, srcFilesEmpty, aTmpDir.toStdString().c_str(), true);
265             }
266
267           mod->loadParaviewState(aFullPath);
268           ret = true;
269         }
270       ret = true;
271     }
272   }
273
274   return ret;
275 }
276
277 /*!
278  * Create an empty file indicating whether source files in the pipeline should be restored.
279  */
280 bool PVGUI_DataModel::createAndCheckRestoreFlag(const QString& tmpdir, QStringList& listOfFiles, bool & alreadyThere)
281 {
282   QString aFullPath = SUIT_Tools::addSlash( tmpdir ) + RESTORE_FLAG_FILE;
283   QFile f(aFullPath);
284   if (f.exists())
285     {
286     alreadyThere = true;
287     return true;
288     }
289   else
290     {
291       bool ret = f.open(QFile::WriteOnly);
292       if (ret)
293         {
294         f.close();
295         listOfFiles << RESTORE_FLAG_FILE;
296         }
297       return ret;
298     }
299 }
300
301
302 /*!
303   \brief Save data model (write ParaView pipeline to the files).
304   \param listOfFiles returning list of the (temporary) files with saved data
305   \return operation status (\c true on success and \c false on error)
306 */
307 bool PVGUI_DataModel::save( QStringList& theListOfFiles)
308 {
309   bool isMultiFile = false; // TODO: decide, how to access this parameter
310   bool ret = false;
311
312   LightApp_DataModel::save( theListOfFiles );
313
314   LightApp_Study* study = dynamic_cast<LightApp_Study*>( getModule()->getApp()->activeStudy() );
315   QString aTmpDir = study->GetTmpDir( myStudyURL.toLatin1(), isMultiFile ).c_str();
316 //  std::cout << "save: tmp dir is" << aTmpDir.toStdString() << std::endl;
317
318   QString aFileName = SUIT_Tools::file( myStudyURL, false ) + "_PARAVIS.pvsm";
319   QString aFullPath = aTmpDir + aFileName;
320
321   PVGUI_Module * mod = dynamic_cast<PVGUI_Module *>(getModule());
322   QStringList srcFiles;
323   if (mod)
324     {
325       // Create ParaView state file:
326       mod->saveParaviewState(aFullPath.toStdString().c_str());
327
328       // add this to the list to be saved:
329       theListOfFiles << aTmpDir;
330       theListOfFiles << aFileName;
331
332       // Potentially save referenced files:
333       SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
334       int aSavingType = aResourceMgr->integerValue( "PARAVIS", "savestate_type", 0 );
335
336       bool unused;
337       bool isBuiltIn = false;
338       pqServer* aServer;
339       QString nullS;
340
341       switch (aSavingType) {
342         case 0: // Save referenced files when they are accessible
343           createAndCheckRestoreFlag(aTmpDir, theListOfFiles ,unused);
344           processAllFilesInState(aFullPath, srcFiles, nullS, false);
345           break;
346         case 1: // Save referenced files only if this is the builtin server
347           aServer = pqApplicationCore::instance()->getActiveServer();
348           if (aServer)
349             isBuiltIn = !aServer->isRemote();
350           if(isBuiltIn)
351             {
352               createAndCheckRestoreFlag(aTmpDir, theListOfFiles, unused);
353               processAllFilesInState(aFullPath, srcFiles, nullS, false);
354             }
355           break;
356         case 2: // Do not save referenced file
357           break;
358         default:
359           break;
360       }
361
362       ret = true;
363     }
364   // Copying valid source files to the temp directory and adding them to the list
365   foreach(QString fName, srcFiles)
366   {
367     QFile fSrc(fName);
368     if (fSrc.exists())
369       {
370         QFileInfo inf(fSrc);
371         QString newPth(SUIT_Tools::addSlash( aTmpDir ) + inf.fileName());
372         if (fSrc.copy(newPth))
373           {
374             theListOfFiles << inf.fileName();
375           }
376       }
377   }
378
379   return ret;
380 }
381
382 /*!
383   \brief Save data model (write ParaView pipeline state to the files).
384   \param url study file path
385   \param study study pointer
386   \param listOfFiles returning list of the (temporary) files with saved data
387   \return operation status (\c true on success and \c false on error)
388 */
389 bool PVGUI_DataModel::saveAs( const QString& url, CAM_Study* study, QStringList& theListOfFiles)
390 {
391   myStudyURL = url;
392   return save( theListOfFiles );
393 }