Salome HOME
Handlling Python scripts without execution permissions
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:      SalomeApp_Application.cxx
24 // Created:   10/22/2004 3:23:45 PM
25 // Author:    Sergey LITONIN
26
27 #ifdef WNT
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>
32 #include <pymath.h>
33 #endif
34
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"
44
45 #include "SalomeApp_ExitDlg.h"
46
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>
54
55 #include <CAM_Module.h>
56
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>
70
71 #include <QtxTreeView.h>
72
73 #include <SALOME_EventFilter.h>
74
75 // temporary commented
76 //#include <OB_ListItem.h>
77
78 #include <PyConsole_Console.h>
79
80 #include <Utils_ORB_INIT.hxx>
81 #include <Utils_SINGLETON.hxx>
82 #include <SALOME_LifeCycleCORBA.hxx>
83
84 #include <QApplication>
85 #include <QAction>
86 #include <QRegExp>
87 #include <QCheckBox>
88 #include <QPushButton>
89 #include <QLabel>
90 #include <QListWidget>
91 #include <QGridLayout>
92 #include <QMenu>
93 #include <QtDebug>
94
95 #include <SALOMEDSClient_ClientFactory.hxx>
96 #include <Basics_Utils.hxx>
97
98 #include <SALOME_ListIO.hxx>
99 #include <SALOME_ListIteratorOfListIO.hxx>
100 #include <SALOME_Prs.h>
101
102
103 #include <ToolsGUI_CatalogGeneratorDlg.h>
104 #include <ToolsGUI_RegWidget.h>
105
106 #include <vector>
107
108 #include <SALOMEDS_Tool.hxx>
109
110 /*!Internal class that updates object browser item properties */
111 // temporary commented
112 /*class SalomeApp_Updater : public OB_Updater
113 {
114 public:
115   SalomeApp_Updater() : OB_Updater(){};
116   virtual ~SalomeApp_Updater(){};
117   virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
118 };
119
120 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
121 {
122   if( !theObj || !theItem )
123     return;
124
125   SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
126   if( !SAObj )
127     return;
128
129   _PTR(SObject) SObj = SAObj->object();
130   if( !SObj )
131     return;
132   _PTR( GenericAttribute ) anAttr;
133
134   // Selectable
135   if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
136   {
137     _PTR(AttributeSelectable) aAttrSel = anAttr;
138     theItem->setSelectable( aAttrSel->IsSelectable() );
139   }
140   // Expandable
141   if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
142   {
143     _PTR(AttributeExpandable) aAttrExpand = anAttr;
144     theItem->setExpandable( aAttrExpand->IsExpandable() );
145   }
146   // Opened
147   //this attribute is not supported in the version of SALOME 3.x
148   //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
149   //{
150   //  _PTR(AttributeOpened) aAttrOpen = anAttr;
151   //  theItem->setOpen( aAttrOpen->IsOpened() );
152   //}
153 }*/
154
155 /*!Create new instance of SalomeApp_Application.*/
156 extern "C" SALOMEAPP_EXPORT SUIT_Application* createApplication()
157 {
158   return new SalomeApp_Application();
159 }
160
161 /*!Constructor.*/
162 SalomeApp_Application::SalomeApp_Application()
163   : LightApp_Application()
164 {
165   connect( desktop(), SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
166            this,      SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
167 }
168
169 /*!Destructor.
170  *\li Destroy event filter.
171  */
172 SalomeApp_Application::~SalomeApp_Application()
173 {
174   // Do not destroy. It's a singleton !
175   //SALOME_EventFilter::Destroy();
176 }
177
178 /*!Start application.*/
179 void SalomeApp_Application::start()
180 {
181   LightApp_Application::start();
182
183   SALOME_EventFilter::Init();
184
185   static bool isFirst = true;
186   if ( isFirst ) {
187     isFirst = false;
188
189     QString hdffile;
190     QStringList pyfiles;
191
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();
200       }
201       else {
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];
210               }
211             }
212           }
213         }
214       }
215     }
216     // Here pyfiles elements are: "script_name": [list_of_"arg"s]
217     // For example: "/absolute/path/to/my_script.py": ["1", "2"]
218
219     if ( !hdffile.isEmpty() )       // open hdf file given as parameter
220       onOpenDoc( hdffile );
221     else if ( pyfiles.count() > 0 ) // create new study
222       onNewDoc();
223
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];
238               QString args = "";
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("[\"]$") );
244                 args += arg+",";
245               }
246               args.remove( QRegExp("[,]$") );
247               if (!args.isEmpty()) {
248                 args = "args:"+args;
249               }
250
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);
255             }
256           } // end for loop on pyfiles QStringList
257         }
258       }
259     }
260   }
261 }
262
263 /*!Create actions:*/
264 void SalomeApp_Application::createActions()
265 {
266   LightApp_Application::createActions();
267
268   SUIT_Desktop* desk = desktop();
269
270   //! Save GUI state
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() ) );
275
276   //! Dump study
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() ) );
280
281   //! Load script
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() ) );
285
286   //! Properties
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() ) );
290
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() ) );
295
296   //! Registry Display
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() ) );
300
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
307
308
309   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
310
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 );
314
315   createMenu( FileLoadId,   fileMenu, 0 );  //SRN: BugID IPAL9021, add a menu item "Load"
316
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 );
323
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 );
328
329   createExtraActions();
330
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());
335   if(res==NULL)
336     PyErr_Print();
337   Py_XDECREF(res);
338   Py_XDECREF(pluginsmanager);
339   PyGILState_Release(gstate);
340   // end of SALOME plugins loading
341
342 }
343
344
345 /*!Set desktop:*/
346 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
347 {
348   LightApp_Application::setDesktop( desk );
349
350   if ( desk ) {
351     connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
352              this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
353   }
354 }
355
356 /*!
357   \brief Close application.
358 */
359 void SalomeApp_Application::onExit()
360 {
361   bool killServers = false;
362   bool result = true;
363
364   if ( exitConfirmation() ) {
365     SalomeApp_ExitDlg dlg( desktop() );
366     result = dlg.exec() == QDialog::Accepted;
367     killServers = dlg.isServersShutdown();
368   }
369
370   if ( result )
371     SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
372 }
373
374 /*!SLOT. Load document.*/
375 void SalomeApp_Application::onLoadDoc()
376 {
377   QString studyName;
378
379   std::vector<std::string> List = studyMgr()->GetOpenStudies();
380
381   SUIT_Session* aSession = SUIT_Session::session();
382   QList<SUIT_Application*> aAppList = aSession->applications();
383
384   QStringList unloadedStudies;
385
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() )
394          continue;
395        if ( aApp->activeStudy()->studyName() == studyName )
396          isAlreadyOpen = true;
397      }
398
399      if ( !isAlreadyOpen )
400        unloadedStudies << studyName;
401   }
402
403   studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
404   if ( studyName.isEmpty() )
405     return;
406
407 #ifndef WIN32
408   // this code replaces marker of windows drive and path become invalid therefore
409   // defines placed there
410   studyName.replace( QRegExp(":"), "/" );
411 #endif
412
413   if ( onLoadDoc( studyName ) ) {
414     updateWindows();
415     updateViewManagers();
416     updateObjectBrowser( true );
417   }
418 }
419
420 /*!SLOT. Create new study and load script*/
421 void SalomeApp_Application::onNewWithScript()
422 {
423   QStringList filtersList;
424   filtersList.append(tr("PYTHON_FILES_FILTER"));
425   filtersList.append(tr("ALL_FILES_FILTER"));
426
427   QString anInitialPath = "";
428   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
429     anInitialPath = QDir::currentPath();
430
431   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
432
433   if ( !aFile.isEmpty() )
434   {
435     onNewDoc();
436
437     QString command = QString("execfile(r\"%1\")").arg(aFile);
438
439     PyConsole_Console* pyConsole = pythonConsole();
440
441     if ( pyConsole )
442       pyConsole->exec( command );
443   }
444 }
445
446
447 /*!SLOT. Load document with \a aName.*/
448 bool SalomeApp_Application::onLoadDoc( const QString& aName )
449 {
450   bool res = true;
451   if ( !activeStudy() ) {
452     // if no study - load in current desktop
453     res = useStudy( aName );
454   }
455   else {
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;
466     }
467     if ( !isAlreadyOpen ) {
468       aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
469       if ( aApp )
470         res = aApp->useStudy( aName );
471     }
472     else {
473       aApp->desktop()->activateWindow();
474     }
475   }
476
477   return res;
478 }
479
480 /*!SLOT. Copy objects to study maneger from selection maneger..*/
481 void SalomeApp_Application::onCopy()
482 {
483   SALOME_ListIO list;
484   LightApp_SelectionMgr* mgr = selectionMgr();
485   mgr->selectedObjects(list);
486
487   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
488   if(study == NULL) return;
489
490   _PTR(Study) stdDS = study->studyDS();
491   if(!stdDS) return;
492
493   SALOME_ListIteratorOfListIO it( list );
494   if(it.More())
495     {
496       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
497       try {
498         studyMgr()->Copy(so);
499         onSelectionChanged();
500       }
501       catch(...) {
502       }
503     }
504 }
505
506 /*!SLOT. Paste objects to study maneger from selection manager.*/
507 void SalomeApp_Application::onPaste()
508 {
509   SALOME_ListIO list;
510   LightApp_SelectionMgr* mgr = selectionMgr();
511   mgr->selectedObjects(list);
512
513   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
514   if(study == NULL) return;
515
516   _PTR(Study) stdDS = study->studyDS();
517   if(!stdDS) return;
518
519   if ( stdDS->GetProperties()->IsLocked() ) {
520     SUIT_MessageBox::warning( desktop(),
521                               QObject::tr("WRN_WARNING"),
522                               QObject::tr("WRN_STUDY_LOCKED") );
523     return;
524   }
525
526   SALOME_ListIteratorOfListIO it( list );
527   if(it.More())
528     {
529       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
530       try {
531         studyMgr()->Paste(so);
532         updateObjectBrowser( true );
533         updateActions(); //SRN: BugID IPAL9377, case 3
534       }
535       catch(...) {
536       }
537     }
538 }
539
540 /*!Check the application on closing.
541  * \retval true if possible, else false
542  */
543 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
544 {
545   return LightApp_Application::isPossibleToClose( closePermanently );
546 }
547
548 /*! Check if the study is locked */
549 void SalomeApp_Application::onCloseDoc( bool ask )
550 {
551   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
552
553   if (study != NULL) {
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;
561
562     }
563   }
564
565   LightApp_Application::onCloseDoc( ask );
566 }
567
568 /*!Sets enable or disable some actions on selection changed.*/
569 void SalomeApp_Application::onSelectionChanged()
570 {
571    SALOME_ListIO list;
572    LightApp_SelectionMgr* mgr = selectionMgr();
573    mgr->selectedObjects(list);
574
575    bool canCopy  = false;
576    bool canPaste = false;
577
578    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
579    if (study != NULL) {
580      _PTR(Study) stdDS = study->studyDS();
581
582      if (stdDS) {
583        SALOME_ListIteratorOfListIO it ( list );
584
585        if (it.More() && list.Extent() == 1) {
586          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
587
588          if ( so ) {
589              canCopy = studyMgr()->CanCopy(so);
590              canPaste = studyMgr()->CanPaste(so);
591          }
592        }
593      }
594    }
595
596    action(EditCopyId)->setEnabled(canCopy);
597    action(EditPasteId)->setEnabled(canPaste);
598 }
599
600 /*!Delete references.*/
601 void SalomeApp_Application::onDeleteInvalidReferences()
602 {
603   SALOME_ListIO aList;
604   LightApp_SelectionMgr* mgr = selectionMgr();
605   mgr->selectedObjects( aList, QString(), false );
606
607   if( aList.IsEmpty() )
608     return;
609
610   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
611   _PTR(Study) aStudyDS = aStudy->studyDS();
612   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
613   _PTR(SObject) anObj;
614
615   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
616     if ( it.Value()->hasEntry() )
617     {
618       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
619       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
620         aRefObj = anObj;
621
622       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
623          aStudyBuilder->RemoveReference( aSObject );
624     }
625   updateObjectBrowser();
626 }
627
628 /*!Private SLOT. */
629 void SalomeApp_Application::onOpenWith()
630 {
631   QApplication::setOverrideCursor( Qt::WaitCursor );
632   SALOME_ListIO aList;
633   LightApp_SelectionMgr* mgr = selectionMgr();
634   mgr->selectedObjects(aList);
635   if (aList.Extent() != 1)
636     {
637       QApplication::restoreOverrideCursor();
638       return;
639     }
640   Handle(SALOME_InteractiveObject) aIObj = aList.First();
641   QString aModuleName(aIObj->getComponentDataType());
642   QString aModuleTitle = moduleTitle(aModuleName);
643   activateModule(aModuleTitle);
644   QApplication::restoreOverrideCursor();
645 }
646
647 /*!
648   Creates new study
649 */
650 SUIT_Study* SalomeApp_Application::createNewStudy()
651 {
652   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
653
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* ) ) );
659
660   //to receive signal in application that NoteBook's variable was modified
661   connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
662            this, SIGNAL(notebookVarUpdated(QString)) );
663
664   return aStudy;
665 }
666
667 /*!
668   Enable/Disable menu items and toolbar buttons. Rebuild menu
669 */
670 void SalomeApp_Application::updateCommandsStatus()
671 {
672   LightApp_Application::updateCommandsStatus();
673
674   // Dump study menu
675   QAction* a = action( DumpStudyId );
676   if ( a )
677     a->setEnabled( activeStudy() );
678
679   // Load script menu
680   a = action( LoadScriptId );
681   if ( a )
682     a->setEnabled( activeStudy() );
683
684   // Properties menu
685   a = action( PropertiesId );
686   if( a )
687     a->setEnabled( activeStudy() );
688
689   // Save GUI state menu
690   a = action( SaveGUIStateId );
691   if( a )
692     a->setEnabled( activeStudy() );
693
694   // update state of Copy/Paste menu items
695   onSelectionChanged();
696 }
697
698 /*!
699   \class DumpStudyFileDlg
700   Private class used in Dump Study operation.  Consists 2 check boxes:
701   "Publish in study" and "Save GUI parameters"
702 */
703 class DumpStudyFileDlg : public SUIT_FileDlg
704 {
705 public:
706   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
707   {
708     QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
709     if ( grid )
710     {
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") );
715
716       QHBoxLayout *layout = new QHBoxLayout;
717       layout->addWidget(myPublishChk);
718       layout->addWidget(myMultiFileChk);
719       layout->addWidget(mySaveGUIChk);
720       hB->setLayout(layout);
721
722       QPushButton* pb = new QPushButton(this);
723
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 );
728
729       pb->hide();
730     }
731   }
732   QCheckBox* myPublishChk;
733   QCheckBox* myMultiFileChk;
734   QCheckBox* mySaveGUIChk;
735 };
736
737 class DumpStudyFileValidator : public SUIT_FileValidator
738 {
739  public:
740   DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
741   virtual ~DumpStudyFileValidator() {};
742   virtual bool canSave( const QString& file, bool permissions );
743 };
744
745 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
746 {
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") );
752     return false;
753   }
754   return SUIT_FileValidator::canSave( file, permissions);
755 }
756
757 /*!Private SLOT. On dump study.*/
758 void SalomeApp_Application::onDumpStudy( )
759 {
760   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
761   if ( !appStudy ) return;
762   _PTR(Study) aStudy = appStudy->studyDS();
763
764   QStringList aFilters;
765   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
766
767   bool anIsPublish = true;
768   bool anIsMultiFile = false;
769   bool anIsSaveGUI = true;
770
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 );
775   }
776
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 )
785   {
786     QString aFileName = fd.selectedFile();
787
788     bool toPublish = fd.myPublishChk->isChecked();
789     bool isMultiFile = fd.myMultiFileChk->isChecked();
790     bool toSaveGUI = fd.mySaveGUIChk->isChecked();
791
792     if ( !aFileName.isEmpty() ) {
793       QFileInfo aFileInfo(aFileName);
794       if( aFileInfo.isDir() ) // IPAL19257
795         return;
796
797       // Issue 21377 - dump study implementation moved to SalomeApp_Study class
798       bool res;
799       {
800         SUIT_OverrideCursor wc;
801         res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
802       }
803       if ( !res )
804         SUIT_MessageBox::warning( desktop(),
805                                   QObject::tr("WRN_WARNING"),
806                                   tr("WRN_DUMP_STUDY_FAILED") );
807     }
808   }
809 }
810
811 /*!Private SLOT. On load script.*/
812 void SalomeApp_Application::onLoadScript( )
813 {
814   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
815   if ( !appStudy ) return;
816   _PTR(Study) aStudy = appStudy->studyDS();
817
818   if ( aStudy->GetProperties()->IsLocked() ) {
819     SUIT_MessageBox::warning( desktop(),
820                               QObject::tr("WRN_WARNING"),
821                               QObject::tr("WRN_STUDY_LOCKED") );
822     return;
823   }
824
825   QStringList filtersList;
826   filtersList.append(tr("PYTHON_FILES_FILTER"));
827   filtersList.append(tr("ALL_FILES_FILTER"));
828
829   QString anInitialPath = "";
830   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
831     anInitialPath = QDir::currentPath();
832
833   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
834
835   if ( !aFile.isEmpty() )
836   {
837     QString command = QString("execfile(r\"%1\")").arg(aFile);
838
839     PyConsole_Console* pyConsole = pythonConsole();
840
841     if ( pyConsole )
842       pyConsole->exec( command );
843   }
844 }
845
846 /*!Private SLOT. On save GUI state.*/
847 void SalomeApp_Application::onSaveGUIState()
848 {
849   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
850   if ( study ) {
851     SalomeApp_VisualState( this ).storeState();
852     updateSavePointDataObjects( study );
853     updateObjectBrowser();
854   }
855   updateActions();
856 }
857
858 /*!Gets file filter.
859  *\retval QString "(*.hdf)"
860  */
861 QString SalomeApp_Application::getFileFilter() const
862 {
863   return "(*.hdf)";
864 }
865
866 /*!Create window.*/
867 QWidget* SalomeApp_Application::createWindow( const int flag )
868 {
869   QWidget* wid = 0;
870   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
871
872   SUIT_ResourceMgr* resMgr = resourceMgr();
873
874   if ( flag == WT_ObjectBrowser )
875   {
876     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
877     if ( ob ) {
878       // temporary commented
879       //ob->setUpdater( new SalomeApp_Updater() );
880
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);
886 #endif
887
888       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
889
890       QString
891         ValueCol = QObject::tr( "VALUE_COLUMN" ),
892         IORCol = QObject::tr( "IOR_COLUMN" ),
893         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
894         EntryCol = QObject::tr( "ENTRY_COLUMN" );
895
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 );
905
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 );
909
910       ob->setAutoSizeFirstColumn(autoSizeFirst);
911       ob->setAutoSizeColumns(autoSize);
912       ob->setResizeOnExpandItem(resizeOnExpandItem);
913       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
914
915       // temporary commented
916       /*
917       for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
918       {
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 ) );
922       }
923       */
924
925       // temporary commented
926       /*
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() );
930       */
931     }
932   }
933   else if ( flag == WT_PyConsole )
934   {
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" ) );
940     wid = pyCons;
941     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
942     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
943   }
944   else if ( flag == WT_NoteBook )
945   {
946     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
947     if ( appStudy ) {
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 ) ) );
953     }
954     wid = getNoteBook();
955   }
956   return wid;
957 }
958
959 /*!Create preferences.*/
960 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
961 {
962   LightApp_Application::createPreferences(pref);
963
964   if ( !pref )
965     return;
966
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++ )
971   {
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 ) );
974   }
975   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
976
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 );
987 }
988
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;
995
996   if ( activeStudy() )
997   {
998     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
999     if ( !sName.isEmpty() ) {
1000       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1001       if ( study ) {
1002         _PTR(Study) stdDS = study->studyDS();
1003         if(stdDS) {
1004           if ( stdDS->GetProperties()->IsLocked() ) {
1005             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1006           } else {
1007             aTitle += QString( " - [%1]" ).arg( sName );
1008           }
1009         }
1010       }
1011     }
1012   }
1013
1014   desktop()->setWindowTitle( aTitle );
1015 }
1016
1017 int SalomeApp_Application::closeChoice( const QString& docName )
1018 {
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 );
1022
1023   int res = CloseCancel;
1024   if ( answer == 0 )
1025     res = CloseSave;
1026   else if ( answer == 1 )
1027     res = CloseDiscard;
1028   else if ( answer == 2 )
1029     res = CloseUnload;
1030
1031   return res;
1032 }
1033
1034 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1035 {
1036   bool res = true;
1037   switch( choice )
1038   {
1039   case CloseSave:
1040     if ( activeStudy()->isSaved() )
1041       onSaveDoc();
1042     else if ( !onSaveAsDoc() )
1043       res = false;
1044     break;
1045   case CloseDiscard:
1046     break;
1047   case CloseUnload:
1048     closePermanently = false;
1049     break;
1050   case CloseCancel:
1051   default:
1052     res = false;
1053   }
1054
1055   return res;
1056 }
1057
1058 int SalomeApp_Application::openChoice( const QString& aName )
1059 {
1060   int choice = LightApp_Application::openChoice( aName );
1061
1062   if ( QFileInfo( aName ).exists() ) {
1063     if ( choice == OpenNew ) { // The document isn't already open.
1064       bool exist = false;
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() ) )
1068           exist = true;
1069       }
1070       // The document already exists in the study manager.
1071       // Do you want to reload it?
1072       if ( exist ) {
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;
1077         else
1078           choice = OpenCancel;
1079       }
1080     }
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()));
1085     return false;
1086   }
1087
1088   return choice;
1089 }
1090
1091 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1092 {
1093   bool res = false;
1094   int choice = aChoice;
1095   switch ( choice )
1096   {
1097   case OpenRefresh:
1098     {
1099       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1100       if ( aStudy )
1101       {
1102         studyMgr()->Close( aStudy );
1103         choice = OpenNew;
1104       }
1105     }
1106   default:
1107     res = LightApp_Application::openAction( choice, aName );
1108     break;
1109   }
1110
1111   return res;
1112 }
1113
1114 /*!
1115   \brief Get map of the operations which can be performed
1116   on the module activation.
1117
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
1124   the made choice.
1125
1126   \return map of the operations
1127   \sa moduleActionSelected()
1128 */
1129 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1130 {
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" ) );
1134   return opmap;
1135 }
1136
1137 /*!
1138   \brief Called when the used selectes required operation chosen
1139   from "Activate module" dialog box.
1140
1141   Performs the required operation according to the user choice.
1142
1143   \param id operation identifier
1144   \sa activateModuleActions()
1145 */
1146 void SalomeApp_Application::moduleActionSelected( const int id )
1147 {
1148   switch ( id ) {
1149   case LoadStudyId:
1150     onLoadDoc();
1151     break;
1152   case NewAndScriptId:
1153     onNewWithScript();
1154     break;
1155   default:
1156     LightApp_Application::moduleActionSelected( id );
1157     break;
1158   }
1159 }
1160
1161 /*!Gets CORBA::ORB_var*/
1162 CORBA::ORB_var SalomeApp_Application::orb()
1163 {
1164   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1165   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1166   return _orb;
1167 }
1168
1169 /*!Create and return SALOMEDS_StudyManager.*/
1170 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1171 {
1172   static _PTR(StudyManager) _sm;
1173   if(!_sm) _sm = ClientFactory::StudyManager();
1174   return _sm.get();
1175 }
1176
1177 /*!Create and return SALOME_NamingService.*/
1178 SALOME_NamingService* SalomeApp_Application::namingService()
1179 {
1180   static SALOME_NamingService _ns(orb());
1181   return &_ns;
1182 }
1183
1184 /*!Create and return SALOME_LifeCycleCORBA.*/
1185 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1186 {
1187   static SALOME_LifeCycleCORBA _lcc( namingService() );
1188   return &_lcc;
1189 }
1190
1191 /*!Private SLOT. On preferences.*/
1192 void SalomeApp_Application::onProperties()
1193 {
1194   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1195   if( !study )
1196     return;
1197
1198   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1199   SB->NewCommand();
1200
1201   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1202   int res = aDlg.exec();
1203   if( res==QDialog::Accepted && aDlg.isChanged() )
1204     SB->CommitCommand();
1205   else
1206     SB->AbortCommand();
1207
1208   //study->updateCaptions();
1209   updateDesktopTitle();
1210   updateActions();
1211 }
1212
1213 /*!Insert items in popup, which necessary for current application*/
1214 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1215 {
1216   LightApp_SelectionMgr* mgr = selectionMgr();
1217   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1218   mgr->setSelectionCacheEnabled( true );
1219
1220   LightApp_Application::contextMenuPopup( type, thePopup, title );
1221
1222   // temporary commented
1223   /*OB_Browser* ob = objectBrowser();
1224   if ( !ob || type != ob->popupClientType() )
1225     return;*/
1226
1227   // Get selected objects
1228   SALOME_ListIO aList;
1229   mgr->selectedObjects( aList, QString(), false );
1230
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() ) );
1239   }
1240
1241   // "Delete reference" item should appear only for invalid references
1242
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;
1248
1249   for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1250     if( it.Value()->hasEntry() )
1251     {
1252       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1253       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1254         aRefObj = anObj;
1255
1256       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1257         isInvalidRefs = true;
1258     }
1259
1260   // Add "Delete reference" item to popup
1261   if ( isInvalidRefs )
1262   {
1263     thePopup->addSeparator();
1264     thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1265     return;
1266   }
1267
1268   // "Activate module" item should appear only if it's necessary
1269   if ( aList.Extent() == 1 ) {
1270     aList.Clear();
1271     mgr->selectedObjects( aList );
1272
1273     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1274
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() );
1279       if ( study ) {
1280         _PTR(Study) stdDS = study->studyDS();
1281         if ( stdDS ) {
1282           _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1283           if ( aSO ) {
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]);
1292               }
1293             }
1294           }
1295         }
1296       }
1297     }
1298
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() ) );
1307     }
1308   }
1309
1310   mgr->setSelectionCacheEnabled( cacheIsOn );
1311 }
1312
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 )
1318 {
1319   // update "non-existing" (not loaded yet) data models
1320   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1321   if ( study )
1322   {
1323     _PTR(Study) stdDS = study->studyDS();
1324     if( stdDS )
1325     {
1326       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1327       {
1328         _PTR(SComponent) aComponent ( it->Value() );
1329
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
1334 #endif
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 );
1341       }
1342     }
1343   }
1344
1345   // create data objects that correspond to GUI state save points
1346   if ( study ) updateSavePointDataObjects( study );
1347
1348   // update existing data models (already loaded SComponents)
1349   LightApp_Application::updateObjectBrowser( updateModels );
1350 }
1351
1352 /*!Display Catalog Genenerator dialog */
1353 void SalomeApp_Application::onCatalogGen()
1354 {
1355   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1356   aDlg.exec();
1357 }
1358
1359 /*!Display Registry Display dialog */
1360 void SalomeApp_Application::onRegDisplay()
1361 {
1362   CORBA::ORB_var anOrb = orb();
1363   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1364   regWnd->show();
1365   regWnd->raise();
1366   regWnd->activateWindow();
1367 }
1368
1369 /*!find original object by double click on item */
1370 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1371 {
1372   // Issue 21379: References are supported at LightApp_DataObject level
1373   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1374
1375   if( obj && obj->isReference() )
1376   {
1377     QString entry = obj->refEntry();
1378
1379     SUIT_DataOwnerPtrList aList;
1380     aList.append( new LightApp_DataOwner( entry ) );
1381     selectionMgr()->setSelected( aList, false );
1382
1383     SUIT_DataBrowser* ob = objectBrowser();
1384
1385     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1386     if ( !aSelectedIndexes.isEmpty() )
1387       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1388   }
1389 }
1390
1391 /*!
1392   Creates new view manager
1393   \param type - type of view manager
1394 */
1395 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1396 {
1397   return createViewManager(type);
1398 }
1399
1400
1401 /*!Global utility funciton, returns selected GUI Save point object's ID */
1402 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1403 {
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
1411       return -1;
1412     bool ok; // conversion to integer is ok?
1413     int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1414     return ok ? savePoint : -1;
1415   }
1416   return -1;
1417 }
1418
1419 /*!Called on Restore GUI State popup command*/
1420 void SalomeApp_Application::onRestoreGUIState()
1421 {
1422   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1423   if ( savePoint == -1 )
1424     return;
1425   SalomeApp_VisualState( this ).restoreState( savePoint );
1426 }
1427
1428 /*!Called on Delete GUI State popup command*/
1429 void SalomeApp_Application::onDeleteGUIState()
1430 {
1431   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1432   if ( savePoint == -1 )
1433     return;
1434   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1435   if ( !study )
1436     return;
1437
1438   study->removeSavePoint( savePoint );
1439   updateSavePointDataObjects( study );
1440 }
1441
1442 /*!Called on New study operation*/
1443 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1444 {
1445   LightApp_Application::onStudyCreated( study );
1446
1447   desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1448                                windowDock( getWindow( WT_ObjectBrowser ) ) );
1449
1450   loadDockWindowsState();
1451
1452   connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1453            this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1454
1455
1456   objectBrowserColumnsVisibility();
1457 }
1458
1459 /*!Called on Save study operation*/
1460 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1461 {
1462   LightApp_Application::onStudySaved( study );
1463
1464   // temporary commented
1465   /*if ( objectBrowser() ) {
1466     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1467     objectBrowser()->updateTree( study->root() );
1468   }*/
1469 }
1470
1471 /*!Called on Open study operation*/
1472 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1473 {
1474   LightApp_Application::onStudyOpened( study );
1475
1476   desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1477                                windowDock( getWindow( WT_ObjectBrowser ) ) );
1478
1479   loadDockWindowsState();
1480
1481   connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1482            this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1483
1484   objectBrowserColumnsVisibility();
1485
1486   // temporary commented
1487   /*if ( objectBrowser() ) {
1488     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1489     objectBrowser()->updateTree( study->root() );
1490   }*/
1491 }
1492
1493 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1494 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1495 {
1496
1497   SUIT_DataBrowser* ob = objectBrowser();
1498   LightApp_SelectionMgr* selMgr = selectionMgr();
1499
1500   if ( !study || !ob || !selMgr )
1501     return;
1502
1503   // find GUI states root object
1504   SUIT_DataObject* guiRootObj = 0;
1505   DataObjectList ch;
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 ) ) {
1510       guiRootObj = *it;
1511       break;
1512     }
1513   }
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++ )
1524       delete ch[i];
1525     delete guiRootObj;
1526     ob->setAutoUpdate(isAutoUpdate);
1527     return;
1528   }
1529   // case 2: no more save points but root does not exist either
1530   if ( savePoints.empty() && !guiRootObj )
1531     return;
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
1537   // re-create it.
1538   if ( guiRootObj->nextBrother() ) {
1539     study->root()->removeChild(guiRootObj);
1540     study->root()->appendChild(guiRootObj);
1541     //study->root()->dump();
1542   }
1543
1544   // store data objects in a map id-to-DataObject
1545   QMap<int,SalomeApp_SavePointObject*> mapDO;
1546   ch.clear();
1547   guiRootObj->children( ch );
1548   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1549     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1550     if ( dobj )
1551       mapDO[dobj->getId()] = dobj;
1552   }
1553
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 );
1559     else
1560       mapDO.remove( savePoints[i] );
1561
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 )
1570       delete it.value();
1571     ob->setAutoUpdate(isAutoUpdate);
1572   }
1573 }
1574
1575 /*! Check data object */
1576 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1577 {
1578   if (theObj)
1579     return true;
1580
1581   return false;
1582 }
1583
1584 /*!
1585   Opens other study into active Study. If Study is empty - creates it.
1586   \param theName - name of study
1587 */
1588 bool SalomeApp_Application::useStudy( const QString& theName )
1589 {
1590   createEmptyStudy();
1591   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1592   bool res = false;
1593   if (aStudy)
1594     res = aStudy->loadDocument( theName );
1595   updateDesktopTitle();
1596   updateCommandsStatus();
1597   return res;
1598 }
1599
1600 /*! Show/hide object browser colums according to preferences */
1601 void SalomeApp_Application::objectBrowserColumnsVisibility()
1602 {
1603   if ( objectBrowser() )
1604     for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1605     {
1606       bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1607       objectBrowser()->treeView()->setColumnHidden( i, !shown );
1608     }
1609 }
1610
1611 /*! Set SalomeApp_NoteBook pointer */
1612 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1613 {
1614   myNoteBook = theNoteBook;
1615 }
1616
1617 /*! Return SalomeApp_NoteBook pointer */
1618 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1619 {
1620   return myNoteBook;
1621 }
1622
1623 /*!
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
1630  * Example:
1631  * <section name="MODULENAME">
1632  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1633  * </section>
1634  * <section name="importmed">
1635  *   <parameter name="title" value="My menu"/>
1636  *   <parameter name="objectid" value="VISU.Result"/>
1637  *   <parameter name="method" value="nameOfModuleMethod"/>
1638  * </section>
1639  */
1640 void SalomeApp_Application::createExtraActions()
1641 {
1642   myExtActions.clear();
1643   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1644
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())
1657           continue;
1658
1659         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1660         if (aModuleName.isNull())
1661           aModuleName = aModName;
1662
1663         QAction* aAction = new QAction(aTitle, this);
1664         QStringList aData;
1665         aData<<aModuleName<<aSlot;
1666         aAction->setData(aData);
1667         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1668         myExtActions[aId] = aAction;
1669       }
1670     }
1671   }
1672 }
1673
1674 /*!
1675  * Called when extra action is selected
1676  */
1677 void SalomeApp_Application::onExtAction()
1678 {
1679   QAction* aAction = ::qobject_cast<QAction*>(sender());
1680   if (!aAction)
1681     return;
1682
1683   QVariant aData = aAction->data();
1684   QStringList aDataList = aData.value<QStringList>();
1685   if (aDataList.size() != 2)
1686     return;
1687
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)
1693     return;
1694   if (!anIO->hasEntry())
1695     return;
1696
1697   QString aEntry(anIO->getEntry());
1698
1699   QApplication::setOverrideCursor( Qt::WaitCursor );
1700   QString aModuleTitle = moduleTitle(aDataList[0]);
1701   activateModule(aModuleTitle);
1702   QApplication::restoreOverrideCursor();
1703
1704   QCoreApplication::processEvents();
1705
1706   CAM_Module* aModule = activeModule();
1707   if (!aModule)
1708     return;
1709
1710   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1711     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1712 }
1713
1714 /*!
1715  * Called when window activated
1716  */
1717 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1718 {
1719   SUIT_DataBrowser* anOB = objectBrowser();
1720   if( !anOB )
1721     return;
1722   SUIT_DataObject* rootObj = anOB->root();
1723   if( !rootObj )
1724     return;
1725
1726   DataObjectList listObj = rootObj->children( true );
1727
1728   SUIT_ViewModel* vmod = 0;
1729   if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1730     vmod = vman->getViewModel();
1731   updateVisibilityState( listObj, vmod );
1732 }
1733
1734 /*!
1735   Update visibility state of given objects
1736  */
1737 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1738                                                    SUIT_ViewModel*  theViewModel )
1739 {
1740   LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1741
1742   if(!theViewModel)
1743     return;
1744
1745   SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1746
1747   if (theList.isEmpty() || !aView || !aStudy)
1748     return;
1749
1750   for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1751     LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1752
1753     if (!obj || aStudy->isComponent(obj->entry()))
1754       continue;
1755
1756     LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1757     Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1758
1759     if(anObjModule) {
1760       LightApp_Displayer* aDisplayer = anObjModule->displayer();
1761       if(aDisplayer) {
1762         if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1763           if(aDisplayer->IsDisplayed(obj->entry(),aView))
1764             anObjState = Qtx::ShownState;
1765           else
1766             anObjState = Qtx::HiddenState;
1767         }
1768       }
1769       aStudy->setVisibilityState( obj->entry(), anObjState );
1770     }
1771   }
1772 }
1773
1774 /*!
1775   Called then view manager removed
1776 */
1777 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1778 {
1779   ViewManagerList lst;
1780   viewManagers(lst);
1781   if( lst.count() == 1) { // in case if closed last view window
1782     LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1783     if(aStudy)
1784       aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1785   }
1786 }
1787
1788 /*!
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
1792 */
1793 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1794 {
1795   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1796 }
1797
1798 /*!
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.
1803 */
1804 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1805 {
1806   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1807
1808   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1809
1810   if(!aStudy || savePoint == -1)
1811     return false;
1812
1813   if ( !name.isNull() && !name.isEmpty() ) {
1814     aStudy->setNameOfSavePoint( savePoint, name );
1815     updateSavePointDataObjects( aStudy );
1816
1817     //Mark study as modified
1818     aStudy->Modified();
1819     return true;
1820   }
1821   return false;
1822 }
1823
1824 /*!
1825   \return default windows( Object Browser, Python Console )
1826   Adds to map \a aMap.
1827 */
1828 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1829 {
1830   LightApp_Application::defaultWindows(aMap);
1831   if ( !aMap.contains( WT_NoteBook ) ) {
1832     if ( !myNoteBook ) {
1833       aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1834     }
1835   }
1836 }
1837
1838 /*!
1839   Gets current windows.
1840   \param winMap - output current windows map.
1841 */
1842 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1843 {
1844   LightApp_Application::currentWindows( aMap );
1845   if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1846     aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1847 }
1848
1849 //============================================================================
1850 /*! Function : onUpdateStudy
1851  *  Purpose  : Slot to update the study.
1852  */
1853 //============================================================================
1854 void SalomeApp_Application::onUpdateStudy()
1855 {
1856   QApplication::setOverrideCursor( Qt::WaitCursor );
1857
1858   if( !updateStudy() )
1859     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1860
1861   QApplication::restoreOverrideCursor();
1862 }
1863
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.
1868  */
1869 //============================================================================
1870 bool SalomeApp_Application::updateStudy()
1871 {
1872   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1873   if ( !study || !myNoteBook )
1874     return false;
1875
1876   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1877   myNoteBook->setDumpedStudyName( study->studyName() );
1878
1879   _PTR(Study) studyDS = study->studyDS();
1880
1881   // get unique temporary directory name
1882   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1883   if( aTmpDir.isEmpty() )
1884     return false;
1885
1886   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1887     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1888
1889   // dump study to the temporary directory
1890   QString aScriptName( "notebook" );
1891   bool toPublish = true;
1892   bool isMultiFile = false;
1893   bool toSaveGUI = true;
1894
1895   int savePoint;
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
1902   }
1903   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1904   if ( toSaveGUI )
1905     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1906
1907   if( ok )
1908     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1909   else
1910     return false;
1911
1912   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1913   int anIndex = aList.indexOf( this );
1914
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 ) {
1920
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 ] );
1926
1927     if( !app )
1928       return false;
1929
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 );
1933   }
1934
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 );
1940
1941   if( !changeDesktop ) {
1942     ok = onRestoreStudy( aDumpScript,
1943                          aStudyName,
1944                          isStudySaved );
1945   }
1946
1947   return ok;
1948 }
1949
1950 //============================================================================
1951 /*! Function : onRestoreStudy
1952  *  Purpose  : Load the dumped study from Python script
1953  */
1954 //============================================================================
1955 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
1956                                             const QString& theStudyName,
1957                                             bool theIsStudySaved )
1958 {
1959   bool ok = true;
1960
1961   // create a new study
1962   onNewDoc();
1963
1964   // get active application
1965   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1966
1967   // load study from the temporary directory
1968   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
1969
1970   PyConsole_Console* pyConsole = app->pythonConsole();
1971   if ( pyConsole )
1972     pyConsole->execAndWait( command );
1973
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;
1981   if( ok )
1982     ok = aDir.rmdir( aDir.absolutePath() );
1983
1984   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1985   {
1986     _PTR(Study) aStudyDS = newStudy->studyDS();
1987     app->getNoteBook()->Init( aStudyDS );
1988     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
1989     newStudy->Modified();
1990     updateDesktopTitle();
1991     updateActions();
1992   }
1993   else
1994     ok = false;
1995
1996   return ok;
1997 }
1998
1999 /*!
2000   Close the Application
2001 */
2002 void SalomeApp_Application::afterCloseDoc()
2003 {
2004   // emit signal to restore study from Python script
2005   if ( myNoteBook ) {
2006     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2007                             myNoteBook->getDumpedStudyName(),
2008                             myNoteBook->isDumpedStudySaved() );
2009   }
2010   LightApp_Application::afterCloseDoc();
2011 }