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 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
179 SalomeApp_Application::SalomeApp_Application(SALOME_NamingService_Abstract *ns):myIsCloseFromExit( false ),myToIgnoreMessages( false )
182 _ns.reset(new SALOME_NamingService(orb()));
188 *\li Destroy event filter.
190 SalomeApp_Application::~SalomeApp_Application()
192 // Do not destroy. It's a singleton !
193 //SALOME_EventFilter::Destroy();
196 QStringList __getArgsList(QString argsString)
198 // Special process if some items of 'args:' list are themselves lists
199 // Note that an item can be a list, but not a list of lists...
200 // So we can have something like this:
201 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
202 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
203 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
204 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
205 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
207 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
212 return argsString.split(",", QString::SkipEmptyParts);
215 /*!Start application.*/
216 void SalomeApp_Application::start()
218 // process the command line options before start: to createActions in accordance to the options
219 static bool isFirst = true;
226 QStringList args = QApplication::arguments();
227 for (int i = 1; i < args.count(); i++) {
228 QRegExp rxs ("--study-hdf=(.+)");
229 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
230 QString file = rxs.capturedTexts()[1];
231 QFileInfo fi ( file );
232 QString extension = fi.suffix().toLower();
233 if ( extension == "hdf" && fi.exists() )
234 hdffile = fi.absoluteFilePath();
237 QRegExp rxp ("--pyscript=\\[(.+)\\]");
238 if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
240 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
241 for (int k = 0; k < dictList.count(); ++k) {
242 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
243 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
244 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
245 pyfiles += rxd.capturedTexts()[m];
252 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
253 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
255 LightApp_Application::start();
256 SALOME_EventFilter::Init();
258 setProperty("open_study_from_command_line", true);
259 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
260 onOpenDoc( hdffile );
261 setProperty("open_study_from_command_line", QVariant());
263 #ifndef DISABLE_PYCONSOLE
264 // import/execute python scripts
265 if ( pyfiles.count() > 0 && activeStudy() ) {
266 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
267 PyConsole_Console* pyConsole = pythonConsole();
268 if ( appStudy && pyConsole ) {
269 if ( !getStudy()->GetProperties()->IsLocked() ) {
270 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
271 // Path is absolute, script has .py extension
272 for (int j = 0; j < pyfiles.count(); j++ ) {
273 // Extract scripts and their arguments, if any
274 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
275 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
276 QString script = rxp.capturedTexts()[1];
278 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
279 for (int k = 0; k < argList.count(); k++ ) {
280 QString arg = argList[k].trimmed();
281 arg.remove( QRegExp("^[\"]") );
282 arg.remove( QRegExp("[\"]$") );
283 args << QString("\"%1\"").arg(arg);
285 if (args.count() == 1)
288 script.remove( QRegExp("^python.*[\\s]+") );
289 QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(","));
290 pyConsole->exec(command);
292 } // end for loop on pyfiles QStringList
298 LightApp_Application::start();
299 SALOME_EventFilter::Init();
304 void SalomeApp_Application::createActions()
306 LightApp_Application::createActions();
308 SUIT_Desktop* desk = desktop();
311 // "Save GUI State" command is moved to VISU module
312 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
313 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
314 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
317 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
318 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
319 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
322 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
323 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
324 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
327 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
328 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
329 0, desk, false, this, SLOT( onProperties() ) );
331 //! Catalog Generator
332 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
333 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
334 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
337 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
338 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
339 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
341 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
342 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
343 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
344 //no need at this action for mono-study application because study is always exists
345 action( ConnectId )->setVisible( false );
347 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
348 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
349 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
350 //no need at this action for mono-study application because study is always exists
351 action( DisconnectId )->setVisible( false );
354 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
356 // "Save GUI State" command is renamed to "Save VISU State" and
357 // creation of menu item is moved to VISU
358 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
360 createMenu( ConnectId, fileMenu, 5 );
361 createMenu( DisconnectId, fileMenu, 5 );
362 createMenu( separator(), fileMenu, -1, 5 );
364 createMenu( DumpStudyId, fileMenu, 10, -1 );
365 createMenu( LoadScriptId, fileMenu, 10, -1 );
366 createMenu( separator(), fileMenu, -1, 10, -1 );
367 createMenu( PropertiesId, fileMenu, 10, -1 );
368 createMenu( separator(), fileMenu, -1, 10, -1 );
370 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
371 createMenu( CatalogGenId, toolsMenu, 10, -1 );
372 createMenu( RegDisplayId, toolsMenu, 10, -1 );
373 createMenu( separator(), toolsMenu, -1, 15, -1 );
375 createExtraActions();
377 #ifndef DISABLE_PYCONSOLE
378 #ifndef DISABLE_SALOMEOBJECT
379 // import Python module that manages SALOME plugins
381 PyLockWrapper lck; // acquire GIL
382 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
383 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
387 // end of SALOME plugins loading
394 \brief Close application.
396 void SalomeApp_Application::onExit()
398 //MessageLocker ml( myToIgnoreMessages );
400 bool killServers = false;
403 if ( exitConfirmation() ) {
404 SalomeApp_ExitDlg dlg( desktop() );
405 result = dlg.exec() == QDialog::Accepted;
406 killServers = dlg.isServersShutdown();
410 if ( !killServers ) myIsCloseFromExit = true;
411 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
412 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
416 /*!SLOT. Create a document.*/
417 void SalomeApp_Application::onNewDoc()
419 MessageLocker ml( myToIgnoreMessages );
421 LightApp_Application::onNewDoc();
424 /*!SLOT. Load document.*/
425 void SalomeApp_Application::onLoadDoc()
427 MessageLocker ml( myToIgnoreMessages );
431 // rnv: According to the single-study approach on the server side
432 // can be only one study. So if it is exists connect to them,
433 // overwise show warning message: "No active study on the server"
436 SUIT_Session* aSession = SUIT_Session::session();
437 QList<SUIT_Application*> aAppList = aSession->applications();
439 QStringList unloadedStudies;
441 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
442 studyName = List[ind].c_str();
443 // Add to list only unloaded studies
444 bool isAlreadyOpen = false;
445 QListIterator<SUIT_Application*> it( aAppList );
446 while ( it.hasNext() && !isAlreadyOpen ) {
447 SUIT_Application* aApp = it.next();
448 if( !aApp || !aApp->activeStudy() )
450 if ( aApp->activeStudy()->studyName() == studyName )
451 isAlreadyOpen = true;
454 if ( !isAlreadyOpen )
455 unloadedStudies << studyName;
457 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
458 if ( studyName.isEmpty() )
463 SUIT_MessageBox::warning( desktop(),
464 QObject::tr("WRN_WARNING"),
465 QObject::tr("WRN_NO_STUDY_ON SERV") );
469 studyName = activeStudy()->studyName();
472 // this code replaces marker of windows drive and path become invalid therefore
473 // defines placed there
474 studyName.replace( QRegExp(":"), "/" );
477 if ( onLoadDoc( studyName ) ) {
479 updateViewManagers();
480 updateObjectBrowser( true );
484 /*!SLOT. Unload document.*/
485 void SalomeApp_Application::onUnloadDoc( bool ask )
488 activeStudy()->abortAllOperations();
489 if ( activeStudy()->isModified() ) {
490 QString docName = activeStudy()->studyName().trimmed();
491 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
492 tr( "DISCONNECT_DESCRIPTION" ),
493 tr( "DISCONNECT_SAVE" ),
494 tr( "DISCONNECT_WO_SAVE" ),
495 tr( "APPCLOSE_CANCEL" ), 0 );
496 if ( answer == 0 ) { // save before unload
497 if ( activeStudy()->isSaved() )
499 else if ( !onSaveAsDoc() )
502 else if ( answer == 2 ) // Cancel
506 closeActiveDoc( false );
509 /*!SLOT. Create new study and load script*/
510 void SalomeApp_Application::onNewWithScript()
512 QStringList filtersList;
513 filtersList.append(tr("PYTHON_FILES_FILTER"));
514 filtersList.append(tr("ALL_FILES_FILTER"));
516 QString anInitialPath = "";
517 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
518 anInitialPath = QDir::currentPath();
520 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
522 if ( !aFile.isEmpty() )
526 QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile);
528 #ifndef DISABLE_PYCONSOLE
529 PyConsole_Console* pyConsole = pythonConsole();
532 pyConsole->exec( command );
538 /*!SLOT. Load document with \a aName.*/
539 bool SalomeApp_Application::onLoadDoc( const QString& aName )
541 if ( !LightApp_Application::closeDoc() )
545 if ( !activeStudy() ) {
546 // if no study - load in current desktop
547 res = useStudy( aName );
550 // if study exists - load in new desktop. Check: is the same file is loaded?
551 SUIT_Session* aSession = SUIT_Session::session();
552 QList<SUIT_Application*> aAppList = aSession->applications();
553 bool isAlreadyOpen = false;
554 SalomeApp_Application* aApp = 0;
555 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
556 it != aAppList.end() && !isAlreadyOpen; ++it ) {
557 aApp = dynamic_cast<SalomeApp_Application*>( *it );
558 if ( aApp && aApp->activeStudy()->studyName() == aName )
559 isAlreadyOpen = true;
561 if ( !isAlreadyOpen ) {
562 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
564 res = aApp->useStudy( aName );
567 aApp->desktop()->activateWindow();
574 /*!SLOT. Parse message for desktop.*/
575 void SalomeApp_Application::onDesktopMessage( const QString& message )
577 if ( myToIgnoreMessages )
578 return; // a message from SALOMEDS is caused by GUI action
580 MessageLocker ml( myToIgnoreMessages );
582 if (message.indexOf("studyCreated") == 0) {
583 if (!activeStudy()) {
585 updateCommandsStatus();
588 if (message.indexOf("studyCleared") == 0) {
589 // Disconnect GUI from active study, because it was closed on DS side.
591 closeActiveDoc( false );
592 // Disable 'Connect' action
593 QAction* a = action( ConnectId );
595 a->setEnabled( false );
598 else if ( message.toLower() == "connect_to_study" ) {
600 useStudy( activeStudy()->studyName() );
602 if (message.indexOf("studyNameChanged") == 0) {
603 updateDesktopTitle();
605 LightApp_Application::onDesktopMessage( message );
608 /*!On module activation action.*/
609 void SalomeApp_Application::onModuleActivation( const QString& modName )
611 if (!activeStudy() && !modName.isEmpty())
614 LightApp_Application::onModuleActivation( modName );
617 /*!SLOT. Copy objects to study maneger from selection maneger..*/
618 void SalomeApp_Application::onCopy()
620 LightApp_Application::onCopy();
623 LightApp_SelectionMgr* mgr = selectionMgr();
624 mgr->selectedObjects(list);
626 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
627 if(study == NULL) return;
629 _PTR(Study) stdDS = getStudy();
632 SALOME_ListIteratorOfListIO it( list );
635 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
640 onSelectionChanged();
648 /*!SLOT. Paste objects to study maneger from selection manager.*/
649 void SalomeApp_Application::onPaste()
651 LightApp_Application::onPaste();
654 LightApp_SelectionMgr* mgr = selectionMgr();
655 mgr->selectedObjects(list);
657 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
658 if(study == NULL) return;
660 _PTR(Study) stdDS = getStudy();
663 if ( stdDS->GetProperties()->IsLocked() ) {
664 SUIT_MessageBox::warning( desktop(),
665 QObject::tr("WRN_WARNING"),
666 QObject::tr("WRN_STUDY_LOCKED") );
670 SALOME_ListIteratorOfListIO it( list );
673 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
678 updateObjectBrowser( true );
679 updateActions(); //SRN: BugID IPAL9377, case 3
687 /*!Check the application on closing.
688 * \retval true if possible, else false
690 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
692 return LightApp_Application::isPossibleToClose( closePermanently );
695 /*! Check if the study is locked */
696 void SalomeApp_Application::onCloseDoc( bool ask )
698 if(getStudy()->IsStudyLocked()) {
699 if ( SUIT_MessageBox::question( desktop(),
700 QObject::tr( "WRN_WARNING" ),
701 QObject::tr( "CLOSE_LOCKED_STUDY" ),
702 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
703 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
706 MessageLocker ml( myToIgnoreMessages );
708 LightApp_Application::onCloseDoc( ask );
710 // reinitialize study to have empty data
711 //getStudy()->Init();
714 /*!SLOT. Reload document from the file.*/
715 bool SalomeApp_Application::onReopenDoc()
717 MessageLocker ml( myToIgnoreMessages );
719 return LightApp_Application::onReopenDoc();
723 /*!SLOT. Load document.*/
724 void SalomeApp_Application::onOpenDoc()
726 MessageLocker ml( myToIgnoreMessages );
728 LightApp_Application::onOpenDoc();
731 /*!SLOT. Load document.*/
732 bool SalomeApp_Application::onOpenDoc(const QString& name)
734 MessageLocker ml( myToIgnoreMessages );
736 return LightApp_Application::onOpenDoc(name);
739 /*!Sets enable or disable some actions on selection changed.*/
740 void SalomeApp_Application::onSelectionChanged()
743 LightApp_SelectionMgr* mgr = selectionMgr();
744 mgr->selectedObjects(list);
746 bool canCopy = false;
747 bool canPaste = false;
749 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
752 canCopy = m->canCopy();
753 canPaste = m->canPaste();
756 SALOME_ListIteratorOfListIO it ( list );
758 if (it.More() && list.Extent() == 1) {
759 _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry());
762 canCopy = canCopy || getStudy()->CanCopy(so);
763 canPaste = canPaste || getStudy()->CanPaste(so);
767 action(EditCopyId)->setEnabled(canCopy);
768 action(EditPasteId)->setEnabled(canPaste);
771 /*!Delete references.*/
772 void SalomeApp_Application::onDeleteInvalidReferences()
775 LightApp_SelectionMgr* mgr = selectionMgr();
776 mgr->selectedObjects( aList, QString(), false );
778 if( aList.IsEmpty() )
781 _PTR(Study) aStudyDS = getStudy();
782 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
785 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
786 if ( it.Value()->hasEntry() )
788 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
789 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
792 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
793 aStudyBuilder->RemoveReference( aSObject );
795 updateObjectBrowser();
799 void SalomeApp_Application::onOpenWith()
801 QApplication::setOverrideCursor( Qt::WaitCursor );
803 LightApp_SelectionMgr* mgr = selectionMgr();
804 mgr->selectedObjects(aList);
805 if (aList.Extent() != 1)
807 QApplication::restoreOverrideCursor();
810 Handle(SALOME_InteractiveObject) aIObj = aList.First();
811 QString aModuleName(aIObj->getComponentDataType());
812 QString aModuleTitle = moduleTitle(aModuleName);
813 if (aModuleTitle.isEmpty()) // no gui
814 aModuleTitle = moduleDisplayer(aModuleName);
815 activateModule(aModuleTitle);
816 QApplication::restoreOverrideCursor();
822 SUIT_Study* SalomeApp_Application::createNewStudy()
824 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
826 // Set up processing of major study-related events
827 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
828 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
829 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
830 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
832 #ifndef DISABLE_PYCONSOLE
833 //to receive signal in application that NoteBook's variable was modified
834 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
835 this, SIGNAL(notebookVarUpdated(QString)) );
844 Enable/Disable menu items and toolbar buttons. Rebuild menu
846 void SalomeApp_Application::updateCommandsStatus()
848 LightApp_Application::updateCommandsStatus();
851 QAction* a = action( DumpStudyId );
853 a->setEnabled( activeStudy() );
855 #ifndef DISABLE_PYCONSOLE
857 a = action( LoadScriptId );
859 a->setEnabled( pythonConsole() );
863 a = action( PropertiesId );
865 a->setEnabled( activeStudy() );
867 // Save GUI state menu
868 a = action( SaveGUIStateId );
870 a->setEnabled( activeStudy() );
872 // Connect study menu
873 a = action( ConnectId );
875 a->setEnabled( !activeStudy() );
877 // Disconnect study menu
878 a = action( DisconnectId );
880 a->setEnabled( activeStudy() );
882 // update state of Copy/Paste menu items
883 onSelectionChanged();
887 \class DumpStudyFileDlg
888 Private class used in Dump Study operation. Consists 2 check boxes:
889 "Publish in study" and "Save GUI parameters"
891 class DumpStudyFileDlg : public SUIT_FileDlg
894 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
896 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
899 QWidget *hB = new QWidget( this );
900 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
901 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
902 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
904 QHBoxLayout *layout = new QHBoxLayout;
905 layout->addWidget(myPublishChk);
906 layout->addWidget(myMultiFileChk);
907 layout->addWidget(mySaveGUIChk);
908 hB->setLayout(layout);
910 QPushButton* pb = new QPushButton(this);
912 int row = grid->rowCount();
913 grid->addWidget( new QLabel("", this), row, 0 );
914 grid->addWidget( hB, row, 1, 1, 3 );
915 grid->addWidget( pb, row, 5 );
920 QCheckBox* myPublishChk;
921 QCheckBox* myMultiFileChk;
922 QCheckBox* mySaveGUIChk;
925 /*!Private SLOT. On dump study.*/
926 void SalomeApp_Application::onDumpStudy( )
928 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
929 if ( !appStudy ) return;
931 QStringList aFilters;
932 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
934 bool anIsPublish = true;
935 bool anIsMultiFile = false;
936 bool anIsSaveGUI = true;
938 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
939 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
940 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
941 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
944 DumpStudyFileDlg fd( desktop() );
945 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
946 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
947 fd.setNameFilters( aFilters );
948 fd.myPublishChk->setChecked( anIsPublish );
949 fd.myMultiFileChk->setChecked( anIsMultiFile );
950 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
951 if ( fd.exec() == QDialog::Accepted )
953 QString aFileName = fd.selectedFile();
955 bool toPublish = fd.myPublishChk->isChecked();
956 bool isMultiFile = fd.myMultiFileChk->isChecked();
957 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
959 if ( !aFileName.isEmpty() ) {
960 QFileInfo aFileInfo(aFileName);
961 if( aFileInfo.isDir() ) // IPAL19257
964 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
967 SUIT_OverrideCursor wc;
968 ensureShaperIsActivated();
969 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
972 SUIT_MessageBox::warning( desktop(),
973 QObject::tr("WRN_WARNING"),
974 tr("WRN_DUMP_STUDY_FAILED") );
979 /*!Private SLOT. On load script.*/
980 void SalomeApp_Application::onLoadScript( )
982 if ( getStudy()->GetProperties()->IsLocked() ) {
983 SUIT_MessageBox::warning( desktop(),
984 QObject::tr("WRN_WARNING"),
985 QObject::tr("WRN_STUDY_LOCKED") );
989 QStringList filtersList;
990 filtersList.append(tr("PYTHON_FILES_FILTER"));
991 filtersList.append(tr("ALL_FILES_FILTER"));
993 QString anInitialPath = "";
994 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
995 anInitialPath = QDir::currentPath();
997 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
999 if ( !aFile.isEmpty() )
1002 QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile);
1004 #ifndef DISABLE_PYCONSOLE
1005 PyConsole_Console* pyConsole = pythonConsole();
1008 pyConsole->exec( command );
1013 /*!Private SLOT. On save GUI state.*/
1014 void SalomeApp_Application::onSaveGUIState()
1016 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1018 SalomeApp_VisualState( this ).storeState();
1019 updateSavePointDataObjects( study );
1020 updateObjectBrowser();
1025 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1026 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1028 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1029 QAction* send = ::qobject_cast<QAction*>( sender() );
1032 QString aWinName = send->data().toString();
1033 if ( theIsVisible && aWinName == "objectBrowser" )
1034 objectBrowserColumnsVisibility();
1038 QWidget* SalomeApp_Application::createWindow( const int flag )
1041 #ifndef DISABLE_PYCONSOLE
1042 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1044 wid = LightApp_Application::createWindow(flag);
1047 SUIT_ResourceMgr* resMgr = resourceMgr();
1049 if ( flag == WT_ObjectBrowser )
1051 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1053 // temporary commented
1054 //ob->setUpdater( new SalomeApp_Updater() );
1056 #ifdef WITH_SALOMEDS_OBSERVER
1057 //do not activate the automatic update of Qt tree through signal/slot
1058 ob->setAutoUpdate(false);
1059 //activate update of modified objects only
1060 ob->setUpdateModified(true);
1063 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1066 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1067 IORCol = QObject::tr( "IOR_COLUMN" ),
1068 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1069 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1071 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1072 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1073 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1074 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1075 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1076 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1077 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1078 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1079 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1081 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1082 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1083 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1085 ob->setAutoSizeFirstColumn(autoSizeFirst);
1086 ob->setAutoSizeColumns(autoSize);
1087 ob->setResizeOnExpandItem(resizeOnExpandItem);
1088 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1090 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1092 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1093 ob->treeView()->setColumnHidden( i, !shown );
1096 // temporary commented
1098 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1100 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1101 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1102 QString().sprintf( "visibility_column_%d", i ), true ) );
1106 // temporary commented
1108 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1109 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1110 ob->resize( desktop()->width()/3, ob->height() );
1114 #ifndef DISABLE_PYCONSOLE
1115 else if ( flag == WT_PyConsole )
1117 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1118 pyCons->setObjectName( "pythonConsole" );
1119 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1120 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1121 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1122 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1123 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1126 else if ( flag == WT_NoteBook )
1128 setNoteBook( new SalomeApp_NoteBook( desktop() ) );
1129 //to receive signal in NoteBook that it's variable was modified
1130 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1131 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1133 wid = getNoteBook();
1134 wid->setObjectName( "noteBook" );
1140 /*!Create preferences.*/
1141 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1143 LightApp_Application::createPreferences(pref);
1148 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1149 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1150 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1151 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1153 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1154 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1156 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1158 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1159 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1160 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1161 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1162 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1163 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1164 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1165 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1166 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1167 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1170 /*!Update desktop title.*/
1171 void SalomeApp_Application::updateDesktopTitle() {
1172 QString aTitle = applicationName();
1173 QString aVer = applicationVersion();
1174 if ( !aVer.isEmpty() )
1175 aTitle += QString( " " ) + aVer;
1177 if ( activeStudy() )
1179 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1180 if ( !sName.isEmpty() ) {
1181 if ( getStudy()->GetProperties()->IsLocked() ) {
1182 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1184 aTitle += QString( " - [%1]" ).arg( sName );
1189 desktop()->setWindowTitle( aTitle );
1192 int SalomeApp_Application::closeChoice( const QString& /*docName*/ )
1194 QStringList buttons;
1195 QMap<int, int> choices;
1197 buttons << tr ("APPCLOSE_SAVE"); // Save & Clear
1198 choices.insert( idx++, CloseSave ); // ...
1199 buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving
1200 choices.insert( idx++, CloseDiscard ); // ...
1201 if ( myIsCloseFromExit ) {
1202 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1203 choices.insert( idx++, CloseDisconnectSave ); // ...
1204 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1205 choices.insert( idx++, CloseDisconnect ); // ...
1207 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1208 choices.insert( idx++, CloseCancel ); // ...
1210 if( !activeStudy()->isModified() )
1212 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1213 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1214 return choices[answer];
1217 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1223 if ( activeStudy()->isSaved() )
1225 else if ( !onSaveAsDoc() )
1230 case CloseDisconnectSave:
1231 if ( activeStudy()->isSaved() )
1233 else if ( !onSaveAsDoc() )
1236 case CloseDisconnect:
1237 closeActiveDoc( false );
1238 closePermanently = false;
1247 int SalomeApp_Application::openChoice( const QString& aName )
1249 int choice = LightApp_Application::openChoice( aName );
1251 if ( QFileInfo( aName ).exists() ) {
1252 if ( choice == OpenNew ) { // The document isn't already open.
1254 if ( aName == getStudy()->Name().c_str() )
1256 // The document already exists in the study.
1257 // Do you want to reload it?
1259 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1260 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1261 if ( answer == SUIT_MessageBox::Yes )
1262 choice = OpenRefresh;
1264 choice = OpenCancel;
1267 } else { // file is not exist on disk
1268 SUIT_MessageBox::warning( desktop(),
1269 QObject::tr("WRN_WARNING"),
1270 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data()));
1277 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1280 int choice = aChoice;
1287 res = LightApp_Application::openAction( choice, aName );
1295 \brief Get map of the operations which can be performed
1296 on the module activation.
1298 The method should return the map of the kind \c {<id>:<name>}
1299 where \c <id> is an integer identifier of the operation and
1300 \c <name> is a title for the button to be added to the
1301 dialog box. After user selects the required operation by the
1302 clicking the corresponding button in the dialog box, its identifier
1303 is passed to the moduleActionSelected() method to process
1306 \return map of the operations
1307 \sa moduleActionSelected()
1309 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1311 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1313 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1315 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1320 \brief Called when the used selectes required operation chosen
1321 from "Activate module" dialog box.
1323 Performs the required operation according to the user choice.
1325 \param id operation identifier
1326 \sa activateModuleActions()
1328 void SalomeApp_Application::moduleActionSelected( const int id )
1334 case NewAndScriptId:
1338 LightApp_Application::moduleActionSelected( id );
1343 /*!Gets CORBA::ORB_var*/
1344 CORBA::ORB_var SalomeApp_Application::orb()
1346 static CORBA::ORB_var _orb;
1348 if ( CORBA::is_nil( _orb ) ) {
1349 Qtx::CmdLineArgs args;
1350 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1351 _orb = init( args.argc(), args.argv() );
1357 /*!Create and return SALOMEDS_Study.*/
1358 _PTR(Study) SalomeApp_Application::getStudy()
1360 static _PTR(Study) _study;
1362 CORBA::Object_var aSObject = namingService()->Resolve("/Study");
1363 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject);
1364 _study = ClientFactory::Study(aStudy);
1369 /*!Create and return SALOME_NamingService.*/
1370 SALOME_NamingService_Abstract *SalomeApp_Application::namingService()
1375 /*!Create and return SALOME_LifeCycleCORBA.*/
1376 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1378 static SALOME_LifeCycleCORBA _lcc( namingService() );
1382 /*!Private SLOT. On preferences.*/
1383 void SalomeApp_Application::onProperties()
1385 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1389 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1392 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1393 int res = aDlg.exec();
1394 if( res==QDialog::Accepted && aDlg.isChanged() )
1395 SB->CommitCommand();
1399 //study->updateCaptions();
1400 updateDesktopTitle();
1404 /*!Insert items in popup, which necessary for current application*/
1405 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1407 LightApp_SelectionMgr* mgr = selectionMgr();
1408 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1409 mgr->setSelectionCacheEnabled( true );
1411 LightApp_Application::contextMenuPopup( type, thePopup, title );
1413 // temporary commented
1414 /*OB_Browser* ob = objectBrowser();
1415 if ( !ob || type != ob->popupClientType() )
1418 // Get selected objects
1419 SALOME_ListIO aList;
1420 mgr->selectedObjects( aList, QString(), false );
1422 // add GUI state commands: restore, rename
1423 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1424 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1425 thePopup->addSeparator();
1426 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1427 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1428 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1429 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1432 // "Delete reference" item should appear only for invalid references
1434 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1435 bool isInvalidRefs = false;
1437 _PTR(SObject) anObj;
1438 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1440 if( it.Value()->hasEntry() )
1442 _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1443 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1446 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1447 isInvalidRefs = true;
1451 // Add "Delete reference" item to popup
1452 if ( isInvalidRefs )
1454 thePopup->addSeparator();
1455 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1459 // "Activate module" item should appear only if it's necessary
1460 if ( aList.Extent() == 1 ) {
1462 mgr->selectedObjects( aList );
1464 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1466 // add extra popup menu (defined in XML)
1467 if ( myExtActions.size() > 0 ) {
1468 // Use only first selected object
1469 _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() );
1471 _PTR( GenericAttribute ) anAttr;
1472 std::string auid = "AttributeUserID";
1473 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1474 if ( aSO->FindAttribute( anAttr, auid ) ) {
1475 _PTR(AttributeUserID) aAttrID = anAttr;
1476 QString aId = aAttrID->Value().c_str();
1477 if ( myExtActions.contains( aId ) ) {
1478 thePopup->addAction(myExtActions[aId]);
1484 // check if item is a "GUI state" item (also a first level object)
1485 QString entry( aIObj->getEntry() );
1486 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1487 QString aModuleName( aIObj->getComponentDataType() );
1488 QString aModuleTitle = moduleTitle( aModuleName );
1489 if (aModuleTitle.isEmpty()) {
1490 // use displayer module, if given
1491 aModuleTitle = moduleDisplayer( aModuleName );
1493 CAM_Module* currentModule = activeModule();
1494 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() ) {
1495 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1500 mgr->setSelectionCacheEnabled( cacheIsOn );
1503 /*!Update obect browser:
1504 1.if 'updateModels' true, update existing data models;
1505 2. update "non-existing" (not loaded yet) data models;
1506 3. update object browser if it exists */
1507 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1509 // update "non-existing" (not loaded yet) data models
1510 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1513 for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() )
1515 _PTR(SComponent) aComponent ( it->Value() );
1517 #ifndef WITH_SALOMEDS_OBSERVER
1518 // with GUI observers this check is not needed anymore
1519 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1520 continue; // skip the magic "Interface Applicative" component
1522 if ( !objectBrowser() )
1523 getWindow( WT_ObjectBrowser );
1524 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1525 objectBrowser()->setAutoUpdate( false );
1526 SalomeApp_DataModel::synchronize( aComponent, study );
1527 objectBrowser()->setAutoUpdate( isAutoUpdate );
1531 // create data objects that correspond to GUI state save points
1532 if ( study ) updateSavePointDataObjects( study );
1534 // update existing data models (already loaded SComponents)
1535 LightApp_Application::updateObjectBrowser( updateModels );
1538 /*!Display Catalog Genenerator dialog */
1539 void SalomeApp_Application::onCatalogGen()
1541 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1545 /*!Display Registry Display dialog */
1546 void SalomeApp_Application::onRegDisplay()
1548 CORBA::ORB_var anOrb = orb();
1549 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1552 regWnd->activateWindow();
1555 /*!find original object by double click on item */
1556 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1558 // Issue 21379: References are supported at LightApp_DataObject level
1559 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1561 if( obj && obj->isReference() )
1563 QString entry = obj->refEntry();
1565 SUIT_DataOwnerPtrList aList;
1566 aList.append( new LightApp_DataOwner( entry ) );
1567 selectionMgr()->setSelected( aList, false );
1569 SUIT_DataBrowser* ob = objectBrowser();
1571 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1572 if ( !aSelectedIndexes.isEmpty() )
1573 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1575 emit objectDoubleClicked( theObj );
1579 Creates new view manager
1580 \param type - type of view manager
1582 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1584 return createViewManager(type);
1588 /*!Global utility function, returns selected GUI Save point object's ID */
1589 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1591 SALOME_ListIO aList;
1592 selMgr->selectedObjects( aList );
1593 if( aList.Extent() > 0 ) {
1594 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1595 QString entry( aIObj->getEntry() );
1596 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1597 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1599 bool ok; // conversion to integer is ok?
1600 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1601 return ok ? savePoint : -1;
1606 /*!Called on Restore GUI State popup command*/
1607 void SalomeApp_Application::onRestoreGUIState()
1609 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1610 if ( savePoint == -1 )
1612 SalomeApp_VisualState( this ).restoreState( savePoint );
1615 /*!Called on Delete GUI State popup command*/
1616 void SalomeApp_Application::onDeleteGUIState()
1618 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1619 if ( savePoint == -1 )
1621 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1625 study->removeSavePoint( savePoint );
1626 updateSavePointDataObjects( study );
1629 /*!Called on New study operation*/
1630 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1632 LightApp_Application::onStudyCreated( study );
1634 //#ifndef DISABLE_PYCONSOLE
1635 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1636 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1639 loadDockWindowsState();
1641 objectBrowserColumnsVisibility();
1644 /*!Called on Open study operation*/
1645 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1647 LightApp_Application::onStudyOpened( study );
1649 //#ifndef DISABLE_PYCONSOLE
1650 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1651 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1654 loadDockWindowsState();
1656 objectBrowserColumnsVisibility();
1658 // temporary commented
1659 /*if ( objectBrowser() ) {
1660 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1661 objectBrowser()->updateTree( study->root() );
1665 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1666 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1669 SUIT_DataBrowser* ob = objectBrowser();
1670 LightApp_SelectionMgr* selMgr = selectionMgr();
1672 if ( !study || !ob || !selMgr )
1675 // find GUI states root object
1676 SUIT_DataObject* guiRootObj = 0;
1678 study->root()->children( ch );
1679 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1680 for ( ; it != last ; ++it ) {
1681 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1686 std::vector<int> savePoints = study->getSavePoints();
1687 // case 1: no more save points but they existed in study's tree
1688 if ( savePoints.empty() && guiRootObj ) {
1689 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1690 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1691 const bool isAutoUpdate = ob->autoUpdate();
1692 selMgr->clearSelected();
1693 ob->setAutoUpdate(true);
1694 DataObjectList ch = guiRootObj->children();
1695 for( int i = 0; i < ch.size(); i++ )
1698 ob->setAutoUpdate(isAutoUpdate);
1701 // case 2: no more save points but root does not exist either
1702 if ( savePoints.empty() && !guiRootObj )
1704 // case 3: save points but no root for them - create it
1705 if ( !savePoints.empty() && !guiRootObj )
1706 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1707 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1708 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1710 if ( guiRootObj->nextBrother() ) {
1711 study->root()->removeChild(guiRootObj);
1712 study->root()->appendChild(guiRootObj);
1713 //study->root()->dump();
1716 // store data objects in a map id-to-DataObject
1717 QMap<int,SalomeApp_SavePointObject*> mapDO;
1719 guiRootObj->children( ch );
1720 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1721 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1723 mapDO[dobj->getId()] = dobj;
1726 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1727 // if in the map - remove it from map.
1728 for ( size_t i = 0; i < savePoints.size(); i++ )
1729 if ( !mapDO.contains( savePoints[i] ) )
1730 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1732 mapDO.remove( savePoints[i] );
1734 // delete DataObjects that are still in the map -- their IDs were not found in data model
1735 if( mapDO.size() > 0) {
1736 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1737 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1738 selMgr->clearSelected();
1739 const bool isAutoUpdate = ob->autoUpdate();
1740 ob->setAutoUpdate(true);
1741 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1743 ob->setAutoUpdate(isAutoUpdate);
1747 /*! Check data object */
1748 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1757 Opens other study into active Study. If Study is empty - creates it.
1758 \param theName - name of study
1760 bool SalomeApp_Application::useStudy( const QString& theName )
1763 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1766 res = aStudy->loadDocument( theName );
1767 updateDesktopTitle();
1768 updateCommandsStatus();
1772 /*! Show/hide object browser colums according to preferences */
1773 void SalomeApp_Application::objectBrowserColumnsVisibility()
1775 if ( objectBrowser() )
1776 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1778 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1779 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1783 #ifndef DISABLE_PYCONSOLE
1784 /*! Set SalomeApp_NoteBook pointer */
1785 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1787 myNoteBook = theNoteBook;
1790 /*! Return SalomeApp_NoteBook pointer */
1791 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1798 * Define extra actions defined in module definition XML file.
1799 * Additional popup items sections can be defined by parameter "popupitems".
1800 * Supported attributes:
1801 * title - title of menu item,
1802 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1803 * method - method which has to be called when menu item is selected
1805 * <section name="MODULENAME">
1806 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1808 * <section name="importmed">
1809 * <parameter name="title" value="My menu"/>
1810 * <parameter name="objectid" value="VISU.Result"/>
1811 * <parameter name="method" value="nameOfModuleMethod"/>
1814 void SalomeApp_Application::createExtraActions()
1816 myExtActions.clear();
1817 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1819 QStringList aModules;
1820 modules(aModules, false);
1821 foreach(QString aModile, aModules) {
1822 QString aModName = moduleName(aModile);
1823 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1824 if (!aSectionStr.isNull()) {
1825 QStringList aSections = aSectionStr.split(':');
1826 foreach(QString aSection, aSections) {
1827 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1828 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1829 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1830 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1833 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1834 if (aModuleName.isNull())
1835 aModuleName = aModName;
1837 QAction* aAction = new QAction(aTitle, this);
1839 aData<<aModuleName<<aSlot;
1840 aAction->setData(aData);
1841 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1842 myExtActions[aId] = aAction;
1849 * Called when extra action is selected
1851 void SalomeApp_Application::onExtAction()
1853 QAction* aAction = ::qobject_cast<QAction*>(sender());
1857 QVariant aData = aAction->data();
1858 QStringList aDataList = aData.value<QStringList>();
1859 if (aDataList.size() != 2)
1862 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1863 SALOME_ListIO aListIO;
1864 aSelectionMgr->selectedObjects(aListIO);
1865 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1866 if (aListIO.Extent() < 1)
1868 if (!anIO->hasEntry())
1871 QString aEntry(anIO->getEntry());
1873 QApplication::setOverrideCursor( Qt::WaitCursor );
1874 QString aModuleTitle = moduleTitle(aDataList[0]);
1875 activateModule(aModuleTitle);
1876 QApplication::restoreOverrideCursor();
1878 QCoreApplication::processEvents();
1880 CAM_Module* aModule = activeModule();
1884 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1885 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1889 Checks that an object can be renamed.
1890 \param entry entry of the object
1891 \brief Return \c true if object can be renamed
1893 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1895 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1899 Rename object by entry.
1900 \param entry entry of the object
1901 \param name new name of the object
1902 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1904 bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name )
1906 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1908 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1910 if(!aStudy || savePoint == -1)
1913 if ( !name.isNull() && !name.isEmpty() ) {
1914 aStudy->setNameOfSavePoint( savePoint, name );
1915 updateSavePointDataObjects( aStudy );
1917 //Mark study as modified
1924 #ifndef DISABLE_PYCONSOLE
1925 //============================================================================
1926 /*! Function : onUpdateStudy
1927 * Purpose : Slot to update the study.
1929 //============================================================================
1930 void SalomeApp_Application::onUpdateStudy()
1932 QApplication::setOverrideCursor( Qt::WaitCursor );
1934 if( !updateStudy() )
1935 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1937 QApplication::restoreOverrideCursor();
1940 //============================================================================
1941 /*! Function : updateStudy
1942 * Purpose : Update study by dumping the study to Python script and loading it.
1943 * It is used to apply variable modifications done in NoteBook to created objects.
1945 //============================================================================
1946 bool SalomeApp_Application::updateStudy()
1948 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1949 if ( !study || !myNoteBook )
1952 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1953 myNoteBook->setDumpedStudyName( study->studyName() );
1955 // get unique temporary directory name
1956 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1958 if( aTmpDir.isEmpty() )
1961 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1962 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1964 // dump study to the temporary directory
1965 QString aScriptName( "notebook" );
1966 bool toPublish = true;
1967 bool isMultiFile = false;
1968 bool toSaveGUI = true;
1971 _PTR(AttributeParameter) ap;
1972 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1973 if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag.
1974 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1975 ip->setDumpPython();
1976 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1978 bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1980 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1983 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1987 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1988 int anIndex = aList.indexOf( this );
1990 // Disconnect dialog from application desktop in case if:
1991 // 1) Application is not the first application in the session
1992 // 2) Application is the first application in session but not the only.
1993 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1994 if( changeDesktop ) {
1996 SalomeApp_Application* app = this;
1997 if( anIndex > 0 && anIndex < aList.count() )
1998 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1999 else if(anIndex == 0 && aList.count() > 1)
2000 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2005 // creation a new study and restoring will be done in another application
2006 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2007 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2010 QString aDumpScript = myNoteBook->getDumpedStudyScript();
2011 QString aStudyName = myNoteBook->getDumpedStudyName();
2012 bool isStudySaved = myNoteBook->isDumpedStudySaved();
2013 // clear a study (delete all objects)
2014 onCloseDoc( false );
2016 if( !changeDesktop ) {
2017 ok = onRestoreStudy( aDumpScript,
2026 //============================================================================
2027 /*! Function : onRestoreStudy
2028 * Purpose : Load the dumped study from Python script
2030 //============================================================================
2031 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2032 const QString& theStudyName,
2033 bool theIsStudySaved )
2037 // create a new study
2040 // get active application
2041 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2043 // load study from the temporary directory
2044 QFileInfo aScriptInfo = QFileInfo(theDumpScript);
2045 QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath());
2047 #ifndef DISABLE_PYCONSOLE
2048 PyConsole_Console* pyConsole = app->pythonConsole();
2050 pyConsole->execAndWait( command );
2053 // remove temporary directory
2054 QString aStudyName = aScriptInfo.baseName();
2055 QDir aDir = aScriptInfo.absoluteDir();
2056 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2057 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2058 ok = aDir.remove( *it ) && ok;
2060 ok = aDir.rmdir( aDir.absolutePath() );
2062 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2064 #ifndef DISABLE_PYCONSOLE
2065 if ( app->getNoteBook() )
2066 app->getNoteBook()->Init();
2067 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2068 newStudy->Modified();
2069 updateDesktopTitle();
2080 Close the Application
2082 void SalomeApp_Application::afterCloseDoc()
2084 #ifndef DISABLE_PYCONSOLE
2085 // emit signal to restore study from Python script
2087 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2088 myNoteBook->getDumpedStudyName(),
2089 myNoteBook->isDumpedStudySaved() );
2092 LightApp_Application::afterCloseDoc();
2095 bool SalomeApp_Application::canOpenDoc( const QString& url )
2097 _PTR(Study) aStudyDS = getStudy();
2099 return aStudyDS->CanOpen( url.toUtf8().data() );
2104 Asks to close existing document.
2106 bool SalomeApp_Application::checkExistingDoc()
2108 return LightApp_Application::checkExistingDoc();
2112 #ifndef DISABLE_PYCONSOLE
2114 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2116 return new SalomeApp_PyInterp;
2119 #endif // DISABLE_PYCONSOLE
2121 void SalomeApp_Application::ensureShaperIsActivated()
2123 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
2124 _PTR(Study) studyDS = getStudy();
2125 if ( study && studyDS )
2127 _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study
2128 bool shaperIsActive = false;
2129 QList<CAM_DataModel*> models;
2130 study->dataModels( models );
2131 for( int i = 0; i < models.count() && !shaperIsActive; i++ )
2132 shaperIsActive = models[i]->module()->moduleName() == "Shaper";
2134 if (shaper && !shaperIsActive)
2135 onDesktopMessage("register_module_in_study/Shaper");