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( "exec(open(\"%1\").read())" ).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("exec(open(\"%1\").read())").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("exec(open(\"%1\").read())").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 QWidget* SalomeApp_Application::createWindow( const int flag )
976 #ifndef DISABLE_PYCONSOLE
977 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
979 wid = LightApp_Application::createWindow(flag);
982 SUIT_ResourceMgr* resMgr = resourceMgr();
984 if ( flag == WT_ObjectBrowser )
986 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
988 // temporary commented
989 //ob->setUpdater( new SalomeApp_Updater() );
991 #ifdef WITH_SALOMEDS_OBSERVER
992 //do not activate the automatic update of Qt tree through signal/slot
993 ob->setAutoUpdate(false);
994 //activate update of modified objects only
995 ob->setUpdateModified(true);
998 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1001 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1002 IORCol = QObject::tr( "IOR_COLUMN" ),
1003 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1004 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1006 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1007 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1008 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1009 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1010 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1011 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1012 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1013 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1014 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1016 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1017 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1018 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1020 ob->setAutoSizeFirstColumn(autoSizeFirst);
1021 ob->setAutoSizeColumns(autoSize);
1022 ob->setResizeOnExpandItem(resizeOnExpandItem);
1023 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1025 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1027 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1028 ob->treeView()->setColumnHidden( i, !shown );
1031 // temporary commented
1033 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1035 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1036 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1037 QString().sprintf( "visibility_column_%d", i ), true ) );
1041 // temporary commented
1043 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1044 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1045 ob->resize( desktop()->width()/3, ob->height() );
1049 #ifndef DISABLE_PYCONSOLE
1050 else if ( flag == WT_PyConsole )
1052 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1053 pyCons->setObjectName( "pythonConsole" );
1054 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1055 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1056 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1057 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1058 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1061 else if ( flag == WT_NoteBook )
1063 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1065 _PTR(Study) aStudy = appStudy->studyDS();
1066 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1067 //to receive signal in NoteBook that it's variable was modified
1068 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1069 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1071 wid = getNoteBook();
1072 wid->setObjectName( "noteBook" );
1078 /*!Create preferences.*/
1079 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1081 LightApp_Application::createPreferences(pref);
1086 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1087 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1088 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1089 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1091 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1092 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1094 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1096 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1097 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1098 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1099 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1100 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1101 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1102 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1103 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1104 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1105 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1108 /*!Update desktop title.*/
1109 void SalomeApp_Application::updateDesktopTitle() {
1110 QString aTitle = applicationName();
1111 QString aVer = applicationVersion();
1112 if ( !aVer.isEmpty() )
1113 aTitle += QString( " " ) + aVer;
1115 if ( activeStudy() )
1117 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1118 if ( !sName.isEmpty() ) {
1119 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1121 _PTR(Study) stdDS = study->studyDS();
1123 if ( stdDS->GetProperties()->IsLocked() ) {
1124 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1126 aTitle += QString( " - [%1]" ).arg( sName );
1133 desktop()->setWindowTitle( aTitle );
1136 int SalomeApp_Application::closeChoice( const QString& docName )
1138 QStringList buttons;
1139 QMap<int, int> choices;
1141 buttons << tr ("APPCLOSE_SAVE"); // Save & Close
1142 choices.insert( idx++, CloseSave ); // ...
1143 buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving
1144 choices.insert( idx++, CloseDiscard ); // ...
1145 if ( myIsCloseFromExit ) {
1146 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1147 choices.insert( idx++, CloseDisconnectSave ); // ...
1148 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1149 choices.insert( idx++, CloseDisconnect ); // ...
1151 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1152 choices.insert( idx++, CloseCancel ); // ...
1154 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1155 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1156 return choices[answer];
1159 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1165 if ( activeStudy()->isSaved() )
1167 else if ( !onSaveAsDoc() )
1172 case CloseDisconnectSave:
1173 if ( activeStudy()->isSaved() )
1175 else if ( !onSaveAsDoc() )
1177 case CloseDisconnect:
1178 closeActiveDoc( false );
1179 closePermanently = false;
1188 int SalomeApp_Application::openChoice( const QString& aName )
1190 int choice = LightApp_Application::openChoice( aName );
1192 if ( QFileInfo( aName ).exists() ) {
1193 if ( choice == OpenNew ) { // The document isn't already open.
1195 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1196 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1197 if ( aName == QString( lst[i].c_str() ) )
1200 // The document already exists in the study manager.
1201 // Do you want to reload it?
1203 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1204 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1205 if ( answer == SUIT_MessageBox::Yes )
1206 choice = OpenRefresh;
1208 choice = OpenCancel;
1211 } else { // file is not exist on disk
1212 SUIT_MessageBox::warning( desktop(),
1213 QObject::tr("WRN_WARNING"),
1214 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1221 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1224 int choice = aChoice;
1229 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1232 studyMgr()->Close( aStudy );
1237 res = LightApp_Application::openAction( choice, aName );
1245 \brief Get map of the operations which can be performed
1246 on the module activation.
1248 The method should return the map of the kind \c {<id>:<name>}
1249 where \c <id> is an integer identifier of the operation and
1250 \c <name> is a title for the button to be added to the
1251 dialog box. After user selects the required operation by the
1252 clicking the corresponding button in the dialog box, its identifier
1253 is passed to the moduleActionSelected() method to process
1256 \return map of the operations
1257 \sa moduleActionSelected()
1259 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1261 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1263 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1265 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1270 \brief Called when the used selectes required operation chosen
1271 from "Activate module" dialog box.
1273 Performs the required operation according to the user choice.
1275 \param id operation identifier
1276 \sa activateModuleActions()
1278 void SalomeApp_Application::moduleActionSelected( const int id )
1284 case NewAndScriptId:
1288 LightApp_Application::moduleActionSelected( id );
1293 /*!Gets CORBA::ORB_var*/
1294 CORBA::ORB_var SalomeApp_Application::orb()
1296 static CORBA::ORB_var _orb;
1298 if ( CORBA::is_nil( _orb ) ) {
1299 Qtx::CmdLineArgs args;
1300 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1301 _orb = init( args.argc(), args.argv() );
1307 /*!Create and return SALOMEDS_StudyManager.*/
1308 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1310 static _PTR(StudyManager) _sm;
1311 if(!_sm) _sm = ClientFactory::StudyManager();
1315 /*!Create and return SALOME_NamingService.*/
1316 SALOME_NamingService* SalomeApp_Application::namingService()
1318 static SALOME_NamingService _ns(orb());
1322 /*!Create and return SALOME_LifeCycleCORBA.*/
1323 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1325 static SALOME_LifeCycleCORBA _lcc( namingService() );
1329 /*!Private SLOT. On preferences.*/
1330 void SalomeApp_Application::onProperties()
1332 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1336 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1339 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1340 int res = aDlg.exec();
1341 if( res==QDialog::Accepted && aDlg.isChanged() )
1342 SB->CommitCommand();
1346 //study->updateCaptions();
1347 updateDesktopTitle();
1351 /*!Insert items in popup, which necessary for current application*/
1352 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1354 LightApp_SelectionMgr* mgr = selectionMgr();
1355 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1356 mgr->setSelectionCacheEnabled( true );
1358 LightApp_Application::contextMenuPopup( type, thePopup, title );
1360 // temporary commented
1361 /*OB_Browser* ob = objectBrowser();
1362 if ( !ob || type != ob->popupClientType() )
1365 // Get selected objects
1366 SALOME_ListIO aList;
1367 mgr->selectedObjects( aList, QString(), false );
1369 // add GUI state commands: restore, rename
1370 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1371 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1372 thePopup->addSeparator();
1373 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1374 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1375 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1376 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1379 // "Delete reference" item should appear only for invalid references
1381 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1382 bool isInvalidRefs = false;
1383 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1385 _PTR(Study) aStudyDS = aStudy->studyDS();
1386 _PTR(SObject) anObj;
1388 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1390 if( it.Value()->hasEntry() )
1392 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1393 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1396 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1397 isInvalidRefs = true;
1401 // Add "Delete reference" item to popup
1402 if ( isInvalidRefs )
1404 thePopup->addSeparator();
1405 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1409 // "Activate module" item should appear only if it's necessary
1410 if ( aList.Extent() == 1 ) {
1412 mgr->selectedObjects( aList );
1414 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1416 // add extra popup menu (defined in XML)
1417 if ( myExtActions.size() > 0 ) {
1418 // Use only first selected object
1419 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1421 _PTR(Study) stdDS = study->studyDS();
1423 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1425 _PTR( GenericAttribute ) anAttr;
1426 std::string auid = "AttributeUserID";
1427 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1428 if ( aSO->FindAttribute( anAttr, auid ) ) {
1429 _PTR(AttributeUserID) aAttrID = anAttr;
1430 QString aId = aAttrID->Value().c_str();
1431 if ( myExtActions.contains( aId ) ) {
1432 thePopup->addAction(myExtActions[aId]);
1440 // check if item is a "GUI state" item (also a first level object)
1441 QString entry( aIObj->getEntry() );
1442 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1443 QString aModuleName( aIObj->getComponentDataType() );
1444 QString aModuleTitle = moduleTitle( aModuleName );
1445 CAM_Module* currentModule = activeModule();
1446 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1447 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1452 mgr->setSelectionCacheEnabled( cacheIsOn );
1455 /*!Update obect browser:
1456 1.if 'updateModels' true, update existing data models;
1457 2. update "non-existing" (not loaded yet) data models;
1458 3. update object browser if it exists */
1459 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1461 // update "non-existing" (not loaded yet) data models
1462 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1465 _PTR(Study) stdDS = study->studyDS();
1468 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1470 _PTR(SComponent) aComponent ( it->Value() );
1472 #ifndef WITH_SALOMEDS_OBSERVER
1473 // with GUI observers this check is not needed anymore
1474 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1475 continue; // skip the magic "Interface Applicative" component
1477 if ( !objectBrowser() )
1478 getWindow( WT_ObjectBrowser );
1479 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1480 objectBrowser()->setAutoUpdate( false );
1481 SalomeApp_DataModel::synchronize( aComponent, study );
1482 objectBrowser()->setAutoUpdate( isAutoUpdate );
1487 // create data objects that correspond to GUI state save points
1488 if ( study ) updateSavePointDataObjects( study );
1490 // update existing data models (already loaded SComponents)
1491 LightApp_Application::updateObjectBrowser( updateModels );
1494 /*!Display Catalog Genenerator dialog */
1495 void SalomeApp_Application::onCatalogGen()
1497 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1501 /*!Display Registry Display dialog */
1502 void SalomeApp_Application::onRegDisplay()
1504 CORBA::ORB_var anOrb = orb();
1505 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1508 regWnd->activateWindow();
1511 /*!find original object by double click on item */
1512 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1514 // Issue 21379: References are supported at LightApp_DataObject level
1515 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1517 if( obj && obj->isReference() )
1519 QString entry = obj->refEntry();
1521 SUIT_DataOwnerPtrList aList;
1522 aList.append( new LightApp_DataOwner( entry ) );
1523 selectionMgr()->setSelected( aList, false );
1525 SUIT_DataBrowser* ob = objectBrowser();
1527 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1528 if ( !aSelectedIndexes.isEmpty() )
1529 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1531 emit objectDoubleClicked( theObj );
1535 Creates new view manager
1536 \param type - type of view manager
1538 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1540 return createViewManager(type);
1544 /*!Global utility function, returns selected GUI Save point object's ID */
1545 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1547 SALOME_ListIO aList;
1548 selMgr->selectedObjects( aList );
1549 if( aList.Extent() > 0 ) {
1550 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1551 QString entry( aIObj->getEntry() );
1552 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1553 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1555 bool ok; // conversion to integer is ok?
1556 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1557 return ok ? savePoint : -1;
1562 /*!Called on Restore GUI State popup command*/
1563 void SalomeApp_Application::onRestoreGUIState()
1565 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1566 if ( savePoint == -1 )
1568 SalomeApp_VisualState( this ).restoreState( savePoint );
1571 /*!Called on Delete GUI State popup command*/
1572 void SalomeApp_Application::onDeleteGUIState()
1574 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1575 if ( savePoint == -1 )
1577 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1581 study->removeSavePoint( savePoint );
1582 updateSavePointDataObjects( study );
1585 /*!Called on New study operation*/
1586 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1588 LightApp_Application::onStudyCreated( study );
1590 //#ifndef DISABLE_PYCONSOLE
1591 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1592 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1595 loadDockWindowsState();
1597 objectBrowserColumnsVisibility();
1600 /*!Called on Open study operation*/
1601 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1603 LightApp_Application::onStudyOpened( study );
1605 //#ifndef DISABLE_PYCONSOLE
1606 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1607 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1610 loadDockWindowsState();
1612 objectBrowserColumnsVisibility();
1614 // temporary commented
1615 /*if ( objectBrowser() ) {
1616 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1617 objectBrowser()->updateTree( study->root() );
1621 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1622 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1625 SUIT_DataBrowser* ob = objectBrowser();
1626 LightApp_SelectionMgr* selMgr = selectionMgr();
1628 if ( !study || !ob || !selMgr )
1631 // find GUI states root object
1632 SUIT_DataObject* guiRootObj = 0;
1634 study->root()->children( ch );
1635 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1636 for ( ; it != last ; ++it ) {
1637 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1642 std::vector<int> savePoints = study->getSavePoints();
1643 // case 1: no more save points but they existed in study's tree
1644 if ( savePoints.empty() && guiRootObj ) {
1645 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1646 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1647 const bool isAutoUpdate = ob->autoUpdate();
1648 selMgr->clearSelected();
1649 ob->setAutoUpdate(true);
1650 DataObjectList ch = guiRootObj->children();
1651 for( int i = 0; i < ch.size(); i++ )
1654 ob->setAutoUpdate(isAutoUpdate);
1657 // case 2: no more save points but root does not exist either
1658 if ( savePoints.empty() && !guiRootObj )
1660 // case 3: save points but no root for them - create it
1661 if ( !savePoints.empty() && !guiRootObj )
1662 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1663 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1664 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1666 if ( guiRootObj->nextBrother() ) {
1667 study->root()->removeChild(guiRootObj);
1668 study->root()->appendChild(guiRootObj);
1669 //study->root()->dump();
1672 // store data objects in a map id-to-DataObject
1673 QMap<int,SalomeApp_SavePointObject*> mapDO;
1675 guiRootObj->children( ch );
1676 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1677 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1679 mapDO[dobj->getId()] = dobj;
1682 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1683 // if in the map - remove it from map.
1684 for ( int i = 0; i < savePoints.size(); i++ )
1685 if ( !mapDO.contains( savePoints[i] ) )
1686 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1688 mapDO.remove( savePoints[i] );
1690 // delete DataObjects that are still in the map -- their IDs were not found in data model
1691 if( mapDO.size() > 0) {
1692 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1693 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1694 selMgr->clearSelected();
1695 const bool isAutoUpdate = ob->autoUpdate();
1696 ob->setAutoUpdate(true);
1697 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1699 ob->setAutoUpdate(isAutoUpdate);
1703 /*! Check data object */
1704 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1713 Opens other study into active Study. If Study is empty - creates it.
1714 \param theName - name of study
1716 bool SalomeApp_Application::useStudy( const QString& theName )
1719 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1722 res = aStudy->loadDocument( theName );
1723 updateDesktopTitle();
1724 updateCommandsStatus();
1728 /*! Show/hide object browser colums according to preferences */
1729 void SalomeApp_Application::objectBrowserColumnsVisibility()
1731 if ( objectBrowser() )
1732 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1734 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1735 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1739 #ifndef DISABLE_PYCONSOLE
1740 /*! Set SalomeApp_NoteBook pointer */
1741 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1743 myNoteBook = theNoteBook;
1746 /*! Return SalomeApp_NoteBook pointer */
1747 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1754 * Define extra actions defined in module definition XML file.
1755 * Additional popup items sections can be defined by parameter "popupitems".
1756 * Supported attributes:
1757 * title - title of menu item,
1758 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1759 * method - method which has to be called when menu item is selected
1761 * <section name="MODULENAME">
1762 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1764 * <section name="importmed">
1765 * <parameter name="title" value="My menu"/>
1766 * <parameter name="objectid" value="VISU.Result"/>
1767 * <parameter name="method" value="nameOfModuleMethod"/>
1770 void SalomeApp_Application::createExtraActions()
1772 myExtActions.clear();
1773 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1775 QStringList aModules;
1776 modules(aModules, false);
1777 foreach(QString aModile, aModules) {
1778 QString aModName = moduleName(aModile);
1779 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1780 if (!aSectionStr.isNull()) {
1781 QStringList aSections = aSectionStr.split(':');
1782 foreach(QString aSection, aSections) {
1783 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1784 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1785 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1786 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1789 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1790 if (aModuleName.isNull())
1791 aModuleName = aModName;
1793 QAction* aAction = new QAction(aTitle, this);
1795 aData<<aModuleName<<aSlot;
1796 aAction->setData(aData);
1797 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1798 myExtActions[aId] = aAction;
1805 * Called when extra action is selected
1807 void SalomeApp_Application::onExtAction()
1809 QAction* aAction = ::qobject_cast<QAction*>(sender());
1813 QVariant aData = aAction->data();
1814 QStringList aDataList = aData.value<QStringList>();
1815 if (aDataList.size() != 2)
1818 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1819 SALOME_ListIO aListIO;
1820 aSelectionMgr->selectedObjects(aListIO);
1821 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1822 if (aListIO.Extent() < 1)
1824 if (!anIO->hasEntry())
1827 QString aEntry(anIO->getEntry());
1829 QApplication::setOverrideCursor( Qt::WaitCursor );
1830 QString aModuleTitle = moduleTitle(aDataList[0]);
1831 activateModule(aModuleTitle);
1832 QApplication::restoreOverrideCursor();
1834 QCoreApplication::processEvents();
1836 CAM_Module* aModule = activeModule();
1840 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1841 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1845 Checks that an object can be renamed.
1846 \param entry entry of the object
1847 \brief Return \c true if object can be renamed
1849 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1851 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1855 Rename object by entry.
1856 \param entry entry of the object
1857 \param name new name of the object
1858 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1860 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1862 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1864 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1866 if(!aStudy || savePoint == -1)
1869 if ( !name.isNull() && !name.isEmpty() ) {
1870 aStudy->setNameOfSavePoint( savePoint, name );
1871 updateSavePointDataObjects( aStudy );
1873 //Mark study as modified
1880 #ifndef DISABLE_PYCONSOLE
1881 //============================================================================
1882 /*! Function : onUpdateStudy
1883 * Purpose : Slot to update the study.
1885 //============================================================================
1886 void SalomeApp_Application::onUpdateStudy()
1888 QApplication::setOverrideCursor( Qt::WaitCursor );
1890 if( !updateStudy() )
1891 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1893 QApplication::restoreOverrideCursor();
1896 //============================================================================
1897 /*! Function : updateStudy
1898 * Purpose : Update study by dumping the study to Python script and loading it.
1899 * It is used to apply variable modifications done in NoteBook to created objects.
1901 //============================================================================
1902 bool SalomeApp_Application::updateStudy()
1904 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1905 if ( !study || !myNoteBook )
1908 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1909 myNoteBook->setDumpedStudyName( study->studyName() );
1911 _PTR(Study) studyDS = study->studyDS();
1913 // get unique temporary directory name
1914 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1915 if( aTmpDir.isEmpty() )
1918 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1919 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1921 // dump study to the temporary directory
1922 QString aScriptName( "notebook" );
1923 bool toPublish = true;
1924 bool isMultiFile = false;
1925 bool toSaveGUI = true;
1928 _PTR(AttributeParameter) ap;
1929 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1930 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1931 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1932 ip->setDumpPython(studyDS);
1933 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1935 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1937 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1940 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1944 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1945 int anIndex = aList.indexOf( this );
1947 // Disconnect dialog from application desktop in case if:
1948 // 1) Application is not the first application in the session
1949 // 2) Application is the first application in session but not the only.
1950 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1951 if( changeDesktop ) {
1953 SalomeApp_Application* app = this;
1954 if( anIndex > 0 && anIndex < aList.count() )
1955 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1956 else if(anIndex == 0 && aList.count() > 1)
1957 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1962 // creation a new study and restoring will be done in another application
1963 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1964 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1967 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1968 QString aStudyName = myNoteBook->getDumpedStudyName();
1969 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1970 // clear a study (delete all objects)
1971 onCloseDoc( false );
1973 if( !changeDesktop ) {
1974 ok = onRestoreStudy( aDumpScript,
1983 //============================================================================
1984 /*! Function : onRestoreStudy
1985 * Purpose : Load the dumped study from Python script
1987 //============================================================================
1988 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1989 const QString& theStudyName,
1990 bool theIsStudySaved )
1994 // create a new study
1997 // get active application
1998 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2000 // load study from the temporary directory
2001 QString command = QString( "exec(open(\"%1\").read())" ).arg( theDumpScript );
2003 #ifndef DISABLE_PYCONSOLE
2004 PyConsole_Console* pyConsole = app->pythonConsole();
2006 pyConsole->execAndWait( command );
2009 // remove temporary directory
2010 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2011 QString aStudyName = aScriptInfo.baseName();
2012 QDir aDir = aScriptInfo.absoluteDir();
2013 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2014 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2015 ok = aDir.remove( *it ) && ok;
2017 ok = aDir.rmdir( aDir.absolutePath() );
2019 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2021 #ifndef DISABLE_PYCONSOLE
2022 _PTR(Study) aStudyDS = newStudy->studyDS();
2023 if ( app->getNoteBook() )
2024 app->getNoteBook()->Init( aStudyDS );
2025 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2026 newStudy->Modified();
2027 updateDesktopTitle();
2038 Close the Application
2040 void SalomeApp_Application::afterCloseDoc()
2042 #ifndef DISABLE_PYCONSOLE
2043 // emit signal to restore study from Python script
2045 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2046 myNoteBook->getDumpedStudyName(),
2047 myNoteBook->isDumpedStudySaved() );
2050 LightApp_Application::afterCloseDoc();
2054 Asks to close existing document.
2056 bool SalomeApp_Application::checkExistingDoc()
2058 bool result = LightApp_Application::checkExistingDoc();
2059 if ( result && !activeStudy() ) {
2060 SALOMEDSClient_StudyManager* aMgr = studyMgr();
2062 std::vector<std::string> List = studyMgr()->GetOpenStudies();
2063 if( List.size() > 0 ) {
2064 SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2073 #ifndef DISABLE_PYCONSOLE
2075 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2077 return new SalomeApp_PyInterp;
2080 #endif // DISABLE_PYCONSOLE