1 // Copyright (C) 2007-2015 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" // WARNING! This include must be the first!
39 #include <PyConsole_Console.h>
40 #include "SalomeApp_NoteBook.h"
42 #include "SalomeApp_Application.h"
43 #include "SalomeApp_Study.h"
44 #include "SalomeApp_DataModel.h"
45 #include "SalomeApp_DataObject.h"
46 #include "SalomeApp_VisualState.h"
47 #include "SalomeApp_StudyPropertiesDlg.h"
48 #include "SalomeApp_LoadStudiesDlg.h"
49 #include "SalomeApp_ExitDlg.h"
51 #include <LightApp_Application.h>
52 #include <LightApp_Module.h>
53 #include <LightApp_Preferences.h>
54 #include <LightApp_SelectionMgr.h>
55 #include <LightApp_NameDlg.h>
56 #include <LightApp_DataOwner.h>
58 #include <CAM_Module.h>
60 #include <SUIT_Tools.h>
61 #include <SUIT_Session.h>
62 #include <SUIT_Desktop.h>
63 #include <SUIT_DataBrowser.h>
64 #include <SUIT_FileDlg.h>
65 #include <SUIT_FileValidator.h>
66 #include <SUIT_MessageBox.h>
67 #include <SUIT_ResourceMgr.h>
68 #include <SUIT_TreeModel.h>
69 #include <SUIT_ViewWindow.h>
70 #include <SUIT_ViewManager.h>
71 #include <SUIT_ViewModel.h>
72 #include <SUIT_OverrideCursor.h>
74 #include <QtxTreeView.h>
76 #include <SALOME_EventFilter.h>
78 // temporary commented
79 //#include <OB_ListItem.h>
82 #include <Utils_ORB_INIT.hxx>
83 #include <Utils_SINGLETON.hxx>
84 #include <SALOME_LifeCycleCORBA.hxx>
86 #include <QApplication>
90 #include <QPushButton>
92 #include <QListWidget>
93 #include <QGridLayout>
97 #include <SALOMEDSClient_ClientFactory.hxx>
98 #include <Basics_Utils.hxx>
100 #include <SALOME_ListIO.hxx>
101 #include <SALOME_Prs.h>
104 #include <ToolsGUI_CatalogGeneratorDlg.h>
105 #include <ToolsGUI_RegWidget.h>
109 #include <SALOMEDS_Tool.hxx>
111 /*!Internal class that updates object browser item properties */
112 // temporary commented
113 /*class SalomeApp_Updater : public OB_Updater
116 SalomeApp_Updater() : OB_Updater(){};
117 virtual ~SalomeApp_Updater(){};
118 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
121 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
123 if( !theObj || !theItem )
126 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
130 _PTR(SObject) SObj = SAObj->object();
133 _PTR( GenericAttribute ) anAttr;
136 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
138 _PTR(AttributeSelectable) aAttrSel = anAttr;
139 theItem->setSelectable( aAttrSel->IsSelectable() );
142 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
144 _PTR(AttributeExpandable) aAttrExpand = anAttr;
145 theItem->setExpandable( aAttrExpand->IsExpandable() );
148 //this attribute is not supported in the version of SALOME 3.x
149 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
151 // _PTR(AttributeOpened) aAttrOpen = anAttr;
152 // theItem->setOpen( aAttrOpen->IsOpened() );
156 /*!Create new instance of SalomeApp_Application.*/
157 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
159 return new SalomeApp_Application();
163 SalomeApp_Application::SalomeApp_Application()
164 : LightApp_Application(),
165 myIsCloseFromExit( false )
170 *\li Destroy event filter.
172 SalomeApp_Application::~SalomeApp_Application()
174 // Do not destroy. It's a singleton !
175 //SALOME_EventFilter::Destroy();
178 QStringList __getArgsList(QString argsString)
180 // Special process if some items of 'args:' list are themselves lists
181 // Note that an item can be a list, but not a list of lists...
182 // So we can have something like this:
183 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
184 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
185 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
186 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
187 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
189 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
194 return argsString.split(",", QString::SkipEmptyParts);
197 /*!Start application.*/
198 void SalomeApp_Application::start()
200 // process the command line options before start: to createActions in accordance to the options
201 static bool isFirst = true;
209 for (int i = 1; i < qApp->argc(); i++) {
210 QRegExp rxs ("--study-hdf=(.+)");
211 if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
212 QString file = rxs.capturedTexts()[1];
213 QFileInfo fi ( file );
214 QString extension = fi.suffix().toLower();
215 if ( extension == "hdf" && fi.exists() )
216 hdffile = fi.absoluteFilePath();
219 QRegExp rxp ("--pyscript=\\[(.+)\\]");
220 if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
222 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
223 for (int k = 0; k < dictList.count(); ++k) {
224 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
225 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
226 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
227 pyfiles += rxd.capturedTexts()[m];
234 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
235 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
237 LightApp_Application::start();
238 SALOME_EventFilter::Init();
240 setProperty("open_study_from_command_line", true);
241 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
242 onOpenDoc( hdffile );
243 else if ( pyfiles.count() > 0 ) // create new study
245 else if (!loadStudy.isEmpty()) {// load study by name
246 if (onLoadDoc(loadStudy))
247 updateObjectBrowser(true);
249 setProperty("open_study_from_command_line", QVariant());
251 #ifndef DISABLE_PYCONSOLE
252 // import/execute python scripts
253 if ( pyfiles.count() > 0 && activeStudy() ) {
254 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
255 PyConsole_Console* pyConsole = pythonConsole();
256 if ( appStudy && pyConsole ) {
257 _PTR(Study) aStudy = appStudy->studyDS();
258 if ( !aStudy->GetProperties()->IsLocked() ) {
259 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
260 // Path is absolute, script has .py extension
261 for (uint j = 0; j < pyfiles.count(); j++ ) {
262 // Extract scripts and their arguments, if any
263 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
264 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
265 QString script = rxp.capturedTexts()[1];
267 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
268 for (uint k = 0; k < argList.count(); k++ ) {
269 QString arg = argList[k].trimmed();
270 arg.remove( QRegExp("^[\"]") );
271 arg.remove( QRegExp("[\"]$") );
274 args.remove( QRegExp("[,]$") );
275 if (!args.isEmpty()) {
279 script.remove( QRegExp("^python.*[\\s]+") );
280 QString cmd = script+" "+args;
281 QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
282 pyConsole->exec(command);
284 } // end for loop on pyfiles QStringList
290 LightApp_Application::start();
291 SALOME_EventFilter::Init();
296 void SalomeApp_Application::createActions()
298 LightApp_Application::createActions();
300 SUIT_Desktop* desk = desktop();
303 // "Save GUI State" command is moved to VISU module
304 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
305 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
306 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
309 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
310 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
311 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
314 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
315 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
316 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
319 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
320 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
321 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
323 //! Catalog Generator
324 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
325 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
326 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
329 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
330 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
331 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
333 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
334 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
335 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
337 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
338 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
339 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
342 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
344 // "Save GUI State" command is renamed to "Save VISU State" and
345 // creation of menu item is moved to VISU
346 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
348 createMenu( ConnectId, fileMenu, 5 );
349 createMenu( DisconnectId, fileMenu, 5 );
350 createMenu( separator(), fileMenu, -1, 5 );
352 createMenu( DumpStudyId, fileMenu, 10, -1 );
353 createMenu( LoadScriptId, fileMenu, 10, -1 );
354 createMenu( separator(), fileMenu, -1, 10, -1 );
355 createMenu( PropertiesId, fileMenu, 10, -1 );
356 createMenu( separator(), fileMenu, -1, 10, -1 );
358 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
359 createMenu( CatalogGenId, toolsMenu, 10, -1 );
360 createMenu( RegDisplayId, toolsMenu, 10, -1 );
361 createMenu( separator(), toolsMenu, -1, 15, -1 );
363 createExtraActions();
365 #ifndef DISABLE_PYCONSOLE
366 #ifndef DISABLE_SALOMEOBJECT
367 // import Python module that manages SALOME plugins
369 PyLockWrapper lck; // acquire GIL
370 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
371 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
375 // end of SALOME plugins loading
382 \brief Close application.
384 void SalomeApp_Application::onExit()
386 bool killServers = false;
389 if ( exitConfirmation() ) {
390 SalomeApp_ExitDlg dlg( desktop() );
391 result = dlg.exec() == QDialog::Accepted;
392 killServers = dlg.isServersShutdown();
396 if ( !killServers ) myIsCloseFromExit = true;
397 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
398 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
402 /*!SLOT. Load document.*/
403 void SalomeApp_Application::onLoadDoc()
407 std::vector<std::string> List = studyMgr()->GetOpenStudies();
409 // rnv: According to the single-study approach on the server side
410 // can be only one study. So if it is exists connect to them,
411 // overwise show warning message: "No active study on the server"
414 SUIT_Session* aSession = SUIT_Session::session();
415 QList<SUIT_Application*> aAppList = aSession->applications();
417 QStringList unloadedStudies;
419 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
420 studyName = List[ind].c_str();
421 // Add to list only unloaded studies
422 bool isAlreadyOpen = false;
423 QListIterator<SUIT_Application*> it( aAppList );
424 while ( it.hasNext() && !isAlreadyOpen ) {
425 SUIT_Application* aApp = it.next();
426 if( !aApp || !aApp->activeStudy() )
428 if ( aApp->activeStudy()->studyName() == studyName )
429 isAlreadyOpen = true;
432 if ( !isAlreadyOpen )
433 unloadedStudies << studyName;
435 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
436 if ( studyName.isEmpty() )
440 if(List.size() <= 0) {
441 SUIT_MessageBox::warning( desktop(),
442 QObject::tr("WRN_WARNING"),
443 QObject::tr("WRN_NO_STUDY_ON SERV") );
447 studyName = List[0].c_str();
450 // this code replaces marker of windows drive and path become invalid therefore
451 // defines placed there
452 studyName.replace( QRegExp(":"), "/" );
455 if ( onLoadDoc( studyName ) ) {
457 updateViewManagers();
458 updateObjectBrowser( true );
462 /*!SLOT. Unload document.*/
463 void SalomeApp_Application::onUnloadDoc( bool ask )
466 activeStudy()->abortAllOperations();
467 if ( activeStudy()->isModified() ) {
468 QString docName = activeStudy()->studyName().trimmed();
469 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
470 tr( "DISCONNECT_DESCRIPTION" ),
471 tr( "DISCONNECT_SAVE" ),
472 tr( "DISCONNECT_WO_SAVE" ),
473 tr( "APPCLOSE_CANCEL" ), 0 );
474 if ( answer == 0 ) { // save before unload
475 if ( activeStudy()->isSaved() )
477 else if ( !onSaveAsDoc() )
480 else if ( answer == 2 ) // Cancel
484 closeActiveDoc( false );
487 /*!SLOT. Create new study and load script*/
488 void SalomeApp_Application::onNewWithScript()
490 QStringList filtersList;
491 filtersList.append(tr("PYTHON_FILES_FILTER"));
492 filtersList.append(tr("ALL_FILES_FILTER"));
494 QString anInitialPath = "";
495 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
496 anInitialPath = QDir::currentPath();
498 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
500 if ( !aFile.isEmpty() )
504 QString command = QString("execfile(r\"%1\")").arg(aFile);
506 #ifndef DISABLE_PYCONSOLE
507 PyConsole_Console* pyConsole = pythonConsole();
510 pyConsole->exec( command );
516 /*!SLOT. Load document with \a aName.*/
517 bool SalomeApp_Application::onLoadDoc( const QString& aName )
519 #ifdef SINGLE_DESKTOP
520 if ( !LightApp_Application::closeDoc() )
524 if ( !activeStudy() ) {
525 // if no study - load in current desktop
526 res = useStudy( aName );
529 // if study exists - load in new desktop. Check: is the same file is loaded?
530 SUIT_Session* aSession = SUIT_Session::session();
531 QList<SUIT_Application*> aAppList = aSession->applications();
532 bool isAlreadyOpen = false;
533 SalomeApp_Application* aApp = 0;
534 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
535 it != aAppList.end() && !isAlreadyOpen; ++it ) {
536 aApp = dynamic_cast<SalomeApp_Application*>( *it );
537 if ( aApp && aApp->activeStudy()->studyName() == aName )
538 isAlreadyOpen = true;
540 if ( !isAlreadyOpen ) {
541 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
543 res = aApp->useStudy( aName );
546 aApp->desktop()->activateWindow();
553 /*!SLOT. Parse message for desktop.*/
554 void SalomeApp_Application::onDesktopMessage( const QString& message )
556 if (message.indexOf("studyCreated:") == 0) {
557 // Enable 'Connect' action
558 updateCommandsStatus();
560 else if (message.indexOf("studyClosed:") == 0) {
561 /* message also contains ID of the closed study,
562 but as soon as SALOME is mono-study application for the moment,
563 this ID is not needed now.*/
564 //long aStudyId = message.section(':', 1).toLong();
565 // Disconnect GUI from active study, because it was closed on DS side.
566 closeActiveDoc( false );
567 // Disable 'Connect' action
568 QAction* a = action( ConnectId );
570 a->setEnabled( false );
572 else if ( message.toLower() == "connect_to_study" ) {
575 LightApp_Application::onDesktopMessage( message );
578 /*!SLOT. Copy objects to study maneger from selection maneger..*/
579 void SalomeApp_Application::onCopy()
582 LightApp_SelectionMgr* mgr = selectionMgr();
583 mgr->selectedObjects(list);
585 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
586 if(study == NULL) return;
588 _PTR(Study) stdDS = study->studyDS();
591 SALOME_ListIteratorOfListIO it( list );
594 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
596 studyMgr()->Copy(so);
597 onSelectionChanged();
604 /*!SLOT. Paste objects to study maneger from selection manager.*/
605 void SalomeApp_Application::onPaste()
608 LightApp_SelectionMgr* mgr = selectionMgr();
609 mgr->selectedObjects(list);
611 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
612 if(study == NULL) return;
614 _PTR(Study) stdDS = study->studyDS();
617 if ( stdDS->GetProperties()->IsLocked() ) {
618 SUIT_MessageBox::warning( desktop(),
619 QObject::tr("WRN_WARNING"),
620 QObject::tr("WRN_STUDY_LOCKED") );
624 SALOME_ListIteratorOfListIO it( list );
627 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
629 studyMgr()->Paste(so);
630 updateObjectBrowser( true );
631 updateActions(); //SRN: BugID IPAL9377, case 3
638 /*!Check the application on closing.
639 * \retval true if possible, else false
641 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
643 return LightApp_Application::isPossibleToClose( closePermanently );
646 /*! Check if the study is locked */
647 void SalomeApp_Application::onCloseDoc( bool ask )
649 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
652 _PTR(Study) stdDS = study->studyDS();
653 if(stdDS && stdDS->IsStudyLocked()) {
654 if ( SUIT_MessageBox::question( desktop(),
655 QObject::tr( "WRN_WARNING" ),
656 QObject::tr( "CLOSE_LOCKED_STUDY" ),
657 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
658 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
662 LightApp_Application::onCloseDoc( ask );
665 /*!Sets enable or disable some actions on selection changed.*/
666 void SalomeApp_Application::onSelectionChanged()
669 LightApp_SelectionMgr* mgr = selectionMgr();
670 mgr->selectedObjects(list);
672 bool canCopy = false;
673 bool canPaste = false;
675 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
678 canCopy = m->canCopy();
679 canPaste = m->canPaste();
682 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
684 _PTR(Study) stdDS = study->studyDS();
687 SALOME_ListIteratorOfListIO it ( list );
689 if (it.More() && list.Extent() == 1) {
690 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
693 canCopy = canCopy || studyMgr()->CanCopy(so);
694 canPaste = canPaste || studyMgr()->CanPaste(so);
700 action(EditCopyId)->setEnabled(canCopy);
701 action(EditPasteId)->setEnabled(canPaste);
704 /*!Delete references.*/
705 void SalomeApp_Application::onDeleteInvalidReferences()
708 LightApp_SelectionMgr* mgr = selectionMgr();
709 mgr->selectedObjects( aList, QString(), false );
711 if( aList.IsEmpty() )
714 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
715 _PTR(Study) aStudyDS = aStudy->studyDS();
716 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
719 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
720 if ( it.Value()->hasEntry() )
722 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
723 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
726 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
727 aStudyBuilder->RemoveReference( aSObject );
729 updateObjectBrowser();
733 void SalomeApp_Application::onOpenWith()
735 QApplication::setOverrideCursor( Qt::WaitCursor );
737 LightApp_SelectionMgr* mgr = selectionMgr();
738 mgr->selectedObjects(aList);
739 if (aList.Extent() != 1)
741 QApplication::restoreOverrideCursor();
744 Handle(SALOME_InteractiveObject) aIObj = aList.First();
745 QString aModuleName(aIObj->getComponentDataType());
746 QString aModuleTitle = moduleTitle(aModuleName);
747 activateModule(aModuleTitle);
748 QApplication::restoreOverrideCursor();
754 SUIT_Study* SalomeApp_Application::createNewStudy()
756 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
758 // Set up processing of major study-related events
759 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
760 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
761 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
762 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
764 #ifndef DISABLE_PYCONSOLE
765 //to receive signal in application that NoteBook's variable was modified
766 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
767 this, SIGNAL(notebookVarUpdated(QString)) );
774 Enable/Disable menu items and toolbar buttons. Rebuild menu
776 void SalomeApp_Application::updateCommandsStatus()
778 LightApp_Application::updateCommandsStatus();
781 QAction* a = action( DumpStudyId );
783 a->setEnabled( activeStudy() );
785 #ifndef DISABLE_PYCONSOLE
787 a = action( LoadScriptId );
789 a->setEnabled( pythonConsole() );
793 a = action( PropertiesId );
795 a->setEnabled( activeStudy() );
797 // Save GUI state menu
798 a = action( SaveGUIStateId );
800 a->setEnabled( activeStudy() );
802 // Connect study menu
803 a = action( ConnectId );
805 a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
807 // Disconnect study menu
808 a = action( DisconnectId );
810 a->setEnabled( activeStudy() );
812 // update state of Copy/Paste menu items
813 onSelectionChanged();
817 \class DumpStudyFileDlg
818 Private class used in Dump Study operation. Consists 2 check boxes:
819 "Publish in study" and "Save GUI parameters"
821 class DumpStudyFileDlg : public SUIT_FileDlg
824 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
826 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
829 QWidget *hB = new QWidget( this );
830 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
831 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
832 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
834 QHBoxLayout *layout = new QHBoxLayout;
835 layout->addWidget(myPublishChk);
836 layout->addWidget(myMultiFileChk);
837 layout->addWidget(mySaveGUIChk);
838 hB->setLayout(layout);
840 QPushButton* pb = new QPushButton(this);
842 int row = grid->rowCount();
843 grid->addWidget( new QLabel("", this), row, 0 );
844 grid->addWidget( hB, row, 1, 1, 3 );
845 grid->addWidget( pb, row, 5 );
850 QCheckBox* myPublishChk;
851 QCheckBox* myMultiFileChk;
852 QCheckBox* mySaveGUIChk;
855 class DumpStudyFileValidator : public SUIT_FileValidator
858 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
859 virtual ~DumpStudyFileValidator() {};
860 virtual bool canSave( const QString& file, bool permissions );
863 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
865 QFileInfo fi( file );
866 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
867 SUIT_MessageBox::critical( parent(),
868 QObject::tr("WRN_WARNING"),
869 QObject::tr("WRN_FILE_NAME_BAD") );
872 return SUIT_FileValidator::canSave( file, permissions);
875 /*!Private SLOT. On dump study.*/
876 void SalomeApp_Application::onDumpStudy( )
878 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
879 if ( !appStudy ) return;
880 _PTR(Study) aStudy = appStudy->studyDS();
882 QStringList aFilters;
883 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
885 bool anIsPublish = true;
886 bool anIsMultiFile = false;
887 bool anIsSaveGUI = true;
889 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
890 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
891 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
892 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
895 DumpStudyFileDlg fd( desktop() );
896 fd.setValidator( new DumpStudyFileValidator( &fd ) );
897 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
898 fd.setFilters( aFilters );
899 fd.myPublishChk->setChecked( anIsPublish );
900 fd.myMultiFileChk->setChecked( anIsMultiFile );
901 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
902 if ( fd.exec() == QDialog::Accepted )
904 QString aFileName = fd.selectedFile();
906 bool toPublish = fd.myPublishChk->isChecked();
907 bool isMultiFile = fd.myMultiFileChk->isChecked();
908 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
910 if ( !aFileName.isEmpty() ) {
911 QFileInfo aFileInfo(aFileName);
912 if( aFileInfo.isDir() ) // IPAL19257
915 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
918 SUIT_OverrideCursor wc;
919 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
922 SUIT_MessageBox::warning( desktop(),
923 QObject::tr("WRN_WARNING"),
924 tr("WRN_DUMP_STUDY_FAILED") );
929 /*!Private SLOT. On load script.*/
930 void SalomeApp_Application::onLoadScript( )
932 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
934 _PTR(Study) aStudy = appStudy->studyDS();
935 if ( aStudy->GetProperties()->IsLocked() ) {
936 SUIT_MessageBox::warning( desktop(),
937 QObject::tr("WRN_WARNING"),
938 QObject::tr("WRN_STUDY_LOCKED") );
943 QStringList filtersList;
944 filtersList.append(tr("PYTHON_FILES_FILTER"));
945 filtersList.append(tr("ALL_FILES_FILTER"));
947 QString anInitialPath = "";
948 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
949 anInitialPath = QDir::currentPath();
951 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
953 if ( !aFile.isEmpty() )
955 QString command = QString("execfile(r\"%1\")").arg(aFile);
957 #ifndef DISABLE_PYCONSOLE
958 PyConsole_Console* pyConsole = pythonConsole();
961 pyConsole->exec( command );
966 /*!Private SLOT. On save GUI state.*/
967 void SalomeApp_Application::onSaveGUIState()
969 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
971 SalomeApp_VisualState( this ).storeState();
972 updateSavePointDataObjects( study );
973 updateObjectBrowser();
978 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
979 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
981 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
982 QAction* send = ::qobject_cast<QAction*>( sender() );
985 QString aWinName = send->data().toString();
986 if ( theIsVisible && aWinName == "objectBrowser" )
987 objectBrowserColumnsVisibility();
991 *\retval QString "(*.hdf)"
993 QString SalomeApp_Application::getFileFilter() const
999 QWidget* SalomeApp_Application::createWindow( const int flag )
1002 #ifndef DISABLE_PYCONSOLE
1003 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1005 wid = LightApp_Application::createWindow(flag);
1008 SUIT_ResourceMgr* resMgr = resourceMgr();
1010 if ( flag == WT_ObjectBrowser )
1012 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1014 // temporary commented
1015 //ob->setUpdater( new SalomeApp_Updater() );
1017 #ifdef WITH_SALOMEDS_OBSERVER
1018 //do not activate the automatic update of Qt tree through signal/slot
1019 ob->setAutoUpdate(false);
1020 //activate update of modified objects only
1021 ob->setUpdateModified(true);
1024 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1027 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1028 IORCol = QObject::tr( "IOR_COLUMN" ),
1029 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1030 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1032 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1033 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1034 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1035 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1036 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1037 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1038 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1039 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1040 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1042 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1043 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1044 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1046 ob->setAutoSizeFirstColumn(autoSizeFirst);
1047 ob->setAutoSizeColumns(autoSize);
1048 ob->setResizeOnExpandItem(resizeOnExpandItem);
1049 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1051 // temporary commented
1053 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1055 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1056 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1057 QString().sprintf( "visibility_column_%d", i ), true ) );
1061 // temporary commented
1063 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1064 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1065 ob->resize( desktop()->width()/3, ob->height() );
1069 #ifndef DISABLE_PYCONSOLE
1070 else if ( flag == WT_PyConsole )
1072 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
1073 pyCons->setObjectName( "pythonConsole" );
1074 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1075 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1076 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1077 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1079 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1080 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1082 else if ( flag == WT_NoteBook )
1084 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1086 _PTR(Study) aStudy = appStudy->studyDS();
1087 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1088 //to receive signal in NoteBook that it's variable was modified
1089 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1090 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1092 wid = getNoteBook();
1093 wid->setObjectName( "noteBook" );
1099 /*!Create preferences.*/
1100 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1102 LightApp_Application::createPreferences(pref);
1107 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1108 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1109 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1110 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1112 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1113 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1115 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1117 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1118 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1119 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1120 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1121 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1122 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1123 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1124 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1125 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1126 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1129 /*!Update desktop title.*/
1130 void SalomeApp_Application::updateDesktopTitle() {
1131 QString aTitle = applicationName();
1132 QString aVer = applicationVersion();
1133 if ( !aVer.isEmpty() )
1134 aTitle += QString( " " ) + aVer;
1136 if ( activeStudy() )
1138 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1139 if ( !sName.isEmpty() ) {
1140 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1142 _PTR(Study) stdDS = study->studyDS();
1144 if ( stdDS->GetProperties()->IsLocked() ) {
1145 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1147 aTitle += QString( " - [%1]" ).arg( sName );
1154 desktop()->setWindowTitle( aTitle );
1157 int SalomeApp_Application::closeChoice( const QString& docName )
1159 QStringList buttons;
1160 QMap<int, int> choices;
1162 buttons << tr ("APPCLOSE_SAVE"); // Save & Close
1163 choices.insert( idx++, CloseSave ); // ...
1164 buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving
1165 choices.insert( idx++, CloseDiscard ); // ...
1166 if ( myIsCloseFromExit ) {
1167 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1168 choices.insert( idx++, CloseDisconnectSave ); // ...
1169 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1170 choices.insert( idx++, CloseDisconnect ); // ...
1172 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1173 choices.insert( idx++, CloseCancel ); // ...
1175 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1176 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1177 return choices[answer];
1180 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1186 if ( activeStudy()->isSaved() )
1188 else if ( !onSaveAsDoc() )
1193 case CloseDisconnectSave:
1194 if ( activeStudy()->isSaved() )
1196 else if ( !onSaveAsDoc() )
1198 case CloseDisconnect:
1199 closeActiveDoc( false );
1200 closePermanently = false;
1209 int SalomeApp_Application::openChoice( const QString& aName )
1211 int choice = LightApp_Application::openChoice( aName );
1213 if ( QFileInfo( aName ).exists() ) {
1214 if ( choice == OpenNew ) { // The document isn't already open.
1216 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1217 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1218 if ( aName == QString( lst[i].c_str() ) )
1221 // The document already exists in the study manager.
1222 // Do you want to reload it?
1224 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1225 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1226 if ( answer == SUIT_MessageBox::Yes )
1227 choice = OpenRefresh;
1229 choice = OpenCancel;
1232 } else { // file is not exist on disk
1233 SUIT_MessageBox::warning( desktop(),
1234 QObject::tr("WRN_WARNING"),
1235 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1242 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1245 int choice = aChoice;
1250 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1253 studyMgr()->Close( aStudy );
1258 res = LightApp_Application::openAction( choice, aName );
1266 \brief Get map of the operations which can be performed
1267 on the module activation.
1269 The method should return the map of the kind \c {<id>:<name>}
1270 where \c <id> is an integer identifier of the operation and
1271 \c <name> is a title for the button to be added to the
1272 dialog box. After user selects the required operation by the
1273 clicking the corresponding button in the dialog box, its identifier
1274 is passed to the moduleActionSelected() method to process
1277 \return map of the operations
1278 \sa moduleActionSelected()
1280 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1282 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1284 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1286 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1291 \brief Called when the used selectes required operation chosen
1292 from "Activate module" dialog box.
1294 Performs the required operation according to the user choice.
1296 \param id operation identifier
1297 \sa activateModuleActions()
1299 void SalomeApp_Application::moduleActionSelected( const int id )
1305 case NewAndScriptId:
1309 LightApp_Application::moduleActionSelected( id );
1314 /*!Gets CORBA::ORB_var*/
1315 CORBA::ORB_var SalomeApp_Application::orb()
1317 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1318 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1322 /*!Create and return SALOMEDS_StudyManager.*/
1323 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1325 static _PTR(StudyManager) _sm;
1326 if(!_sm) _sm = ClientFactory::StudyManager();
1330 /*!Create and return SALOME_NamingService.*/
1331 SALOME_NamingService* SalomeApp_Application::namingService()
1333 static SALOME_NamingService _ns(orb());
1337 /*!Create and return SALOME_LifeCycleCORBA.*/
1338 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1340 static SALOME_LifeCycleCORBA _lcc( namingService() );
1344 /*!Private SLOT. On preferences.*/
1345 void SalomeApp_Application::onProperties()
1347 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1351 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1354 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1355 int res = aDlg.exec();
1356 if( res==QDialog::Accepted && aDlg.isChanged() )
1357 SB->CommitCommand();
1361 //study->updateCaptions();
1362 updateDesktopTitle();
1366 /*!Insert items in popup, which necessary for current application*/
1367 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1369 LightApp_SelectionMgr* mgr = selectionMgr();
1370 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1371 mgr->setSelectionCacheEnabled( true );
1373 LightApp_Application::contextMenuPopup( type, thePopup, title );
1375 // temporary commented
1376 /*OB_Browser* ob = objectBrowser();
1377 if ( !ob || type != ob->popupClientType() )
1380 // Get selected objects
1381 SALOME_ListIO aList;
1382 mgr->selectedObjects( aList, QString(), false );
1384 // add GUI state commands: restore, rename
1385 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1386 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1387 thePopup->addSeparator();
1388 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1389 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1390 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1391 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1394 // "Delete reference" item should appear only for invalid references
1396 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1397 bool isInvalidRefs = false;
1398 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1400 _PTR(Study) aStudyDS = aStudy->studyDS();
1401 _PTR(SObject) anObj;
1403 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1405 if( it.Value()->hasEntry() )
1407 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1408 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1411 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1412 isInvalidRefs = true;
1416 // Add "Delete reference" item to popup
1417 if ( isInvalidRefs )
1419 thePopup->addSeparator();
1420 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1424 // "Activate module" item should appear only if it's necessary
1425 if ( aList.Extent() == 1 ) {
1427 mgr->selectedObjects( aList );
1429 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1431 // add extra popup menu (defined in XML)
1432 if ( myExtActions.size() > 0 ) {
1433 // Use only first selected object
1434 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1436 _PTR(Study) stdDS = study->studyDS();
1438 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1440 _PTR( GenericAttribute ) anAttr;
1441 std::string auid = "AttributeUserID";
1442 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1443 if ( aSO->FindAttribute( anAttr, auid ) ) {
1444 _PTR(AttributeUserID) aAttrID = anAttr;
1445 QString aId = aAttrID->Value().c_str();
1446 if ( myExtActions.contains( aId ) ) {
1447 thePopup->addAction(myExtActions[aId]);
1455 // check if item is a "GUI state" item (also a first level object)
1456 QString entry( aIObj->getEntry() );
1457 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1458 QString aModuleName( aIObj->getComponentDataType() );
1459 QString aModuleTitle = moduleTitle( aModuleName );
1460 CAM_Module* currentModule = activeModule();
1461 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1462 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1467 mgr->setSelectionCacheEnabled( cacheIsOn );
1470 /*!Update obect browser:
1471 1.if 'updateModels' true, update existing data models;
1472 2. update "non-existing" (not loaded yet) data models;
1473 3. update object browser if it exists */
1474 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1476 // update "non-existing" (not loaded yet) data models
1477 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1480 _PTR(Study) stdDS = study->studyDS();
1483 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1485 _PTR(SComponent) aComponent ( it->Value() );
1487 #ifndef WITH_SALOMEDS_OBSERVER
1488 // with GUI observers this check is not needed anymore
1489 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1490 continue; // skip the magic "Interface Applicative" component
1492 if ( !objectBrowser() )
1493 getWindow( WT_ObjectBrowser );
1494 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1495 objectBrowser()->setAutoUpdate( false );
1496 SalomeApp_DataModel::synchronize( aComponent, study );
1497 objectBrowser()->setAutoUpdate( isAutoUpdate );
1502 // create data objects that correspond to GUI state save points
1503 if ( study ) updateSavePointDataObjects( study );
1505 // update existing data models (already loaded SComponents)
1506 LightApp_Application::updateObjectBrowser( updateModels );
1509 /*!Display Catalog Genenerator dialog */
1510 void SalomeApp_Application::onCatalogGen()
1512 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1516 /*!Display Registry Display dialog */
1517 void SalomeApp_Application::onRegDisplay()
1519 CORBA::ORB_var anOrb = orb();
1520 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1523 regWnd->activateWindow();
1526 /*!find original object by double click on item */
1527 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1529 // Issue 21379: References are supported at LightApp_DataObject level
1530 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1532 if( obj && obj->isReference() )
1534 QString entry = obj->refEntry();
1536 SUIT_DataOwnerPtrList aList;
1537 aList.append( new LightApp_DataOwner( entry ) );
1538 selectionMgr()->setSelected( aList, false );
1540 SUIT_DataBrowser* ob = objectBrowser();
1542 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1543 if ( !aSelectedIndexes.isEmpty() )
1544 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1549 Creates new view manager
1550 \param type - type of view manager
1552 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1554 return createViewManager(type);
1558 /*!Global utility function, returns selected GUI Save point object's ID */
1559 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1561 SALOME_ListIO aList;
1562 selMgr->selectedObjects( aList );
1563 if( aList.Extent() > 0 ) {
1564 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1565 QString entry( aIObj->getEntry() );
1566 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1567 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1569 bool ok; // conversion to integer is ok?
1570 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1571 return ok ? savePoint : -1;
1576 /*!Called on Restore GUI State popup command*/
1577 void SalomeApp_Application::onRestoreGUIState()
1579 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1580 if ( savePoint == -1 )
1582 SalomeApp_VisualState( this ).restoreState( savePoint );
1585 /*!Called on Delete GUI State popup command*/
1586 void SalomeApp_Application::onDeleteGUIState()
1588 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1589 if ( savePoint == -1 )
1591 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1595 study->removeSavePoint( savePoint );
1596 updateSavePointDataObjects( study );
1599 /*!Called on New study operation*/
1600 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1602 LightApp_Application::onStudyCreated( study );
1604 //#ifndef DISABLE_PYCONSOLE
1605 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1606 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1609 loadDockWindowsState();
1611 objectBrowserColumnsVisibility();
1614 /*!Called on Open study operation*/
1615 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1617 LightApp_Application::onStudyOpened( study );
1619 //#ifndef DISABLE_PYCONSOLE
1620 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1621 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1624 loadDockWindowsState();
1626 objectBrowserColumnsVisibility();
1628 // temporary commented
1629 /*if ( objectBrowser() ) {
1630 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1631 objectBrowser()->updateTree( study->root() );
1635 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1636 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1639 SUIT_DataBrowser* ob = objectBrowser();
1640 LightApp_SelectionMgr* selMgr = selectionMgr();
1642 if ( !study || !ob || !selMgr )
1645 // find GUI states root object
1646 SUIT_DataObject* guiRootObj = 0;
1648 study->root()->children( ch );
1649 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1650 for ( ; it != last ; ++it ) {
1651 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1656 std::vector<int> savePoints = study->getSavePoints();
1657 // case 1: no more save points but they existed in study's tree
1658 if ( savePoints.empty() && guiRootObj ) {
1659 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1660 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1661 const bool isAutoUpdate = ob->autoUpdate();
1662 selMgr->clearSelected();
1663 ob->setAutoUpdate(true);
1664 DataObjectList ch = guiRootObj->children();
1665 for( int i = 0; i < ch.size(); i++ )
1668 ob->setAutoUpdate(isAutoUpdate);
1671 // case 2: no more save points but root does not exist either
1672 if ( savePoints.empty() && !guiRootObj )
1674 // case 3: save points but no root for them - create it
1675 if ( !savePoints.empty() && !guiRootObj )
1676 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1677 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1678 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1680 if ( guiRootObj->nextBrother() ) {
1681 study->root()->removeChild(guiRootObj);
1682 study->root()->appendChild(guiRootObj);
1683 //study->root()->dump();
1686 // store data objects in a map id-to-DataObject
1687 QMap<int,SalomeApp_SavePointObject*> mapDO;
1689 guiRootObj->children( ch );
1690 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1691 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1693 mapDO[dobj->getId()] = dobj;
1696 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1697 // if in the map - remove it from map.
1698 for ( int i = 0; i < savePoints.size(); i++ )
1699 if ( !mapDO.contains( savePoints[i] ) )
1700 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1702 mapDO.remove( savePoints[i] );
1704 // delete DataObjects that are still in the map -- their IDs were not found in data model
1705 if( mapDO.size() > 0) {
1706 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1707 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1708 selMgr->clearSelected();
1709 const bool isAutoUpdate = ob->autoUpdate();
1710 ob->setAutoUpdate(true);
1711 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1713 ob->setAutoUpdate(isAutoUpdate);
1717 /*! Check data object */
1718 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1727 Opens other study into active Study. If Study is empty - creates it.
1728 \param theName - name of study
1730 bool SalomeApp_Application::useStudy( const QString& theName )
1733 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1736 res = aStudy->loadDocument( theName );
1737 updateDesktopTitle();
1738 updateCommandsStatus();
1742 /*! Show/hide object browser colums according to preferences */
1743 void SalomeApp_Application::objectBrowserColumnsVisibility()
1745 if ( objectBrowser() )
1746 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1748 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1749 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1753 #ifndef DISABLE_PYCONSOLE
1754 /*! Set SalomeApp_NoteBook pointer */
1755 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1757 myNoteBook = theNoteBook;
1760 /*! Return SalomeApp_NoteBook pointer */
1761 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1768 * Define extra actions defined in module definition XML file.
1769 * Additional popup items sections can be defined by parameter "popupitems".
1770 * Supported attributes:
1771 * title - title of menu item,
1772 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1773 * method - method which has to be called when menu item is selected
1775 * <section name="MODULENAME">
1776 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1778 * <section name="importmed">
1779 * <parameter name="title" value="My menu"/>
1780 * <parameter name="objectid" value="VISU.Result"/>
1781 * <parameter name="method" value="nameOfModuleMethod"/>
1784 void SalomeApp_Application::createExtraActions()
1786 myExtActions.clear();
1787 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1789 QStringList aModules;
1790 modules(aModules, false);
1791 foreach(QString aModile, aModules) {
1792 QString aModName = moduleName(aModile);
1793 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1794 if (!aSectionStr.isNull()) {
1795 QStringList aSections = aSectionStr.split(':');
1796 foreach(QString aSection, aSections) {
1797 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1798 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1799 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1800 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1803 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1804 if (aModuleName.isNull())
1805 aModuleName = aModName;
1807 QAction* aAction = new QAction(aTitle, this);
1809 aData<<aModuleName<<aSlot;
1810 aAction->setData(aData);
1811 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1812 myExtActions[aId] = aAction;
1819 * Called when extra action is selected
1821 void SalomeApp_Application::onExtAction()
1823 QAction* aAction = ::qobject_cast<QAction*>(sender());
1827 QVariant aData = aAction->data();
1828 QStringList aDataList = aData.value<QStringList>();
1829 if (aDataList.size() != 2)
1832 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1833 SALOME_ListIO aListIO;
1834 aSelectionMgr->selectedObjects(aListIO);
1835 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1836 if (aListIO.Extent() < 1)
1838 if (!anIO->hasEntry())
1841 QString aEntry(anIO->getEntry());
1843 QApplication::setOverrideCursor( Qt::WaitCursor );
1844 QString aModuleTitle = moduleTitle(aDataList[0]);
1845 activateModule(aModuleTitle);
1846 QApplication::restoreOverrideCursor();
1848 QCoreApplication::processEvents();
1850 CAM_Module* aModule = activeModule();
1854 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1855 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1859 Checks that an object can be renamed.
1860 \param entry entry of the object
1861 \brief Return \c true if object can be renamed
1863 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1865 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1869 Rename object by entry.
1870 \param entry entry of the object
1871 \param name new name of the object
1872 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1874 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1876 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1878 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1880 if(!aStudy || savePoint == -1)
1883 if ( !name.isNull() && !name.isEmpty() ) {
1884 aStudy->setNameOfSavePoint( savePoint, name );
1885 updateSavePointDataObjects( aStudy );
1887 //Mark study as modified
1894 #ifndef DISABLE_PYCONSOLE
1895 //============================================================================
1896 /*! Function : onUpdateStudy
1897 * Purpose : Slot to update the study.
1899 //============================================================================
1900 void SalomeApp_Application::onUpdateStudy()
1902 QApplication::setOverrideCursor( Qt::WaitCursor );
1904 if( !updateStudy() )
1905 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1907 QApplication::restoreOverrideCursor();
1910 //============================================================================
1911 /*! Function : updateStudy
1912 * Purpose : Update study by dumping the study to Python script and loading it.
1913 * It is used to apply variable modifications done in NoteBook to created objects.
1915 //============================================================================
1916 bool SalomeApp_Application::updateStudy()
1918 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1919 if ( !study || !myNoteBook )
1922 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1923 myNoteBook->setDumpedStudyName( study->studyName() );
1925 _PTR(Study) studyDS = study->studyDS();
1927 // get unique temporary directory name
1928 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1929 if( aTmpDir.isEmpty() )
1932 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1933 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1935 // dump study to the temporary directory
1936 QString aScriptName( "notebook" );
1937 bool toPublish = true;
1938 bool isMultiFile = false;
1939 bool toSaveGUI = true;
1942 _PTR(AttributeParameter) ap;
1943 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1944 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1945 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1946 ip->setDumpPython(studyDS);
1947 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1949 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1951 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1954 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1958 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1959 int anIndex = aList.indexOf( this );
1961 // Disconnect dialog from application desktop in case if:
1962 // 1) Application is not the first application in the session
1963 // 2) Application is the first application in session but not the only.
1964 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1965 if( changeDesktop ) {
1967 SalomeApp_Application* app = this;
1968 if( anIndex > 0 && anIndex < aList.count() )
1969 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1970 else if(anIndex == 0 && aList.count() > 1)
1971 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1976 // creation a new study and restoring will be done in another application
1977 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1978 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1981 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1982 QString aStudyName = myNoteBook->getDumpedStudyName();
1983 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1984 // clear a study (delete all objects)
1985 onCloseDoc( false );
1987 if( !changeDesktop ) {
1988 ok = onRestoreStudy( aDumpScript,
1997 //============================================================================
1998 /*! Function : onRestoreStudy
1999 * Purpose : Load the dumped study from Python script
2001 //============================================================================
2002 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2003 const QString& theStudyName,
2004 bool theIsStudySaved )
2008 // create a new study
2011 // get active application
2012 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2014 // load study from the temporary directory
2015 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2017 #ifndef DISABLE_PYCONSOLE
2018 PyConsole_Console* pyConsole = app->pythonConsole();
2020 pyConsole->execAndWait( command );
2023 // remove temporary directory
2024 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2025 QString aStudyName = aScriptInfo.baseName();
2026 QDir aDir = aScriptInfo.absoluteDir();
2027 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2028 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2029 ok = aDir.remove( *it ) && ok;
2031 ok = aDir.rmdir( aDir.absolutePath() );
2033 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2035 #ifndef DISABLE_PYCONSOLE
2036 _PTR(Study) aStudyDS = newStudy->studyDS();
2037 app->getNoteBook()->Init( aStudyDS );
2038 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2039 newStudy->Modified();
2040 updateDesktopTitle();
2051 Close the Application
2053 void SalomeApp_Application::afterCloseDoc()
2055 #ifndef DISABLE_PYCONSOLE
2056 // emit signal to restore study from Python script
2058 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2059 myNoteBook->getDumpedStudyName(),
2060 myNoteBook->isDumpedStudySaved() );
2063 LightApp_Application::afterCloseDoc();
2067 Asks to close existing document.
2069 bool SalomeApp_Application::checkExistingDoc()
2071 bool result = LightApp_Application::checkExistingDoc();
2072 if ( result && !activeStudy() ) {
2073 SALOMEDSClient_StudyManager* aMgr = studyMgr();
2075 std::vector<std::string> List = studyMgr()->GetOpenStudies();
2076 if( List.size() > 0 ) {
2077 SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2086 #ifndef DISABLE_PYCONSOLE
2088 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2090 return new SalomeApp_PyInterp();
2093 #endif // DISABLE_PYCONSOLE