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 PyGILState_Release(gstate);
340 // end of SALOME plugins loading
346 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
348 LightApp_Application::setDesktop( desk );
351 connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
352 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
357 \brief Close application.
359 void SalomeApp_Application::onExit()
361 bool killServers = false;
364 if ( exitConfirmation() ) {
365 SalomeApp_ExitDlg dlg( desktop() );
366 result = dlg.exec() == QDialog::Accepted;
367 killServers = dlg.isServersShutdown();
371 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
374 /*!SLOT. Load document.*/
375 void SalomeApp_Application::onLoadDoc()
379 std::vector<std::string> List = studyMgr()->GetOpenStudies();
381 SUIT_Session* aSession = SUIT_Session::session();
382 QList<SUIT_Application*> aAppList = aSession->applications();
384 QStringList unloadedStudies;
386 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
387 studyName = List[ind].c_str();
388 // Add to list only unloaded studies
389 bool isAlreadyOpen = false;
390 QListIterator<SUIT_Application*> it( aAppList );
391 while ( it.hasNext() && !isAlreadyOpen ) {
392 SUIT_Application* aApp = it.next();
393 if( !aApp || !aApp->activeStudy() )
395 if ( aApp->activeStudy()->studyName() == studyName )
396 isAlreadyOpen = true;
399 if ( !isAlreadyOpen )
400 unloadedStudies << studyName;
403 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
404 if ( studyName.isEmpty() )
408 // this code replaces marker of windows drive and path become invalid therefore
409 // defines placed there
410 studyName.replace( QRegExp(":"), "/" );
413 if ( onLoadDoc( studyName ) ) {
415 updateViewManagers();
416 updateObjectBrowser( true );
420 /*!SLOT. Create new study and load script*/
421 void SalomeApp_Application::onNewWithScript()
423 QStringList filtersList;
424 filtersList.append(tr("PYTHON_FILES_FILTER"));
425 filtersList.append(tr("ALL_FILES_FILTER"));
427 QString anInitialPath = "";
428 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
429 anInitialPath = QDir::currentPath();
431 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
433 if ( !aFile.isEmpty() )
437 QString command = QString("execfile(r\"%1\")").arg(aFile);
439 PyConsole_Console* pyConsole = pythonConsole();
442 pyConsole->exec( command );
447 /*!SLOT. Load document with \a aName.*/
448 bool SalomeApp_Application::onLoadDoc( const QString& aName )
451 if ( !activeStudy() ) {
452 // if no study - load in current desktop
453 res = useStudy( aName );
456 // if study exists - load in new desktop. Check: is the same file is loaded?
457 SUIT_Session* aSession = SUIT_Session::session();
458 QList<SUIT_Application*> aAppList = aSession->applications();
459 bool isAlreadyOpen = false;
460 SalomeApp_Application* aApp = 0;
461 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
462 it != aAppList.end() && !isAlreadyOpen; ++it ) {
463 aApp = dynamic_cast<SalomeApp_Application*>( *it );
464 if ( aApp && aApp->activeStudy()->studyName() == aName )
465 isAlreadyOpen = true;
467 if ( !isAlreadyOpen ) {
468 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
470 res = aApp->useStudy( aName );
473 aApp->desktop()->activateWindow();
480 /*!SLOT. Copy objects to study maneger from selection maneger..*/
481 void SalomeApp_Application::onCopy()
484 LightApp_SelectionMgr* mgr = selectionMgr();
485 mgr->selectedObjects(list);
487 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
488 if(study == NULL) return;
490 _PTR(Study) stdDS = study->studyDS();
493 SALOME_ListIteratorOfListIO it( list );
496 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
498 studyMgr()->Copy(so);
499 onSelectionChanged();
506 /*!SLOT. Paste objects to study maneger from selection manager.*/
507 void SalomeApp_Application::onPaste()
510 LightApp_SelectionMgr* mgr = selectionMgr();
511 mgr->selectedObjects(list);
513 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
514 if(study == NULL) return;
516 _PTR(Study) stdDS = study->studyDS();
519 if ( stdDS->GetProperties()->IsLocked() ) {
520 SUIT_MessageBox::warning( desktop(),
521 QObject::tr("WRN_WARNING"),
522 QObject::tr("WRN_STUDY_LOCKED") );
526 SALOME_ListIteratorOfListIO it( list );
529 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
531 studyMgr()->Paste(so);
532 updateObjectBrowser( true );
533 updateActions(); //SRN: BugID IPAL9377, case 3
540 /*!Check the application on closing.
541 * \retval true if possible, else false
543 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
545 return LightApp_Application::isPossibleToClose( closePermanently );
548 /*! Check if the study is locked */
549 void SalomeApp_Application::onCloseDoc( bool ask )
551 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
554 _PTR(Study) stdDS = study->studyDS();
555 if(stdDS && stdDS->IsStudyLocked()) {
556 if ( SUIT_MessageBox::question( desktop(),
557 QObject::tr( "WRN_WARNING" ),
558 QObject::tr( "CLOSE_LOCKED_STUDY" ),
559 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
560 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
565 LightApp_Application::onCloseDoc( ask );
568 /*!Sets enable or disable some actions on selection changed.*/
569 void SalomeApp_Application::onSelectionChanged()
572 LightApp_SelectionMgr* mgr = selectionMgr();
573 mgr->selectedObjects(list);
575 bool canCopy = false;
576 bool canPaste = false;
578 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
580 _PTR(Study) stdDS = study->studyDS();
583 SALOME_ListIteratorOfListIO it ( list );
585 if (it.More() && list.Extent() == 1) {
586 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
589 canCopy = studyMgr()->CanCopy(so);
590 canPaste = studyMgr()->CanPaste(so);
596 action(EditCopyId)->setEnabled(canCopy);
597 action(EditPasteId)->setEnabled(canPaste);
600 /*!Delete references.*/
601 void SalomeApp_Application::onDeleteInvalidReferences()
604 LightApp_SelectionMgr* mgr = selectionMgr();
605 mgr->selectedObjects( aList, QString(), false );
607 if( aList.IsEmpty() )
610 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
611 _PTR(Study) aStudyDS = aStudy->studyDS();
612 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
615 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
616 if ( it.Value()->hasEntry() )
618 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
619 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
622 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
623 aStudyBuilder->RemoveReference( aSObject );
625 updateObjectBrowser();
629 void SalomeApp_Application::onOpenWith()
631 QApplication::setOverrideCursor( Qt::WaitCursor );
633 LightApp_SelectionMgr* mgr = selectionMgr();
634 mgr->selectedObjects(aList);
635 if (aList.Extent() != 1)
637 QApplication::restoreOverrideCursor();
640 Handle(SALOME_InteractiveObject) aIObj = aList.First();
641 QString aModuleName(aIObj->getComponentDataType());
642 QString aModuleTitle = moduleTitle(aModuleName);
643 activateModule(aModuleTitle);
644 QApplication::restoreOverrideCursor();
650 SUIT_Study* SalomeApp_Application::createNewStudy()
652 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
654 // Set up processing of major study-related events
655 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
656 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
657 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
658 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
660 //to receive signal in application that NoteBook's variable was modified
661 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
662 this, SIGNAL(notebookVarUpdated(QString)) );
668 Enable/Disable menu items and toolbar buttons. Rebuild menu
670 void SalomeApp_Application::updateCommandsStatus()
672 LightApp_Application::updateCommandsStatus();
675 QAction* a = action( DumpStudyId );
677 a->setEnabled( activeStudy() );
680 a = action( LoadScriptId );
682 a->setEnabled( activeStudy() );
685 a = action( PropertiesId );
687 a->setEnabled( activeStudy() );
689 // Save GUI state menu
690 a = action( SaveGUIStateId );
692 a->setEnabled( activeStudy() );
694 // update state of Copy/Paste menu items
695 onSelectionChanged();
699 \class DumpStudyFileDlg
700 Private class used in Dump Study operation. Consists 2 check boxes:
701 "Publish in study" and "Save GUI parameters"
703 class DumpStudyFileDlg : public SUIT_FileDlg
706 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
708 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
711 QWidget *hB = new QWidget( this );
712 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
713 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
714 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
716 QHBoxLayout *layout = new QHBoxLayout;
717 layout->addWidget(myPublishChk);
718 layout->addWidget(myMultiFileChk);
719 layout->addWidget(mySaveGUIChk);
720 hB->setLayout(layout);
722 QPushButton* pb = new QPushButton(this);
724 int row = grid->rowCount();
725 grid->addWidget( new QLabel("", this), row, 0 );
726 grid->addWidget( hB, row, 1, 1, 3 );
727 grid->addWidget( pb, row, 5 );
732 QCheckBox* myPublishChk;
733 QCheckBox* myMultiFileChk;
734 QCheckBox* mySaveGUIChk;
737 class DumpStudyFileValidator : public SUIT_FileValidator
740 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
741 virtual ~DumpStudyFileValidator() {};
742 virtual bool canSave( const QString& file, bool permissions );
745 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
747 QFileInfo fi( file );
748 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
749 SUIT_MessageBox::critical( parent(),
750 QObject::tr("WRN_WARNING"),
751 QObject::tr("WRN_FILE_NAME_BAD") );
754 return SUIT_FileValidator::canSave( file, permissions);
757 /*!Private SLOT. On dump study.*/
758 void SalomeApp_Application::onDumpStudy( )
760 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
761 if ( !appStudy ) return;
762 _PTR(Study) aStudy = appStudy->studyDS();
764 QStringList aFilters;
765 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
767 bool anIsPublish = true;
768 bool anIsMultiFile = false;
769 bool anIsSaveGUI = true;
771 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
772 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
773 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
774 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
777 DumpStudyFileDlg fd( desktop() );
778 fd.setValidator( new DumpStudyFileValidator( &fd ) );
779 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
780 fd.setFilters( aFilters );
781 fd.myPublishChk->setChecked( anIsPublish );
782 fd.myMultiFileChk->setChecked( anIsMultiFile );
783 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
784 if ( fd.exec() == QDialog::Accepted )
786 QString aFileName = fd.selectedFile();
788 bool toPublish = fd.myPublishChk->isChecked();
789 bool isMultiFile = fd.myMultiFileChk->isChecked();
790 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
792 if ( !aFileName.isEmpty() ) {
793 QFileInfo aFileInfo(aFileName);
794 if( aFileInfo.isDir() ) // IPAL19257
797 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
798 bool res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
801 SUIT_MessageBox::warning( desktop(),
802 QObject::tr("WRN_WARNING"),
803 tr("WRN_DUMP_STUDY_FAILED") );
808 /*!Private SLOT. On load script.*/
809 void SalomeApp_Application::onLoadScript( )
811 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
812 if ( !appStudy ) return;
813 _PTR(Study) aStudy = appStudy->studyDS();
815 if ( aStudy->GetProperties()->IsLocked() ) {
816 SUIT_MessageBox::warning( desktop(),
817 QObject::tr("WRN_WARNING"),
818 QObject::tr("WRN_STUDY_LOCKED") );
822 QStringList filtersList;
823 filtersList.append(tr("PYTHON_FILES_FILTER"));
824 filtersList.append(tr("ALL_FILES_FILTER"));
826 QString anInitialPath = "";
827 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
828 anInitialPath = QDir::currentPath();
830 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
832 if ( !aFile.isEmpty() )
834 QString command = QString("execfile(r\"%1\")").arg(aFile);
836 PyConsole_Console* pyConsole = pythonConsole();
839 pyConsole->exec( command );
843 /*!Private SLOT. On save GUI state.*/
844 void SalomeApp_Application::onSaveGUIState()
846 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
848 SalomeApp_VisualState( this ).storeState();
849 updateSavePointDataObjects( study );
850 updateObjectBrowser();
856 *\retval QString "(*.hdf)"
858 QString SalomeApp_Application::getFileFilter() const
864 QWidget* SalomeApp_Application::createWindow( const int flag )
867 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
869 SUIT_ResourceMgr* resMgr = resourceMgr();
871 if ( flag == WT_ObjectBrowser )
873 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
875 // temporary commented
876 //ob->setUpdater( new SalomeApp_Updater() );
878 #ifdef WITH_SALOMEDS_OBSERVER
879 //do not activate the automatic update of Qt tree through signal/slot
880 ob->setAutoUpdate(false);
881 //activate update of modified objects only
882 ob->setUpdateModified(true);
885 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
888 ValueCol = QObject::tr( "VALUE_COLUMN" ),
889 IORCol = QObject::tr( "IOR_COLUMN" ),
890 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
891 EntryCol = QObject::tr( "ENTRY_COLUMN" );
893 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
894 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
895 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
896 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
897 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
898 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
899 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
900 treeModel->setAppropriate( IORCol, Qtx::Toggled );
901 treeModel->setAppropriate( RefCol, Qtx::Toggled );
903 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
904 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
905 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
907 ob->setAutoSizeFirstColumn(autoSizeFirst);
908 ob->setAutoSizeColumns(autoSize);
909 ob->setResizeOnExpandItem(resizeOnExpandItem);
910 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
912 // temporary commented
914 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
916 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
917 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
918 QString().sprintf( "visibility_column_%d", i ), true ) );
922 // temporary commented
924 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
925 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
926 ob->resize( desktop()->width()/3, ob->height() );
930 else if ( flag == WT_PyConsole )
932 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
933 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
934 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
935 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
936 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
938 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
939 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
941 else if ( flag == WT_NoteBook )
943 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
945 _PTR(Study) aStudy = appStudy->studyDS();
946 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
947 //to receive signal in NoteBook that it's variable was modified
948 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
949 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
956 /*!Create preferences.*/
957 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
959 LightApp_Application::createPreferences(pref);
964 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
965 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
966 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
967 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
969 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
970 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
972 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
974 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
975 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
976 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
977 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
978 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
979 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
980 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
981 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
982 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
983 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
986 /*!Update desktop title.*/
987 void SalomeApp_Application::updateDesktopTitle() {
988 QString aTitle = applicationName();
989 QString aVer = applicationVersion();
990 if ( !aVer.isEmpty() )
991 aTitle += QString( " " ) + aVer;
995 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
996 if ( !sName.isEmpty() ) {
997 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
999 _PTR(Study) stdDS = study->studyDS();
1001 if ( stdDS->GetProperties()->IsLocked() ) {
1002 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1004 aTitle += QString( " - [%1]" ).arg( sName );
1011 desktop()->setWindowTitle( aTitle );
1014 int SalomeApp_Application::closeChoice( const QString& docName )
1016 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1017 tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1018 tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1020 int res = CloseCancel;
1023 else if ( answer == 1 )
1025 else if ( answer == 2 )
1031 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1037 if ( activeStudy()->isSaved() )
1039 else if ( !onSaveAsDoc() )
1045 closePermanently = false;
1055 int SalomeApp_Application::openChoice( const QString& aName )
1057 int choice = LightApp_Application::openChoice( aName );
1059 if ( QFileInfo( aName ).exists() ) {
1060 if ( choice == OpenNew ) { // The document isn't already open.
1062 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1063 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1064 if ( aName == QString( lst[i].c_str() ) )
1067 // The document already exists in the study manager.
1068 // Do you want to reload it?
1070 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1071 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1072 if ( answer == SUIT_MessageBox::Yes )
1073 choice = OpenRefresh;
1075 choice = OpenCancel;
1078 } else { // file is not exist on disk
1079 SUIT_MessageBox::warning( desktop(),
1080 QObject::tr("WRN_WARNING"),
1081 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1088 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1091 int choice = aChoice;
1096 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1099 studyMgr()->Close( aStudy );
1104 res = LightApp_Application::openAction( choice, aName );
1112 \brief Get map of the operations which can be performed
1113 on the module activation.
1115 The method should return the map of the kind \c {<id>:<name>}
1116 where \c <id> is an integer identifier of the operation and
1117 \c <name> is a title for the button to be added to the
1118 dialog box. After user selects the required operation by the
1119 clicking the corresponding button in the dialog box, its identifier
1120 is passed to the moduleActionSelected() method to process
1123 \return map of the operations
1124 \sa moduleActionSelected()
1126 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1128 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1129 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1130 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1135 \brief Called when the used selectes required operation chosen
1136 from "Activate module" dialog box.
1138 Performs the required operation according to the user choice.
1140 \param id operation identifier
1141 \sa activateModuleActions()
1143 void SalomeApp_Application::moduleActionSelected( const int id )
1149 case NewAndScriptId:
1153 LightApp_Application::moduleActionSelected( id );
1158 /*!Gets CORBA::ORB_var*/
1159 CORBA::ORB_var SalomeApp_Application::orb()
1161 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1162 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1166 /*!Create and return SALOMEDS_StudyManager.*/
1167 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1169 static _PTR(StudyManager) _sm;
1170 if(!_sm) _sm = ClientFactory::StudyManager();
1174 /*!Create and return SALOME_NamingService.*/
1175 SALOME_NamingService* SalomeApp_Application::namingService()
1177 static SALOME_NamingService _ns(orb());
1181 /*!Create and return SALOME_LifeCycleCORBA.*/
1182 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1184 static SALOME_LifeCycleCORBA _lcc( namingService() );
1188 /*!Private SLOT. On preferences.*/
1189 void SalomeApp_Application::onProperties()
1191 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1195 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1198 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1199 int res = aDlg.exec();
1200 if( res==QDialog::Accepted && aDlg.isChanged() )
1201 SB->CommitCommand();
1205 //study->updateCaptions();
1206 updateDesktopTitle();
1210 /*!Insert items in popup, which necessary for current application*/
1211 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1213 LightApp_SelectionMgr* mgr = selectionMgr();
1214 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1215 mgr->setSelectionCacheEnabled( true );
1217 LightApp_Application::contextMenuPopup( type, thePopup, title );
1219 // temporary commented
1220 /*OB_Browser* ob = objectBrowser();
1221 if ( !ob || type != ob->popupClientType() )
1224 // Get selected objects
1225 SALOME_ListIO aList;
1226 mgr->selectedObjects( aList, QString(), false );
1228 // add GUI state commands: restore, rename
1229 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1230 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1231 thePopup->addSeparator();
1232 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1233 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1234 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1235 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1238 // "Delete reference" item should appear only for invalid references
1240 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1241 bool isInvalidRefs = false;
1242 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1243 _PTR(Study) aStudyDS = aStudy->studyDS();
1244 _PTR(SObject) anObj;
1246 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1247 if( it.Value()->hasEntry() )
1249 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1250 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1253 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1254 isInvalidRefs = true;
1257 // Add "Delete reference" item to popup
1258 if ( isInvalidRefs )
1260 thePopup->addSeparator();
1261 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1265 // "Activate module" item should appear only if it's necessary
1266 if ( aList.Extent() == 1 ) {
1268 mgr->selectedObjects( aList );
1270 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1272 // add extra popup menu (defined in XML)
1273 if ( myExtActions.size() > 0 ) {
1274 // Use only first selected object
1275 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1277 _PTR(Study) stdDS = study->studyDS();
1279 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1281 _PTR( GenericAttribute ) anAttr;
1282 std::string auid = "AttributeUserID";
1283 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1284 if ( aSO->FindAttribute( anAttr, auid ) ) {
1285 _PTR(AttributeUserID) aAttrID = anAttr;
1286 QString aId = aAttrID->Value().c_str();
1287 if ( myExtActions.contains( aId ) ) {
1288 thePopup->addAction(myExtActions[aId]);
1296 // check if item is a "GUI state" item (also a first level object)
1297 QString entry( aIObj->getEntry() );
1298 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1299 QString aModuleName( aIObj->getComponentDataType() );
1300 QString aModuleTitle = moduleTitle( aModuleName );
1301 CAM_Module* currentModule = activeModule();
1302 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1303 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1307 mgr->setSelectionCacheEnabled( cacheIsOn );
1310 /*!Update obect browser:
1311 1.if 'updateModels' true, update existing data models;
1312 2. update "non-existing" (not loaded yet) data models;
1313 3. update object browser if it exists */
1314 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1316 // update "non-existing" (not loaded yet) data models
1317 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1320 _PTR(Study) stdDS = study->studyDS();
1323 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1325 _PTR(SComponent) aComponent ( it->Value() );
1327 #ifndef WITH_SALOMEDS_OBSERVER
1328 // with GUI observers this check is not needed anymore
1329 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1330 continue; // skip the magic "Interface Applicative" component
1332 if ( !objectBrowser() )
1333 getWindow( WT_ObjectBrowser );
1334 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1335 objectBrowser()->setAutoUpdate( false );
1336 SalomeApp_DataModel::synchronize( aComponent, study );
1337 objectBrowser()->setAutoUpdate( isAutoUpdate );
1342 // create data objects that correspond to GUI state save points
1343 if ( study ) updateSavePointDataObjects( study );
1345 // update existing data models (already loaded SComponents)
1346 LightApp_Application::updateObjectBrowser( updateModels );
1349 /*!Display Catalog Genenerator dialog */
1350 void SalomeApp_Application::onCatalogGen()
1352 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1356 /*!Display Registry Display dialog */
1357 void SalomeApp_Application::onRegDisplay()
1359 CORBA::ORB_var anOrb = orb();
1360 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1363 regWnd->activateWindow();
1366 /*!find original object by double click on item */
1367 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1369 // Issue 21379: References are supported at LightApp_DataObject level
1370 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1372 if( obj && obj->isReference() )
1374 QString entry = obj->refEntry();
1376 SUIT_DataOwnerPtrList aList;
1377 aList.append( new LightApp_DataOwner( entry ) );
1378 selectionMgr()->setSelected( aList, false );
1380 SUIT_DataBrowser* ob = objectBrowser();
1382 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1383 if ( !aSelectedIndexes.isEmpty() )
1384 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1389 Creates new view manager
1390 \param type - type of view manager
1392 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1394 return createViewManager(type);
1398 /*!Global utility funciton, returns selected GUI Save point object's ID */
1399 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1401 SALOME_ListIO aList;
1402 selMgr->selectedObjects( aList );
1403 if( aList.Extent() > 0 ) {
1404 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1405 QString entry( aIObj->getEntry() );
1406 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1407 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1409 bool ok; // conversion to integer is ok?
1410 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1411 return ok ? savePoint : -1;
1416 /*!Called on Restore GUI State popup command*/
1417 void SalomeApp_Application::onRestoreGUIState()
1419 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1420 if ( savePoint == -1 )
1422 SalomeApp_VisualState( this ).restoreState( savePoint );
1425 /*!Called on Delete GUI State popup command*/
1426 void SalomeApp_Application::onDeleteGUIState()
1428 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1429 if ( savePoint == -1 )
1431 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1435 study->removeSavePoint( savePoint );
1436 updateSavePointDataObjects( study );
1439 /*!Called on New study operation*/
1440 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1442 LightApp_Application::onStudyCreated( study );
1444 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1445 windowDock( getWindow( WT_ObjectBrowser ) ) );
1447 loadDockWindowsState();
1449 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1450 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1453 objectBrowserColumnsVisibility();
1456 /*!Called on Save study operation*/
1457 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1459 LightApp_Application::onStudySaved( study );
1461 // temporary commented
1462 /*if ( objectBrowser() ) {
1463 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1464 objectBrowser()->updateTree( study->root() );
1468 /*!Called on Open study operation*/
1469 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1471 LightApp_Application::onStudyOpened( study );
1473 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1474 windowDock( getWindow( WT_ObjectBrowser ) ) );
1476 loadDockWindowsState();
1478 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1479 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1481 objectBrowserColumnsVisibility();
1483 // temporary commented
1484 /*if ( objectBrowser() ) {
1485 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1486 objectBrowser()->updateTree( study->root() );
1490 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1491 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1494 SUIT_DataBrowser* ob = objectBrowser();
1495 LightApp_SelectionMgr* selMgr = selectionMgr();
1497 if ( !study || !ob || !selMgr )
1500 // find GUI states root object
1501 SUIT_DataObject* guiRootObj = 0;
1503 study->root()->children( ch );
1504 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1505 for ( ; it != last ; ++it ) {
1506 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1511 std::vector<int> savePoints = study->getSavePoints();
1512 // case 1: no more save points but they existed in study's tree
1513 if ( savePoints.empty() && guiRootObj ) {
1514 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1515 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1516 const bool isAutoUpdate = ob->autoUpdate();
1517 selMgr->clearSelected();
1518 ob->setAutoUpdate(true);
1519 DataObjectList ch = guiRootObj->children();
1520 for( int i = 0; i < ch.size(); i++ )
1523 ob->setAutoUpdate(isAutoUpdate);
1526 // case 2: no more save points but root does not exist either
1527 if ( savePoints.empty() && !guiRootObj )
1529 // case 3: save points but no root for them - create it
1530 if ( !savePoints.empty() && !guiRootObj )
1531 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1532 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1533 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1535 if ( guiRootObj->nextBrother() ) {
1536 study->root()->removeChild(guiRootObj);
1537 study->root()->appendChild(guiRootObj);
1538 //study->root()->dump();
1541 // store data objects in a map id-to-DataObject
1542 QMap<int,SalomeApp_SavePointObject*> mapDO;
1544 guiRootObj->children( ch );
1545 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1546 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1548 mapDO[dobj->getId()] = dobj;
1551 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1552 // if in the map - remove it from map.
1553 for ( int i = 0; i < savePoints.size(); i++ )
1554 if ( !mapDO.contains( savePoints[i] ) )
1555 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1557 mapDO.remove( savePoints[i] );
1559 // delete DataObjects that are still in the map -- their IDs were not found in data model
1560 if( mapDO.size() > 0) {
1561 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1562 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1563 selMgr->clearSelected();
1564 const bool isAutoUpdate = ob->autoUpdate();
1565 ob->setAutoUpdate(true);
1566 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1568 ob->setAutoUpdate(isAutoUpdate);
1572 /*! Check data object */
1573 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1582 Opens other study into active Study. If Study is empty - creates it.
1583 \param theName - name of study
1585 bool SalomeApp_Application::useStudy( const QString& theName )
1588 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1591 res = aStudy->loadDocument( theName );
1592 updateDesktopTitle();
1593 updateCommandsStatus();
1597 /*! Show/hide object browser colums according to preferences */
1598 void SalomeApp_Application::objectBrowserColumnsVisibility()
1600 if ( objectBrowser() )
1601 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1603 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1604 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1608 /*! Set SalomeApp_NoteBook pointer */
1609 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1611 myNoteBook = theNoteBook;
1614 /*! Return SalomeApp_NoteBook pointer */
1615 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1621 * Define extra actions defined in module definition XML file.
1622 * Additional popup items sections can be defined by parameter "popupitems".
1623 * Supported attributes:
1624 * title - title of menu item,
1625 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1626 * method - method which has to be called when menu item is selected
1628 * <section name="MODULENAME">
1629 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1631 * <section name="importmed">
1632 * <parameter name="title" value="My menu"/>
1633 * <parameter name="objectid" value="VISU.Result"/>
1634 * <parameter name="method" value="nameOfModuleMethod"/>
1637 void SalomeApp_Application::createExtraActions()
1639 myExtActions.clear();
1640 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1642 QStringList aModules;
1643 modules(aModules, false);
1644 foreach(QString aModile, aModules) {
1645 QString aModName = moduleName(aModile);
1646 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1647 if (!aSectionStr.isNull()) {
1648 QStringList aSections = aSectionStr.split(':');
1649 foreach(QString aSection, aSections) {
1650 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1651 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1652 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1653 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1656 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1657 if (aModuleName.isNull())
1658 aModuleName = aModName;
1660 QAction* aAction = new QAction(aTitle, this);
1662 aData<<aModuleName<<aSlot;
1663 aAction->setData(aData);
1664 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1665 myExtActions[aId] = aAction;
1672 * Called when extra action is selected
1674 void SalomeApp_Application::onExtAction()
1676 QAction* aAction = ::qobject_cast<QAction*>(sender());
1680 QVariant aData = aAction->data();
1681 QStringList aDataList = aData.value<QStringList>();
1682 if (aDataList.size() != 2)
1685 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1686 SALOME_ListIO aListIO;
1687 aSelectionMgr->selectedObjects(aListIO);
1688 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1689 if (aListIO.Extent() < 1)
1691 if (!anIO->hasEntry())
1694 QString aEntry(anIO->getEntry());
1696 QApplication::setOverrideCursor( Qt::WaitCursor );
1697 QString aModuleTitle = moduleTitle(aDataList[0]);
1698 activateModule(aModuleTitle);
1699 QApplication::restoreOverrideCursor();
1701 QCoreApplication::processEvents();
1703 CAM_Module* aModule = activeModule();
1707 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1708 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1712 * Called when window activated
1714 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1716 SUIT_DataBrowser* anOB = objectBrowser();
1719 SUIT_DataObject* rootObj = anOB->root();
1723 DataObjectList listObj = rootObj->children( true );
1725 SUIT_ViewModel* vmod = 0;
1726 if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1727 vmod = vman->getViewModel();
1728 updateVisibilityState( listObj, vmod );
1732 Update visibility state of given objects
1734 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1735 SUIT_ViewModel* theViewModel )
1737 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1742 SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1744 if (theList.isEmpty() || !aView || !aStudy)
1747 for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1748 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1750 if (!obj || aStudy->isComponent(obj->entry()))
1753 LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1754 Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1757 LightApp_Displayer* aDisplayer = anObjModule->displayer();
1759 if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1760 if(aDisplayer->IsDisplayed(obj->entry(),aView))
1761 anObjState = Qtx::ShownState;
1763 anObjState = Qtx::HiddenState;
1766 aStudy->setVisibilityState( obj->entry(), anObjState );
1772 Called then view manager removed
1774 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1776 ViewManagerList lst;
1778 if( lst.count() == 1) { // in case if closed last view window
1779 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1781 aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1786 Checks that an object can be renamed.
1787 \param entry entry of the object
1788 \brief Return \c true if object can be renamed
1790 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1792 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1796 Rename object by entry.
1797 \param entry entry of the object
1798 \param name new name of the object
1799 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1801 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1803 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1805 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1807 if(!aStudy || savePoint == -1)
1810 if ( !name.isNull() && !name.isEmpty() ) {
1811 aStudy->setNameOfSavePoint( savePoint, name );
1812 updateSavePointDataObjects( aStudy );
1814 //Mark study as modified
1822 \return default windows( Object Browser, Python Console )
1823 Adds to map \a aMap.
1825 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1827 LightApp_Application::defaultWindows(aMap);
1828 if ( !aMap.contains( WT_NoteBook ) ) {
1829 if ( !myNoteBook ) {
1830 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1836 Gets current windows.
1837 \param winMap - output current windows map.
1839 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1841 LightApp_Application::currentWindows( aMap );
1842 if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1843 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1846 //============================================================================
1847 /*! Function : onUpdateStudy
1848 * Purpose : Slot to update the study.
1850 //============================================================================
1851 void SalomeApp_Application::onUpdateStudy()
1853 QApplication::setOverrideCursor( Qt::WaitCursor );
1855 if( !updateStudy() )
1856 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1858 QApplication::restoreOverrideCursor();
1861 //============================================================================
1862 /*! Function : updateStudy
1863 * Purpose : Update study by dumping the study to Python script and loading it.
1864 * It is used to apply variable modifications done in NoteBook to created objects.
1866 //============================================================================
1867 bool SalomeApp_Application::updateStudy()
1869 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1870 if ( !study || !myNoteBook )
1873 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1874 myNoteBook->setDumpedStudyName( study->studyName() );
1876 _PTR(Study) studyDS = study->studyDS();
1878 // get unique temporary directory name
1879 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1880 if( aTmpDir.isEmpty() )
1883 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1884 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1886 // dump study to the temporary directory
1887 QString aScriptName( "notebook" );
1888 bool toPublish = true;
1889 bool isMultiFile = false;
1890 bool toSaveGUI = true;
1893 _PTR(AttributeParameter) ap;
1894 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1895 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1896 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1897 ip->setDumpPython(studyDS);
1898 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1900 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1902 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1905 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1909 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1910 int anIndex = aList.indexOf( this );
1912 // Disconnect dialog from application desktop in case if:
1913 // 1) Application is not the first application in the session
1914 // 2) Application is the first application in session but not the only.
1915 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1917 SalomeApp_Application* app;
1918 if( anIndex > 0 && anIndex < aList.count() )
1919 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1920 else if(anIndex == 0 && aList.count() > 1)
1921 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1926 if( changeDesktop ) {
1927 // creation a new study and restoring will be done in another application
1928 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1929 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1932 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1933 QString aStudyName = myNoteBook->getDumpedStudyName();
1934 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1935 // clear a study (delete all objects)
1936 onCloseDoc( false );
1938 if( !changeDesktop ) {
1939 ok = onRestoreStudy( aDumpScript,
1947 //============================================================================
1948 /*! Function : onRestoreStudy
1949 * Purpose : Load the dumped study from Python script
1951 //============================================================================
1952 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1953 const QString& theStudyName,
1954 bool theIsStudySaved )
1958 // create a new study
1961 // get active application
1962 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1964 // load study from the temporary directory
1965 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1967 PyConsole_Console* pyConsole = app->pythonConsole();
1969 pyConsole->execAndWait( command );
1971 // remove temporary directory
1972 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1973 QString aStudyName = aScriptInfo.baseName();
1974 QDir aDir = aScriptInfo.absoluteDir();
1975 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1976 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1977 ok = aDir.remove( *it ) && ok;
1979 ok = aDir.rmdir( aDir.absolutePath() );
1981 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1983 _PTR(Study) aStudyDS = newStudy->studyDS();
1984 app->getNoteBook()->Init( aStudyDS );
1985 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1986 newStudy->Modified();
1987 updateDesktopTitle();
1997 Close the Application
1999 void SalomeApp_Application::closeApplication()
2001 // emit signal to restore study from Python script
2003 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2004 myNoteBook->getDumpedStudyName(),
2005 myNoteBook->isDumpedStudySaved() );
2007 LightApp_Application::closeApplication();