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