X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSalomeApp%2FSalomeApp_Application.cxx;h=d5cc4fb4452aa4856d1726df763a1babf3726086;hb=9ee7121c89dee1b85745c54ffef953855c6b8041;hp=b7db9089f00d99078c6533c0dc7a2f0010efedd2;hpb=8dc06f253c1d6a0bb3cc999842fa5a7848c79f40;p=modules%2Fgui.git diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index b7db9089f..d5cc4fb44 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -35,9 +35,10 @@ #endif #ifndef DISABLE_PYCONSOLE - #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first! - #include + #include "SalomeApp_PyInterp.h" #include "SalomeApp_NoteBook.h" + #include "LightApp_PyEditor.h" + #include "PyConsole_Console.h" #endif #include "SalomeApp_Application.h" #include "SalomeApp_Study.h" @@ -49,6 +50,7 @@ #include "SalomeApp_ExitDlg.h" #include +#include #include #include #include @@ -62,7 +64,6 @@ #include #include #include -#include #include #include #include @@ -84,6 +85,7 @@ #include #include +#include #include #include #include @@ -108,6 +110,8 @@ #include +std::unique_ptr SalomeApp_Application::_ns; + /*!Internal class that updates object browser item properties */ // temporary commented /*class SalomeApp_Updater : public OB_Updater @@ -153,17 +157,31 @@ void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem ) //} }*/ -/*!Create new instance of SalomeApp_Application.*/ -extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication() +namespace { - return new SalomeApp_Application(); + /*! + \brief Flag locker. + */ + class MessageLocker + { + public: + //! Constructor. Sets passed boolean flag to \c true. + MessageLocker( bool& Lock ) : myPrevState( Lock ), myLock( Lock ) { myLock = true; } + //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false. + ~MessageLocker() { myLock = myPrevState; } + private: + bool myPrevState; + bool& myLock; //! External 'Lock state' boolean flag + }; } /*!Constructor.*/ -SalomeApp_Application::SalomeApp_Application() - : LightApp_Application(), - myIsCloseFromExit( false ) +SalomeApp_Application::SalomeApp_Application(SALOME_NamingService_Abstract *ns):myIsCloseFromExit( false ),myToIgnoreMessages( false ) { + if(!ns) + _ns.reset(new SALOME_NamingService(orb())); + else + _ns.reset(ns); } /*!Destructor. @@ -175,6 +193,25 @@ SalomeApp_Application::~SalomeApp_Application() //SALOME_EventFilter::Destroy(); } +QStringList __getArgsList(QString argsString) +{ + // Special process if some items of 'args:' list are themselves lists + // Note that an item can be a list, but not a list of lists... + // So we can have something like this: + // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok" + // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok" + // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok] + argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes + bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0); + if (containsList) { + QStringList sl = argsString.split("\"", QString::SkipEmptyParts); + sl.removeAll(", "); + return sl; + } + else + return argsString.split(",", QString::SkipEmptyParts); +} + /*!Start application.*/ void SalomeApp_Application::start() { @@ -185,11 +222,11 @@ void SalomeApp_Application::start() QString hdffile; QStringList pyfiles; - QString loadStudy; - for (int i = 1; i < qApp->argc(); i++) { + QStringList args = QApplication::arguments(); + for (int i = 1; i < args.count(); i++) { QRegExp rxs ("--study-hdf=(.+)"); - if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) { + if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) { QString file = rxs.capturedTexts()[1]; QFileInfo fi ( file ); QString extension = fi.suffix().toLower(); @@ -198,7 +235,7 @@ void SalomeApp_Application::start() } else { QRegExp rxp ("--pyscript=\\[(.+)\\]"); - if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) { + if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) { // pyscript QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts); for (int k = 0; k < dictList.count(); ++k) { @@ -218,14 +255,10 @@ void SalomeApp_Application::start() LightApp_Application::start(); SALOME_EventFilter::Init(); - if ( !hdffile.isEmpty() ) // open hdf file given as parameter + setProperty("open_study_from_command_line", true); + if ( !hdffile.isEmpty() ) // open hdf file given as parameter onOpenDoc( hdffile ); - else if ( pyfiles.count() > 0 ) // create new study - onNewDoc(); - else if (!loadStudy.isEmpty()) {// load study by name - if (onLoadDoc(loadStudy)) - updateObjectBrowser(true); - } + setProperty("open_study_from_command_line", QVariant()); #ifndef DISABLE_PYCONSOLE // import/execute python scripts @@ -233,31 +266,27 @@ void SalomeApp_Application::start() SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); PyConsole_Console* pyConsole = pythonConsole(); if ( appStudy && pyConsole ) { - _PTR(Study) aStudy = appStudy->studyDS(); - if ( !aStudy->GetProperties()->IsLocked() ) { + if ( !getStudy()->GetProperties()->IsLocked() ) { // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]} // Path is absolute, script has .py extension - for (uint j = 0; j < pyfiles.count(); j++ ) { + for (int j = 0; j < pyfiles.count(); j++ ) { // Extract scripts and their arguments, if any QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]"); if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) { QString script = rxp.capturedTexts()[1]; - QString args = ""; - QStringList argList = rxp.capturedTexts()[2].split(",", QString::SkipEmptyParts); - for (uint k = 0; k < argList.count(); k++ ) { + QStringList args; + QStringList argList = __getArgsList(rxp.capturedTexts()[2]); + for (int k = 0; k < argList.count(); k++ ) { QString arg = argList[k].trimmed(); arg.remove( QRegExp("^[\"]") ); arg.remove( QRegExp("[\"]$") ); - args += arg+","; - } - args.remove( QRegExp("[,]$") ); - if (!args.isEmpty()) { - args = "args:"+args; + args << QString("\"%1\"").arg(arg); } + if (args.count() == 1) + args << ""; script.remove( QRegExp("^python.*[\\s]+") ); - QString cmd = script+" "+args; - QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed()); + QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(",")); pyConsole->exec(command); } } // end for loop on pyfiles QStringList @@ -297,7 +326,7 @@ void SalomeApp_Application::createActions() //! Properties createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(), tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ), - Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) ); + 0, desk, false, this, SLOT( onProperties() ) ); //! Catalog Generator createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(), @@ -312,10 +341,14 @@ void SalomeApp_Application::createActions() createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(), tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ), Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) ); + //no need at this action for mono-study application because study is always exists + action( ConnectId )->setVisible( false ); createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(), tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ), Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) ); + //no need at this action for mono-study application because study is always exists + action( DisconnectId )->setVisible( false ); int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 ); @@ -362,6 +395,8 @@ void SalomeApp_Application::createActions() */ void SalomeApp_Application::onExit() { + //MessageLocker ml( myToIgnoreMessages ); + bool killServers = false; bool result = true; @@ -378,12 +413,20 @@ void SalomeApp_Application::onExit() } } +/*!SLOT. Create a document.*/ +void SalomeApp_Application::onNewDoc() +{ + MessageLocker ml( myToIgnoreMessages ); + + LightApp_Application::onNewDoc(); +} + /*!SLOT. Load document.*/ void SalomeApp_Application::onLoadDoc() { - QString studyName; + MessageLocker ml( myToIgnoreMessages ); - std::vector List = studyMgr()->GetOpenStudies(); + QString studyName; // rnv: According to the single-study approach on the server side // can be only one study. So if it is exists connect to them, @@ -416,14 +459,14 @@ void SalomeApp_Application::onLoadDoc() return; */ - if(List.size() <= 0) { + if(!activeStudy()) { SUIT_MessageBox::warning( desktop(), QObject::tr("WRN_WARNING"), QObject::tr("WRN_NO_STUDY_ON SERV") ); return; } - studyName = List[0].c_str(); + studyName = activeStudy()->studyName(); #ifndef WIN32 // this code replaces marker of windows drive and path become invalid therefore @@ -480,7 +523,7 @@ void SalomeApp_Application::onNewWithScript() { onNewDoc(); - QString command = QString("execfile(r\"%1\")").arg(aFile); + QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile); #ifndef DISABLE_PYCONSOLE PyConsole_Console* pyConsole = pythonConsole(); @@ -495,10 +538,9 @@ void SalomeApp_Application::onNewWithScript() /*!SLOT. Load document with \a aName.*/ bool SalomeApp_Application::onLoadDoc( const QString& aName ) { -#ifdef SINGLE_DESKTOP if ( !LightApp_Application::closeDoc() ) return false; -#endif + bool res = true; if ( !activeStudy() ) { // if no study - load in current desktop @@ -532,31 +574,51 @@ bool SalomeApp_Application::onLoadDoc( const QString& aName ) /*!SLOT. Parse message for desktop.*/ void SalomeApp_Application::onDesktopMessage( const QString& message ) { - if (message.indexOf("studyCreated:") == 0) { - // Enable 'Connect' action - updateCommandsStatus(); + if ( myToIgnoreMessages ) + return; // a message from SALOMEDS is caused by GUI action + + MessageLocker ml( myToIgnoreMessages ); + + if (message.indexOf("studyCreated") == 0) { + if (!activeStudy()) { + onNewDoc(); + updateCommandsStatus(); + } } - else if (message.indexOf("studyClosed:") == 0) { - /* message also contains ID of the closed study, - but as soon as SALOME is mono-study application for the moment, - this ID is not needed now.*/ - //long aStudyId = message.section(':', 1).toLong(); + if (message.indexOf("studyCleared") == 0) { // Disconnect GUI from active study, because it was closed on DS side. - closeActiveDoc( false ); - // Disable 'Connect' action - QAction* a = action( ConnectId ); - if ( a ) - a->setEnabled( false ); + if (activeStudy()) { + closeActiveDoc( false ); + // Disable 'Connect' action + QAction* a = action( ConnectId ); + if ( a ) + a->setEnabled( false ); + } } else if ( message.toLower() == "connect_to_study" ) { - onLoadDoc(); + if ( activeStudy() ) + useStudy( activeStudy()->studyName() ); + } + if (message.indexOf("studyNameChanged") == 0) { + updateDesktopTitle(); } LightApp_Application::onDesktopMessage( message ); } +/*!On module activation action.*/ +void SalomeApp_Application::onModuleActivation( const QString& modName ) +{ + if (!activeStudy() && !modName.isEmpty()) + getStudy()->Init(); + + LightApp_Application::onModuleActivation( modName ); +} + /*!SLOT. Copy objects to study maneger from selection maneger..*/ void SalomeApp_Application::onCopy() { + LightApp_Application::onCopy(); + SALOME_ListIO list; LightApp_SelectionMgr* mgr = selectionMgr(); mgr->selectedObjects(list); @@ -564,18 +626,21 @@ void SalomeApp_Application::onCopy() SalomeApp_Study* study = dynamic_cast(activeStudy()); if(study == NULL) return; - _PTR(Study) stdDS = study->studyDS(); + _PTR(Study) stdDS = getStudy(); if(!stdDS) return; SALOME_ListIteratorOfListIO it( list ); if(it.More()) { _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry()); - try { - studyMgr()->Copy(so); - onSelectionChanged(); - } - catch(...) { + if( so ) + { + try { + stdDS->Copy(so); + onSelectionChanged(); + } + catch(...) { + } } } } @@ -583,6 +648,8 @@ void SalomeApp_Application::onCopy() /*!SLOT. Paste objects to study maneger from selection manager.*/ void SalomeApp_Application::onPaste() { + LightApp_Application::onPaste(); + SALOME_ListIO list; LightApp_SelectionMgr* mgr = selectionMgr(); mgr->selectedObjects(list); @@ -590,7 +657,7 @@ void SalomeApp_Application::onPaste() SalomeApp_Study* study = dynamic_cast(activeStudy()); if(study == NULL) return; - _PTR(Study) stdDS = study->studyDS(); + _PTR(Study) stdDS = getStudy(); if(!stdDS) return; if ( stdDS->GetProperties()->IsLocked() ) { @@ -604,12 +671,15 @@ void SalomeApp_Application::onPaste() if(it.More()) { _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry()); - try { - studyMgr()->Paste(so); - updateObjectBrowser( true ); - updateActions(); //SRN: BugID IPAL9377, case 3 - } - catch(...) { + if( so ) + { + try { + stdDS->Paste(so); + updateObjectBrowser( true ); + updateActions(); //SRN: BugID IPAL9377, case 3 + } + catch(...) { + } } } } @@ -625,20 +695,45 @@ bool SalomeApp_Application::isPossibleToClose( bool& closePermanently ) /*! Check if the study is locked */ void SalomeApp_Application::onCloseDoc( bool ask ) { - SalomeApp_Study* study = dynamic_cast(activeStudy()); - - if (study != NULL) { - _PTR(Study) stdDS = study->studyDS(); - if(stdDS && stdDS->IsStudyLocked()) { - if ( SUIT_MessageBox::question( desktop(), - QObject::tr( "WRN_WARNING" ), - QObject::tr( "CLOSE_LOCKED_STUDY" ), - SUIT_MessageBox::Yes | SUIT_MessageBox::No, - SUIT_MessageBox::No) == SUIT_MessageBox::No ) return; + if(getStudy()->IsStudyLocked()) { + if ( SUIT_MessageBox::question( desktop(), + QObject::tr( "WRN_WARNING" ), + QObject::tr( "CLOSE_LOCKED_STUDY" ), + SUIT_MessageBox::Yes | SUIT_MessageBox::No, + SUIT_MessageBox::No) == SUIT_MessageBox::No ) return; - } } + MessageLocker ml( myToIgnoreMessages ); + LightApp_Application::onCloseDoc( ask ); + + // reinitialize study to have empty data + //getStudy()->Init(); +} + +/*!SLOT. Reload document from the file.*/ +bool SalomeApp_Application::onReopenDoc() +{ + MessageLocker ml( myToIgnoreMessages ); + + return LightApp_Application::onReopenDoc(); +} + + +/*!SLOT. Load document.*/ +void SalomeApp_Application::onOpenDoc() +{ + MessageLocker ml( myToIgnoreMessages ); + + LightApp_Application::onOpenDoc(); +} + +/*!SLOT. Load document.*/ +bool SalomeApp_Application::onOpenDoc(const QString& name) +{ + MessageLocker ml( myToIgnoreMessages ); + + return LightApp_Application::onOpenDoc(name); } /*!Sets enable or disable some actions on selection changed.*/ @@ -658,21 +753,14 @@ void SalomeApp_Application::onSelectionChanged() canPaste = m->canPaste(); } - SalomeApp_Study* study = dynamic_cast(activeStudy()); - if (study) { - _PTR(Study) stdDS = study->studyDS(); + SALOME_ListIteratorOfListIO it ( list ); - if (stdDS) { - SALOME_ListIteratorOfListIO it ( list ); + if (it.More() && list.Extent() == 1) { + _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry()); - if (it.More() && list.Extent() == 1) { - _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry()); - - if ( so ) { - canCopy = canCopy || studyMgr()->CanCopy(so); - canPaste = canPaste || studyMgr()->CanPaste(so); - } - } + if ( so ) { + canCopy = canCopy || getStudy()->CanCopy(so); + canPaste = canPaste || getStudy()->CanPaste(so); } } @@ -690,8 +778,7 @@ void SalomeApp_Application::onDeleteInvalidReferences() if( aList.IsEmpty() ) return; - SalomeApp_Study* aStudy = dynamic_cast(activeStudy()); - _PTR(Study) aStudyDS = aStudy->studyDS(); + _PTR(Study) aStudyDS = getStudy(); _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder(); _PTR(SObject) anObj; @@ -746,6 +833,8 @@ SUIT_Study* SalomeApp_Application::createNewStudy() this, SIGNAL(notebookVarUpdated(QString)) ); #endif + getStudy()->Init(); + return aStudy; } @@ -781,7 +870,7 @@ void SalomeApp_Application::updateCommandsStatus() // Connect study menu a = action( ConnectId ); if( a ) - a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 ); + a->setEnabled( !activeStudy() ); // Disconnect study menu a = action( DisconnectId ); @@ -831,32 +920,11 @@ public: QCheckBox* mySaveGUIChk; }; -class DumpStudyFileValidator : public SUIT_FileValidator -{ - public: - DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {}; - virtual ~DumpStudyFileValidator() {}; - virtual bool canSave( const QString& file, bool permissions ); -}; - -bool DumpStudyFileValidator::canSave(const QString& file, bool permissions) -{ - QFileInfo fi( file ); - if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) { - SUIT_MessageBox::critical( parent(), - QObject::tr("WRN_WARNING"), - QObject::tr("WRN_FILE_NAME_BAD") ); - return false; - } - return SUIT_FileValidator::canSave( file, permissions); -} - /*!Private SLOT. On dump study.*/ void SalomeApp_Application::onDumpStudy( ) { SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); if ( !appStudy ) return; - _PTR(Study) aStudy = appStudy->studyDS(); QStringList aFilters; aFilters.append( tr( "PYTHON_FILES_FILTER" ) ); @@ -872,9 +940,9 @@ void SalomeApp_Application::onDumpStudy( ) } DumpStudyFileDlg fd( desktop() ); - fd.setValidator( new DumpStudyFileValidator( &fd ) ); + fd.setValidator( new LightApp_PyFileValidator( &fd ) ); fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) ); - fd.setFilters( aFilters ); + fd.setNameFilters( aFilters ); fd.myPublishChk->setChecked( anIsPublish ); fd.myMultiFileChk->setChecked( anIsMultiFile ); fd.mySaveGUIChk->setChecked( anIsSaveGUI ); @@ -895,6 +963,7 @@ void SalomeApp_Application::onDumpStudy( ) bool res; { SUIT_OverrideCursor wc; + ensureShaperIsActivated(); res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI ); } if ( !res ) @@ -908,15 +977,11 @@ void SalomeApp_Application::onDumpStudy( ) /*!Private SLOT. On load script.*/ void SalomeApp_Application::onLoadScript( ) { - SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); - if ( appStudy ) { - _PTR(Study) aStudy = appStudy->studyDS(); - if ( aStudy->GetProperties()->IsLocked() ) { - SUIT_MessageBox::warning( desktop(), - QObject::tr("WRN_WARNING"), - QObject::tr("WRN_STUDY_LOCKED") ); - return; - } + if ( getStudy()->GetProperties()->IsLocked() ) { + SUIT_MessageBox::warning( desktop(), + QObject::tr("WRN_WARNING"), + QObject::tr("WRN_STUDY_LOCKED") ); + return; } QStringList filtersList; @@ -931,7 +996,8 @@ void SalomeApp_Application::onLoadScript( ) if ( !aFile.isEmpty() ) { - QString command = QString("execfile(r\"%1\")").arg(aFile); + + QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile); #ifndef DISABLE_PYCONSOLE PyConsole_Console* pyConsole = pythonConsole(); @@ -966,14 +1032,6 @@ void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible ) objectBrowserColumnsVisibility(); } -/*!Gets file filter. - *\retval QString "(*.hdf)" - */ -QString SalomeApp_Application::getFileFilter() const -{ - return "(*.hdf)"; -} - /*!Create window.*/ QWidget* SalomeApp_Application::createWindow( const int flag ) { @@ -1027,6 +1085,12 @@ QWidget* SalomeApp_Application::createWindow( const int flag ) ob->setResizeOnExpandItem(resizeOnExpandItem); ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) ); + for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ ) + { + bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true ); + ob->treeView()->setColumnHidden( i, !shown ); + } + // temporary commented /* for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ ) @@ -1048,26 +1112,22 @@ QWidget* SalomeApp_Application::createWindow( const int flag ) #ifndef DISABLE_PYCONSOLE else if ( flag == WT_PyConsole ) { - PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() ); + PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) ); pyCons->setObjectName( "pythonConsole" ); pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) ); pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" )); pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true )); + pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) ); pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) ); wid = pyCons; - //pyCons->resize( pyCons->width(), desktop()->height()/4 ); - pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) ); } else if ( flag == WT_NoteBook ) { - SalomeApp_Study* appStudy = dynamic_cast( activeStudy() ); - if ( appStudy ) { - _PTR(Study) aStudy = appStudy->studyDS(); - setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) ); - //to receive signal in NoteBook that it's variable was modified - connect( this, SIGNAL( notebookVarUpdated( QString ) ), - getNoteBook(), SLOT( onVarUpdate( QString ) ) ); - } + setNoteBook( new SalomeApp_NoteBook( desktop() ) ); + //to receive signal in NoteBook that it's variable was modified + connect( this, SIGNAL( notebookVarUpdated( QString ) ), + getNoteBook(), SLOT( onVarUpdate( QString ) ) ); + wid = getNoteBook(); wid->setObjectName( "noteBook" ); } @@ -1116,16 +1176,10 @@ void SalomeApp_Application::updateDesktopTitle() { { QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false ); if ( !sName.isEmpty() ) { - SalomeApp_Study* study = dynamic_cast(activeStudy()); - if ( study ) { - _PTR(Study) stdDS = study->studyDS(); - if(stdDS) { - if ( stdDS->GetProperties()->IsLocked() ) { - aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) ); - } else { - aTitle += QString( " - [%1]" ).arg( sName ); - } - } + if ( getStudy()->GetProperties()->IsLocked() ) { + aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) ); + } else { + aTitle += QString( " - [%1]" ).arg( sName ); } } } @@ -1133,14 +1187,14 @@ void SalomeApp_Application::updateDesktopTitle() { desktop()->setWindowTitle( aTitle ); } -int SalomeApp_Application::closeChoice( const QString& docName ) +int SalomeApp_Application::closeChoice( const QString& /*docName*/ ) { QStringList buttons; QMap choices; int idx = 0; - buttons << tr ("APPCLOSE_SAVE"); // Save & Close + buttons << tr ("APPCLOSE_SAVE"); // Save & Clear choices.insert( idx++, CloseSave ); // ... - buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving + buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving choices.insert( idx++, CloseDiscard ); // ... if ( myIsCloseFromExit ) { buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect @@ -1151,6 +1205,8 @@ int SalomeApp_Application::closeChoice( const QString& docName ) buttons << tr ("APPCLOSE_CANCEL"); // Cancel choices.insert( idx++, CloseCancel ); // ... + if( !activeStudy()->isModified() ) + return CloseCancel; int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 ); return choices[answer]; @@ -1174,6 +1230,7 @@ bool SalomeApp_Application::closeAction( const int choice, bool& closePermanentl onSaveDoc(); else if ( !onSaveAsDoc() ) res = false; + // fall through! case CloseDisconnect: closeActiveDoc( false ); closePermanently = false; @@ -1192,12 +1249,9 @@ int SalomeApp_Application::openChoice( const QString& aName ) if ( QFileInfo( aName ).exists() ) { if ( choice == OpenNew ) { // The document isn't already open. bool exist = false; - std::vector lst = studyMgr()->GetOpenStudies(); - for ( uint i = 0; i < lst.size() && !exist; i++ ) { - if ( aName == QString( lst[i].c_str() ) ) - exist = true; - } - // The document already exists in the study manager. + if ( aName == getStudy()->Name().c_str() ) + exist = true; + // The document already exists in the study. // Do you want to reload it? if ( exist ) { int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ), @@ -1211,7 +1265,7 @@ int SalomeApp_Application::openChoice( const QString& aName ) } else { // file is not exist on disk SUIT_MessageBox::warning( desktop(), QObject::tr("WRN_WARNING"), - QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data())); + QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data())); return false; } @@ -1225,14 +1279,8 @@ bool SalomeApp_Application::openAction( const int aChoice, const QString& aName switch ( choice ) { case OpenRefresh: - { - _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() ); - if ( aStudy ) - { - studyMgr()->Close( aStudy ); - choice = OpenNew; - } - } + choice = OpenNew; + // fall through! default: res = LightApp_Application::openAction( choice, aName ); break; @@ -1293,24 +1341,33 @@ void SalomeApp_Application::moduleActionSelected( const int id ) /*!Gets CORBA::ORB_var*/ CORBA::ORB_var SalomeApp_Application::orb() { - ORB_INIT& init = *SINGLETON_::Instance(); - static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() ); + static CORBA::ORB_var _orb; + + if ( CORBA::is_nil( _orb ) ) { + Qtx::CmdLineArgs args; + ORB_INIT& init = *SINGLETON_::Instance(); + _orb = init( args.argc(), args.argv() ); + } + return _orb; } -/*!Create and return SALOMEDS_StudyManager.*/ -SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr() +/*!Create and return SALOMEDS_Study.*/ +_PTR(Study) SalomeApp_Application::getStudy() { - static _PTR(StudyManager) _sm; - if(!_sm) _sm = ClientFactory::StudyManager(); - return _sm.get(); + static _PTR(Study) _study; + if(!_study) { + CORBA::Object_var aSObject = namingService()->Resolve("/Study"); + SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject); + _study = ClientFactory::Study(aStudy); + } + return _study; } /*!Create and return SALOME_NamingService.*/ -SALOME_NamingService* SalomeApp_Application::namingService() +SALOME_NamingService_Abstract *SalomeApp_Application::namingService() { - static SALOME_NamingService _ns(orb()); - return &_ns; + return _ns.get(); } /*!Create and return SALOME_LifeCycleCORBA.*/ @@ -1374,72 +1431,62 @@ void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePop // isInvalidRefs will be true, if at least one of selected objects is invalid reference bool isInvalidRefs = false; - SalomeApp_Study* aStudy = dynamic_cast(activeStudy()); - if ( aStudy ) { - _PTR(Study) aStudyDS = aStudy->studyDS(); - _PTR(SObject) anObj; - for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() ) + _PTR(SObject) anObj; + for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() ) + { + if( it.Value()->hasEntry() ) { - if( it.Value()->hasEntry() ) - { - _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject; - while( aRefObj && aRefObj->ReferencedObject( anObj ) ) - aRefObj = anObj; + _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject; + while( aRefObj && aRefObj->ReferencedObject( anObj ) ) + aRefObj = anObj; - if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() ) - isInvalidRefs = true; - } + if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() ) + isInvalidRefs = true; } + } - // Add "Delete reference" item to popup - if ( isInvalidRefs ) - { - thePopup->addSeparator(); - thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) ); - return; - } + // Add "Delete reference" item to popup + if ( isInvalidRefs ) + { + thePopup->addSeparator(); + thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) ); + return; + } - // "Activate module" item should appear only if it's necessary - if ( aList.Extent() == 1 ) { - aList.Clear(); - mgr->selectedObjects( aList ); - - Handle(SALOME_InteractiveObject) aIObj = aList.First(); - - // add extra popup menu (defined in XML) - if ( myExtActions.size() > 0 ) { - // Use only first selected object - SalomeApp_Study* study = dynamic_cast( activeStudy() ); - if ( study ) { - _PTR(Study) stdDS = study->studyDS(); - if ( stdDS ) { - _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() ); - if ( aSO ) { - _PTR( GenericAttribute ) anAttr; - std::string auid = "AttributeUserID"; - auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID); - if ( aSO->FindAttribute( anAttr, auid ) ) { - _PTR(AttributeUserID) aAttrID = anAttr; - QString aId = aAttrID->Value().c_str(); - if ( myExtActions.contains( aId ) ) { - thePopup->addAction(myExtActions[aId]); - } - } - } + // "Activate module" item should appear only if it's necessary + if ( aList.Extent() == 1 ) { + aList.Clear(); + mgr->selectedObjects( aList ); + + Handle(SALOME_InteractiveObject) aIObj = aList.First(); + + // add extra popup menu (defined in XML) + if ( myExtActions.size() > 0 ) { + // Use only first selected object + _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() ); + if ( aSO ) { + _PTR( GenericAttribute ) anAttr; + std::string auid = "AttributeUserID"; + auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID); + if ( aSO->FindAttribute( anAttr, auid ) ) { + _PTR(AttributeUserID) aAttrID = anAttr; + QString aId = aAttrID->Value().c_str(); + if ( myExtActions.contains( aId ) ) { + thePopup->addAction(myExtActions[aId]); } } } + } - // check if item is a "GUI state" item (also a first level object) - QString entry( aIObj->getEntry() ); - if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) { - QString aModuleName( aIObj->getComponentDataType() ); - QString aModuleTitle = moduleTitle( aModuleName ); - CAM_Module* currentModule = activeModule(); - if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() ) - thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) ); - } + // check if item is a "GUI state" item (also a first level object) + QString entry( aIObj->getEntry() ); + if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) { + QString aModuleName( aIObj->getComponentDataType() ); + QString aModuleTitle = moduleTitle( aModuleName ); + CAM_Module* currentModule = activeModule(); + if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() ) + thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) ); } } @@ -1456,25 +1503,21 @@ void SalomeApp_Application::updateObjectBrowser( const bool updateModels ) SalomeApp_Study* study = dynamic_cast(activeStudy()); if ( study ) { - _PTR(Study) stdDS = study->studyDS(); - if( stdDS ) + for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() ) { - for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() ) - { - _PTR(SComponent) aComponent ( it->Value() ); + _PTR(SComponent) aComponent ( it->Value() ); #ifndef WITH_SALOMEDS_OBSERVER - // with GUI observers this check is not needed anymore - if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() ) - continue; // skip the magic "Interface Applicative" component + // with GUI observers this check is not needed anymore + if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() ) + continue; // skip the magic "Interface Applicative" component #endif - if ( !objectBrowser() ) - getWindow( WT_ObjectBrowser ); - const bool isAutoUpdate = objectBrowser()->autoUpdate(); - objectBrowser()->setAutoUpdate( false ); - SalomeApp_DataModel::synchronize( aComponent, study ); - objectBrowser()->setAutoUpdate( isAutoUpdate ); - } + if ( !objectBrowser() ) + getWindow( WT_ObjectBrowser ); + const bool isAutoUpdate = objectBrowser()->autoUpdate(); + objectBrowser()->setAutoUpdate( false ); + SalomeApp_DataModel::synchronize( aComponent, study ); + objectBrowser()->setAutoUpdate( isAutoUpdate ); } } @@ -1522,6 +1565,7 @@ void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj ) if ( !aSelectedIndexes.isEmpty() ) ob->treeView()->scrollTo( aSelectedIndexes.first() ); } + emit objectDoubleClicked( theObj ); } /*! @@ -1674,7 +1718,7 @@ void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study ) // iterate new save points. if DataObject with such ID not found in map - create DataObject // if in the map - remove it from map. - for ( int i = 0; i < savePoints.size(); i++ ) + for ( size_t i = 0; i < savePoints.size(); i++ ) if ( !mapDO.contains( savePoints[i] ) ) new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study ); else @@ -1850,7 +1894,7 @@ bool SalomeApp_Application::renameAllowed( const QString& entry) const \param name new name of the object \brief Return \c true if rename operation finished successfully, \c false otherwise. */ -bool SalomeApp_Application::renameObject( const QString& entry, const QString& name ) +bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name ) { SalomeApp_Study* aStudy = dynamic_cast( activeStudy() ); @@ -1901,10 +1945,9 @@ bool SalomeApp_Application::updateStudy() myNoteBook->setIsDumpedStudySaved( study->isSaved() ); myNoteBook->setDumpedStudyName( study->studyName() ); - _PTR(Study) studyDS = study->studyDS(); - // get unique temporary directory name QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() ); + if( aTmpDir.isEmpty() ) return false; @@ -1920,12 +1963,12 @@ bool SalomeApp_Application::updateStudy() int savePoint; _PTR(AttributeParameter) ap; _PTR(IParameters) ip = ClientFactory::getIParameters(ap); - if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag. + if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag. if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method - ip->setDumpPython(studyDS); + ip->setDumpPython(); savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point } - bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile ); + bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile ); if ( toSaveGUI ) study->removeSavePoint(savePoint); //SRN: remove the created temporary save point. @@ -1991,7 +2034,8 @@ bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript, SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); // load study from the temporary directory - QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript ); + QFileInfo aScriptInfo = QFileInfo(theDumpScript); + QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath()); #ifndef DISABLE_PYCONSOLE PyConsole_Console* pyConsole = app->pythonConsole(); @@ -2000,7 +2044,6 @@ bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript, #endif // remove temporary directory - QFileInfo aScriptInfo = QFileInfo( theDumpScript ); QString aStudyName = aScriptInfo.baseName(); QDir aDir = aScriptInfo.absoluteDir(); QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) ); @@ -2012,8 +2055,8 @@ bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript, if( SalomeApp_Study* newStudy = dynamic_cast( app->activeStudy() ) ) { #ifndef DISABLE_PYCONSOLE - _PTR(Study) aStudyDS = newStudy->studyDS(); - app->getNoteBook()->Init( aStudyDS ); + if ( app->getNoteBook() ) + app->getNoteBook()->Init(); newStudy->updateFromNotebook(theStudyName, theIsStudySaved); newStudy->Modified(); updateDesktopTitle(); @@ -2042,23 +2085,20 @@ void SalomeApp_Application::afterCloseDoc() LightApp_Application::afterCloseDoc(); } +bool SalomeApp_Application::canOpenDoc( const QString& url ) +{ + _PTR(Study) aStudyDS = getStudy(); + if ( aStudyDS ) + return aStudyDS->CanOpen( url.toUtf8().data() ); + return false; +} + /* Asks to close existing document. */ bool SalomeApp_Application::checkExistingDoc() { - bool result = LightApp_Application::checkExistingDoc(); - if ( result && !activeStudy() ) { - SALOMEDSClient_StudyManager* aMgr = studyMgr(); - if ( aMgr ) { - std::vector List = studyMgr()->GetOpenStudies(); - if( List.size() > 0 ) { - SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" )); - result = false; - } - } - } - return result; + return LightApp_Application::checkExistingDoc(); } @@ -2066,7 +2106,25 @@ bool SalomeApp_Application::checkExistingDoc() PyConsole_Interp* SalomeApp_Application::createPyInterp() { - return new SalomeApp_PyInterp(); + return new SalomeApp_PyInterp; } #endif // DISABLE_PYCONSOLE + +void SalomeApp_Application::ensureShaperIsActivated() +{ + SalomeApp_Study* study = dynamic_cast(activeStudy()); + _PTR(Study) studyDS = getStudy(); + if ( study && studyDS ) + { + _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study + bool shaperIsActive = false; + QList models; + study->dataModels( models ); + for( int i = 0; i < models.count() && !shaperIsActive; i++ ) + shaperIsActive = models[i]->module()->moduleName() == "Shaper"; + + if (shaper && !shaperIsActive) + onDesktopMessage("register_module_in_study/Shaper"); + } +}