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>
69 #include <SUIT_OverrideCursor.h>
71 #include <QtxTreeView.h>
73 #include <SALOME_EventFilter.h>
75 // temporary commented
76 //#include <OB_ListItem.h>
78 #include <PyConsole_Console.h>
80 #include <Utils_ORB_INIT.hxx>
81 #include <Utils_SINGLETON.hxx>
82 #include <SALOME_LifeCycleCORBA.hxx>
84 #include <QApplication>
88 #include <QPushButton>
90 #include <QListWidget>
91 #include <QGridLayout>
95 #include <SALOMEDSClient_ClientFactory.hxx>
96 #include <Basics_Utils.hxx>
98 #include <SALOME_ListIO.hxx>
99 #include <SALOME_ListIteratorOfListIO.hxx>
100 #include <SALOME_Prs.h>
103 #include <ToolsGUI_CatalogGeneratorDlg.h>
104 #include <ToolsGUI_RegWidget.h>
108 #include <SALOMEDS_Tool.hxx>
110 /*!Internal class that updates object browser item properties */
111 // temporary commented
112 /*class SalomeApp_Updater : public OB_Updater
115 SalomeApp_Updater() : OB_Updater(){};
116 virtual ~SalomeApp_Updater(){};
117 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
120 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
122 if( !theObj || !theItem )
125 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
129 _PTR(SObject) SObj = SAObj->object();
132 _PTR( GenericAttribute ) anAttr;
135 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
137 _PTR(AttributeSelectable) aAttrSel = anAttr;
138 theItem->setSelectable( aAttrSel->IsSelectable() );
141 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
143 _PTR(AttributeExpandable) aAttrExpand = anAttr;
144 theItem->setExpandable( aAttrExpand->IsExpandable() );
147 //this attribute is not supported in the version of SALOME 3.x
148 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
150 // _PTR(AttributeOpened) aAttrOpen = anAttr;
151 // theItem->setOpen( aAttrOpen->IsOpened() );
155 /*!Create new instance of SalomeApp_Application.*/
156 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
158 return new SalomeApp_Application();
162 SalomeApp_Application::SalomeApp_Application()
163 : LightApp_Application()
165 connect( desktop(), SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
166 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
170 *\li Destroy event filter.
172 SalomeApp_Application::~SalomeApp_Application()
174 // Do not destroy. It's a singleton !
175 //SALOME_EventFilter::Destroy();
178 /*!Start application.*/
179 void SalomeApp_Application::start()
181 LightApp_Application::start();
183 SALOME_EventFilter::Init();
185 static bool isFirst = true;
192 for (int i = 1; i < qApp->argc(); i++) {
193 QRegExp rxs ("--study-hdf=(.+)");
194 if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
195 QString file = rxs.capturedTexts()[1];
196 QFileInfo fi ( file );
197 QString extension = fi.suffix().toLower();
198 if ( extension == "hdf" && fi.exists() )
199 hdffile = fi.absoluteFilePath();
202 QRegExp rxp ("--pyscript=(.+)");
203 if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
204 QStringList files = rxp.capturedTexts()[1].split(",",QString::SkipEmptyParts);
210 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
211 onOpenDoc( hdffile );
212 else if ( pyfiles.count() > 0 ) // create new study
215 // import/execute python scripts
216 if ( pyfiles.count() > 0 && activeStudy() ) {
217 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
218 PyConsole_Console* pyConsole = pythonConsole();
219 if ( appStudy && pyConsole ) {
220 _PTR(Study) aStudy = appStudy->studyDS();
221 if ( !aStudy->GetProperties()->IsLocked() ) {
222 for (uint j = 0; j < pyfiles.count(); j++ ) {
223 QFileInfo fi ( pyfiles[j] );
224 QFileInfo fipy ( pyfiles[j] + ".py" );
225 QString command = QString( "execfile(r\"%1\")" );
226 if ( fi.isAbsolute() ) {
228 pyConsole->exec( command.arg( fi.absoluteFilePath() ) );
229 else if ( fipy.exists() )
230 pyConsole->exec( command.arg( fipy.absoluteFilePath() ) );
232 qDebug() << "Can't execute file" << pyfiles[j];
237 dirs << QDir::currentPath();
238 if ( ::getenv( "PYTHONPATH" ) )
239 dirs += QString( ::getenv( "PYTHONPATH" ) ).split( QRegExp( "[:|;]" ) );
240 foreach( QString dir, dirs ) {
241 qDebug() << "try" << QFileInfo( dir, pyfiles[j] ).absoluteFilePath();
242 qDebug() << "try" << QFileInfo( dir, pyfiles[j] + ".py" ).absoluteFilePath();
243 if ( QFileInfo( dir, pyfiles[j] ).exists() ) {
244 pyConsole->exec( command.arg( QFileInfo( dir, pyfiles[j] ).absoluteFilePath() ) );
248 else if ( QFileInfo( dir, pyfiles[j] + ".py" ).exists() ) {
249 pyConsole->exec( command.arg( QFileInfo( dir, pyfiles[j] + ".py" ).absoluteFilePath() ) );
255 qDebug() << "Can't execute file" << pyfiles[j];
266 void SalomeApp_Application::createActions()
268 LightApp_Application::createActions();
270 SUIT_Desktop* desk = desktop();
273 // "Save GUI State" command is moved to VISU module
274 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
275 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
276 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
279 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
280 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
281 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
284 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
285 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
286 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
289 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
290 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
291 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
293 //! Catalog Generator
294 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
295 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
296 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
299 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
300 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
301 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
303 //SRN: BugID IPAL9021, add an action "Load"
304 createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
305 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
306 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
307 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
308 //SRN: BugID IPAL9021: End
311 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
313 // "Save GUI State" command is renamed to "Save VISU State" and
314 // creation of menu item is moved to VISU
315 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
317 createMenu( FileLoadId, fileMenu, 0 ); //SRN: BugID IPAL9021, add a menu item "Load"
319 createMenu( DumpStudyId, fileMenu, 10, -1 );
320 createMenu( separator(), fileMenu, -1, 10, -1 );
321 createMenu( LoadScriptId, fileMenu, 10, -1 );
322 createMenu( separator(), fileMenu, -1, 10, -1 );
323 createMenu( PropertiesId, fileMenu, 10, -1 );
324 createMenu( separator(), fileMenu, -1, 10, -1 );
326 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
327 createMenu( CatalogGenId, toolsMenu, 10, -1 );
328 createMenu( RegDisplayId, toolsMenu, 10, -1 );
329 createMenu( separator(), toolsMenu, -1, 15, -1 );
331 createExtraActions();
333 // import Python module that manages SALOME plugins
334 PyGILState_STATE gstate = PyGILState_Ensure();
335 PyObject* pluginsmanager=PyImport_ImportModule((char*)"salome_pluginsmanager");
336 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());
340 Py_XDECREF(pluginsmanager);
341 PyGILState_Release(gstate);
342 // end of SALOME plugins loading
348 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
350 LightApp_Application::setDesktop( desk );
353 connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
354 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
359 \brief Close application.
361 void SalomeApp_Application::onExit()
363 bool killServers = false;
366 if ( exitConfirmation() ) {
367 SalomeApp_ExitDlg dlg( desktop() );
368 result = dlg.exec() == QDialog::Accepted;
369 killServers = dlg.isServersShutdown();
373 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
376 /*!SLOT. Load document.*/
377 void SalomeApp_Application::onLoadDoc()
381 std::vector<std::string> List = studyMgr()->GetOpenStudies();
383 SUIT_Session* aSession = SUIT_Session::session();
384 QList<SUIT_Application*> aAppList = aSession->applications();
386 QStringList unloadedStudies;
388 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
389 studyName = List[ind].c_str();
390 // Add to list only unloaded studies
391 bool isAlreadyOpen = false;
392 QListIterator<SUIT_Application*> it( aAppList );
393 while ( it.hasNext() && !isAlreadyOpen ) {
394 SUIT_Application* aApp = it.next();
395 if( !aApp || !aApp->activeStudy() )
397 if ( aApp->activeStudy()->studyName() == studyName )
398 isAlreadyOpen = true;
401 if ( !isAlreadyOpen )
402 unloadedStudies << studyName;
405 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
406 if ( studyName.isEmpty() )
410 // this code replaces marker of windows drive and path become invalid therefore
411 // defines placed there
412 studyName.replace( QRegExp(":"), "/" );
415 if ( onLoadDoc( studyName ) ) {
417 updateViewManagers();
418 updateObjectBrowser( true );
422 /*!SLOT. Create new study and load script*/
423 void SalomeApp_Application::onNewWithScript()
425 QStringList filtersList;
426 filtersList.append(tr("PYTHON_FILES_FILTER"));
427 filtersList.append(tr("ALL_FILES_FILTER"));
429 QString anInitialPath = "";
430 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
431 anInitialPath = QDir::currentPath();
433 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
435 if ( !aFile.isEmpty() )
439 QString command = QString("execfile(r\"%1\")").arg(aFile);
441 PyConsole_Console* pyConsole = pythonConsole();
444 pyConsole->exec( command );
449 /*!SLOT. Load document with \a aName.*/
450 bool SalomeApp_Application::onLoadDoc( const QString& aName )
453 if ( !activeStudy() ) {
454 // if no study - load in current desktop
455 res = useStudy( aName );
458 // if study exists - load in new desktop. Check: is the same file is loaded?
459 SUIT_Session* aSession = SUIT_Session::session();
460 QList<SUIT_Application*> aAppList = aSession->applications();
461 bool isAlreadyOpen = false;
462 SalomeApp_Application* aApp = 0;
463 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
464 it != aAppList.end() && !isAlreadyOpen; ++it ) {
465 aApp = dynamic_cast<SalomeApp_Application*>( *it );
466 if ( aApp && aApp->activeStudy()->studyName() == aName )
467 isAlreadyOpen = true;
469 if ( !isAlreadyOpen ) {
470 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
472 res = aApp->useStudy( aName );
475 aApp->desktop()->activateWindow();
482 /*!SLOT. Copy objects to study maneger from selection maneger..*/
483 void SalomeApp_Application::onCopy()
486 LightApp_SelectionMgr* mgr = selectionMgr();
487 mgr->selectedObjects(list);
489 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
490 if(study == NULL) return;
492 _PTR(Study) stdDS = study->studyDS();
495 SALOME_ListIteratorOfListIO it( list );
498 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
500 studyMgr()->Copy(so);
501 onSelectionChanged();
508 /*!SLOT. Paste objects to study maneger from selection manager.*/
509 void SalomeApp_Application::onPaste()
512 LightApp_SelectionMgr* mgr = selectionMgr();
513 mgr->selectedObjects(list);
515 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
516 if(study == NULL) return;
518 _PTR(Study) stdDS = study->studyDS();
521 if ( stdDS->GetProperties()->IsLocked() ) {
522 SUIT_MessageBox::warning( desktop(),
523 QObject::tr("WRN_WARNING"),
524 QObject::tr("WRN_STUDY_LOCKED") );
528 SALOME_ListIteratorOfListIO it( list );
531 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
533 studyMgr()->Paste(so);
534 updateObjectBrowser( true );
535 updateActions(); //SRN: BugID IPAL9377, case 3
542 /*!Check the application on closing.
543 * \retval true if possible, else false
545 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
547 return LightApp_Application::isPossibleToClose( closePermanently );
550 /*! Check if the study is locked */
551 void SalomeApp_Application::onCloseDoc( bool ask )
553 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
556 _PTR(Study) stdDS = study->studyDS();
557 if(stdDS && stdDS->IsStudyLocked()) {
558 if ( SUIT_MessageBox::question( desktop(),
559 QObject::tr( "WRN_WARNING" ),
560 QObject::tr( "CLOSE_LOCKED_STUDY" ),
561 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
562 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
567 LightApp_Application::onCloseDoc( ask );
570 /*!Sets enable or disable some actions on selection changed.*/
571 void SalomeApp_Application::onSelectionChanged()
574 LightApp_SelectionMgr* mgr = selectionMgr();
575 mgr->selectedObjects(list);
577 bool canCopy = false;
578 bool canPaste = false;
580 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
582 _PTR(Study) stdDS = study->studyDS();
585 SALOME_ListIteratorOfListIO it ( list );
587 if (it.More() && list.Extent() == 1) {
588 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
591 canCopy = studyMgr()->CanCopy(so);
592 canPaste = studyMgr()->CanPaste(so);
598 action(EditCopyId)->setEnabled(canCopy);
599 action(EditPasteId)->setEnabled(canPaste);
602 /*!Delete references.*/
603 void SalomeApp_Application::onDeleteInvalidReferences()
606 LightApp_SelectionMgr* mgr = selectionMgr();
607 mgr->selectedObjects( aList, QString(), false );
609 if( aList.IsEmpty() )
612 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
613 _PTR(Study) aStudyDS = aStudy->studyDS();
614 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
617 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
618 if ( it.Value()->hasEntry() )
620 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
621 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
624 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
625 aStudyBuilder->RemoveReference( aSObject );
627 updateObjectBrowser();
631 void SalomeApp_Application::onOpenWith()
633 QApplication::setOverrideCursor( Qt::WaitCursor );
635 LightApp_SelectionMgr* mgr = selectionMgr();
636 mgr->selectedObjects(aList);
637 if (aList.Extent() != 1)
639 QApplication::restoreOverrideCursor();
642 Handle(SALOME_InteractiveObject) aIObj = aList.First();
643 QString aModuleName(aIObj->getComponentDataType());
644 QString aModuleTitle = moduleTitle(aModuleName);
645 activateModule(aModuleTitle);
646 QApplication::restoreOverrideCursor();
652 SUIT_Study* SalomeApp_Application::createNewStudy()
654 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
656 // Set up processing of major study-related events
657 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
658 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
659 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
660 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
662 //to receive signal in application that NoteBook's variable was modified
663 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
664 this, SIGNAL(notebookVarUpdated(QString)) );
670 Enable/Disable menu items and toolbar buttons. Rebuild menu
672 void SalomeApp_Application::updateCommandsStatus()
674 LightApp_Application::updateCommandsStatus();
677 QAction* a = action( DumpStudyId );
679 a->setEnabled( activeStudy() );
682 a = action( LoadScriptId );
684 a->setEnabled( activeStudy() );
687 a = action( PropertiesId );
689 a->setEnabled( activeStudy() );
691 // Save GUI state menu
692 a = action( SaveGUIStateId );
694 a->setEnabled( activeStudy() );
696 // update state of Copy/Paste menu items
697 onSelectionChanged();
701 \class DumpStudyFileDlg
702 Private class used in Dump Study operation. Consists 2 check boxes:
703 "Publish in study" and "Save GUI parameters"
705 class DumpStudyFileDlg : public SUIT_FileDlg
708 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
710 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
713 QWidget *hB = new QWidget( this );
714 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
715 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
716 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
718 QHBoxLayout *layout = new QHBoxLayout;
719 layout->addWidget(myPublishChk);
720 layout->addWidget(myMultiFileChk);
721 layout->addWidget(mySaveGUIChk);
722 hB->setLayout(layout);
724 QPushButton* pb = new QPushButton(this);
726 int row = grid->rowCount();
727 grid->addWidget( new QLabel("", this), row, 0 );
728 grid->addWidget( hB, row, 1, 1, 3 );
729 grid->addWidget( pb, row, 5 );
734 QCheckBox* myPublishChk;
735 QCheckBox* myMultiFileChk;
736 QCheckBox* mySaveGUIChk;
739 class DumpStudyFileValidator : public SUIT_FileValidator
742 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
743 virtual ~DumpStudyFileValidator() {};
744 virtual bool canSave( const QString& file, bool permissions );
747 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
749 QFileInfo fi( file );
750 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
751 SUIT_MessageBox::critical( parent(),
752 QObject::tr("WRN_WARNING"),
753 QObject::tr("WRN_FILE_NAME_BAD") );
756 return SUIT_FileValidator::canSave( file, permissions);
759 /*!Private SLOT. On dump study.*/
760 void SalomeApp_Application::onDumpStudy( )
762 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
763 if ( !appStudy ) return;
764 _PTR(Study) aStudy = appStudy->studyDS();
766 QStringList aFilters;
767 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
769 bool anIsPublish = true;
770 bool anIsMultiFile = false;
771 bool anIsSaveGUI = true;
773 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
774 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
775 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
776 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
779 DumpStudyFileDlg fd( desktop() );
780 fd.setValidator( new DumpStudyFileValidator( &fd ) );
781 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
782 fd.setFilters( aFilters );
783 fd.myPublishChk->setChecked( anIsPublish );
784 fd.myMultiFileChk->setChecked( anIsMultiFile );
785 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
786 if ( fd.exec() == QDialog::Accepted )
788 QString aFileName = fd.selectedFile();
790 bool toPublish = fd.myPublishChk->isChecked();
791 bool isMultiFile = fd.myMultiFileChk->isChecked();
792 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
794 if ( !aFileName.isEmpty() ) {
795 QFileInfo aFileInfo(aFileName);
796 if( aFileInfo.isDir() ) // IPAL19257
799 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
802 SUIT_OverrideCursor wc;
803 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
806 SUIT_MessageBox::warning( desktop(),
807 QObject::tr("WRN_WARNING"),
808 tr("WRN_DUMP_STUDY_FAILED") );
813 /*!Private SLOT. On load script.*/
814 void SalomeApp_Application::onLoadScript( )
816 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
817 if ( !appStudy ) return;
818 _PTR(Study) aStudy = appStudy->studyDS();
820 if ( aStudy->GetProperties()->IsLocked() ) {
821 SUIT_MessageBox::warning( desktop(),
822 QObject::tr("WRN_WARNING"),
823 QObject::tr("WRN_STUDY_LOCKED") );
827 QStringList filtersList;
828 filtersList.append(tr("PYTHON_FILES_FILTER"));
829 filtersList.append(tr("ALL_FILES_FILTER"));
831 QString anInitialPath = "";
832 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
833 anInitialPath = QDir::currentPath();
835 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
837 if ( !aFile.isEmpty() )
839 QString command = QString("execfile(r\"%1\")").arg(aFile);
841 PyConsole_Console* pyConsole = pythonConsole();
844 pyConsole->exec( command );
848 /*!Private SLOT. On save GUI state.*/
849 void SalomeApp_Application::onSaveGUIState()
851 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
853 SalomeApp_VisualState( this ).storeState();
854 updateSavePointDataObjects( study );
855 updateObjectBrowser();
861 *\retval QString "(*.hdf)"
863 QString SalomeApp_Application::getFileFilter() const
869 QWidget* SalomeApp_Application::createWindow( const int flag )
872 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
874 SUIT_ResourceMgr* resMgr = resourceMgr();
876 if ( flag == WT_ObjectBrowser )
878 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
880 // temporary commented
881 //ob->setUpdater( new SalomeApp_Updater() );
883 #ifdef WITH_SALOMEDS_OBSERVER
884 //do not activate the automatic update of Qt tree through signal/slot
885 ob->setAutoUpdate(false);
886 //activate update of modified objects only
887 ob->setUpdateModified(true);
890 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
893 ValueCol = QObject::tr( "VALUE_COLUMN" ),
894 IORCol = QObject::tr( "IOR_COLUMN" ),
895 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
896 EntryCol = QObject::tr( "ENTRY_COLUMN" );
898 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
899 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
900 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
901 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
902 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
903 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
904 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
905 treeModel->setAppropriate( IORCol, Qtx::Toggled );
906 treeModel->setAppropriate( RefCol, Qtx::Toggled );
908 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
909 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
910 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
912 ob->setAutoSizeFirstColumn(autoSizeFirst);
913 ob->setAutoSizeColumns(autoSize);
914 ob->setResizeOnExpandItem(resizeOnExpandItem);
915 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
917 // temporary commented
919 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
921 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
922 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
923 QString().sprintf( "visibility_column_%d", i ), true ) );
927 // temporary commented
929 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
930 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
931 ob->resize( desktop()->width()/3, ob->height() );
935 else if ( flag == WT_PyConsole )
937 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
938 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
939 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
940 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
941 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
943 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
944 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
946 else if ( flag == WT_NoteBook )
948 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
950 _PTR(Study) aStudy = appStudy->studyDS();
951 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
952 //to receive signal in NoteBook that it's variable was modified
953 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
954 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
961 /*!Create preferences.*/
962 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
964 LightApp_Application::createPreferences(pref);
969 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
970 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
971 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
972 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
974 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
975 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
977 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
979 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
980 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
981 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
982 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
983 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
984 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
985 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
986 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
987 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
988 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
991 /*!Update desktop title.*/
992 void SalomeApp_Application::updateDesktopTitle() {
993 QString aTitle = applicationName();
994 QString aVer = applicationVersion();
995 if ( !aVer.isEmpty() )
996 aTitle += QString( " " ) + aVer;
1000 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1001 if ( !sName.isEmpty() ) {
1002 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1004 _PTR(Study) stdDS = study->studyDS();
1006 if ( stdDS->GetProperties()->IsLocked() ) {
1007 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1009 aTitle += QString( " - [%1]" ).arg( sName );
1016 desktop()->setWindowTitle( aTitle );
1019 int SalomeApp_Application::closeChoice( const QString& docName )
1021 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1022 tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1023 tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1025 int res = CloseCancel;
1028 else if ( answer == 1 )
1030 else if ( answer == 2 )
1036 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1042 if ( activeStudy()->isSaved() )
1044 else if ( !onSaveAsDoc() )
1050 closePermanently = false;
1060 int SalomeApp_Application::openChoice( const QString& aName )
1062 int choice = LightApp_Application::openChoice( aName );
1064 if ( QFileInfo( aName ).exists() ) {
1065 if ( choice == OpenNew ) { // The document isn't already open.
1067 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1068 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1069 if ( aName == QString( lst[i].c_str() ) )
1072 // The document already exists in the study manager.
1073 // Do you want to reload it?
1075 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1076 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1077 if ( answer == SUIT_MessageBox::Yes )
1078 choice = OpenRefresh;
1080 choice = OpenCancel;
1083 } else { // file is not exist on disk
1084 SUIT_MessageBox::warning( desktop(),
1085 QObject::tr("WRN_WARNING"),
1086 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1093 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1096 int choice = aChoice;
1101 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1104 studyMgr()->Close( aStudy );
1109 res = LightApp_Application::openAction( choice, aName );
1117 \brief Get map of the operations which can be performed
1118 on the module activation.
1120 The method should return the map of the kind \c {<id>:<name>}
1121 where \c <id> is an integer identifier of the operation and
1122 \c <name> is a title for the button to be added to the
1123 dialog box. After user selects the required operation by the
1124 clicking the corresponding button in the dialog box, its identifier
1125 is passed to the moduleActionSelected() method to process
1128 \return map of the operations
1129 \sa moduleActionSelected()
1131 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1133 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1134 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1135 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1140 \brief Called when the used selectes required operation chosen
1141 from "Activate module" dialog box.
1143 Performs the required operation according to the user choice.
1145 \param id operation identifier
1146 \sa activateModuleActions()
1148 void SalomeApp_Application::moduleActionSelected( const int id )
1154 case NewAndScriptId:
1158 LightApp_Application::moduleActionSelected( id );
1163 /*!Gets CORBA::ORB_var*/
1164 CORBA::ORB_var SalomeApp_Application::orb()
1166 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1167 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1171 /*!Create and return SALOMEDS_StudyManager.*/
1172 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1174 static _PTR(StudyManager) _sm;
1175 if(!_sm) _sm = ClientFactory::StudyManager();
1179 /*!Create and return SALOME_NamingService.*/
1180 SALOME_NamingService* SalomeApp_Application::namingService()
1182 static SALOME_NamingService _ns(orb());
1186 /*!Create and return SALOME_LifeCycleCORBA.*/
1187 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1189 static SALOME_LifeCycleCORBA _lcc( namingService() );
1193 /*!Private SLOT. On preferences.*/
1194 void SalomeApp_Application::onProperties()
1196 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1200 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1203 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1204 int res = aDlg.exec();
1205 if( res==QDialog::Accepted && aDlg.isChanged() )
1206 SB->CommitCommand();
1210 //study->updateCaptions();
1211 updateDesktopTitle();
1215 /*!Insert items in popup, which necessary for current application*/
1216 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1218 LightApp_SelectionMgr* mgr = selectionMgr();
1219 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1220 mgr->setSelectionCacheEnabled( true );
1222 LightApp_Application::contextMenuPopup( type, thePopup, title );
1224 // temporary commented
1225 /*OB_Browser* ob = objectBrowser();
1226 if ( !ob || type != ob->popupClientType() )
1229 // Get selected objects
1230 SALOME_ListIO aList;
1231 mgr->selectedObjects( aList, QString(), false );
1233 // add GUI state commands: restore, rename
1234 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1235 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1236 thePopup->addSeparator();
1237 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1238 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1239 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1240 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1243 // "Delete reference" item should appear only for invalid references
1245 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1246 bool isInvalidRefs = false;
1247 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1248 _PTR(Study) aStudyDS = aStudy->studyDS();
1249 _PTR(SObject) anObj;
1251 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1252 if( it.Value()->hasEntry() )
1254 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1255 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1258 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1259 isInvalidRefs = true;
1262 // Add "Delete reference" item to popup
1263 if ( isInvalidRefs )
1265 thePopup->addSeparator();
1266 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1270 // "Activate module" item should appear only if it's necessary
1271 if ( aList.Extent() == 1 ) {
1273 mgr->selectedObjects( aList );
1275 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1277 // add extra popup menu (defined in XML)
1278 if ( myExtActions.size() > 0 ) {
1279 // Use only first selected object
1280 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1282 _PTR(Study) stdDS = study->studyDS();
1284 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1286 _PTR( GenericAttribute ) anAttr;
1287 std::string auid = "AttributeUserID";
1288 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1289 if ( aSO->FindAttribute( anAttr, auid ) ) {
1290 _PTR(AttributeUserID) aAttrID = anAttr;
1291 QString aId = aAttrID->Value().c_str();
1292 if ( myExtActions.contains( aId ) ) {
1293 thePopup->addAction(myExtActions[aId]);
1301 // check if item is a "GUI state" item (also a first level object)
1302 QString entry( aIObj->getEntry() );
1303 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1304 QString aModuleName( aIObj->getComponentDataType() );
1305 QString aModuleTitle = moduleTitle( aModuleName );
1306 CAM_Module* currentModule = activeModule();
1307 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1308 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1312 mgr->setSelectionCacheEnabled( cacheIsOn );
1315 /*!Update obect browser:
1316 1.if 'updateModels' true, update existing data models;
1317 2. update "non-existing" (not loaded yet) data models;
1318 3. update object browser if it exists */
1319 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1321 // update "non-existing" (not loaded yet) data models
1322 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1325 _PTR(Study) stdDS = study->studyDS();
1328 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1330 _PTR(SComponent) aComponent ( it->Value() );
1332 #ifndef WITH_SALOMEDS_OBSERVER
1333 // with GUI observers this check is not needed anymore
1334 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1335 continue; // skip the magic "Interface Applicative" component
1337 if ( !objectBrowser() )
1338 getWindow( WT_ObjectBrowser );
1339 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1340 objectBrowser()->setAutoUpdate( false );
1341 SalomeApp_DataModel::synchronize( aComponent, study );
1342 objectBrowser()->setAutoUpdate( isAutoUpdate );
1347 // create data objects that correspond to GUI state save points
1348 if ( study ) updateSavePointDataObjects( study );
1350 // update existing data models (already loaded SComponents)
1351 LightApp_Application::updateObjectBrowser( updateModels );
1354 /*!Display Catalog Genenerator dialog */
1355 void SalomeApp_Application::onCatalogGen()
1357 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1361 /*!Display Registry Display dialog */
1362 void SalomeApp_Application::onRegDisplay()
1364 CORBA::ORB_var anOrb = orb();
1365 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1368 regWnd->activateWindow();
1371 /*!find original object by double click on item */
1372 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1374 // Issue 21379: References are supported at LightApp_DataObject level
1375 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1377 if( obj && obj->isReference() )
1379 QString entry = obj->refEntry();
1381 SUIT_DataOwnerPtrList aList;
1382 aList.append( new LightApp_DataOwner( entry ) );
1383 selectionMgr()->setSelected( aList, false );
1385 SUIT_DataBrowser* ob = objectBrowser();
1387 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1388 if ( !aSelectedIndexes.isEmpty() )
1389 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1394 Creates new view manager
1395 \param type - type of view manager
1397 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1399 return createViewManager(type);
1403 /*!Global utility funciton, returns selected GUI Save point object's ID */
1404 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1406 SALOME_ListIO aList;
1407 selMgr->selectedObjects( aList );
1408 if( aList.Extent() > 0 ) {
1409 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1410 QString entry( aIObj->getEntry() );
1411 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1412 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1414 bool ok; // conversion to integer is ok?
1415 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1416 return ok ? savePoint : -1;
1421 /*!Called on Restore GUI State popup command*/
1422 void SalomeApp_Application::onRestoreGUIState()
1424 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1425 if ( savePoint == -1 )
1427 SalomeApp_VisualState( this ).restoreState( savePoint );
1430 /*!Called on Delete GUI State popup command*/
1431 void SalomeApp_Application::onDeleteGUIState()
1433 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1434 if ( savePoint == -1 )
1436 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1440 study->removeSavePoint( savePoint );
1441 updateSavePointDataObjects( study );
1444 /*!Called on New study operation*/
1445 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1447 LightApp_Application::onStudyCreated( study );
1449 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1450 windowDock( getWindow( WT_ObjectBrowser ) ) );
1452 loadDockWindowsState();
1454 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1455 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1458 objectBrowserColumnsVisibility();
1461 /*!Called on Save study operation*/
1462 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1464 LightApp_Application::onStudySaved( study );
1466 // temporary commented
1467 /*if ( objectBrowser() ) {
1468 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1469 objectBrowser()->updateTree( study->root() );
1473 /*!Called on Open study operation*/
1474 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1476 LightApp_Application::onStudyOpened( study );
1478 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1479 windowDock( getWindow( WT_ObjectBrowser ) ) );
1481 loadDockWindowsState();
1483 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1484 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1486 objectBrowserColumnsVisibility();
1488 // temporary commented
1489 /*if ( objectBrowser() ) {
1490 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1491 objectBrowser()->updateTree( study->root() );
1495 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1496 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1499 SUIT_DataBrowser* ob = objectBrowser();
1500 LightApp_SelectionMgr* selMgr = selectionMgr();
1502 if ( !study || !ob || !selMgr )
1505 // find GUI states root object
1506 SUIT_DataObject* guiRootObj = 0;
1508 study->root()->children( ch );
1509 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1510 for ( ; it != last ; ++it ) {
1511 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1516 std::vector<int> savePoints = study->getSavePoints();
1517 // case 1: no more save points but they existed in study's tree
1518 if ( savePoints.empty() && guiRootObj ) {
1519 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1520 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1521 const bool isAutoUpdate = ob->autoUpdate();
1522 selMgr->clearSelected();
1523 ob->setAutoUpdate(true);
1524 DataObjectList ch = guiRootObj->children();
1525 for( int i = 0; i < ch.size(); i++ )
1528 ob->setAutoUpdate(isAutoUpdate);
1531 // case 2: no more save points but root does not exist either
1532 if ( savePoints.empty() && !guiRootObj )
1534 // case 3: save points but no root for them - create it
1535 if ( !savePoints.empty() && !guiRootObj )
1536 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1537 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1538 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1540 if ( guiRootObj->nextBrother() ) {
1541 study->root()->removeChild(guiRootObj);
1542 study->root()->appendChild(guiRootObj);
1543 //study->root()->dump();
1546 // store data objects in a map id-to-DataObject
1547 QMap<int,SalomeApp_SavePointObject*> mapDO;
1549 guiRootObj->children( ch );
1550 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1551 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1553 mapDO[dobj->getId()] = dobj;
1556 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1557 // if in the map - remove it from map.
1558 for ( int i = 0; i < savePoints.size(); i++ )
1559 if ( !mapDO.contains( savePoints[i] ) )
1560 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1562 mapDO.remove( savePoints[i] );
1564 // delete DataObjects that are still in the map -- their IDs were not found in data model
1565 if( mapDO.size() > 0) {
1566 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1567 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1568 selMgr->clearSelected();
1569 const bool isAutoUpdate = ob->autoUpdate();
1570 ob->setAutoUpdate(true);
1571 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1573 ob->setAutoUpdate(isAutoUpdate);
1577 /*! Check data object */
1578 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1587 Opens other study into active Study. If Study is empty - creates it.
1588 \param theName - name of study
1590 bool SalomeApp_Application::useStudy( const QString& theName )
1593 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1596 res = aStudy->loadDocument( theName );
1597 updateDesktopTitle();
1598 updateCommandsStatus();
1602 /*! Show/hide object browser colums according to preferences */
1603 void SalomeApp_Application::objectBrowserColumnsVisibility()
1605 if ( objectBrowser() )
1606 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1608 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1609 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1613 /*! Set SalomeApp_NoteBook pointer */
1614 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1616 myNoteBook = theNoteBook;
1619 /*! Return SalomeApp_NoteBook pointer */
1620 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1626 * Define extra actions defined in module definition XML file.
1627 * Additional popup items sections can be defined by parameter "popupitems".
1628 * Supported attributes:
1629 * title - title of menu item,
1630 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1631 * method - method which has to be called when menu item is selected
1633 * <section name="MODULENAME">
1634 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1636 * <section name="importmed">
1637 * <parameter name="title" value="My menu"/>
1638 * <parameter name="objectid" value="VISU.Result"/>
1639 * <parameter name="method" value="nameOfModuleMethod"/>
1642 void SalomeApp_Application::createExtraActions()
1644 myExtActions.clear();
1645 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1647 QStringList aModules;
1648 modules(aModules, false);
1649 foreach(QString aModile, aModules) {
1650 QString aModName = moduleName(aModile);
1651 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1652 if (!aSectionStr.isNull()) {
1653 QStringList aSections = aSectionStr.split(':');
1654 foreach(QString aSection, aSections) {
1655 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1656 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1657 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1658 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1661 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1662 if (aModuleName.isNull())
1663 aModuleName = aModName;
1665 QAction* aAction = new QAction(aTitle, this);
1667 aData<<aModuleName<<aSlot;
1668 aAction->setData(aData);
1669 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1670 myExtActions[aId] = aAction;
1677 * Called when extra action is selected
1679 void SalomeApp_Application::onExtAction()
1681 QAction* aAction = ::qobject_cast<QAction*>(sender());
1685 QVariant aData = aAction->data();
1686 QStringList aDataList = aData.value<QStringList>();
1687 if (aDataList.size() != 2)
1690 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1691 SALOME_ListIO aListIO;
1692 aSelectionMgr->selectedObjects(aListIO);
1693 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1694 if (aListIO.Extent() < 1)
1696 if (!anIO->hasEntry())
1699 QString aEntry(anIO->getEntry());
1701 QApplication::setOverrideCursor( Qt::WaitCursor );
1702 QString aModuleTitle = moduleTitle(aDataList[0]);
1703 activateModule(aModuleTitle);
1704 QApplication::restoreOverrideCursor();
1706 QCoreApplication::processEvents();
1708 CAM_Module* aModule = activeModule();
1712 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1713 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1717 * Called when window activated
1719 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1721 SUIT_DataBrowser* anOB = objectBrowser();
1724 SUIT_DataObject* rootObj = anOB->root();
1728 DataObjectList listObj = rootObj->children( true );
1730 SUIT_ViewModel* vmod = 0;
1731 if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1732 vmod = vman->getViewModel();
1733 updateVisibilityState( listObj, vmod );
1737 Update visibility state of given objects
1739 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1740 SUIT_ViewModel* theViewModel )
1742 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1747 SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1749 if (theList.isEmpty() || !aView || !aStudy)
1752 for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1753 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1755 if (!obj || aStudy->isComponent(obj->entry()))
1758 LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1759 Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1762 LightApp_Displayer* aDisplayer = anObjModule->displayer();
1764 if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1765 if(aDisplayer->IsDisplayed(obj->entry(),aView))
1766 anObjState = Qtx::ShownState;
1768 anObjState = Qtx::HiddenState;
1771 aStudy->setVisibilityState( obj->entry(), anObjState );
1777 Called then view manager removed
1779 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1781 ViewManagerList lst;
1783 if( lst.count() == 1) { // in case if closed last view window
1784 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1786 aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1791 Checks that an object can be renamed.
1792 \param entry entry of the object
1793 \brief Return \c true if object can be renamed
1795 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1797 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1801 Rename object by entry.
1802 \param entry entry of the object
1803 \param name new name of the object
1804 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1806 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1808 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1810 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1812 if(!aStudy || savePoint == -1)
1815 if ( !name.isNull() && !name.isEmpty() ) {
1816 aStudy->setNameOfSavePoint( savePoint, name );
1817 updateSavePointDataObjects( aStudy );
1819 //Mark study as modified
1827 \return default windows( Object Browser, Python Console )
1828 Adds to map \a aMap.
1830 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1832 LightApp_Application::defaultWindows(aMap);
1833 if ( !aMap.contains( WT_NoteBook ) ) {
1834 if ( !myNoteBook ) {
1835 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1841 Gets current windows.
1842 \param winMap - output current windows map.
1844 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1846 LightApp_Application::currentWindows( aMap );
1847 if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1848 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1851 //============================================================================
1852 /*! Function : onUpdateStudy
1853 * Purpose : Slot to update the study.
1855 //============================================================================
1856 void SalomeApp_Application::onUpdateStudy()
1858 QApplication::setOverrideCursor( Qt::WaitCursor );
1860 if( !updateStudy() )
1861 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1863 QApplication::restoreOverrideCursor();
1866 //============================================================================
1867 /*! Function : updateStudy
1868 * Purpose : Update study by dumping the study to Python script and loading it.
1869 * It is used to apply variable modifications done in NoteBook to created objects.
1871 //============================================================================
1872 bool SalomeApp_Application::updateStudy()
1874 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1875 if ( !study || !myNoteBook )
1878 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1879 myNoteBook->setDumpedStudyName( study->studyName() );
1881 _PTR(Study) studyDS = study->studyDS();
1883 // get unique temporary directory name
1884 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1885 if( aTmpDir.isEmpty() )
1888 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1889 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1891 // dump study to the temporary directory
1892 QString aScriptName( "notebook" );
1893 bool toPublish = true;
1894 bool isMultiFile = false;
1895 bool toSaveGUI = true;
1898 _PTR(AttributeParameter) ap;
1899 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1900 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1901 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1902 ip->setDumpPython(studyDS);
1903 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1905 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1907 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1910 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1914 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1915 int anIndex = aList.indexOf( this );
1917 // Disconnect dialog from application desktop in case if:
1918 // 1) Application is not the first application in the session
1919 // 2) Application is the first application in session but not the only.
1920 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1922 SalomeApp_Application* app;
1923 if( anIndex > 0 && anIndex < aList.count() )
1924 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1925 else if(anIndex == 0 && aList.count() > 1)
1926 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1931 if( changeDesktop ) {
1932 // creation a new study and restoring will be done in another application
1933 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1934 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1937 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1938 QString aStudyName = myNoteBook->getDumpedStudyName();
1939 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1940 // clear a study (delete all objects)
1941 onCloseDoc( false );
1943 if( !changeDesktop ) {
1944 ok = onRestoreStudy( aDumpScript,
1952 //============================================================================
1953 /*! Function : onRestoreStudy
1954 * Purpose : Load the dumped study from Python script
1956 //============================================================================
1957 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1958 const QString& theStudyName,
1959 bool theIsStudySaved )
1963 // create a new study
1966 // get active application
1967 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1969 // load study from the temporary directory
1970 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1972 PyConsole_Console* pyConsole = app->pythonConsole();
1974 pyConsole->execAndWait( command );
1976 // remove temporary directory
1977 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1978 QString aStudyName = aScriptInfo.baseName();
1979 QDir aDir = aScriptInfo.absoluteDir();
1980 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1981 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1982 ok = aDir.remove( *it ) && ok;
1984 ok = aDir.rmdir( aDir.absolutePath() );
1986 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1988 _PTR(Study) aStudyDS = newStudy->studyDS();
1989 app->getNoteBook()->Init( aStudyDS );
1990 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1991 newStudy->Modified();
1992 updateDesktopTitle();
2002 Close the Application
2004 void SalomeApp_Application::closeApplication()
2006 // emit signal to restore study from Python script
2008 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2009 myNoteBook->getDumpedStudyName(),
2010 myNoteBook->isDumpedStudySaved() );
2012 LightApp_Application::closeApplication();