see "http://doc.nnov.opencascade.com/doku.php?id=projects:guithare:gui_backup" for more info
QStringList anAddFamilies = aResMgr->stringValue( "PyConsole", "additional_families" ).split( ";", QString::SkipEmptyParts );
QString aFamily;
for ( QStringList::Iterator it = anAddFamilies.begin(); it != anAddFamilies.end(); ++it )
+ {
+ aFamily = *it;
+ if ( famdb.contains(aFamily) )
{
- aFamily = *it;
- if ( famdb.contains(aFamily) )
- {
- f.setFamily( aFamily );
- aResMgr->setValue( "PyConsole", "font", f );
- break;
- }
+ f.setFamily( aFamily );
+ aResMgr->setValue( "PyConsole", "font", f );
+ break;
}
+ }
}
/*!Destructor.
pref->addPreference( tr( "PREF_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file" );
pref->addPreference( tr( "PREF_ASCII_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "ascii_file" );
pref->addPreference( tr( "PREF_STORE_POS" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_positions" );
+ pref->addPreference( tr( "PREF_BACKUP" ), studyGroup, LightApp_Preferences::DblSpin, "Study", "backup_studies" );
int extgroup = pref->addPreference( tr( "PREF_GROUP_EXT_BROWSER" ), genTab );
QString platform;
aSStyle->polish(qApp);
}
}
+
+ double time = resMgr->doubleValue( "Study", "backup_studies", 0. );
+ SUIT_Session::session()->setBackupTime( time );
}
/*!
if ( objectBrowser() )
objectBrowser()->updateTree();
+
+ LightApp_Study* aStudy = (LightApp_Study*)activeStudy();
+ aStudy->setRestoreFolder( myBFolder );
+ //myBFolder = "";
}
/*!
}
return res;
-}
\ No newline at end of file
+}
+
+/*!
+ * Calls 'backup' method of active study
+ */
+void LightApp_Application::backup( const QString& fName )
+{
+ LightApp_Study* study = dynamic_cast<LightApp_Study*>( activeStudy() );
+ if ( study )
+ study->backup( fName );
+}
+
+/*!
+ * Keeps folder to be used for restoring.
+ */
+void LightApp_Application::setRestoreFolder( const QString& fName )
+{
+ myBFolder = fName;
+}
+
+/*!
+ * Gets backup time from preferences; this method is used by session when backup timer is created.
+*/
+double LightApp_Application::getBackupTime() const
+{
+ SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+ double res = resMgr->doubleValue( "Study", "backup_studies", 0. );
+ return res;
+}
+
virtual void updateDesktopTitle();
+ virtual void backup( const QString& fName );
+ virtual void setRestoreFolder( const QString& fName );
+ virtual double getBackupTime() const;
+
signals:
void studyOpened();
void studySaved();
static LightApp_Preferences* _prefs_;
static int lastStudyId;
+
+ QString myBFolder;
};
#ifdef WIN32
}
return NULL;
}
+
+/*!
+ to do:
+*/
+void LightApp_DataModel::backup( const QString& /*fName*/, QStringList& files )
+{
+
+}
LightApp_DataObject* findObjectByEntry( SUIT_DataBrowser* theOB,
const QString& theEntry );
+ virtual void backup( const QString& fName, QStringList& files );
+
signals:
void opened();
void saved();
#include "LightApp_DataModel.h"
#include "LightApp_DataObject.h"
#include "LightApp_HDFDriver.h"
+#include "LightApp_Module.h"
#include "SUIT_ResourceMgr.h"
#include "SUIT_DataObjectIterator.h"
#include <set>
#include <QString>
+#include <QDir>
/*!
Constructor.
{
myDriver->ClearDriverContents();
// create files for models from theFileName
- if( !openStudyData(theFileName))
- return false;
+
+ if ( myRestFolder.isEmpty() )
+ {
+ if( !openStudyData(theFileName))
+ return false;
+ }
+ else
+ {
+ // Case when study is restored from backup
+ openBackupData();
+ }
setRoot( new LightApp_RootObject( this ) ); // create myRoot
bool res = CAM_Study::openDocument( theFileName );
emit opened( this );
+
+ if ( !myRestFolder.isEmpty() )
+ {
+ setIsSaved( false );
+ //myRestFolder = "";
+ }
+
return res;
}
comp.append( obj->entry() );
}
}
+
+/*!
+ * Keeps folder to be used for restoring.
+ */
+void LightApp_Study::setRestoreFolder( const QString& folder )
+{
+ myRestFolder = folder;
+}
+
+/*!
+ * - Call LightApp_DataModel::backup() for each data model
+ * - Creates "data" file in backup folder; this file contains name of opened
+ * HDF-file if study was stored or opened, name of temporary folder used
+ * by LightApp_Driver for study opening, list of backup files created by each model
+ */
+void LightApp_Study::backup( const QString& fName )
+{
+ QList<CAM_DataModel*> list;
+ dataModels( list );
+
+ QListIterator<CAM_DataModel*> itList( list );
+ while ( itList.hasNext() )
+ {
+ LightApp_DataModel* model = (LightApp_DataModel*)itList.next();
+ if ( model && model->getModule() )
+ {
+ // writes location of hdf-file
+ QString hdfName = QString( "HDF:" ) + studyName() + "\n";
+
+ //QString tmpName = QString( " ) + GetTmpDir( "", false ).c_str() + "\n";
+ QString tmpName( "TMP:" );
+
+ LightApp_Driver::ListOfFiles files =
+ myDriver->GetListOfFiles( model->getModule()->name().toLatin1().constData() );
+ if ( files.size() > 0 )
+ tmpName += files.front().c_str();
+ else
+ {
+ // New (not saved study). Use backup folder as default
+ tmpName += fName;
+ }
+ tmpName += '\n';
+
+ QString dataName = Qtx::addSlash( fName ) + "data";
+ FILE* f = fopen( dataName.toLatin1().constData(), "w" );
+ if ( f )
+ {
+ fputs( hdfName.toLatin1().constData(), f );
+ fputs( tmpName.toLatin1().constData(), f );
+
+ // backup model
+ QStringList backupFiles;
+ model->backup( fName, backupFiles );
+
+ // module data string
+ CAM_Module* mod = model->module();
+ {
+ QString modStr = mod->name();
+ QStringList::iterator it;
+ for ( it = backupFiles.begin(); it != backupFiles.end(); ++it )
+ {
+ const QString& curr = * it;
+ modStr += QString( "*" ) + curr;
+ }
+ fputs( modStr.toLatin1().constData(), f );
+ }
+ fclose( f );
+ }
+ }
+ }
+}
+
+/*!
+ * Prepare files to be used by data models for restoring; these files are
+ * created from backup files and files of previously opened study.
+ */
+bool LightApp_Study::openBackupData()
+{
+ // Case when study is restored from backup
+ // Here:
+ // tmpFolder - folder where temporary files of previously opened study was saved (ex. D:\temp\84623)
+ // hdfName \96 name of HDF-file of previous study, if exists.
+ // backupFolder \96 folder with backup files.
+
+ // Main idea:
+ // - Parse \93data\94 file and gets file names, Fill driver with files of results tmpFolder.
+ // - Move all files from backup to tmp.
+ // - Open study using this files.
+ // - Redirect name of opened study to previous hdfName.
+
+ // Parse \93data\94
+
+ // data-file - something like this
+ // HDF:D:/sln/CATHARE/Data/1.hdf
+ // TMP:d:\temp\84623\
+ // CATHAREGUI*1.cbf
+ QString dataName = Qtx::addSlash( myRestFolder ) + "data";
+ FILE* f = fopen( dataName.toLatin1().constData(), "r" );
+ if ( !f )
+ return false;
+
+ char buff[ 1024 ];
+
+ // hdf-name
+ memset( buff, 0, 1024 );
+ fgets( buff, 1024, f );
+ QString hdfName( buff );
+ hdfName.remove( '\n' );
+ hdfName.remove( "HDF:" );
+
+ // name of temporary file
+ memset( buff, 0, 1024 );
+ fgets( buff, 1024, f );
+ QString tmpFolder( buff );
+ tmpFolder.remove( '\n' );
+ tmpFolder.remove( "TMP:" );
+
+ // list of files
+ QString modName;
+ LightApp_Driver::ListOfFiles modFiles;
+ while( !feof( f ) )
+ {
+ modName = "";
+ modFiles.clear();
+
+ memset( buff, 0, 1024 );
+ fgets( buff, 1024, f );
+ QString modStr( buff );
+
+ QStringList lst = modStr.split( "*" );
+ QStringList::iterator it = lst.begin();
+ for ( int i = 0; it != lst.end(); ++it, ++i )
+ {
+ const QString& curr = *it;
+ if ( i == 0 )
+ {
+ modName = curr;
+ modFiles.push_back( Qtx::addSlash( tmpFolder ).toLatin1().constData() );
+ continue;
+ }
+ else
+ modFiles.push_back( curr.toLatin1().constData() );
+ }
+
+ // fill driver
+ myDriver->SetListOfFiles( modName.toLatin1().constData(), modFiles );
+ }
+
+ fclose( f );
+
+ // Move all files from backup to tmp
+
+ if ( !QFileInfo( tmpFolder ).exists() )
+ QDir().mkdir( tmpFolder );
+
+ if ( !QFileInfo( tmpFolder ).exists() )
+ return false;
+
+ QDir restDir( myRestFolder );
+ QStringList restList = restDir.entryList ( QDir::AllEntries );
+ QStringList::iterator it;
+ for ( it = restList.begin(); it != restList.end(); ++it )
+ {
+ const QString& locName = *it;
+ if ( locName == "." || locName == ".." || locName == "data" )
+ continue;
+
+ QString oldName = QDir::convertSeparators( Qtx::addSlash( myRestFolder ) + locName );
+ QString newName = QDir::convertSeparators( Qtx::addSlash( tmpFolder ) + locName );
+ if ( oldName != newName ) // oldName == newName for non-saved study
+ {
+ QFile::remove( newName );
+ QFile::copy( oldName, newName );
+ }
+ }
+ return true;
+}
+
virtual void children( const QString&, QStringList& ) const;
virtual void components( QStringList& ) const;
+ void backup( const QString& fName);
+ void setRestoreFolder( const QString& folder );
+
protected:
virtual void saveModuleData ( QString theModuleName, QStringList theListOfFiles );
virtual void openModuleData ( QString theModuleName, QStringList& theListOfFiles );
void closed ( SUIT_Study* );
void created( SUIT_Study* );
+private:
+
+ bool openBackupData();
+
private:
LightApp_Driver* myDriver;
+ QString myRestFolder;
friend class LightApp_Application;
};
<section name="Study">
<!-- General study settings -->
<parameter name="store_positions" value="true" />
+ <parameter name="backup_studies" value="5.0" />
</section>
<section name="Activate">
<!-- StartUp settings -->
<source>PREF_STORE_POS</source>
<translation>Store positions of windows</translation>
</message>
+ <message>
+ <source>PREF_BACKUP</source>
+ <translation>Backup every N minutes</translation>
+ </message>
<message>
<source>PREF_PROJECTION_MODE</source>
<translation>Projection mode:</translation>
if( SUIT_ResourceMgr* aResMgr = resourceMgr() )
aResMgr->setValue( "Printer", "last_used_printer", thePrinterName );
}
+
+/*!
+ * Curent implementation does nothing; calls 'backup' method of active study in LightApp_Application
+ */
+void SUIT_Application::backup( const QString& /*fName*/ )
+{
+}
+
+/*!
+ * SUIT_Application does nothing; LightApp_Application keeps folder to be used for restoring.
+ */
+void SUIT_Application::setRestoreFolder( const QString& /*fName*/ )
+{
+}
+
+/*!
+ * Gets backup time from preferences; this method is used by session when backup timer is created.
+ */
+double SUIT_Application::getBackupTime() const
+{
+ return 0;
+}
//! Sets a name of the last used printer
void setLastUsedPrinter( const QString& );
+ virtual void backup( const QString& fName );
+ virtual void setRestoreFolder( const QString& fName );
+ virtual double getBackupTime() const;
+
signals:
void applicationClosed( SUIT_Application* );
void activated( SUIT_Application* );
//
#include "SUIT_Session.h"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
#include "SUIT_Study.h"
#include "SUIT_Tools.h"
#include "SUIT_MessageBox.h"
#include "SUIT_ResourceMgr.h"
#include <QApplication>
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
+#include <QTimer>
+#include <QFileInfo>
+#include <QDir>
+#include <QSet>
SUIT_Session* SUIT_Session::mySession = 0;
myActiveApp( 0 ),
myHandler( 0 ),
myExitStatus( NORMAL ),
- myExitFlags ( 0 )
+ myExitFlags ( 0 ),
+ myBTimer( 0 ),
+ myBFile( 0 )
{
SUIT_ASSERT( !mySession )
myResMgr = 0;
}
mySession = 0;
+
+ // remove backup
+ if ( myBFile )
+ fclose( myBFile );
+ if ( !myBFolder.isEmpty() )
+ Qtx::rmDir( myBFolder );
}
/*! \retval return mySession */
myResMgr->loadLanguage();
}
- //jfa 22.06.2005:SUIT_Application* anApp = crtInst( args, argv );
- SUIT_Application* anApp = crtInst();
- if ( !anApp )
+ //jfa 22.06.2005:SUIT_Application* app = crtInst( args, argv );
+ SUIT_Application* app = crtInst();
+ if ( !app )
{
SUIT_MessageBox::warning( 0, tr( "Error" ), tr( "Can not create application \"%1\": %2").arg( appName ).arg( lastError() ) );
return 0;
}
- anApp->setObjectName( appName );
+ app->setObjectName( appName );
- insertApplication( anApp );
+ insertApplication( app );
if ( !myHandler )
{
myHandler = crtHndlr();
}
- anApp->start();
+ app->start();
// Application can be closed during starting (not started).
- if ( !myAppList.contains( anApp ) )
- anApp = 0;
+ if ( !myAppList.contains( app ) )
+ app = 0;
+
+ if ( !myBTimer )
+ {
+ myBTimer = (QTimer*)1; // block reation on creation of new application
+ restoreBackup();
+ myBTimer = 0;
+ createBTimer();
+ }
- return anApp;
+ return app;
}
/*!
{
myActiveApp = app;
}
+
+/*!
+ Gets prefix to be used for creating backup copies
+*/
+QString SUIT_Session::getBPrefix() const
+{
+ //qint64 pId = QApplication::applicationPid();
+#ifdef WNT
+ QString usr( getenv( "USERNAME" ) );
+#else
+ QString usr( getenv( "USER" ) );
+#endif
+
+ // Create folder
+ QString anAppName;
+ SUIT_Application* app = activeApplication();
+ if ( app )
+ anAppName = app->applicationName();
+ else
+ anAppName = "SALOME";
+
+ QString pref = anAppName + "_" + usr;
+
+ return pref;
+}
+
+/*!
+ Gets backup interval
+*/
+double SUIT_Session::backupTime() const
+{
+ double res;
+ if ( myBTimer )
+ res = myBTimer->interval() / 60. / 10e-3;
+ else
+ res = 0;
+ return res;
+}
+
+/*!
+ Sets backup interval; this method is used by application
+ when the interval is changed in preferences
+*/
+void SUIT_Session::setBackupTime( const double val ) const
+{
+ int newInt = val * 60 * 1e3;
+ if ( !myBTimer || newInt == myBTimer->interval() )
+ return;
+
+ myBTimer->setInterval( newInt );
+ if ( val <= 0 )
+ myBTimer->stop();
+ else
+ myBTimer->start();
+}
+
+/*!
+ Creates timer to be used for backup
+*/
+void SUIT_Session::createBTimer()
+{
+ if ( myBTimer )
+ return;
+
+ SUIT_Application* app = activeApplication();
+ if ( !app )
+ return;
+
+ myBTimer = new QTimer( this );
+ connect( myBTimer, SIGNAL( timeout() ), this, SLOT( onBTimer() ) );
+
+ double mSec = app->getBackupTime() * 60 * 1e3;
+ if ( mSec > 0 )
+ myBTimer->start( mSec );
+
+ QString pref = QDir::convertSeparators( QDir::tempPath() + "/" + getBPrefix() );
+ myBFolder = pref;
+ int i = 0;
+ while( QFileInfo( myBFolder ).exists() )
+ {
+ myBFolder = pref + QString( "_%1" ).arg( ++i );
+ }
+
+ if ( !QDir().mkdir( myBFolder ) )
+ myBFolder = "";
+
+ if ( !myBFolder.isEmpty() )
+ {
+ QString used = Qtx::addSlash( myBFolder ) + "used";
+ myBFile = fopen( used.toLatin1().constData(), "w" );
+ }
+}
+
+/*!
+ Slot, called when backup interval is out, iterates through all opened
+ applications, creates 'folderName' directories for them and calls app->backup( folderName );
+*/
+void SUIT_Session::onBTimer()
+{
+ QApplication::setOverrideCursor( Qt::WaitCursor );
+
+ // clear folder
+ Qtx::rmDir( myBFolder );
+ QDir().mkdir( myBFolder );
+
+ // create backup
+ QString aName;
+ QList<SUIT_Application*> aList = applications();
+ QList<SUIT_Application*>::iterator it;
+ for ( it = aList.begin(); it != aList.end(); ++it )
+ {
+ SUIT_Application* app = *it;
+ if ( app && app->activeStudy() )
+ {
+ aName = app->activeStudy()->studyName();
+ aName.replace( ":", "%" );
+ aName.replace( "/", "+" );
+ aName.replace( "\\", "+" );
+ QString aFName = QDir::convertSeparators( myBFolder + "/" + aName );
+ QDir().mkdir( aFName );
+ QFileInfo fi( aFName );
+ if ( fi.exists() &&fi.isDir() )
+ app->backup( aFName );
+ }
+ }
+
+ QApplication::restoreOverrideCursor();
+}
+
+/*!
+ Restores crashed studies from backup
+*/
+void SUIT_Session::restoreBackup()
+{
+ QString pref = getBPrefix();
+
+ // checks whether temp folder contains old backups
+ QDir tmpDir( QDir::tempPath() );
+
+ QStringList filt;
+ filt.append( pref + "*" );
+ tmpDir.setNameFilters( filt );
+
+ QStringList sess = tmpDir.entryList ( QDir::Dirs );
+ if ( sess.count() == 0 )
+ return;
+
+ QSet<QString> stdSet;
+ QList<QString> toRestore;
+ QList<QString> toRemove;
+
+ // iterate through temp folder
+ QStringList::iterator sessIter;
+ for ( sessIter = sess.begin(); sessIter != sess.end(); ++sessIter )
+ {
+ // iterate through session folder
+ const QString& stdRoot = Qtx::addSlash( QDir::tempPath() ) + *sessIter;
+
+ // checks whether folder is not currently used
+ QString testFile = Qtx::addSlash( stdRoot ) + "used";
+ QFileInfo fi( testFile );
+ if ( fi.exists() && !QFile( testFile ).remove() )
+ continue;
+
+ toRemove.append( stdRoot );
+
+ QDir sessDir( stdRoot );
+ QStringList stdList = sessDir.entryList ( QDir::Dirs );
+
+ QStringList::iterator stdIt;
+ for ( stdIt = stdList.begin(); stdIt != stdList.end(); ++stdIt )
+ {
+ const QString& locName = *stdIt;
+ if ( *stdIt == "." || *stdIt == ".." )
+ continue;
+
+ const QString& study = Qtx::addSlash( stdRoot ) + *stdIt;
+ QDir stdDir( study );
+ QStringList fList = sessDir.entryList ( QDir::AllEntries );
+ if ( fList.count() > 2 && !stdSet.contains( locName ) )
+ {
+ stdSet.insert( locName );
+ toRestore.append( study );
+ }
+ }
+ }
+
+ // restore study if necessary
+ if ( !toRestore.isEmpty() )
+ {
+ QWidget* p = activeApplication() ? (QWidget*)activeApplication()->desktop() : 0;
+
+ int aBtn = SUIT_MessageBox::warning( p, tr( "WRN_WARNING" ), tr( "WANT_TO_RESTORE" ),
+ SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::Yes );
+ if ( aBtn == SUIT_MessageBox::Yes )
+ {
+ QStringList::iterator it;
+ bool isFirst = true;
+ for ( it = toRestore.begin(); it != toRestore.end(); ++it )
+ {
+ SUIT_Application* app = activeApplication();
+ if ( !app )
+ return;
+
+ if ( !isFirst )
+ app = startApplication( app->objectName(), 0, 0 );
+
+ isFirst = false;
+
+ if ( !app )
+ continue;
+
+ app->setRestoreFolder( *it );
+
+ QString fName = *it;
+ int ind = fName.lastIndexOf( "\\" );
+ if ( ind == -1 )
+ ind = fName.lastIndexOf( "/" );
+ if ( ind >= 0 )
+ fName = fName.right( fName.length() - ind -1 );
+ fName.replace( "%", ":" );
+ fName.replace( "+", "/" );
+ fName.replace( "+", QDir::separator() );
+ if ( !app->useFile( fName ) )
+ app->closeApplication();
+ }
+ }
+ }
+
+ // remove all backup folders
+ QStringList::iterator it;
+ for ( it = toRemove.begin(); it != toRemove.end(); ++it )
+ {
+ Qtx::rmDir( *it );
+ }
+}
+
#endif
class SUIT_ResourceMgr;
+class QTimer;
class SUIT_ExceptionHandler;
#ifdef WIN32
void insertApplication( SUIT_Application* );
+ double backupTime() const;
+ void setBackupTime( const double val ) const;
+
signals:
void applicationClosed( SUIT_Application* );
private slots:
void onApplicationClosed( SUIT_Application* );
void onApplicationActivated( SUIT_Application* );
+ void onBTimer();
+
+private:
+ QString getBPrefix() const;
+ void createBTimer();
+ void restoreBackup();
private:
typedef QList<SUIT_Application*> AppList;
int myExitStatus;
int myExitFlags;
+
+ QString myBFolder;
+ QTimer* myBTimer;
+ FILE* myBFile;
};
#endif
void SUIT_Study::restoreState(int /*savePoint*/)
{
}
+
<translation>All files (*)</translation>
</message>
</context>
+ <context>
+ <name>SUIT_Session</name>
+ <message>
+ <source>WANT_TO_RESTORE</source>
+ <translation>Application crashed and one or several studies was unsaved.
+Do you want to restore them?</translation>
+ </message>
+ </context>
</TS>