1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: SalomeApp_Application.cxx
24 // Created: 10/22/2004 3:23:45 PM
25 // Author: Sergey LITONIN
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #ifndef DISABLE_PYCONSOLE
37 #ifndef DISABLE_PYCONSOLE
38 #include "SalomeApp_PyInterp.h"
39 #include "SalomeApp_NoteBook.h"
40 #include "LightApp_PyEditor.h"
41 #include "PyConsole_Console.h"
43 #include "SalomeApp_Application.h"
44 #include "SalomeApp_Study.h"
45 #include "SalomeApp_DataModel.h"
46 #include "SalomeApp_DataObject.h"
47 #include "SalomeApp_VisualState.h"
48 #include "SalomeApp_StudyPropertiesDlg.h"
49 #include "SalomeApp_LoadStudiesDlg.h"
50 #include "SalomeApp_ExitDlg.h"
52 #include <LightApp_Application.h>
53 #include <LightApp_FileValidator.h>
54 #include <LightApp_Module.h>
55 #include <LightApp_Preferences.h>
56 #include <LightApp_SelectionMgr.h>
57 #include <LightApp_NameDlg.h>
58 #include <LightApp_DataOwner.h>
60 #include <CAM_Module.h>
62 #include <SUIT_Tools.h>
63 #include <SUIT_Session.h>
64 #include <SUIT_Desktop.h>
65 #include <SUIT_DataBrowser.h>
66 #include <SUIT_FileDlg.h>
67 #include <SUIT_MessageBox.h>
68 #include <SUIT_ResourceMgr.h>
69 #include <SUIT_TreeModel.h>
70 #include <SUIT_ViewWindow.h>
71 #include <SUIT_ViewManager.h>
72 #include <SUIT_ViewModel.h>
73 #include <SUIT_OverrideCursor.h>
75 #include <QtxTreeView.h>
77 #include <SALOME_EventFilter.h>
79 // temporary commented
80 //#include <OB_ListItem.h>
83 #include <SALOME_LifeCycleCORBA.hxx>
85 #include <QApplication>
90 #include <QPushButton>
92 #include <QListWidget>
93 #include <QGridLayout>
97 #include <SALOMEDSClient_ClientFactory.hxx>
98 #include <ArgvKeeper.hxx>
99 #include <Basics_Utils.hxx>
100 #include <OpUtil.hxx>
102 #include <SALOME_ListIO.hxx>
103 #include <SALOME_Prs.h>
106 #include <ToolsGUI_CatalogGeneratorDlg.h>
107 #include <ToolsGUI_RegWidget.h>
111 #include <SALOMEDS_Tool.hxx>
113 std::unique_ptr<SALOME_NamingService_Abstract> SalomeApp_Application::_ns;
115 /*!Internal class that updates object browser item properties */
116 // temporary commented
117 /*class SalomeApp_Updater : public OB_Updater
120 SalomeApp_Updater() : OB_Updater(){};
121 virtual ~SalomeApp_Updater(){};
122 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
125 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
127 if( !theObj || !theItem )
130 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
134 _PTR(SObject) SObj = SAObj->object();
137 _PTR( GenericAttribute ) anAttr;
140 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
142 _PTR(AttributeSelectable) aAttrSel = anAttr;
143 theItem->setSelectable( aAttrSel->IsSelectable() );
146 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
148 _PTR(AttributeExpandable) aAttrExpand = anAttr;
149 theItem->setExpandable( aAttrExpand->IsExpandable() );
152 //this attribute is not supported in the version of SALOME 3.x
153 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
155 // _PTR(AttributeOpened) aAttrOpen = anAttr;
156 // theItem->setOpen( aAttrOpen->IsOpened() );
168 //! Constructor. Sets passed boolean flag to \c true.
169 MessageLocker( bool& Lock ) : myPrevState( Lock ), myLock( Lock ) { myLock = true; }
170 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
171 ~MessageLocker() { myLock = myPrevState; }
174 bool& myLock; //! External 'Lock state' boolean flag
178 \brief Dynamic property manager
185 PropertyMgr(QObject* object, const QString& property, const QVariant& value)
186 : myObject(object), myProperty(property)
188 myObject->setProperty(qPrintable(myProperty), value);
192 myObject->setProperty(qPrintable(myProperty), QVariant());
198 SalomeApp_Application::SalomeApp_Application(SALOME_NamingService_Abstract *ns):myIsCloseFromExit( false ),myToIgnoreMessages( false )
201 _ns.reset(new SALOME_NamingService(orb()));
207 *\li Destroy event filter.
209 SalomeApp_Application::~SalomeApp_Application()
211 // Do not destroy. It's a singleton !
212 //SALOME_EventFilter::Destroy();
215 QStringList __getArgsList(QString argsString)
217 // Special process if some items of 'args:' list are themselves lists
218 // Note that an item can be a list, but not a list of lists...
219 // So we can have something like this:
220 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
221 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
222 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
223 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
224 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
226 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
231 return argsString.split(",", QString::SkipEmptyParts);
234 /*!Start application.*/
235 void SalomeApp_Application::start()
237 // process the command line options before start: to createActions in accordance to the options
238 static bool isFirst = true;
245 QStringList args = QApplication::arguments();
246 for (int i = 1; i < args.count(); i++) {
247 QRegExp rxs ("--study-hdf=(.+)");
248 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
249 QString file = rxs.capturedTexts()[1];
250 QFileInfo fi ( file );
251 QString extension = fi.suffix().toLower();
252 if ( extension == "hdf" && fi.exists() )
253 hdffile = fi.absoluteFilePath();
256 QRegExp rxp ("--pyscript=\\[(.+)\\]");
257 if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
259 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
260 for (int k = 0; k < dictList.count(); ++k) {
261 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
262 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
263 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
264 pyfiles += rxd.capturedTexts()[m];
271 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
272 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
274 LightApp_Application::start();
275 SALOME_EventFilter::Init();
277 if ( !hdffile.isEmpty() )
279 // open hdf file given as parameter
280 PropertyMgr propm( this, "open_study_from_command_line", true );
281 onOpenDoc( hdffile );
284 #ifndef DISABLE_PYCONSOLE
285 // import/execute python scripts
286 if ( pyfiles.count() > 0 && activeStudy() ) {
287 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
288 PyConsole_Console* pyConsole = pythonConsole();
289 if ( appStudy && pyConsole ) {
290 if ( !getStudy()->GetProperties()->IsLocked() ) {
291 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
292 // Path is absolute, script has .py extension
293 for (int j = 0; j < pyfiles.count(); j++ ) {
294 // Extract scripts and their arguments, if any
295 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
296 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
297 QString script = rxp.capturedTexts()[1];
299 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
300 for (int k = 0; k < argList.count(); k++ ) {
301 QString arg = argList[k].trimmed();
302 arg.remove( QRegExp("^[\"]") );
303 arg.remove( QRegExp("[\"]$") );
304 args << QString("\"%1\"").arg(arg);
306 if (args.count() == 1)
309 script.remove( QRegExp("^python.*[\\s]+") );
310 QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(","));
311 PropertyMgr propm( this, "IsLoadedScript", true );
312 pyConsole->exec(command);
314 } // end for loop on pyfiles QStringList
320 LightApp_Application::start();
321 SALOME_EventFilter::Init();
326 void SalomeApp_Application::createActions()
328 LightApp_Application::createActions();
330 SUIT_Desktop* desk = desktop();
333 // "Save GUI State" command is moved to VISU module
334 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
335 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
336 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
339 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
340 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
341 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
344 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
345 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
346 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
349 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
350 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
351 0, desk, false, this, SLOT( onProperties() ) );
353 //! Catalog Generator
354 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
355 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
356 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
359 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
360 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
361 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
363 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
364 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
365 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
366 //no need at this action for mono-study application because study is always exists
367 action( ConnectId )->setVisible( false );
369 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
370 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
371 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
372 //no need at this action for mono-study application because study is always exists
373 action( DisconnectId )->setVisible( false );
376 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
378 // "Save GUI State" command is renamed to "Save VISU State" and
379 // creation of menu item is moved to VISU
380 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
382 createMenu( ConnectId, fileMenu, 5 );
383 createMenu( DisconnectId, fileMenu, 5 );
384 createMenu( separator(), fileMenu, -1, 5 );
386 createMenu( DumpStudyId, fileMenu, 10, -1 );
387 createMenu( LoadScriptId, fileMenu, 10, -1 );
388 createMenu( separator(), fileMenu, -1, 10, -1 );
389 createMenu( PropertiesId, fileMenu, 10, -1 );
390 createMenu( separator(), fileMenu, -1, 10, -1 );
392 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
393 createMenu( CatalogGenId, toolsMenu, 10, -1 );
394 createMenu( RegDisplayId, toolsMenu, 10, -1 );
395 createMenu( separator(), toolsMenu, -1, 15, -1 );
397 createExtraActions();
399 #ifndef DISABLE_PYCONSOLE
400 #ifndef DISABLE_SALOMEOBJECT
401 // import Python module that manages SALOME plugins
403 PyLockWrapper lck; // acquire GIL
404 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
405 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
409 // end of SALOME plugins loading
416 \brief Close application.
418 void SalomeApp_Application::onExit()
420 //MessageLocker ml( myToIgnoreMessages );
422 bool killServers = false;
425 if ( exitConfirmation() ) {
426 SalomeApp_ExitDlg dlg( desktop() );
427 result = dlg.exec() == QDialog::Accepted;
428 killServers = dlg.isServersShutdown();
432 if ( !killServers ) myIsCloseFromExit = true;
433 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
434 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
438 /*!SLOT. Create a document.*/
439 void SalomeApp_Application::onNewDoc()
441 MessageLocker ml( myToIgnoreMessages );
443 LightApp_Application::onNewDoc();
446 /*!SLOT. Load document.*/
447 void SalomeApp_Application::onLoadDoc()
449 MessageLocker ml( myToIgnoreMessages );
453 // rnv: According to the single-study approach on the server side
454 // can be only one study. So if it is exists connect to them,
455 // overwise show warning message: "No active study on the server"
458 SUIT_Session* aSession = SUIT_Session::session();
459 QList<SUIT_Application*> aAppList = aSession->applications();
461 QStringList unloadedStudies;
463 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
464 studyName = List[ind].c_str();
465 // Add to list only unloaded studies
466 bool isAlreadyOpen = false;
467 QListIterator<SUIT_Application*> it( aAppList );
468 while ( it.hasNext() && !isAlreadyOpen ) {
469 SUIT_Application* aApp = it.next();
470 if( !aApp || !aApp->activeStudy() )
472 if ( aApp->activeStudy()->studyName() == studyName )
473 isAlreadyOpen = true;
476 if ( !isAlreadyOpen )
477 unloadedStudies << studyName;
479 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
480 if ( studyName.isEmpty() )
485 SUIT_MessageBox::warning( desktop(),
486 QObject::tr("WRN_WARNING"),
487 QObject::tr("WRN_NO_STUDY_ON SERV") );
491 studyName = activeStudy()->studyName();
494 // this code replaces marker of windows drive and path become invalid therefore
495 // defines placed there
496 studyName.replace( QRegExp(":"), "/" );
499 if ( onLoadDoc( studyName ) ) {
501 updateViewManagers();
502 updateObjectBrowser( true );
506 /*!SLOT. Unload document.*/
507 void SalomeApp_Application::onUnloadDoc( bool ask )
510 activeStudy()->abortAllOperations();
511 if ( activeStudy()->isModified() ) {
512 QString docName = activeStudy()->studyName().trimmed();
513 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
514 tr( "DISCONNECT_DESCRIPTION" ),
515 tr( "DISCONNECT_SAVE" ),
516 tr( "DISCONNECT_WO_SAVE" ),
517 tr( "APPCLOSE_CANCEL" ), 0 );
518 if ( answer == 0 ) { // save before unload
519 if ( activeStudy()->isSaved() )
521 else if ( !onSaveAsDoc() )
524 else if ( answer == 2 ) // Cancel
528 closeActiveDoc( false );
531 /*!SLOT. Create new study and load script*/
532 void SalomeApp_Application::onNewWithScript()
534 QStringList filtersList;
535 filtersList.append(tr("PYTHON_FILES_FILTER"));
536 filtersList.append(tr("ALL_FILES_FILTER"));
538 QString anInitialPath = "";
539 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
540 anInitialPath = QDir::currentPath();
542 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
544 if ( !aFile.isEmpty() )
548 #ifndef DISABLE_PYCONSOLE
549 QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile);
550 PyConsole_Console* pyConsole = pythonConsole();
551 PropertyMgr propm( this, "IsLoadedScript", true );
553 pyConsole->exec( command );
559 /*!SLOT. Load document with \a aName.*/
560 bool SalomeApp_Application::onLoadDoc( const QString& aName )
562 if ( !LightApp_Application::closeDoc() )
566 if ( !activeStudy() ) {
567 // if no study - load in current desktop
568 res = useStudy( aName );
571 // if study exists - load in new desktop. Check: is the same file is loaded?
572 SUIT_Session* aSession = SUIT_Session::session();
573 QList<SUIT_Application*> aAppList = aSession->applications();
574 bool isAlreadyOpen = false;
575 SalomeApp_Application* aApp = 0;
576 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
577 it != aAppList.end() && !isAlreadyOpen; ++it ) {
578 aApp = dynamic_cast<SalomeApp_Application*>( *it );
579 if ( aApp && aApp->activeStudy()->studyName() == aName )
580 isAlreadyOpen = true;
582 if ( !isAlreadyOpen ) {
583 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
585 res = aApp->useStudy( aName );
588 aApp->desktop()->activateWindow();
595 /*!SLOT. Parse message for desktop.*/
596 void SalomeApp_Application::onDesktopMessage( const QString& message )
598 if ( myToIgnoreMessages )
599 return; // a message from SALOMEDS is caused by GUI action
601 MessageLocker ml( myToIgnoreMessages );
603 if (message.indexOf("studyCreated") == 0) {
604 if (!activeStudy()) {
606 updateCommandsStatus();
609 if (message.indexOf("studyCleared") == 0) {
610 // Disconnect GUI from active study, because it was closed on DS side.
612 closeActiveDoc( false );
613 // Disable 'Connect' action
614 QAction* a = action( ConnectId );
616 a->setEnabled( false );
619 else if ( message.toLower() == "connect_to_study" ) {
621 useStudy( activeStudy()->studyName() );
623 if (message.indexOf("studyNameChanged") == 0) {
624 updateDesktopTitle();
626 LightApp_Application::onDesktopMessage( message );
629 /*!On module activation action.*/
630 void SalomeApp_Application::onModuleActivation( const QString& modName )
632 if (!activeStudy() && !modName.isEmpty())
635 LightApp_Application::onModuleActivation( modName );
638 /*!SLOT. Copy objects to study maneger from selection maneger..*/
639 void SalomeApp_Application::onCopy()
641 LightApp_Application::onCopy();
644 LightApp_SelectionMgr* mgr = selectionMgr();
645 mgr->selectedObjects(list);
647 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
648 if(study == NULL) return;
650 _PTR(Study) stdDS = getStudy();
653 SALOME_ListIteratorOfListIO it( list );
656 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
661 onSelectionChanged();
669 /*!SLOT. Paste objects to study maneger from selection manager.*/
670 void SalomeApp_Application::onPaste()
672 LightApp_Application::onPaste();
675 LightApp_SelectionMgr* mgr = selectionMgr();
676 mgr->selectedObjects(list);
678 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
679 if(study == NULL) return;
681 _PTR(Study) stdDS = getStudy();
684 if ( stdDS->GetProperties()->IsLocked() ) {
685 SUIT_MessageBox::warning( desktop(),
686 QObject::tr("WRN_WARNING"),
687 QObject::tr("WRN_STUDY_LOCKED") );
691 SALOME_ListIteratorOfListIO it( list );
694 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
699 updateObjectBrowser( true );
700 updateActions(); //SRN: BugID IPAL9377, case 3
708 /*!Check the application on closing.
709 * \retval true if possible, else false
711 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
713 return LightApp_Application::isPossibleToClose( closePermanently );
716 /*! Check if the study is locked */
717 void SalomeApp_Application::onCloseDoc( bool ask )
719 if(getStudy()->IsStudyLocked()) {
720 if ( SUIT_MessageBox::question( desktop(),
721 QObject::tr( "WRN_WARNING" ),
722 QObject::tr( "CLOSE_LOCKED_STUDY" ),
723 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
724 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
727 MessageLocker ml( myToIgnoreMessages );
729 LightApp_Application::onCloseDoc( ask );
731 // reinitialize study to have empty data
732 //getStudy()->Init();
735 /*!SLOT. Reload document from the file.*/
736 bool SalomeApp_Application::onReopenDoc()
738 MessageLocker ml( myToIgnoreMessages );
740 return LightApp_Application::onReopenDoc();
744 /*!SLOT. Load document.*/
745 void SalomeApp_Application::onOpenDoc()
747 MessageLocker ml( myToIgnoreMessages );
749 LightApp_Application::onOpenDoc();
752 /*!SLOT. Load document.*/
753 bool SalomeApp_Application::onOpenDoc(const QString& name)
755 MessageLocker ml( myToIgnoreMessages );
757 return LightApp_Application::onOpenDoc(name);
760 /*!Sets enable or disable some actions on selection changed.*/
761 void SalomeApp_Application::onSelectionChanged()
764 LightApp_SelectionMgr* mgr = selectionMgr();
765 mgr->selectedObjects(list);
767 bool canCopy = false;
768 bool canPaste = false;
770 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
773 canCopy = m->canCopy();
774 canPaste = m->canPaste();
777 SALOME_ListIteratorOfListIO it ( list );
779 if (it.More() && list.Extent() == 1) {
780 _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry());
783 canCopy = canCopy || getStudy()->CanCopy(so);
784 canPaste = canPaste || getStudy()->CanPaste(so);
788 action(EditCopyId)->setEnabled(canCopy);
789 action(EditPasteId)->setEnabled(canPaste);
792 /*!Delete references.*/
793 void SalomeApp_Application::onDeleteInvalidReferences()
796 LightApp_SelectionMgr* mgr = selectionMgr();
797 mgr->selectedObjects( aList, QString(), false );
799 if( aList.IsEmpty() )
802 _PTR(Study) aStudyDS = getStudy();
803 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
806 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
807 if ( it.Value()->hasEntry() )
809 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
810 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
813 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
814 aStudyBuilder->RemoveReference( aSObject );
816 updateObjectBrowser();
820 void SalomeApp_Application::onOpenWith()
822 QApplication::setOverrideCursor( Qt::WaitCursor );
824 LightApp_SelectionMgr* mgr = selectionMgr();
825 mgr->selectedObjects(aList);
826 if (aList.Extent() != 1)
828 QApplication::restoreOverrideCursor();
831 Handle(SALOME_InteractiveObject) aIObj = aList.First();
832 QString aModuleName(aIObj->getComponentDataType());
833 QString aModuleTitle = moduleTitle(aModuleName);
834 if (aModuleTitle.isEmpty()) // no gui
835 aModuleTitle = moduleDisplayer(aModuleName);
836 activateModule(aModuleTitle);
837 QApplication::restoreOverrideCursor();
843 SUIT_Study* SalomeApp_Application::createNewStudy()
845 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
847 // Set up processing of major study-related events
848 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
849 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
850 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
851 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
853 #ifndef DISABLE_PYCONSOLE
854 //to receive signal in application that NoteBook's variable was modified
855 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
856 this, SIGNAL(notebookVarUpdated(QString)) );
865 Enable/Disable menu items and toolbar buttons. Rebuild menu
867 void SalomeApp_Application::updateCommandsStatus()
869 LightApp_Application::updateCommandsStatus();
872 QAction* a = action( DumpStudyId );
874 a->setEnabled( activeStudy() );
876 #ifndef DISABLE_PYCONSOLE
878 a = action( LoadScriptId );
880 a->setEnabled( pythonConsole() );
884 a = action( PropertiesId );
886 a->setEnabled( activeStudy() );
888 // Save GUI state menu
889 a = action( SaveGUIStateId );
891 a->setEnabled( activeStudy() );
893 // Connect study menu
894 a = action( ConnectId );
896 a->setEnabled( !activeStudy() );
898 // Disconnect study menu
899 a = action( DisconnectId );
901 a->setEnabled( activeStudy() );
903 // update state of Copy/Paste menu items
904 onSelectionChanged();
908 \class DumpStudyFileDlg
909 Private class used in Dump Study operation. Consists 2 check boxes:
910 "Publish in study" and "Save GUI parameters"
912 class DumpStudyFileDlg : public SUIT_FileDlg
915 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
917 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
920 QWidget *hB = new QWidget( this );
921 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
922 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
923 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
925 QHBoxLayout *layout = new QHBoxLayout;
926 layout->addWidget(myPublishChk);
927 layout->addWidget(myMultiFileChk);
928 layout->addWidget(mySaveGUIChk);
929 hB->setLayout(layout);
931 QPushButton* pb = new QPushButton(this);
933 int row = grid->rowCount();
934 grid->addWidget( new QLabel("", this), row, 0 );
935 grid->addWidget( hB, row, 1, 1, 3 );
936 grid->addWidget( pb, row, 5 );
941 QCheckBox* myPublishChk;
942 QCheckBox* myMultiFileChk;
943 QCheckBox* mySaveGUIChk;
946 /*!Private SLOT. On dump study.*/
947 void SalomeApp_Application::onDumpStudy( )
949 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
950 if ( !appStudy ) return;
952 QStringList aFilters;
953 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
955 bool anIsPublish = true;
956 bool anIsMultiFile = false;
957 bool anIsSaveGUI = true;
959 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
960 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
961 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
962 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
965 DumpStudyFileDlg fd( desktop() );
966 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
967 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
968 fd.setNameFilters( aFilters );
969 fd.myPublishChk->setChecked( anIsPublish );
970 fd.myMultiFileChk->setChecked( anIsMultiFile );
971 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
972 if ( fd.exec() == QDialog::Accepted )
974 QString aFileName = fd.selectedFile();
976 bool toPublish = fd.myPublishChk->isChecked();
977 bool isMultiFile = fd.myMultiFileChk->isChecked();
978 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
980 if ( !aFileName.isEmpty() ) {
981 QFileInfo aFileInfo(aFileName);
982 if( aFileInfo.isDir() ) // IPAL19257
985 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
988 SUIT_OverrideCursor wc;
989 ensureShaperIsActivated();
990 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
993 SUIT_MessageBox::warning( desktop(),
994 QObject::tr("WRN_WARNING"),
995 tr("WRN_DUMP_STUDY_FAILED") );
1000 /*!Private SLOT. On load script.*/
1001 void SalomeApp_Application::onLoadScript( )
1003 if ( getStudy()->GetProperties()->IsLocked() ) {
1004 SUIT_MessageBox::warning( desktop(),
1005 QObject::tr("WRN_WARNING"),
1006 QObject::tr("WRN_STUDY_LOCKED") );
1010 QStringList filtersList;
1011 filtersList.append(tr("PYTHON_FILES_FILTER"));
1012 filtersList.append(tr("ALL_FILES_FILTER"));
1014 QString anInitialPath = "";
1015 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
1016 anInitialPath = QDir::currentPath();
1018 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
1020 if ( !aFile.isEmpty() )
1022 #ifndef DISABLE_PYCONSOLE
1023 QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile);
1024 PyConsole_Console* pyConsole = pythonConsole();
1025 PropertyMgr propm( this, "IsLoadedScript", true );
1027 pyConsole->exec(command);
1032 /*!Private SLOT. On save GUI state.*/
1033 void SalomeApp_Application::onSaveGUIState()
1035 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1037 SalomeApp_VisualState( this ).storeState();
1038 updateSavePointDataObjects( study );
1039 updateObjectBrowser();
1044 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1045 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1047 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1048 QAction* send = ::qobject_cast<QAction*>( sender() );
1051 QString aWinName = send->data().toString();
1052 if ( theIsVisible && aWinName == "objectBrowser" )
1053 objectBrowserColumnsVisibility();
1057 QWidget* SalomeApp_Application::createWindow( const int flag )
1060 #ifndef DISABLE_PYCONSOLE
1061 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1063 wid = LightApp_Application::createWindow(flag);
1066 SUIT_ResourceMgr* resMgr = resourceMgr();
1068 if ( flag == WT_ObjectBrowser )
1070 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1072 // temporary commented
1073 //ob->setUpdater( new SalomeApp_Updater() );
1075 #ifdef WITH_SALOMEDS_OBSERVER
1076 //do not activate the automatic update of Qt tree through signal/slot
1077 ob->setAutoUpdate(false);
1078 //activate update of modified objects only
1079 ob->setUpdateModified(true);
1082 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1085 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1086 IORCol = QObject::tr( "IOR_COLUMN" ),
1087 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1088 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1090 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1091 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1092 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1093 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1094 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1095 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1096 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1097 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1098 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1100 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1101 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1102 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1104 ob->setAutoSizeFirstColumn(autoSizeFirst);
1105 ob->setAutoSizeColumns(autoSize);
1106 ob->setResizeOnExpandItem(resizeOnExpandItem);
1107 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1109 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1111 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1112 ob->treeView()->setColumnHidden( i, !shown );
1115 // temporary commented
1117 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1119 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1120 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1121 QString().sprintf( "visibility_column_%d", i ), true ) );
1125 // temporary commented
1127 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1128 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1129 ob->resize( desktop()->width()/3, ob->height() );
1133 #ifndef DISABLE_PYCONSOLE
1134 else if ( flag == WT_PyConsole )
1136 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1137 pyCons->setObjectName( "pythonConsole" );
1138 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1139 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1140 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1141 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1142 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1145 else if ( flag == WT_NoteBook )
1147 setNoteBook( new SalomeApp_NoteBook( desktop() ) );
1148 //to receive signal in NoteBook that it's variable was modified
1149 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1150 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1152 wid = getNoteBook();
1153 wid->setObjectName( "noteBook" );
1159 /*!Create preferences.*/
1160 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1162 LightApp_Application::createPreferences(pref);
1167 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1168 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1169 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1170 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1172 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1173 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1175 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1177 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1178 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1179 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1180 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1181 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1182 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1183 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1184 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1185 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1186 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1189 /*!Update desktop title.*/
1190 void SalomeApp_Application::updateDesktopTitle() {
1191 QString aTitle = applicationName();
1192 QString aVer = applicationVersion();
1193 if ( !aVer.isEmpty() )
1194 aTitle += QString( " " ) + aVer;
1196 if ( activeStudy() )
1198 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1199 if ( !sName.isEmpty() ) {
1200 if ( getStudy()->GetProperties()->IsLocked() ) {
1201 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1203 aTitle += QString( " - [%1]" ).arg( sName );
1208 desktop()->setWindowTitle( aTitle );
1211 int SalomeApp_Application::closeChoice( const QString& /*docName*/ )
1213 QStringList buttons;
1214 QMap<int, int> choices;
1216 buttons << tr ("APPCLOSE_SAVE"); // Save & Clear
1217 choices.insert( idx++, CloseSave ); // ...
1218 buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving
1219 choices.insert( idx++, CloseDiscard ); // ...
1220 if ( myIsCloseFromExit ) {
1221 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1222 choices.insert( idx++, CloseDisconnectSave ); // ...
1223 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1224 choices.insert( idx++, CloseDisconnect ); // ...
1226 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1227 choices.insert( idx++, CloseCancel ); // ...
1229 if( !activeStudy()->isModified() )
1231 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1232 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1233 return choices[answer];
1236 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1242 if ( activeStudy()->isSaved() )
1244 else if ( !onSaveAsDoc() )
1249 case CloseDisconnectSave:
1250 if ( activeStudy()->isSaved() )
1252 else if ( !onSaveAsDoc() )
1255 case CloseDisconnect:
1256 closeActiveDoc( false );
1257 closePermanently = false;
1266 int SalomeApp_Application::openChoice( const QString& aName )
1268 int choice = LightApp_Application::openChoice( aName );
1270 if ( QFileInfo( aName ).exists() ) {
1271 if ( choice == OpenNew ) { // The document isn't already open.
1273 if ( aName == getStudy()->Name().c_str() )
1275 // The document already exists in the study.
1276 // Do you want to reload it?
1278 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1279 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1280 if ( answer == SUIT_MessageBox::Yes )
1281 choice = OpenRefresh;
1283 choice = OpenCancel;
1286 } else { // file is not exist on disk
1287 SUIT_MessageBox::warning( desktop(),
1288 QObject::tr("WRN_WARNING"),
1289 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data()));
1296 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1299 int choice = aChoice;
1306 res = LightApp_Application::openAction( choice, aName );
1314 \brief Get map of the operations which can be performed
1315 on the module activation.
1317 The method should return the map of the kind \c {<id>:<name>}
1318 where \c <id> is an integer identifier of the operation and
1319 \c <name> is a title for the button to be added to the
1320 dialog box. After user selects the required operation by the
1321 clicking the corresponding button in the dialog box, its identifier
1322 is passed to the moduleActionSelected() method to process
1325 \return map of the operations
1326 \sa moduleActionSelected()
1328 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1330 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1332 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1334 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1339 \brief Called when the used selectes required operation chosen
1340 from "Activate module" dialog box.
1342 Performs the required operation according to the user choice.
1344 \param id operation identifier
1345 \sa activateModuleActions()
1347 void SalomeApp_Application::moduleActionSelected( const int id )
1353 case NewAndScriptId:
1357 LightApp_Application::moduleActionSelected( id );
1362 /*!Gets CORBA::ORB_var*/
1363 CORBA::ORB_var SalomeApp_Application::orb()
1365 static CORBA::ORB_var _orb;
1367 if ( CORBA::is_nil( _orb ) ) {
1368 Qtx::CmdLineArgs args;
1369 SetArgcArgv( args.argc(), args.argv() );
1370 _orb = KERNEL::GetRefToORB();
1376 /*!Create and return SALOMEDS_Study.*/
1377 _PTR(Study) SalomeApp_Application::getStudy()
1379 static _PTR(Study) _study;
1381 CORBA::Object_var aSObject = namingService()->Resolve("/Study");
1382 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject);
1383 _study = ClientFactory::Study(aStudy);
1388 /*!Create and return SALOME_NamingService.*/
1389 SALOME_NamingService_Abstract *SalomeApp_Application::namingService()
1394 /*!Create and return SALOME_LifeCycleCORBA.*/
1395 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1397 static SALOME_LifeCycleCORBA _lcc( namingService() );
1401 /*!Private SLOT. On preferences.*/
1402 void SalomeApp_Application::onProperties()
1404 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1408 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1411 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1412 int res = aDlg.exec();
1413 if( res==QDialog::Accepted && aDlg.isChanged() )
1414 SB->CommitCommand();
1418 //study->updateCaptions();
1419 updateDesktopTitle();
1423 /*!Insert items in popup, which necessary for current application*/
1424 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1426 LightApp_SelectionMgr* mgr = selectionMgr();
1427 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1428 mgr->setSelectionCacheEnabled( true );
1430 LightApp_Application::contextMenuPopup( type, thePopup, title );
1432 // temporary commented
1433 /*OB_Browser* ob = objectBrowser();
1434 if ( !ob || type != ob->popupClientType() )
1437 // Get selected objects
1438 SALOME_ListIO aList;
1439 mgr->selectedObjects( aList, QString(), false );
1441 // add GUI state commands: restore, rename
1442 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1443 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1444 thePopup->addSeparator();
1445 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1446 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1447 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1448 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1451 // "Delete reference" item should appear only for invalid references
1453 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1454 bool isInvalidRefs = false;
1456 _PTR(SObject) anObj;
1457 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1459 if( it.Value()->hasEntry() )
1461 _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1462 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1465 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1466 isInvalidRefs = true;
1470 // Add "Delete reference" item to popup
1471 if ( isInvalidRefs )
1473 thePopup->addSeparator();
1474 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1478 // "Activate module" item should appear only if it's necessary
1479 if ( aList.Extent() == 1 ) {
1481 mgr->selectedObjects( aList );
1483 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1485 // add extra popup menu (defined in XML)
1486 if ( myExtActions.size() > 0 ) {
1487 // Use only first selected object
1488 _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() );
1490 _PTR( GenericAttribute ) anAttr;
1491 std::string auid = "AttributeUserID";
1492 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1493 if ( aSO->FindAttribute( anAttr, auid ) ) {
1494 _PTR(AttributeUserID) aAttrID = anAttr;
1495 QString aId = aAttrID->Value().c_str();
1496 if ( myExtActions.contains( aId ) ) {
1497 thePopup->addAction(myExtActions[aId]);
1503 // check if item is a "GUI state" item (also a first level object)
1504 QString entry( aIObj->getEntry() );
1505 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1506 QString aModuleName( aIObj->getComponentDataType() );
1507 QString aModuleTitle = moduleTitle( aModuleName );
1508 if (aModuleTitle.isEmpty()) {
1509 // use displayer module, if given
1510 aModuleTitle = moduleDisplayer( aModuleName );
1512 CAM_Module* currentModule = activeModule();
1513 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() ) {
1514 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1519 mgr->setSelectionCacheEnabled( cacheIsOn );
1522 /*!Update obect browser:
1523 1.if 'updateModels' true, update existing data models;
1524 2. update "non-existing" (not loaded yet) data models;
1525 3. update object browser if it exists */
1526 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1528 // update "non-existing" (not loaded yet) data models
1529 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1532 for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() )
1534 _PTR(SComponent) aComponent ( it->Value() );
1536 #ifndef WITH_SALOMEDS_OBSERVER
1537 // with GUI observers this check is not needed anymore
1538 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1539 continue; // skip the magic "Interface Applicative" component
1541 if ( !objectBrowser() )
1542 getWindow( WT_ObjectBrowser );
1543 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1544 objectBrowser()->setAutoUpdate( false );
1545 SalomeApp_DataModel::synchronize( aComponent, study );
1546 objectBrowser()->setAutoUpdate( isAutoUpdate );
1550 // create data objects that correspond to GUI state save points
1551 if ( study ) updateSavePointDataObjects( study );
1553 // update existing data models (already loaded SComponents)
1554 LightApp_Application::updateObjectBrowser( updateModels );
1557 /*!Display Catalog Genenerator dialog */
1558 void SalomeApp_Application::onCatalogGen()
1560 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1564 /*!Display Registry Display dialog */
1565 void SalomeApp_Application::onRegDisplay()
1567 CORBA::ORB_var anOrb = orb();
1568 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1571 regWnd->activateWindow();
1574 /*!find original object by double click on item */
1575 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1577 // Issue 21379: References are supported at LightApp_DataObject level
1578 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1580 if( obj && obj->isReference() )
1582 QString entry = obj->refEntry();
1584 SUIT_DataOwnerPtrList aList;
1585 aList.append( new LightApp_DataOwner( entry ) );
1586 selectionMgr()->setSelected( aList, false );
1588 SUIT_DataBrowser* ob = objectBrowser();
1590 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1591 if ( !aSelectedIndexes.isEmpty() )
1592 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1594 emit objectDoubleClicked( theObj );
1598 Creates new view manager
1599 \param type - type of view manager
1601 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1603 return createViewManager(type);
1607 /*!Global utility function, returns selected GUI Save point object's ID */
1608 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1610 SALOME_ListIO aList;
1611 selMgr->selectedObjects( aList );
1612 if( aList.Extent() > 0 ) {
1613 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1614 QString entry( aIObj->getEntry() );
1615 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1616 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1618 bool ok; // conversion to integer is ok?
1619 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1620 return ok ? savePoint : -1;
1625 /*!Called on Restore GUI State popup command*/
1626 void SalomeApp_Application::onRestoreGUIState()
1628 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1629 if ( savePoint == -1 )
1631 SalomeApp_VisualState( this ).restoreState( savePoint );
1634 /*!Called on Delete GUI State popup command*/
1635 void SalomeApp_Application::onDeleteGUIState()
1637 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1638 if ( savePoint == -1 )
1640 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1644 study->removeSavePoint( savePoint );
1645 updateSavePointDataObjects( study );
1648 /*!Called on New study operation*/
1649 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1651 LightApp_Application::onStudyCreated( study );
1653 //#ifndef DISABLE_PYCONSOLE
1654 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1655 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1658 loadDockWindowsState();
1660 objectBrowserColumnsVisibility();
1663 /*!Called on Open study operation*/
1664 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1666 LightApp_Application::onStudyOpened( study );
1668 //#ifndef DISABLE_PYCONSOLE
1669 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1670 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1673 loadDockWindowsState();
1675 objectBrowserColumnsVisibility();
1677 // temporary commented
1678 /*if ( objectBrowser() ) {
1679 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1680 objectBrowser()->updateTree( study->root() );
1684 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1685 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1688 SUIT_DataBrowser* ob = objectBrowser();
1689 LightApp_SelectionMgr* selMgr = selectionMgr();
1691 if ( !study || !ob || !selMgr )
1694 // find GUI states root object
1695 SUIT_DataObject* guiRootObj = 0;
1697 study->root()->children( ch );
1698 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1699 for ( ; it != last ; ++it ) {
1700 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1705 std::vector<int> savePoints = study->getSavePoints();
1706 // case 1: no more save points but they existed in study's tree
1707 if ( savePoints.empty() && guiRootObj ) {
1708 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1709 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1710 const bool isAutoUpdate = ob->autoUpdate();
1711 selMgr->clearSelected();
1712 ob->setAutoUpdate(true);
1713 DataObjectList ch = guiRootObj->children();
1714 for( int i = 0; i < ch.size(); i++ )
1717 ob->setAutoUpdate(isAutoUpdate);
1720 // case 2: no more save points but root does not exist either
1721 if ( savePoints.empty() && !guiRootObj )
1723 // case 3: save points but no root for them - create it
1724 if ( !savePoints.empty() && !guiRootObj )
1725 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1726 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1727 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1729 if ( guiRootObj->nextBrother() ) {
1730 study->root()->removeChild(guiRootObj);
1731 study->root()->appendChild(guiRootObj);
1732 //study->root()->dump();
1735 // store data objects in a map id-to-DataObject
1736 QMap<int,SalomeApp_SavePointObject*> mapDO;
1738 guiRootObj->children( ch );
1739 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1740 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1742 mapDO[dobj->getId()] = dobj;
1745 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1746 // if in the map - remove it from map.
1747 for ( size_t i = 0; i < savePoints.size(); i++ )
1748 if ( !mapDO.contains( savePoints[i] ) )
1749 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1751 mapDO.remove( savePoints[i] );
1753 // delete DataObjects that are still in the map -- their IDs were not found in data model
1754 if( mapDO.size() > 0) {
1755 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1756 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1757 selMgr->clearSelected();
1758 const bool isAutoUpdate = ob->autoUpdate();
1759 ob->setAutoUpdate(true);
1760 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1762 ob->setAutoUpdate(isAutoUpdate);
1766 /*! Check data object */
1767 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1776 Opens other study into active Study. If Study is empty - creates it.
1777 \param theName - name of study
1779 bool SalomeApp_Application::useStudy( const QString& theName )
1782 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1785 res = aStudy->loadDocument( theName );
1786 updateDesktopTitle();
1787 updateCommandsStatus();
1791 /*! Show/hide object browser colums according to preferences */
1792 void SalomeApp_Application::objectBrowserColumnsVisibility()
1794 if ( objectBrowser() )
1795 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1797 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1798 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1802 #ifndef DISABLE_PYCONSOLE
1803 /*! Set SalomeApp_NoteBook pointer */
1804 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1806 myNoteBook = theNoteBook;
1809 /*! Return SalomeApp_NoteBook pointer */
1810 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1817 * Define extra actions defined in module definition XML file.
1818 * Additional popup items sections can be defined by parameter "popupitems".
1819 * Supported attributes:
1820 * title - title of menu item,
1821 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1822 * method - method which has to be called when menu item is selected
1824 * <section name="MODULENAME">
1825 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1827 * <section name="importmed">
1828 * <parameter name="title" value="My menu"/>
1829 * <parameter name="objectid" value="VISU.Result"/>
1830 * <parameter name="method" value="nameOfModuleMethod"/>
1833 void SalomeApp_Application::createExtraActions()
1835 myExtActions.clear();
1836 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1838 QStringList aModules;
1839 modules(aModules, false);
1840 foreach(QString aModile, aModules) {
1841 QString aModName = moduleName(aModile);
1842 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1843 if (!aSectionStr.isNull()) {
1844 QStringList aSections = aSectionStr.split(':');
1845 foreach(QString aSection, aSections) {
1846 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1847 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1848 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1849 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1852 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1853 if (aModuleName.isNull())
1854 aModuleName = aModName;
1856 QAction* aAction = new QAction(aTitle, this);
1858 aData<<aModuleName<<aSlot;
1859 aAction->setData(aData);
1860 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1861 myExtActions[aId] = aAction;
1868 * Called when extra action is selected
1870 void SalomeApp_Application::onExtAction()
1872 QAction* aAction = ::qobject_cast<QAction*>(sender());
1876 QVariant aData = aAction->data();
1877 QStringList aDataList = aData.value<QStringList>();
1878 if (aDataList.size() != 2)
1881 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1882 SALOME_ListIO aListIO;
1883 aSelectionMgr->selectedObjects(aListIO);
1884 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1885 if (aListIO.Extent() < 1)
1887 if (!anIO->hasEntry())
1890 QString aEntry(anIO->getEntry());
1892 QApplication::setOverrideCursor( Qt::WaitCursor );
1893 QString aModuleTitle = moduleTitle(aDataList[0]);
1894 activateModule(aModuleTitle);
1895 QApplication::restoreOverrideCursor();
1897 QCoreApplication::processEvents();
1899 CAM_Module* aModule = activeModule();
1903 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1904 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1908 Checks that an object can be renamed.
1909 \param entry entry of the object
1910 \brief Return \c true if object can be renamed
1912 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1914 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1918 Rename object by entry.
1919 \param entry entry of the object
1920 \param name new name of the object
1921 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1923 bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name )
1925 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1927 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1929 if(!aStudy || savePoint == -1)
1932 if ( !name.isNull() && !name.isEmpty() ) {
1933 aStudy->setNameOfSavePoint( savePoint, name );
1934 updateSavePointDataObjects( aStudy );
1936 //Mark study as modified
1943 #ifndef DISABLE_PYCONSOLE
1944 //============================================================================
1945 /*! Function : onUpdateStudy
1946 * Purpose : Slot to update the study.
1948 //============================================================================
1949 void SalomeApp_Application::onUpdateStudy()
1951 QApplication::setOverrideCursor( Qt::WaitCursor );
1953 if( !updateStudy() )
1954 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1956 QApplication::restoreOverrideCursor();
1959 //============================================================================
1960 /*! Function : updateStudy
1961 * Purpose : Update study by dumping the study to Python script and loading it.
1962 * It is used to apply variable modifications done in NoteBook to created objects.
1964 //============================================================================
1965 bool SalomeApp_Application::updateStudy()
1967 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1968 if ( !study || !myNoteBook )
1971 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1972 myNoteBook->setDumpedStudyName( study->studyName() );
1974 // get unique temporary directory name
1975 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1977 if( aTmpDir.isEmpty() )
1980 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1981 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1983 // dump study to the temporary directory
1984 QString aScriptName( "notebook" );
1985 bool toPublish = true;
1986 bool isMultiFile = false;
1987 bool toSaveGUI = true;
1990 _PTR(AttributeParameter) ap;
1991 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1992 if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag.
1993 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1994 ip->setDumpPython();
1995 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1997 bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1999 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
2002 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
2006 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2007 int anIndex = aList.indexOf( this );
2009 // Disconnect dialog from application desktop in case if:
2010 // 1) Application is not the first application in the session
2011 // 2) Application is the first application in session but not the only.
2012 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2013 if( changeDesktop ) {
2015 SalomeApp_Application* app = this;
2016 if( anIndex > 0 && anIndex < aList.count() )
2017 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2018 else if(anIndex == 0 && aList.count() > 1)
2019 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2024 // creation a new study and restoring will be done in another application
2025 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2026 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2029 QString aDumpScript = myNoteBook->getDumpedStudyScript();
2030 QString aStudyName = myNoteBook->getDumpedStudyName();
2031 bool isStudySaved = myNoteBook->isDumpedStudySaved();
2032 // clear a study (delete all objects)
2033 onCloseDoc( false );
2035 if( !changeDesktop ) {
2036 ok = onRestoreStudy( aDumpScript,
2045 //============================================================================
2046 /*! Function : onRestoreStudy
2047 * Purpose : Load the dumped study from Python script
2049 //============================================================================
2050 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2051 const QString& theStudyName,
2052 bool theIsStudySaved )
2056 // create a new study
2059 // get active application
2060 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2062 // load study from the temporary directory
2063 QFileInfo aScriptInfo = QFileInfo(theDumpScript);
2064 QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath());
2066 #ifndef DISABLE_PYCONSOLE
2067 PyConsole_Console* pyConsole = app->pythonConsole();
2069 PropertyMgr propm( this, "IsLoadedScript", true );
2070 pyConsole->execAndWait( command );
2074 // remove temporary directory
2075 QString aStudyName = aScriptInfo.baseName();
2076 QDir aDir = aScriptInfo.absoluteDir();
2077 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2078 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2079 ok = aDir.remove( *it ) && ok;
2081 ok = aDir.rmdir( aDir.absolutePath() );
2083 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2085 #ifndef DISABLE_PYCONSOLE
2086 if ( app->getNoteBook() )
2087 app->getNoteBook()->Init();
2088 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2089 newStudy->Modified();
2090 updateDesktopTitle();
2101 Close the Application
2103 void SalomeApp_Application::afterCloseDoc()
2105 #ifndef DISABLE_PYCONSOLE
2106 // emit signal to restore study from Python script
2108 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2109 myNoteBook->getDumpedStudyName(),
2110 myNoteBook->isDumpedStudySaved() );
2113 LightApp_Application::afterCloseDoc();
2116 bool SalomeApp_Application::canOpenDoc( const QString& url )
2118 _PTR(Study) aStudyDS = getStudy();
2120 return aStudyDS->CanOpen( url.toUtf8().data() );
2125 Asks to close existing document.
2127 bool SalomeApp_Application::checkExistingDoc()
2129 return LightApp_Application::checkExistingDoc();
2133 #ifndef DISABLE_PYCONSOLE
2135 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2137 return new SalomeApp_PyInterp( resourceMgr() );
2140 #endif // DISABLE_PYCONSOLE
2142 void SalomeApp_Application::ensureShaperIsActivated()
2144 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
2145 _PTR(Study) studyDS = getStudy();
2146 if ( study && studyDS )
2148 _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study
2149 bool shaperIsActive = false;
2150 QList<CAM_DataModel*> models;
2151 study->dataModels( models );
2152 for( int i = 0; i < models.count() && !shaperIsActive; i++ )
2153 shaperIsActive = models[i]->module()->moduleName() == "Shaper";
2155 if (shaper && !shaperIsActive)
2156 onDesktopMessage("register_module_in_study/Shaper");