1 // Copyright (C) 2007-2024 CEA, EDF, 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>
76 #include <QtxFeatureSearch.h>
78 #include <SALOME_EventFilter.h>
80 // temporary commented
81 //#include <OB_ListItem.h>
84 #include <SALOME_LifeCycleCORBA.hxx>
86 #include <QApplication>
91 #include <QPushButton>
93 #include <QListWidget>
94 #include <QGridLayout>
98 #include <SALOMEDSClient_ClientFactory.hxx>
99 #include <ArgvKeeper.hxx>
100 #include <Basics_Utils.hxx>
101 #include <OpUtil.hxx>
103 #include <SALOME_ListIO.hxx>
104 #include <SALOME_Prs.h>
107 #include <ToolsGUI_CatalogGeneratorDlg.h>
108 #include <ToolsGUI_RegWidget.h>
113 #include <SALOMEDS_Tool.hxx>
115 #include <SALOMEconfig.h>
116 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
118 std::unique_ptr<SALOME_NamingService_Abstract> SalomeApp_Application::_ns;
120 /*!Internal class that updates object browser item properties */
121 // temporary commented
122 /*class SalomeApp_Updater : public OB_Updater
125 SalomeApp_Updater() : OB_Updater(){};
126 virtual ~SalomeApp_Updater(){};
127 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
130 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
132 if( !theObj || !theItem )
135 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
139 _PTR(SObject) SObj = SAObj->object();
142 _PTR( GenericAttribute ) anAttr;
145 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
147 _PTR(AttributeSelectable) aAttrSel = anAttr;
148 theItem->setSelectable( aAttrSel->IsSelectable() );
151 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
153 _PTR(AttributeExpandable) aAttrExpand = anAttr;
154 theItem->setExpandable( aAttrExpand->IsExpandable() );
157 //this attribute is not supported in the version of SALOME 3.x
158 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
160 // _PTR(AttributeOpened) aAttrOpen = anAttr;
161 // theItem->setOpen( aAttrOpen->IsOpened() );
173 //! Constructor. Sets passed boolean flag to \c true.
174 MessageLocker( bool& Lock ) : myPrevState( Lock ), myLock( Lock ) { myLock = true; }
175 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
176 ~MessageLocker() { myLock = myPrevState; }
179 bool& myLock; //! External 'Lock state' boolean flag
183 \brief Dynamic property manager
190 PropertyMgr(QObject* object, const QString& property, const QVariant& value)
191 : myObject(object), myProperty(property)
193 myObject->setProperty(qPrintable(myProperty), value);
197 myObject->setProperty(qPrintable(myProperty), QVariant());
203 SalomeApp_Application::SalomeApp_Application(SALOME_NamingService_Abstract *ns):myIsCloseFromExit( false ),myToIgnoreMessages( false )
206 _ns.reset(new SALOME_NamingService(orb()));
212 *\li Destroy event filter.
214 SalomeApp_Application::~SalomeApp_Application()
216 // Do not destroy. It's a singleton !
217 //SALOME_EventFilter::Destroy();
220 QStringList __getArgsList(QString argsString)
222 // Special process if some items of 'args:' list are themselves lists
223 // Note that an item can be a list, but not a list of lists...
224 // So we can have something like this:
225 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
226 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
227 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
228 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
229 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
231 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
236 return argsString.split(",", QString::SkipEmptyParts);
239 /*!Start application.*/
240 void SalomeApp_Application::start()
242 // process the command line options before start: to createActions in accordance to the options
243 static bool isFirst = true;
250 QStringList args = QApplication::arguments();
251 for (int i = 1; i < args.count(); i++) {
252 QRegExp rxs ("--study-hdf=(.+)");
253 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
254 QString file = rxs.capturedTexts()[1];
255 QFileInfo fi ( file );
256 QString extension = fi.suffix().toLower();
257 if ( extension == "hdf" && fi.exists() )
258 hdffile = fi.absoluteFilePath();
261 QRegExp rxp ("--pyscript=\\[(.+)\\]");
262 if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
264 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
265 for (int k = 0; k < dictList.count(); ++k) {
266 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
267 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
268 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
269 pyfiles += rxd.capturedTexts()[m];
276 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
277 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
279 LightApp_Application::start();
280 SALOME_EventFilter::Init();
282 if ( !hdffile.isEmpty() )
284 // open hdf file given as parameter
285 PropertyMgr propm( this, "open_study_from_command_line", true );
286 onOpenDoc( hdffile );
289 #ifndef DISABLE_PYCONSOLE
290 // import/execute python scripts
291 if ( pyfiles.count() > 0 && activeStudy() ) {
292 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
293 PyConsole_Console* pyConsole = pythonConsole();
294 if ( appStudy && pyConsole ) {
295 if ( !getStudy()->GetProperties()->IsLocked() ) {
296 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
297 // Path is absolute, script has .py extension
298 for (int j = 0; j < pyfiles.count(); j++ ) {
299 // Extract scripts and their arguments, if any
300 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
301 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
302 QString script = rxp.capturedTexts()[1];
304 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
305 for (int k = 0; k < argList.count(); k++ ) {
306 QString arg = argList[k].trimmed();
307 arg.remove( QRegExp("^[\"]") );
308 arg.remove( QRegExp("[\"]$") );
309 args << QString("\"%1\"").arg(arg);
311 if (args.count() == 1)
314 script.remove( QRegExp("^python.*[\\s]+") );
315 QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(","));
316 PropertyMgr propm( this, "IsLoadedScript", true );
317 pyConsole->exec(command);
319 } // end for loop on pyfiles QStringList
325 LightApp_Application::start();
326 SALOME_EventFilter::Init();
331 void SalomeApp_Application::createActions()
333 LightApp_Application::createActions();
335 SUIT_Desktop* desk = desktop();
338 // "Save GUI State" command is moved to VISU module
339 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
340 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
341 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
344 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
345 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
346 QKeySequence::UnknownKey, desk, false, this, SLOT( onDumpStudy() ), "/PRP_DESK_FILE_DUMP_STUDY" );
349 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
350 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
351 QKeySequence::UnknownKey, desk, false, this, SLOT( onLoadScript() ), "/PRP_DESK_FILE_LOAD_SCRIPT" );
354 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
355 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
356 0, desk, false, this, SLOT( onProperties() ) );
358 //! Catalog Generator
359 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
360 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
361 QKeySequence::UnknownKey, desk, false, this, SLOT( onCatalogGen() ), "/PRP_DESK_CATALOG_GENERATOR" );
364 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
365 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
366 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
368 //! Find action dialog
369 createAction( FindActionId, tr( "TOT_DESK_FIND_ACTION" ), QIcon(),
370 tr( "MEN_DESK_FIND_ACTION" ), tr( "PRP_DESK_FIND_ACTION" ),
371 QKeySequence::UnknownKey, desk, false, this, SLOT( onFindAction() ), "/PRP_DESK_FIND_ACTION" );
373 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
374 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
375 QKeySequence::UnknownKey, desk, false, this, SLOT( onLoadDoc() ), "/PRP_DESK_CONNECT" );
376 //no need at this action for mono-study application because study is always exists
377 action( ConnectId )->setVisible( false );
379 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
380 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
381 QKeySequence::UnknownKey, desk, false, this, SLOT( onUnloadDoc() ), "/PRP_DESK_DISCONNECT" );
382 //no need at this action for mono-study application because study is always exists
383 action( DisconnectId )->setVisible( false );
386 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
388 // "Save GUI State" command is renamed to "Save VISU State" and
389 // creation of menu item is moved to VISU
390 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
392 createMenu( ConnectId, fileMenu, 5 );
393 createMenu( DisconnectId, fileMenu, 5 );
394 createMenu( separator(), fileMenu, -1, 5 );
396 createMenu( DumpStudyId, fileMenu, 10, -1 );
397 createMenu( LoadScriptId, fileMenu, 10, -1 );
398 createMenu( separator(), fileMenu, -1, 10, -1 );
399 createMenu( PropertiesId, fileMenu, 10, -1 );
400 createMenu( separator(), fileMenu, -1, 10, -1 );
402 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
403 createMenu( CatalogGenId, toolsMenu, 10, -1 );
404 createMenu( RegDisplayId, toolsMenu, 10, -1 );
405 createMenu( FindActionId, toolsMenu, 10, -1 );
406 createMenu( separator(), toolsMenu, -1, 15, -1 );
408 createExtraActions();
410 #ifndef DISABLE_PYCONSOLE
411 #ifndef DISABLE_SALOMEOBJECT
412 // import Python module that manages SALOME plugins
414 PyLockWrapper lck; // acquire GIL
415 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
416 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
420 // end of SALOME plugins loading
427 \brief Close application.
429 void SalomeApp_Application::onExit()
431 //MessageLocker ml( myToIgnoreMessages );
433 bool killServers = false;
436 if ( exitConfirmation() ) {
437 SalomeApp_ExitDlg dlg( desktop() );
438 result = dlg.exec() == QDialog::Accepted;
439 killServers = dlg.isServersShutdown();
443 if ( !killServers ) myIsCloseFromExit = true;
444 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
445 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
449 /*!SLOT. Create a document.*/
450 void SalomeApp_Application::onNewDoc()
452 MessageLocker ml( myToIgnoreMessages );
454 LightApp_Application::onNewDoc();
457 /*!SLOT. Load document.*/
458 void SalomeApp_Application::onLoadDoc()
460 MessageLocker ml( myToIgnoreMessages );
464 // rnv: According to the single-study approach on the server side
465 // can be only one study. So if it is exists connect to them,
466 // overwise show warning message: "No active study on the server"
469 SUIT_Session* aSession = SUIT_Session::session();
470 QList<SUIT_Application*> aAppList = aSession->applications();
472 QStringList unloadedStudies;
474 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
475 studyName = List[ind].c_str();
476 // Add to list only unloaded studies
477 bool isAlreadyOpen = false;
478 QListIterator<SUIT_Application*> it( aAppList );
479 while ( it.hasNext() && !isAlreadyOpen ) {
480 SUIT_Application* aApp = it.next();
481 if( !aApp || !aApp->activeStudy() )
483 if ( aApp->activeStudy()->studyName() == studyName )
484 isAlreadyOpen = true;
487 if ( !isAlreadyOpen )
488 unloadedStudies << studyName;
490 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
491 if ( studyName.isEmpty() )
496 SUIT_MessageBox::warning( desktop(),
497 QObject::tr("WRN_WARNING"),
498 QObject::tr("WRN_NO_STUDY_ON SERV") );
502 studyName = activeStudy()->studyName();
505 // this code replaces marker of windows drive and path become invalid therefore
506 // defines placed there
507 studyName.replace( QRegExp(":"), "/" );
510 if ( onLoadDoc( studyName ) ) {
512 updateViewManagers();
513 updateObjectBrowser( true );
517 /*!SLOT. Unload document.*/
518 void SalomeApp_Application::onUnloadDoc( bool ask )
521 activeStudy()->abortAllOperations();
522 if ( activeStudy()->isModified() ) {
523 QString docName = activeStudy()->studyName().trimmed();
524 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
525 tr( "DISCONNECT_DESCRIPTION" ),
526 tr( "DISCONNECT_SAVE" ),
527 tr( "DISCONNECT_WO_SAVE" ),
528 tr( "APPCLOSE_CANCEL" ), 0 );
529 if ( answer == 0 ) { // save before unload
530 if ( activeStudy()->isSaved() )
532 else if ( !onSaveAsDoc() )
535 else if ( answer == 2 ) // Cancel
539 closeActiveDoc( false );
542 /*!SLOT. Create new study and load script*/
543 void SalomeApp_Application::onNewWithScript()
545 QStringList filtersList;
546 filtersList.append(tr("PYTHON_FILES_FILTER"));
547 filtersList.append(tr("ALL_FILES_FILTER"));
549 QString anInitialPath = "";
550 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
551 anInitialPath = QDir::currentPath();
553 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
555 if ( !aFile.isEmpty() )
559 #ifndef DISABLE_PYCONSOLE
560 QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile);
561 PyConsole_Console* pyConsole = pythonConsole();
562 PropertyMgr propm( this, "IsLoadedScript", true );
564 pyConsole->exec( command );
570 /*!SLOT. Load document with \a aName.*/
571 bool SalomeApp_Application::onLoadDoc( const QString& aName )
573 if ( !LightApp_Application::closeDoc() )
577 if ( !activeStudy() ) {
578 // if no study - load in current desktop
579 res = useStudy( aName );
582 // if study exists - load in new desktop. Check: is the same file is loaded?
583 SUIT_Session* aSession = SUIT_Session::session();
584 QList<SUIT_Application*> aAppList = aSession->applications();
585 bool isAlreadyOpen = false;
586 SalomeApp_Application* aApp = 0;
587 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
588 it != aAppList.end() && !isAlreadyOpen; ++it ) {
589 aApp = dynamic_cast<SalomeApp_Application*>( *it );
590 if ( aApp && aApp->activeStudy()->studyName() == aName )
591 isAlreadyOpen = true;
593 if ( !isAlreadyOpen ) {
594 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
596 res = aApp->useStudy( aName );
599 aApp->desktop()->activateWindow();
606 /*!SLOT. Parse message for desktop.*/
607 void SalomeApp_Application::onDesktopMessage( const QString& message )
609 if ( myToIgnoreMessages )
610 return; // a message from SALOMEDS is caused by GUI action
612 MessageLocker ml( myToIgnoreMessages );
614 if (message.indexOf("studyCreated") == 0) {
615 if (!activeStudy()) {
617 updateCommandsStatus();
620 if (message.indexOf("studyCleared") == 0) {
621 // Disconnect GUI from active study, because it was closed on DS side.
623 closeActiveDoc( false );
624 // Disable 'Connect' action
625 QAction* a = action( ConnectId );
627 a->setEnabled( false );
630 else if ( message.toLower() == "connect_to_study" ) {
632 useStudy( activeStudy()->studyName() );
634 if (message.indexOf("studyNameChanged") == 0) {
635 updateDesktopTitle();
637 LightApp_Application::onDesktopMessage( message );
640 /*!On module activation action.*/
641 void SalomeApp_Application::onModuleActivation( const QString& modName )
643 if (!activeStudy() && !modName.isEmpty())
646 LightApp_Application::onModuleActivation( modName );
649 /*!SLOT. Copy objects to study maneger from selection maneger..*/
650 void SalomeApp_Application::onCopy()
652 LightApp_Application::onCopy();
655 LightApp_SelectionMgr* mgr = selectionMgr();
656 mgr->selectedObjects(list);
658 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
659 if(study == NULL) return;
661 _PTR(Study) stdDS = getStudy();
664 SALOME_ListIteratorOfListIO it( list );
667 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
672 onSelectionChanged();
680 /*!SLOT. Paste objects to study maneger from selection manager.*/
681 void SalomeApp_Application::onPaste()
683 LightApp_Application::onPaste();
686 LightApp_SelectionMgr* mgr = selectionMgr();
687 mgr->selectedObjects(list);
689 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
690 if(study == NULL) return;
692 _PTR(Study) stdDS = getStudy();
695 if ( stdDS->GetProperties()->IsLocked() ) {
696 SUIT_MessageBox::warning( desktop(),
697 QObject::tr("WRN_WARNING"),
698 QObject::tr("WRN_STUDY_LOCKED") );
702 SALOME_ListIteratorOfListIO it( list );
705 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
710 updateObjectBrowser( true );
711 updateActions(); //SRN: BugID IPAL9377, case 3
719 /*!Check the application on closing.
720 * \retval true if possible, else false
722 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
724 return LightApp_Application::isPossibleToClose( closePermanently );
727 /*! Check if the study is locked */
728 void SalomeApp_Application::onCloseDoc( bool ask )
730 if(getStudy()->IsStudyLocked()) {
731 if ( SUIT_MessageBox::question( desktop(),
732 QObject::tr( "WRN_WARNING" ),
733 QObject::tr( "CLOSE_LOCKED_STUDY" ),
734 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
735 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
738 MessageLocker ml( myToIgnoreMessages );
740 LightApp_Application::onCloseDoc( ask );
742 // reinitialize study to have empty data
743 //getStudy()->Init();
746 /*!SLOT. Reload document from the file.*/
747 bool SalomeApp_Application::onReopenDoc()
749 MessageLocker ml( myToIgnoreMessages );
751 return LightApp_Application::onReopenDoc();
755 /*!SLOT. Load document.*/
756 void SalomeApp_Application::onOpenDoc()
758 MessageLocker ml( myToIgnoreMessages );
760 LightApp_Application::onOpenDoc();
763 /*!SLOT. Load document.*/
764 bool SalomeApp_Application::onOpenDoc(const QString& name)
766 MessageLocker ml( myToIgnoreMessages );
768 return LightApp_Application::onOpenDoc(name);
771 /*!Sets enable or disable some actions on selection changed.*/
772 void SalomeApp_Application::onSelectionChanged()
775 LightApp_SelectionMgr* mgr = selectionMgr();
776 mgr->selectedObjects(list);
778 bool canCopy = false;
779 bool canPaste = false;
781 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
784 canCopy = m->canCopy();
785 canPaste = m->canPaste();
788 SALOME_ListIteratorOfListIO it ( list );
790 if (it.More() && list.Extent() == 1) {
791 _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry());
794 canCopy = canCopy || getStudy()->CanCopy(so);
795 canPaste = canPaste || getStudy()->CanPaste(so);
799 action(EditCopyId)->setEnabled(canCopy);
800 action(EditPasteId)->setEnabled(canPaste);
803 /*!Delete references.*/
804 void SalomeApp_Application::onDeleteInvalidReferences()
807 LightApp_SelectionMgr* mgr = selectionMgr();
808 mgr->selectedObjects( aList, QString(), false );
810 if( aList.IsEmpty() )
813 _PTR(Study) aStudyDS = getStudy();
814 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
817 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
818 if ( it.Value()->hasEntry() )
820 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
821 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
824 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
825 aStudyBuilder->RemoveReference( aSObject );
827 updateObjectBrowser();
831 void SalomeApp_Application::onOpenWith()
833 QApplication::setOverrideCursor( Qt::WaitCursor );
835 LightApp_SelectionMgr* mgr = selectionMgr();
836 mgr->selectedObjects(aList);
837 if (aList.Extent() != 1)
839 QApplication::restoreOverrideCursor();
842 Handle(SALOME_InteractiveObject) aIObj = aList.First();
843 QString aModuleName(aIObj->getComponentDataType());
844 QString aModuleTitle = moduleTitle(aModuleName);
845 if (aModuleTitle.isEmpty()) // no gui
846 aModuleTitle = moduleDisplayer(aModuleName);
847 activateModule(aModuleTitle);
848 QApplication::restoreOverrideCursor();
854 SUIT_Study* SalomeApp_Application::createNewStudy()
856 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
858 // Set up processing of major study-related events
859 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
860 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
861 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
862 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
864 #ifndef DISABLE_PYCONSOLE
865 //to receive signal in application that NoteBook's variable was modified
866 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
867 this, SIGNAL(notebookVarUpdated(QString)) );
876 Enable/Disable menu items and toolbar buttons. Rebuild menu
878 void SalomeApp_Application::updateCommandsStatus()
880 LightApp_Application::updateCommandsStatus();
883 QAction* a = action( DumpStudyId );
885 a->setEnabled( activeStudy() );
887 #ifndef DISABLE_PYCONSOLE
889 a = action( LoadScriptId );
891 a->setEnabled( pythonConsole() );
895 a = action( PropertiesId );
897 a->setEnabled( activeStudy() );
899 // Save GUI state menu
900 a = action( SaveGUIStateId );
902 a->setEnabled( activeStudy() );
904 // Connect study menu
905 a = action( ConnectId );
907 a->setEnabled( !activeStudy() );
909 // Disconnect study menu
910 a = action( DisconnectId );
912 a->setEnabled( activeStudy() );
914 // update state of Copy/Paste menu items
915 onSelectionChanged();
919 \class DumpStudyFileDlg
920 Private class used in Dump Study operation. Consists 2 check boxes:
921 "Publish in study" and "Save GUI parameters"
923 class DumpStudyFileDlg : public SUIT_FileDlg
926 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
928 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
931 QWidget *hB = new QWidget( this );
932 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
933 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
934 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
936 QHBoxLayout *layout = new QHBoxLayout;
937 layout->addWidget(myPublishChk);
938 layout->addWidget(myMultiFileChk);
939 layout->addWidget(mySaveGUIChk);
940 hB->setLayout(layout);
942 QPushButton* pb = new QPushButton(this);
944 int row = grid->rowCount();
945 grid->addWidget( new QLabel("", this), row, 0 );
946 grid->addWidget( hB, row, 1, 1, 3 );
947 grid->addWidget( pb, row, 5 );
952 QCheckBox* myPublishChk;
953 QCheckBox* myMultiFileChk;
954 QCheckBox* mySaveGUIChk;
957 /*!Private SLOT. On dump study.*/
958 void SalomeApp_Application::onDumpStudy( )
960 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
961 if ( !appStudy ) return;
963 QStringList aFilters;
964 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
966 bool anIsPublish = true;
967 bool anIsMultiFile = false;
968 bool anIsSaveGUI = true;
970 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
971 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
972 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
973 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
976 DumpStudyFileDlg fd( desktop() );
977 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
978 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
979 fd.setNameFilters( aFilters );
980 fd.myPublishChk->setChecked( anIsPublish );
981 fd.myMultiFileChk->setChecked( anIsMultiFile );
982 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
983 if ( fd.exec() == QDialog::Accepted )
985 QString aFileName = fd.selectedFile();
987 bool toPublish = fd.myPublishChk->isChecked();
988 bool isMultiFile = fd.myMultiFileChk->isChecked();
989 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
991 if ( !aFileName.isEmpty() ) {
992 QFileInfo aFileInfo(aFileName);
993 if( aFileInfo.isDir() ) // IPAL19257
996 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
999 SUIT_OverrideCursor wc;
1000 ensureShaperIsActivated();
1001 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
1004 SUIT_MessageBox::warning( desktop(),
1005 QObject::tr("WRN_WARNING"),
1006 tr("WRN_DUMP_STUDY_FAILED") );
1011 /*!Private SLOT. On load script.*/
1012 void SalomeApp_Application::onLoadScript( )
1014 if ( getStudy()->GetProperties()->IsLocked() ) {
1015 SUIT_MessageBox::warning( desktop(),
1016 QObject::tr("WRN_WARNING"),
1017 QObject::tr("WRN_STUDY_LOCKED") );
1021 QStringList filtersList;
1022 filtersList.append(tr("PYTHON_FILES_FILTER"));
1023 filtersList.append(tr("ALL_FILES_FILTER"));
1025 QString anInitialPath = "";
1026 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
1027 anInitialPath = QDir::currentPath();
1029 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
1031 if ( !aFile.isEmpty() )
1033 #ifndef DISABLE_PYCONSOLE
1034 QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile);
1035 PyConsole_Console* pyConsole = pythonConsole();
1036 PropertyMgr propm( this, "IsLoadedScript", true );
1038 pyConsole->exec(command);
1043 /*!Private SLOT. On save GUI state.*/
1044 void SalomeApp_Application::onSaveGUIState()
1046 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1048 SalomeApp_VisualState( this ).storeState();
1049 updateSavePointDataObjects( study );
1050 updateObjectBrowser();
1055 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1056 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1058 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1059 QAction* send = ::qobject_cast<QAction*>( sender() );
1062 QString aWinName = send->data().toString();
1063 if ( theIsVisible && aWinName == "objectBrowser" )
1064 objectBrowserColumnsVisibility();
1068 QWidget* SalomeApp_Application::createWindow( const int flag )
1071 #ifndef DISABLE_PYCONSOLE
1072 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1074 wid = LightApp_Application::createWindow(flag);
1077 SUIT_ResourceMgr* resMgr = resourceMgr();
1079 if ( flag == WT_ObjectBrowser )
1081 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1083 // temporary commented
1084 //ob->setUpdater( new SalomeApp_Updater() );
1086 #ifdef WITH_SALOMEDS_OBSERVER
1087 //do not activate the automatic update of Qt tree through signal/slot
1088 ob->setAutoUpdate(false);
1089 //activate update of modified objects only
1090 ob->setUpdateModified(true);
1093 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1096 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1097 IORCol = QObject::tr( "IOR_COLUMN" ),
1098 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1099 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1101 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1102 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1103 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1104 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1105 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1106 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1107 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1108 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1109 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1111 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1112 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1113 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1115 ob->setAutoSizeFirstColumn(autoSizeFirst);
1116 ob->setAutoSizeColumns(autoSize);
1117 ob->setResizeOnExpandItem(resizeOnExpandItem);
1118 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1120 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1122 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1123 ob->treeView()->setColumnHidden( i, !shown );
1126 // temporary commented
1128 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1130 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1131 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1132 QString().sprintf( "visibility_column_%d", i ), true ) );
1136 // temporary commented
1138 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1139 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1140 ob->resize( desktop()->width()/3, ob->height() );
1144 #ifndef DISABLE_PYCONSOLE
1145 else if ( flag == WT_PyConsole )
1147 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1148 pyCons->setObjectName( "pythonConsole" );
1149 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1150 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1151 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1152 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1153 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1156 else if ( flag == WT_NoteBook )
1158 setNoteBook( new SalomeApp_NoteBook( desktop() ) );
1159 //to receive signal in NoteBook that it's variable was modified
1160 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1161 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1163 wid = getNoteBook();
1164 wid->setObjectName( "noteBook" );
1170 /*!Create preferences.*/
1171 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1173 LightApp_Application::createPreferences(pref);
1178 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1179 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1180 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1181 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1183 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1184 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1186 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1188 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1189 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1190 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1191 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1192 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1193 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1194 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1195 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1196 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1197 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1200 /*!Update desktop title.*/
1201 void SalomeApp_Application::updateDesktopTitle() {
1202 QString aTitle = applicationName();
1203 QString aVer = applicationVersion();
1204 if ( !aVer.isEmpty() )
1205 aTitle += QString( " " ) + aVer;
1207 if ( activeStudy() )
1209 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1210 if ( !sName.isEmpty() ) {
1211 if ( getStudy()->GetProperties()->IsLocked() ) {
1212 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1214 aTitle += QString( " - [%1]" ).arg( sName );
1219 desktop()->setWindowTitle( aTitle );
1222 int SalomeApp_Application::closeChoice( const QString& /*docName*/ )
1224 QStringList buttons;
1225 QMap<int, int> choices;
1227 buttons << tr ("APPCLOSE_SAVE"); // Save & Clear
1228 choices.insert( idx++, CloseSave ); // ...
1229 buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving
1230 choices.insert( idx++, CloseDiscard ); // ...
1231 if ( myIsCloseFromExit ) {
1232 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1233 choices.insert( idx++, CloseDisconnectSave ); // ...
1234 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1235 choices.insert( idx++, CloseDisconnect ); // ...
1237 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1238 choices.insert( idx++, CloseCancel ); // ...
1240 if( !activeStudy()->isModified() )
1242 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1243 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1244 return choices[answer];
1247 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1253 if ( activeStudy()->isSaved() )
1255 else if ( !onSaveAsDoc() )
1260 case CloseDisconnectSave:
1261 if ( activeStudy()->isSaved() )
1263 else if ( !onSaveAsDoc() )
1266 case CloseDisconnect:
1267 closeActiveDoc( false );
1268 closePermanently = false;
1277 int SalomeApp_Application::openChoice( const QString& aName )
1279 int choice = LightApp_Application::openChoice( aName );
1281 if ( QFileInfo( aName ).exists() ) {
1282 if ( choice == OpenNew ) { // The document isn't already open.
1284 if ( aName == getStudy()->Name().c_str() )
1286 // The document already exists in the study.
1287 // Do you want to reload it?
1289 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1290 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1291 if ( answer == SUIT_MessageBox::Yes )
1292 choice = OpenRefresh;
1294 choice = OpenCancel;
1297 } else { // file is not exist on disk
1298 SUIT_MessageBox::warning( desktop(),
1299 QObject::tr("WRN_WARNING"),
1300 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data()));
1307 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1310 int choice = aChoice;
1317 res = LightApp_Application::openAction( choice, aName );
1325 \brief Get map of the operations which can be performed
1326 on the module activation.
1328 The method should return the map of the kind \c {<id>:<name>}
1329 where \c <id> is an integer identifier of the operation and
1330 \c <name> is a title for the button to be added to the
1331 dialog box. After user selects the required operation by the
1332 clicking the corresponding button in the dialog box, its identifier
1333 is passed to the moduleActionSelected() method to process
1336 \return map of the operations
1337 \sa moduleActionSelected()
1339 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1341 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1343 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1345 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1350 \brief Called when the used selectes required operation chosen
1351 from "Activate module" dialog box.
1353 Performs the required operation according to the user choice.
1355 \param id operation identifier
1356 \sa activateModuleActions()
1358 void SalomeApp_Application::moduleActionSelected( const int id )
1364 case NewAndScriptId:
1368 LightApp_Application::moduleActionSelected( id );
1373 /*!Gets CORBA::ORB_var*/
1374 CORBA::ORB_var SalomeApp_Application::orb()
1376 static CORBA::ORB_var _orb;
1378 if ( CORBA::is_nil( _orb ) ) {
1379 Qtx::CmdLineArgs args;
1380 SetArgcArgv( args.argc(), args.argv() );
1381 _orb = KERNEL::GetRefToORB();
1387 /*!Create and return SALOMEDS_Study.*/
1388 _PTR(Study) SalomeApp_Application::getStudy()
1390 static _PTR(Study) _study;
1392 CORBA::Object_var aSObject = namingService()->Resolve("/Study");
1393 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject);
1394 _study = ClientFactory::Study(aStudy);
1399 /*!Create and return SALOME_NamingService.*/
1400 SALOME_NamingService_Abstract *SalomeApp_Application::namingService()
1405 /*!Create and return SALOME_LifeCycleCORBA.*/
1406 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1408 static SALOME_LifeCycleCORBA _lcc( namingService() );
1412 /*!Private SLOT. On preferences.*/
1413 void SalomeApp_Application::onProperties()
1415 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1419 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1422 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1423 int res = aDlg.exec();
1424 if( res==QDialog::Accepted && aDlg.isChanged() )
1425 SB->CommitCommand();
1429 //study->updateCaptions();
1430 updateDesktopTitle();
1434 /*!Insert items in popup, which necessary for current application*/
1435 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1437 LightApp_SelectionMgr* mgr = selectionMgr();
1438 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1439 mgr->setSelectionCacheEnabled( true );
1441 LightApp_Application::contextMenuPopup( type, thePopup, title );
1443 // temporary commented
1444 /*OB_Browser* ob = objectBrowser();
1445 if ( !ob || type != ob->popupClientType() )
1448 // Get selected objects
1449 SALOME_ListIO aList;
1450 mgr->selectedObjects( aList, QString(), false );
1452 // add GUI state commands: restore, rename
1453 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1454 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1455 thePopup->addSeparator();
1456 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1457 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1458 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1459 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1462 // "Delete reference" item should appear only for invalid references
1464 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1465 bool isInvalidRefs = false;
1467 _PTR(SObject) anObj;
1468 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1470 if( it.Value()->hasEntry() )
1472 _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1473 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1476 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1477 isInvalidRefs = true;
1481 // Add "Delete reference" item to popup
1482 if ( isInvalidRefs )
1484 thePopup->addSeparator();
1485 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1489 // "Activate module" item should appear only if it's necessary
1490 if ( aList.Extent() == 1 ) {
1492 mgr->selectedObjects( aList );
1494 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1496 // add extra popup menu (defined in XML)
1497 if ( myExtActions.size() > 0 ) {
1498 // Use only first selected object
1499 _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() );
1501 _PTR( GenericAttribute ) anAttr;
1502 std::string auid = "AttributeUserID";
1503 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1504 if ( aSO->FindAttribute( anAttr, auid ) ) {
1505 _PTR(AttributeUserID) aAttrID = anAttr;
1506 QString aId = aAttrID->Value().c_str();
1507 if ( myExtActions.contains( aId ) ) {
1508 thePopup->addAction(myExtActions[aId]);
1514 // check if item is a "GUI state" item (also a first level object)
1515 QString entry( aIObj->getEntry() );
1516 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1517 QString aModuleName( aIObj->getComponentDataType() );
1518 QString aModuleTitle = moduleTitle( aModuleName );
1519 if (aModuleTitle.isEmpty()) {
1520 // use displayer module, if given
1521 aModuleTitle = moduleDisplayer( aModuleName );
1523 CAM_Module* currentModule = activeModule();
1524 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() ) {
1525 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1530 mgr->setSelectionCacheEnabled( cacheIsOn );
1533 /*!Update obect browser:
1534 1.if 'updateModels' true, update existing data models;
1535 2. update "non-existing" (not loaded yet) data models;
1536 3. update object browser if it exists */
1537 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1539 // update "non-existing" (not loaded yet) data models
1540 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1543 for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() )
1545 _PTR(SComponent) aComponent ( it->Value() );
1547 #ifndef WITH_SALOMEDS_OBSERVER
1548 // with GUI observers this check is not needed anymore
1549 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1550 continue; // skip the magic "Interface Applicative" component
1552 if ( !objectBrowser() )
1553 getWindow( WT_ObjectBrowser );
1554 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1555 objectBrowser()->setAutoUpdate( false );
1556 SalomeApp_DataModel::synchronize( aComponent, study );
1557 objectBrowser()->setAutoUpdate( isAutoUpdate );
1561 // create data objects that correspond to GUI state save points
1562 if ( study ) updateSavePointDataObjects( study );
1564 // update existing data models (already loaded SComponents)
1565 LightApp_Application::updateObjectBrowser( updateModels );
1568 /*!Display Catalog Genenerator dialog */
1569 void SalomeApp_Application::onCatalogGen()
1571 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1575 /*!Display Registry Display dialog */
1576 void SalomeApp_Application::onRegDisplay()
1578 CORBA::ORB_var anOrb = orb();
1579 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1582 regWnd->activateWindow();
1585 /*!Display Action Search dialog */
1586 void SalomeApp_Application::onFindAction()
1588 const auto pActiveModule = activeModule();
1589 if (pActiveModule && pActiveModule->name() == "PARAVIS") {
1591 // ParaViS module has its own action search dialog (Quick Launch dialog).
1592 // Keep this conditional block until ParaViS's actions are not added to ShortcutMgr resource and asset files.
1595 QtxFeatureSearchDialog aDlg( desktop() );
1597 aDlg.setActiveModuleID(pActiveModule->name());
1599 aDlg.setActiveModuleID();
1604 /*!find original object by double click on item */
1605 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1607 // Issue 21379: References are supported at LightApp_DataObject level
1608 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1610 if( obj && obj->isReference() )
1612 QString entry = obj->refEntry();
1614 SUIT_DataOwnerPtrList aList;
1615 aList.append( new LightApp_DataOwner( entry ) );
1616 selectionMgr()->setSelected( aList, false );
1618 SUIT_DataBrowser* ob = objectBrowser();
1620 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1621 if ( !aSelectedIndexes.isEmpty() )
1622 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1624 emit objectDoubleClicked( theObj );
1628 Creates new view manager
1629 \param type - type of view manager
1631 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1633 return createViewManager(type);
1637 /*!Global utility function, returns selected GUI Save point object's ID */
1638 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1640 SALOME_ListIO aList;
1641 selMgr->selectedObjects( aList );
1642 if( aList.Extent() > 0 ) {
1643 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1644 QString entry( aIObj->getEntry() );
1645 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1646 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1648 bool ok; // conversion to integer is ok?
1649 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1650 return ok ? savePoint : -1;
1655 /*!Called on Restore GUI State popup command*/
1656 void SalomeApp_Application::onRestoreGUIState()
1658 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1659 if ( savePoint == -1 )
1661 SalomeApp_VisualState( this ).restoreState( savePoint );
1664 /*!Called on Delete GUI State popup command*/
1665 void SalomeApp_Application::onDeleteGUIState()
1667 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1668 if ( savePoint == -1 )
1670 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1674 study->removeSavePoint( savePoint );
1675 updateSavePointDataObjects( study );
1678 /*!Called on New study operation*/
1679 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1681 LightApp_Application::onStudyCreated( study );
1683 //#ifndef DISABLE_PYCONSOLE
1684 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1685 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1688 loadDockWindowsState();
1690 objectBrowserColumnsVisibility();
1693 /*!Called on Open study operation*/
1694 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1696 LightApp_Application::onStudyOpened( study );
1698 //#ifndef DISABLE_PYCONSOLE
1699 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1700 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1703 loadDockWindowsState();
1705 objectBrowserColumnsVisibility();
1707 // temporary commented
1708 /*if ( objectBrowser() ) {
1709 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1710 objectBrowser()->updateTree( study->root() );
1714 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1715 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1718 SUIT_DataBrowser* ob = objectBrowser();
1719 LightApp_SelectionMgr* selMgr = selectionMgr();
1721 if ( !study || !ob || !selMgr )
1724 // find GUI states root object
1725 SUIT_DataObject* guiRootObj = 0;
1727 study->root()->children( ch );
1728 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1729 for ( ; it != last ; ++it ) {
1730 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1735 std::vector<int> savePoints = study->getSavePoints();
1736 // case 1: no more save points but they existed in study's tree
1737 if ( savePoints.empty() && guiRootObj ) {
1738 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1739 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1740 const bool isAutoUpdate = ob->autoUpdate();
1741 selMgr->clearSelected();
1742 ob->setAutoUpdate(true);
1743 DataObjectList ch = guiRootObj->children();
1744 for( int i = 0; i < ch.size(); i++ )
1747 ob->setAutoUpdate(isAutoUpdate);
1750 // case 2: no more save points but root does not exist either
1751 if ( savePoints.empty() && !guiRootObj )
1753 // case 3: save points but no root for them - create it
1754 if ( !savePoints.empty() && !guiRootObj )
1755 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1756 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1757 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1759 if ( guiRootObj->nextBrother() ) {
1760 study->root()->removeChild(guiRootObj);
1761 study->root()->appendChild(guiRootObj);
1762 //study->root()->dump();
1765 // store data objects in a map id-to-DataObject
1766 QMap<int,SalomeApp_SavePointObject*> mapDO;
1768 guiRootObj->children( ch );
1769 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1770 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1772 mapDO[dobj->getId()] = dobj;
1775 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1776 // if in the map - remove it from map.
1777 for ( size_t i = 0; i < savePoints.size(); i++ )
1778 if ( !mapDO.contains( savePoints[i] ) )
1779 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1781 mapDO.remove( savePoints[i] );
1783 // delete DataObjects that are still in the map -- their IDs were not found in data model
1784 if( mapDO.size() > 0) {
1785 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1786 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1787 selMgr->clearSelected();
1788 const bool isAutoUpdate = ob->autoUpdate();
1789 ob->setAutoUpdate(true);
1790 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1792 ob->setAutoUpdate(isAutoUpdate);
1796 /*! Check data object */
1797 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1806 Opens other study into active Study. If Study is empty - creates it.
1807 \param theName - name of study
1809 bool SalomeApp_Application::useStudy( const QString& theName )
1812 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1815 res = aStudy->loadDocument( theName );
1816 updateDesktopTitle();
1817 updateCommandsStatus();
1821 /*! Show/hide object browser colums according to preferences */
1822 void SalomeApp_Application::objectBrowserColumnsVisibility()
1824 if ( objectBrowser() )
1825 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1827 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1828 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1832 #ifndef DISABLE_PYCONSOLE
1833 /*! Set SalomeApp_NoteBook pointer */
1834 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1836 myNoteBook = theNoteBook;
1839 /*! Return SalomeApp_NoteBook pointer */
1840 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1847 * Define extra actions defined in module definition XML file.
1848 * Additional popup items sections can be defined by parameter "popupitems".
1849 * Supported attributes:
1850 * title - title of menu item,
1851 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1852 * method - method which has to be called when menu item is selected
1854 * <section name="MODULENAME">
1855 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1857 * <section name="importmed">
1858 * <parameter name="title" value="My menu"/>
1859 * <parameter name="objectid" value="VISU.Result"/>
1860 * <parameter name="method" value="nameOfModuleMethod"/>
1863 void SalomeApp_Application::createExtraActions()
1865 myExtActions.clear();
1866 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1868 QStringList aModules;
1869 modules(aModules, false);
1870 foreach(QString aModile, aModules) {
1871 QString aModName = moduleName(aModile);
1872 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1873 if (!aSectionStr.isNull()) {
1874 QStringList aSections = aSectionStr.split(':');
1875 foreach(QString aSection, aSections) {
1876 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1877 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1878 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1879 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1882 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1883 if (aModuleName.isNull())
1884 aModuleName = aModName;
1886 QAction* aAction = new QAction(aTitle, this);
1888 aData<<aModuleName<<aSlot;
1889 aAction->setData(aData);
1890 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1891 myExtActions[aId] = aAction;
1898 * Called when extra action is selected
1900 void SalomeApp_Application::onExtAction()
1902 QAction* aAction = ::qobject_cast<QAction*>(sender());
1906 QVariant aData = aAction->data();
1907 QStringList aDataList = aData.value<QStringList>();
1908 if (aDataList.size() != 2)
1911 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1912 SALOME_ListIO aListIO;
1913 aSelectionMgr->selectedObjects(aListIO);
1914 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1915 if (aListIO.Extent() < 1)
1917 if (!anIO->hasEntry())
1920 QString aEntry(anIO->getEntry());
1922 QApplication::setOverrideCursor( Qt::WaitCursor );
1923 QString aModuleTitle = moduleTitle(aDataList[0]);
1924 activateModule(aModuleTitle);
1925 QApplication::restoreOverrideCursor();
1927 QCoreApplication::processEvents();
1929 CAM_Module* aModule = activeModule();
1933 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1934 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1938 Checks that an object can be renamed.
1939 \param entry entry of the object
1940 \brief Return \c true if object can be renamed
1942 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1944 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1948 Rename object by entry.
1949 \param entry entry of the object
1950 \param name new name of the object
1951 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1953 bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name )
1955 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1957 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1959 if(!aStudy || savePoint == -1)
1962 if ( !name.isNull() && !name.isEmpty() ) {
1963 aStudy->setNameOfSavePoint( savePoint, name );
1964 updateSavePointDataObjects( aStudy );
1966 //Mark study as modified
1973 #ifndef DISABLE_PYCONSOLE
1974 //============================================================================
1975 /*! Function : onUpdateStudy
1976 * Purpose : Slot to update the study.
1978 //============================================================================
1979 void SalomeApp_Application::onUpdateStudy()
1981 QApplication::setOverrideCursor( Qt::WaitCursor );
1983 if( !updateStudy() )
1984 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1986 QApplication::restoreOverrideCursor();
1989 //============================================================================
1990 /*! Function : updateStudy
1991 * Purpose : Update study by dumping the study to Python script and loading it.
1992 * It is used to apply variable modifications done in NoteBook to created objects.
1994 //============================================================================
1995 bool SalomeApp_Application::updateStudy()
1997 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1998 if ( !study || !myNoteBook )
2001 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
2002 myNoteBook->setDumpedStudyName( study->studyName() );
2004 // get unique temporary directory name
2005 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
2007 if( aTmpDir.isEmpty() )
2010 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
2011 aTmpDir.remove( aTmpDir.length() - 1, 1 );
2013 // dump study to the temporary directory
2014 QString aScriptName( "notebook" );
2015 bool toPublish = true;
2016 bool isMultiFile = false;
2017 bool toSaveGUI = true;
2020 _PTR(AttributeParameter) ap;
2021 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
2022 if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag.
2023 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
2024 ip->setDumpPython();
2025 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
2027 bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
2029 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
2032 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
2036 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2037 int anIndex = aList.indexOf( this );
2039 // Disconnect dialog from application desktop in case if:
2040 // 1) Application is not the first application in the session
2041 // 2) Application is the first application in session but not the only.
2042 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2043 if( changeDesktop ) {
2045 SalomeApp_Application* app = this;
2046 if( anIndex > 0 && anIndex < aList.count() )
2047 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2048 else if(anIndex == 0 && aList.count() > 1)
2049 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2054 // creation a new study and restoring will be done in another application
2055 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2056 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2059 QString aDumpScript = myNoteBook->getDumpedStudyScript();
2060 QString aStudyName = myNoteBook->getDumpedStudyName();
2061 bool isStudySaved = myNoteBook->isDumpedStudySaved();
2062 // clear a study (delete all objects)
2063 onCloseDoc( false );
2065 if( !changeDesktop ) {
2066 ok = onRestoreStudy( aDumpScript,
2075 //============================================================================
2076 /*! Function : onRestoreStudy
2077 * Purpose : Load the dumped study from Python script
2079 //============================================================================
2080 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2081 const QString& theStudyName,
2082 bool theIsStudySaved )
2086 // create a new study
2089 // get active application
2090 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2092 // load study from the temporary directory
2093 QFileInfo aScriptInfo = QFileInfo(theDumpScript);
2094 QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath());
2096 #ifndef DISABLE_PYCONSOLE
2097 PyConsole_Console* pyConsole = app->pythonConsole();
2099 PropertyMgr propm( this, "IsLoadedScript", true );
2100 pyConsole->execAndWait( command );
2104 // remove temporary directory
2105 QString aStudyName = aScriptInfo.baseName();
2106 QDir aDir = aScriptInfo.absoluteDir();
2107 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2108 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2109 ok = aDir.remove( *it ) && ok;
2111 ok = aDir.rmdir( aDir.absolutePath() );
2113 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2115 #ifndef DISABLE_PYCONSOLE
2116 if ( app->getNoteBook() )
2117 app->getNoteBook()->Init();
2118 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2119 newStudy->Modified();
2120 updateDesktopTitle();
2131 Close the Application
2133 void SalomeApp_Application::afterCloseDoc()
2135 #ifndef DISABLE_PYCONSOLE
2136 // emit signal to restore study from Python script
2138 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2139 myNoteBook->getDumpedStudyName(),
2140 myNoteBook->isDumpedStudySaved() );
2143 LightApp_Application::afterCloseDoc();
2146 bool SalomeApp_Application::canOpenDoc( const QString& url )
2148 _PTR(Study) aStudyDS = getStudy();
2150 return aStudyDS->CanOpen( url.toUtf8().data() );
2155 Asks to close existing document.
2157 bool SalomeApp_Application::checkExistingDoc()
2159 return LightApp_Application::checkExistingDoc();
2163 #ifndef DISABLE_PYCONSOLE
2165 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2167 return new SalomeApp_PyInterp( resourceMgr() );
2170 #endif // DISABLE_PYCONSOLE
2172 void SalomeApp_Application::ensureShaperIsActivated()
2174 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
2175 _PTR(Study) studyDS = getStudy();
2176 if ( study && studyDS )
2178 _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study
2179 bool shaperIsActive = false;
2180 QList<CAM_DataModel*> models;
2181 study->dataModels( models );
2182 for( int i = 0; i < models.count() && !shaperIsActive; i++ )
2183 shaperIsActive = models[i]->module()->moduleName() == "Shaper";
2185 if (shaper && !shaperIsActive)
2186 onDesktopMessage("register_module_in_study/Shaper");
2190 void SalomeApp_Application::addCatalogue( const QString& moduleName, const QString& catalogue )
2192 CORBA::Object_var obj = namingService()->Resolve( "/Kernel/ModulCatalog" );
2193 SALOME_ModuleCatalog::ModuleCatalog_var moduleCatalogue = SALOME_ModuleCatalog::ModuleCatalog::_narrow( obj );
2194 QFileInfo fi( catalogue );
2195 if ( !CORBA::is_nil( moduleCatalogue ) && fi.isFile() )
2197 SALOME_ModuleCatalog::ListOfComponents_var known = moduleCatalogue->GetComponentList();
2198 bool loaded = false;
2199 for ( int i = 0; i < (int)known->length() && !loaded; i++ )
2200 loaded = QString( known[i].in() ) == moduleName;
2202 moduleCatalogue->ImportXmlCatalogFile( catalogue.toUtf8().constData() );