1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: SalomeApp_Application.cxx
24 // Created: 10/22/2004 3:23:45 PM
25 // Author: Sergey LITONIN
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #ifndef DISABLE_PYCONSOLE
37 #ifndef DISABLE_PYCONSOLE
38 #include "SalomeApp_PyInterp.h"
39 #include "SalomeApp_NoteBook.h"
40 #include "LightApp_PyEditor.h"
41 #include "PyConsole_Console.h"
43 #include "SalomeApp_Application.h"
44 #include "SalomeApp_Study.h"
45 #include "SalomeApp_DataModel.h"
46 #include "SalomeApp_DataObject.h"
47 #include "SalomeApp_VisualState.h"
48 #include "SalomeApp_StudyPropertiesDlg.h"
49 #include "SalomeApp_LoadStudiesDlg.h"
50 #include "SalomeApp_ExitDlg.h"
52 #include <LightApp_Application.h>
53 #include <LightApp_FileValidator.h>
54 #include <LightApp_Module.h>
55 #include <LightApp_Preferences.h>
56 #include <LightApp_SelectionMgr.h>
57 #include <LightApp_NameDlg.h>
58 #include <LightApp_DataOwner.h>
60 #include <CAM_Module.h>
62 #include <SUIT_Tools.h>
63 #include <SUIT_Session.h>
64 #include <SUIT_Desktop.h>
65 #include <SUIT_DataBrowser.h>
66 #include <SUIT_FileDlg.h>
67 #include <SUIT_MessageBox.h>
68 #include <SUIT_ResourceMgr.h>
69 #include <SUIT_TreeModel.h>
70 #include <SUIT_ViewWindow.h>
71 #include <SUIT_ViewManager.h>
72 #include <SUIT_ViewModel.h>
73 #include <SUIT_OverrideCursor.h>
75 #include <QtxTreeView.h>
77 #include <SALOME_EventFilter.h>
79 // temporary commented
80 //#include <OB_ListItem.h>
83 #include <Utils_ORB_INIT.hxx>
84 #include <Utils_SINGLETON.hxx>
85 #include <SALOME_LifeCycleCORBA.hxx>
87 #include <QApplication>
92 #include <QPushButton>
94 #include <QListWidget>
95 #include <QGridLayout>
99 #include <SALOMEDSClient_ClientFactory.hxx>
100 #include <Basics_Utils.hxx>
102 #include <SALOME_ListIO.hxx>
103 #include <SALOME_Prs.h>
106 #include <ToolsGUI_CatalogGeneratorDlg.h>
107 #include <ToolsGUI_RegWidget.h>
111 #include <SALOMEDS_Tool.hxx>
113 /*!Internal class that updates object browser item properties */
114 // temporary commented
115 /*class SalomeApp_Updater : public OB_Updater
118 SalomeApp_Updater() : OB_Updater(){};
119 virtual ~SalomeApp_Updater(){};
120 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
123 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
125 if( !theObj || !theItem )
128 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
132 _PTR(SObject) SObj = SAObj->object();
135 _PTR( GenericAttribute ) anAttr;
138 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
140 _PTR(AttributeSelectable) aAttrSel = anAttr;
141 theItem->setSelectable( aAttrSel->IsSelectable() );
144 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
146 _PTR(AttributeExpandable) aAttrExpand = anAttr;
147 theItem->setExpandable( aAttrExpand->IsExpandable() );
150 //this attribute is not supported in the version of SALOME 3.x
151 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
153 // _PTR(AttributeOpened) aAttrOpen = anAttr;
154 // theItem->setOpen( aAttrOpen->IsOpened() );
158 /*!Create new instance of SalomeApp_Application.*/
159 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
161 return new SalomeApp_Application();
165 SalomeApp_Application::SalomeApp_Application()
166 : LightApp_Application(),
167 myIsCloseFromExit( false )
172 *\li Destroy event filter.
174 SalomeApp_Application::~SalomeApp_Application()
176 // Do not destroy. It's a singleton !
177 //SALOME_EventFilter::Destroy();
180 QStringList __getArgsList(QString argsString)
182 // Special process if some items of 'args:' list are themselves lists
183 // Note that an item can be a list, but not a list of lists...
184 // So we can have something like this:
185 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
186 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
187 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
188 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
189 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
191 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
196 return argsString.split(",", QString::SkipEmptyParts);
199 /*!Start application.*/
200 void SalomeApp_Application::start()
202 // process the command line options before start: to createActions in accordance to the options
203 static bool isFirst = true;
211 for (int i = 1; i < qApp->arguments().size(); i++) {
212 QRegExp rxs ("--study-hdf=(.+)");
213 if ( rxs.indexIn( qApp->arguments()[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
214 QString file = rxs.capturedTexts()[1];
215 QFileInfo fi ( file );
216 QString extension = fi.suffix().toLower();
217 if ( extension == "hdf" && fi.exists() )
218 hdffile = fi.absoluteFilePath();
221 QRegExp rxp ("--pyscript=\\[(.+)\\]");
222 if ( rxp.indexIn( qApp->arguments()[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
224 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
225 for (int k = 0; k < dictList.count(); ++k) {
226 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
227 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
228 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
229 pyfiles += rxd.capturedTexts()[m];
236 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
237 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
239 LightApp_Application::start();
240 SALOME_EventFilter::Init();
242 setProperty("open_study_from_command_line", true);
243 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
244 onOpenDoc( hdffile );
245 else if ( pyfiles.count() > 0 ) // create new study
247 else if (!loadStudy.isEmpty()) {// load study by name
248 if (onLoadDoc(loadStudy))
249 updateObjectBrowser(true);
251 setProperty("open_study_from_command_line", QVariant());
253 #ifndef DISABLE_PYCONSOLE
254 // import/execute python scripts
255 if ( pyfiles.count() > 0 && activeStudy() ) {
256 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
257 PyConsole_Console* pyConsole = pythonConsole();
258 if ( appStudy && pyConsole ) {
259 _PTR(Study) aStudy = appStudy->studyDS();
260 if ( !aStudy->GetProperties()->IsLocked() ) {
261 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
262 // Path is absolute, script has .py extension
263 for (uint j = 0; j < pyfiles.count(); j++ ) {
264 // Extract scripts and their arguments, if any
265 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
266 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
267 QString script = rxp.capturedTexts()[1];
269 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
270 for (uint k = 0; k < argList.count(); k++ ) {
271 QString arg = argList[k].trimmed();
272 arg.remove( QRegExp("^[\"]") );
273 arg.remove( QRegExp("[\"]$") );
276 args.remove( QRegExp("[,]$") );
277 if (!args.isEmpty()) {
281 script.remove( QRegExp("^python.*[\\s]+") );
282 QString cmd = script+" "+args;
283 QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
284 pyConsole->exec(command);
286 } // end for loop on pyfiles QStringList
292 LightApp_Application::start();
293 SALOME_EventFilter::Init();
298 void SalomeApp_Application::createActions()
300 LightApp_Application::createActions();
302 SUIT_Desktop* desk = desktop();
305 // "Save GUI State" command is moved to VISU module
306 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
307 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
308 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
311 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
312 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
313 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
316 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
317 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
318 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
321 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
322 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
323 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
325 //! Catalog Generator
326 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
327 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
328 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
331 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
332 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
333 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
335 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
336 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
337 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
339 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
340 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
341 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
344 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
346 // "Save GUI State" command is renamed to "Save VISU State" and
347 // creation of menu item is moved to VISU
348 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
350 createMenu( ConnectId, fileMenu, 5 );
351 createMenu( DisconnectId, fileMenu, 5 );
352 createMenu( separator(), fileMenu, -1, 5 );
354 createMenu( DumpStudyId, fileMenu, 10, -1 );
355 createMenu( LoadScriptId, fileMenu, 10, -1 );
356 createMenu( separator(), fileMenu, -1, 10, -1 );
357 createMenu( PropertiesId, fileMenu, 10, -1 );
358 createMenu( separator(), fileMenu, -1, 10, -1 );
360 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
361 createMenu( CatalogGenId, toolsMenu, 10, -1 );
362 createMenu( RegDisplayId, toolsMenu, 10, -1 );
363 createMenu( separator(), toolsMenu, -1, 15, -1 );
365 createExtraActions();
367 #ifndef DISABLE_PYCONSOLE
368 #ifndef DISABLE_SALOMEOBJECT
369 // import Python module that manages SALOME plugins
371 PyLockWrapper lck; // acquire GIL
372 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
373 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
377 // end of SALOME plugins loading
384 \brief Close application.
386 void SalomeApp_Application::onExit()
388 bool killServers = false;
391 if ( exitConfirmation() ) {
392 SalomeApp_ExitDlg dlg( desktop() );
393 result = dlg.exec() == QDialog::Accepted;
394 killServers = dlg.isServersShutdown();
398 if ( !killServers ) myIsCloseFromExit = true;
399 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
400 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
404 /*!SLOT. Load document.*/
405 void SalomeApp_Application::onLoadDoc()
409 std::vector<std::string> List = studyMgr()->GetOpenStudies();
411 // rnv: According to the single-study approach on the server side
412 // can be only one study. So if it is exists connect to them,
413 // overwise show warning message: "No active study on the server"
416 SUIT_Session* aSession = SUIT_Session::session();
417 QList<SUIT_Application*> aAppList = aSession->applications();
419 QStringList unloadedStudies;
421 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
422 studyName = List[ind].c_str();
423 // Add to list only unloaded studies
424 bool isAlreadyOpen = false;
425 QListIterator<SUIT_Application*> it( aAppList );
426 while ( it.hasNext() && !isAlreadyOpen ) {
427 SUIT_Application* aApp = it.next();
428 if( !aApp || !aApp->activeStudy() )
430 if ( aApp->activeStudy()->studyName() == studyName )
431 isAlreadyOpen = true;
434 if ( !isAlreadyOpen )
435 unloadedStudies << studyName;
437 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
438 if ( studyName.isEmpty() )
442 if(List.size() <= 0) {
443 SUIT_MessageBox::warning( desktop(),
444 QObject::tr("WRN_WARNING"),
445 QObject::tr("WRN_NO_STUDY_ON SERV") );
449 studyName = List[0].c_str();
452 // this code replaces marker of windows drive and path become invalid therefore
453 // defines placed there
454 studyName.replace( QRegExp(":"), "/" );
457 if ( onLoadDoc( studyName ) ) {
459 updateViewManagers();
460 updateObjectBrowser( true );
464 /*!SLOT. Unload document.*/
465 void SalomeApp_Application::onUnloadDoc( bool ask )
468 activeStudy()->abortAllOperations();
469 if ( activeStudy()->isModified() ) {
470 QString docName = activeStudy()->studyName().trimmed();
471 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
472 tr( "DISCONNECT_DESCRIPTION" ),
473 tr( "DISCONNECT_SAVE" ),
474 tr( "DISCONNECT_WO_SAVE" ),
475 tr( "APPCLOSE_CANCEL" ), 0 );
476 if ( answer == 0 ) { // save before unload
477 if ( activeStudy()->isSaved() )
479 else if ( !onSaveAsDoc() )
482 else if ( answer == 2 ) // Cancel
486 closeActiveDoc( false );
489 /*!SLOT. Create new study and load script*/
490 void SalomeApp_Application::onNewWithScript()
492 QStringList filtersList;
493 filtersList.append(tr("PYTHON_FILES_FILTER"));
494 filtersList.append(tr("ALL_FILES_FILTER"));
496 QString anInitialPath = "";
497 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
498 anInitialPath = QDir::currentPath();
500 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
502 if ( !aFile.isEmpty() )
506 QString command = QString("execfile(r\"%1\")").arg(aFile);
508 #ifndef DISABLE_PYCONSOLE
509 PyConsole_Console* pyConsole = pythonConsole();
512 pyConsole->exec( command );
518 /*!SLOT. Load document with \a aName.*/
519 bool SalomeApp_Application::onLoadDoc( const QString& aName )
521 #ifdef SINGLE_DESKTOP
522 if ( !LightApp_Application::closeDoc() )
526 if ( !activeStudy() ) {
527 // if no study - load in current desktop
528 res = useStudy( aName );
531 // if study exists - load in new desktop. Check: is the same file is loaded?
532 SUIT_Session* aSession = SUIT_Session::session();
533 QList<SUIT_Application*> aAppList = aSession->applications();
534 bool isAlreadyOpen = false;
535 SalomeApp_Application* aApp = 0;
536 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
537 it != aAppList.end() && !isAlreadyOpen; ++it ) {
538 aApp = dynamic_cast<SalomeApp_Application*>( *it );
539 if ( aApp && aApp->activeStudy()->studyName() == aName )
540 isAlreadyOpen = true;
542 if ( !isAlreadyOpen ) {
543 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
545 res = aApp->useStudy( aName );
548 aApp->desktop()->activateWindow();
555 /*!SLOT. Parse message for desktop.*/
556 void SalomeApp_Application::onDesktopMessage( const QString& message )
558 if (message.indexOf("studyCreated:") == 0) {
559 // Enable 'Connect' action
560 updateCommandsStatus();
562 else if (message.indexOf("studyClosed:") == 0) {
563 /* message also contains ID of the closed study,
564 but as soon as SALOME is mono-study application for the moment,
565 this ID is not needed now.*/
566 //long aStudyId = message.section(':', 1).toLong();
567 // Disconnect GUI from active study, because it was closed on DS side.
568 closeActiveDoc( false );
569 // Disable 'Connect' action
570 QAction* a = action( ConnectId );
572 a->setEnabled( false );
574 else if ( message.toLower() == "connect_to_study" ) {
577 LightApp_Application::onDesktopMessage( message );
580 /*!SLOT. Copy objects to study maneger from selection maneger..*/
581 void SalomeApp_Application::onCopy()
583 LightApp_Application::onCopy();
586 LightApp_SelectionMgr* mgr = selectionMgr();
587 mgr->selectedObjects(list);
589 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
590 if(study == NULL) return;
592 _PTR(Study) stdDS = study->studyDS();
595 SALOME_ListIteratorOfListIO it( list );
598 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
602 studyMgr()->Copy(so);
603 onSelectionChanged();
611 /*!SLOT. Paste objects to study maneger from selection manager.*/
612 void SalomeApp_Application::onPaste()
614 LightApp_Application::onPaste();
617 LightApp_SelectionMgr* mgr = selectionMgr();
618 mgr->selectedObjects(list);
620 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
621 if(study == NULL) return;
623 _PTR(Study) stdDS = study->studyDS();
626 if ( stdDS->GetProperties()->IsLocked() ) {
627 SUIT_MessageBox::warning( desktop(),
628 QObject::tr("WRN_WARNING"),
629 QObject::tr("WRN_STUDY_LOCKED") );
633 SALOME_ListIteratorOfListIO it( list );
636 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
640 studyMgr()->Paste(so);
641 updateObjectBrowser( true );
642 updateActions(); //SRN: BugID IPAL9377, case 3
650 /*!Check the application on closing.
651 * \retval true if possible, else false
653 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
655 return LightApp_Application::isPossibleToClose( closePermanently );
658 /*! Check if the study is locked */
659 void SalomeApp_Application::onCloseDoc( bool ask )
661 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
664 _PTR(Study) stdDS = study->studyDS();
665 if(stdDS && stdDS->IsStudyLocked()) {
666 if ( SUIT_MessageBox::question( desktop(),
667 QObject::tr( "WRN_WARNING" ),
668 QObject::tr( "CLOSE_LOCKED_STUDY" ),
669 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
670 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
674 LightApp_Application::onCloseDoc( ask );
677 /*!Sets enable or disable some actions on selection changed.*/
678 void SalomeApp_Application::onSelectionChanged()
681 LightApp_SelectionMgr* mgr = selectionMgr();
682 mgr->selectedObjects(list);
684 bool canCopy = false;
685 bool canPaste = false;
687 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
690 canCopy = m->canCopy();
691 canPaste = m->canPaste();
694 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
696 _PTR(Study) stdDS = study->studyDS();
699 SALOME_ListIteratorOfListIO it ( list );
701 if (it.More() && list.Extent() == 1) {
702 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
705 canCopy = canCopy || studyMgr()->CanCopy(so);
706 canPaste = canPaste || studyMgr()->CanPaste(so);
712 action(EditCopyId)->setEnabled(canCopy);
713 action(EditPasteId)->setEnabled(canPaste);
716 /*!Delete references.*/
717 void SalomeApp_Application::onDeleteInvalidReferences()
720 LightApp_SelectionMgr* mgr = selectionMgr();
721 mgr->selectedObjects( aList, QString(), false );
723 if( aList.IsEmpty() )
726 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
727 _PTR(Study) aStudyDS = aStudy->studyDS();
728 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
731 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
732 if ( it.Value()->hasEntry() )
734 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
735 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
738 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
739 aStudyBuilder->RemoveReference( aSObject );
741 updateObjectBrowser();
745 void SalomeApp_Application::onOpenWith()
747 QApplication::setOverrideCursor( Qt::WaitCursor );
749 LightApp_SelectionMgr* mgr = selectionMgr();
750 mgr->selectedObjects(aList);
751 if (aList.Extent() != 1)
753 QApplication::restoreOverrideCursor();
756 Handle(SALOME_InteractiveObject) aIObj = aList.First();
757 QString aModuleName(aIObj->getComponentDataType());
758 QString aModuleTitle = moduleTitle(aModuleName);
759 activateModule(aModuleTitle);
760 QApplication::restoreOverrideCursor();
766 SUIT_Study* SalomeApp_Application::createNewStudy()
768 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
770 // Set up processing of major study-related events
771 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
772 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
773 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
774 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
776 #ifndef DISABLE_PYCONSOLE
777 //to receive signal in application that NoteBook's variable was modified
778 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
779 this, SIGNAL(notebookVarUpdated(QString)) );
786 Enable/Disable menu items and toolbar buttons. Rebuild menu
788 void SalomeApp_Application::updateCommandsStatus()
790 LightApp_Application::updateCommandsStatus();
793 QAction* a = action( DumpStudyId );
795 a->setEnabled( activeStudy() );
797 #ifndef DISABLE_PYCONSOLE
799 a = action( LoadScriptId );
801 a->setEnabled( pythonConsole() );
805 a = action( PropertiesId );
807 a->setEnabled( activeStudy() );
809 // Save GUI state menu
810 a = action( SaveGUIStateId );
812 a->setEnabled( activeStudy() );
814 // Connect study menu
815 a = action( ConnectId );
817 a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
819 // Disconnect study menu
820 a = action( DisconnectId );
822 a->setEnabled( activeStudy() );
824 // update state of Copy/Paste menu items
825 onSelectionChanged();
829 \class DumpStudyFileDlg
830 Private class used in Dump Study operation. Consists 2 check boxes:
831 "Publish in study" and "Save GUI parameters"
833 class DumpStudyFileDlg : public SUIT_FileDlg
836 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
838 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
841 QWidget *hB = new QWidget( this );
842 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
843 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
844 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
846 QHBoxLayout *layout = new QHBoxLayout;
847 layout->addWidget(myPublishChk);
848 layout->addWidget(myMultiFileChk);
849 layout->addWidget(mySaveGUIChk);
850 hB->setLayout(layout);
852 QPushButton* pb = new QPushButton(this);
854 int row = grid->rowCount();
855 grid->addWidget( new QLabel("", this), row, 0 );
856 grid->addWidget( hB, row, 1, 1, 3 );
857 grid->addWidget( pb, row, 5 );
862 QCheckBox* myPublishChk;
863 QCheckBox* myMultiFileChk;
864 QCheckBox* mySaveGUIChk;
867 /*!Private SLOT. On dump study.*/
868 void SalomeApp_Application::onDumpStudy( )
870 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
871 if ( !appStudy ) return;
872 _PTR(Study) aStudy = appStudy->studyDS();
874 QStringList aFilters;
875 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
877 bool anIsPublish = true;
878 bool anIsMultiFile = false;
879 bool anIsSaveGUI = true;
881 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
882 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
883 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
884 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
887 DumpStudyFileDlg fd( desktop() );
888 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
889 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
890 fd.setNameFilters( aFilters );
891 fd.myPublishChk->setChecked( anIsPublish );
892 fd.myMultiFileChk->setChecked( anIsMultiFile );
893 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
894 if ( fd.exec() == QDialog::Accepted )
896 QString aFileName = fd.selectedFile();
898 bool toPublish = fd.myPublishChk->isChecked();
899 bool isMultiFile = fd.myMultiFileChk->isChecked();
900 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
902 if ( !aFileName.isEmpty() ) {
903 QFileInfo aFileInfo(aFileName);
904 if( aFileInfo.isDir() ) // IPAL19257
907 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
910 SUIT_OverrideCursor wc;
911 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
914 SUIT_MessageBox::warning( desktop(),
915 QObject::tr("WRN_WARNING"),
916 tr("WRN_DUMP_STUDY_FAILED") );
921 /*!Private SLOT. On load script.*/
922 void SalomeApp_Application::onLoadScript( )
924 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
926 _PTR(Study) aStudy = appStudy->studyDS();
927 if ( aStudy->GetProperties()->IsLocked() ) {
928 SUIT_MessageBox::warning( desktop(),
929 QObject::tr("WRN_WARNING"),
930 QObject::tr("WRN_STUDY_LOCKED") );
935 QStringList filtersList;
936 filtersList.append(tr("PYTHON_FILES_FILTER"));
937 filtersList.append(tr("ALL_FILES_FILTER"));
939 QString anInitialPath = "";
940 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
941 anInitialPath = QDir::currentPath();
943 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
945 if ( !aFile.isEmpty() )
947 QString command = QString("execfile(r\"%1\")").arg(aFile);
949 #ifndef DISABLE_PYCONSOLE
950 PyConsole_Console* pyConsole = pythonConsole();
953 pyConsole->exec( command );
958 /*!Private SLOT. On save GUI state.*/
959 void SalomeApp_Application::onSaveGUIState()
961 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
963 SalomeApp_VisualState( this ).storeState();
964 updateSavePointDataObjects( study );
965 updateObjectBrowser();
970 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
971 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
973 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
974 QAction* send = ::qobject_cast<QAction*>( sender() );
977 QString aWinName = send->data().toString();
978 if ( theIsVisible && aWinName == "objectBrowser" )
979 objectBrowserColumnsVisibility();
983 *\retval QString "(*.hdf)"
985 QString SalomeApp_Application::getFileFilter() const
991 QWidget* SalomeApp_Application::createWindow( const int flag )
994 #ifndef DISABLE_PYCONSOLE
995 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
997 wid = LightApp_Application::createWindow(flag);
1000 SUIT_ResourceMgr* resMgr = resourceMgr();
1002 if ( flag == WT_ObjectBrowser )
1004 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1006 // temporary commented
1007 //ob->setUpdater( new SalomeApp_Updater() );
1009 #ifdef WITH_SALOMEDS_OBSERVER
1010 //do not activate the automatic update of Qt tree through signal/slot
1011 ob->setAutoUpdate(false);
1012 //activate update of modified objects only
1013 ob->setUpdateModified(true);
1016 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1019 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1020 IORCol = QObject::tr( "IOR_COLUMN" ),
1021 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1022 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1024 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1025 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1026 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1027 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1028 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1029 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1030 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1031 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1032 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1034 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1035 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1036 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1038 ob->setAutoSizeFirstColumn(autoSizeFirst);
1039 ob->setAutoSizeColumns(autoSize);
1040 ob->setResizeOnExpandItem(resizeOnExpandItem);
1041 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1043 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1045 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1046 ob->treeView()->setColumnHidden( i, !shown );
1049 // temporary commented
1051 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1053 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1054 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1055 QString().sprintf( "visibility_column_%d", i ), true ) );
1059 // temporary commented
1061 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1062 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1063 ob->resize( desktop()->width()/3, ob->height() );
1067 #ifndef DISABLE_PYCONSOLE
1068 else if ( flag == WT_PyConsole )
1070 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1071 pyCons->setObjectName( "pythonConsole" );
1072 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1073 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1074 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1075 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1076 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1079 else if ( flag == WT_NoteBook )
1081 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1083 _PTR(Study) aStudy = appStudy->studyDS();
1084 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1085 //to receive signal in NoteBook that it's variable was modified
1086 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1087 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1089 wid = getNoteBook();
1090 wid->setObjectName( "noteBook" );
1096 /*!Create preferences.*/
1097 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1099 LightApp_Application::createPreferences(pref);
1104 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1105 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1106 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1107 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1109 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1110 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1112 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1114 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1115 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1116 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1117 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1118 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1119 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1120 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1121 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1122 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1123 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1126 /*!Update desktop title.*/
1127 void SalomeApp_Application::updateDesktopTitle() {
1128 QString aTitle = applicationName();
1129 QString aVer = applicationVersion();
1130 if ( !aVer.isEmpty() )
1131 aTitle += QString( " " ) + aVer;
1133 if ( activeStudy() )
1135 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1136 if ( !sName.isEmpty() ) {
1137 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1139 _PTR(Study) stdDS = study->studyDS();
1141 if ( stdDS->GetProperties()->IsLocked() ) {
1142 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1144 aTitle += QString( " - [%1]" ).arg( sName );
1151 desktop()->setWindowTitle( aTitle );
1154 int SalomeApp_Application::closeChoice( const QString& docName )
1156 QStringList buttons;
1157 QMap<int, int> choices;
1159 buttons << tr ("APPCLOSE_SAVE"); // Save & Close
1160 choices.insert( idx++, CloseSave ); // ...
1161 buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving
1162 choices.insert( idx++, CloseDiscard ); // ...
1163 if ( myIsCloseFromExit ) {
1164 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1165 choices.insert( idx++, CloseDisconnectSave ); // ...
1166 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1167 choices.insert( idx++, CloseDisconnect ); // ...
1169 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1170 choices.insert( idx++, CloseCancel ); // ...
1172 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1173 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1174 return choices[answer];
1177 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1183 if ( activeStudy()->isSaved() )
1185 else if ( !onSaveAsDoc() )
1190 case CloseDisconnectSave:
1191 if ( activeStudy()->isSaved() )
1193 else if ( !onSaveAsDoc() )
1195 case CloseDisconnect:
1196 closeActiveDoc( false );
1197 closePermanently = false;
1206 int SalomeApp_Application::openChoice( const QString& aName )
1208 int choice = LightApp_Application::openChoice( aName );
1210 if ( QFileInfo( aName ).exists() ) {
1211 if ( choice == OpenNew ) { // The document isn't already open.
1213 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1214 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1215 if ( aName == QString( lst[i].c_str() ) )
1218 // The document already exists in the study manager.
1219 // Do you want to reload it?
1221 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1222 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1223 if ( answer == SUIT_MessageBox::Yes )
1224 choice = OpenRefresh;
1226 choice = OpenCancel;
1229 } else { // file is not exist on disk
1230 SUIT_MessageBox::warning( desktop(),
1231 QObject::tr("WRN_WARNING"),
1232 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1239 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1242 int choice = aChoice;
1247 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1250 studyMgr()->Close( aStudy );
1255 res = LightApp_Application::openAction( choice, aName );
1263 \brief Get map of the operations which can be performed
1264 on the module activation.
1266 The method should return the map of the kind \c {<id>:<name>}
1267 where \c <id> is an integer identifier of the operation and
1268 \c <name> is a title for the button to be added to the
1269 dialog box. After user selects the required operation by the
1270 clicking the corresponding button in the dialog box, its identifier
1271 is passed to the moduleActionSelected() method to process
1274 \return map of the operations
1275 \sa moduleActionSelected()
1277 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1279 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1281 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1283 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1288 \brief Called when the used selectes required operation chosen
1289 from "Activate module" dialog box.
1291 Performs the required operation according to the user choice.
1293 \param id operation identifier
1294 \sa activateModuleActions()
1296 void SalomeApp_Application::moduleActionSelected( const int id )
1302 case NewAndScriptId:
1306 LightApp_Application::moduleActionSelected( id );
1311 /*!Gets CORBA::ORB_var*/
1312 CORBA::ORB_var SalomeApp_Application::orb()
1314 static CORBA::ORB_var _orb;
1316 if ( CORBA::is_nil( _orb ) ) {
1317 Qtx::CmdLineArgs args;
1318 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1319 _orb = init( args.argc(), args.argv() );
1325 /*!Create and return SALOMEDS_StudyManager.*/
1326 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1328 static _PTR(StudyManager) _sm;
1329 if(!_sm) _sm = ClientFactory::StudyManager();
1333 /*!Create and return SALOME_NamingService.*/
1334 SALOME_NamingService* SalomeApp_Application::namingService()
1336 static SALOME_NamingService _ns(orb());
1340 /*!Create and return SALOME_LifeCycleCORBA.*/
1341 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1343 static SALOME_LifeCycleCORBA _lcc( namingService() );
1347 /*!Private SLOT. On preferences.*/
1348 void SalomeApp_Application::onProperties()
1350 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1354 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1357 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1358 int res = aDlg.exec();
1359 if( res==QDialog::Accepted && aDlg.isChanged() )
1360 SB->CommitCommand();
1364 //study->updateCaptions();
1365 updateDesktopTitle();
1369 /*!Insert items in popup, which necessary for current application*/
1370 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1372 LightApp_SelectionMgr* mgr = selectionMgr();
1373 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1374 mgr->setSelectionCacheEnabled( true );
1376 LightApp_Application::contextMenuPopup( type, thePopup, title );
1378 // temporary commented
1379 /*OB_Browser* ob = objectBrowser();
1380 if ( !ob || type != ob->popupClientType() )
1383 // Get selected objects
1384 SALOME_ListIO aList;
1385 mgr->selectedObjects( aList, QString(), false );
1387 // add GUI state commands: restore, rename
1388 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1389 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1390 thePopup->addSeparator();
1391 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1392 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1393 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1394 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1397 // "Delete reference" item should appear only for invalid references
1399 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1400 bool isInvalidRefs = false;
1401 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1403 _PTR(Study) aStudyDS = aStudy->studyDS();
1404 _PTR(SObject) anObj;
1406 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1408 if( it.Value()->hasEntry() )
1410 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1411 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1414 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1415 isInvalidRefs = true;
1419 // Add "Delete reference" item to popup
1420 if ( isInvalidRefs )
1422 thePopup->addSeparator();
1423 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1427 // "Activate module" item should appear only if it's necessary
1428 if ( aList.Extent() == 1 ) {
1430 mgr->selectedObjects( aList );
1432 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1434 // add extra popup menu (defined in XML)
1435 if ( myExtActions.size() > 0 ) {
1436 // Use only first selected object
1437 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1439 _PTR(Study) stdDS = study->studyDS();
1441 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1443 _PTR( GenericAttribute ) anAttr;
1444 std::string auid = "AttributeUserID";
1445 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1446 if ( aSO->FindAttribute( anAttr, auid ) ) {
1447 _PTR(AttributeUserID) aAttrID = anAttr;
1448 QString aId = aAttrID->Value().c_str();
1449 if ( myExtActions.contains( aId ) ) {
1450 thePopup->addAction(myExtActions[aId]);
1458 // check if item is a "GUI state" item (also a first level object)
1459 QString entry( aIObj->getEntry() );
1460 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1461 QString aModuleName( aIObj->getComponentDataType() );
1462 QString aModuleTitle = moduleTitle( aModuleName );
1463 CAM_Module* currentModule = activeModule();
1464 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1465 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1470 mgr->setSelectionCacheEnabled( cacheIsOn );
1473 /*!Update obect browser:
1474 1.if 'updateModels' true, update existing data models;
1475 2. update "non-existing" (not loaded yet) data models;
1476 3. update object browser if it exists */
1477 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1479 // update "non-existing" (not loaded yet) data models
1480 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1483 _PTR(Study) stdDS = study->studyDS();
1486 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1488 _PTR(SComponent) aComponent ( it->Value() );
1490 #ifndef WITH_SALOMEDS_OBSERVER
1491 // with GUI observers this check is not needed anymore
1492 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1493 continue; // skip the magic "Interface Applicative" component
1495 if ( !objectBrowser() )
1496 getWindow( WT_ObjectBrowser );
1497 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1498 objectBrowser()->setAutoUpdate( false );
1499 SalomeApp_DataModel::synchronize( aComponent, study );
1500 objectBrowser()->setAutoUpdate( isAutoUpdate );
1505 // create data objects that correspond to GUI state save points
1506 if ( study ) updateSavePointDataObjects( study );
1508 // update existing data models (already loaded SComponents)
1509 LightApp_Application::updateObjectBrowser( updateModels );
1512 /*!Display Catalog Genenerator dialog */
1513 void SalomeApp_Application::onCatalogGen()
1515 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1519 /*!Display Registry Display dialog */
1520 void SalomeApp_Application::onRegDisplay()
1522 CORBA::ORB_var anOrb = orb();
1523 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1526 regWnd->activateWindow();
1529 /*!find original object by double click on item */
1530 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1532 // Issue 21379: References are supported at LightApp_DataObject level
1533 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1535 if( obj && obj->isReference() )
1537 QString entry = obj->refEntry();
1539 SUIT_DataOwnerPtrList aList;
1540 aList.append( new LightApp_DataOwner( entry ) );
1541 selectionMgr()->setSelected( aList, false );
1543 SUIT_DataBrowser* ob = objectBrowser();
1545 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1546 if ( !aSelectedIndexes.isEmpty() )
1547 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1549 emit objectDoubleClicked( theObj );
1553 Creates new view manager
1554 \param type - type of view manager
1556 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1558 return createViewManager(type);
1562 /*!Global utility function, returns selected GUI Save point object's ID */
1563 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1565 SALOME_ListIO aList;
1566 selMgr->selectedObjects( aList );
1567 if( aList.Extent() > 0 ) {
1568 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1569 QString entry( aIObj->getEntry() );
1570 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1571 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1573 bool ok; // conversion to integer is ok?
1574 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1575 return ok ? savePoint : -1;
1580 /*!Called on Restore GUI State popup command*/
1581 void SalomeApp_Application::onRestoreGUIState()
1583 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1584 if ( savePoint == -1 )
1586 SalomeApp_VisualState( this ).restoreState( savePoint );
1589 /*!Called on Delete GUI State popup command*/
1590 void SalomeApp_Application::onDeleteGUIState()
1592 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1593 if ( savePoint == -1 )
1595 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1599 study->removeSavePoint( savePoint );
1600 updateSavePointDataObjects( study );
1603 /*!Called on New study operation*/
1604 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1606 LightApp_Application::onStudyCreated( study );
1608 //#ifndef DISABLE_PYCONSOLE
1609 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1610 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1613 loadDockWindowsState();
1615 objectBrowserColumnsVisibility();
1618 /*!Called on Open study operation*/
1619 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1621 LightApp_Application::onStudyOpened( study );
1623 //#ifndef DISABLE_PYCONSOLE
1624 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1625 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1628 loadDockWindowsState();
1630 objectBrowserColumnsVisibility();
1632 // temporary commented
1633 /*if ( objectBrowser() ) {
1634 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1635 objectBrowser()->updateTree( study->root() );
1639 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1640 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1643 SUIT_DataBrowser* ob = objectBrowser();
1644 LightApp_SelectionMgr* selMgr = selectionMgr();
1646 if ( !study || !ob || !selMgr )
1649 // find GUI states root object
1650 SUIT_DataObject* guiRootObj = 0;
1652 study->root()->children( ch );
1653 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1654 for ( ; it != last ; ++it ) {
1655 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1660 std::vector<int> savePoints = study->getSavePoints();
1661 // case 1: no more save points but they existed in study's tree
1662 if ( savePoints.empty() && guiRootObj ) {
1663 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1664 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1665 const bool isAutoUpdate = ob->autoUpdate();
1666 selMgr->clearSelected();
1667 ob->setAutoUpdate(true);
1668 DataObjectList ch = guiRootObj->children();
1669 for( int i = 0; i < ch.size(); i++ )
1672 ob->setAutoUpdate(isAutoUpdate);
1675 // case 2: no more save points but root does not exist either
1676 if ( savePoints.empty() && !guiRootObj )
1678 // case 3: save points but no root for them - create it
1679 if ( !savePoints.empty() && !guiRootObj )
1680 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1681 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1682 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1684 if ( guiRootObj->nextBrother() ) {
1685 study->root()->removeChild(guiRootObj);
1686 study->root()->appendChild(guiRootObj);
1687 //study->root()->dump();
1690 // store data objects in a map id-to-DataObject
1691 QMap<int,SalomeApp_SavePointObject*> mapDO;
1693 guiRootObj->children( ch );
1694 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1695 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1697 mapDO[dobj->getId()] = dobj;
1700 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1701 // if in the map - remove it from map.
1702 for ( int i = 0; i < savePoints.size(); i++ )
1703 if ( !mapDO.contains( savePoints[i] ) )
1704 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1706 mapDO.remove( savePoints[i] );
1708 // delete DataObjects that are still in the map -- their IDs were not found in data model
1709 if( mapDO.size() > 0) {
1710 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1711 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1712 selMgr->clearSelected();
1713 const bool isAutoUpdate = ob->autoUpdate();
1714 ob->setAutoUpdate(true);
1715 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1717 ob->setAutoUpdate(isAutoUpdate);
1721 /*! Check data object */
1722 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1731 Opens other study into active Study. If Study is empty - creates it.
1732 \param theName - name of study
1734 bool SalomeApp_Application::useStudy( const QString& theName )
1737 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1740 res = aStudy->loadDocument( theName );
1741 updateDesktopTitle();
1742 updateCommandsStatus();
1746 /*! Show/hide object browser colums according to preferences */
1747 void SalomeApp_Application::objectBrowserColumnsVisibility()
1749 if ( objectBrowser() )
1750 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1752 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1753 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1757 #ifndef DISABLE_PYCONSOLE
1758 /*! Set SalomeApp_NoteBook pointer */
1759 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1761 myNoteBook = theNoteBook;
1764 /*! Return SalomeApp_NoteBook pointer */
1765 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1772 * Define extra actions defined in module definition XML file.
1773 * Additional popup items sections can be defined by parameter "popupitems".
1774 * Supported attributes:
1775 * title - title of menu item,
1776 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1777 * method - method which has to be called when menu item is selected
1779 * <section name="MODULENAME">
1780 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1782 * <section name="importmed">
1783 * <parameter name="title" value="My menu"/>
1784 * <parameter name="objectid" value="VISU.Result"/>
1785 * <parameter name="method" value="nameOfModuleMethod"/>
1788 void SalomeApp_Application::createExtraActions()
1790 myExtActions.clear();
1791 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1793 QStringList aModules;
1794 modules(aModules, false);
1795 foreach(QString aModile, aModules) {
1796 QString aModName = moduleName(aModile);
1797 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1798 if (!aSectionStr.isNull()) {
1799 QStringList aSections = aSectionStr.split(':');
1800 foreach(QString aSection, aSections) {
1801 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1802 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1803 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1804 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1807 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1808 if (aModuleName.isNull())
1809 aModuleName = aModName;
1811 QAction* aAction = new QAction(aTitle, this);
1813 aData<<aModuleName<<aSlot;
1814 aAction->setData(aData);
1815 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1816 myExtActions[aId] = aAction;
1823 * Called when extra action is selected
1825 void SalomeApp_Application::onExtAction()
1827 QAction* aAction = ::qobject_cast<QAction*>(sender());
1831 QVariant aData = aAction->data();
1832 QStringList aDataList = aData.value<QStringList>();
1833 if (aDataList.size() != 2)
1836 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1837 SALOME_ListIO aListIO;
1838 aSelectionMgr->selectedObjects(aListIO);
1839 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1840 if (aListIO.Extent() < 1)
1842 if (!anIO->hasEntry())
1845 QString aEntry(anIO->getEntry());
1847 QApplication::setOverrideCursor( Qt::WaitCursor );
1848 QString aModuleTitle = moduleTitle(aDataList[0]);
1849 activateModule(aModuleTitle);
1850 QApplication::restoreOverrideCursor();
1852 QCoreApplication::processEvents();
1854 CAM_Module* aModule = activeModule();
1858 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1859 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1863 Checks that an object can be renamed.
1864 \param entry entry of the object
1865 \brief Return \c true if object can be renamed
1867 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1869 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1873 Rename object by entry.
1874 \param entry entry of the object
1875 \param name new name of the object
1876 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1878 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1880 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1882 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1884 if(!aStudy || savePoint == -1)
1887 if ( !name.isNull() && !name.isEmpty() ) {
1888 aStudy->setNameOfSavePoint( savePoint, name );
1889 updateSavePointDataObjects( aStudy );
1891 //Mark study as modified
1898 #ifndef DISABLE_PYCONSOLE
1899 //============================================================================
1900 /*! Function : onUpdateStudy
1901 * Purpose : Slot to update the study.
1903 //============================================================================
1904 void SalomeApp_Application::onUpdateStudy()
1906 QApplication::setOverrideCursor( Qt::WaitCursor );
1908 if( !updateStudy() )
1909 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1911 QApplication::restoreOverrideCursor();
1914 //============================================================================
1915 /*! Function : updateStudy
1916 * Purpose : Update study by dumping the study to Python script and loading it.
1917 * It is used to apply variable modifications done in NoteBook to created objects.
1919 //============================================================================
1920 bool SalomeApp_Application::updateStudy()
1922 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1923 if ( !study || !myNoteBook )
1926 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1927 myNoteBook->setDumpedStudyName( study->studyName() );
1929 _PTR(Study) studyDS = study->studyDS();
1931 // get unique temporary directory name
1932 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1933 if( aTmpDir.isEmpty() )
1936 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1937 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1939 // dump study to the temporary directory
1940 QString aScriptName( "notebook" );
1941 bool toPublish = true;
1942 bool isMultiFile = false;
1943 bool toSaveGUI = true;
1946 _PTR(AttributeParameter) ap;
1947 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1948 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1949 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1950 ip->setDumpPython(studyDS);
1951 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1953 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1955 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1958 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1962 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1963 int anIndex = aList.indexOf( this );
1965 // Disconnect dialog from application desktop in case if:
1966 // 1) Application is not the first application in the session
1967 // 2) Application is the first application in session but not the only.
1968 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1969 if( changeDesktop ) {
1971 SalomeApp_Application* app = this;
1972 if( anIndex > 0 && anIndex < aList.count() )
1973 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1974 else if(anIndex == 0 && aList.count() > 1)
1975 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1980 // creation a new study and restoring will be done in another application
1981 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1982 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1985 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1986 QString aStudyName = myNoteBook->getDumpedStudyName();
1987 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1988 // clear a study (delete all objects)
1989 onCloseDoc( false );
1991 if( !changeDesktop ) {
1992 ok = onRestoreStudy( aDumpScript,
2001 //============================================================================
2002 /*! Function : onRestoreStudy
2003 * Purpose : Load the dumped study from Python script
2005 //============================================================================
2006 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2007 const QString& theStudyName,
2008 bool theIsStudySaved )
2012 // create a new study
2015 // get active application
2016 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2018 // load study from the temporary directory
2019 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2021 #ifndef DISABLE_PYCONSOLE
2022 PyConsole_Console* pyConsole = app->pythonConsole();
2024 pyConsole->execAndWait( command );
2027 // remove temporary directory
2028 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2029 QString aStudyName = aScriptInfo.baseName();
2030 QDir aDir = aScriptInfo.absoluteDir();
2031 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2032 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2033 ok = aDir.remove( *it ) && ok;
2035 ok = aDir.rmdir( aDir.absolutePath() );
2037 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2039 #ifndef DISABLE_PYCONSOLE
2040 _PTR(Study) aStudyDS = newStudy->studyDS();
2041 app->getNoteBook()->Init( aStudyDS );
2042 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2043 newStudy->Modified();
2044 updateDesktopTitle();
2055 Close the Application
2057 void SalomeApp_Application::afterCloseDoc()
2059 #ifndef DISABLE_PYCONSOLE
2060 // emit signal to restore study from Python script
2062 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2063 myNoteBook->getDumpedStudyName(),
2064 myNoteBook->isDumpedStudySaved() );
2067 LightApp_Application::afterCloseDoc();
2071 Asks to close existing document.
2073 bool SalomeApp_Application::checkExistingDoc()
2075 bool result = LightApp_Application::checkExistingDoc();
2076 if ( result && !activeStudy() ) {
2077 SALOMEDSClient_StudyManager* aMgr = studyMgr();
2079 std::vector<std::string> List = studyMgr()->GetOpenStudies();
2080 if( List.size() > 0 ) {
2081 SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2090 #ifndef DISABLE_PYCONSOLE
2092 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2094 return new SalomeApp_PyInterp();
2097 #endif // DISABLE_PYCONSOLE