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