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()
584 LightApp_SelectionMgr* mgr = selectionMgr();
585 mgr->selectedObjects(list);
587 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
588 if(study == NULL) return;
590 _PTR(Study) stdDS = study->studyDS();
593 SALOME_ListIteratorOfListIO it( list );
596 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
598 studyMgr()->Copy(so);
599 onSelectionChanged();
606 /*!SLOT. Paste objects to study maneger from selection manager.*/
607 void SalomeApp_Application::onPaste()
610 LightApp_SelectionMgr* mgr = selectionMgr();
611 mgr->selectedObjects(list);
613 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
614 if(study == NULL) return;
616 _PTR(Study) stdDS = study->studyDS();
619 if ( stdDS->GetProperties()->IsLocked() ) {
620 SUIT_MessageBox::warning( desktop(),
621 QObject::tr("WRN_WARNING"),
622 QObject::tr("WRN_STUDY_LOCKED") );
626 SALOME_ListIteratorOfListIO it( list );
629 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
631 studyMgr()->Paste(so);
632 updateObjectBrowser( true );
633 updateActions(); //SRN: BugID IPAL9377, case 3
640 /*!Check the application on closing.
641 * \retval true if possible, else false
643 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
645 return LightApp_Application::isPossibleToClose( closePermanently );
648 /*! Check if the study is locked */
649 void SalomeApp_Application::onCloseDoc( bool ask )
651 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
654 _PTR(Study) stdDS = study->studyDS();
655 if(stdDS && stdDS->IsStudyLocked()) {
656 if ( SUIT_MessageBox::question( desktop(),
657 QObject::tr( "WRN_WARNING" ),
658 QObject::tr( "CLOSE_LOCKED_STUDY" ),
659 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
660 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
664 LightApp_Application::onCloseDoc( ask );
667 /*!Sets enable or disable some actions on selection changed.*/
668 void SalomeApp_Application::onSelectionChanged()
671 LightApp_SelectionMgr* mgr = selectionMgr();
672 mgr->selectedObjects(list);
674 bool canCopy = false;
675 bool canPaste = false;
677 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
680 canCopy = m->canCopy();
681 canPaste = m->canPaste();
684 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
686 _PTR(Study) stdDS = study->studyDS();
689 SALOME_ListIteratorOfListIO it ( list );
691 if (it.More() && list.Extent() == 1) {
692 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
695 canCopy = canCopy || studyMgr()->CanCopy(so);
696 canPaste = canPaste || studyMgr()->CanPaste(so);
702 action(EditCopyId)->setEnabled(canCopy);
703 action(EditPasteId)->setEnabled(canPaste);
706 /*!Delete references.*/
707 void SalomeApp_Application::onDeleteInvalidReferences()
710 LightApp_SelectionMgr* mgr = selectionMgr();
711 mgr->selectedObjects( aList, QString(), false );
713 if( aList.IsEmpty() )
716 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
717 _PTR(Study) aStudyDS = aStudy->studyDS();
718 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
721 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
722 if ( it.Value()->hasEntry() )
724 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
725 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
728 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
729 aStudyBuilder->RemoveReference( aSObject );
731 updateObjectBrowser();
735 void SalomeApp_Application::onOpenWith()
737 QApplication::setOverrideCursor( Qt::WaitCursor );
739 LightApp_SelectionMgr* mgr = selectionMgr();
740 mgr->selectedObjects(aList);
741 if (aList.Extent() != 1)
743 QApplication::restoreOverrideCursor();
746 Handle(SALOME_InteractiveObject) aIObj = aList.First();
747 QString aModuleName(aIObj->getComponentDataType());
748 QString aModuleTitle = moduleTitle(aModuleName);
749 activateModule(aModuleTitle);
750 QApplication::restoreOverrideCursor();
756 SUIT_Study* SalomeApp_Application::createNewStudy()
758 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
760 // Set up processing of major study-related events
761 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
762 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
763 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
764 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
766 #ifndef DISABLE_PYCONSOLE
767 //to receive signal in application that NoteBook's variable was modified
768 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
769 this, SIGNAL(notebookVarUpdated(QString)) );
776 Enable/Disable menu items and toolbar buttons. Rebuild menu
778 void SalomeApp_Application::updateCommandsStatus()
780 LightApp_Application::updateCommandsStatus();
783 QAction* a = action( DumpStudyId );
785 a->setEnabled( activeStudy() );
787 #ifndef DISABLE_PYCONSOLE
789 a = action( LoadScriptId );
791 a->setEnabled( pythonConsole() );
795 a = action( PropertiesId );
797 a->setEnabled( activeStudy() );
799 // Save GUI state menu
800 a = action( SaveGUIStateId );
802 a->setEnabled( activeStudy() );
804 // Connect study menu
805 a = action( ConnectId );
807 a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
809 // Disconnect study menu
810 a = action( DisconnectId );
812 a->setEnabled( activeStudy() );
814 // update state of Copy/Paste menu items
815 onSelectionChanged();
819 \class DumpStudyFileDlg
820 Private class used in Dump Study operation. Consists 2 check boxes:
821 "Publish in study" and "Save GUI parameters"
823 class DumpStudyFileDlg : public SUIT_FileDlg
826 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
828 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
831 QWidget *hB = new QWidget( this );
832 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
833 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
834 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
836 QHBoxLayout *layout = new QHBoxLayout;
837 layout->addWidget(myPublishChk);
838 layout->addWidget(myMultiFileChk);
839 layout->addWidget(mySaveGUIChk);
840 hB->setLayout(layout);
842 QPushButton* pb = new QPushButton(this);
844 int row = grid->rowCount();
845 grid->addWidget( new QLabel("", this), row, 0 );
846 grid->addWidget( hB, row, 1, 1, 3 );
847 grid->addWidget( pb, row, 5 );
852 QCheckBox* myPublishChk;
853 QCheckBox* myMultiFileChk;
854 QCheckBox* mySaveGUIChk;
857 /*!Private SLOT. On dump study.*/
858 void SalomeApp_Application::onDumpStudy( )
860 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
861 if ( !appStudy ) return;
862 _PTR(Study) aStudy = appStudy->studyDS();
864 QStringList aFilters;
865 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
867 bool anIsPublish = true;
868 bool anIsMultiFile = false;
869 bool anIsSaveGUI = true;
871 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
872 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
873 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
874 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
877 DumpStudyFileDlg fd( desktop() );
878 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
879 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
880 fd.setNameFilters( aFilters );
881 fd.myPublishChk->setChecked( anIsPublish );
882 fd.myMultiFileChk->setChecked( anIsMultiFile );
883 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
884 if ( fd.exec() == QDialog::Accepted )
886 QString aFileName = fd.selectedFile();
888 bool toPublish = fd.myPublishChk->isChecked();
889 bool isMultiFile = fd.myMultiFileChk->isChecked();
890 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
892 if ( !aFileName.isEmpty() ) {
893 QFileInfo aFileInfo(aFileName);
894 if( aFileInfo.isDir() ) // IPAL19257
897 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
900 SUIT_OverrideCursor wc;
901 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
904 SUIT_MessageBox::warning( desktop(),
905 QObject::tr("WRN_WARNING"),
906 tr("WRN_DUMP_STUDY_FAILED") );
911 /*!Private SLOT. On load script.*/
912 void SalomeApp_Application::onLoadScript( )
914 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
916 _PTR(Study) aStudy = appStudy->studyDS();
917 if ( aStudy->GetProperties()->IsLocked() ) {
918 SUIT_MessageBox::warning( desktop(),
919 QObject::tr("WRN_WARNING"),
920 QObject::tr("WRN_STUDY_LOCKED") );
925 QStringList filtersList;
926 filtersList.append(tr("PYTHON_FILES_FILTER"));
927 filtersList.append(tr("ALL_FILES_FILTER"));
929 QString anInitialPath = "";
930 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
931 anInitialPath = QDir::currentPath();
933 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
935 if ( !aFile.isEmpty() )
937 QString command = QString("execfile(r\"%1\")").arg(aFile);
939 #ifndef DISABLE_PYCONSOLE
940 PyConsole_Console* pyConsole = pythonConsole();
943 pyConsole->exec( command );
948 /*!Private SLOT. On save GUI state.*/
949 void SalomeApp_Application::onSaveGUIState()
951 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
953 SalomeApp_VisualState( this ).storeState();
954 updateSavePointDataObjects( study );
955 updateObjectBrowser();
960 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
961 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
963 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
964 QAction* send = ::qobject_cast<QAction*>( sender() );
967 QString aWinName = send->data().toString();
968 if ( theIsVisible && aWinName == "objectBrowser" )
969 objectBrowserColumnsVisibility();
973 *\retval QString "(*.hdf)"
975 QString SalomeApp_Application::getFileFilter() const
981 QWidget* SalomeApp_Application::createWindow( const int flag )
984 #ifndef DISABLE_PYCONSOLE
985 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
987 wid = LightApp_Application::createWindow(flag);
990 SUIT_ResourceMgr* resMgr = resourceMgr();
992 if ( flag == WT_ObjectBrowser )
994 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
996 // temporary commented
997 //ob->setUpdater( new SalomeApp_Updater() );
999 #ifdef WITH_SALOMEDS_OBSERVER
1000 //do not activate the automatic update of Qt tree through signal/slot
1001 ob->setAutoUpdate(false);
1002 //activate update of modified objects only
1003 ob->setUpdateModified(true);
1006 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1009 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1010 IORCol = QObject::tr( "IOR_COLUMN" ),
1011 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1012 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1014 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1015 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1016 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1017 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1018 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1019 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1020 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1021 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1022 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1024 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1025 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1026 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1028 ob->setAutoSizeFirstColumn(autoSizeFirst);
1029 ob->setAutoSizeColumns(autoSize);
1030 ob->setResizeOnExpandItem(resizeOnExpandItem);
1031 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1033 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1035 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1036 ob->treeView()->setColumnHidden( i, !shown );
1039 // temporary commented
1041 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1043 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1044 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1045 QString().sprintf( "visibility_column_%d", i ), true ) );
1049 // temporary commented
1051 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1052 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1053 ob->resize( desktop()->width()/3, ob->height() );
1057 #ifndef DISABLE_PYCONSOLE
1058 else if ( flag == WT_PyConsole )
1060 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1061 pyCons->setObjectName( "pythonConsole" );
1062 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1063 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1064 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1065 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1066 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1069 else if ( flag == WT_NoteBook )
1071 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1073 _PTR(Study) aStudy = appStudy->studyDS();
1074 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1075 //to receive signal in NoteBook that it's variable was modified
1076 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1077 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1079 wid = getNoteBook();
1080 wid->setObjectName( "noteBook" );
1086 /*!Create preferences.*/
1087 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1089 LightApp_Application::createPreferences(pref);
1094 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1095 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1096 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1097 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1099 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1100 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1102 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1104 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1105 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1106 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1107 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1108 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1109 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1110 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1111 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1112 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1113 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1116 /*!Update desktop title.*/
1117 void SalomeApp_Application::updateDesktopTitle() {
1118 QString aTitle = applicationName();
1119 QString aVer = applicationVersion();
1120 if ( !aVer.isEmpty() )
1121 aTitle += QString( " " ) + aVer;
1123 if ( activeStudy() )
1125 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1126 if ( !sName.isEmpty() ) {
1127 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1129 _PTR(Study) stdDS = study->studyDS();
1131 if ( stdDS->GetProperties()->IsLocked() ) {
1132 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1134 aTitle += QString( " - [%1]" ).arg( sName );
1141 desktop()->setWindowTitle( aTitle );
1144 int SalomeApp_Application::closeChoice( const QString& docName )
1146 QStringList buttons;
1147 QMap<int, int> choices;
1149 buttons << tr ("APPCLOSE_SAVE"); // Save & Close
1150 choices.insert( idx++, CloseSave ); // ...
1151 buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving
1152 choices.insert( idx++, CloseDiscard ); // ...
1153 if ( myIsCloseFromExit ) {
1154 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1155 choices.insert( idx++, CloseDisconnectSave ); // ...
1156 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1157 choices.insert( idx++, CloseDisconnect ); // ...
1159 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1160 choices.insert( idx++, CloseCancel ); // ...
1162 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1163 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1164 return choices[answer];
1167 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1173 if ( activeStudy()->isSaved() )
1175 else if ( !onSaveAsDoc() )
1180 case CloseDisconnectSave:
1181 if ( activeStudy()->isSaved() )
1183 else if ( !onSaveAsDoc() )
1185 case CloseDisconnect:
1186 closeActiveDoc( false );
1187 closePermanently = false;
1196 int SalomeApp_Application::openChoice( const QString& aName )
1198 int choice = LightApp_Application::openChoice( aName );
1200 if ( QFileInfo( aName ).exists() ) {
1201 if ( choice == OpenNew ) { // The document isn't already open.
1203 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1204 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1205 if ( aName == QString( lst[i].c_str() ) )
1208 // The document already exists in the study manager.
1209 // Do you want to reload it?
1211 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1212 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1213 if ( answer == SUIT_MessageBox::Yes )
1214 choice = OpenRefresh;
1216 choice = OpenCancel;
1219 } else { // file is not exist on disk
1220 SUIT_MessageBox::warning( desktop(),
1221 QObject::tr("WRN_WARNING"),
1222 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1229 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1232 int choice = aChoice;
1237 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1240 studyMgr()->Close( aStudy );
1245 res = LightApp_Application::openAction( choice, aName );
1253 \brief Get map of the operations which can be performed
1254 on the module activation.
1256 The method should return the map of the kind \c {<id>:<name>}
1257 where \c <id> is an integer identifier of the operation and
1258 \c <name> is a title for the button to be added to the
1259 dialog box. After user selects the required operation by the
1260 clicking the corresponding button in the dialog box, its identifier
1261 is passed to the moduleActionSelected() method to process
1264 \return map of the operations
1265 \sa moduleActionSelected()
1267 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1269 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1271 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1273 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1278 \brief Called when the used selectes required operation chosen
1279 from "Activate module" dialog box.
1281 Performs the required operation according to the user choice.
1283 \param id operation identifier
1284 \sa activateModuleActions()
1286 void SalomeApp_Application::moduleActionSelected( const int id )
1292 case NewAndScriptId:
1296 LightApp_Application::moduleActionSelected( id );
1301 /*!Gets CORBA::ORB_var*/
1302 CORBA::ORB_var SalomeApp_Application::orb()
1304 static CORBA::ORB_var _orb;
1306 if ( CORBA::is_nil( _orb ) ) {
1307 Qtx::CmdLineArgs args;
1308 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1309 _orb = init( args.argc(), args.argv() );
1315 /*!Create and return SALOMEDS_StudyManager.*/
1316 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1318 static _PTR(StudyManager) _sm;
1319 if(!_sm) _sm = ClientFactory::StudyManager();
1323 /*!Create and return SALOME_NamingService.*/
1324 SALOME_NamingService* SalomeApp_Application::namingService()
1326 static SALOME_NamingService _ns(orb());
1330 /*!Create and return SALOME_LifeCycleCORBA.*/
1331 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1333 static SALOME_LifeCycleCORBA _lcc( namingService() );
1337 /*!Private SLOT. On preferences.*/
1338 void SalomeApp_Application::onProperties()
1340 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1344 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1347 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1348 int res = aDlg.exec();
1349 if( res==QDialog::Accepted && aDlg.isChanged() )
1350 SB->CommitCommand();
1354 //study->updateCaptions();
1355 updateDesktopTitle();
1359 /*!Insert items in popup, which necessary for current application*/
1360 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1362 LightApp_SelectionMgr* mgr = selectionMgr();
1363 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1364 mgr->setSelectionCacheEnabled( true );
1366 LightApp_Application::contextMenuPopup( type, thePopup, title );
1368 // temporary commented
1369 /*OB_Browser* ob = objectBrowser();
1370 if ( !ob || type != ob->popupClientType() )
1373 // Get selected objects
1374 SALOME_ListIO aList;
1375 mgr->selectedObjects( aList, QString(), false );
1377 // add GUI state commands: restore, rename
1378 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1379 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1380 thePopup->addSeparator();
1381 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1382 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1383 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1384 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1387 // "Delete reference" item should appear only for invalid references
1389 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1390 bool isInvalidRefs = false;
1391 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1393 _PTR(Study) aStudyDS = aStudy->studyDS();
1394 _PTR(SObject) anObj;
1396 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1398 if( it.Value()->hasEntry() )
1400 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1401 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1404 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1405 isInvalidRefs = true;
1409 // Add "Delete reference" item to popup
1410 if ( isInvalidRefs )
1412 thePopup->addSeparator();
1413 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1417 // "Activate module" item should appear only if it's necessary
1418 if ( aList.Extent() == 1 ) {
1420 mgr->selectedObjects( aList );
1422 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1424 // add extra popup menu (defined in XML)
1425 if ( myExtActions.size() > 0 ) {
1426 // Use only first selected object
1427 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1429 _PTR(Study) stdDS = study->studyDS();
1431 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1433 _PTR( GenericAttribute ) anAttr;
1434 std::string auid = "AttributeUserID";
1435 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1436 if ( aSO->FindAttribute( anAttr, auid ) ) {
1437 _PTR(AttributeUserID) aAttrID = anAttr;
1438 QString aId = aAttrID->Value().c_str();
1439 if ( myExtActions.contains( aId ) ) {
1440 thePopup->addAction(myExtActions[aId]);
1448 // check if item is a "GUI state" item (also a first level object)
1449 QString entry( aIObj->getEntry() );
1450 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1451 QString aModuleName( aIObj->getComponentDataType() );
1452 QString aModuleTitle = moduleTitle( aModuleName );
1453 CAM_Module* currentModule = activeModule();
1454 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1455 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1460 mgr->setSelectionCacheEnabled( cacheIsOn );
1463 /*!Update obect browser:
1464 1.if 'updateModels' true, update existing data models;
1465 2. update "non-existing" (not loaded yet) data models;
1466 3. update object browser if it exists */
1467 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1469 // update "non-existing" (not loaded yet) data models
1470 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1473 _PTR(Study) stdDS = study->studyDS();
1476 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1478 _PTR(SComponent) aComponent ( it->Value() );
1480 #ifndef WITH_SALOMEDS_OBSERVER
1481 // with GUI observers this check is not needed anymore
1482 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1483 continue; // skip the magic "Interface Applicative" component
1485 if ( !objectBrowser() )
1486 getWindow( WT_ObjectBrowser );
1487 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1488 objectBrowser()->setAutoUpdate( false );
1489 SalomeApp_DataModel::synchronize( aComponent, study );
1490 objectBrowser()->setAutoUpdate( isAutoUpdate );
1495 // create data objects that correspond to GUI state save points
1496 if ( study ) updateSavePointDataObjects( study );
1498 // update existing data models (already loaded SComponents)
1499 LightApp_Application::updateObjectBrowser( updateModels );
1502 /*!Display Catalog Genenerator dialog */
1503 void SalomeApp_Application::onCatalogGen()
1505 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1509 /*!Display Registry Display dialog */
1510 void SalomeApp_Application::onRegDisplay()
1512 CORBA::ORB_var anOrb = orb();
1513 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1516 regWnd->activateWindow();
1519 /*!find original object by double click on item */
1520 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1522 // Issue 21379: References are supported at LightApp_DataObject level
1523 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1525 if( obj && obj->isReference() )
1527 QString entry = obj->refEntry();
1529 SUIT_DataOwnerPtrList aList;
1530 aList.append( new LightApp_DataOwner( entry ) );
1531 selectionMgr()->setSelected( aList, false );
1533 SUIT_DataBrowser* ob = objectBrowser();
1535 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1536 if ( !aSelectedIndexes.isEmpty() )
1537 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1539 emit objectDoubleClicked( theObj );
1543 Creates new view manager
1544 \param type - type of view manager
1546 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1548 return createViewManager(type);
1552 /*!Global utility function, returns selected GUI Save point object's ID */
1553 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1555 SALOME_ListIO aList;
1556 selMgr->selectedObjects( aList );
1557 if( aList.Extent() > 0 ) {
1558 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1559 QString entry( aIObj->getEntry() );
1560 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1561 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1563 bool ok; // conversion to integer is ok?
1564 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1565 return ok ? savePoint : -1;
1570 /*!Called on Restore GUI State popup command*/
1571 void SalomeApp_Application::onRestoreGUIState()
1573 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1574 if ( savePoint == -1 )
1576 SalomeApp_VisualState( this ).restoreState( savePoint );
1579 /*!Called on Delete GUI State popup command*/
1580 void SalomeApp_Application::onDeleteGUIState()
1582 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1583 if ( savePoint == -1 )
1585 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1589 study->removeSavePoint( savePoint );
1590 updateSavePointDataObjects( study );
1593 /*!Called on New study operation*/
1594 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1596 LightApp_Application::onStudyCreated( study );
1598 //#ifndef DISABLE_PYCONSOLE
1599 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1600 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1603 loadDockWindowsState();
1605 objectBrowserColumnsVisibility();
1608 /*!Called on Open study operation*/
1609 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1611 LightApp_Application::onStudyOpened( study );
1613 //#ifndef DISABLE_PYCONSOLE
1614 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1615 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1618 loadDockWindowsState();
1620 objectBrowserColumnsVisibility();
1622 // temporary commented
1623 /*if ( objectBrowser() ) {
1624 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1625 objectBrowser()->updateTree( study->root() );
1629 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1630 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1633 SUIT_DataBrowser* ob = objectBrowser();
1634 LightApp_SelectionMgr* selMgr = selectionMgr();
1636 if ( !study || !ob || !selMgr )
1639 // find GUI states root object
1640 SUIT_DataObject* guiRootObj = 0;
1642 study->root()->children( ch );
1643 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1644 for ( ; it != last ; ++it ) {
1645 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1650 std::vector<int> savePoints = study->getSavePoints();
1651 // case 1: no more save points but they existed in study's tree
1652 if ( savePoints.empty() && guiRootObj ) {
1653 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1654 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1655 const bool isAutoUpdate = ob->autoUpdate();
1656 selMgr->clearSelected();
1657 ob->setAutoUpdate(true);
1658 DataObjectList ch = guiRootObj->children();
1659 for( int i = 0; i < ch.size(); i++ )
1662 ob->setAutoUpdate(isAutoUpdate);
1665 // case 2: no more save points but root does not exist either
1666 if ( savePoints.empty() && !guiRootObj )
1668 // case 3: save points but no root for them - create it
1669 if ( !savePoints.empty() && !guiRootObj )
1670 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1671 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1672 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1674 if ( guiRootObj->nextBrother() ) {
1675 study->root()->removeChild(guiRootObj);
1676 study->root()->appendChild(guiRootObj);
1677 //study->root()->dump();
1680 // store data objects in a map id-to-DataObject
1681 QMap<int,SalomeApp_SavePointObject*> mapDO;
1683 guiRootObj->children( ch );
1684 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1685 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1687 mapDO[dobj->getId()] = dobj;
1690 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1691 // if in the map - remove it from map.
1692 for ( int i = 0; i < savePoints.size(); i++ )
1693 if ( !mapDO.contains( savePoints[i] ) )
1694 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1696 mapDO.remove( savePoints[i] );
1698 // delete DataObjects that are still in the map -- their IDs were not found in data model
1699 if( mapDO.size() > 0) {
1700 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1701 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1702 selMgr->clearSelected();
1703 const bool isAutoUpdate = ob->autoUpdate();
1704 ob->setAutoUpdate(true);
1705 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1707 ob->setAutoUpdate(isAutoUpdate);
1711 /*! Check data object */
1712 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1721 Opens other study into active Study. If Study is empty - creates it.
1722 \param theName - name of study
1724 bool SalomeApp_Application::useStudy( const QString& theName )
1727 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1730 res = aStudy->loadDocument( theName );
1731 updateDesktopTitle();
1732 updateCommandsStatus();
1736 /*! Show/hide object browser colums according to preferences */
1737 void SalomeApp_Application::objectBrowserColumnsVisibility()
1739 if ( objectBrowser() )
1740 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1742 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1743 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1747 #ifndef DISABLE_PYCONSOLE
1748 /*! Set SalomeApp_NoteBook pointer */
1749 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1751 myNoteBook = theNoteBook;
1754 /*! Return SalomeApp_NoteBook pointer */
1755 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1762 * Define extra actions defined in module definition XML file.
1763 * Additional popup items sections can be defined by parameter "popupitems".
1764 * Supported attributes:
1765 * title - title of menu item,
1766 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1767 * method - method which has to be called when menu item is selected
1769 * <section name="MODULENAME">
1770 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1772 * <section name="importmed">
1773 * <parameter name="title" value="My menu"/>
1774 * <parameter name="objectid" value="VISU.Result"/>
1775 * <parameter name="method" value="nameOfModuleMethod"/>
1778 void SalomeApp_Application::createExtraActions()
1780 myExtActions.clear();
1781 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1783 QStringList aModules;
1784 modules(aModules, false);
1785 foreach(QString aModile, aModules) {
1786 QString aModName = moduleName(aModile);
1787 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1788 if (!aSectionStr.isNull()) {
1789 QStringList aSections = aSectionStr.split(':');
1790 foreach(QString aSection, aSections) {
1791 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1792 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1793 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1794 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1797 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1798 if (aModuleName.isNull())
1799 aModuleName = aModName;
1801 QAction* aAction = new QAction(aTitle, this);
1803 aData<<aModuleName<<aSlot;
1804 aAction->setData(aData);
1805 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1806 myExtActions[aId] = aAction;
1813 * Called when extra action is selected
1815 void SalomeApp_Application::onExtAction()
1817 QAction* aAction = ::qobject_cast<QAction*>(sender());
1821 QVariant aData = aAction->data();
1822 QStringList aDataList = aData.value<QStringList>();
1823 if (aDataList.size() != 2)
1826 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1827 SALOME_ListIO aListIO;
1828 aSelectionMgr->selectedObjects(aListIO);
1829 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1830 if (aListIO.Extent() < 1)
1832 if (!anIO->hasEntry())
1835 QString aEntry(anIO->getEntry());
1837 QApplication::setOverrideCursor( Qt::WaitCursor );
1838 QString aModuleTitle = moduleTitle(aDataList[0]);
1839 activateModule(aModuleTitle);
1840 QApplication::restoreOverrideCursor();
1842 QCoreApplication::processEvents();
1844 CAM_Module* aModule = activeModule();
1848 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1849 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1853 Checks that an object can be renamed.
1854 \param entry entry of the object
1855 \brief Return \c true if object can be renamed
1857 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1859 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1863 Rename object by entry.
1864 \param entry entry of the object
1865 \param name new name of the object
1866 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1868 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1870 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1872 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1874 if(!aStudy || savePoint == -1)
1877 if ( !name.isNull() && !name.isEmpty() ) {
1878 aStudy->setNameOfSavePoint( savePoint, name );
1879 updateSavePointDataObjects( aStudy );
1881 //Mark study as modified
1888 #ifndef DISABLE_PYCONSOLE
1889 //============================================================================
1890 /*! Function : onUpdateStudy
1891 * Purpose : Slot to update the study.
1893 //============================================================================
1894 void SalomeApp_Application::onUpdateStudy()
1896 QApplication::setOverrideCursor( Qt::WaitCursor );
1898 if( !updateStudy() )
1899 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1901 QApplication::restoreOverrideCursor();
1904 //============================================================================
1905 /*! Function : updateStudy
1906 * Purpose : Update study by dumping the study to Python script and loading it.
1907 * It is used to apply variable modifications done in NoteBook to created objects.
1909 //============================================================================
1910 bool SalomeApp_Application::updateStudy()
1912 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1913 if ( !study || !myNoteBook )
1916 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1917 myNoteBook->setDumpedStudyName( study->studyName() );
1919 _PTR(Study) studyDS = study->studyDS();
1921 // get unique temporary directory name
1922 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1923 if( aTmpDir.isEmpty() )
1926 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1927 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1929 // dump study to the temporary directory
1930 QString aScriptName( "notebook" );
1931 bool toPublish = true;
1932 bool isMultiFile = false;
1933 bool toSaveGUI = true;
1936 _PTR(AttributeParameter) ap;
1937 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1938 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1939 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1940 ip->setDumpPython(studyDS);
1941 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1943 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1945 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1948 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1952 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1953 int anIndex = aList.indexOf( this );
1955 // Disconnect dialog from application desktop in case if:
1956 // 1) Application is not the first application in the session
1957 // 2) Application is the first application in session but not the only.
1958 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1959 if( changeDesktop ) {
1961 SalomeApp_Application* app = this;
1962 if( anIndex > 0 && anIndex < aList.count() )
1963 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1964 else if(anIndex == 0 && aList.count() > 1)
1965 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1970 // creation a new study and restoring will be done in another application
1971 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1972 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1975 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1976 QString aStudyName = myNoteBook->getDumpedStudyName();
1977 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1978 // clear a study (delete all objects)
1979 onCloseDoc( false );
1981 if( !changeDesktop ) {
1982 ok = onRestoreStudy( aDumpScript,
1991 //============================================================================
1992 /*! Function : onRestoreStudy
1993 * Purpose : Load the dumped study from Python script
1995 //============================================================================
1996 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1997 const QString& theStudyName,
1998 bool theIsStudySaved )
2002 // create a new study
2005 // get active application
2006 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2008 // load study from the temporary directory
2009 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2011 #ifndef DISABLE_PYCONSOLE
2012 PyConsole_Console* pyConsole = app->pythonConsole();
2014 pyConsole->execAndWait( command );
2017 // remove temporary directory
2018 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2019 QString aStudyName = aScriptInfo.baseName();
2020 QDir aDir = aScriptInfo.absoluteDir();
2021 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2022 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2023 ok = aDir.remove( *it ) && ok;
2025 ok = aDir.rmdir( aDir.absolutePath() );
2027 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2029 #ifndef DISABLE_PYCONSOLE
2030 _PTR(Study) aStudyDS = newStudy->studyDS();
2031 if ( app->getNoteBook() )
2032 app->getNoteBook()->Init( aStudyDS );
2033 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2034 newStudy->Modified();
2035 updateDesktopTitle();
2046 Close the Application
2048 void SalomeApp_Application::afterCloseDoc()
2050 #ifndef DISABLE_PYCONSOLE
2051 // emit signal to restore study from Python script
2053 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2054 myNoteBook->getDumpedStudyName(),
2055 myNoteBook->isDumpedStudySaved() );
2058 LightApp_Application::afterCloseDoc();
2062 Asks to close existing document.
2064 bool SalomeApp_Application::checkExistingDoc()
2066 bool result = LightApp_Application::checkExistingDoc();
2067 if ( result && !activeStudy() ) {
2068 SALOMEDSClient_StudyManager* aMgr = studyMgr();
2070 std::vector<std::string> List = studyMgr()->GetOpenStudies();
2071 if( List.size() > 0 ) {
2072 SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2081 #ifndef DISABLE_PYCONSOLE
2083 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2085 return new SalomeApp_PyInterp();
2088 #endif // DISABLE_PYCONSOLE