1 // Copyright (C) 2007-2013 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.
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>
35 #include "SalomeApp_PyInterp.h" // WARNING! This include must be the first!
36 #include "SalomeApp_Application.h"
37 #include "SalomeApp_Study.h"
38 #include "SalomeApp_DataModel.h"
39 #include "SalomeApp_DataObject.h"
40 #include "SalomeApp_VisualState.h"
41 #include "SalomeApp_StudyPropertiesDlg.h"
42 #include "SalomeApp_LoadStudiesDlg.h"
43 #include "SalomeApp_NoteBook.h"
45 #include "SalomeApp_ExitDlg.h"
47 #include <LightApp_Application.h>
48 #include <LightApp_Module.h>
49 #include <LightApp_Preferences.h>
50 #include <LightApp_SelectionMgr.h>
51 #include <LightApp_NameDlg.h>
52 #include <LightApp_DataOwner.h>
53 #include <LightApp_Displayer.h>
55 #include <CAM_Module.h>
57 #include <SUIT_Tools.h>
58 #include <SUIT_Session.h>
59 #include <SUIT_Desktop.h>
60 #include <SUIT_DataBrowser.h>
61 #include <SUIT_FileDlg.h>
62 #include <SUIT_FileValidator.h>
63 #include <SUIT_MessageBox.h>
64 #include <SUIT_ResourceMgr.h>
65 #include <SUIT_TreeModel.h>
66 #include <SUIT_ViewWindow.h>
67 #include <SUIT_ViewManager.h>
68 #include <SUIT_ViewModel.h>
70 #include <QtxTreeView.h>
72 #include <SALOME_EventFilter.h>
74 // temporary commented
75 //#include <OB_ListItem.h>
77 #include <PyConsole_Console.h>
79 #include <Utils_ORB_INIT.hxx>
80 #include <Utils_SINGLETON.hxx>
81 #include <SALOME_LifeCycleCORBA.hxx>
83 #include <QApplication>
87 #include <QPushButton>
89 #include <QListWidget>
90 #include <QGridLayout>
94 #include <SALOMEDSClient_ClientFactory.hxx>
95 #include <Basics_Utils.hxx>
97 #include <SALOME_ListIO.hxx>
98 #include <SALOME_ListIteratorOfListIO.hxx>
99 #include <SALOME_Prs.h>
102 #include <ToolsGUI_CatalogGeneratorDlg.h>
103 #include <ToolsGUI_RegWidget.h>
107 #include <SALOMEDS_Tool.hxx>
109 /*!Internal class that updates object browser item properties */
110 // temporary commented
111 /*class SalomeApp_Updater : public OB_Updater
114 SalomeApp_Updater() : OB_Updater(){};
115 virtual ~SalomeApp_Updater(){};
116 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
119 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
121 if( !theObj || !theItem )
124 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
128 _PTR(SObject) SObj = SAObj->object();
131 _PTR( GenericAttribute ) anAttr;
134 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
136 _PTR(AttributeSelectable) aAttrSel = anAttr;
137 theItem->setSelectable( aAttrSel->IsSelectable() );
140 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
142 _PTR(AttributeExpandable) aAttrExpand = anAttr;
143 theItem->setExpandable( aAttrExpand->IsExpandable() );
146 //this attribute is not supported in the version of SALOME 3.x
147 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
149 // _PTR(AttributeOpened) aAttrOpen = anAttr;
150 // theItem->setOpen( aAttrOpen->IsOpened() );
154 /*!Create new instance of SalomeApp_Application.*/
155 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
157 return new SalomeApp_Application();
161 SalomeApp_Application::SalomeApp_Application()
162 : LightApp_Application()
164 connect( desktop(), SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
165 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
169 *\li Destroy event filter.
171 SalomeApp_Application::~SalomeApp_Application()
173 // Do not destroy. It's a singleton !
174 //SALOME_EventFilter::Destroy();
177 /*!Start application.*/
178 void SalomeApp_Application::start()
180 LightApp_Application::start();
182 SALOME_EventFilter::Init();
184 static bool isFirst = true;
191 for (int i = 1; i < qApp->argc(); i++) {
192 QRegExp rxs ("--study-hdf=(.+)");
193 if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
194 QString file = rxs.capturedTexts()[1];
195 QFileInfo fi ( file );
196 QString extension = fi.suffix().toLower();
197 if ( extension == "hdf" && fi.exists() )
198 hdffile = fi.absoluteFilePath();
201 QRegExp rxp ("--pyscript=(.+)");
202 if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
203 QStringList files = rxp.capturedTexts()[1].split(",",QString::SkipEmptyParts);
209 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
210 onOpenDoc( hdffile );
211 else if ( pyfiles.count() > 0 ) // create new study
214 // import/execute python scripts
215 if ( pyfiles.count() > 0 && activeStudy() ) {
216 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
217 PyConsole_Console* pyConsole = pythonConsole();
218 if ( appStudy && pyConsole ) {
219 _PTR(Study) aStudy = appStudy->studyDS();
220 if ( !aStudy->GetProperties()->IsLocked() ) {
221 for (uint j = 0; j < pyfiles.count(); j++ ) {
222 QFileInfo fi ( pyfiles[j] );
223 QFileInfo fipy ( pyfiles[j] + ".py" );
224 QString command = QString( "execfile(r\"%1\")" );
225 if ( fi.isAbsolute() ) {
227 pyConsole->exec( command.arg( fi.absoluteFilePath() ) );
228 else if ( fipy.exists() )
229 pyConsole->exec( command.arg( fipy.absoluteFilePath() ) );
231 qDebug() << "Can't execute file" << pyfiles[j];
236 dirs << QDir::currentPath();
237 if ( ::getenv( "PYTHONPATH" ) )
238 dirs += QString( ::getenv( "PYTHONPATH" ) ).split( QRegExp( "[:|;]" ) );
239 foreach( QString dir, dirs ) {
240 qDebug() << "try" << QFileInfo( dir, pyfiles[j] ).absoluteFilePath();
241 qDebug() << "try" << QFileInfo( dir, pyfiles[j] + ".py" ).absoluteFilePath();
242 if ( QFileInfo( dir, pyfiles[j] ).exists() ) {
243 pyConsole->exec( command.arg( QFileInfo( dir, pyfiles[j] ).absoluteFilePath() ) );
247 else if ( QFileInfo( dir, pyfiles[j] + ".py" ).exists() ) {
248 pyConsole->exec( command.arg( QFileInfo( dir, pyfiles[j] + ".py" ).absoluteFilePath() ) );
254 qDebug() << "Can't execute file" << pyfiles[j];
265 void SalomeApp_Application::createActions()
267 LightApp_Application::createActions();
269 SUIT_Desktop* desk = desktop();
272 // "Save GUI State" command is moved to VISU module
273 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
274 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
275 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
278 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
279 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
280 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
283 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
284 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
285 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
288 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
289 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
290 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
292 //! Catalog Generator
293 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
294 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
295 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
298 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
299 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
300 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
302 //SRN: BugID IPAL9021, add an action "Load"
303 createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
304 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
305 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
306 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
307 //SRN: BugID IPAL9021: End
310 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
312 // "Save GUI State" command is renamed to "Save VISU State" and
313 // creation of menu item is moved to VISU
314 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
316 createMenu( FileLoadId, fileMenu, 0 ); //SRN: BugID IPAL9021, add a menu item "Load"
318 createMenu( DumpStudyId, fileMenu, 10, -1 );
319 createMenu( separator(), fileMenu, -1, 10, -1 );
320 createMenu( LoadScriptId, fileMenu, 10, -1 );
321 createMenu( separator(), fileMenu, -1, 10, -1 );
322 createMenu( PropertiesId, fileMenu, 10, -1 );
323 createMenu( separator(), fileMenu, -1, 10, -1 );
325 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
326 createMenu( CatalogGenId, toolsMenu, 10, -1 );
327 createMenu( RegDisplayId, toolsMenu, 10, -1 );
328 createMenu( separator(), toolsMenu, -1, 15, -1 );
330 createExtraActions();
332 // import Python module that manages SALOME plugins
333 PyGILState_STATE gstate = PyGILState_Ensure();
334 PyObject* pluginsmanager=PyImport_ImportModule((char*)"salome_pluginsmanager");
335 PyObject* 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());
339 Py_XDECREF(pluginsmanager);
340 PyGILState_Release(gstate);
341 // end of SALOME plugins loading
347 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
349 LightApp_Application::setDesktop( desk );
352 connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
353 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
358 \brief Close application.
360 void SalomeApp_Application::onExit()
362 bool killServers = false;
365 if ( exitConfirmation() ) {
366 SalomeApp_ExitDlg dlg( desktop() );
367 result = dlg.exec() == QDialog::Accepted;
368 killServers = dlg.isServersShutdown();
372 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
375 /*!SLOT. Load document.*/
376 void SalomeApp_Application::onLoadDoc()
380 std::vector<std::string> List = studyMgr()->GetOpenStudies();
382 SUIT_Session* aSession = SUIT_Session::session();
383 QList<SUIT_Application*> aAppList = aSession->applications();
385 QStringList unloadedStudies;
387 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
388 studyName = List[ind].c_str();
389 // Add to list only unloaded studies
390 bool isAlreadyOpen = false;
391 QListIterator<SUIT_Application*> it( aAppList );
392 while ( it.hasNext() && !isAlreadyOpen ) {
393 SUIT_Application* aApp = it.next();
394 if( !aApp || !aApp->activeStudy() )
396 if ( aApp->activeStudy()->studyName() == studyName )
397 isAlreadyOpen = true;
400 if ( !isAlreadyOpen )
401 unloadedStudies << studyName;
404 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
405 if ( studyName.isEmpty() )
409 // this code replaces marker of windows drive and path become invalid therefore
410 // defines placed there
411 studyName.replace( QRegExp(":"), "/" );
414 if ( onLoadDoc( studyName ) ) {
416 updateViewManagers();
417 updateObjectBrowser( true );
421 /*!SLOT. Create new study and load script*/
422 void SalomeApp_Application::onNewWithScript()
424 QStringList filtersList;
425 filtersList.append(tr("PYTHON_FILES_FILTER"));
426 filtersList.append(tr("ALL_FILES_FILTER"));
428 QString anInitialPath = "";
429 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
430 anInitialPath = QDir::currentPath();
432 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
434 if ( !aFile.isEmpty() )
438 QString command = QString("execfile(r\"%1\")").arg(aFile);
440 PyConsole_Console* pyConsole = pythonConsole();
443 pyConsole->exec( command );
448 /*!SLOT. Load document with \a aName.*/
449 bool SalomeApp_Application::onLoadDoc( const QString& aName )
452 if ( !activeStudy() ) {
453 // if no study - load in current desktop
454 res = useStudy( aName );
457 // if study exists - load in new desktop. Check: is the same file is loaded?
458 SUIT_Session* aSession = SUIT_Session::session();
459 QList<SUIT_Application*> aAppList = aSession->applications();
460 bool isAlreadyOpen = false;
461 SalomeApp_Application* aApp = 0;
462 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
463 it != aAppList.end() && !isAlreadyOpen; ++it ) {
464 aApp = dynamic_cast<SalomeApp_Application*>( *it );
465 if ( aApp && aApp->activeStudy()->studyName() == aName )
466 isAlreadyOpen = true;
468 if ( !isAlreadyOpen ) {
469 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
471 res = aApp->useStudy( aName );
474 aApp->desktop()->activateWindow();
481 /*!SLOT. Copy objects to study maneger from selection maneger..*/
482 void SalomeApp_Application::onCopy()
485 LightApp_SelectionMgr* mgr = selectionMgr();
486 mgr->selectedObjects(list);
488 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
489 if(study == NULL) return;
491 _PTR(Study) stdDS = study->studyDS();
494 SALOME_ListIteratorOfListIO it( list );
497 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
499 studyMgr()->Copy(so);
500 onSelectionChanged();
507 /*!SLOT. Paste objects to study maneger from selection manager.*/
508 void SalomeApp_Application::onPaste()
511 LightApp_SelectionMgr* mgr = selectionMgr();
512 mgr->selectedObjects(list);
514 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
515 if(study == NULL) return;
517 _PTR(Study) stdDS = study->studyDS();
520 if ( stdDS->GetProperties()->IsLocked() ) {
521 SUIT_MessageBox::warning( desktop(),
522 QObject::tr("WRN_WARNING"),
523 QObject::tr("WRN_STUDY_LOCKED") );
527 SALOME_ListIteratorOfListIO it( list );
530 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
532 studyMgr()->Paste(so);
533 updateObjectBrowser( true );
534 updateActions(); //SRN: BugID IPAL9377, case 3
541 /*!Check the application on closing.
542 * \retval true if possible, else false
544 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
546 return LightApp_Application::isPossibleToClose( closePermanently );
549 /*! Check if the study is locked */
550 void SalomeApp_Application::onCloseDoc( bool ask )
552 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
555 _PTR(Study) stdDS = study->studyDS();
556 if(stdDS && stdDS->IsStudyLocked()) {
557 if ( SUIT_MessageBox::question( desktop(),
558 QObject::tr( "WRN_WARNING" ),
559 QObject::tr( "CLOSE_LOCKED_STUDY" ),
560 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
561 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
566 LightApp_Application::onCloseDoc( ask );
569 /*!Sets enable or disable some actions on selection changed.*/
570 void SalomeApp_Application::onSelectionChanged()
573 LightApp_SelectionMgr* mgr = selectionMgr();
574 mgr->selectedObjects(list);
576 bool canCopy = false;
577 bool canPaste = false;
579 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
581 _PTR(Study) stdDS = study->studyDS();
584 SALOME_ListIteratorOfListIO it ( list );
586 if (it.More() && list.Extent() == 1) {
587 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
590 canCopy = studyMgr()->CanCopy(so);
591 canPaste = studyMgr()->CanPaste(so);
597 action(EditCopyId)->setEnabled(canCopy);
598 action(EditPasteId)->setEnabled(canPaste);
601 /*!Delete references.*/
602 void SalomeApp_Application::onDeleteInvalidReferences()
605 LightApp_SelectionMgr* mgr = selectionMgr();
606 mgr->selectedObjects( aList, QString(), false );
608 if( aList.IsEmpty() )
611 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
612 _PTR(Study) aStudyDS = aStudy->studyDS();
613 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
616 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
617 if ( it.Value()->hasEntry() )
619 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
620 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
623 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
624 aStudyBuilder->RemoveReference( aSObject );
626 updateObjectBrowser();
630 void SalomeApp_Application::onOpenWith()
632 QApplication::setOverrideCursor( Qt::WaitCursor );
634 LightApp_SelectionMgr* mgr = selectionMgr();
635 mgr->selectedObjects(aList);
636 if (aList.Extent() != 1)
638 QApplication::restoreOverrideCursor();
641 Handle(SALOME_InteractiveObject) aIObj = aList.First();
642 QString aModuleName(aIObj->getComponentDataType());
643 QString aModuleTitle = moduleTitle(aModuleName);
644 activateModule(aModuleTitle);
645 QApplication::restoreOverrideCursor();
651 SUIT_Study* SalomeApp_Application::createNewStudy()
653 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
655 // Set up processing of major study-related events
656 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
657 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
658 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
659 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
661 //to receive signal in application that NoteBook's variable was modified
662 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
663 this, SIGNAL(notebookVarUpdated(QString)) );
669 Enable/Disable menu items and toolbar buttons. Rebuild menu
671 void SalomeApp_Application::updateCommandsStatus()
673 LightApp_Application::updateCommandsStatus();
676 QAction* a = action( DumpStudyId );
678 a->setEnabled( activeStudy() );
681 a = action( LoadScriptId );
683 a->setEnabled( activeStudy() );
686 a = action( PropertiesId );
688 a->setEnabled( activeStudy() );
690 // Save GUI state menu
691 a = action( SaveGUIStateId );
693 a->setEnabled( activeStudy() );
695 // update state of Copy/Paste menu items
696 onSelectionChanged();
700 \class DumpStudyFileDlg
701 Private class used in Dump Study operation. Consists 2 check boxes:
702 "Publish in study" and "Save GUI parameters"
704 class DumpStudyFileDlg : public SUIT_FileDlg
707 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
709 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
712 QWidget *hB = new QWidget( this );
713 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
714 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
715 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
717 QHBoxLayout *layout = new QHBoxLayout;
718 layout->addWidget(myPublishChk);
719 layout->addWidget(myMultiFileChk);
720 layout->addWidget(mySaveGUIChk);
721 hB->setLayout(layout);
723 QPushButton* pb = new QPushButton(this);
725 int row = grid->rowCount();
726 grid->addWidget( new QLabel("", this), row, 0 );
727 grid->addWidget( hB, row, 1, 1, 3 );
728 grid->addWidget( pb, row, 5 );
733 QCheckBox* myPublishChk;
734 QCheckBox* myMultiFileChk;
735 QCheckBox* mySaveGUIChk;
738 class DumpStudyFileValidator : public SUIT_FileValidator
741 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
742 virtual ~DumpStudyFileValidator() {};
743 virtual bool canSave( const QString& file, bool permissions );
746 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
748 QFileInfo fi( file );
749 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
750 SUIT_MessageBox::critical( parent(),
751 QObject::tr("WRN_WARNING"),
752 QObject::tr("WRN_FILE_NAME_BAD") );
755 return SUIT_FileValidator::canSave( file, permissions);
758 /*!Private SLOT. On dump study.*/
759 void SalomeApp_Application::onDumpStudy( )
761 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
762 if ( !appStudy ) return;
763 _PTR(Study) aStudy = appStudy->studyDS();
765 QStringList aFilters;
766 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
768 bool anIsPublish = true;
769 bool anIsMultiFile = false;
770 bool anIsSaveGUI = true;
772 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
773 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
774 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
775 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
778 DumpStudyFileDlg fd( desktop() );
779 fd.setValidator( new DumpStudyFileValidator( &fd ) );
780 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
781 fd.setFilters( aFilters );
782 fd.myPublishChk->setChecked( anIsPublish );
783 fd.myMultiFileChk->setChecked( anIsMultiFile );
784 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
785 if ( fd.exec() == QDialog::Accepted )
787 QString aFileName = fd.selectedFile();
789 bool toPublish = fd.myPublishChk->isChecked();
790 bool isMultiFile = fd.myMultiFileChk->isChecked();
791 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
793 if ( !aFileName.isEmpty() ) {
794 QFileInfo aFileInfo(aFileName);
795 if( aFileInfo.isDir() ) // IPAL19257
798 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
799 bool res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
802 SUIT_MessageBox::warning( desktop(),
803 QObject::tr("WRN_WARNING"),
804 tr("WRN_DUMP_STUDY_FAILED") );
809 /*!Private SLOT. On load script.*/
810 void SalomeApp_Application::onLoadScript( )
812 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
813 if ( !appStudy ) return;
814 _PTR(Study) aStudy = appStudy->studyDS();
816 if ( aStudy->GetProperties()->IsLocked() ) {
817 SUIT_MessageBox::warning( desktop(),
818 QObject::tr("WRN_WARNING"),
819 QObject::tr("WRN_STUDY_LOCKED") );
823 QStringList filtersList;
824 filtersList.append(tr("PYTHON_FILES_FILTER"));
825 filtersList.append(tr("ALL_FILES_FILTER"));
827 QString anInitialPath = "";
828 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
829 anInitialPath = QDir::currentPath();
831 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
833 if ( !aFile.isEmpty() )
835 QString command = QString("execfile(r\"%1\")").arg(aFile);
837 PyConsole_Console* pyConsole = pythonConsole();
840 pyConsole->exec( command );
844 /*!Private SLOT. On save GUI state.*/
845 void SalomeApp_Application::onSaveGUIState()
847 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
849 SalomeApp_VisualState( this ).storeState();
850 updateSavePointDataObjects( study );
851 updateObjectBrowser();
857 *\retval QString "(*.hdf)"
859 QString SalomeApp_Application::getFileFilter() const
865 QWidget* SalomeApp_Application::createWindow( const int flag )
868 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
870 SUIT_ResourceMgr* resMgr = resourceMgr();
872 if ( flag == WT_ObjectBrowser )
874 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
876 // temporary commented
877 //ob->setUpdater( new SalomeApp_Updater() );
879 #ifdef WITH_SALOMEDS_OBSERVER
880 //do not activate the automatic update of Qt tree through signal/slot
881 ob->setAutoUpdate(false);
882 //activate update of modified objects only
883 ob->setUpdateModified(true);
886 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
889 ValueCol = QObject::tr( "VALUE_COLUMN" ),
890 IORCol = QObject::tr( "IOR_COLUMN" ),
891 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
892 EntryCol = QObject::tr( "ENTRY_COLUMN" );
894 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
895 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
896 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
897 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
898 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
899 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
900 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
901 treeModel->setAppropriate( IORCol, Qtx::Toggled );
902 treeModel->setAppropriate( RefCol, Qtx::Toggled );
904 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
905 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
906 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
908 ob->setAutoSizeFirstColumn(autoSizeFirst);
909 ob->setAutoSizeColumns(autoSize);
910 ob->setResizeOnExpandItem(resizeOnExpandItem);
911 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
913 // temporary commented
915 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
917 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
918 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
919 QString().sprintf( "visibility_column_%d", i ), true ) );
923 // temporary commented
925 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
926 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
927 ob->resize( desktop()->width()/3, ob->height() );
931 else if ( flag == WT_PyConsole )
933 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
934 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
935 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
936 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
937 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
939 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
940 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
942 else if ( flag == WT_NoteBook )
944 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
946 _PTR(Study) aStudy = appStudy->studyDS();
947 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
948 //to receive signal in NoteBook that it's variable was modified
949 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
950 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
957 /*!Create preferences.*/
958 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
960 LightApp_Application::createPreferences(pref);
965 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
966 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
967 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
968 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
970 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
971 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
973 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
975 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
976 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
977 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
978 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
979 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
980 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
981 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
982 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
983 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
984 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
987 /*!Update desktop title.*/
988 void SalomeApp_Application::updateDesktopTitle() {
989 QString aTitle = applicationName();
990 QString aVer = applicationVersion();
991 if ( !aVer.isEmpty() )
992 aTitle += QString( " " ) + aVer;
996 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
997 if ( !sName.isEmpty() ) {
998 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1000 _PTR(Study) stdDS = study->studyDS();
1002 if ( stdDS->GetProperties()->IsLocked() ) {
1003 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1005 aTitle += QString( " - [%1]" ).arg( sName );
1012 desktop()->setWindowTitle( aTitle );
1015 int SalomeApp_Application::closeChoice( const QString& docName )
1017 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1018 tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1019 tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1021 int res = CloseCancel;
1024 else if ( answer == 1 )
1026 else if ( answer == 2 )
1032 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1038 if ( activeStudy()->isSaved() )
1040 else if ( !onSaveAsDoc() )
1046 closePermanently = false;
1056 int SalomeApp_Application::openChoice( const QString& aName )
1058 int choice = LightApp_Application::openChoice( aName );
1060 if ( QFileInfo( aName ).exists() ) {
1061 if ( choice == OpenNew ) { // The document isn't already open.
1063 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1064 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1065 if ( aName == QString( lst[i].c_str() ) )
1068 // The document already exists in the study manager.
1069 // Do you want to reload it?
1071 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1072 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1073 if ( answer == SUIT_MessageBox::Yes )
1074 choice = OpenRefresh;
1076 choice = OpenCancel;
1079 } else { // file is not exist on disk
1080 SUIT_MessageBox::warning( desktop(),
1081 QObject::tr("WRN_WARNING"),
1082 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1089 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1092 int choice = aChoice;
1097 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1100 studyMgr()->Close( aStudy );
1105 res = LightApp_Application::openAction( choice, aName );
1113 \brief Get map of the operations which can be performed
1114 on the module activation.
1116 The method should return the map of the kind \c {<id>:<name>}
1117 where \c <id> is an integer identifier of the operation and
1118 \c <name> is a title for the button to be added to the
1119 dialog box. After user selects the required operation by the
1120 clicking the corresponding button in the dialog box, its identifier
1121 is passed to the moduleActionSelected() method to process
1124 \return map of the operations
1125 \sa moduleActionSelected()
1127 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1129 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1130 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1131 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1136 \brief Called when the used selectes required operation chosen
1137 from "Activate module" dialog box.
1139 Performs the required operation according to the user choice.
1141 \param id operation identifier
1142 \sa activateModuleActions()
1144 void SalomeApp_Application::moduleActionSelected( const int id )
1150 case NewAndScriptId:
1154 LightApp_Application::moduleActionSelected( id );
1159 /*!Gets CORBA::ORB_var*/
1160 CORBA::ORB_var SalomeApp_Application::orb()
1162 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1163 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1167 /*!Create and return SALOMEDS_StudyManager.*/
1168 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1170 static _PTR(StudyManager) _sm;
1171 if(!_sm) _sm = ClientFactory::StudyManager();
1175 /*!Create and return SALOME_NamingService.*/
1176 SALOME_NamingService* SalomeApp_Application::namingService()
1178 static SALOME_NamingService _ns(orb());
1182 /*!Create and return SALOME_LifeCycleCORBA.*/
1183 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1185 static SALOME_LifeCycleCORBA _lcc( namingService() );
1189 /*!Private SLOT. On preferences.*/
1190 void SalomeApp_Application::onProperties()
1192 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1196 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1199 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1200 int res = aDlg.exec();
1201 if( res==QDialog::Accepted && aDlg.isChanged() )
1202 SB->CommitCommand();
1206 //study->updateCaptions();
1207 updateDesktopTitle();
1211 /*!Insert items in popup, which necessary for current application*/
1212 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1214 LightApp_SelectionMgr* mgr = selectionMgr();
1215 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1216 mgr->setSelectionCacheEnabled( true );
1218 LightApp_Application::contextMenuPopup( type, thePopup, title );
1220 // temporary commented
1221 /*OB_Browser* ob = objectBrowser();
1222 if ( !ob || type != ob->popupClientType() )
1225 // Get selected objects
1226 SALOME_ListIO aList;
1227 mgr->selectedObjects( aList, QString(), false );
1229 // add GUI state commands: restore, rename
1230 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1231 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1232 thePopup->addSeparator();
1233 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1234 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1235 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1236 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1239 // "Delete reference" item should appear only for invalid references
1241 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1242 bool isInvalidRefs = false;
1243 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1244 _PTR(Study) aStudyDS = aStudy->studyDS();
1245 _PTR(SObject) anObj;
1247 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1248 if( it.Value()->hasEntry() )
1250 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1251 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1254 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1255 isInvalidRefs = true;
1258 // Add "Delete reference" item to popup
1259 if ( isInvalidRefs )
1261 thePopup->addSeparator();
1262 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1266 // "Activate module" item should appear only if it's necessary
1267 if ( aList.Extent() == 1 ) {
1269 mgr->selectedObjects( aList );
1271 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1273 // add extra popup menu (defined in XML)
1274 if ( myExtActions.size() > 0 ) {
1275 // Use only first selected object
1276 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1278 _PTR(Study) stdDS = study->studyDS();
1280 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1282 _PTR( GenericAttribute ) anAttr;
1283 std::string auid = "AttributeUserID";
1284 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1285 if ( aSO->FindAttribute( anAttr, auid ) ) {
1286 _PTR(AttributeUserID) aAttrID = anAttr;
1287 QString aId = aAttrID->Value().c_str();
1288 if ( myExtActions.contains( aId ) ) {
1289 thePopup->addAction(myExtActions[aId]);
1297 // check if item is a "GUI state" item (also a first level object)
1298 QString entry( aIObj->getEntry() );
1299 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1300 QString aModuleName( aIObj->getComponentDataType() );
1301 QString aModuleTitle = moduleTitle( aModuleName );
1302 CAM_Module* currentModule = activeModule();
1303 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1304 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1308 mgr->setSelectionCacheEnabled( cacheIsOn );
1311 /*!Update obect browser:
1312 1.if 'updateModels' true, update existing data models;
1313 2. update "non-existing" (not loaded yet) data models;
1314 3. update object browser if it exists */
1315 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1317 // update "non-existing" (not loaded yet) data models
1318 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1321 _PTR(Study) stdDS = study->studyDS();
1324 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1326 _PTR(SComponent) aComponent ( it->Value() );
1328 #ifndef WITH_SALOMEDS_OBSERVER
1329 // with GUI observers this check is not needed anymore
1330 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1331 continue; // skip the magic "Interface Applicative" component
1333 if ( !objectBrowser() )
1334 getWindow( WT_ObjectBrowser );
1335 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1336 objectBrowser()->setAutoUpdate( false );
1337 SalomeApp_DataModel::synchronize( aComponent, study );
1338 objectBrowser()->setAutoUpdate( isAutoUpdate );
1343 // create data objects that correspond to GUI state save points
1344 if ( study ) updateSavePointDataObjects( study );
1346 // update existing data models (already loaded SComponents)
1347 LightApp_Application::updateObjectBrowser( updateModels );
1350 /*!Display Catalog Genenerator dialog */
1351 void SalomeApp_Application::onCatalogGen()
1353 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1357 /*!Display Registry Display dialog */
1358 void SalomeApp_Application::onRegDisplay()
1360 CORBA::ORB_var anOrb = orb();
1361 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1364 regWnd->activateWindow();
1367 /*!find original object by double click on item */
1368 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1370 // Issue 21379: References are supported at LightApp_DataObject level
1371 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1373 if( obj && obj->isReference() )
1375 QString entry = obj->refEntry();
1377 SUIT_DataOwnerPtrList aList;
1378 aList.append( new LightApp_DataOwner( entry ) );
1379 selectionMgr()->setSelected( aList, false );
1381 SUIT_DataBrowser* ob = objectBrowser();
1383 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1384 if ( !aSelectedIndexes.isEmpty() )
1385 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1390 Creates new view manager
1391 \param type - type of view manager
1393 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1395 return createViewManager(type);
1399 /*!Global utility funciton, returns selected GUI Save point object's ID */
1400 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1402 SALOME_ListIO aList;
1403 selMgr->selectedObjects( aList );
1404 if( aList.Extent() > 0 ) {
1405 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1406 QString entry( aIObj->getEntry() );
1407 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1408 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1410 bool ok; // conversion to integer is ok?
1411 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1412 return ok ? savePoint : -1;
1417 /*!Called on Restore GUI State popup command*/
1418 void SalomeApp_Application::onRestoreGUIState()
1420 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1421 if ( savePoint == -1 )
1423 SalomeApp_VisualState( this ).restoreState( savePoint );
1426 /*!Called on Delete GUI State popup command*/
1427 void SalomeApp_Application::onDeleteGUIState()
1429 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1430 if ( savePoint == -1 )
1432 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1436 study->removeSavePoint( savePoint );
1437 updateSavePointDataObjects( study );
1440 /*!Called on New study operation*/
1441 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1443 LightApp_Application::onStudyCreated( study );
1445 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1446 windowDock( getWindow( WT_ObjectBrowser ) ) );
1448 loadDockWindowsState();
1450 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1451 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1454 objectBrowserColumnsVisibility();
1457 /*!Called on Save study operation*/
1458 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1460 LightApp_Application::onStudySaved( study );
1462 // temporary commented
1463 /*if ( objectBrowser() ) {
1464 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1465 objectBrowser()->updateTree( study->root() );
1469 /*!Called on Open study operation*/
1470 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1472 LightApp_Application::onStudyOpened( study );
1474 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1475 windowDock( getWindow( WT_ObjectBrowser ) ) );
1477 loadDockWindowsState();
1479 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1480 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1482 objectBrowserColumnsVisibility();
1484 // temporary commented
1485 /*if ( objectBrowser() ) {
1486 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1487 objectBrowser()->updateTree( study->root() );
1491 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1492 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1495 SUIT_DataBrowser* ob = objectBrowser();
1496 LightApp_SelectionMgr* selMgr = selectionMgr();
1498 if ( !study || !ob || !selMgr )
1501 // find GUI states root object
1502 SUIT_DataObject* guiRootObj = 0;
1504 study->root()->children( ch );
1505 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1506 for ( ; it != last ; ++it ) {
1507 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1512 std::vector<int> savePoints = study->getSavePoints();
1513 // case 1: no more save points but they existed in study's tree
1514 if ( savePoints.empty() && guiRootObj ) {
1515 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1516 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1517 const bool isAutoUpdate = ob->autoUpdate();
1518 selMgr->clearSelected();
1519 ob->setAutoUpdate(true);
1520 DataObjectList ch = guiRootObj->children();
1521 for( int i = 0; i < ch.size(); i++ )
1524 ob->setAutoUpdate(isAutoUpdate);
1527 // case 2: no more save points but root does not exist either
1528 if ( savePoints.empty() && !guiRootObj )
1530 // case 3: save points but no root for them - create it
1531 if ( !savePoints.empty() && !guiRootObj )
1532 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1533 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1534 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1536 if ( guiRootObj->nextBrother() ) {
1537 study->root()->removeChild(guiRootObj);
1538 study->root()->appendChild(guiRootObj);
1539 //study->root()->dump();
1542 // store data objects in a map id-to-DataObject
1543 QMap<int,SalomeApp_SavePointObject*> mapDO;
1545 guiRootObj->children( ch );
1546 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1547 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1549 mapDO[dobj->getId()] = dobj;
1552 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1553 // if in the map - remove it from map.
1554 for ( int i = 0; i < savePoints.size(); i++ )
1555 if ( !mapDO.contains( savePoints[i] ) )
1556 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1558 mapDO.remove( savePoints[i] );
1560 // delete DataObjects that are still in the map -- their IDs were not found in data model
1561 if( mapDO.size() > 0) {
1562 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1563 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1564 selMgr->clearSelected();
1565 const bool isAutoUpdate = ob->autoUpdate();
1566 ob->setAutoUpdate(true);
1567 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1569 ob->setAutoUpdate(isAutoUpdate);
1573 /*! Check data object */
1574 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1583 Opens other study into active Study. If Study is empty - creates it.
1584 \param theName - name of study
1586 bool SalomeApp_Application::useStudy( const QString& theName )
1589 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1592 res = aStudy->loadDocument( theName );
1593 updateDesktopTitle();
1594 updateCommandsStatus();
1598 /*! Show/hide object browser colums according to preferences */
1599 void SalomeApp_Application::objectBrowserColumnsVisibility()
1601 if ( objectBrowser() )
1602 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1604 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1605 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1609 /*! Set SalomeApp_NoteBook pointer */
1610 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1612 myNoteBook = theNoteBook;
1615 /*! Return SalomeApp_NoteBook pointer */
1616 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1622 * Define extra actions defined in module definition XML file.
1623 * Additional popup items sections can be defined by parameter "popupitems".
1624 * Supported attributes:
1625 * title - title of menu item,
1626 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1627 * method - method which has to be called when menu item is selected
1629 * <section name="MODULENAME">
1630 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1632 * <section name="importmed">
1633 * <parameter name="title" value="My menu"/>
1634 * <parameter name="objectid" value="VISU.Result"/>
1635 * <parameter name="method" value="nameOfModuleMethod"/>
1638 void SalomeApp_Application::createExtraActions()
1640 myExtActions.clear();
1641 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1643 QStringList aModules;
1644 modules(aModules, false);
1645 foreach(QString aModile, aModules) {
1646 QString aModName = moduleName(aModile);
1647 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1648 if (!aSectionStr.isNull()) {
1649 QStringList aSections = aSectionStr.split(':');
1650 foreach(QString aSection, aSections) {
1651 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1652 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1653 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1654 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1657 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1658 if (aModuleName.isNull())
1659 aModuleName = aModName;
1661 QAction* aAction = new QAction(aTitle, this);
1663 aData<<aModuleName<<aSlot;
1664 aAction->setData(aData);
1665 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1666 myExtActions[aId] = aAction;
1673 * Called when extra action is selected
1675 void SalomeApp_Application::onExtAction()
1677 QAction* aAction = ::qobject_cast<QAction*>(sender());
1681 QVariant aData = aAction->data();
1682 QStringList aDataList = aData.value<QStringList>();
1683 if (aDataList.size() != 2)
1686 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1687 SALOME_ListIO aListIO;
1688 aSelectionMgr->selectedObjects(aListIO);
1689 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1690 if (aListIO.Extent() < 1)
1692 if (!anIO->hasEntry())
1695 QString aEntry(anIO->getEntry());
1697 QApplication::setOverrideCursor( Qt::WaitCursor );
1698 QString aModuleTitle = moduleTitle(aDataList[0]);
1699 activateModule(aModuleTitle);
1700 QApplication::restoreOverrideCursor();
1702 QCoreApplication::processEvents();
1704 CAM_Module* aModule = activeModule();
1708 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1709 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1713 * Called when window activated
1715 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1717 SUIT_DataBrowser* anOB = objectBrowser();
1720 SUIT_DataObject* rootObj = anOB->root();
1724 DataObjectList listObj = rootObj->children( true );
1726 SUIT_ViewModel* vmod = 0;
1727 if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1728 vmod = vman->getViewModel();
1729 updateVisibilityState( listObj, vmod );
1733 Update visibility state of given objects
1735 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1736 SUIT_ViewModel* theViewModel )
1738 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1743 SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1745 if (theList.isEmpty() || !aView || !aStudy)
1748 for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1749 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1751 if (!obj || aStudy->isComponent(obj->entry()))
1754 LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1755 Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1758 LightApp_Displayer* aDisplayer = anObjModule->displayer();
1760 if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1761 if(aDisplayer->IsDisplayed(obj->entry(),aView))
1762 anObjState = Qtx::ShownState;
1764 anObjState = Qtx::HiddenState;
1767 aStudy->setVisibilityState( obj->entry(), anObjState );
1773 Called then view manager removed
1775 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1777 ViewManagerList lst;
1779 if( lst.count() == 1) { // in case if closed last view window
1780 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1782 aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1787 Checks that an object can be renamed.
1788 \param entry entry of the object
1789 \brief Return \c true if object can be renamed
1791 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1793 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1797 Rename object by entry.
1798 \param entry entry of the object
1799 \param name new name of the object
1800 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1802 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1804 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1806 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1808 if(!aStudy || savePoint == -1)
1811 if ( !name.isNull() && !name.isEmpty() ) {
1812 aStudy->setNameOfSavePoint( savePoint, name );
1813 updateSavePointDataObjects( aStudy );
1815 //Mark study as modified
1823 \return default windows( Object Browser, Python Console )
1824 Adds to map \a aMap.
1826 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1828 LightApp_Application::defaultWindows(aMap);
1829 if ( !aMap.contains( WT_NoteBook ) ) {
1830 if ( !myNoteBook ) {
1831 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1837 Gets current windows.
1838 \param winMap - output current windows map.
1840 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1842 LightApp_Application::currentWindows( aMap );
1843 if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1844 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1847 //============================================================================
1848 /*! Function : onUpdateStudy
1849 * Purpose : Slot to update the study.
1851 //============================================================================
1852 void SalomeApp_Application::onUpdateStudy()
1854 QApplication::setOverrideCursor( Qt::WaitCursor );
1856 if( !updateStudy() )
1857 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1859 QApplication::restoreOverrideCursor();
1862 //============================================================================
1863 /*! Function : updateStudy
1864 * Purpose : Update study by dumping the study to Python script and loading it.
1865 * It is used to apply variable modifications done in NoteBook to created objects.
1867 //============================================================================
1868 bool SalomeApp_Application::updateStudy()
1870 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1871 if ( !study || !myNoteBook )
1874 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1875 myNoteBook->setDumpedStudyName( study->studyName() );
1877 _PTR(Study) studyDS = study->studyDS();
1879 // get unique temporary directory name
1880 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1881 if( aTmpDir.isEmpty() )
1884 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1885 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1887 // dump study to the temporary directory
1888 QString aScriptName( "notebook" );
1889 bool toPublish = true;
1890 bool isMultiFile = false;
1891 bool toSaveGUI = true;
1894 _PTR(AttributeParameter) ap;
1895 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1896 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1897 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1898 ip->setDumpPython(studyDS);
1899 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1901 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1903 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1906 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1910 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1911 int anIndex = aList.indexOf( this );
1913 // Disconnect dialog from application desktop in case if:
1914 // 1) Application is not the first application in the session
1915 // 2) Application is the first application in session but not the only.
1916 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1918 SalomeApp_Application* app;
1919 if( anIndex > 0 && anIndex < aList.count() )
1920 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1921 else if(anIndex == 0 && aList.count() > 1)
1922 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1927 if( changeDesktop ) {
1928 // creation a new study and restoring will be done in another application
1929 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1930 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1933 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1934 QString aStudyName = myNoteBook->getDumpedStudyName();
1935 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1936 // clear a study (delete all objects)
1937 onCloseDoc( false );
1939 if( !changeDesktop ) {
1940 ok = onRestoreStudy( aDumpScript,
1948 //============================================================================
1949 /*! Function : onRestoreStudy
1950 * Purpose : Load the dumped study from Python script
1952 //============================================================================
1953 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1954 const QString& theStudyName,
1955 bool theIsStudySaved )
1959 // create a new study
1962 // get active application
1963 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1965 // load study from the temporary directory
1966 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1968 PyConsole_Console* pyConsole = app->pythonConsole();
1970 pyConsole->execAndWait( command );
1972 // remove temporary directory
1973 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1974 QString aStudyName = aScriptInfo.baseName();
1975 QDir aDir = aScriptInfo.absoluteDir();
1976 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1977 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1978 ok = aDir.remove( *it ) && ok;
1980 ok = aDir.rmdir( aDir.absolutePath() );
1982 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1984 _PTR(Study) aStudyDS = newStudy->studyDS();
1985 app->getNoteBook()->Init( aStudyDS );
1986 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1987 newStudy->Modified();
1988 updateDesktopTitle();
1998 Close the Application
2000 void SalomeApp_Application::closeApplication()
2002 // emit signal to restore study from Python script
2004 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2005 myNoteBook->getDumpedStudyName(),
2006 myNoteBook->isDumpedStudySaved() );
2008 LightApp_Application::closeApplication();