1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: SalomeApp_Application.cxx
24 // Created: 10/22/2004 3:23:45 PM
25 // Author: Sergey LITONIN
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #ifndef DISABLE_PYCONSOLE
37 #ifndef DISABLE_PYCONSOLE
38 #include "SalomeApp_PyInterp.h"
39 #include "SalomeApp_NoteBook.h"
40 #include "LightApp_PyEditor.h"
41 #include "PyConsole_Console.h"
43 #include "SalomeApp_Application.h"
44 #include "SalomeApp_Study.h"
45 #include "SalomeApp_DataModel.h"
46 #include "SalomeApp_DataObject.h"
47 #include "SalomeApp_VisualState.h"
48 #include "SalomeApp_StudyPropertiesDlg.h"
49 #include "SalomeApp_LoadStudiesDlg.h"
50 #include "SalomeApp_ExitDlg.h"
52 #include <LightApp_Application.h>
53 #include <LightApp_FileValidator.h>
54 #include <LightApp_Module.h>
55 #include <LightApp_Preferences.h>
56 #include <LightApp_SelectionMgr.h>
57 #include <LightApp_NameDlg.h>
58 #include <LightApp_DataOwner.h>
60 #include <CAM_Module.h>
62 #include <SUIT_Tools.h>
63 #include <SUIT_Session.h>
64 #include <SUIT_Desktop.h>
65 #include <SUIT_DataBrowser.h>
66 #include <SUIT_FileDlg.h>
67 #include <SUIT_MessageBox.h>
68 #include <SUIT_ResourceMgr.h>
69 #include <SUIT_TreeModel.h>
70 #include <SUIT_ViewWindow.h>
71 #include <SUIT_ViewManager.h>
72 #include <SUIT_ViewModel.h>
73 #include <SUIT_OverrideCursor.h>
75 #include <QtxTreeView.h>
77 #include <SALOME_EventFilter.h>
79 // temporary commented
80 //#include <OB_ListItem.h>
83 #include <Utils_ORB_INIT.hxx>
84 #include <Utils_SINGLETON.hxx>
85 #include <SALOME_LifeCycleCORBA.hxx>
87 #include <QApplication>
92 #include <QPushButton>
94 #include <QListWidget>
95 #include <QGridLayout>
99 #include <SALOMEDSClient_ClientFactory.hxx>
100 #include <Basics_Utils.hxx>
102 #include <SALOME_ListIO.hxx>
103 #include <SALOME_Prs.h>
106 #include <ToolsGUI_CatalogGeneratorDlg.h>
107 #include <ToolsGUI_RegWidget.h>
111 #include <SALOMEDS_Tool.hxx>
113 /*!Internal class that updates object browser item properties */
114 // temporary commented
115 /*class SalomeApp_Updater : public OB_Updater
118 SalomeApp_Updater() : OB_Updater(){};
119 virtual ~SalomeApp_Updater(){};
120 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
123 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
125 if( !theObj || !theItem )
128 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
132 _PTR(SObject) SObj = SAObj->object();
135 _PTR( GenericAttribute ) anAttr;
138 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
140 _PTR(AttributeSelectable) aAttrSel = anAttr;
141 theItem->setSelectable( aAttrSel->IsSelectable() );
144 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
146 _PTR(AttributeExpandable) aAttrExpand = anAttr;
147 theItem->setExpandable( aAttrExpand->IsExpandable() );
150 //this attribute is not supported in the version of SALOME 3.x
151 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
153 // _PTR(AttributeOpened) aAttrOpen = anAttr;
154 // theItem->setOpen( aAttrOpen->IsOpened() );
166 //! Constructor. Sets passed boolean flag to \c true.
167 MessageLocker( bool& Lock ) : myPrevState( Lock ), myLock( Lock ) { myLock = true; }
168 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
169 ~MessageLocker() { myLock = myPrevState; }
172 bool& myLock; //! External 'Lock state' boolean flag
176 /*!Create new instance of SalomeApp_Application.*/
177 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
179 return new SalomeApp_Application();
183 SalomeApp_Application::SalomeApp_Application()
184 : LightApp_Application(),
185 myIsCloseFromExit( false ),
186 myToIgnoreMessages( false )
191 *\li Destroy event filter.
193 SalomeApp_Application::~SalomeApp_Application()
195 // Do not destroy. It's a singleton !
196 //SALOME_EventFilter::Destroy();
199 QStringList __getArgsList(QString argsString)
201 // Special process if some items of 'args:' list are themselves lists
202 // Note that an item can be a list, but not a list of lists...
203 // So we can have something like this:
204 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
205 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
206 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
207 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
208 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
210 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
215 return argsString.split(",", QString::SkipEmptyParts);
218 /*!Start application.*/
219 void SalomeApp_Application::start()
221 // process the command line options before start: to createActions in accordance to the options
222 static bool isFirst = true;
229 QStringList args = QApplication::arguments();
230 for (int i = 1; i < args.count(); i++) {
231 QRegExp rxs ("--study-hdf=(.+)");
232 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
233 QString file = rxs.capturedTexts()[1];
234 QFileInfo fi ( file );
235 QString extension = fi.suffix().toLower();
236 if ( extension == "hdf" && fi.exists() )
237 hdffile = fi.absoluteFilePath();
240 QRegExp rxp ("--pyscript=\\[(.+)\\]");
241 if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
243 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
244 for (int k = 0; k < dictList.count(); ++k) {
245 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
246 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
247 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
248 pyfiles += rxd.capturedTexts()[m];
255 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
256 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
258 LightApp_Application::start();
259 SALOME_EventFilter::Init();
261 setProperty("open_study_from_command_line", true);
262 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
263 onOpenDoc( hdffile );
264 setProperty("open_study_from_command_line", QVariant());
266 #ifndef DISABLE_PYCONSOLE
267 // import/execute python scripts
268 if ( pyfiles.count() > 0 && activeStudy() ) {
269 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
270 PyConsole_Console* pyConsole = pythonConsole();
271 if ( appStudy && pyConsole ) {
272 if ( !getStudy()->GetProperties()->IsLocked() ) {
273 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
274 // Path is absolute, script has .py extension
275 for (int j = 0; j < pyfiles.count(); j++ ) {
276 // Extract scripts and their arguments, if any
277 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
278 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
279 QString script = rxp.capturedTexts()[1];
281 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
282 for (int k = 0; k < argList.count(); k++ ) {
283 QString arg = argList[k].trimmed();
284 arg.remove( QRegExp("^[\"]") );
285 arg.remove( QRegExp("[\"]$") );
286 args << QString("\"%1\"").arg(arg);
288 if (args.count() == 1)
291 script.remove( QRegExp("^python.*[\\s]+") );
292 QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(","));
293 pyConsole->exec(command);
295 } // end for loop on pyfiles QStringList
301 LightApp_Application::start();
302 SALOME_EventFilter::Init();
307 void SalomeApp_Application::createActions()
309 LightApp_Application::createActions();
311 SUIT_Desktop* desk = desktop();
314 // "Save GUI State" command is moved to VISU module
315 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
316 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
317 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
320 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
321 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
322 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
325 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
326 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
327 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
330 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
331 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
332 0, desk, false, this, SLOT( onProperties() ) );
334 //! Catalog Generator
335 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
336 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
337 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
340 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
341 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
342 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
344 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
345 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
346 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
347 //no need at this action for mono-study application because study is always exists
348 action( ConnectId )->setVisible( false );
350 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
351 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
352 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
353 //no need at this action for mono-study application because study is always exists
354 action( DisconnectId )->setVisible( false );
357 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
359 // "Save GUI State" command is renamed to "Save VISU State" and
360 // creation of menu item is moved to VISU
361 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
363 createMenu( ConnectId, fileMenu, 5 );
364 createMenu( DisconnectId, fileMenu, 5 );
365 createMenu( separator(), fileMenu, -1, 5 );
367 createMenu( DumpStudyId, fileMenu, 10, -1 );
368 createMenu( LoadScriptId, fileMenu, 10, -1 );
369 createMenu( separator(), fileMenu, -1, 10, -1 );
370 createMenu( PropertiesId, fileMenu, 10, -1 );
371 createMenu( separator(), fileMenu, -1, 10, -1 );
373 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
374 createMenu( CatalogGenId, toolsMenu, 10, -1 );
375 createMenu( RegDisplayId, toolsMenu, 10, -1 );
376 createMenu( separator(), toolsMenu, -1, 15, -1 );
378 createExtraActions();
380 #ifndef DISABLE_PYCONSOLE
381 #ifndef DISABLE_SALOMEOBJECT
382 // import Python module that manages SALOME plugins
384 PyLockWrapper lck; // acquire GIL
385 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
386 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
390 // end of SALOME plugins loading
397 \brief Close application.
399 void SalomeApp_Application::onExit()
401 //MessageLocker ml( myToIgnoreMessages );
403 bool killServers = false;
406 if ( exitConfirmation() ) {
407 SalomeApp_ExitDlg dlg( desktop() );
408 result = dlg.exec() == QDialog::Accepted;
409 killServers = dlg.isServersShutdown();
413 if ( !killServers ) myIsCloseFromExit = true;
414 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
415 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
419 /*!SLOT. Create a document.*/
420 void SalomeApp_Application::onNewDoc()
422 MessageLocker ml( myToIgnoreMessages );
424 LightApp_Application::onNewDoc();
427 /*!SLOT. Load document.*/
428 void SalomeApp_Application::onLoadDoc()
430 MessageLocker ml( myToIgnoreMessages );
434 // rnv: According to the single-study approach on the server side
435 // can be only one study. So if it is exists connect to them,
436 // overwise show warning message: "No active study on the server"
439 SUIT_Session* aSession = SUIT_Session::session();
440 QList<SUIT_Application*> aAppList = aSession->applications();
442 QStringList unloadedStudies;
444 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
445 studyName = List[ind].c_str();
446 // Add to list only unloaded studies
447 bool isAlreadyOpen = false;
448 QListIterator<SUIT_Application*> it( aAppList );
449 while ( it.hasNext() && !isAlreadyOpen ) {
450 SUIT_Application* aApp = it.next();
451 if( !aApp || !aApp->activeStudy() )
453 if ( aApp->activeStudy()->studyName() == studyName )
454 isAlreadyOpen = true;
457 if ( !isAlreadyOpen )
458 unloadedStudies << studyName;
460 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
461 if ( studyName.isEmpty() )
466 SUIT_MessageBox::warning( desktop(),
467 QObject::tr("WRN_WARNING"),
468 QObject::tr("WRN_NO_STUDY_ON SERV") );
472 studyName = activeStudy()->studyName();
475 // this code replaces marker of windows drive and path become invalid therefore
476 // defines placed there
477 studyName.replace( QRegExp(":"), "/" );
480 if ( onLoadDoc( studyName ) ) {
482 updateViewManagers();
483 updateObjectBrowser( true );
487 /*!SLOT. Unload document.*/
488 void SalomeApp_Application::onUnloadDoc( bool ask )
491 activeStudy()->abortAllOperations();
492 if ( activeStudy()->isModified() ) {
493 QString docName = activeStudy()->studyName().trimmed();
494 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
495 tr( "DISCONNECT_DESCRIPTION" ),
496 tr( "DISCONNECT_SAVE" ),
497 tr( "DISCONNECT_WO_SAVE" ),
498 tr( "APPCLOSE_CANCEL" ), 0 );
499 if ( answer == 0 ) { // save before unload
500 if ( activeStudy()->isSaved() )
502 else if ( !onSaveAsDoc() )
505 else if ( answer == 2 ) // Cancel
509 closeActiveDoc( false );
512 /*!SLOT. Create new study and load script*/
513 void SalomeApp_Application::onNewWithScript()
515 QStringList filtersList;
516 filtersList.append(tr("PYTHON_FILES_FILTER"));
517 filtersList.append(tr("ALL_FILES_FILTER"));
519 QString anInitialPath = "";
520 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
521 anInitialPath = QDir::currentPath();
523 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
525 if ( !aFile.isEmpty() )
529 QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile);
531 #ifndef DISABLE_PYCONSOLE
532 PyConsole_Console* pyConsole = pythonConsole();
535 pyConsole->exec( command );
541 /*!SLOT. Load document with \a aName.*/
542 bool SalomeApp_Application::onLoadDoc( const QString& aName )
544 if ( !LightApp_Application::closeDoc() )
548 if ( !activeStudy() ) {
549 // if no study - load in current desktop
550 res = useStudy( aName );
553 // if study exists - load in new desktop. Check: is the same file is loaded?
554 SUIT_Session* aSession = SUIT_Session::session();
555 QList<SUIT_Application*> aAppList = aSession->applications();
556 bool isAlreadyOpen = false;
557 SalomeApp_Application* aApp = 0;
558 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
559 it != aAppList.end() && !isAlreadyOpen; ++it ) {
560 aApp = dynamic_cast<SalomeApp_Application*>( *it );
561 if ( aApp && aApp->activeStudy()->studyName() == aName )
562 isAlreadyOpen = true;
564 if ( !isAlreadyOpen ) {
565 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
567 res = aApp->useStudy( aName );
570 aApp->desktop()->activateWindow();
577 /*!SLOT. Parse message for desktop.*/
578 void SalomeApp_Application::onDesktopMessage( const QString& message )
580 if ( myToIgnoreMessages )
581 return; // a message from SALOMEDS is caused by GUI action
583 MessageLocker ml( myToIgnoreMessages );
585 if (message.indexOf("studyCreated") == 0) {
586 if (!activeStudy()) {
588 updateCommandsStatus();
591 if (message.indexOf("studyCleared") == 0) {
592 // Disconnect GUI from active study, because it was closed on DS side.
594 closeActiveDoc( false );
595 // Disable 'Connect' action
596 QAction* a = action( ConnectId );
598 a->setEnabled( false );
601 else if ( message.toLower() == "connect_to_study" ) {
603 useStudy( activeStudy()->studyName() );
605 if (message.indexOf("studyNameChanged") == 0) {
606 updateDesktopTitle();
608 LightApp_Application::onDesktopMessage( message );
611 /*!On module activation action.*/
612 void SalomeApp_Application::onModuleActivation( const QString& modName )
614 if (!activeStudy() && !modName.isEmpty())
617 LightApp_Application::onModuleActivation( modName );
620 /*!SLOT. Copy objects to study maneger from selection maneger..*/
621 void SalomeApp_Application::onCopy()
623 LightApp_Application::onCopy();
626 LightApp_SelectionMgr* mgr = selectionMgr();
627 mgr->selectedObjects(list);
629 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
630 if(study == NULL) return;
632 _PTR(Study) stdDS = getStudy();
635 SALOME_ListIteratorOfListIO it( list );
638 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
643 onSelectionChanged();
651 /*!SLOT. Paste objects to study maneger from selection manager.*/
652 void SalomeApp_Application::onPaste()
654 LightApp_Application::onPaste();
657 LightApp_SelectionMgr* mgr = selectionMgr();
658 mgr->selectedObjects(list);
660 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
661 if(study == NULL) return;
663 _PTR(Study) stdDS = getStudy();
666 if ( stdDS->GetProperties()->IsLocked() ) {
667 SUIT_MessageBox::warning( desktop(),
668 QObject::tr("WRN_WARNING"),
669 QObject::tr("WRN_STUDY_LOCKED") );
673 SALOME_ListIteratorOfListIO it( list );
676 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
681 updateObjectBrowser( true );
682 updateActions(); //SRN: BugID IPAL9377, case 3
690 /*!Check the application on closing.
691 * \retval true if possible, else false
693 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
695 return LightApp_Application::isPossibleToClose( closePermanently );
698 /*! Check if the study is locked */
699 void SalomeApp_Application::onCloseDoc( bool ask )
701 if(getStudy()->IsStudyLocked()) {
702 if ( SUIT_MessageBox::question( desktop(),
703 QObject::tr( "WRN_WARNING" ),
704 QObject::tr( "CLOSE_LOCKED_STUDY" ),
705 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
706 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
709 MessageLocker ml( myToIgnoreMessages );
711 LightApp_Application::onCloseDoc( ask );
713 // reinitialize study to have empty data
714 //getStudy()->Init();
717 /*!SLOT. Reload document from the file.*/
718 bool SalomeApp_Application::onReopenDoc()
720 MessageLocker ml( myToIgnoreMessages );
722 return LightApp_Application::onReopenDoc();
726 /*!SLOT. Load document.*/
727 void SalomeApp_Application::onOpenDoc()
729 MessageLocker ml( myToIgnoreMessages );
731 LightApp_Application::onOpenDoc();
734 /*!SLOT. Load document.*/
735 bool SalomeApp_Application::onOpenDoc(const QString& name)
737 MessageLocker ml( myToIgnoreMessages );
739 return LightApp_Application::onOpenDoc(name);
742 /*!Sets enable or disable some actions on selection changed.*/
743 void SalomeApp_Application::onSelectionChanged()
746 LightApp_SelectionMgr* mgr = selectionMgr();
747 mgr->selectedObjects(list);
749 bool canCopy = false;
750 bool canPaste = false;
752 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
755 canCopy = m->canCopy();
756 canPaste = m->canPaste();
759 SALOME_ListIteratorOfListIO it ( list );
761 if (it.More() && list.Extent() == 1) {
762 _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry());
765 canCopy = canCopy || getStudy()->CanCopy(so);
766 canPaste = canPaste || getStudy()->CanPaste(so);
770 action(EditCopyId)->setEnabled(canCopy);
771 action(EditPasteId)->setEnabled(canPaste);
774 /*!Delete references.*/
775 void SalomeApp_Application::onDeleteInvalidReferences()
778 LightApp_SelectionMgr* mgr = selectionMgr();
779 mgr->selectedObjects( aList, QString(), false );
781 if( aList.IsEmpty() )
784 _PTR(Study) aStudyDS = getStudy();
785 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
788 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
789 if ( it.Value()->hasEntry() )
791 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
792 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
795 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
796 aStudyBuilder->RemoveReference( aSObject );
798 updateObjectBrowser();
802 void SalomeApp_Application::onOpenWith()
804 QApplication::setOverrideCursor( Qt::WaitCursor );
806 LightApp_SelectionMgr* mgr = selectionMgr();
807 mgr->selectedObjects(aList);
808 if (aList.Extent() != 1)
810 QApplication::restoreOverrideCursor();
813 Handle(SALOME_InteractiveObject) aIObj = aList.First();
814 QString aModuleName(aIObj->getComponentDataType());
815 QString aModuleTitle = moduleTitle(aModuleName);
816 activateModule(aModuleTitle);
817 QApplication::restoreOverrideCursor();
823 SUIT_Study* SalomeApp_Application::createNewStudy()
825 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
827 // Set up processing of major study-related events
828 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
829 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
830 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
831 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
833 #ifndef DISABLE_PYCONSOLE
834 //to receive signal in application that NoteBook's variable was modified
835 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
836 this, SIGNAL(notebookVarUpdated(QString)) );
845 Enable/Disable menu items and toolbar buttons. Rebuild menu
847 void SalomeApp_Application::updateCommandsStatus()
849 LightApp_Application::updateCommandsStatus();
852 QAction* a = action( DumpStudyId );
854 a->setEnabled( activeStudy() );
856 #ifndef DISABLE_PYCONSOLE
858 a = action( LoadScriptId );
860 a->setEnabled( pythonConsole() );
864 a = action( PropertiesId );
866 a->setEnabled( activeStudy() );
868 // Save GUI state menu
869 a = action( SaveGUIStateId );
871 a->setEnabled( activeStudy() );
873 // Connect study menu
874 a = action( ConnectId );
876 a->setEnabled( !activeStudy() );
878 // Disconnect study menu
879 a = action( DisconnectId );
881 a->setEnabled( activeStudy() );
883 // update state of Copy/Paste menu items
884 onSelectionChanged();
888 \class DumpStudyFileDlg
889 Private class used in Dump Study operation. Consists 2 check boxes:
890 "Publish in study" and "Save GUI parameters"
892 class DumpStudyFileDlg : public SUIT_FileDlg
895 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
897 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
900 QWidget *hB = new QWidget( this );
901 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
902 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
903 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
905 QHBoxLayout *layout = new QHBoxLayout;
906 layout->addWidget(myPublishChk);
907 layout->addWidget(myMultiFileChk);
908 layout->addWidget(mySaveGUIChk);
909 hB->setLayout(layout);
911 QPushButton* pb = new QPushButton(this);
913 int row = grid->rowCount();
914 grid->addWidget( new QLabel("", this), row, 0 );
915 grid->addWidget( hB, row, 1, 1, 3 );
916 grid->addWidget( pb, row, 5 );
921 QCheckBox* myPublishChk;
922 QCheckBox* myMultiFileChk;
923 QCheckBox* mySaveGUIChk;
926 /*!Private SLOT. On dump study.*/
927 void SalomeApp_Application::onDumpStudy( )
929 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
930 if ( !appStudy ) return;
932 QStringList aFilters;
933 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
935 bool anIsPublish = true;
936 bool anIsMultiFile = false;
937 bool anIsSaveGUI = true;
939 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
940 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
941 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
942 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
945 DumpStudyFileDlg fd( desktop() );
946 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
947 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
948 fd.setNameFilters( aFilters );
949 fd.myPublishChk->setChecked( anIsPublish );
950 fd.myMultiFileChk->setChecked( anIsMultiFile );
951 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
952 if ( fd.exec() == QDialog::Accepted )
954 QString aFileName = fd.selectedFile();
956 bool toPublish = fd.myPublishChk->isChecked();
957 bool isMultiFile = fd.myMultiFileChk->isChecked();
958 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
960 if ( !aFileName.isEmpty() ) {
961 QFileInfo aFileInfo(aFileName);
962 if( aFileInfo.isDir() ) // IPAL19257
965 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
968 SUIT_OverrideCursor wc;
969 ensureShaperIsActivated();
970 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
973 SUIT_MessageBox::warning( desktop(),
974 QObject::tr("WRN_WARNING"),
975 tr("WRN_DUMP_STUDY_FAILED") );
980 /*!Private SLOT. On load script.*/
981 void SalomeApp_Application::onLoadScript( )
983 if ( getStudy()->GetProperties()->IsLocked() ) {
984 SUIT_MessageBox::warning( desktop(),
985 QObject::tr("WRN_WARNING"),
986 QObject::tr("WRN_STUDY_LOCKED") );
990 QStringList filtersList;
991 filtersList.append(tr("PYTHON_FILES_FILTER"));
992 filtersList.append(tr("ALL_FILES_FILTER"));
994 QString anInitialPath = "";
995 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
996 anInitialPath = QDir::currentPath();
998 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
1000 if ( !aFile.isEmpty() )
1003 QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile);
1005 #ifndef DISABLE_PYCONSOLE
1006 PyConsole_Console* pyConsole = pythonConsole();
1009 pyConsole->exec( command );
1014 /*!Private SLOT. On save GUI state.*/
1015 void SalomeApp_Application::onSaveGUIState()
1017 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1019 SalomeApp_VisualState( this ).storeState();
1020 updateSavePointDataObjects( study );
1021 updateObjectBrowser();
1026 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1027 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1029 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1030 QAction* send = ::qobject_cast<QAction*>( sender() );
1033 QString aWinName = send->data().toString();
1034 if ( theIsVisible && aWinName == "objectBrowser" )
1035 objectBrowserColumnsVisibility();
1039 QWidget* SalomeApp_Application::createWindow( const int flag )
1042 #ifndef DISABLE_PYCONSOLE
1043 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1045 wid = LightApp_Application::createWindow(flag);
1048 SUIT_ResourceMgr* resMgr = resourceMgr();
1050 if ( flag == WT_ObjectBrowser )
1052 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1054 // temporary commented
1055 //ob->setUpdater( new SalomeApp_Updater() );
1057 #ifdef WITH_SALOMEDS_OBSERVER
1058 //do not activate the automatic update of Qt tree through signal/slot
1059 ob->setAutoUpdate(false);
1060 //activate update of modified objects only
1061 ob->setUpdateModified(true);
1064 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1067 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1068 IORCol = QObject::tr( "IOR_COLUMN" ),
1069 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1070 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1072 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1073 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1074 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1075 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1076 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1077 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1078 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1079 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1080 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1082 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1083 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1084 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1086 ob->setAutoSizeFirstColumn(autoSizeFirst);
1087 ob->setAutoSizeColumns(autoSize);
1088 ob->setResizeOnExpandItem(resizeOnExpandItem);
1089 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1091 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1093 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1094 ob->treeView()->setColumnHidden( i, !shown );
1097 // temporary commented
1099 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1101 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1102 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1103 QString().sprintf( "visibility_column_%d", i ), true ) );
1107 // temporary commented
1109 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1110 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1111 ob->resize( desktop()->width()/3, ob->height() );
1115 #ifndef DISABLE_PYCONSOLE
1116 else if ( flag == WT_PyConsole )
1118 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1119 pyCons->setObjectName( "pythonConsole" );
1120 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1121 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1122 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1123 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1124 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1127 else if ( flag == WT_NoteBook )
1129 setNoteBook( new SalomeApp_NoteBook( desktop() ) );
1130 //to receive signal in NoteBook that it's variable was modified
1131 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1132 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1134 wid = getNoteBook();
1135 wid->setObjectName( "noteBook" );
1141 /*!Create preferences.*/
1142 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1144 LightApp_Application::createPreferences(pref);
1149 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1150 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1151 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1152 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1154 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1155 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1157 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1159 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1160 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1161 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1162 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1163 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1164 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1165 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1166 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1167 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1168 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1171 /*!Update desktop title.*/
1172 void SalomeApp_Application::updateDesktopTitle() {
1173 QString aTitle = applicationName();
1174 QString aVer = applicationVersion();
1175 if ( !aVer.isEmpty() )
1176 aTitle += QString( " " ) + aVer;
1178 if ( activeStudy() )
1180 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1181 if ( !sName.isEmpty() ) {
1182 if ( getStudy()->GetProperties()->IsLocked() ) {
1183 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1185 aTitle += QString( " - [%1]" ).arg( sName );
1190 desktop()->setWindowTitle( aTitle );
1193 int SalomeApp_Application::closeChoice( const QString& /*docName*/ )
1195 QStringList buttons;
1196 QMap<int, int> choices;
1198 buttons << tr ("APPCLOSE_SAVE"); // Save & Clear
1199 choices.insert( idx++, CloseSave ); // ...
1200 buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving
1201 choices.insert( idx++, CloseDiscard ); // ...
1202 if ( myIsCloseFromExit ) {
1203 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1204 choices.insert( idx++, CloseDisconnectSave ); // ...
1205 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1206 choices.insert( idx++, CloseDisconnect ); // ...
1208 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1209 choices.insert( idx++, CloseCancel ); // ...
1211 if( !activeStudy()->isModified() )
1213 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1214 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1215 return choices[answer];
1218 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1224 if ( activeStudy()->isSaved() )
1226 else if ( !onSaveAsDoc() )
1231 case CloseDisconnectSave:
1232 if ( activeStudy()->isSaved() )
1234 else if ( !onSaveAsDoc() )
1237 case CloseDisconnect:
1238 closeActiveDoc( false );
1239 closePermanently = false;
1248 int SalomeApp_Application::openChoice( const QString& aName )
1250 int choice = LightApp_Application::openChoice( aName );
1252 if ( QFileInfo( aName ).exists() ) {
1253 if ( choice == OpenNew ) { // The document isn't already open.
1255 if ( aName == getStudy()->Name().c_str() )
1257 // The document already exists in the study.
1258 // Do you want to reload it?
1260 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1261 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1262 if ( answer == SUIT_MessageBox::Yes )
1263 choice = OpenRefresh;
1265 choice = OpenCancel;
1268 } else { // file is not exist on disk
1269 SUIT_MessageBox::warning( desktop(),
1270 QObject::tr("WRN_WARNING"),
1271 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data()));
1278 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1281 int choice = aChoice;
1288 res = LightApp_Application::openAction( choice, aName );
1296 \brief Get map of the operations which can be performed
1297 on the module activation.
1299 The method should return the map of the kind \c {<id>:<name>}
1300 where \c <id> is an integer identifier of the operation and
1301 \c <name> is a title for the button to be added to the
1302 dialog box. After user selects the required operation by the
1303 clicking the corresponding button in the dialog box, its identifier
1304 is passed to the moduleActionSelected() method to process
1307 \return map of the operations
1308 \sa moduleActionSelected()
1310 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1312 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1314 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1316 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1321 \brief Called when the used selectes required operation chosen
1322 from "Activate module" dialog box.
1324 Performs the required operation according to the user choice.
1326 \param id operation identifier
1327 \sa activateModuleActions()
1329 void SalomeApp_Application::moduleActionSelected( const int id )
1335 case NewAndScriptId:
1339 LightApp_Application::moduleActionSelected( id );
1344 /*!Gets CORBA::ORB_var*/
1345 CORBA::ORB_var SalomeApp_Application::orb()
1347 static CORBA::ORB_var _orb;
1349 if ( CORBA::is_nil( _orb ) ) {
1350 Qtx::CmdLineArgs args;
1351 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1352 _orb = init( args.argc(), args.argv() );
1358 /*!Create and return SALOMEDS_Study.*/
1359 _PTR(Study) SalomeApp_Application::getStudy()
1361 static _PTR(Study) _study;
1363 CORBA::Object_var aSObject = namingService()->Resolve("/Study");
1364 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject);
1365 _study = ClientFactory::Study(aStudy);
1370 /*!Create and return SALOME_NamingService.*/
1371 SALOME_NamingService* SalomeApp_Application::namingService()
1373 static SALOME_NamingService _ns(orb());
1377 /*!Create and return SALOME_LifeCycleCORBA.*/
1378 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1380 static SALOME_LifeCycleCORBA _lcc( namingService() );
1384 /*!Private SLOT. On preferences.*/
1385 void SalomeApp_Application::onProperties()
1387 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1391 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1394 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1395 int res = aDlg.exec();
1396 if( res==QDialog::Accepted && aDlg.isChanged() )
1397 SB->CommitCommand();
1401 //study->updateCaptions();
1402 updateDesktopTitle();
1406 /*!Insert items in popup, which necessary for current application*/
1407 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1409 LightApp_SelectionMgr* mgr = selectionMgr();
1410 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1411 mgr->setSelectionCacheEnabled( true );
1413 LightApp_Application::contextMenuPopup( type, thePopup, title );
1415 // temporary commented
1416 /*OB_Browser* ob = objectBrowser();
1417 if ( !ob || type != ob->popupClientType() )
1420 // Get selected objects
1421 SALOME_ListIO aList;
1422 mgr->selectedObjects( aList, QString(), false );
1424 // add GUI state commands: restore, rename
1425 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1426 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1427 thePopup->addSeparator();
1428 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1429 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1430 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1431 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1434 // "Delete reference" item should appear only for invalid references
1436 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1437 bool isInvalidRefs = false;
1439 _PTR(SObject) anObj;
1440 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1442 if( it.Value()->hasEntry() )
1444 _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1445 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1448 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1449 isInvalidRefs = true;
1453 // Add "Delete reference" item to popup
1454 if ( isInvalidRefs )
1456 thePopup->addSeparator();
1457 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1461 // "Activate module" item should appear only if it's necessary
1462 if ( aList.Extent() == 1 ) {
1464 mgr->selectedObjects( aList );
1466 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1468 // add extra popup menu (defined in XML)
1469 if ( myExtActions.size() > 0 ) {
1470 // Use only first selected object
1471 _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() );
1473 _PTR( GenericAttribute ) anAttr;
1474 std::string auid = "AttributeUserID";
1475 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1476 if ( aSO->FindAttribute( anAttr, auid ) ) {
1477 _PTR(AttributeUserID) aAttrID = anAttr;
1478 QString aId = aAttrID->Value().c_str();
1479 if ( myExtActions.contains( aId ) ) {
1480 thePopup->addAction(myExtActions[aId]);
1486 // check if item is a "GUI state" item (also a first level object)
1487 QString entry( aIObj->getEntry() );
1488 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1489 QString aModuleName( aIObj->getComponentDataType() );
1490 QString aModuleTitle = moduleTitle( aModuleName );
1491 CAM_Module* currentModule = activeModule();
1492 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1493 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1497 mgr->setSelectionCacheEnabled( cacheIsOn );
1500 /*!Update obect browser:
1501 1.if 'updateModels' true, update existing data models;
1502 2. update "non-existing" (not loaded yet) data models;
1503 3. update object browser if it exists */
1504 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1506 // update "non-existing" (not loaded yet) data models
1507 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1510 for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() )
1512 _PTR(SComponent) aComponent ( it->Value() );
1514 #ifndef WITH_SALOMEDS_OBSERVER
1515 // with GUI observers this check is not needed anymore
1516 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1517 continue; // skip the magic "Interface Applicative" component
1519 if ( !objectBrowser() )
1520 getWindow( WT_ObjectBrowser );
1521 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1522 objectBrowser()->setAutoUpdate( false );
1523 SalomeApp_DataModel::synchronize( aComponent, study );
1524 objectBrowser()->setAutoUpdate( isAutoUpdate );
1528 // create data objects that correspond to GUI state save points
1529 if ( study ) updateSavePointDataObjects( study );
1531 // update existing data models (already loaded SComponents)
1532 LightApp_Application::updateObjectBrowser( updateModels );
1535 /*!Display Catalog Genenerator dialog */
1536 void SalomeApp_Application::onCatalogGen()
1538 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1542 /*!Display Registry Display dialog */
1543 void SalomeApp_Application::onRegDisplay()
1545 CORBA::ORB_var anOrb = orb();
1546 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1549 regWnd->activateWindow();
1552 /*!find original object by double click on item */
1553 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1555 // Issue 21379: References are supported at LightApp_DataObject level
1556 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1558 if( obj && obj->isReference() )
1560 QString entry = obj->refEntry();
1562 SUIT_DataOwnerPtrList aList;
1563 aList.append( new LightApp_DataOwner( entry ) );
1564 selectionMgr()->setSelected( aList, false );
1566 SUIT_DataBrowser* ob = objectBrowser();
1568 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1569 if ( !aSelectedIndexes.isEmpty() )
1570 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1572 emit objectDoubleClicked( theObj );
1576 Creates new view manager
1577 \param type - type of view manager
1579 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1581 return createViewManager(type);
1585 /*!Global utility function, returns selected GUI Save point object's ID */
1586 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1588 SALOME_ListIO aList;
1589 selMgr->selectedObjects( aList );
1590 if( aList.Extent() > 0 ) {
1591 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1592 QString entry( aIObj->getEntry() );
1593 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1594 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1596 bool ok; // conversion to integer is ok?
1597 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1598 return ok ? savePoint : -1;
1603 /*!Called on Restore GUI State popup command*/
1604 void SalomeApp_Application::onRestoreGUIState()
1606 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1607 if ( savePoint == -1 )
1609 SalomeApp_VisualState( this ).restoreState( savePoint );
1612 /*!Called on Delete GUI State popup command*/
1613 void SalomeApp_Application::onDeleteGUIState()
1615 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1616 if ( savePoint == -1 )
1618 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1622 study->removeSavePoint( savePoint );
1623 updateSavePointDataObjects( study );
1626 /*!Called on New study operation*/
1627 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1629 LightApp_Application::onStudyCreated( study );
1631 //#ifndef DISABLE_PYCONSOLE
1632 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1633 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1636 loadDockWindowsState();
1638 objectBrowserColumnsVisibility();
1641 /*!Called on Open study operation*/
1642 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1644 LightApp_Application::onStudyOpened( study );
1646 //#ifndef DISABLE_PYCONSOLE
1647 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1648 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1651 loadDockWindowsState();
1653 objectBrowserColumnsVisibility();
1655 // temporary commented
1656 /*if ( objectBrowser() ) {
1657 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1658 objectBrowser()->updateTree( study->root() );
1662 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1663 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1666 SUIT_DataBrowser* ob = objectBrowser();
1667 LightApp_SelectionMgr* selMgr = selectionMgr();
1669 if ( !study || !ob || !selMgr )
1672 // find GUI states root object
1673 SUIT_DataObject* guiRootObj = 0;
1675 study->root()->children( ch );
1676 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1677 for ( ; it != last ; ++it ) {
1678 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1683 std::vector<int> savePoints = study->getSavePoints();
1684 // case 1: no more save points but they existed in study's tree
1685 if ( savePoints.empty() && guiRootObj ) {
1686 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1687 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1688 const bool isAutoUpdate = ob->autoUpdate();
1689 selMgr->clearSelected();
1690 ob->setAutoUpdate(true);
1691 DataObjectList ch = guiRootObj->children();
1692 for( int i = 0; i < ch.size(); i++ )
1695 ob->setAutoUpdate(isAutoUpdate);
1698 // case 2: no more save points but root does not exist either
1699 if ( savePoints.empty() && !guiRootObj )
1701 // case 3: save points but no root for them - create it
1702 if ( !savePoints.empty() && !guiRootObj )
1703 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1704 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1705 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1707 if ( guiRootObj->nextBrother() ) {
1708 study->root()->removeChild(guiRootObj);
1709 study->root()->appendChild(guiRootObj);
1710 //study->root()->dump();
1713 // store data objects in a map id-to-DataObject
1714 QMap<int,SalomeApp_SavePointObject*> mapDO;
1716 guiRootObj->children( ch );
1717 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1718 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1720 mapDO[dobj->getId()] = dobj;
1723 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1724 // if in the map - remove it from map.
1725 for ( size_t i = 0; i < savePoints.size(); i++ )
1726 if ( !mapDO.contains( savePoints[i] ) )
1727 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1729 mapDO.remove( savePoints[i] );
1731 // delete DataObjects that are still in the map -- their IDs were not found in data model
1732 if( mapDO.size() > 0) {
1733 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1734 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1735 selMgr->clearSelected();
1736 const bool isAutoUpdate = ob->autoUpdate();
1737 ob->setAutoUpdate(true);
1738 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1740 ob->setAutoUpdate(isAutoUpdate);
1744 /*! Check data object */
1745 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1754 Opens other study into active Study. If Study is empty - creates it.
1755 \param theName - name of study
1757 bool SalomeApp_Application::useStudy( const QString& theName )
1760 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1763 res = aStudy->loadDocument( theName );
1764 updateDesktopTitle();
1765 updateCommandsStatus();
1769 /*! Show/hide object browser colums according to preferences */
1770 void SalomeApp_Application::objectBrowserColumnsVisibility()
1772 if ( objectBrowser() )
1773 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1775 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1776 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1780 #ifndef DISABLE_PYCONSOLE
1781 /*! Set SalomeApp_NoteBook pointer */
1782 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1784 myNoteBook = theNoteBook;
1787 /*! Return SalomeApp_NoteBook pointer */
1788 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1795 * Define extra actions defined in module definition XML file.
1796 * Additional popup items sections can be defined by parameter "popupitems".
1797 * Supported attributes:
1798 * title - title of menu item,
1799 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1800 * method - method which has to be called when menu item is selected
1802 * <section name="MODULENAME">
1803 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1805 * <section name="importmed">
1806 * <parameter name="title" value="My menu"/>
1807 * <parameter name="objectid" value="VISU.Result"/>
1808 * <parameter name="method" value="nameOfModuleMethod"/>
1811 void SalomeApp_Application::createExtraActions()
1813 myExtActions.clear();
1814 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1816 QStringList aModules;
1817 modules(aModules, false);
1818 foreach(QString aModile, aModules) {
1819 QString aModName = moduleName(aModile);
1820 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1821 if (!aSectionStr.isNull()) {
1822 QStringList aSections = aSectionStr.split(':');
1823 foreach(QString aSection, aSections) {
1824 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1825 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1826 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1827 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1830 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1831 if (aModuleName.isNull())
1832 aModuleName = aModName;
1834 QAction* aAction = new QAction(aTitle, this);
1836 aData<<aModuleName<<aSlot;
1837 aAction->setData(aData);
1838 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1839 myExtActions[aId] = aAction;
1846 * Called when extra action is selected
1848 void SalomeApp_Application::onExtAction()
1850 QAction* aAction = ::qobject_cast<QAction*>(sender());
1854 QVariant aData = aAction->data();
1855 QStringList aDataList = aData.value<QStringList>();
1856 if (aDataList.size() != 2)
1859 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1860 SALOME_ListIO aListIO;
1861 aSelectionMgr->selectedObjects(aListIO);
1862 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1863 if (aListIO.Extent() < 1)
1865 if (!anIO->hasEntry())
1868 QString aEntry(anIO->getEntry());
1870 QApplication::setOverrideCursor( Qt::WaitCursor );
1871 QString aModuleTitle = moduleTitle(aDataList[0]);
1872 activateModule(aModuleTitle);
1873 QApplication::restoreOverrideCursor();
1875 QCoreApplication::processEvents();
1877 CAM_Module* aModule = activeModule();
1881 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1882 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1886 Checks that an object can be renamed.
1887 \param entry entry of the object
1888 \brief Return \c true if object can be renamed
1890 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1892 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1896 Rename object by entry.
1897 \param entry entry of the object
1898 \param name new name of the object
1899 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1901 bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name )
1903 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1905 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1907 if(!aStudy || savePoint == -1)
1910 if ( !name.isNull() && !name.isEmpty() ) {
1911 aStudy->setNameOfSavePoint( savePoint, name );
1912 updateSavePointDataObjects( aStudy );
1914 //Mark study as modified
1921 #ifndef DISABLE_PYCONSOLE
1922 //============================================================================
1923 /*! Function : onUpdateStudy
1924 * Purpose : Slot to update the study.
1926 //============================================================================
1927 void SalomeApp_Application::onUpdateStudy()
1929 QApplication::setOverrideCursor( Qt::WaitCursor );
1931 if( !updateStudy() )
1932 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1934 QApplication::restoreOverrideCursor();
1937 //============================================================================
1938 /*! Function : updateStudy
1939 * Purpose : Update study by dumping the study to Python script and loading it.
1940 * It is used to apply variable modifications done in NoteBook to created objects.
1942 //============================================================================
1943 bool SalomeApp_Application::updateStudy()
1945 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1946 if ( !study || !myNoteBook )
1949 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1950 myNoteBook->setDumpedStudyName( study->studyName() );
1952 // get unique temporary directory name
1953 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1955 if( aTmpDir.isEmpty() )
1958 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1959 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1961 // dump study to the temporary directory
1962 QString aScriptName( "notebook" );
1963 bool toPublish = true;
1964 bool isMultiFile = false;
1965 bool toSaveGUI = true;
1968 _PTR(AttributeParameter) ap;
1969 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1970 if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag.
1971 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1972 ip->setDumpPython();
1973 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1975 bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1977 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1980 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1984 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1985 int anIndex = aList.indexOf( this );
1987 // Disconnect dialog from application desktop in case if:
1988 // 1) Application is not the first application in the session
1989 // 2) Application is the first application in session but not the only.
1990 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1991 if( changeDesktop ) {
1993 SalomeApp_Application* app = this;
1994 if( anIndex > 0 && anIndex < aList.count() )
1995 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1996 else if(anIndex == 0 && aList.count() > 1)
1997 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2002 // creation a new study and restoring will be done in another application
2003 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2004 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2007 QString aDumpScript = myNoteBook->getDumpedStudyScript();
2008 QString aStudyName = myNoteBook->getDumpedStudyName();
2009 bool isStudySaved = myNoteBook->isDumpedStudySaved();
2010 // clear a study (delete all objects)
2011 onCloseDoc( false );
2013 if( !changeDesktop ) {
2014 ok = onRestoreStudy( aDumpScript,
2023 //============================================================================
2024 /*! Function : onRestoreStudy
2025 * Purpose : Load the dumped study from Python script
2027 //============================================================================
2028 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2029 const QString& theStudyName,
2030 bool theIsStudySaved )
2034 // create a new study
2037 // get active application
2038 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2040 // load study from the temporary directory
2041 QFileInfo aScriptInfo = QFileInfo(theDumpScript);
2042 QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath());
2044 #ifndef DISABLE_PYCONSOLE
2045 PyConsole_Console* pyConsole = app->pythonConsole();
2047 pyConsole->execAndWait( command );
2050 // remove temporary directory
2051 QString aStudyName = aScriptInfo.baseName();
2052 QDir aDir = aScriptInfo.absoluteDir();
2053 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2054 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2055 ok = aDir.remove( *it ) && ok;
2057 ok = aDir.rmdir( aDir.absolutePath() );
2059 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2061 #ifndef DISABLE_PYCONSOLE
2062 if ( app->getNoteBook() )
2063 app->getNoteBook()->Init();
2064 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2065 newStudy->Modified();
2066 updateDesktopTitle();
2077 Close the Application
2079 void SalomeApp_Application::afterCloseDoc()
2081 #ifndef DISABLE_PYCONSOLE
2082 // emit signal to restore study from Python script
2084 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2085 myNoteBook->getDumpedStudyName(),
2086 myNoteBook->isDumpedStudySaved() );
2089 LightApp_Application::afterCloseDoc();
2092 bool SalomeApp_Application::canOpenDoc( const QString& url )
2094 _PTR(Study) aStudyDS = getStudy();
2096 return aStudyDS->CanOpen( url.toUtf8().data() );
2101 Asks to close existing document.
2103 bool SalomeApp_Application::checkExistingDoc()
2105 return LightApp_Application::checkExistingDoc();
2109 #ifndef DISABLE_PYCONSOLE
2111 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2113 return new SalomeApp_PyInterp;
2116 #endif // DISABLE_PYCONSOLE
2118 void SalomeApp_Application::ensureShaperIsActivated()
2120 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
2121 _PTR(Study) studyDS = getStudy();
2122 if ( study && studyDS )
2124 _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study
2125 bool shaperIsActive = false;
2126 QList<CAM_DataModel*> models;
2127 study->dataModels( models );
2128 for( int i = 0; i < models.count() && !shaperIsActive; i++ )
2129 shaperIsActive = models[i]->module()->moduleName() == "Shaper";
2131 if (shaper && !shaperIsActive)
2132 onDesktopMessage("register_module_in_study/Shaper");