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>
91 #include <QPushButton>
93 #include <QListWidget>
94 #include <QGridLayout>
98 #include <SALOMEDSClient_ClientFactory.hxx>
99 #include <Basics_Utils.hxx>
101 #include <SALOME_ListIO.hxx>
102 #include <SALOME_Prs.h>
105 #include <ToolsGUI_CatalogGeneratorDlg.h>
106 #include <ToolsGUI_RegWidget.h>
110 #include <SALOMEDS_Tool.hxx>
112 /*!Internal class that updates object browser item properties */
113 // temporary commented
114 /*class SalomeApp_Updater : public OB_Updater
117 SalomeApp_Updater() : OB_Updater(){};
118 virtual ~SalomeApp_Updater(){};
119 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
122 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
124 if( !theObj || !theItem )
127 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
131 _PTR(SObject) SObj = SAObj->object();
134 _PTR( GenericAttribute ) anAttr;
137 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
139 _PTR(AttributeSelectable) aAttrSel = anAttr;
140 theItem->setSelectable( aAttrSel->IsSelectable() );
143 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
145 _PTR(AttributeExpandable) aAttrExpand = anAttr;
146 theItem->setExpandable( aAttrExpand->IsExpandable() );
149 //this attribute is not supported in the version of SALOME 3.x
150 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
152 // _PTR(AttributeOpened) aAttrOpen = anAttr;
153 // theItem->setOpen( aAttrOpen->IsOpened() );
157 /*!Create new instance of SalomeApp_Application.*/
158 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
160 return new SalomeApp_Application();
164 SalomeApp_Application::SalomeApp_Application()
165 : LightApp_Application(),
166 myIsCloseFromExit( false )
171 *\li Destroy event filter.
173 SalomeApp_Application::~SalomeApp_Application()
175 // Do not destroy. It's a singleton !
176 //SALOME_EventFilter::Destroy();
179 QStringList __getArgsList(QString argsString)
181 // Special process if some items of 'args:' list are themselves lists
182 // Note that an item can be a list, but not a list of lists...
183 // So we can have something like this:
184 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
185 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
186 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
187 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
188 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
190 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
195 return argsString.split(",", QString::SkipEmptyParts);
198 /*!Start application.*/
199 void SalomeApp_Application::start()
201 // process the command line options before start: to createActions in accordance to the options
202 static bool isFirst = true;
210 for (int i = 1; i < qApp->arguments().size(); i++) {
211 QRegExp rxs ("--study-hdf=(.+)");
212 if ( rxs.indexIn( qApp->arguments()[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
213 QString file = rxs.capturedTexts()[1];
214 QFileInfo fi ( file );
215 QString extension = fi.suffix().toLower();
216 if ( extension == "hdf" && fi.exists() )
217 hdffile = fi.absoluteFilePath();
220 QRegExp rxp ("--pyscript=\\[(.+)\\]");
221 if ( rxp.indexIn( qApp->arguments()[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
223 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
224 for (int k = 0; k < dictList.count(); ++k) {
225 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
226 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
227 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
228 pyfiles += rxd.capturedTexts()[m];
235 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
236 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
238 LightApp_Application::start();
239 SALOME_EventFilter::Init();
241 setProperty("open_study_from_command_line", true);
242 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
243 onOpenDoc( hdffile );
244 else if ( pyfiles.count() > 0 ) // create new study
246 else if (!loadStudy.isEmpty()) {// load study by name
247 if (onLoadDoc(loadStudy))
248 updateObjectBrowser(true);
250 setProperty("open_study_from_command_line", QVariant());
252 #ifndef DISABLE_PYCONSOLE
253 // import/execute python scripts
254 if ( pyfiles.count() > 0 && activeStudy() ) {
255 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
256 PyConsole_Console* pyConsole = pythonConsole();
257 if ( appStudy && pyConsole ) {
258 _PTR(Study) aStudy = appStudy->studyDS();
259 if ( !aStudy->GetProperties()->IsLocked() ) {
260 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
261 // Path is absolute, script has .py extension
262 for (uint j = 0; j < pyfiles.count(); j++ ) {
263 // Extract scripts and their arguments, if any
264 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
265 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
266 QString script = rxp.capturedTexts()[1];
268 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
269 for (uint k = 0; k < argList.count(); k++ ) {
270 QString arg = argList[k].trimmed();
271 arg.remove( QRegExp("^[\"]") );
272 arg.remove( QRegExp("[\"]$") );
275 args.remove( QRegExp("[,]$") );
276 if (!args.isEmpty()) {
280 script.remove( QRegExp("^python.*[\\s]+") );
281 QString cmd = script+" "+args;
282 QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
283 pyConsole->exec(command);
285 } // end for loop on pyfiles QStringList
291 LightApp_Application::start();
292 SALOME_EventFilter::Init();
297 void SalomeApp_Application::createActions()
299 LightApp_Application::createActions();
301 SUIT_Desktop* desk = desktop();
304 // "Save GUI State" command is moved to VISU module
305 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
306 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
307 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
310 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
311 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
312 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
315 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
316 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
317 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
320 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
321 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
322 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
324 //! Catalog Generator
325 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
326 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
327 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
330 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
331 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
332 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
334 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
335 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
336 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
338 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
339 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
340 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
343 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
345 // "Save GUI State" command is renamed to "Save VISU State" and
346 // creation of menu item is moved to VISU
347 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
349 createMenu( ConnectId, fileMenu, 5 );
350 createMenu( DisconnectId, fileMenu, 5 );
351 createMenu( separator(), fileMenu, -1, 5 );
353 createMenu( DumpStudyId, fileMenu, 10, -1 );
354 createMenu( LoadScriptId, fileMenu, 10, -1 );
355 createMenu( separator(), fileMenu, -1, 10, -1 );
356 createMenu( PropertiesId, fileMenu, 10, -1 );
357 createMenu( separator(), fileMenu, -1, 10, -1 );
359 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
360 createMenu( CatalogGenId, toolsMenu, 10, -1 );
361 createMenu( RegDisplayId, toolsMenu, 10, -1 );
362 createMenu( separator(), toolsMenu, -1, 15, -1 );
364 createExtraActions();
366 #ifndef DISABLE_PYCONSOLE
367 #ifndef DISABLE_SALOMEOBJECT
368 // import Python module that manages SALOME plugins
370 PyLockWrapper lck; // acquire GIL
371 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
372 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
376 // end of SALOME plugins loading
383 \brief Close application.
385 void SalomeApp_Application::onExit()
387 bool killServers = false;
390 if ( exitConfirmation() ) {
391 SalomeApp_ExitDlg dlg( desktop() );
392 result = dlg.exec() == QDialog::Accepted;
393 killServers = dlg.isServersShutdown();
397 if ( !killServers ) myIsCloseFromExit = true;
398 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
399 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
403 /*!SLOT. Load document.*/
404 void SalomeApp_Application::onLoadDoc()
408 std::vector<std::string> List = studyMgr()->GetOpenStudies();
410 // rnv: According to the single-study approach on the server side
411 // can be only one study. So if it is exists connect to them,
412 // overwise show warning message: "No active study on the server"
415 SUIT_Session* aSession = SUIT_Session::session();
416 QList<SUIT_Application*> aAppList = aSession->applications();
418 QStringList unloadedStudies;
420 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
421 studyName = List[ind].c_str();
422 // Add to list only unloaded studies
423 bool isAlreadyOpen = false;
424 QListIterator<SUIT_Application*> it( aAppList );
425 while ( it.hasNext() && !isAlreadyOpen ) {
426 SUIT_Application* aApp = it.next();
427 if( !aApp || !aApp->activeStudy() )
429 if ( aApp->activeStudy()->studyName() == studyName )
430 isAlreadyOpen = true;
433 if ( !isAlreadyOpen )
434 unloadedStudies << studyName;
436 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
437 if ( studyName.isEmpty() )
441 if(List.size() <= 0) {
442 SUIT_MessageBox::warning( desktop(),
443 QObject::tr("WRN_WARNING"),
444 QObject::tr("WRN_NO_STUDY_ON SERV") );
448 studyName = List[0].c_str();
451 // this code replaces marker of windows drive and path become invalid therefore
452 // defines placed there
453 studyName.replace( QRegExp(":"), "/" );
456 if ( onLoadDoc( studyName ) ) {
458 updateViewManagers();
459 updateObjectBrowser( true );
463 /*!SLOT. Unload document.*/
464 void SalomeApp_Application::onUnloadDoc( bool ask )
467 activeStudy()->abortAllOperations();
468 if ( activeStudy()->isModified() ) {
469 QString docName = activeStudy()->studyName().trimmed();
470 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
471 tr( "DISCONNECT_DESCRIPTION" ),
472 tr( "DISCONNECT_SAVE" ),
473 tr( "DISCONNECT_WO_SAVE" ),
474 tr( "APPCLOSE_CANCEL" ), 0 );
475 if ( answer == 0 ) { // save before unload
476 if ( activeStudy()->isSaved() )
478 else if ( !onSaveAsDoc() )
481 else if ( answer == 2 ) // Cancel
485 closeActiveDoc( false );
488 /*!SLOT. Create new study and load script*/
489 void SalomeApp_Application::onNewWithScript()
491 QStringList filtersList;
492 filtersList.append(tr("PYTHON_FILES_FILTER"));
493 filtersList.append(tr("ALL_FILES_FILTER"));
495 QString anInitialPath = "";
496 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
497 anInitialPath = QDir::currentPath();
499 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
501 if ( !aFile.isEmpty() )
505 QString command = QString("execfile(r\"%1\")").arg(aFile);
507 #ifndef DISABLE_PYCONSOLE
508 PyConsole_Console* pyConsole = pythonConsole();
511 pyConsole->exec( command );
517 /*!SLOT. Load document with \a aName.*/
518 bool SalomeApp_Application::onLoadDoc( const QString& aName )
520 #ifdef SINGLE_DESKTOP
521 if ( !LightApp_Application::closeDoc() )
525 if ( !activeStudy() ) {
526 // if no study - load in current desktop
527 res = useStudy( aName );
530 // if study exists - load in new desktop. Check: is the same file is loaded?
531 SUIT_Session* aSession = SUIT_Session::session();
532 QList<SUIT_Application*> aAppList = aSession->applications();
533 bool isAlreadyOpen = false;
534 SalomeApp_Application* aApp = 0;
535 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
536 it != aAppList.end() && !isAlreadyOpen; ++it ) {
537 aApp = dynamic_cast<SalomeApp_Application*>( *it );
538 if ( aApp && aApp->activeStudy()->studyName() == aName )
539 isAlreadyOpen = true;
541 if ( !isAlreadyOpen ) {
542 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
544 res = aApp->useStudy( aName );
547 aApp->desktop()->activateWindow();
554 /*!SLOT. Parse message for desktop.*/
555 void SalomeApp_Application::onDesktopMessage( const QString& message )
557 if (message.indexOf("studyCreated:") == 0) {
558 // Enable 'Connect' action
559 updateCommandsStatus();
561 else if (message.indexOf("studyClosed:") == 0) {
562 /* message also contains ID of the closed study,
563 but as soon as SALOME is mono-study application for the moment,
564 this ID is not needed now.*/
565 //long aStudyId = message.section(':', 1).toLong();
566 // Disconnect GUI from active study, because it was closed on DS side.
567 closeActiveDoc( false );
568 // Disable 'Connect' action
569 QAction* a = action( ConnectId );
571 a->setEnabled( false );
573 else if ( message.toLower() == "connect_to_study" ) {
576 LightApp_Application::onDesktopMessage( message );
579 /*!SLOT. Copy objects to study maneger from selection maneger..*/
580 void SalomeApp_Application::onCopy()
583 LightApp_SelectionMgr* mgr = selectionMgr();
584 mgr->selectedObjects(list);
586 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
587 if(study == NULL) return;
589 _PTR(Study) stdDS = study->studyDS();
592 SALOME_ListIteratorOfListIO it( list );
595 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
597 studyMgr()->Copy(so);
598 onSelectionChanged();
605 /*!SLOT. Paste objects to study maneger from selection manager.*/
606 void SalomeApp_Application::onPaste()
609 LightApp_SelectionMgr* mgr = selectionMgr();
610 mgr->selectedObjects(list);
612 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
613 if(study == NULL) return;
615 _PTR(Study) stdDS = study->studyDS();
618 if ( stdDS->GetProperties()->IsLocked() ) {
619 SUIT_MessageBox::warning( desktop(),
620 QObject::tr("WRN_WARNING"),
621 QObject::tr("WRN_STUDY_LOCKED") );
625 SALOME_ListIteratorOfListIO it( list );
628 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
630 studyMgr()->Paste(so);
631 updateObjectBrowser( true );
632 updateActions(); //SRN: BugID IPAL9377, case 3
639 /*!Check the application on closing.
640 * \retval true if possible, else false
642 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
644 return LightApp_Application::isPossibleToClose( closePermanently );
647 /*! Check if the study is locked */
648 void SalomeApp_Application::onCloseDoc( bool ask )
650 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
653 _PTR(Study) stdDS = study->studyDS();
654 if(stdDS && stdDS->IsStudyLocked()) {
655 if ( SUIT_MessageBox::question( desktop(),
656 QObject::tr( "WRN_WARNING" ),
657 QObject::tr( "CLOSE_LOCKED_STUDY" ),
658 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
659 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
663 LightApp_Application::onCloseDoc( ask );
666 /*!Sets enable or disable some actions on selection changed.*/
667 void SalomeApp_Application::onSelectionChanged()
670 LightApp_SelectionMgr* mgr = selectionMgr();
671 mgr->selectedObjects(list);
673 bool canCopy = false;
674 bool canPaste = false;
676 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
679 canCopy = m->canCopy();
680 canPaste = m->canPaste();
683 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
685 _PTR(Study) stdDS = study->studyDS();
688 SALOME_ListIteratorOfListIO it ( list );
690 if (it.More() && list.Extent() == 1) {
691 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
694 canCopy = canCopy || studyMgr()->CanCopy(so);
695 canPaste = canPaste || studyMgr()->CanPaste(so);
701 action(EditCopyId)->setEnabled(canCopy);
702 action(EditPasteId)->setEnabled(canPaste);
705 /*!Delete references.*/
706 void SalomeApp_Application::onDeleteInvalidReferences()
709 LightApp_SelectionMgr* mgr = selectionMgr();
710 mgr->selectedObjects( aList, QString(), false );
712 if( aList.IsEmpty() )
715 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
716 _PTR(Study) aStudyDS = aStudy->studyDS();
717 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
720 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
721 if ( it.Value()->hasEntry() )
723 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
724 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
727 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
728 aStudyBuilder->RemoveReference( aSObject );
730 updateObjectBrowser();
734 void SalomeApp_Application::onOpenWith()
736 QApplication::setOverrideCursor( Qt::WaitCursor );
738 LightApp_SelectionMgr* mgr = selectionMgr();
739 mgr->selectedObjects(aList);
740 if (aList.Extent() != 1)
742 QApplication::restoreOverrideCursor();
745 Handle(SALOME_InteractiveObject) aIObj = aList.First();
746 QString aModuleName(aIObj->getComponentDataType());
747 QString aModuleTitle = moduleTitle(aModuleName);
748 activateModule(aModuleTitle);
749 QApplication::restoreOverrideCursor();
755 SUIT_Study* SalomeApp_Application::createNewStudy()
757 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
759 // Set up processing of major study-related events
760 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
761 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
762 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
763 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
765 #ifndef DISABLE_PYCONSOLE
766 //to receive signal in application that NoteBook's variable was modified
767 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
768 this, SIGNAL(notebookVarUpdated(QString)) );
775 Enable/Disable menu items and toolbar buttons. Rebuild menu
777 void SalomeApp_Application::updateCommandsStatus()
779 LightApp_Application::updateCommandsStatus();
782 QAction* a = action( DumpStudyId );
784 a->setEnabled( activeStudy() );
786 #ifndef DISABLE_PYCONSOLE
788 a = action( LoadScriptId );
790 a->setEnabled( pythonConsole() );
794 a = action( PropertiesId );
796 a->setEnabled( activeStudy() );
798 // Save GUI state menu
799 a = action( SaveGUIStateId );
801 a->setEnabled( activeStudy() );
803 // Connect study menu
804 a = action( ConnectId );
806 a->setEnabled( !activeStudy() && studyMgr()->GetOpenStudies().size() > 0 );
808 // Disconnect study menu
809 a = action( DisconnectId );
811 a->setEnabled( activeStudy() );
813 // update state of Copy/Paste menu items
814 onSelectionChanged();
818 \class DumpStudyFileDlg
819 Private class used in Dump Study operation. Consists 2 check boxes:
820 "Publish in study" and "Save GUI parameters"
822 class DumpStudyFileDlg : public SUIT_FileDlg
825 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
827 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
830 QWidget *hB = new QWidget( this );
831 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
832 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
833 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
835 QHBoxLayout *layout = new QHBoxLayout;
836 layout->addWidget(myPublishChk);
837 layout->addWidget(myMultiFileChk);
838 layout->addWidget(mySaveGUIChk);
839 hB->setLayout(layout);
841 QPushButton* pb = new QPushButton(this);
843 int row = grid->rowCount();
844 grid->addWidget( new QLabel("", this), row, 0 );
845 grid->addWidget( hB, row, 1, 1, 3 );
846 grid->addWidget( pb, row, 5 );
851 QCheckBox* myPublishChk;
852 QCheckBox* myMultiFileChk;
853 QCheckBox* mySaveGUIChk;
856 class DumpStudyFileValidator : public SUIT_FileValidator
859 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
860 virtual ~DumpStudyFileValidator() {};
861 virtual bool canSave( const QString& file, bool permissions );
864 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
866 QFileInfo fi( file );
867 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
868 SUIT_MessageBox::critical( parent(),
869 QObject::tr("WRN_WARNING"),
870 QObject::tr("WRN_FILE_NAME_BAD") );
873 return SUIT_FileValidator::canSave( file, permissions);
876 /*!Private SLOT. On dump study.*/
877 void SalomeApp_Application::onDumpStudy( )
879 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
880 if ( !appStudy ) return;
881 _PTR(Study) aStudy = appStudy->studyDS();
883 QStringList aFilters;
884 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
886 bool anIsPublish = true;
887 bool anIsMultiFile = false;
888 bool anIsSaveGUI = true;
890 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
891 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
892 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
893 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
896 DumpStudyFileDlg fd( desktop() );
897 fd.setValidator( new DumpStudyFileValidator( &fd ) );
898 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
899 fd.setNameFilters( aFilters );
900 fd.myPublishChk->setChecked( anIsPublish );
901 fd.myMultiFileChk->setChecked( anIsMultiFile );
902 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
903 if ( fd.exec() == QDialog::Accepted )
905 QString aFileName = fd.selectedFile();
907 bool toPublish = fd.myPublishChk->isChecked();
908 bool isMultiFile = fd.myMultiFileChk->isChecked();
909 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
911 if ( !aFileName.isEmpty() ) {
912 QFileInfo aFileInfo(aFileName);
913 if( aFileInfo.isDir() ) // IPAL19257
916 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
919 SUIT_OverrideCursor wc;
920 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
923 SUIT_MessageBox::warning( desktop(),
924 QObject::tr("WRN_WARNING"),
925 tr("WRN_DUMP_STUDY_FAILED") );
930 /*!Private SLOT. On load script.*/
931 void SalomeApp_Application::onLoadScript( )
933 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
935 _PTR(Study) aStudy = appStudy->studyDS();
936 if ( aStudy->GetProperties()->IsLocked() ) {
937 SUIT_MessageBox::warning( desktop(),
938 QObject::tr("WRN_WARNING"),
939 QObject::tr("WRN_STUDY_LOCKED") );
944 QStringList filtersList;
945 filtersList.append(tr("PYTHON_FILES_FILTER"));
946 filtersList.append(tr("ALL_FILES_FILTER"));
948 QString anInitialPath = "";
949 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
950 anInitialPath = QDir::currentPath();
952 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
954 if ( !aFile.isEmpty() )
956 QString command = QString("execfile(r\"%1\")").arg(aFile);
958 #ifndef DISABLE_PYCONSOLE
959 PyConsole_Console* pyConsole = pythonConsole();
962 pyConsole->exec( command );
967 /*!Private SLOT. On save GUI state.*/
968 void SalomeApp_Application::onSaveGUIState()
970 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
972 SalomeApp_VisualState( this ).storeState();
973 updateSavePointDataObjects( study );
974 updateObjectBrowser();
979 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
980 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
982 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
983 QAction* send = ::qobject_cast<QAction*>( sender() );
986 QString aWinName = send->data().toString();
987 if ( theIsVisible && aWinName == "objectBrowser" )
988 objectBrowserColumnsVisibility();
992 *\retval QString "(*.hdf)"
994 QString SalomeApp_Application::getFileFilter() const
1000 QWidget* SalomeApp_Application::createWindow( const int flag )
1003 #ifndef DISABLE_PYCONSOLE
1004 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1006 wid = LightApp_Application::createWindow(flag);
1009 SUIT_ResourceMgr* resMgr = resourceMgr();
1011 if ( flag == WT_ObjectBrowser )
1013 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1015 // temporary commented
1016 //ob->setUpdater( new SalomeApp_Updater() );
1018 #ifdef WITH_SALOMEDS_OBSERVER
1019 //do not activate the automatic update of Qt tree through signal/slot
1020 ob->setAutoUpdate(false);
1021 //activate update of modified objects only
1022 ob->setUpdateModified(true);
1025 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1028 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1029 IORCol = QObject::tr( "IOR_COLUMN" ),
1030 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1031 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1033 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1034 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1035 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1036 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1037 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1038 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1039 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1040 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1041 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1043 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1044 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1045 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1047 ob->setAutoSizeFirstColumn(autoSizeFirst);
1048 ob->setAutoSizeColumns(autoSize);
1049 ob->setResizeOnExpandItem(resizeOnExpandItem);
1050 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1052 // temporary commented
1054 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1056 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1057 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1058 QString().sprintf( "visibility_column_%d", i ), true ) );
1062 // temporary commented
1064 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1065 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1066 ob->resize( desktop()->width()/3, ob->height() );
1070 #ifndef DISABLE_PYCONSOLE
1071 else if ( flag == WT_PyConsole )
1073 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), getPyInterp() );
1074 pyCons->setObjectName( "pythonConsole" );
1075 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1076 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1077 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1078 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1080 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1081 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1083 else if ( flag == WT_NoteBook )
1085 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1087 _PTR(Study) aStudy = appStudy->studyDS();
1088 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1089 //to receive signal in NoteBook that it's variable was modified
1090 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1091 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1093 wid = getNoteBook();
1094 wid->setObjectName( "noteBook" );
1100 /*!Create preferences.*/
1101 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1103 LightApp_Application::createPreferences(pref);
1108 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1109 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1110 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1111 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1113 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1114 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1116 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1118 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1119 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1120 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1121 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1122 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1123 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1124 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1125 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1126 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1127 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1130 /*!Update desktop title.*/
1131 void SalomeApp_Application::updateDesktopTitle() {
1132 QString aTitle = applicationName();
1133 QString aVer = applicationVersion();
1134 if ( !aVer.isEmpty() )
1135 aTitle += QString( " " ) + aVer;
1137 if ( activeStudy() )
1139 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1140 if ( !sName.isEmpty() ) {
1141 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1143 _PTR(Study) stdDS = study->studyDS();
1145 if ( stdDS->GetProperties()->IsLocked() ) {
1146 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1148 aTitle += QString( " - [%1]" ).arg( sName );
1155 desktop()->setWindowTitle( aTitle );
1158 int SalomeApp_Application::closeChoice( const QString& docName )
1160 QStringList buttons;
1161 QMap<int, int> choices;
1163 buttons << tr ("APPCLOSE_SAVE"); // Save & Close
1164 choices.insert( idx++, CloseSave ); // ...
1165 buttons << tr ("APPCLOSE_CLOSE"); // Close w/o saving
1166 choices.insert( idx++, CloseDiscard ); // ...
1167 if ( myIsCloseFromExit ) {
1168 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1169 choices.insert( idx++, CloseDisconnectSave ); // ...
1170 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1171 choices.insert( idx++, CloseDisconnect ); // ...
1173 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1174 choices.insert( idx++, CloseCancel ); // ...
1176 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1177 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1178 return choices[answer];
1181 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1187 if ( activeStudy()->isSaved() )
1189 else if ( !onSaveAsDoc() )
1194 case CloseDisconnectSave:
1195 if ( activeStudy()->isSaved() )
1197 else if ( !onSaveAsDoc() )
1199 case CloseDisconnect:
1200 closeActiveDoc( false );
1201 closePermanently = false;
1210 int SalomeApp_Application::openChoice( const QString& aName )
1212 int choice = LightApp_Application::openChoice( aName );
1214 if ( QFileInfo( aName ).exists() ) {
1215 if ( choice == OpenNew ) { // The document isn't already open.
1217 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1218 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1219 if ( aName == QString( lst[i].c_str() ) )
1222 // The document already exists in the study manager.
1223 // Do you want to reload it?
1225 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1226 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1227 if ( answer == SUIT_MessageBox::Yes )
1228 choice = OpenRefresh;
1230 choice = OpenCancel;
1233 } else { // file is not exist on disk
1234 SUIT_MessageBox::warning( desktop(),
1235 QObject::tr("WRN_WARNING"),
1236 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1243 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1246 int choice = aChoice;
1251 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1254 studyMgr()->Close( aStudy );
1259 res = LightApp_Application::openAction( choice, aName );
1267 \brief Get map of the operations which can be performed
1268 on the module activation.
1270 The method should return the map of the kind \c {<id>:<name>}
1271 where \c <id> is an integer identifier of the operation and
1272 \c <name> is a title for the button to be added to the
1273 dialog box. After user selects the required operation by the
1274 clicking the corresponding button in the dialog box, its identifier
1275 is passed to the moduleActionSelected() method to process
1278 \return map of the operations
1279 \sa moduleActionSelected()
1281 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1283 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1285 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1287 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1292 \brief Called when the used selectes required operation chosen
1293 from "Activate module" dialog box.
1295 Performs the required operation according to the user choice.
1297 \param id operation identifier
1298 \sa activateModuleActions()
1300 void SalomeApp_Application::moduleActionSelected( const int id )
1306 case NewAndScriptId:
1310 LightApp_Application::moduleActionSelected( id );
1315 /*!Gets CORBA::ORB_var*/
1316 CORBA::ORB_var SalomeApp_Application::orb()
1318 static CORBA::ORB_var _orb;
1320 if ( CORBA::is_nil( _orb ) ) {
1321 Qtx::CmdLineArgs args;
1322 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1323 _orb = init( args.argc(), args.argv() );
1329 /*!Create and return SALOMEDS_StudyManager.*/
1330 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1332 static _PTR(StudyManager) _sm;
1333 if(!_sm) _sm = ClientFactory::StudyManager();
1337 /*!Create and return SALOME_NamingService.*/
1338 SALOME_NamingService* SalomeApp_Application::namingService()
1340 static SALOME_NamingService _ns(orb());
1344 /*!Create and return SALOME_LifeCycleCORBA.*/
1345 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1347 static SALOME_LifeCycleCORBA _lcc( namingService() );
1351 /*!Private SLOT. On preferences.*/
1352 void SalomeApp_Application::onProperties()
1354 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1358 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1361 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1362 int res = aDlg.exec();
1363 if( res==QDialog::Accepted && aDlg.isChanged() )
1364 SB->CommitCommand();
1368 //study->updateCaptions();
1369 updateDesktopTitle();
1373 /*!Insert items in popup, which necessary for current application*/
1374 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1376 LightApp_SelectionMgr* mgr = selectionMgr();
1377 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1378 mgr->setSelectionCacheEnabled( true );
1380 LightApp_Application::contextMenuPopup( type, thePopup, title );
1382 // temporary commented
1383 /*OB_Browser* ob = objectBrowser();
1384 if ( !ob || type != ob->popupClientType() )
1387 // Get selected objects
1388 SALOME_ListIO aList;
1389 mgr->selectedObjects( aList, QString(), false );
1391 // add GUI state commands: restore, rename
1392 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1393 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1394 thePopup->addSeparator();
1395 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1396 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1397 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1398 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1401 // "Delete reference" item should appear only for invalid references
1403 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1404 bool isInvalidRefs = false;
1405 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1407 _PTR(Study) aStudyDS = aStudy->studyDS();
1408 _PTR(SObject) anObj;
1410 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1412 if( it.Value()->hasEntry() )
1414 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1415 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1418 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1419 isInvalidRefs = true;
1423 // Add "Delete reference" item to popup
1424 if ( isInvalidRefs )
1426 thePopup->addSeparator();
1427 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1431 // "Activate module" item should appear only if it's necessary
1432 if ( aList.Extent() == 1 ) {
1434 mgr->selectedObjects( aList );
1436 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1438 // add extra popup menu (defined in XML)
1439 if ( myExtActions.size() > 0 ) {
1440 // Use only first selected object
1441 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1443 _PTR(Study) stdDS = study->studyDS();
1445 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1447 _PTR( GenericAttribute ) anAttr;
1448 std::string auid = "AttributeUserID";
1449 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1450 if ( aSO->FindAttribute( anAttr, auid ) ) {
1451 _PTR(AttributeUserID) aAttrID = anAttr;
1452 QString aId = aAttrID->Value().c_str();
1453 if ( myExtActions.contains( aId ) ) {
1454 thePopup->addAction(myExtActions[aId]);
1462 // check if item is a "GUI state" item (also a first level object)
1463 QString entry( aIObj->getEntry() );
1464 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1465 QString aModuleName( aIObj->getComponentDataType() );
1466 QString aModuleTitle = moduleTitle( aModuleName );
1467 CAM_Module* currentModule = activeModule();
1468 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1469 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1474 mgr->setSelectionCacheEnabled( cacheIsOn );
1477 /*!Update obect browser:
1478 1.if 'updateModels' true, update existing data models;
1479 2. update "non-existing" (not loaded yet) data models;
1480 3. update object browser if it exists */
1481 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1483 // update "non-existing" (not loaded yet) data models
1484 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1487 _PTR(Study) stdDS = study->studyDS();
1490 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1492 _PTR(SComponent) aComponent ( it->Value() );
1494 #ifndef WITH_SALOMEDS_OBSERVER
1495 // with GUI observers this check is not needed anymore
1496 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1497 continue; // skip the magic "Interface Applicative" component
1499 if ( !objectBrowser() )
1500 getWindow( WT_ObjectBrowser );
1501 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1502 objectBrowser()->setAutoUpdate( false );
1503 SalomeApp_DataModel::synchronize( aComponent, study );
1504 objectBrowser()->setAutoUpdate( isAutoUpdate );
1509 // create data objects that correspond to GUI state save points
1510 if ( study ) updateSavePointDataObjects( study );
1512 // update existing data models (already loaded SComponents)
1513 LightApp_Application::updateObjectBrowser( updateModels );
1516 /*!Display Catalog Genenerator dialog */
1517 void SalomeApp_Application::onCatalogGen()
1519 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1523 /*!Display Registry Display dialog */
1524 void SalomeApp_Application::onRegDisplay()
1526 CORBA::ORB_var anOrb = orb();
1527 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1530 regWnd->activateWindow();
1533 /*!find original object by double click on item */
1534 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1536 // Issue 21379: References are supported at LightApp_DataObject level
1537 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1539 if( obj && obj->isReference() )
1541 QString entry = obj->refEntry();
1543 SUIT_DataOwnerPtrList aList;
1544 aList.append( new LightApp_DataOwner( entry ) );
1545 selectionMgr()->setSelected( aList, false );
1547 SUIT_DataBrowser* ob = objectBrowser();
1549 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1550 if ( !aSelectedIndexes.isEmpty() )
1551 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1556 Creates new view manager
1557 \param type - type of view manager
1559 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1561 return createViewManager(type);
1565 /*!Global utility function, returns selected GUI Save point object's ID */
1566 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1568 SALOME_ListIO aList;
1569 selMgr->selectedObjects( aList );
1570 if( aList.Extent() > 0 ) {
1571 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1572 QString entry( aIObj->getEntry() );
1573 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1574 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1576 bool ok; // conversion to integer is ok?
1577 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1578 return ok ? savePoint : -1;
1583 /*!Called on Restore GUI State popup command*/
1584 void SalomeApp_Application::onRestoreGUIState()
1586 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1587 if ( savePoint == -1 )
1589 SalomeApp_VisualState( this ).restoreState( savePoint );
1592 /*!Called on Delete GUI State popup command*/
1593 void SalomeApp_Application::onDeleteGUIState()
1595 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1596 if ( savePoint == -1 )
1598 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1602 study->removeSavePoint( savePoint );
1603 updateSavePointDataObjects( study );
1606 /*!Called on New study operation*/
1607 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1609 LightApp_Application::onStudyCreated( study );
1611 //#ifndef DISABLE_PYCONSOLE
1612 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1613 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1616 loadDockWindowsState();
1618 objectBrowserColumnsVisibility();
1621 /*!Called on Open study operation*/
1622 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1624 LightApp_Application::onStudyOpened( study );
1626 //#ifndef DISABLE_PYCONSOLE
1627 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1628 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1631 loadDockWindowsState();
1633 objectBrowserColumnsVisibility();
1635 // temporary commented
1636 /*if ( objectBrowser() ) {
1637 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1638 objectBrowser()->updateTree( study->root() );
1642 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1643 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1646 SUIT_DataBrowser* ob = objectBrowser();
1647 LightApp_SelectionMgr* selMgr = selectionMgr();
1649 if ( !study || !ob || !selMgr )
1652 // find GUI states root object
1653 SUIT_DataObject* guiRootObj = 0;
1655 study->root()->children( ch );
1656 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1657 for ( ; it != last ; ++it ) {
1658 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1663 std::vector<int> savePoints = study->getSavePoints();
1664 // case 1: no more save points but they existed in study's tree
1665 if ( savePoints.empty() && guiRootObj ) {
1666 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1667 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1668 const bool isAutoUpdate = ob->autoUpdate();
1669 selMgr->clearSelected();
1670 ob->setAutoUpdate(true);
1671 DataObjectList ch = guiRootObj->children();
1672 for( int i = 0; i < ch.size(); i++ )
1675 ob->setAutoUpdate(isAutoUpdate);
1678 // case 2: no more save points but root does not exist either
1679 if ( savePoints.empty() && !guiRootObj )
1681 // case 3: save points but no root for them - create it
1682 if ( !savePoints.empty() && !guiRootObj )
1683 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1684 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1685 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1687 if ( guiRootObj->nextBrother() ) {
1688 study->root()->removeChild(guiRootObj);
1689 study->root()->appendChild(guiRootObj);
1690 //study->root()->dump();
1693 // store data objects in a map id-to-DataObject
1694 QMap<int,SalomeApp_SavePointObject*> mapDO;
1696 guiRootObj->children( ch );
1697 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1698 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1700 mapDO[dobj->getId()] = dobj;
1703 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1704 // if in the map - remove it from map.
1705 for ( int i = 0; i < savePoints.size(); i++ )
1706 if ( !mapDO.contains( savePoints[i] ) )
1707 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1709 mapDO.remove( savePoints[i] );
1711 // delete DataObjects that are still in the map -- their IDs were not found in data model
1712 if( mapDO.size() > 0) {
1713 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1714 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1715 selMgr->clearSelected();
1716 const bool isAutoUpdate = ob->autoUpdate();
1717 ob->setAutoUpdate(true);
1718 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1720 ob->setAutoUpdate(isAutoUpdate);
1724 /*! Check data object */
1725 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1734 Opens other study into active Study. If Study is empty - creates it.
1735 \param theName - name of study
1737 bool SalomeApp_Application::useStudy( const QString& theName )
1740 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1743 res = aStudy->loadDocument( theName );
1744 updateDesktopTitle();
1745 updateCommandsStatus();
1749 /*! Show/hide object browser colums according to preferences */
1750 void SalomeApp_Application::objectBrowserColumnsVisibility()
1752 if ( objectBrowser() )
1753 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1755 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1756 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1760 #ifndef DISABLE_PYCONSOLE
1761 /*! Set SalomeApp_NoteBook pointer */
1762 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1764 myNoteBook = theNoteBook;
1767 /*! Return SalomeApp_NoteBook pointer */
1768 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1775 * Define extra actions defined in module definition XML file.
1776 * Additional popup items sections can be defined by parameter "popupitems".
1777 * Supported attributes:
1778 * title - title of menu item,
1779 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1780 * method - method which has to be called when menu item is selected
1782 * <section name="MODULENAME">
1783 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1785 * <section name="importmed">
1786 * <parameter name="title" value="My menu"/>
1787 * <parameter name="objectid" value="VISU.Result"/>
1788 * <parameter name="method" value="nameOfModuleMethod"/>
1791 void SalomeApp_Application::createExtraActions()
1793 myExtActions.clear();
1794 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1796 QStringList aModules;
1797 modules(aModules, false);
1798 foreach(QString aModile, aModules) {
1799 QString aModName = moduleName(aModile);
1800 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1801 if (!aSectionStr.isNull()) {
1802 QStringList aSections = aSectionStr.split(':');
1803 foreach(QString aSection, aSections) {
1804 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1805 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1806 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1807 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1810 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1811 if (aModuleName.isNull())
1812 aModuleName = aModName;
1814 QAction* aAction = new QAction(aTitle, this);
1816 aData<<aModuleName<<aSlot;
1817 aAction->setData(aData);
1818 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1819 myExtActions[aId] = aAction;
1826 * Called when extra action is selected
1828 void SalomeApp_Application::onExtAction()
1830 QAction* aAction = ::qobject_cast<QAction*>(sender());
1834 QVariant aData = aAction->data();
1835 QStringList aDataList = aData.value<QStringList>();
1836 if (aDataList.size() != 2)
1839 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1840 SALOME_ListIO aListIO;
1841 aSelectionMgr->selectedObjects(aListIO);
1842 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1843 if (aListIO.Extent() < 1)
1845 if (!anIO->hasEntry())
1848 QString aEntry(anIO->getEntry());
1850 QApplication::setOverrideCursor( Qt::WaitCursor );
1851 QString aModuleTitle = moduleTitle(aDataList[0]);
1852 activateModule(aModuleTitle);
1853 QApplication::restoreOverrideCursor();
1855 QCoreApplication::processEvents();
1857 CAM_Module* aModule = activeModule();
1861 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1862 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1866 Checks that an object can be renamed.
1867 \param entry entry of the object
1868 \brief Return \c true if object can be renamed
1870 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1872 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1876 Rename object by entry.
1877 \param entry entry of the object
1878 \param name new name of the object
1879 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1881 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1883 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1885 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1887 if(!aStudy || savePoint == -1)
1890 if ( !name.isNull() && !name.isEmpty() ) {
1891 aStudy->setNameOfSavePoint( savePoint, name );
1892 updateSavePointDataObjects( aStudy );
1894 //Mark study as modified
1901 #ifndef DISABLE_PYCONSOLE
1902 //============================================================================
1903 /*! Function : onUpdateStudy
1904 * Purpose : Slot to update the study.
1906 //============================================================================
1907 void SalomeApp_Application::onUpdateStudy()
1909 QApplication::setOverrideCursor( Qt::WaitCursor );
1911 if( !updateStudy() )
1912 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1914 QApplication::restoreOverrideCursor();
1917 //============================================================================
1918 /*! Function : updateStudy
1919 * Purpose : Update study by dumping the study to Python script and loading it.
1920 * It is used to apply variable modifications done in NoteBook to created objects.
1922 //============================================================================
1923 bool SalomeApp_Application::updateStudy()
1925 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1926 if ( !study || !myNoteBook )
1929 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1930 myNoteBook->setDumpedStudyName( study->studyName() );
1932 _PTR(Study) studyDS = study->studyDS();
1934 // get unique temporary directory name
1935 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1936 if( aTmpDir.isEmpty() )
1939 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1940 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1942 // dump study to the temporary directory
1943 QString aScriptName( "notebook" );
1944 bool toPublish = true;
1945 bool isMultiFile = false;
1946 bool toSaveGUI = true;
1949 _PTR(AttributeParameter) ap;
1950 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1951 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1952 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1953 ip->setDumpPython(studyDS);
1954 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1956 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1958 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1961 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1965 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1966 int anIndex = aList.indexOf( this );
1968 // Disconnect dialog from application desktop in case if:
1969 // 1) Application is not the first application in the session
1970 // 2) Application is the first application in session but not the only.
1971 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1972 if( changeDesktop ) {
1974 SalomeApp_Application* app = this;
1975 if( anIndex > 0 && anIndex < aList.count() )
1976 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1977 else if(anIndex == 0 && aList.count() > 1)
1978 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1983 // creation a new study and restoring will be done in another application
1984 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1985 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1988 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1989 QString aStudyName = myNoteBook->getDumpedStudyName();
1990 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1991 // clear a study (delete all objects)
1992 onCloseDoc( false );
1994 if( !changeDesktop ) {
1995 ok = onRestoreStudy( aDumpScript,
2004 //============================================================================
2005 /*! Function : onRestoreStudy
2006 * Purpose : Load the dumped study from Python script
2008 //============================================================================
2009 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2010 const QString& theStudyName,
2011 bool theIsStudySaved )
2015 // create a new study
2018 // get active application
2019 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2021 // load study from the temporary directory
2022 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2024 #ifndef DISABLE_PYCONSOLE
2025 PyConsole_Console* pyConsole = app->pythonConsole();
2027 pyConsole->execAndWait( command );
2030 // remove temporary directory
2031 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2032 QString aStudyName = aScriptInfo.baseName();
2033 QDir aDir = aScriptInfo.absoluteDir();
2034 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2035 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2036 ok = aDir.remove( *it ) && ok;
2038 ok = aDir.rmdir( aDir.absolutePath() );
2040 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2042 #ifndef DISABLE_PYCONSOLE
2043 _PTR(Study) aStudyDS = newStudy->studyDS();
2044 app->getNoteBook()->Init( aStudyDS );
2045 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2046 newStudy->Modified();
2047 updateDesktopTitle();
2058 Close the Application
2060 void SalomeApp_Application::afterCloseDoc()
2062 #ifndef DISABLE_PYCONSOLE
2063 // emit signal to restore study from Python script
2065 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2066 myNoteBook->getDumpedStudyName(),
2067 myNoteBook->isDumpedStudySaved() );
2070 LightApp_Application::afterCloseDoc();
2074 Asks to close existing document.
2076 bool SalomeApp_Application::checkExistingDoc()
2078 bool result = LightApp_Application::checkExistingDoc();
2079 if ( result && !activeStudy() ) {
2080 SALOMEDSClient_StudyManager* aMgr = studyMgr();
2082 std::vector<std::string> List = studyMgr()->GetOpenStudies();
2083 if( List.size() > 0 ) {
2084 SUIT_MessageBox::critical( desktop(), tr( "WRN_WARNING" ), tr( "ERR_ACTIVEDOC_LOAD" ));
2093 #ifndef DISABLE_PYCONSOLE
2095 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2097 return new SalomeApp_PyInterp();
2100 #endif // DISABLE_PYCONSOLE