]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
[bos#35161][EDF](2023-T1) Automatic backup - initial commit
authormbs <martin.bernhard@opencascade.com>
Sat, 9 Dec 2023 22:09:53 +0000 (22:09 +0000)
committermbs <martin.bernhard@opencascade.com>
Fri, 19 Jan 2024 23:11:08 +0000 (23:11 +0000)
17 files changed:
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/Model/Model_Session.cpp
src/Model/Model_Session.h
src/ModelAPI/ModelAPI_Session.h
src/ModuleBase/ModuleBase_Preferences.cpp
src/SHAPERGUI/CMakeLists.txt
src/SHAPERGUI/SHAPERGUI.cpp
src/SHAPERGUI/SHAPERGUI.h
src/SHAPERGUI/SHAPERGUI_CheckBackup.cpp [new file with mode: 0644]
src/SHAPERGUI/SHAPERGUI_CheckBackup.h [new file with mode: 0644]
src/SHAPERGUI/SHAPERGUI_DataModel.cpp
src/SHAPERGUI/SHAPERGUI_DataModel.h
src/SHAPERGUI/SHAPERGUI_msg_fr.ts
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h
test.hdfs/testme.py

index 5f8b9fe5352101baec03b6e592d4e7737e744bd9..df27cd5d1754b2fb3bb42da27292bfc1fa5b21e4 100644 (file)
 # define _separator_ '/'
 #endif
 
+//---------------------------------------------------------
+#define USE_DEBUG
+#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "Model_Document"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
 static const int UNDO_LIMIT = 1000;  // number of possible undo operations (big for sketcher)
 
 static const int TAG_GENERAL = 1;  // general properties tag
@@ -448,6 +457,7 @@ static bool saveDocument(Handle(Model_Application) theApp,
                          Handle(TDocStd_Document) theDoc,
                          const TCollection_ExtendedString& theFilename)
 {
+  DBG_FUNC();
   PCDM_StoreStatus aStatus;
   try {
     // create the directory to save the document
@@ -485,8 +495,15 @@ static bool saveDocument(Handle(Model_Application) theApp,
 }
 
 bool Model_Document::save(
-  const char* theDirName, const char* theFileName, std::list<std::string>& theResults)
+  const char* theDirName, const char* theFileName,
+  std::list<std::string>& theResults,
+  bool doBackup/*=false*/)
 {
+  DBG_FUN();
+  ARG(theDirName);
+  ARG(theFileName);
+  ARG(doBackup);
+
   // if the history line is not in the end, move it to the end before save, otherwise
   // problems with results restore and (the most important) naming problems will appear
   // due to change evolution to SELECTION (problems in NamedShape and Name)
index 1dec08f14434d02d8557ee83fd2b936cb8f6dabe..0e8670e85662a38fb9313a0218de64b3235b6d6c 100644 (file)
@@ -73,7 +73,7 @@ class Model_Document : public ModelAPI_Document
   //! \param theResults the result full file names that were stored by "save"
   //! \returns true if file was stored successfully
   MODEL_EXPORT virtual bool save(
-    const char* theDirName, const char* theFileName, std::list<std::string>& theResults);
+    const char* theDirName, const char* theFileName, std::list<std::string>& theResults, bool doBackup=false);
 
   //! Export the list of features to the file
   //! \param theFilename path to save the file
index b80cdd8eaf92737a34e09d233bece4bb6f4f0dc6..bc89ab43a5393b0dd081aea0e6bfa1158c9639b3 100644 (file)
 
 #include <TopoDS_Shape.hxx>
 
+//---------------------------------------------------------
+#define USE_DEBUG
+#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "Model_Session"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
 static Model_Session* myImpl = new Model_Session();
 
 // to redirect all calls to the root document
@@ -65,9 +74,12 @@ bool Model_Session::load(const char* theFileName)
   return aRes;
 }
 
-bool Model_Session::save(const char* theFileName, std::list<std::string>& theResults)
+bool Model_Session::save(const char* theFileName, std::list<std::string>& theResults, bool doBackup=false)
 {
-  return ROOT_DOC->save(theFileName, "root", theResults);
+  DBG_FUN();
+  ARG(theFileName);
+  ARG(doBackup);
+  return ROOT_DOC->save(theFileName, "root", theResults, doBackup);
 }
 
 void Model_Session::closeAll()
index c74f9528632a2a71d89f53a254f25c06a2730906..5a5db88650fb7f36ddcf36b8dc45e3263241d098 100644 (file)
@@ -66,7 +66,7 @@ class Model_Session : public ModelAPI_Session, public Events_Listener
   //! \param theFileName full name of the file to store
   //! \param theResults the result full file names that were stored by "save"
   //! \returns true if file was stored successfully
-  MODEL_EXPORT virtual bool save(const char* theFileName, std::list<std::string>& theResults);
+  MODEL_EXPORT virtual bool save(const char* theFileName, std::list<std::string>& theResults, bool dobackup=false);
 
   //! Closes all documents
   MODEL_EXPORT virtual void closeAll();
index 566158c60274cc7502c0766f8453db958385555f..732884eff539028e4c7f38ebfbebb45df0c6d366 100644 (file)
@@ -59,7 +59,7 @@ protected:
   //! \param theFileName full name of the file to store
   //! \param theResults the result full file names that were stored by "save"
   //! \returns true if file was stored successfully
-  virtual bool save(const char* theFileName, std::list<std::string>& theResults) = 0;
+  virtual bool save(const char* theFileName, std::list<std::string>& theResults, bool isBackup=false) = 0;
 
   //! Closes all documents
   virtual void closeAll() = 0;
index e7827fbad873d2ee0ecaf5213808f449ea63d8dc..38aaf1fc6d14ef7c80ce5ad0378e2ffda989f9ca 100644 (file)
@@ -220,6 +220,35 @@ void ModuleBase_Preferences::createGeneralTab(ModuleBase_IPrefMgr* thePref, int
                                   "part_visualization_study");
   thePref->setItemProperty("strings", visuItemList, visuId);
   thePref->setItemProperty("indexes", visuIdList, visuId);
+
+#if 1
+  // Group related to automatic backup
+  group = thePref->addPreference(QObject::tr("Automatically backup a study"), generalTab,
+                                 SUIT_PreferenceMgr::Auto, QString(), QString());
+
+  thePref->addPreference(QObject::tr("Enable automatic backup"), group, SUIT_PreferenceMgr::Bool,
+                         ModuleBase_Preferences::GENERAL_SECTION, "use_auto_backup");
+
+  int delay = thePref->addPreference(QObject::tr("Backup Interval" ), group, SUIT_PreferenceMgr::IntSpin,
+                                     ModuleBase_Preferences::GENERAL_SECTION, "backup_interval" );
+  thePref->setItemProperty( "min", 5, delay );
+  thePref->setItemProperty( "max", 1440, delay );
+  thePref->setItemProperty( "suffix", " min", delay );
+
+  int folderPref = thePref->addPreference(QObject::tr("Backup Folder"), group, SUIT_PreferenceMgr::File, "backup_folder", QString()/*platform*/);
+  thePref->setItemProperty( "mode", Qtx::PT_Directory, folderPref );
+
+  visuItemList.clear();
+  visuItemList << QObject::tr("Store last backup only")
+               << QObject::tr("Store full backup history");
+  visuIdList.clear();
+  visuIdList << 0 << 1;
+  visuId = thePref->addPreference(QObject::tr("Backup Storage"), group, SUIT_PreferenceMgr::Selector,
+                                  ModuleBase_Preferences::GENERAL_SECTION,
+                                  "auto_backup_storage");
+  thePref->setItemProperty("strings", visuItemList, visuId);
+  thePref->setItemProperty("indexes", visuIdList, visuId);
+#endif
 }
 
 void ModuleBase_Preferences::updateSketchTab(ModuleBase_IPrefMgr* thePref, int thePageId)
index efc731ca2ffd87c473c486e155f1ee1396b9141b..2b1886b1b9b98a2ab67dd788f34f24e00fc787c3 100644 (file)
@@ -30,6 +30,7 @@ SET(UPDATE_TRANSLATION OFF)
 SET(PROJECT_HEADERS
     SHAPER_SHAPERGUI.h
     SHAPERGUI.h
+    SHAPERGUI_CheckBackup.h
     SHAPERGUI_DataModel.h
     SHAPERGUI_OCCSelector.h
     SHAPERGUI_SalomeViewer.h
@@ -39,6 +40,7 @@ SET(PROJECT_HEADERS
 
 SET(PROJECT_MOC_HEADERS
     SHAPERGUI.h
+    SHAPERGUI_CheckBackup.h
     SHAPERGUI_DataModel.h
     SHAPERGUI_NestedButton.h
     SHAPERGUI_SalomeViewer.h
@@ -50,6 +52,7 @@ QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
 
 SET(PROJECT_SOURCES
     SHAPERGUI.cpp
+    SHAPERGUI_CheckBackup.cpp
     SHAPERGUI_DataModel.cpp
     SHAPERGUI_OCCSelector.cpp
     SHAPERGUI_SalomeViewer.cpp
index b1857383834035a7df4e394e69f885e140c867ea..4b61fa21d6233d24cf9a1dabd50b8b2fdb15b5be 100644 (file)
@@ -18,6 +18,7 @@
 //
 
 #include "SHAPERGUI.h"
+#include "SHAPERGUI_CheckBackup.h"
 #include "SHAPERGUI_DataModel.h"
 #include "SHAPERGUI_OCCSelector.h"
 #include "SHAPERGUI_NestedButton.h"
 #include <QTimer>
 #include <QMenu>
 #include <QToolBar>
+#include <QFileInfo>
+#include <QDir>
+
+#include <chrono>
+#include <future>
+#include <thread>
 
 #include <ModelAPI_Session.h>
 #include <Events_MessageBool.h>
 
+//---------------------------------------------------------
+#define USE_DEBUG
+//#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "SHAPERGUI"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
 #if OCC_VERSION_HEX < 0x070400
   #define SALOME_PATCH_FOR_CTRL_WHEEL
 #endif
@@ -136,6 +152,13 @@ private:
 };
 
 
+// static void DumpOperations(XGUI_Workshop *wshop)
+// {
+//   XGUI_OperationMgr *aOpMgr = wshop->operationMgr();
+//   if (!aOpMgr) return;
+//   QStringList operations = aOpMgr->operationList();
+//   SHOW(operations);
+// }
 
 
 //******************************************************
@@ -145,6 +168,7 @@ SHAPERGUI::SHAPERGUI()
   myInspectionPanel(0), myIsFacesPanelVisible(false), myIsToolbarsModified(false),
   myAxisArrowRate(-1)
 {
+  DBG_FUN();
   myWorkshop = new XGUI_Workshop(this);
   connect(myWorkshop, SIGNAL(commandStatusUpdated()),
           this, SLOT(onUpdateCommandStatus()));
@@ -153,6 +177,12 @@ SHAPERGUI::SHAPERGUI()
 
   ModuleBase_Preferences::setResourceMgr(application()->resourceMgr());
 
+  // initialize backup timer
+  myBackupTimer = new QTimer( this );
+  myBackupTimer->setSingleShot( true );
+  connect( myBackupTimer, SIGNAL( timeout() ), this, SLOT( onBackupDoc() ) );
+  connect( this, SIGNAL( backupDone(QString,bool) ), this, SLOT( onBackupDone(QString,bool) ));
+
   // It will be called in XGUI_Workshop::startApplication
   // ModuleBase_Preferences::loadCustomProps();
 }
@@ -160,6 +190,7 @@ SHAPERGUI::SHAPERGUI()
 //******************************************************
 SHAPERGUI::~SHAPERGUI()
 {
+  DBG_FUN();
   delete myWorkshop;
   delete myProxyViewer;
 }
@@ -167,6 +198,7 @@ SHAPERGUI::~SHAPERGUI()
 //******************************************************
 void SHAPERGUI::initialize(CAM_Application* theApp)
 {
+  DBG_FUN();
   LightApp_Module::initialize(theApp);
 
   myWorkshop->startApplication();
@@ -281,6 +313,7 @@ void SHAPERGUI::viewManagers(QStringList& theList) const
 //******************************************************
 bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
 {
+  DBG_FUN();
   ModelAPI_Session::get()->moduleDocument(); // initialize a root document if not done yet
 
   // this must be done in the initialization and in activation (on the second activation
@@ -383,6 +416,22 @@ bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
           this, SLOT(onSaveDocByShaper()));
   connect(getApp()->action(LightApp_Application::FileSaveAsId), SIGNAL(triggered(bool)),
           this, SLOT(onSaveAsDocByShaper()));
+
+  //MBS:
+  SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
+  if ( aResMgr && application()->activeStudy() ) {
+    bool useBackup = aResMgr->booleanValue( "General", "use_auto_backup", true );
+    if (useBackup) {
+      int backupInterval = aResMgr->integerValue( "General", "backup_interval", 1 );
+      if ( backupInterval > 0 ){
+        backupInterval = 1;
+        MSGEL("....starting BackupTimer: interval=" << backupInterval);
+        myBackupTimer->start( backupInterval*60000 );
+      }
+    }
+  }
+  //connect();
+
   updateInfoPanel();
 
   //connect(myWorkshop->operationMgr(), SIGNAL(operationResumed(ModuleBase_Operation*)),
@@ -400,6 +449,7 @@ bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
 //******************************************************
 void SHAPERGUI::hideInternalWindows()
 {
+  DBG_FUN();
   myProxyViewer->activateViewer(false);
   setMenuShown(false);
   setToolShown(false);
@@ -428,14 +478,17 @@ void SHAPERGUI::hideInternalWindows()
 //******************************************************
 bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
 {
+  DBG_FUN();
   saveToolbarsConfig();
   myWorkshop->deactivateModule();
 
+  MSGEL("....stopping BackupTimer");
+  myBackupTimer->stop();
+
   myIsInspectionVisible = myInspectionPanel->isVisible();
   myIsFacesPanelVisible = myWorkshop->facesPanel()->isVisible();
   hideInternalWindows();
 
-
   // the active operation should be stopped for the next activation.
   // There should not be active operation and visualized preview.
   // Abort operation should be performed before the selection's remove
@@ -530,21 +583,77 @@ static void onOperationGeneric( ModuleBase_Operation* theOperation,
                                            event );
 }
 
+class WaitBackupResetter {
+public:
+  WaitBackupResetter(XGUI_Workshop *theWshop)
+    :myWorkshop(theWshop)
+  {
+  }
+  WaitBackupResetter() = delete;
+  ~WaitBackupResetter()
+  {
+    if (myWorkshop)
+    {
+      myWorkshop->setWaitForBackup(false);
+      myWorkshop = nullptr;
+    }
+  }
+private:
+  XGUI_Workshop *myWorkshop;
+};
+
 //******************************************************
 void SHAPERGUI::onOperationCommitted(ModuleBase_Operation* theOperation)
 {
+  DBG_FUN();
+  SHOW(theOperation->id());
+
   onOperationGeneric(theOperation, moduleName(), "committed");
+
+  if (myWorkshop && myWorkshop->waitForBackup()) 
+  {
+    XGUI_OperationMgr *operMgr = myWorkshop->operationMgr();
+    if (operMgr && operMgr->hasOperation())
+    {
+      // If the user is still running an operation, e.g. we left the line creation
+      // during sketch creation, do not yet create the backup
+      std::cout << "---> There are still active operations!" << std::endl;
+      return;
+    }
+    // There are no more active operations => we can now do the backup
+    WaitBackupResetter _resetter(myWorkshop);
+    onBackupDoc();
+  }
 }
 
 //******************************************************
 void SHAPERGUI::onOperationAborted(ModuleBase_Operation* theOperation)
 {
+  DBG_FUN();
+  SHOW(theOperation->id());
+
   onOperationGeneric(theOperation, moduleName(), "aborted");
+
+  if (myWorkshop && myWorkshop->waitForBackup()) 
+  {
+    XGUI_OperationMgr *operMgr = myWorkshop->operationMgr();
+    if (operMgr && operMgr->hasOperation())
+    {
+      // If the user is still running an operation, e.g. we left the line creation
+      // during sketch creation, do not yet create the backup
+      std::cout << "---> There are still active operations!" << std::endl;
+      return;
+    }
+    // There are no more active operations => we can now do the backup
+    WaitBackupResetter _resetter(myWorkshop);
+    onBackupDoc();
+  }
 }
 
 //******************************************************
 void SHAPERGUI::onViewManagerAdded(SUIT_ViewManager* theMgr)
 {
+  DBG_FUN();
   if (!mySelector) {
     mySelector = createSelector(theMgr);
     myWorkshop->selectionActivate()->updateSelectionFilters();
@@ -565,6 +674,7 @@ void SHAPERGUI::onViewManagerAdded(SUIT_ViewManager* theMgr)
 //******************************************************
 void SHAPERGUI::onViewManagerRemoved(SUIT_ViewManager* theMgr)
 {
+  DBG_FUN();
   if (mySelector) {
     if (theMgr->getType() == OCCViewer_Viewer::Type()) {
       OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
@@ -603,6 +713,7 @@ QtxPopupMgr* SHAPERGUI::popupMgr()
 //******************************************************
 void SHAPERGUI::onDefaultPreferences()
 {
+  DBG_FUN();
   // reset main resources
   ModuleBase_Preferences::resetResourcePreferences(preferences());
   // reset plugin's resources
@@ -614,6 +725,7 @@ void SHAPERGUI::onDefaultPreferences()
 //******************************************************
 void SHAPERGUI::onScriptLoaded()
 {
+  DBG_FUN();
   // this slot is called after processing of the LoadScriptId action of SalomeApp Application
   // Each dumped script contains updateObjBrowser() that creates a new instance of Object
   // Browser. When SHAPER module is active, this browser should not be used. It might be removed
@@ -629,6 +741,7 @@ void SHAPERGUI::onScriptLoaded()
 //******************************************************
 void SHAPERGUI::onSaveDocByShaper()
 {
+  DBG_FUN();
   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
     return;
 
@@ -638,12 +751,153 @@ void SHAPERGUI::onSaveDocByShaper()
 //******************************************************
 void SHAPERGUI::onSaveAsDocByShaper()
 {
+  DBG_FUN();
   if(!workshop()->operationMgr()->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
     return;
 
   getApp()->onSaveAsDoc();
 }
 
+//******************************************************
+void SHAPERGUI::onBackupDoc()
+{
+  DBG_FUN();
+  MSGEL("  ...backing up current study");
+
+  if (myWorkshop && myWorkshop->operationMgr()) 
+  {
+    if (myWorkshop->operationMgr()->hasOperation())
+    {
+      // If the user is running an operation, only do the backup
+      // after the operation has finished (committed or cancelled).
+      myWorkshop->setWaitForBackup();
+      return;
+    }
+    // Run the backup in a separate thread!!
+    myBackupResult = std::async(std::launch::async, [this]{return this->backupDoc();});
+  }
+}
+
+class LockBackupState {
+public:
+  LockBackupState(XGUI_Workshop *wshop) : myWorkshop(wshop)
+  {
+    if (myWorkshop) myWorkshop->setBackupState();
+  }
+  ~LockBackupState()
+  {
+    if (myWorkshop) myWorkshop->setBackupState(false);
+    myWorkshop = nullptr;
+  }
+  XGUI_Workshop *myWorkshop;
+};
+
+//******************************************************
+bool SHAPERGUI::backupDoc()
+{
+  DBG_FUN();
+
+  bool isOk = false;
+#if 0
+  MSGEL("...sleep for 5 seconds");
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  isOk = true;
+  QString aName("/some/file/name.hdf");
+#else
+  SUIT_Study* study = application()->activeStudy();
+  if ( !study )
+    return false;
+
+  // if ( !abortAllOperations() )
+  //   return false;
+
+  LockBackupState lockBackup(myWorkshop);
+
+  QString aName = study->studyName();
+  try
+  {
+    SHOW(aName);
+    if ( aName.isNull() )
+      return false;
+
+    const QChar aSep = QDir::separator();
+
+    QString aFolder("/home/bernhard/backups");
+
+    QDateTime now = QDateTime::currentDateTime();
+    aFolder += aSep + now.toString("yyyyMMdd_hhmmss");
+
+    QDir aDir(aFolder);
+    if (!aDir.exists()) {
+      aDir.mkpath(aFolder);
+      aDir.mkdir(aFolder);
+    }
+
+    if (study->isSaved()) {
+      // Retrieve the filename only from the fullpath
+      QFileInfo fi(aName);
+      aName = fi.completeBaseName();
+    }
+    QString aFullName = aFolder + aSep + aName + QString(".hdf");
+    SHOW(aFullName);
+
+    // Save the study into a single HDF file
+    isOk = study->saveDocumentAs( aFullName, true );
+    if (!isOk){
+      MSGEL("ERR: failed to backup study document");
+      return isOk;
+    }
+
+    // Now, dump the python script
+    LightApp_Study *lightStudy = dynamic_cast<LightApp_Study*>(study);
+    if (!lightStudy)
+      return false;
+
+    aFullName = aFolder + aSep + aName + QString(".py");
+    isOk = lightStudy->dump(aFullName, true, false, false);
+    if (!isOk){
+      MSGEL("ERR: failed to backup python script");
+      return isOk;
+    }
+
+    // Finally start another salome process and reload the saved document & script for verification
+    SHAPERGUI_CheckBackup checkBackup(aFolder, aName);
+    QString testScript("/home/bernhard/backups/checkValidity.py");
+    int aResult = checkBackup.run(testScript);
+    isOk = (aResult == 0);
+  }
+  catch (std::exception &ex)
+  {
+    std::cout << "ERROR: std::exception caught" << std::endl;
+    isOk = false;
+  }
+  catch (...)
+  {
+    std::cout << "ERROR: unknown exception caught" << std::endl;
+    isOk = false;
+  }
+  #endif
+
+  MSGEL("...emit backupDone signal");
+  emit backupDone(aName, isOk);
+  return isOk;
+}
+
+//******************************************************
+void SHAPERGUI::onBackupDone(QString aName, bool aResult)
+{
+  DBG_FUN();
+  ARG(aName);
+  ARG(aResult);
+
+  bool isOk = myBackupResult.get();
+  SHOW(isOk);
+  QFileInfo fi(aName);
+  aName = fi.canonicalPath();
+  SHOW(aName);
+  putInfo( isOk ? tr("Backup done in folder: %1").arg(aName) : tr("Failed to backup active study!"), 5000 );
+}
+
 //******************************************************
 void SHAPERGUI::onUpdateCommandStatus()
 {
@@ -658,6 +912,7 @@ void SHAPERGUI::onUpdateCommandStatus()
 //******************************************************
 SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
 {
+  DBG_FUN();
   if (theMgr->getType() == OCCViewer_Viewer::Type()) {
     OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
 
@@ -697,6 +952,7 @@ SHAPERGUI_OCCSelector* SHAPERGUI::createSelector(SUIT_ViewManager* theMgr)
 //******************************************************
 CAM_DataModel* SHAPERGUI::createDataModel()
 {
+  DBG_FUN();
   return new SHAPERGUI_DataModel(this);
 }
 
@@ -924,6 +1180,7 @@ void SHAPERGUI::contextMenuPopup(const QString& theClient, QMenu* theMenu, QStri
 //******************************************************
 void SHAPERGUI::createPreferences()
 {
+  DBG_FUN();
   LightApp_Preferences* aPref = preferences();
   if (!aPref)
     return;
@@ -1017,6 +1274,9 @@ void SHAPERGUI::createPreferences()
 //******************************************************
 void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& theParam)
 {
+  DBG_FUN();
+  ARG(theSection);
+  ARG(theParam);
   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
   QString aVal = aResMgr->stringValue(theSection, theParam);
   Config_Prop* aProp = Config_PropManager::findProp(theSection.toStdString(),
@@ -1081,11 +1341,33 @@ void SHAPERGUI::preferencesChanged(const QString& theSection, const QString& the
       }
     }
   }
-  else if (theSection == ModuleBase_Preferences::GENERAL_SECTION && theParam == "create_init_part") {
-    bool aCreate = ModuleBase_Preferences::resourceMgr()->booleanValue(
-      ModuleBase_Preferences::GENERAL_SECTION, "create_init_part", true);
-    Events_MessageBool aCreateMsg(Events_Loop::eventByName(EVENT_CREATE_PART_ON_START), aCreate);
-    aCreateMsg.send();
+  else if (theSection == ModuleBase_Preferences::GENERAL_SECTION) {
+    if (theParam == "create_init_part") {
+      bool aCreate = ModuleBase_Preferences::resourceMgr()->booleanValue(
+        ModuleBase_Preferences::GENERAL_SECTION, "create_init_part", true);
+      Events_MessageBool aCreateMsg(Events_Loop::eventByName(EVENT_CREATE_PART_ON_START), aCreate);
+      aCreateMsg.send();
+    }
+    else if (theParam == "use_auto_backup") {
+      bool useBackup = ModuleBase_Preferences::resourceMgr()->booleanValue(
+        ModuleBase_Preferences::GENERAL_SECTION, "use_auto_backup", true);
+      if (useBackup) {
+        int backupInterval = aResMgr->integerValue( ModuleBase_Preferences::GENERAL_SECTION, "backup_interval", 1 );
+        if ( backupInterval > 0 ){
+          backupInterval = 1;
+          MSGEL("....starting BackupTimer: interval=" << backupInterval << " min");
+          myBackupTimer->start( backupInterval*60000 );
+        }
+        else {
+          MSGEL("....stopping backup timer");
+          myBackupTimer->stop();
+        }
+      }
+      else {
+        MSGEL("....stopping backup timer");
+        myBackupTimer->stop();
+      }
+    }
   }
   else if (theSection == ModuleBase_Preferences::VIEWER_SECTION &&
            theParam.startsWith("group_names_"))
@@ -1103,11 +1385,13 @@ void SHAPERGUI::putInfo(const QString& theInfo, const int theMSecs)
 
 bool SHAPERGUI::abortAllOperations()
 {
+  DBG_FUN();
   return workshop()->operationMgr()->abortAllOperations();
 }
 
 void SHAPERGUI::createFeatureActions()
 {
+  DBG_FUN();
   myWorkshop->menuMgr()->createFeatureActions();
 }
 
@@ -1237,6 +1521,7 @@ void SHAPERGUI::updateToolbars(const QMap<QString, QIntList>& theNewToolbars)
 
 void SHAPERGUI::saveToolbarsConfig()
 {
+  DBG_FUN();
   if (!myIsToolbarsModified)
     return;
   // Save toolbars configuration into map
@@ -1285,6 +1570,7 @@ void SHAPERGUI::saveToolbarsConfig()
 
 void SHAPERGUI::loadToolbarsConfig()
 {
+  DBG_FUN();
   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
   QStringList aToolbarNames = aResMgr->parameters(ToolbarsSection);
   if (aToolbarNames.size() == 0)
@@ -1385,6 +1671,7 @@ QIntList SHAPERGUI::getFreeCommands() const
 
 void SHAPERGUI::resetToolbars()
 {
+  DBG_FUN();
   if (!myDefaultToolbars.isEmpty())
     updateToolbars(myDefaultToolbars);
   myIsToolbarsModified = false;
@@ -1394,6 +1681,7 @@ void SHAPERGUI::resetToolbars()
 
 void SHAPERGUI::publishToStudy()
 {
+  DBG_FUN();
   if (isActiveModule() && ModelAPI_Session::get()->hasModuleDocument()) {
     myWorkshop->module()->launchOperation("PublishToStudy", false);
 
index 2a84accc3bc5bf7ddbd571e1a0f086b656a24f1e..173426f822defedfd9425530133a85e6eda9010b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <QList>
 #include <QMap>
+#include <future>
 
 class XGUI_Workshop;
 class SHAPERGUI_OCCSelector;
@@ -177,6 +178,9 @@ Q_OBJECT
 
   virtual void updateInfoPanel();
 
+ signals:
+  void backupDone(QString aName, bool aResult);
+
  public slots:
   /// \brief The method is redefined to connect to the study viewer before the data
   /// model is filled by opened file. This file open will flush redisplay signals for,
@@ -212,6 +216,12 @@ Q_OBJECT
   /// Save application functionality with additional processing of aborting the current operation
   void onSaveAsDocByShaper();
 
+  /// Backup document functionality with additional file validation
+  void onBackupDoc();
+
+  /// Document has been backed-up
+  void onBackupDone(QString aName, bool aResult);
+
   /// Obtains the current application and updates its actions
   void onUpdateCommandStatus();
 
@@ -228,6 +238,8 @@ Q_OBJECT
   /// Abort all operations
   virtual bool abortAllOperations();
 
+  bool backupDoc();
+
 private slots:
   void onWhatIs(bool isToggled);
 
@@ -306,6 +318,9 @@ private slots:
   Handle(Graphic3d_AspectMarker3d) myHighlightPointAspect;
 
   double myAxisArrowRate;
+
+  QTimer*   myBackupTimer;
+  std::future<bool> myBackupResult;
 };
 
 #endif
diff --git a/src/SHAPERGUI/SHAPERGUI_CheckBackup.cpp b/src/SHAPERGUI/SHAPERGUI_CheckBackup.cpp
new file mode 100644 (file)
index 0000000..b5e643e
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright (C) 2023  CEA, EDF, OPEN CASCADE SAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SHAPERGUI_CheckBackup.h"
+#include <QDir>
+#include <QFileInfo>
+#include <QStringList>
+
+//---------------------------------------------------------
+#define USE_DEBUG
+//#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "SHAPERGUI_CheckBackup"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
+
+
+SHAPERGUI_CheckBackup::SHAPERGUI_CheckBackup(const QString &theFolder, const QString &theBaseName)
+  : myProcess(nullptr)
+  , myFolder(theFolder)
+  , myBaseName(theBaseName)
+{
+  DBG_FUN();
+  ARG(theFolder);
+  ARG(theBaseName);
+}
+
+
+int SHAPERGUI_CheckBackup::run(const QString &theTestScript)
+{
+  DBG_FUN();
+  ARG(theTestScript);
+
+  int aResult = 0;
+  if (myProcess)
+    return 1;
+
+  QString aProgName = std::getenv("PYTHONBIN");
+  if (aProgName.isEmpty())
+    aProgName = "python3";
+
+  const QChar aSep = QDir::separator();
+
+  QString testBackup("test_backup.py");
+  QStringList dirs;
+#if 0
+  dirs << QString(std::getenv("SHAPER_ROOT_DIR"))
+       << QString("bin")
+       << QString("salome")
+       << testBackup;
+#else
+  dirs << QString(std::getenv("HOME"))
+       << QString("S2")
+       << QString("SALOME-MBS-DB11")
+       << testBackup;
+#endif
+  QString scriptName = dirs.join( QDir::separator() );
+
+  QStringList args;
+  args << scriptName << myFolder << myBaseName << theTestScript;
+
+  myProcess = new QProcess(this);
+  if (!myProcess)
+    return 2;
+
+  connect(myProcess, SIGNAL(started()), this, SLOT(procStarted()));
+  connect(myProcess, SIGNAL(error(QProcess::ProcessError)), this,
+          SLOT(procError(QProcess::ProcessError)));
+  connect(myProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this,
+          SLOT(procFinished(int, QProcess::ExitStatus)));
+
+  SHOW(aProgName);
+  SHOW(args);
+  myProcess->setStandardOutputFile((QStringList() << myFolder << myBaseName+".log").join(aSep));
+  myProcess->start(aProgName, args);
+  myProcess->waitForFinished(300000);
+  int exitStat = myProcess->exitStatus();
+  SHOW(exitStat);
+  int exitCode = myProcess->exitCode();
+  SHOW(exitCode);
+  if (exitStat == 0/*NormalExit*/ && exitCode != 0) 
+    aResult = exitCode;
+  else if (exitStat == -1/*CrashExit*/)
+    aResult = 99;
+  myProcess->deleteLater();
+
+  return 0;
+}
+
+
+void SHAPERGUI_CheckBackup::procStarted()
+{
+  DBG_FUN();
+}
+
+
+void SHAPERGUI_CheckBackup::procFinished(int code, QProcess::ExitStatus stat)
+{
+  DBG_FUN();
+  ARG(code);
+  ARG2(stat, int);
+}
+
+
+void SHAPERGUI_CheckBackup::procError(QProcess::ProcessError err)
+{
+  DBG_FUN();
+  ARG2(err, int);
+}
diff --git a/src/SHAPERGUI/SHAPERGUI_CheckBackup.h b/src/SHAPERGUI/SHAPERGUI_CheckBackup.h
new file mode 100644 (file)
index 0000000..b491912
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2023  CEA, EDF, OPEN CASCADE SAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SHAPERGUI_CHECKBACKUP_H
+#define SHAPERGUI_CHECKBACKUP_H
+
+#include "SHAPER_SHAPERGUI.h"
+#include <QProcess>
+
+
+class SHAPERGUI_EXPORT SHAPERGUI_CheckBackup : public QObject
+{
+  Q_OBJECT
+public:
+  SHAPERGUI_CheckBackup(const QString &theFolder, const QString &theBaseName);
+  int run(const QString &theTestScript);
+
+private slots:
+  void procStarted();
+  void procFinished(int, QProcess::ExitStatus);
+  void procError(QProcess::ProcessError);
+
+private:
+  QProcess* myProcess;
+  QString   myFolder;
+  QString   myBaseName;
+};
+
+#endif
index a8856b26ddaf8d409a251f534d63dddb062ca753..1769826a2a2f4405cff3a6bff412ea0e02815eea 100644 (file)
 #include <QDir>
 #include <QTextStream>
 
+//---------------------------------------------------------
+#define USE_DEBUG
+//#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "SHAPERGUI_DataModel"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
 #define DUMP_NAME "shaper_dump.py"
 
 
 SHAPERGUI_DataModel::SHAPERGUI_DataModel(SHAPERGUI* theModule)
     : LightApp_DataModel(theModule), myStudyPath(""), myModule(theModule)
 {
+  DBG_FUN();
 }
 
 SHAPERGUI_DataModel::~SHAPERGUI_DataModel()
 {
+  DBG_FUN();
 }
 
 bool SHAPERGUI_DataModel::open(const QString& thePath, CAM_Study* theStudy, QStringList theFiles)
 {
+  DBG_FUN();
+  ARG(thePath);
+  ARG(theFiles);
   LightApp_DataModel::open( thePath, theStudy, theFiles );
   if (theFiles.size() == 0)
     return false;
@@ -83,12 +97,17 @@ bool SHAPERGUI_DataModel::open(const QString& thePath, CAM_Study* theStudy, QStr
   return true;
 }
 
-bool SHAPERGUI_DataModel::save(QStringList& theFiles)
+bool SHAPERGUI_DataModel::save(QStringList& theFiles, bool isBackup/*=false*/)
 {
+  DBG_FUN();
+  ARG(theFiles);
+  ARG(isBackup);
   // Publish to study before saving of the data model
-  myModule->publishToStudy();
+  //if (!isBackup) 
+    myModule->publishToStudy();
 
-  LightApp_DataModel::save( theFiles );
+  //if (!isBackup)
+    LightApp_DataModel::save( theFiles );
   XGUI_Workshop* aWorkShop = myModule->workshop();
   std::list<std::string> aFileNames;
 
@@ -120,14 +139,19 @@ bool SHAPERGUI_DataModel::save(QStringList& theFiles)
   return true;
 }
 
-bool SHAPERGUI_DataModel::saveAs(const QString& thePath, CAM_Study* theStudy, QStringList& theFiles)
+bool SHAPERGUI_DataModel::saveAs(const QString& thePath, CAM_Study* theStudy, QStringList& theFiles, bool isBackup/*=false*/)
 {
+  DBG_FUN();
+  ARG(thePath);
+  ARG(theFiles);
+  ARG(isBackup);
   myStudyPath = thePath;
-  return save(theFiles);
+  return save(theFiles, isBackup);
 }
 
 bool SHAPERGUI_DataModel::close()
 {
+  DBG_FUN();
   myModule->workshop()->closeDocument();
   return LightApp_DataModel::close();
 }
@@ -174,6 +198,9 @@ void SHAPERGUI_DataModel::removeDirectory(const QString& theDirectoryName)
 bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy,
                                      bool isMultiFile,  QStringList& theListOfFiles)
 {
+  DBG_FUN();
+  ARG(thePath);
+  ARG(theListOfFiles);
   LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(theStudy);
   if (!aStudy)
     return false;
index 571d1b76a04b2861b6e63a6beade2d29678d2569..3cba44fcd37c887f389f3e7d4c4a9811d5e1250c 100644 (file)
@@ -46,13 +46,13 @@ class SHAPERGUI_EXPORT SHAPERGUI_DataModel : public LightApp_DataModel
 
   /// Save module data to file
   /// \param theFiles list of created files
-  virtual bool save(QStringList& theFiles);
+  virtual bool save(QStringList& theFiles, bool isBackup=false);
 
   /// Save module data to a file
   /// \param thePath a path to the directory
   /// \param theStudy a current study
   /// \param theFiles a list of files to open
-  virtual bool saveAs(const QString& thePath, CAM_Study* theStudy, QStringList& theFiles);
+  virtual bool saveAs(const QString& thePath, CAM_Study* theStudy, QStringList& theFiles, bool isBackup=false);
 
   /// Close data structure
   virtual bool close();
index 740d35f89941f9f4877f9afd6962d3f9fe9b23ac..2bf82b2822f5437cd92cf3893ca90f1704f2b8d2 100644 (file)
         <source>Text color</source>
         <translation>Couleur du texte</translation>
     </message>
+    <message>
+        <source>Backup done in folder: %1</source>
+        <translation>Sauvegarde effectuée dans le dossier: %1</translation>
+    </message>
+    <message>
+        <source>Failed to backup active study!</source>
+        <translation>Échec de la sauvegarde de l&apos;étude active!</translation>
+    </message>
 </context>
 <context>
     <name>SHAPERGUI_ToolbarItemsDlg</name>
index 6ae78b95d4bd588ba7199f934272c0fb3a1c06b0..905eb509fbf1e46b58c046d91c2bec1a3d153776 100644 (file)
@@ -180,6 +180,15 @@ static Handle(VInspector_CallBack) MyVCallBack;
 #include <dlfcn.h>
 #endif
 
+//---------------------------------------------------------
+#define USE_DEBUG
+//#define MB_IGNORE_QT
+//#define MB_FULL_DUMP
+#define MBCLASSNAME "XGUI_Workshop"
+#include "MBDebug.h"
+// <-- insert includes for addtional debug headers here!
+//---------------------------------------------------------
+
 //#define DEBUG_WITH_MESSAGE_REPORT
 
 QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end");
@@ -212,8 +221,10 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
       myDisplayer(0),
       mySalomeConnector(theConnector),
       //myViewerSelMode(TopAbs_FACE),
-      myInspectionPanel(0)
+      myInspectionPanel(0),
+      myDoBackup(false)
 {
+  DBG_FUN();
   mySelector = new XGUI_SelectionMgr(this);
   myModuleConnector = new XGUI_ModuleConnector(this);
   myOperationMgr = new XGUI_OperationMgr(this, myModuleConnector);
@@ -315,6 +326,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 //******************************************************
 XGUI_Workshop::~XGUI_Workshop(void)
 {
+  DBG_FUN();
 #ifdef _DEBUG
 #ifdef MISSED_TRANSLATION
   // Save Missed translations
@@ -332,6 +344,7 @@ XGUI_Workshop::~XGUI_Workshop(void)
 //******************************************************
 void XGUI_Workshop::startApplication()
 {
+  DBG_FUN();
   //Initialize event listening
   myEventsListener->initializeEventListening();
 
@@ -700,6 +713,28 @@ void XGUI_Workshop::showHelpPage(const QString& thePage) const
 }
 
 
+//******************************************************
+void XGUI_Workshop::setBackupState(bool doBackup/*=true*/)
+{
+  DBG_FUN();
+  ARG(doBackup);
+  myDoBackup = doBackup;
+}
+
+
+//******************************************************
+void XGUI_Workshop::setWaitForBackup(bool theDoWait/*=true*/)
+{
+  DBG_FUN();
+  ARG(theDoWait);
+  myWaitForBackup = theDoWait;
+  if (theDoWait)
+  {
+    std::cout << "..... waiting for operation to finish to start backup." << std::endl;
+  }
+}
+
+
 //******************************************************
 void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer)
 {
@@ -856,6 +891,9 @@ void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect)
 //******************************************************
 void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
 {
+  DBG_FUN();
+  ARG(theOperation->getDescription()->operationId());
+
   setGrantedFeatures(theOperation);
 
   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
@@ -876,6 +914,9 @@ void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
 //******************************************************
 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
 {
+  DBG_FUN();
+  ARG(theOperation->getDescription()->operationId());
+
   updateCommandStatus();
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
@@ -958,6 +999,10 @@ void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation)
 //******************************************************
 void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>& theFileNames)
 {
+  DBG_FUN();
+  ARG(theName);
+  ARG(theFileNames);
+  SHOW(myDoBackup);
   QApplication::restoreOverrideCursor();
   SessionPtr aMgr = ModelAPI_Session::get();
 
@@ -976,12 +1021,15 @@ void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>&
 //******************************************************
 bool XGUI_Workshop::abortAllOperations()
 {
+  DBG_FUN();
   return myOperationMgr->abortAllOperations();
 }
 
 //******************************************************
 void XGUI_Workshop::operationStarted(ModuleBase_Operation* theOperation)
 {
+  DBG_FUN();
+  ARG(theOperation->getDescription()->operationId());
   setGrantedFeatures(theOperation);
   if (!theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
     updateCommandStatus();
@@ -994,6 +1042,7 @@ void XGUI_Workshop::operationStarted(ModuleBase_Operation* theOperation)
 //******************************************************
 void XGUI_Workshop::onOpen()
 {
+  DBG_FUN();
   if(!abortAllOperations())
     return;
   //save current file before close if modified
@@ -1024,6 +1073,8 @@ void XGUI_Workshop::onOpen()
 //******************************************************
 void XGUI_Workshop::openFile(const QString& theDirectory)
 {
+  DBG_FUN();
+  ARG(theDirectory);
   myCurrentFile = theDirectory;
   if (myCurrentFile.isEmpty())
     return;
@@ -1196,7 +1247,10 @@ void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState)
 //******************************************************
 bool XGUI_Workshop::onSave()
 {
-  if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
+  DBG_FUN();
+  SHOW(myDoBackup);
+
+  if(!myDoBackup && !myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
     return false;
   if (myCurrentFile.isEmpty()) {
     return onSaveAs();
@@ -1228,6 +1282,8 @@ bool XGUI_Workshop::onSave()
 //******************************************************
 bool XGUI_Workshop::onSaveAs()
 {
+  DBG_FUN();
+  SHOW(myDoBackup);
   if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
     return false;
   qreal aRatio = ModuleBase_Tools::currentPixelRatio();
@@ -1446,6 +1502,8 @@ void XGUI_Workshop::onExportPart()
 //******************************************************
 ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
 {
+  DBG_FUN();
+  ARG(theModule);
   QString libName = QString::fromStdString(library(theModule.toStdString()));
   if (libName.isEmpty()) {
     qWarning(qPrintable(tr("Information about module \"%1\" doesn't exist.").arg(theModule)));
@@ -2355,10 +2413,12 @@ bool hasResults(QObjectPtrList theObjects, const std::set<std::string>& theTypes
 // all nested parts.
 std::list<FeaturePtr> allFeatures(const DocumentPtr& theDocument)
 {
+  DBG_FUNC();
   std::list<FeaturePtr> aResultList;
   std::list<FeaturePtr> anAllFeatures = theDocument->allFeatures();
   foreach (const FeaturePtr& aFeature, anAllFeatures) {
     // The order of appending features of the part and the part itself is important
+    MSGEL("* aFeature = [" << aFeature->getKind() << "]  action=" << aFeature->isAction());
 
     // Append features from a part feature
     std::list<ResultPtr> aResults;
index b6e25c670dee278a950fca4b030ba4cd3c2d5a56..676a44d463099829c421a4047f899d91da43a5bd 100644 (file)
@@ -354,6 +354,12 @@ Q_OBJECT
 
   void showHelpPage(const QString& thePage) const;
 
+  void setBackupState(bool theDoBackup=true);
+
+  void setWaitForBackup(bool theDoWait=true);
+
+  bool waitForBackup() const  { return myWaitForBackup; }
+
 signals:
   /// Emitted when selection happens in Salome viewer
   void salomeViewerSelection();
@@ -592,6 +598,8 @@ private:
   Config_DataModelReader* myDataModelXMLReader; ///< XML reader of data model
   XGUI_InspectionPanel* myInspectionPanel; ///< container of feature attributes widgets
   QTemporaryDir myTmpDir; ///< a direcory for uncompressed files
+  bool myDoBackup; ///< whether the current save was initiated by automatic backup
+  bool myWaitForBackup; ///< whether to do a backup when current operation finishes
 };
 
 #endif
index 3a89659438163b92c3d8f2a95a5b0ef19d1691a5..b8e3ae4d4c3c6fdab938264f69a4c71deb107a47 100644 (file)
@@ -64,7 +64,7 @@ if __name__ == '__main__':
 
   with open(testlogfile, 'r') as inputFile:
     s = inputFile.read()
-    #print("logfile: ", s)
+    print("logfile: ", s)
     if s.find("FAIL") > 0:
       isOk = False
       error = s