1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: SalomeApp_Application.cxx
24 // Created: 10/22/2004 3:23:45 PM
25 // Author: Sergey LITONIN
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #ifndef DISABLE_PYCONSOLE
37 #ifndef DISABLE_PYCONSOLE
38 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
39 #include <PyConsole_Console.h>
40 #include "SalomeApp_NoteBook.h"
42 #include "SalomeApp_Application.h"
43 #include "SalomeApp_Study.h"
44 #include "SalomeApp_DataModel.h"
45 #include "SalomeApp_DataObject.h"
46 #include "SalomeApp_VisualState.h"
47 #include "SalomeApp_StudyPropertiesDlg.h"
48 #include "SalomeApp_LoadStudiesDlg.h"
49 #include "SalomeApp_ExitDlg.h"
51 #include <LightApp_Application.h>
52 #include <LightApp_Module.h>
53 #include <LightApp_Preferences.h>
54 #include <LightApp_SelectionMgr.h>
55 #include <LightApp_NameDlg.h>
56 #include <LightApp_DataOwner.h>
58 #include <CAM_Module.h>
60 #include <SUIT_Tools.h>
61 #include <SUIT_Session.h>
62 #include <SUIT_Desktop.h>
63 #include <SUIT_DataBrowser.h>
64 #include <SUIT_FileDlg.h>
65 #include <SUIT_FileValidator.h>
66 #include <SUIT_MessageBox.h>
67 #include <SUIT_ResourceMgr.h>
68 #include <SUIT_TreeModel.h>
69 #include <SUIT_ViewWindow.h>
70 #include <SUIT_ViewManager.h>
71 #include <SUIT_ViewModel.h>
72 #include <SUIT_OverrideCursor.h>
74 #include <QtxTreeView.h>
76 #include <SALOME_EventFilter.h>
78 // temporary commented
79 //#include <OB_ListItem.h>
82 #include <Utils_ORB_INIT.hxx>
83 #include <Utils_SINGLETON.hxx>
84 #include <SALOME_LifeCycleCORBA.hxx>
86 #include <QApplication>
90 #include <QPushButton>
92 #include <QListWidget>
93 #include <QGridLayout>
97 #include <SALOMEDSClient_ClientFactory.hxx>
98 #include <Basics_Utils.hxx>
100 #include <SALOME_ListIO.hxx>
101 #include <SALOME_ListIteratorOfListIO.hxx>
102 #include <SALOME_Prs.h>
105 #include <ToolsGUI_CatalogGeneratorDlg.h>
106 #include <ToolsGUI_RegWidget.h>
110 #include <SALOMEDS_Tool.hxx>
112 /*!Internal class that updates object browser item properties */
113 // temporary commented
114 /*class SalomeApp_Updater : public OB_Updater
117 SalomeApp_Updater() : OB_Updater(){};
118 virtual ~SalomeApp_Updater(){};
119 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
122 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
124 if( !theObj || !theItem )
127 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
131 _PTR(SObject) SObj = SAObj->object();
134 _PTR( GenericAttribute ) anAttr;
137 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
139 _PTR(AttributeSelectable) aAttrSel = anAttr;
140 theItem->setSelectable( aAttrSel->IsSelectable() );
143 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
145 _PTR(AttributeExpandable) aAttrExpand = anAttr;
146 theItem->setExpandable( aAttrExpand->IsExpandable() );
149 //this attribute is not supported in the version of SALOME 3.x
150 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
152 // _PTR(AttributeOpened) aAttrOpen = anAttr;
153 // theItem->setOpen( aAttrOpen->IsOpened() );
157 /*!Create new instance of SalomeApp_Application.*/
158 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
160 return new SalomeApp_Application();
164 SalomeApp_Application::SalomeApp_Application()
165 : LightApp_Application()
167 connect( desktop(), SIGNAL( message( const QString& ) ),
168 this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
169 myIsSiman = false; // default
173 *\li Destroy event filter.
175 SalomeApp_Application::~SalomeApp_Application()
177 // Do not destroy. It's a singleton !
178 //SALOME_EventFilter::Destroy();
181 /*!Start application.*/
182 void SalomeApp_Application::start()
184 // process the command line options before start: to createActions in accordance to the options
185 static bool isFirst = true;
193 for (int i = 1; i < qApp->argc(); i++) {
194 QRegExp rxs ("--study-hdf=(.+)");
195 if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
196 QString file = rxs.capturedTexts()[1];
197 QFileInfo fi ( file );
198 QString extension = fi.suffix().toLower();
199 if ( extension == "hdf" && fi.exists() )
200 hdffile = fi.absoluteFilePath();
203 QRegExp rxp ("--pyscript=\\[(.+)\\]");
204 QRegExp rxl ("--siman-study=(.+)");
205 if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
207 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
208 for (int k = 0; k < dictList.count(); ++k) {
209 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
210 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
211 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
212 pyfiles += rxd.capturedTexts()[m];
218 if ( rxl.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxl.capturedTexts().count() > 1 ) {
220 loadStudy = rxl.capturedTexts()[1];
226 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
227 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
229 LightApp_Application::start();
230 SALOME_EventFilter::Init();
232 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
233 onOpenDoc( hdffile );
234 else if ( pyfiles.count() > 0 ) // create new study
236 else if (!loadStudy.isEmpty()) {// load study by name
237 if (onLoadDoc(loadStudy))
238 updateObjectBrowser(true);
241 #ifndef DISABLE_PYCONSOLE
242 // import/execute python scripts
243 if ( pyfiles.count() > 0 && activeStudy() ) {
244 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
245 PyConsole_Console* pyConsole = pythonConsole();
246 if ( appStudy && pyConsole ) {
247 _PTR(Study) aStudy = appStudy->studyDS();
248 if ( !aStudy->GetProperties()->IsLocked() ) {
249 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
250 // Path is absolute, script has .py extension
251 for (uint j = 0; j < pyfiles.count(); j++ ) {
252 // Extract scripts and their arguments, if any
253 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
254 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
255 QString script = rxp.capturedTexts()[1];
257 QStringList argList = rxp.capturedTexts()[2].split(",", QString::SkipEmptyParts);
258 for (uint k = 0; k < argList.count(); k++ ) {
259 QString arg = argList[k].trimmed();
260 arg.remove( QRegExp("^[\"]") );
261 arg.remove( QRegExp("[\"]$") );
264 args.remove( QRegExp("[,]$") );
265 if (!args.isEmpty()) {
269 script.remove( QRegExp("^python.*[\\s]+") );
270 QString cmd = script+" "+args;
271 QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
272 pyConsole->exec(command);
274 } // end for loop on pyfiles QStringList
280 LightApp_Application::start();
281 SALOME_EventFilter::Init();
286 void SalomeApp_Application::createActions()
288 LightApp_Application::createActions();
290 SUIT_Desktop* desk = desktop();
293 // "Save GUI State" command is moved to VISU module
294 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
295 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
296 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
299 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
300 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
301 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
304 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
305 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
306 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
309 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
310 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
311 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
313 //! Catalog Generator
314 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
315 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
316 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
319 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
320 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
321 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
323 //SRN: BugID IPAL9021, add an action "Load"
324 createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
325 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
326 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
327 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
328 //SRN: BugID IPAL9021: End
332 // check-in operations for SIMAN study
333 createAction( SimanCheckInId, tr( "TOT_SIMAN_CHECK_IN" ), QIcon(),
334 tr( "MEN_SIMAN_CHECK_IN" ), tr( "PRP_SIMAN_CHECK_IN" ),
335 0, desk, false, this, SLOT( onCheckIn() ) );
336 createAction( SimanLocalCheckInId, tr( "TOT_SIMAN_LOCAL_CHECK_IN" ), QIcon(),
337 tr( "MEN_SIMAN_LOCAL_CHECK_IN" ), tr( "PRP_SIMAN_LOCAL_CHECK_IN" ),
338 0, desk, false, this, SLOT( onLocalCheckIn() ) );
342 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
344 // "Save GUI State" command is renamed to "Save VISU State" and
345 // creation of menu item is moved to VISU
346 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
348 createMenu( FileLoadId, fileMenu, 0 ); //SRN: BugID IPAL9021, add a menu item "Load"
352 // check-in operation for SIMAN study
353 // last argument "5" locates this just after "Save As" but certain constant is bad => insert after the separator
354 createMenu( SimanCheckInId, fileMenu, 5);
355 createMenu( SimanLocalCheckInId, fileMenu, 5);
356 createMenu( separator(), fileMenu, 5 );
359 createMenu( DumpStudyId, fileMenu, 10, -1 );
360 createMenu( separator(), fileMenu, -1, 10, -1 );
361 createMenu( LoadScriptId, fileMenu, 10, -1 );
362 createMenu( separator(), fileMenu, -1, 10, -1 );
363 createMenu( PropertiesId, fileMenu, 10, -1 );
364 createMenu( separator(), fileMenu, -1, 10, -1 );
366 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
367 createMenu( CatalogGenId, toolsMenu, 10, -1 );
368 createMenu( RegDisplayId, toolsMenu, 10, -1 );
369 createMenu( separator(), toolsMenu, -1, 15, -1 );
371 createExtraActions();
373 #ifndef DISABLE_PYCONSOLE
374 #ifndef DISABLE_SALOMEOBJECT
375 // import Python module that manages SALOME plugins
377 PyLockWrapper lck; // acquire GIL
378 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
379 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str());
383 // end of SALOME plugins loading
391 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
393 LightApp_Application::setDesktop( desk );
396 connect( desk, SIGNAL( message( const QString& ) ),
397 this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
402 \brief Close application.
404 void SalomeApp_Application::onExit()
406 bool killServers = false;
409 if ( exitConfirmation() ) {
410 SalomeApp_ExitDlg dlg( desktop() );
411 result = dlg.exec() == QDialog::Accepted;
412 killServers = dlg.isServersShutdown();
416 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
419 /*!SLOT. Load document.*/
420 void SalomeApp_Application::onLoadDoc()
424 std::vector<std::string> List = studyMgr()->GetOpenStudies();
426 SUIT_Session* aSession = SUIT_Session::session();
427 QList<SUIT_Application*> aAppList = aSession->applications();
429 QStringList unloadedStudies;
431 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
432 studyName = List[ind].c_str();
433 // Add to list only unloaded studies
434 bool isAlreadyOpen = false;
435 QListIterator<SUIT_Application*> it( aAppList );
436 while ( it.hasNext() && !isAlreadyOpen ) {
437 SUIT_Application* aApp = it.next();
438 if( !aApp || !aApp->activeStudy() )
440 if ( aApp->activeStudy()->studyName() == studyName )
441 isAlreadyOpen = true;
444 if ( !isAlreadyOpen )
445 unloadedStudies << studyName;
448 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
449 if ( studyName.isEmpty() )
453 // this code replaces marker of windows drive and path become invalid therefore
454 // defines placed there
455 studyName.replace( QRegExp(":"), "/" );
458 if ( onLoadDoc( studyName ) ) {
460 updateViewManagers();
461 updateObjectBrowser( true );
465 /*!SLOT. Create new study and load script*/
466 void SalomeApp_Application::onNewWithScript()
468 QStringList filtersList;
469 filtersList.append(tr("PYTHON_FILES_FILTER"));
470 filtersList.append(tr("ALL_FILES_FILTER"));
472 QString anInitialPath = "";
473 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
474 anInitialPath = QDir::currentPath();
476 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
478 if ( !aFile.isEmpty() )
482 QString command = QString("execfile(r\"%1\")").arg(aFile);
484 #ifndef DISABLE_PYCONSOLE
485 PyConsole_Console* pyConsole = pythonConsole();
488 pyConsole->exec( command );
494 /*!SLOT. Load document with \a aName.*/
495 bool SalomeApp_Application::onLoadDoc( const QString& aName )
497 #ifdef SINGLE_DESKTOP
498 if ( !LightApp_Application::closeDoc() )
502 if ( !activeStudy() ) {
503 // if no study - load in current desktop
504 res = useStudy( aName );
507 // if study exists - load in new desktop. Check: is the same file is loaded?
508 SUIT_Session* aSession = SUIT_Session::session();
509 QList<SUIT_Application*> aAppList = aSession->applications();
510 bool isAlreadyOpen = false;
511 SalomeApp_Application* aApp = 0;
512 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
513 it != aAppList.end() && !isAlreadyOpen; ++it ) {
514 aApp = dynamic_cast<SalomeApp_Application*>( *it );
515 if ( aApp && aApp->activeStudy()->studyName() == aName )
516 isAlreadyOpen = true;
518 if ( !isAlreadyOpen ) {
519 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
521 res = aApp->useStudy( aName );
524 aApp->desktop()->activateWindow();
531 /*!SLOT. Load document with a name, specified in \a aMessage.*/
532 void SalomeApp_Application::onLoadDocMessage(const QString& aMessage)
534 if (aMessage.indexOf("simanCheckoutDone ") == 0) {
536 onLoadDoc(aMessage.section(' ', 1));
538 printf( "****************************************************************\n" );
539 printf( "* Warning: SALOME is built without SIMAN support.\n" );
540 printf( "****************************************************************\n" );
545 /*!SLOT. Copy objects to study maneger from selection maneger..*/
546 void SalomeApp_Application::onCopy()
549 LightApp_SelectionMgr* mgr = selectionMgr();
550 mgr->selectedObjects(list);
552 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
553 if(study == NULL) return;
555 _PTR(Study) stdDS = study->studyDS();
558 SALOME_ListIteratorOfListIO it( list );
561 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
563 studyMgr()->Copy(so);
564 onSelectionChanged();
571 /*!SLOT. Paste objects to study maneger from selection manager.*/
572 void SalomeApp_Application::onPaste()
575 LightApp_SelectionMgr* mgr = selectionMgr();
576 mgr->selectedObjects(list);
578 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
579 if(study == NULL) return;
581 _PTR(Study) stdDS = study->studyDS();
584 if ( stdDS->GetProperties()->IsLocked() ) {
585 SUIT_MessageBox::warning( desktop(),
586 QObject::tr("WRN_WARNING"),
587 QObject::tr("WRN_STUDY_LOCKED") );
591 SALOME_ListIteratorOfListIO it( list );
594 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
596 studyMgr()->Paste(so);
597 updateObjectBrowser( true );
598 updateActions(); //SRN: BugID IPAL9377, case 3
605 /*!Check the application on closing.
606 * \retval true if possible, else false
608 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
610 return LightApp_Application::isPossibleToClose( closePermanently );
613 /*! Check if the study is locked */
614 void SalomeApp_Application::onCloseDoc( bool ask )
616 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
619 _PTR(Study) stdDS = study->studyDS();
620 if(stdDS && stdDS->IsStudyLocked()) {
621 if ( SUIT_MessageBox::question( desktop(),
622 QObject::tr( "WRN_WARNING" ),
623 QObject::tr( "CLOSE_LOCKED_STUDY" ),
624 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
625 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
630 LightApp_Application::onCloseDoc( ask );
633 /*!Sets enable or disable some actions on selection changed.*/
634 void SalomeApp_Application::onSelectionChanged()
637 LightApp_SelectionMgr* mgr = selectionMgr();
638 mgr->selectedObjects(list);
640 bool canCopy = false;
641 bool canPaste = false;
643 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
645 _PTR(Study) stdDS = study->studyDS();
648 SALOME_ListIteratorOfListIO it ( list );
650 if (it.More() && list.Extent() == 1) {
651 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
654 canCopy = studyMgr()->CanCopy(so);
655 canPaste = studyMgr()->CanPaste(so);
661 action(EditCopyId)->setEnabled(canCopy);
662 action(EditPasteId)->setEnabled(canPaste);
665 /*!Delete references.*/
666 void SalomeApp_Application::onDeleteInvalidReferences()
669 LightApp_SelectionMgr* mgr = selectionMgr();
670 mgr->selectedObjects( aList, QString(), false );
672 if( aList.IsEmpty() )
675 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
676 _PTR(Study) aStudyDS = aStudy->studyDS();
677 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
680 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
681 if ( it.Value()->hasEntry() )
683 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
684 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
687 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
688 aStudyBuilder->RemoveReference( aSObject );
690 updateObjectBrowser();
694 void SalomeApp_Application::onOpenWith()
696 QApplication::setOverrideCursor( Qt::WaitCursor );
698 LightApp_SelectionMgr* mgr = selectionMgr();
699 mgr->selectedObjects(aList);
700 if (aList.Extent() != 1)
702 QApplication::restoreOverrideCursor();
705 Handle(SALOME_InteractiveObject) aIObj = aList.First();
706 QString aModuleName(aIObj->getComponentDataType());
707 QString aModuleTitle = moduleTitle(aModuleName);
708 activateModule(aModuleTitle);
709 QApplication::restoreOverrideCursor();
715 SUIT_Study* SalomeApp_Application::createNewStudy()
717 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
719 // Set up processing of major study-related events
720 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
721 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
722 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
723 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
725 #ifndef DISABLE_PYCONSOLE
726 //to receive signal in application that NoteBook's variable was modified
727 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
728 this, SIGNAL(notebookVarUpdated(QString)) );
735 Enable/Disable menu items and toolbar buttons. Rebuild menu
737 void SalomeApp_Application::updateCommandsStatus()
739 LightApp_Application::updateCommandsStatus();
742 QAction* a = action( DumpStudyId );
744 a->setEnabled( activeStudy() );
747 a = action( LoadScriptId );
749 a->setEnabled( activeStudy() );
752 a = action( PropertiesId );
754 a->setEnabled( activeStudy() );
756 // Save GUI state menu
757 a = action( SaveGUIStateId );
759 a->setEnabled( activeStudy() );
761 // update state of Copy/Paste menu items
762 onSelectionChanged();
766 \class DumpStudyFileDlg
767 Private class used in Dump Study operation. Consists 2 check boxes:
768 "Publish in study" and "Save GUI parameters"
770 class DumpStudyFileDlg : public SUIT_FileDlg
773 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
775 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
778 QWidget *hB = new QWidget( this );
779 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
780 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
781 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
783 QHBoxLayout *layout = new QHBoxLayout;
784 layout->addWidget(myPublishChk);
785 layout->addWidget(myMultiFileChk);
786 layout->addWidget(mySaveGUIChk);
787 hB->setLayout(layout);
789 QPushButton* pb = new QPushButton(this);
791 int row = grid->rowCount();
792 grid->addWidget( new QLabel("", this), row, 0 );
793 grid->addWidget( hB, row, 1, 1, 3 );
794 grid->addWidget( pb, row, 5 );
799 QCheckBox* myPublishChk;
800 QCheckBox* myMultiFileChk;
801 QCheckBox* mySaveGUIChk;
804 class DumpStudyFileValidator : public SUIT_FileValidator
807 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
808 virtual ~DumpStudyFileValidator() {};
809 virtual bool canSave( const QString& file, bool permissions );
812 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
814 QFileInfo fi( file );
815 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
816 SUIT_MessageBox::critical( parent(),
817 QObject::tr("WRN_WARNING"),
818 QObject::tr("WRN_FILE_NAME_BAD") );
821 return SUIT_FileValidator::canSave( file, permissions);
824 /*!Private SLOT. On dump study.*/
825 void SalomeApp_Application::onDumpStudy( )
827 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
828 if ( !appStudy ) return;
829 _PTR(Study) aStudy = appStudy->studyDS();
831 QStringList aFilters;
832 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
834 bool anIsPublish = true;
835 bool anIsMultiFile = false;
836 bool anIsSaveGUI = true;
838 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
839 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
840 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
841 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
844 DumpStudyFileDlg fd( desktop() );
845 fd.setValidator( new DumpStudyFileValidator( &fd ) );
846 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
847 fd.setFilters( aFilters );
848 fd.myPublishChk->setChecked( anIsPublish );
849 fd.myMultiFileChk->setChecked( anIsMultiFile );
850 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
851 if ( fd.exec() == QDialog::Accepted )
853 QString aFileName = fd.selectedFile();
855 bool toPublish = fd.myPublishChk->isChecked();
856 bool isMultiFile = fd.myMultiFileChk->isChecked();
857 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
859 if ( !aFileName.isEmpty() ) {
860 QFileInfo aFileInfo(aFileName);
861 if( aFileInfo.isDir() ) // IPAL19257
864 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
867 SUIT_OverrideCursor wc;
868 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
871 SUIT_MessageBox::warning( desktop(),
872 QObject::tr("WRN_WARNING"),
873 tr("WRN_DUMP_STUDY_FAILED") );
878 /*!Private SLOT. On load script.*/
879 void SalomeApp_Application::onLoadScript( )
881 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
882 if ( !appStudy ) return;
883 _PTR(Study) aStudy = appStudy->studyDS();
885 if ( aStudy->GetProperties()->IsLocked() ) {
886 SUIT_MessageBox::warning( desktop(),
887 QObject::tr("WRN_WARNING"),
888 QObject::tr("WRN_STUDY_LOCKED") );
892 QStringList filtersList;
893 filtersList.append(tr("PYTHON_FILES_FILTER"));
894 filtersList.append(tr("ALL_FILES_FILTER"));
896 QString anInitialPath = "";
897 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
898 anInitialPath = QDir::currentPath();
901 // MPV: if it is SIMAN study, make the initial path as the path to the Siman scripts storage
903 SALOMEDSClient_StudyManager* aMgr = studyMgr();
904 aMgr->GetSimanStudy()->StudyId();
905 anInitialPath = QString(QDir::separator()) + "tmp" + QDir::separator() + "SimanSalome" + QDir::separator() +
906 aMgr->GetSimanStudy()->StudyId().c_str() + QDir::separator() +
907 aMgr->GetSimanStudy()->ScenarioId().c_str() + QDir::separator() + aMgr->GetSimanStudy()->UserId().c_str();
911 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
913 if ( !aFile.isEmpty() )
915 QString command = QString("execfile(r\"%1\")").arg(aFile);
917 #ifndef DISABLE_PYCONSOLE
918 PyConsole_Console* pyConsole = pythonConsole();
921 pyConsole->exec( command );
926 /*!Private SLOT. On save GUI state.*/
927 void SalomeApp_Application::onSaveGUIState()
929 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
931 SalomeApp_VisualState( this ).storeState();
932 updateSavePointDataObjects( study );
933 updateObjectBrowser();
938 /*!Public SLOT. On SIMAN check in operation.*/
939 void SalomeApp_Application::onCheckIn()
942 setMenuShown(SimanCheckInId, false); // check in may be performed only once
943 setMenuShown(SimanLocalCheckInId, false);
944 SALOMEDSClient_StudyManager* aMgr = studyMgr();
945 aMgr->GetSimanStudy()->CheckIn("");
947 printf( "****************************************************************\n" );
948 printf( "* Warning: SALOME is built without SIMAN support.\n" );
949 printf( "****************************************************************\n" );
953 /*!Public SLOT. On SIMAN local check in operation.*/
954 void SalomeApp_Application::onLocalCheckIn()
957 // get the active module
958 CAM_Module* aModule = activeModule();
959 if (!aModule) return; // there is no active module
961 setMenuShown(SimanCheckInId, false); // check in may be performed only once
962 setMenuShown(SimanLocalCheckInId, false);
963 SALOMEDSClient_StudyManager* aMgr = studyMgr();
964 aMgr->GetSimanStudy()->CheckIn(aModule->name().toLatin1().data());
966 printf( "****************************************************************\n" );
967 printf( "* Warning: SALOME is built without SIMAN support.\n" );
968 printf( "****************************************************************\n" );
973 *\retval QString "(*.hdf)"
975 QString SalomeApp_Application::getFileFilter() const
981 QWidget* SalomeApp_Application::createWindow( const int flag )
984 #ifndef DISABLE_PYCONSOLE
985 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
987 wid = LightApp_Application::createWindow(flag);
990 SUIT_ResourceMgr* resMgr = resourceMgr();
992 if ( flag == WT_ObjectBrowser )
994 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
996 // temporary commented
997 //ob->setUpdater( new SalomeApp_Updater() );
999 #ifdef WITH_SALOMEDS_OBSERVER
1000 //do not activate the automatic update of Qt tree through signal/slot
1001 ob->setAutoUpdate(false);
1002 //activate update of modified objects only
1003 ob->setUpdateModified(true);
1006 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1009 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1010 IORCol = QObject::tr( "IOR_COLUMN" ),
1011 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1012 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1014 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1015 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1016 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1017 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1018 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1019 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1020 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1021 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1022 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1024 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1025 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1026 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1028 ob->setAutoSizeFirstColumn(autoSizeFirst);
1029 ob->setAutoSizeColumns(autoSize);
1030 ob->setResizeOnExpandItem(resizeOnExpandItem);
1031 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1033 // temporary commented
1035 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1037 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1038 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1039 QString().sprintf( "visibility_column_%d", i ), true ) );
1043 // temporary commented
1045 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1046 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1047 ob->resize( desktop()->width()/3, ob->height() );
1051 #ifndef DISABLE_PYCONSOLE
1052 else if ( flag == WT_PyConsole )
1054 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
1055 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1056 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1057 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1058 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1060 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1061 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1063 else if ( flag == WT_NoteBook )
1065 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1067 _PTR(Study) aStudy = appStudy->studyDS();
1068 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1069 //to receive signal in NoteBook that it's variable was modified
1070 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1071 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1073 wid = getNoteBook();
1079 /*!Create preferences.*/
1080 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1082 LightApp_Application::createPreferences(pref);
1087 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1088 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1089 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1090 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1092 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1093 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1095 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1097 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1098 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1099 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1100 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1101 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1102 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1103 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1104 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1105 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1106 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1109 /*!Update desktop title.*/
1110 void SalomeApp_Application::updateDesktopTitle() {
1111 QString aTitle = applicationName();
1112 QString aVer = applicationVersion();
1113 if ( !aVer.isEmpty() )
1114 aTitle += QString( " " ) + aVer;
1116 if ( activeStudy() )
1118 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1119 if ( !sName.isEmpty() ) {
1120 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1122 _PTR(Study) stdDS = study->studyDS();
1124 if ( stdDS->GetProperties()->IsLocked() ) {
1125 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1127 aTitle += QString( " - [%1]" ).arg( sName );
1134 desktop()->setWindowTitle( aTitle );
1137 int SalomeApp_Application::closeChoice( const QString& docName )
1139 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1140 tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1141 tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1143 int res = CloseCancel;
1146 else if ( answer == 1 )
1148 else if ( answer == 2 )
1154 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1160 if ( activeStudy()->isSaved() )
1162 else if ( !onSaveAsDoc() )
1168 closePermanently = false;
1178 int SalomeApp_Application::openChoice( const QString& aName )
1180 int choice = LightApp_Application::openChoice( aName );
1182 if ( QFileInfo( aName ).exists() ) {
1183 if ( choice == OpenNew ) { // The document isn't already open.
1185 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1186 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1187 if ( aName == QString( lst[i].c_str() ) )
1190 // The document already exists in the study manager.
1191 // Do you want to reload it?
1193 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1194 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1195 if ( answer == SUIT_MessageBox::Yes )
1196 choice = OpenRefresh;
1198 choice = OpenCancel;
1201 } else { // file is not exist on disk
1202 SUIT_MessageBox::warning( desktop(),
1203 QObject::tr("WRN_WARNING"),
1204 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1211 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1214 int choice = aChoice;
1219 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1222 studyMgr()->Close( aStudy );
1227 res = LightApp_Application::openAction( choice, aName );
1235 \brief Get map of the operations which can be performed
1236 on the module activation.
1238 The method should return the map of the kind \c {<id>:<name>}
1239 where \c <id> is an integer identifier of the operation and
1240 \c <name> is a title for the button to be added to the
1241 dialog box. After user selects the required operation by the
1242 clicking the corresponding button in the dialog box, its identifier
1243 is passed to the moduleActionSelected() method to process
1246 \return map of the operations
1247 \sa moduleActionSelected()
1249 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1251 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1252 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1253 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1258 \brief Called when the used selectes required operation chosen
1259 from "Activate module" dialog box.
1261 Performs the required operation according to the user choice.
1263 \param id operation identifier
1264 \sa activateModuleActions()
1266 void SalomeApp_Application::moduleActionSelected( const int id )
1272 case NewAndScriptId:
1276 LightApp_Application::moduleActionSelected( id );
1281 /*!Gets CORBA::ORB_var*/
1282 CORBA::ORB_var SalomeApp_Application::orb()
1284 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1285 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1289 /*!Create and return SALOMEDS_StudyManager.*/
1290 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1292 static _PTR(StudyManager) _sm;
1293 if(!_sm) _sm = ClientFactory::StudyManager();
1297 /*!Create and return SALOME_NamingService.*/
1298 SALOME_NamingService* SalomeApp_Application::namingService()
1300 static SALOME_NamingService _ns(orb());
1304 /*!Create and return SALOME_LifeCycleCORBA.*/
1305 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1307 static SALOME_LifeCycleCORBA _lcc( namingService() );
1311 /*!Private SLOT. On preferences.*/
1312 void SalomeApp_Application::onProperties()
1314 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1318 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1321 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1322 int res = aDlg.exec();
1323 if( res==QDialog::Accepted && aDlg.isChanged() )
1324 SB->CommitCommand();
1328 //study->updateCaptions();
1329 updateDesktopTitle();
1333 /*!Insert items in popup, which necessary for current application*/
1334 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1336 LightApp_SelectionMgr* mgr = selectionMgr();
1337 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1338 mgr->setSelectionCacheEnabled( true );
1340 LightApp_Application::contextMenuPopup( type, thePopup, title );
1342 // temporary commented
1343 /*OB_Browser* ob = objectBrowser();
1344 if ( !ob || type != ob->popupClientType() )
1347 // Get selected objects
1348 SALOME_ListIO aList;
1349 mgr->selectedObjects( aList, QString(), false );
1351 // add GUI state commands: restore, rename
1352 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1353 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1354 thePopup->addSeparator();
1355 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1356 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1357 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1358 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1361 // "Delete reference" item should appear only for invalid references
1363 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1364 bool isInvalidRefs = false;
1365 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1366 _PTR(Study) aStudyDS = aStudy->studyDS();
1367 _PTR(SObject) anObj;
1369 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1370 if( it.Value()->hasEntry() )
1372 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1373 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1376 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1377 isInvalidRefs = true;
1380 // Add "Delete reference" item to popup
1381 if ( isInvalidRefs )
1383 thePopup->addSeparator();
1384 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1388 // "Activate module" item should appear only if it's necessary
1389 if ( aList.Extent() == 1 ) {
1391 mgr->selectedObjects( aList );
1393 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1395 // add extra popup menu (defined in XML)
1396 if ( myExtActions.size() > 0 ) {
1397 // Use only first selected object
1398 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1400 _PTR(Study) stdDS = study->studyDS();
1402 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1404 _PTR( GenericAttribute ) anAttr;
1405 std::string auid = "AttributeUserID";
1406 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1407 if ( aSO->FindAttribute( anAttr, auid ) ) {
1408 _PTR(AttributeUserID) aAttrID = anAttr;
1409 QString aId = aAttrID->Value().c_str();
1410 if ( myExtActions.contains( aId ) ) {
1411 thePopup->addAction(myExtActions[aId]);
1419 // check if item is a "GUI state" item (also a first level object)
1420 QString entry( aIObj->getEntry() );
1421 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1422 QString aModuleName( aIObj->getComponentDataType() );
1423 QString aModuleTitle = moduleTitle( aModuleName );
1424 CAM_Module* currentModule = activeModule();
1425 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1426 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1430 mgr->setSelectionCacheEnabled( cacheIsOn );
1433 /*!Update obect browser:
1434 1.if 'updateModels' true, update existing data models;
1435 2. update "non-existing" (not loaded yet) data models;
1436 3. update object browser if it exists */
1437 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1439 // update "non-existing" (not loaded yet) data models
1440 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1443 _PTR(Study) stdDS = study->studyDS();
1446 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1448 _PTR(SComponent) aComponent ( it->Value() );
1450 #ifndef WITH_SALOMEDS_OBSERVER
1451 // with GUI observers this check is not needed anymore
1452 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1453 continue; // skip the magic "Interface Applicative" component
1455 if ( !objectBrowser() )
1456 getWindow( WT_ObjectBrowser );
1457 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1458 objectBrowser()->setAutoUpdate( false );
1459 SalomeApp_DataModel::synchronize( aComponent, study );
1460 objectBrowser()->setAutoUpdate( isAutoUpdate );
1465 // create data objects that correspond to GUI state save points
1466 if ( study ) updateSavePointDataObjects( study );
1468 // update existing data models (already loaded SComponents)
1469 LightApp_Application::updateObjectBrowser( updateModels );
1472 /*!Display Catalog Genenerator dialog */
1473 void SalomeApp_Application::onCatalogGen()
1475 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1479 /*!Display Registry Display dialog */
1480 void SalomeApp_Application::onRegDisplay()
1482 CORBA::ORB_var anOrb = orb();
1483 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1486 regWnd->activateWindow();
1489 /*!find original object by double click on item */
1490 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1492 // Issue 21379: References are supported at LightApp_DataObject level
1493 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1495 if( obj && obj->isReference() )
1497 QString entry = obj->refEntry();
1499 SUIT_DataOwnerPtrList aList;
1500 aList.append( new LightApp_DataOwner( entry ) );
1501 selectionMgr()->setSelected( aList, false );
1503 SUIT_DataBrowser* ob = objectBrowser();
1505 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1506 if ( !aSelectedIndexes.isEmpty() )
1507 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1512 Creates new view manager
1513 \param type - type of view manager
1515 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1517 return createViewManager(type);
1521 /*!Global utility function, returns selected GUI Save point object's ID */
1522 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1524 SALOME_ListIO aList;
1525 selMgr->selectedObjects( aList );
1526 if( aList.Extent() > 0 ) {
1527 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1528 QString entry( aIObj->getEntry() );
1529 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1530 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1532 bool ok; // conversion to integer is ok?
1533 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1534 return ok ? savePoint : -1;
1539 /*!Called on Restore GUI State popup command*/
1540 void SalomeApp_Application::onRestoreGUIState()
1542 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1543 if ( savePoint == -1 )
1545 SalomeApp_VisualState( this ).restoreState( savePoint );
1548 /*!Called on Delete GUI State popup command*/
1549 void SalomeApp_Application::onDeleteGUIState()
1551 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1552 if ( savePoint == -1 )
1554 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1558 study->removeSavePoint( savePoint );
1559 updateSavePointDataObjects( study );
1562 /*!Called on New study operation*/
1563 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1565 LightApp_Application::onStudyCreated( study );
1567 #ifndef DISABLE_PYCONSOLE
1568 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1569 windowDock( getWindow( WT_ObjectBrowser ) ) );
1572 loadDockWindowsState();
1574 objectBrowserColumnsVisibility();
1577 /*!Called on Open study operation*/
1578 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1580 LightApp_Application::onStudyOpened( study );
1582 #ifndef DISABLE_PYCONSOLE
1583 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1584 windowDock( getWindow( WT_ObjectBrowser ) ) );
1587 loadDockWindowsState();
1589 objectBrowserColumnsVisibility();
1591 // temporary commented
1592 /*if ( objectBrowser() ) {
1593 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1594 objectBrowser()->updateTree( study->root() );
1598 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1599 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1602 SUIT_DataBrowser* ob = objectBrowser();
1603 LightApp_SelectionMgr* selMgr = selectionMgr();
1605 if ( !study || !ob || !selMgr )
1608 // find GUI states root object
1609 SUIT_DataObject* guiRootObj = 0;
1611 study->root()->children( ch );
1612 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1613 for ( ; it != last ; ++it ) {
1614 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1619 std::vector<int> savePoints = study->getSavePoints();
1620 // case 1: no more save points but they existed in study's tree
1621 if ( savePoints.empty() && guiRootObj ) {
1622 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1623 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1624 const bool isAutoUpdate = ob->autoUpdate();
1625 selMgr->clearSelected();
1626 ob->setAutoUpdate(true);
1627 DataObjectList ch = guiRootObj->children();
1628 for( int i = 0; i < ch.size(); i++ )
1631 ob->setAutoUpdate(isAutoUpdate);
1634 // case 2: no more save points but root does not exist either
1635 if ( savePoints.empty() && !guiRootObj )
1637 // case 3: save points but no root for them - create it
1638 if ( !savePoints.empty() && !guiRootObj )
1639 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1640 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1641 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1643 if ( guiRootObj->nextBrother() ) {
1644 study->root()->removeChild(guiRootObj);
1645 study->root()->appendChild(guiRootObj);
1646 //study->root()->dump();
1649 // store data objects in a map id-to-DataObject
1650 QMap<int,SalomeApp_SavePointObject*> mapDO;
1652 guiRootObj->children( ch );
1653 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1654 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1656 mapDO[dobj->getId()] = dobj;
1659 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1660 // if in the map - remove it from map.
1661 for ( int i = 0; i < savePoints.size(); i++ )
1662 if ( !mapDO.contains( savePoints[i] ) )
1663 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1665 mapDO.remove( savePoints[i] );
1667 // delete DataObjects that are still in the map -- their IDs were not found in data model
1668 if( mapDO.size() > 0) {
1669 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1670 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1671 selMgr->clearSelected();
1672 const bool isAutoUpdate = ob->autoUpdate();
1673 ob->setAutoUpdate(true);
1674 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1676 ob->setAutoUpdate(isAutoUpdate);
1680 /*! Check data object */
1681 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1690 Opens other study into active Study. If Study is empty - creates it.
1691 \param theName - name of study
1693 bool SalomeApp_Application::useStudy( const QString& theName )
1696 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1699 res = aStudy->loadDocument( theName );
1700 updateDesktopTitle();
1701 updateCommandsStatus();
1705 /*! Show/hide object browser colums according to preferences */
1706 void SalomeApp_Application::objectBrowserColumnsVisibility()
1708 if ( objectBrowser() )
1709 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1711 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1712 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1716 #ifndef DISABLE_PYCONSOLE
1717 /*! Set SalomeApp_NoteBook pointer */
1718 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1720 myNoteBook = theNoteBook;
1723 /*! Return SalomeApp_NoteBook pointer */
1724 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1731 * Define extra actions defined in module definition XML file.
1732 * Additional popup items sections can be defined by parameter "popupitems".
1733 * Supported attributes:
1734 * title - title of menu item,
1735 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1736 * method - method which has to be called when menu item is selected
1738 * <section name="MODULENAME">
1739 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1741 * <section name="importmed">
1742 * <parameter name="title" value="My menu"/>
1743 * <parameter name="objectid" value="VISU.Result"/>
1744 * <parameter name="method" value="nameOfModuleMethod"/>
1747 void SalomeApp_Application::createExtraActions()
1749 myExtActions.clear();
1750 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1752 QStringList aModules;
1753 modules(aModules, false);
1754 foreach(QString aModile, aModules) {
1755 QString aModName = moduleName(aModile);
1756 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1757 if (!aSectionStr.isNull()) {
1758 QStringList aSections = aSectionStr.split(':');
1759 foreach(QString aSection, aSections) {
1760 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1761 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1762 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1763 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1766 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1767 if (aModuleName.isNull())
1768 aModuleName = aModName;
1770 QAction* aAction = new QAction(aTitle, this);
1772 aData<<aModuleName<<aSlot;
1773 aAction->setData(aData);
1774 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1775 myExtActions[aId] = aAction;
1782 * Called when extra action is selected
1784 void SalomeApp_Application::onExtAction()
1786 QAction* aAction = ::qobject_cast<QAction*>(sender());
1790 QVariant aData = aAction->data();
1791 QStringList aDataList = aData.value<QStringList>();
1792 if (aDataList.size() != 2)
1795 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1796 SALOME_ListIO aListIO;
1797 aSelectionMgr->selectedObjects(aListIO);
1798 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1799 if (aListIO.Extent() < 1)
1801 if (!anIO->hasEntry())
1804 QString aEntry(anIO->getEntry());
1806 QApplication::setOverrideCursor( Qt::WaitCursor );
1807 QString aModuleTitle = moduleTitle(aDataList[0]);
1808 activateModule(aModuleTitle);
1809 QApplication::restoreOverrideCursor();
1811 QCoreApplication::processEvents();
1813 CAM_Module* aModule = activeModule();
1817 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1818 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1822 Checks that an object can be renamed.
1823 \param entry entry of the object
1824 \brief Return \c true if object can be renamed
1826 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1828 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1832 Rename object by entry.
1833 \param entry entry of the object
1834 \param name new name of the object
1835 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1837 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1839 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1841 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1843 if(!aStudy || savePoint == -1)
1846 if ( !name.isNull() && !name.isEmpty() ) {
1847 aStudy->setNameOfSavePoint( savePoint, name );
1848 updateSavePointDataObjects( aStudy );
1850 //Mark study as modified
1857 #ifndef DISABLE_PYCONSOLE
1858 //============================================================================
1859 /*! Function : onUpdateStudy
1860 * Purpose : Slot to update the study.
1862 //============================================================================
1863 void SalomeApp_Application::onUpdateStudy()
1865 QApplication::setOverrideCursor( Qt::WaitCursor );
1867 if( !updateStudy() )
1868 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1870 QApplication::restoreOverrideCursor();
1873 //============================================================================
1874 /*! Function : updateStudy
1875 * Purpose : Update study by dumping the study to Python script and loading it.
1876 * It is used to apply variable modifications done in NoteBook to created objects.
1878 //============================================================================
1879 bool SalomeApp_Application::updateStudy()
1881 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1882 if ( !study || !myNoteBook )
1885 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1886 myNoteBook->setDumpedStudyName( study->studyName() );
1888 _PTR(Study) studyDS = study->studyDS();
1890 // get unique temporary directory name
1891 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1892 if( aTmpDir.isEmpty() )
1895 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1896 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1898 // dump study to the temporary directory
1899 QString aScriptName( "notebook" );
1900 bool toPublish = true;
1901 bool isMultiFile = false;
1902 bool toSaveGUI = true;
1905 _PTR(AttributeParameter) ap;
1906 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1907 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1908 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1909 ip->setDumpPython(studyDS);
1910 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1912 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1914 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1917 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1921 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1922 int anIndex = aList.indexOf( this );
1924 // Disconnect dialog from application desktop in case if:
1925 // 1) Application is not the first application in the session
1926 // 2) Application is the first application in session but not the only.
1927 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1928 if( changeDesktop ) {
1930 SalomeApp_Application* app = this;
1931 if( anIndex > 0 && anIndex < aList.count() )
1932 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1933 else if(anIndex == 0 && aList.count() > 1)
1934 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1939 // creation a new study and restoring will be done in another application
1940 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1941 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1944 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1945 QString aStudyName = myNoteBook->getDumpedStudyName();
1946 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1947 // clear a study (delete all objects)
1948 onCloseDoc( false );
1950 if( !changeDesktop ) {
1951 ok = onRestoreStudy( aDumpScript,
1960 //============================================================================
1961 /*! Function : onRestoreStudy
1962 * Purpose : Load the dumped study from Python script
1964 //============================================================================
1965 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1966 const QString& theStudyName,
1967 bool theIsStudySaved )
1971 // create a new study
1974 // get active application
1975 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1977 // load study from the temporary directory
1978 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1980 #ifndef DISABLE_PYCONSOLE
1981 PyConsole_Console* pyConsole = app->pythonConsole();
1983 pyConsole->execAndWait( command );
1986 // remove temporary directory
1987 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1988 QString aStudyName = aScriptInfo.baseName();
1989 QDir aDir = aScriptInfo.absoluteDir();
1990 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1991 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1992 ok = aDir.remove( *it ) && ok;
1994 ok = aDir.rmdir( aDir.absolutePath() );
1996 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1998 #ifndef DISABLE_PYCONSOLE
1999 _PTR(Study) aStudyDS = newStudy->studyDS();
2000 app->getNoteBook()->Init( aStudyDS );
2001 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2002 newStudy->Modified();
2003 updateDesktopTitle();
2014 Close the Application
2016 void SalomeApp_Application::afterCloseDoc()
2018 #ifndef DISABLE_PYCONSOLE
2019 // emit signal to restore study from Python script
2021 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2022 myNoteBook->getDumpedStudyName(),
2023 myNoteBook->isDumpedStudySaved() );
2026 LightApp_Application::afterCloseDoc();