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()) {
251 script.remove( QRegExp("^python.*[\\s]+") );
252 QString cmd = script+" "+args;
253 QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
254 pyConsole->exec(command);
256 } // end for loop on pyfiles QStringList
264 void SalomeApp_Application::createActions()
266 LightApp_Application::createActions();
268 SUIT_Desktop* desk = desktop();
271 // "Save GUI State" command is moved to VISU module
272 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
273 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
274 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
277 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
278 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
279 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
282 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
283 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
284 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
287 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
288 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
289 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
291 //! Catalog Generator
292 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
293 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
294 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
297 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
298 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
299 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
301 //SRN: BugID IPAL9021, add an action "Load"
302 createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
303 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
304 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
305 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
306 //SRN: BugID IPAL9021: End
309 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
311 // "Save GUI State" command is renamed to "Save VISU State" and
312 // creation of menu item is moved to VISU
313 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
315 createMenu( FileLoadId, fileMenu, 0 ); //SRN: BugID IPAL9021, add a menu item "Load"
317 createMenu( DumpStudyId, fileMenu, 10, -1 );
318 createMenu( separator(), fileMenu, -1, 10, -1 );
319 createMenu( LoadScriptId, fileMenu, 10, -1 );
320 createMenu( separator(), fileMenu, -1, 10, -1 );
321 createMenu( PropertiesId, fileMenu, 10, -1 );
322 createMenu( separator(), fileMenu, -1, 10, -1 );
324 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
325 createMenu( CatalogGenId, toolsMenu, 10, -1 );
326 createMenu( RegDisplayId, toolsMenu, 10, -1 );
327 createMenu( separator(), toolsMenu, -1, 15, -1 );
329 createExtraActions();
331 // import Python module that manages SALOME plugins
332 PyGILState_STATE gstate = PyGILState_Ensure();
333 PyObject* pluginsmanager=PyImport_ImportModule((char*)"salome_pluginsmanager");
334 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());
338 Py_XDECREF(pluginsmanager);
339 PyGILState_Release(gstate);
340 // end of SALOME plugins loading
346 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
348 LightApp_Application::setDesktop( desk );
351 connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
352 this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
357 \brief Close application.
359 void SalomeApp_Application::onExit()
361 bool killServers = false;
364 if ( exitConfirmation() ) {
365 SalomeApp_ExitDlg dlg( desktop() );
366 result = dlg.exec() == QDialog::Accepted;
367 killServers = dlg.isServersShutdown();
371 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
374 /*!SLOT. Load document.*/
375 void SalomeApp_Application::onLoadDoc()
379 std::vector<std::string> List = studyMgr()->GetOpenStudies();
381 SUIT_Session* aSession = SUIT_Session::session();
382 QList<SUIT_Application*> aAppList = aSession->applications();
384 QStringList unloadedStudies;
386 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
387 studyName = List[ind].c_str();
388 // Add to list only unloaded studies
389 bool isAlreadyOpen = false;
390 QListIterator<SUIT_Application*> it( aAppList );
391 while ( it.hasNext() && !isAlreadyOpen ) {
392 SUIT_Application* aApp = it.next();
393 if( !aApp || !aApp->activeStudy() )
395 if ( aApp->activeStudy()->studyName() == studyName )
396 isAlreadyOpen = true;
399 if ( !isAlreadyOpen )
400 unloadedStudies << studyName;
403 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
404 if ( studyName.isEmpty() )
408 // this code replaces marker of windows drive and path become invalid therefore
409 // defines placed there
410 studyName.replace( QRegExp(":"), "/" );
413 if ( onLoadDoc( studyName ) ) {
415 updateViewManagers();
416 updateObjectBrowser( true );
420 /*!SLOT. Create new study and load script*/
421 void SalomeApp_Application::onNewWithScript()
423 QStringList filtersList;
424 filtersList.append(tr("PYTHON_FILES_FILTER"));
425 filtersList.append(tr("ALL_FILES_FILTER"));
427 QString anInitialPath = "";
428 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
429 anInitialPath = QDir::currentPath();
431 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
433 if ( !aFile.isEmpty() )
437 QString command = QString("execfile(r\"%1\")").arg(aFile);
439 PyConsole_Console* pyConsole = pythonConsole();
442 pyConsole->exec( command );
447 /*!SLOT. Load document with \a aName.*/
448 bool SalomeApp_Application::onLoadDoc( const QString& aName )
451 if ( !activeStudy() ) {
452 // if no study - load in current desktop
453 res = useStudy( aName );
456 // if study exists - load in new desktop. Check: is the same file is loaded?
457 SUIT_Session* aSession = SUIT_Session::session();
458 QList<SUIT_Application*> aAppList = aSession->applications();
459 bool isAlreadyOpen = false;
460 SalomeApp_Application* aApp = 0;
461 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
462 it != aAppList.end() && !isAlreadyOpen; ++it ) {
463 aApp = dynamic_cast<SalomeApp_Application*>( *it );
464 if ( aApp && aApp->activeStudy()->studyName() == aName )
465 isAlreadyOpen = true;
467 if ( !isAlreadyOpen ) {
468 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
470 res = aApp->useStudy( aName );
473 aApp->desktop()->activateWindow();
480 /*!SLOT. Copy objects to study maneger from selection maneger..*/
481 void SalomeApp_Application::onCopy()
484 LightApp_SelectionMgr* mgr = selectionMgr();
485 mgr->selectedObjects(list);
487 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
488 if(study == NULL) return;
490 _PTR(Study) stdDS = study->studyDS();
493 SALOME_ListIteratorOfListIO it( list );
496 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
498 studyMgr()->Copy(so);
499 onSelectionChanged();
506 /*!SLOT. Paste objects to study maneger from selection manager.*/
507 void SalomeApp_Application::onPaste()
510 LightApp_SelectionMgr* mgr = selectionMgr();
511 mgr->selectedObjects(list);
513 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
514 if(study == NULL) return;
516 _PTR(Study) stdDS = study->studyDS();
519 if ( stdDS->GetProperties()->IsLocked() ) {
520 SUIT_MessageBox::warning( desktop(),
521 QObject::tr("WRN_WARNING"),
522 QObject::tr("WRN_STUDY_LOCKED") );
526 SALOME_ListIteratorOfListIO it( list );
529 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
531 studyMgr()->Paste(so);
532 updateObjectBrowser( true );
533 updateActions(); //SRN: BugID IPAL9377, case 3
540 /*!Check the application on closing.
541 * \retval true if possible, else false
543 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
545 return LightApp_Application::isPossibleToClose( closePermanently );
548 /*! Check if the study is locked */
549 void SalomeApp_Application::onCloseDoc( bool ask )
551 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
554 _PTR(Study) stdDS = study->studyDS();
555 if(stdDS && stdDS->IsStudyLocked()) {
556 if ( SUIT_MessageBox::question( desktop(),
557 QObject::tr( "WRN_WARNING" ),
558 QObject::tr( "CLOSE_LOCKED_STUDY" ),
559 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
560 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
565 LightApp_Application::onCloseDoc( ask );
568 /*!Sets enable or disable some actions on selection changed.*/
569 void SalomeApp_Application::onSelectionChanged()
572 LightApp_SelectionMgr* mgr = selectionMgr();
573 mgr->selectedObjects(list);
575 bool canCopy = false;
576 bool canPaste = false;
578 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
580 _PTR(Study) stdDS = study->studyDS();
583 SALOME_ListIteratorOfListIO it ( list );
585 if (it.More() && list.Extent() == 1) {
586 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
589 canCopy = studyMgr()->CanCopy(so);
590 canPaste = studyMgr()->CanPaste(so);
596 action(EditCopyId)->setEnabled(canCopy);
597 action(EditPasteId)->setEnabled(canPaste);
600 /*!Delete references.*/
601 void SalomeApp_Application::onDeleteInvalidReferences()
604 LightApp_SelectionMgr* mgr = selectionMgr();
605 mgr->selectedObjects( aList, QString(), false );
607 if( aList.IsEmpty() )
610 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
611 _PTR(Study) aStudyDS = aStudy->studyDS();
612 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
615 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
616 if ( it.Value()->hasEntry() )
618 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
619 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
622 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
623 aStudyBuilder->RemoveReference( aSObject );
625 updateObjectBrowser();
629 void SalomeApp_Application::onOpenWith()
631 QApplication::setOverrideCursor( Qt::WaitCursor );
633 LightApp_SelectionMgr* mgr = selectionMgr();
634 mgr->selectedObjects(aList);
635 if (aList.Extent() != 1)
637 QApplication::restoreOverrideCursor();
640 Handle(SALOME_InteractiveObject) aIObj = aList.First();
641 QString aModuleName(aIObj->getComponentDataType());
642 QString aModuleTitle = moduleTitle(aModuleName);
643 activateModule(aModuleTitle);
644 QApplication::restoreOverrideCursor();
650 SUIT_Study* SalomeApp_Application::createNewStudy()
652 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
654 // Set up processing of major study-related events
655 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
656 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
657 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
658 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
660 //to receive signal in application that NoteBook's variable was modified
661 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
662 this, SIGNAL(notebookVarUpdated(QString)) );
668 Enable/Disable menu items and toolbar buttons. Rebuild menu
670 void SalomeApp_Application::updateCommandsStatus()
672 LightApp_Application::updateCommandsStatus();
675 QAction* a = action( DumpStudyId );
677 a->setEnabled( activeStudy() );
680 a = action( LoadScriptId );
682 a->setEnabled( activeStudy() );
685 a = action( PropertiesId );
687 a->setEnabled( activeStudy() );
689 // Save GUI state menu
690 a = action( SaveGUIStateId );
692 a->setEnabled( activeStudy() );
694 // update state of Copy/Paste menu items
695 onSelectionChanged();
699 \class DumpStudyFileDlg
700 Private class used in Dump Study operation. Consists 2 check boxes:
701 "Publish in study" and "Save GUI parameters"
703 class DumpStudyFileDlg : public SUIT_FileDlg
706 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
708 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
711 QWidget *hB = new QWidget( this );
712 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
713 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
714 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
716 QHBoxLayout *layout = new QHBoxLayout;
717 layout->addWidget(myPublishChk);
718 layout->addWidget(myMultiFileChk);
719 layout->addWidget(mySaveGUIChk);
720 hB->setLayout(layout);
722 QPushButton* pb = new QPushButton(this);
724 int row = grid->rowCount();
725 grid->addWidget( new QLabel("", this), row, 0 );
726 grid->addWidget( hB, row, 1, 1, 3 );
727 grid->addWidget( pb, row, 5 );
732 QCheckBox* myPublishChk;
733 QCheckBox* myMultiFileChk;
734 QCheckBox* mySaveGUIChk;
737 class DumpStudyFileValidator : public SUIT_FileValidator
740 DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
741 virtual ~DumpStudyFileValidator() {};
742 virtual bool canSave( const QString& file, bool permissions );
745 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
747 QFileInfo fi( file );
748 if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
749 SUIT_MessageBox::critical( parent(),
750 QObject::tr("WRN_WARNING"),
751 QObject::tr("WRN_FILE_NAME_BAD") );
754 return SUIT_FileValidator::canSave( file, permissions);
757 /*!Private SLOT. On dump study.*/
758 void SalomeApp_Application::onDumpStudy( )
760 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
761 if ( !appStudy ) return;
762 _PTR(Study) aStudy = appStudy->studyDS();
764 QStringList aFilters;
765 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
767 bool anIsPublish = true;
768 bool anIsMultiFile = false;
769 bool anIsSaveGUI = true;
771 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
772 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
773 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
774 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
777 DumpStudyFileDlg fd( desktop() );
778 fd.setValidator( new DumpStudyFileValidator( &fd ) );
779 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
780 fd.setFilters( aFilters );
781 fd.myPublishChk->setChecked( anIsPublish );
782 fd.myMultiFileChk->setChecked( anIsMultiFile );
783 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
784 if ( fd.exec() == QDialog::Accepted )
786 QString aFileName = fd.selectedFile();
788 bool toPublish = fd.myPublishChk->isChecked();
789 bool isMultiFile = fd.myMultiFileChk->isChecked();
790 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
792 if ( !aFileName.isEmpty() ) {
793 QFileInfo aFileInfo(aFileName);
794 if( aFileInfo.isDir() ) // IPAL19257
797 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
800 SUIT_OverrideCursor wc;
801 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
804 SUIT_MessageBox::warning( desktop(),
805 QObject::tr("WRN_WARNING"),
806 tr("WRN_DUMP_STUDY_FAILED") );
811 /*!Private SLOT. On load script.*/
812 void SalomeApp_Application::onLoadScript( )
814 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
815 if ( !appStudy ) return;
816 _PTR(Study) aStudy = appStudy->studyDS();
818 if ( aStudy->GetProperties()->IsLocked() ) {
819 SUIT_MessageBox::warning( desktop(),
820 QObject::tr("WRN_WARNING"),
821 QObject::tr("WRN_STUDY_LOCKED") );
825 QStringList filtersList;
826 filtersList.append(tr("PYTHON_FILES_FILTER"));
827 filtersList.append(tr("ALL_FILES_FILTER"));
829 QString anInitialPath = "";
830 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
831 anInitialPath = QDir::currentPath();
833 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
835 if ( !aFile.isEmpty() )
837 QString command = QString("execfile(r\"%1\")").arg(aFile);
839 PyConsole_Console* pyConsole = pythonConsole();
842 pyConsole->exec( command );
846 /*!Private SLOT. On save GUI state.*/
847 void SalomeApp_Application::onSaveGUIState()
849 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
851 SalomeApp_VisualState( this ).storeState();
852 updateSavePointDataObjects( study );
853 updateObjectBrowser();
859 *\retval QString "(*.hdf)"
861 QString SalomeApp_Application::getFileFilter() const
867 QWidget* SalomeApp_Application::createWindow( const int flag )
870 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
872 SUIT_ResourceMgr* resMgr = resourceMgr();
874 if ( flag == WT_ObjectBrowser )
876 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
878 // temporary commented
879 //ob->setUpdater( new SalomeApp_Updater() );
881 #ifdef WITH_SALOMEDS_OBSERVER
882 //do not activate the automatic update of Qt tree through signal/slot
883 ob->setAutoUpdate(false);
884 //activate update of modified objects only
885 ob->setUpdateModified(true);
888 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
891 ValueCol = QObject::tr( "VALUE_COLUMN" ),
892 IORCol = QObject::tr( "IOR_COLUMN" ),
893 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
894 EntryCol = QObject::tr( "ENTRY_COLUMN" );
896 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
897 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
898 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
899 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
900 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
901 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
902 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
903 treeModel->setAppropriate( IORCol, Qtx::Toggled );
904 treeModel->setAppropriate( RefCol, Qtx::Toggled );
906 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
907 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
908 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
910 ob->setAutoSizeFirstColumn(autoSizeFirst);
911 ob->setAutoSizeColumns(autoSize);
912 ob->setResizeOnExpandItem(resizeOnExpandItem);
913 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
915 // temporary commented
917 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
919 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
920 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
921 QString().sprintf( "visibility_column_%d", i ), true ) );
925 // temporary commented
927 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
928 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
929 ob->resize( desktop()->width()/3, ob->height() );
933 else if ( flag == WT_PyConsole )
935 PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
936 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
937 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
938 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
939 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
941 //pyCons->resize( pyCons->width(), desktop()->height()/4 );
942 pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
944 else if ( flag == WT_NoteBook )
946 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
948 _PTR(Study) aStudy = appStudy->studyDS();
949 setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
950 //to receive signal in NoteBook that it's variable was modified
951 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
952 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
959 /*!Create preferences.*/
960 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
962 LightApp_Application::createPreferences(pref);
967 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
968 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
969 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
970 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
972 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
973 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
975 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
977 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
978 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
979 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
980 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
981 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
982 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
983 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
984 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
985 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
986 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
989 /*!Update desktop title.*/
990 void SalomeApp_Application::updateDesktopTitle() {
991 QString aTitle = applicationName();
992 QString aVer = applicationVersion();
993 if ( !aVer.isEmpty() )
994 aTitle += QString( " " ) + aVer;
998 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
999 if ( !sName.isEmpty() ) {
1000 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1002 _PTR(Study) stdDS = study->studyDS();
1004 if ( stdDS->GetProperties()->IsLocked() ) {
1005 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1007 aTitle += QString( " - [%1]" ).arg( sName );
1014 desktop()->setWindowTitle( aTitle );
1017 int SalomeApp_Application::closeChoice( const QString& docName )
1019 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1020 tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1021 tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1023 int res = CloseCancel;
1026 else if ( answer == 1 )
1028 else if ( answer == 2 )
1034 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1040 if ( activeStudy()->isSaved() )
1042 else if ( !onSaveAsDoc() )
1048 closePermanently = false;
1058 int SalomeApp_Application::openChoice( const QString& aName )
1060 int choice = LightApp_Application::openChoice( aName );
1062 if ( QFileInfo( aName ).exists() ) {
1063 if ( choice == OpenNew ) { // The document isn't already open.
1065 std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1066 for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1067 if ( aName == QString( lst[i].c_str() ) )
1070 // The document already exists in the study manager.
1071 // Do you want to reload it?
1073 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1074 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1075 if ( answer == SUIT_MessageBox::Yes )
1076 choice = OpenRefresh;
1078 choice = OpenCancel;
1081 } else { // file is not exist on disk
1082 SUIT_MessageBox::warning( desktop(),
1083 QObject::tr("WRN_WARNING"),
1084 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1091 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1094 int choice = aChoice;
1099 _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1102 studyMgr()->Close( aStudy );
1107 res = LightApp_Application::openAction( choice, aName );
1115 \brief Get map of the operations which can be performed
1116 on the module activation.
1118 The method should return the map of the kind \c {<id>:<name>}
1119 where \c <id> is an integer identifier of the operation and
1120 \c <name> is a title for the button to be added to the
1121 dialog box. After user selects the required operation by the
1122 clicking the corresponding button in the dialog box, its identifier
1123 is passed to the moduleActionSelected() method to process
1126 \return map of the operations
1127 \sa moduleActionSelected()
1129 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1131 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1132 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1133 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1138 \brief Called when the used selectes required operation chosen
1139 from "Activate module" dialog box.
1141 Performs the required operation according to the user choice.
1143 \param id operation identifier
1144 \sa activateModuleActions()
1146 void SalomeApp_Application::moduleActionSelected( const int id )
1152 case NewAndScriptId:
1156 LightApp_Application::moduleActionSelected( id );
1161 /*!Gets CORBA::ORB_var*/
1162 CORBA::ORB_var SalomeApp_Application::orb()
1164 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1165 static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1169 /*!Create and return SALOMEDS_StudyManager.*/
1170 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1172 static _PTR(StudyManager) _sm;
1173 if(!_sm) _sm = ClientFactory::StudyManager();
1177 /*!Create and return SALOME_NamingService.*/
1178 SALOME_NamingService* SalomeApp_Application::namingService()
1180 static SALOME_NamingService _ns(orb());
1184 /*!Create and return SALOME_LifeCycleCORBA.*/
1185 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1187 static SALOME_LifeCycleCORBA _lcc( namingService() );
1191 /*!Private SLOT. On preferences.*/
1192 void SalomeApp_Application::onProperties()
1194 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1198 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1201 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1202 int res = aDlg.exec();
1203 if( res==QDialog::Accepted && aDlg.isChanged() )
1204 SB->CommitCommand();
1208 //study->updateCaptions();
1209 updateDesktopTitle();
1213 /*!Insert items in popup, which necessary for current application*/
1214 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1216 LightApp_SelectionMgr* mgr = selectionMgr();
1217 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1218 mgr->setSelectionCacheEnabled( true );
1220 LightApp_Application::contextMenuPopup( type, thePopup, title );
1222 // temporary commented
1223 /*OB_Browser* ob = objectBrowser();
1224 if ( !ob || type != ob->popupClientType() )
1227 // Get selected objects
1228 SALOME_ListIO aList;
1229 mgr->selectedObjects( aList, QString(), false );
1231 // add GUI state commands: restore, rename
1232 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1233 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1234 thePopup->addSeparator();
1235 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1236 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1237 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1238 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1241 // "Delete reference" item should appear only for invalid references
1243 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1244 bool isInvalidRefs = false;
1245 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1246 _PTR(Study) aStudyDS = aStudy->studyDS();
1247 _PTR(SObject) anObj;
1249 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1250 if( it.Value()->hasEntry() )
1252 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1253 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1256 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1257 isInvalidRefs = true;
1260 // Add "Delete reference" item to popup
1261 if ( isInvalidRefs )
1263 thePopup->addSeparator();
1264 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1268 // "Activate module" item should appear only if it's necessary
1269 if ( aList.Extent() == 1 ) {
1271 mgr->selectedObjects( aList );
1273 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1275 // add extra popup menu (defined in XML)
1276 if ( myExtActions.size() > 0 ) {
1277 // Use only first selected object
1278 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1280 _PTR(Study) stdDS = study->studyDS();
1282 _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1284 _PTR( GenericAttribute ) anAttr;
1285 std::string auid = "AttributeUserID";
1286 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1287 if ( aSO->FindAttribute( anAttr, auid ) ) {
1288 _PTR(AttributeUserID) aAttrID = anAttr;
1289 QString aId = aAttrID->Value().c_str();
1290 if ( myExtActions.contains( aId ) ) {
1291 thePopup->addAction(myExtActions[aId]);
1299 // check if item is a "GUI state" item (also a first level object)
1300 QString entry( aIObj->getEntry() );
1301 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1302 QString aModuleName( aIObj->getComponentDataType() );
1303 QString aModuleTitle = moduleTitle( aModuleName );
1304 CAM_Module* currentModule = activeModule();
1305 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1306 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1310 mgr->setSelectionCacheEnabled( cacheIsOn );
1313 /*!Update obect browser:
1314 1.if 'updateModels' true, update existing data models;
1315 2. update "non-existing" (not loaded yet) data models;
1316 3. update object browser if it exists */
1317 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1319 // update "non-existing" (not loaded yet) data models
1320 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1323 _PTR(Study) stdDS = study->studyDS();
1326 for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1328 _PTR(SComponent) aComponent ( it->Value() );
1330 #ifndef WITH_SALOMEDS_OBSERVER
1331 // with GUI observers this check is not needed anymore
1332 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1333 continue; // skip the magic "Interface Applicative" component
1335 if ( !objectBrowser() )
1336 getWindow( WT_ObjectBrowser );
1337 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1338 objectBrowser()->setAutoUpdate( false );
1339 SalomeApp_DataModel::synchronize( aComponent, study );
1340 objectBrowser()->setAutoUpdate( isAutoUpdate );
1345 // create data objects that correspond to GUI state save points
1346 if ( study ) updateSavePointDataObjects( study );
1348 // update existing data models (already loaded SComponents)
1349 LightApp_Application::updateObjectBrowser( updateModels );
1352 /*!Display Catalog Genenerator dialog */
1353 void SalomeApp_Application::onCatalogGen()
1355 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1359 /*!Display Registry Display dialog */
1360 void SalomeApp_Application::onRegDisplay()
1362 CORBA::ORB_var anOrb = orb();
1363 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1366 regWnd->activateWindow();
1369 /*!find original object by double click on item */
1370 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1372 // Issue 21379: References are supported at LightApp_DataObject level
1373 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1375 if( obj && obj->isReference() )
1377 QString entry = obj->refEntry();
1379 SUIT_DataOwnerPtrList aList;
1380 aList.append( new LightApp_DataOwner( entry ) );
1381 selectionMgr()->setSelected( aList, false );
1383 SUIT_DataBrowser* ob = objectBrowser();
1385 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1386 if ( !aSelectedIndexes.isEmpty() )
1387 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1392 Creates new view manager
1393 \param type - type of view manager
1395 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1397 return createViewManager(type);
1401 /*!Global utility funciton, returns selected GUI Save point object's ID */
1402 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1404 SALOME_ListIO aList;
1405 selMgr->selectedObjects( aList );
1406 if( aList.Extent() > 0 ) {
1407 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1408 QString entry( aIObj->getEntry() );
1409 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1410 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1412 bool ok; // conversion to integer is ok?
1413 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1414 return ok ? savePoint : -1;
1419 /*!Called on Restore GUI State popup command*/
1420 void SalomeApp_Application::onRestoreGUIState()
1422 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1423 if ( savePoint == -1 )
1425 SalomeApp_VisualState( this ).restoreState( savePoint );
1428 /*!Called on Delete GUI State popup command*/
1429 void SalomeApp_Application::onDeleteGUIState()
1431 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1432 if ( savePoint == -1 )
1434 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1438 study->removeSavePoint( savePoint );
1439 updateSavePointDataObjects( study );
1442 /*!Called on New study operation*/
1443 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1445 LightApp_Application::onStudyCreated( study );
1447 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1448 windowDock( getWindow( WT_ObjectBrowser ) ) );
1450 loadDockWindowsState();
1452 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1453 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1456 objectBrowserColumnsVisibility();
1459 /*!Called on Save study operation*/
1460 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1462 LightApp_Application::onStudySaved( study );
1464 // temporary commented
1465 /*if ( objectBrowser() ) {
1466 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1467 objectBrowser()->updateTree( study->root() );
1471 /*!Called on Open study operation*/
1472 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1474 LightApp_Application::onStudyOpened( study );
1476 desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1477 windowDock( getWindow( WT_ObjectBrowser ) ) );
1479 loadDockWindowsState();
1481 connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1482 this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1484 objectBrowserColumnsVisibility();
1486 // temporary commented
1487 /*if ( objectBrowser() ) {
1488 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1489 objectBrowser()->updateTree( study->root() );
1493 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1494 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1497 SUIT_DataBrowser* ob = objectBrowser();
1498 LightApp_SelectionMgr* selMgr = selectionMgr();
1500 if ( !study || !ob || !selMgr )
1503 // find GUI states root object
1504 SUIT_DataObject* guiRootObj = 0;
1506 study->root()->children( ch );
1507 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1508 for ( ; it != last ; ++it ) {
1509 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1514 std::vector<int> savePoints = study->getSavePoints();
1515 // case 1: no more save points but they existed in study's tree
1516 if ( savePoints.empty() && guiRootObj ) {
1517 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1518 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1519 const bool isAutoUpdate = ob->autoUpdate();
1520 selMgr->clearSelected();
1521 ob->setAutoUpdate(true);
1522 DataObjectList ch = guiRootObj->children();
1523 for( int i = 0; i < ch.size(); i++ )
1526 ob->setAutoUpdate(isAutoUpdate);
1529 // case 2: no more save points but root does not exist either
1530 if ( savePoints.empty() && !guiRootObj )
1532 // case 3: save points but no root for them - create it
1533 if ( !savePoints.empty() && !guiRootObj )
1534 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1535 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1536 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1538 if ( guiRootObj->nextBrother() ) {
1539 study->root()->removeChild(guiRootObj);
1540 study->root()->appendChild(guiRootObj);
1541 //study->root()->dump();
1544 // store data objects in a map id-to-DataObject
1545 QMap<int,SalomeApp_SavePointObject*> mapDO;
1547 guiRootObj->children( ch );
1548 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1549 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1551 mapDO[dobj->getId()] = dobj;
1554 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1555 // if in the map - remove it from map.
1556 for ( int i = 0; i < savePoints.size(); i++ )
1557 if ( !mapDO.contains( savePoints[i] ) )
1558 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1560 mapDO.remove( savePoints[i] );
1562 // delete DataObjects that are still in the map -- their IDs were not found in data model
1563 if( mapDO.size() > 0) {
1564 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1565 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1566 selMgr->clearSelected();
1567 const bool isAutoUpdate = ob->autoUpdate();
1568 ob->setAutoUpdate(true);
1569 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1571 ob->setAutoUpdate(isAutoUpdate);
1575 /*! Check data object */
1576 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1585 Opens other study into active Study. If Study is empty - creates it.
1586 \param theName - name of study
1588 bool SalomeApp_Application::useStudy( const QString& theName )
1591 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1594 res = aStudy->loadDocument( theName );
1595 updateDesktopTitle();
1596 updateCommandsStatus();
1600 /*! Show/hide object browser colums according to preferences */
1601 void SalomeApp_Application::objectBrowserColumnsVisibility()
1603 if ( objectBrowser() )
1604 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1606 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1607 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1611 /*! Set SalomeApp_NoteBook pointer */
1612 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1614 myNoteBook = theNoteBook;
1617 /*! Return SalomeApp_NoteBook pointer */
1618 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1624 * Define extra actions defined in module definition XML file.
1625 * Additional popup items sections can be defined by parameter "popupitems".
1626 * Supported attributes:
1627 * title - title of menu item,
1628 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1629 * method - method which has to be called when menu item is selected
1631 * <section name="MODULENAME">
1632 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1634 * <section name="importmed">
1635 * <parameter name="title" value="My menu"/>
1636 * <parameter name="objectid" value="VISU.Result"/>
1637 * <parameter name="method" value="nameOfModuleMethod"/>
1640 void SalomeApp_Application::createExtraActions()
1642 myExtActions.clear();
1643 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1645 QStringList aModules;
1646 modules(aModules, false);
1647 foreach(QString aModile, aModules) {
1648 QString aModName = moduleName(aModile);
1649 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1650 if (!aSectionStr.isNull()) {
1651 QStringList aSections = aSectionStr.split(':');
1652 foreach(QString aSection, aSections) {
1653 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1654 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1655 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1656 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1659 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1660 if (aModuleName.isNull())
1661 aModuleName = aModName;
1663 QAction* aAction = new QAction(aTitle, this);
1665 aData<<aModuleName<<aSlot;
1666 aAction->setData(aData);
1667 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1668 myExtActions[aId] = aAction;
1675 * Called when extra action is selected
1677 void SalomeApp_Application::onExtAction()
1679 QAction* aAction = ::qobject_cast<QAction*>(sender());
1683 QVariant aData = aAction->data();
1684 QStringList aDataList = aData.value<QStringList>();
1685 if (aDataList.size() != 2)
1688 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1689 SALOME_ListIO aListIO;
1690 aSelectionMgr->selectedObjects(aListIO);
1691 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1692 if (aListIO.Extent() < 1)
1694 if (!anIO->hasEntry())
1697 QString aEntry(anIO->getEntry());
1699 QApplication::setOverrideCursor( Qt::WaitCursor );
1700 QString aModuleTitle = moduleTitle(aDataList[0]);
1701 activateModule(aModuleTitle);
1702 QApplication::restoreOverrideCursor();
1704 QCoreApplication::processEvents();
1706 CAM_Module* aModule = activeModule();
1710 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1711 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1715 * Called when window activated
1717 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1719 SUIT_DataBrowser* anOB = objectBrowser();
1722 SUIT_DataObject* rootObj = anOB->root();
1726 DataObjectList listObj = rootObj->children( true );
1728 SUIT_ViewModel* vmod = 0;
1729 if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1730 vmod = vman->getViewModel();
1731 updateVisibilityState( listObj, vmod );
1735 Update visibility state of given objects
1737 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1738 SUIT_ViewModel* theViewModel )
1740 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1745 SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1747 if (theList.isEmpty() || !aView || !aStudy)
1750 for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1751 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1753 if (!obj || aStudy->isComponent(obj->entry()))
1756 LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1757 Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1760 LightApp_Displayer* aDisplayer = anObjModule->displayer();
1762 if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1763 if(aDisplayer->IsDisplayed(obj->entry(),aView))
1764 anObjState = Qtx::ShownState;
1766 anObjState = Qtx::HiddenState;
1769 aStudy->setVisibilityState( obj->entry(), anObjState );
1775 Called then view manager removed
1777 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1779 ViewManagerList lst;
1781 if( lst.count() == 1) { // in case if closed last view window
1782 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1784 aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1789 Checks that an object can be renamed.
1790 \param entry entry of the object
1791 \brief Return \c true if object can be renamed
1793 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1795 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1799 Rename object by entry.
1800 \param entry entry of the object
1801 \param name new name of the object
1802 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1804 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1806 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1808 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1810 if(!aStudy || savePoint == -1)
1813 if ( !name.isNull() && !name.isEmpty() ) {
1814 aStudy->setNameOfSavePoint( savePoint, name );
1815 updateSavePointDataObjects( aStudy );
1817 //Mark study as modified
1825 \return default windows( Object Browser, Python Console )
1826 Adds to map \a aMap.
1828 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1830 LightApp_Application::defaultWindows(aMap);
1831 if ( !aMap.contains( WT_NoteBook ) ) {
1832 if ( !myNoteBook ) {
1833 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1839 Gets current windows.
1840 \param winMap - output current windows map.
1842 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1844 LightApp_Application::currentWindows( aMap );
1845 if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1846 aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1849 //============================================================================
1850 /*! Function : onUpdateStudy
1851 * Purpose : Slot to update the study.
1853 //============================================================================
1854 void SalomeApp_Application::onUpdateStudy()
1856 QApplication::setOverrideCursor( Qt::WaitCursor );
1858 if( !updateStudy() )
1859 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1861 QApplication::restoreOverrideCursor();
1864 //============================================================================
1865 /*! Function : updateStudy
1866 * Purpose : Update study by dumping the study to Python script and loading it.
1867 * It is used to apply variable modifications done in NoteBook to created objects.
1869 //============================================================================
1870 bool SalomeApp_Application::updateStudy()
1872 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1873 if ( !study || !myNoteBook )
1876 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1877 myNoteBook->setDumpedStudyName( study->studyName() );
1879 _PTR(Study) studyDS = study->studyDS();
1881 // get unique temporary directory name
1882 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1883 if( aTmpDir.isEmpty() )
1886 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1887 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1889 // dump study to the temporary directory
1890 QString aScriptName( "notebook" );
1891 bool toPublish = true;
1892 bool isMultiFile = false;
1893 bool toSaveGUI = true;
1896 _PTR(AttributeParameter) ap;
1897 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1898 if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1899 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1900 ip->setDumpPython(studyDS);
1901 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1903 bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1905 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1908 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1912 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1913 int anIndex = aList.indexOf( this );
1915 // Disconnect dialog from application desktop in case if:
1916 // 1) Application is not the first application in the session
1917 // 2) Application is the first application in session but not the only.
1918 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1919 if( changeDesktop ) {
1921 SalomeApp_Application* app = this;
1922 if( anIndex > 0 && anIndex < aList.count() )
1923 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1924 else if(anIndex == 0 && aList.count() > 1)
1925 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1930 // creation a new study and restoring will be done in another application
1931 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
1932 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
1935 QString aDumpScript = myNoteBook->getDumpedStudyScript();
1936 QString aStudyName = myNoteBook->getDumpedStudyName();
1937 bool isStudySaved = myNoteBook->isDumpedStudySaved();
1938 // clear a study (delete all objects)
1939 onCloseDoc( false );
1941 if( !changeDesktop ) {
1942 ok = onRestoreStudy( aDumpScript,
1950 //============================================================================
1951 /*! Function : onRestoreStudy
1952 * Purpose : Load the dumped study from Python script
1954 //============================================================================
1955 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1956 const QString& theStudyName,
1957 bool theIsStudySaved )
1961 // create a new study
1964 // get active application
1965 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1967 // load study from the temporary directory
1968 QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1970 PyConsole_Console* pyConsole = app->pythonConsole();
1972 pyConsole->execAndWait( command );
1974 // remove temporary directory
1975 QFileInfo aScriptInfo = QFileInfo( theDumpScript );
1976 QString aStudyName = aScriptInfo.baseName();
1977 QDir aDir = aScriptInfo.absoluteDir();
1978 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1979 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1980 ok = aDir.remove( *it ) && ok;
1982 ok = aDir.rmdir( aDir.absolutePath() );
1984 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1986 _PTR(Study) aStudyDS = newStudy->studyDS();
1987 app->getNoteBook()->Init( aStudyDS );
1988 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1989 newStudy->Modified();
1990 updateDesktopTitle();
2000 Close the Application
2002 void SalomeApp_Application::afterCloseDoc()
2004 // emit signal to restore study from Python script
2006 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2007 myNoteBook->getDumpedStudyName(),
2008 myNoteBook->isDumpedStudySaved() );
2010 LightApp_Application::afterCloseDoc();