Salome HOME
7e3a64966f8863d51b3c4203ff638c0d2821d12f
[modules/gui.git] / src / SalomeApp / SalomeApp_Application.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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 WIN32
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   connect( desktop(), SIGNAL( message( const QString& ) ),
168            this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
169   myIsSiman = false; // default
170 }
171
172 /*!Destructor.
173  *\li Destroy event filter.
174  */
175 SalomeApp_Application::~SalomeApp_Application()
176 {
177   // Do not destroy. It's a singleton !
178   //SALOME_EventFilter::Destroy();
179 }
180
181 /*!Start application.*/
182 void SalomeApp_Application::start()
183 {
184   // process the command line options before start: to createActions in accordance to the options
185   static bool isFirst = true;
186   if ( isFirst ) {
187     isFirst = false;
188
189     QString hdffile;
190     QStringList pyfiles;
191     QString loadStudy;
192
193     for (int i = 1; i < qApp->argc(); i++) {
194       QRegExp rxs ("--study-hdf=(.+)");
195       if ( rxs.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxs.capturedTexts().count() > 1 ) {
196         QString file = rxs.capturedTexts()[1];
197         QFileInfo fi ( file );
198         QString extension = fi.suffix().toLower();
199         if ( extension == "hdf" && fi.exists() )
200           hdffile = fi.absoluteFilePath();
201       }
202       else {
203         QRegExp rxp ("--pyscript=\\[(.+)\\]");
204         QRegExp rxl ("--siman-study=(.+)");
205         if ( rxp.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxp.capturedTexts().count() > 1 ) {
206           // pyscript
207           QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
208           for (int k = 0; k < dictList.count(); ++k) {
209             QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
210             if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
211               for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
212                 pyfiles += rxd.capturedTexts()[m];
213               }
214             }
215           }
216         }
217 #ifdef WITH_SIMANIO
218         if ( rxl.indexIn( QString(qApp->argv()[i]) ) >= 0 && rxl.capturedTexts().count() > 1 ) {
219           // siman
220           loadStudy = rxl.capturedTexts()[1];
221           myIsSiman = true;
222         }
223 #endif
224       }
225     }
226     // Here pyfiles elements are: "script_name": [list_of_"arg"s]
227     // For example: "/absolute/path/to/my_script.py": ["1", "2"]
228
229     LightApp_Application::start();
230     SALOME_EventFilter::Init();
231
232     if ( !hdffile.isEmpty() )       // open hdf file given as parameter
233       onOpenDoc( hdffile );
234     else if ( pyfiles.count() > 0 ) // create new study
235       onNewDoc();
236     else if (!loadStudy.isEmpty()) {// load study by name
237       if (onLoadDoc(loadStudy))
238         updateObjectBrowser(true);
239     }
240
241     // import/execute python scripts
242     if ( pyfiles.count() > 0 && activeStudy() ) {
243       SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
244       PyConsole_Console* pyConsole = pythonConsole();
245       if ( appStudy && pyConsole ) {
246         _PTR(Study) aStudy = appStudy->studyDS();
247         if ( !aStudy->GetProperties()->IsLocked() ) {
248           // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
249           // Path is absolute, script has .py extension
250           for (uint j = 0; j < pyfiles.count(); j++ ) {
251             // Extract scripts and their arguments, if any
252             QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
253             if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
254               QString script = rxp.capturedTexts()[1];
255               QString args = "";
256               QStringList argList = rxp.capturedTexts()[2].split(",", QString::SkipEmptyParts);
257               for (uint k = 0; k < argList.count(); k++ ) {
258                 QString arg = argList[k].trimmed();
259                 arg.remove( QRegExp("^[\"]") );
260                 arg.remove( QRegExp("[\"]$") );
261                 args += arg+",";
262               }
263               args.remove( QRegExp("[,]$") );
264               if (!args.isEmpty()) {
265                 args = "args:"+args;
266               }
267
268               script.remove( QRegExp("^python.*[\\s]+") );
269               QString cmd = script+" "+args;
270               QString command = QString( "execfile(r\"%1\")" ).arg(cmd.trimmed());
271               pyConsole->exec(command);
272             }
273           } // end for loop on pyfiles QStringList
274         }
275       }
276     }
277   } else {
278     LightApp_Application::start();
279     SALOME_EventFilter::Init();
280   }
281 }
282
283 /*!Create actions:*/
284 void SalomeApp_Application::createActions()
285 {
286   LightApp_Application::createActions();
287
288   SUIT_Desktop* desk = desktop();
289
290   //! Save GUI state
291   // "Save GUI State" command is moved to VISU module
292   //  createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
293   //            tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
294   //            0, desk, false, this, SLOT( onSaveGUIState() ) );
295
296   //! Dump study
297   createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
298                 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
299                 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
300
301   //! Load script
302   createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
303                 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
304                 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
305
306   //! Properties
307   createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
308                 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
309                 Qt::CTRL+Qt::Key_P, desk, false, this, SLOT( onProperties() ) );
310
311   //! Catalog Generator
312   createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ),  QIcon(),
313                 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
314                 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
315
316   //! Registry Display
317   createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ),  QIcon(),
318                 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
319                 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
320
321   //SRN: BugID IPAL9021, add an action "Load"
322   createAction( FileLoadId, tr( "TOT_DESK_FILE_LOAD" ),
323                 resourceMgr()->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
324                 tr( "MEN_DESK_FILE_LOAD" ), tr( "PRP_DESK_FILE_LOAD" ),
325                 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
326   //SRN: BugID IPAL9021: End
327
328 #ifdef WITH_SIMANIO
329   if (myIsSiman) {
330     // check-in operations for SIMAN study  
331     createAction( SimanCheckInId, tr( "TOT_SIMAN_CHECK_IN" ), QIcon(),
332                 tr( "MEN_SIMAN_CHECK_IN" ), tr( "PRP_SIMAN_CHECK_IN" ),
333                 0, desk, false, this, SLOT( onCheckIn() ) );
334     createAction( SimanLocalCheckInId, tr( "TOT_SIMAN_LOCAL_CHECK_IN" ), QIcon(),
335                 tr( "MEN_SIMAN_LOCAL_CHECK_IN" ), tr( "PRP_SIMAN_LOCAL_CHECK_IN" ),
336                 0, desk, false, this, SLOT( onLocalCheckIn() ) );
337   }
338 #endif
339
340   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
341
342   // "Save GUI State" command is renamed to "Save VISU State" and
343   // creation of menu item is moved to VISU
344   //  createMenu( SaveGUIStateId, fileMenu, 10, -1 );
345
346   createMenu( FileLoadId,   fileMenu, 0 );  //SRN: BugID IPAL9021, add a menu item "Load"
347
348 #ifdef WITH_SIMANIO
349   if (myIsSiman) {
350     // check-in operation for SIMAN study
351     // last argument "5" locates this just after "Save As" but certain constant is bad => insert after the separator
352     createMenu( SimanCheckInId, fileMenu, 5);
353     createMenu( SimanLocalCheckInId, fileMenu, 5);
354     createMenu( separator(), fileMenu, 5 );
355   }
356 #endif
357   createMenu( DumpStudyId, fileMenu, 10, -1 );
358   createMenu( separator(), fileMenu, -1, 10, -1 );
359   createMenu( LoadScriptId, fileMenu, 10, -1 );
360   createMenu( separator(), fileMenu, -1, 10, -1 );
361   createMenu( PropertiesId, fileMenu, 10, -1 );
362   createMenu( separator(), fileMenu, -1, 10, -1 );
363
364   int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
365   createMenu( CatalogGenId, toolsMenu, 10, -1 );
366   createMenu( RegDisplayId, toolsMenu, 10, -1 );
367   createMenu( separator(), toolsMenu, -1, 15, -1 );
368
369   createExtraActions();
370
371   // import Python module that manages SALOME plugins
372   PyGILState_STATE gstate = PyGILState_Ensure();
373   PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
374   PyObjWrapper 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());
375   if ( !res )
376     PyErr_Print();
377   PyGILState_Release(gstate);
378   // end of SALOME plugins loading
379
380 }
381
382
383 /*!Set desktop:*/
384 void SalomeApp_Application::setDesktop( SUIT_Desktop* desk )
385 {
386   LightApp_Application::setDesktop( desk );
387
388   if ( desk ) {
389     connect( desk, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
390              this, SLOT( onWindowActivated( SUIT_ViewWindow* ) ), Qt::UniqueConnection );
391     connect( desk, SIGNAL( message( const QString& ) ),
392              this, SLOT( onLoadDocMessage( const QString& ) ), Qt::UniqueConnection );
393   }
394 }
395
396 /*!
397   \brief Close application.
398 */
399 void SalomeApp_Application::onExit()
400 {
401   bool killServers = false;
402   bool result = true;
403
404   if ( exitConfirmation() ) {
405     SalomeApp_ExitDlg dlg( desktop() );
406     result = dlg.exec() == QDialog::Accepted;
407     killServers = dlg.isServersShutdown();
408   }
409
410   if ( result )
411     SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
412 }
413
414 /*!SLOT. Load document.*/
415 void SalomeApp_Application::onLoadDoc()
416 {
417   QString studyName;
418
419   std::vector<std::string> List = studyMgr()->GetOpenStudies();
420
421   SUIT_Session* aSession = SUIT_Session::session();
422   QList<SUIT_Application*> aAppList = aSession->applications();
423
424   QStringList unloadedStudies;
425
426   for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
427      studyName = List[ind].c_str();
428      // Add to list only unloaded studies
429      bool isAlreadyOpen = false;
430      QListIterator<SUIT_Application*> it( aAppList );
431      while ( it.hasNext() && !isAlreadyOpen ) {
432        SUIT_Application* aApp = it.next();
433        if( !aApp || !aApp->activeStudy() )
434          continue;
435        if ( aApp->activeStudy()->studyName() == studyName )
436          isAlreadyOpen = true;
437      }
438
439      if ( !isAlreadyOpen )
440        unloadedStudies << studyName;
441   }
442
443   studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
444   if ( studyName.isEmpty() )
445     return;
446
447 #ifndef WIN32
448   // this code replaces marker of windows drive and path become invalid therefore
449   // defines placed there
450   studyName.replace( QRegExp(":"), "/" );
451 #endif
452
453   if ( onLoadDoc( studyName ) ) {
454     updateWindows();
455     updateViewManagers();
456     updateObjectBrowser( true );
457   }
458 }
459
460 /*!SLOT. Create new study and load script*/
461 void SalomeApp_Application::onNewWithScript()
462 {
463   QStringList filtersList;
464   filtersList.append(tr("PYTHON_FILES_FILTER"));
465   filtersList.append(tr("ALL_FILES_FILTER"));
466
467   QString anInitialPath = "";
468   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
469     anInitialPath = QDir::currentPath();
470
471   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
472
473   if ( !aFile.isEmpty() )
474   {
475     onNewDoc();
476
477     QString command = QString("execfile(r\"%1\")").arg(aFile);
478
479     PyConsole_Console* pyConsole = pythonConsole();
480
481     if ( pyConsole )
482       pyConsole->exec( command );
483   }
484 }
485
486
487 /*!SLOT. Load document with \a aName.*/
488 bool SalomeApp_Application::onLoadDoc( const QString& aName )
489 {
490   bool res = true;
491   if ( !activeStudy() ) {
492     // if no study - load in current desktop
493     res = useStudy( aName );
494   }
495   else {
496     // if study exists - load in new desktop. Check: is the same file is loaded?
497     SUIT_Session* aSession = SUIT_Session::session();
498     QList<SUIT_Application*> aAppList = aSession->applications();
499     bool isAlreadyOpen = false;
500     SalomeApp_Application* aApp = 0;
501     for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
502           it != aAppList.end() && !isAlreadyOpen; ++it ) {
503       aApp = dynamic_cast<SalomeApp_Application*>( *it );
504       if ( aApp && aApp->activeStudy()->studyName() == aName )
505         isAlreadyOpen = true;
506     }
507     if ( !isAlreadyOpen ) {
508       aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
509       if ( aApp )
510         res = aApp->useStudy( aName );
511     }
512     else {
513       aApp->desktop()->activateWindow();
514     }
515   }
516
517   return res;
518 }
519
520 /*!SLOT. Load document with a name, specified in \a aMessage.*/
521 void SalomeApp_Application::onLoadDocMessage(const QString& aMessage)
522 {
523   if (aMessage.indexOf("simanCheckoutDone ") == 0) {
524 #ifdef WITH_SIMANIO
525     onLoadDoc(aMessage.section(' ', 1));
526 #else
527     printf( "****************************************************************\n" );
528     printf( "*    Warning: SALOME is built without SIMAN support.\n" );
529     printf( "****************************************************************\n" );
530 #endif
531   }
532 }
533
534 /*!SLOT. Copy objects to study maneger from selection maneger..*/
535 void SalomeApp_Application::onCopy()
536 {
537   SALOME_ListIO list;
538   LightApp_SelectionMgr* mgr = selectionMgr();
539   mgr->selectedObjects(list);
540
541   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
542   if(study == NULL) return;
543
544   _PTR(Study) stdDS = study->studyDS();
545   if(!stdDS) return;
546
547   SALOME_ListIteratorOfListIO it( list );
548   if(it.More())
549     {
550       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
551       try {
552         studyMgr()->Copy(so);
553         onSelectionChanged();
554       }
555       catch(...) {
556       }
557     }
558 }
559
560 /*!SLOT. Paste objects to study maneger from selection manager.*/
561 void SalomeApp_Application::onPaste()
562 {
563   SALOME_ListIO list;
564   LightApp_SelectionMgr* mgr = selectionMgr();
565   mgr->selectedObjects(list);
566
567   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
568   if(study == NULL) return;
569
570   _PTR(Study) stdDS = study->studyDS();
571   if(!stdDS) return;
572
573   if ( stdDS->GetProperties()->IsLocked() ) {
574     SUIT_MessageBox::warning( desktop(),
575                               QObject::tr("WRN_WARNING"),
576                               QObject::tr("WRN_STUDY_LOCKED") );
577     return;
578   }
579
580   SALOME_ListIteratorOfListIO it( list );
581   if(it.More())
582     {
583       _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
584       try {
585         studyMgr()->Paste(so);
586         updateObjectBrowser( true );
587         updateActions(); //SRN: BugID IPAL9377, case 3
588       }
589       catch(...) {
590       }
591     }
592 }
593
594 /*!Check the application on closing.
595  * \retval true if possible, else false
596  */
597 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
598 {
599   return LightApp_Application::isPossibleToClose( closePermanently );
600 }
601
602 /*! Check if the study is locked */
603 void SalomeApp_Application::onCloseDoc( bool ask )
604 {
605   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
606
607   if (study != NULL) {
608     _PTR(Study) stdDS = study->studyDS();
609     if(stdDS && stdDS->IsStudyLocked()) {
610       if ( SUIT_MessageBox::question( desktop(),
611                                       QObject::tr( "WRN_WARNING" ),
612                                       QObject::tr( "CLOSE_LOCKED_STUDY" ),
613                                       SUIT_MessageBox::Yes | SUIT_MessageBox::No,
614                                       SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
615
616     }
617   }
618
619   LightApp_Application::onCloseDoc( ask );
620 }
621
622 /*!Sets enable or disable some actions on selection changed.*/
623 void SalomeApp_Application::onSelectionChanged()
624 {
625    SALOME_ListIO list;
626    LightApp_SelectionMgr* mgr = selectionMgr();
627    mgr->selectedObjects(list);
628
629    bool canCopy  = false;
630    bool canPaste = false;
631
632    SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
633    if (study != NULL) {
634      _PTR(Study) stdDS = study->studyDS();
635
636      if (stdDS) {
637        SALOME_ListIteratorOfListIO it ( list );
638
639        if (it.More() && list.Extent() == 1) {
640          _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
641
642          if ( so ) {
643              canCopy = studyMgr()->CanCopy(so);
644              canPaste = studyMgr()->CanPaste(so);
645          }
646        }
647      }
648    }
649
650    action(EditCopyId)->setEnabled(canCopy);
651    action(EditPasteId)->setEnabled(canPaste);
652 }
653
654 /*!Delete references.*/
655 void SalomeApp_Application::onDeleteInvalidReferences()
656 {
657   SALOME_ListIO aList;
658   LightApp_SelectionMgr* mgr = selectionMgr();
659   mgr->selectedObjects( aList, QString(), false );
660
661   if( aList.IsEmpty() )
662     return;
663
664   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
665   _PTR(Study) aStudyDS = aStudy->studyDS();
666   _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
667   _PTR(SObject) anObj;
668
669   for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
670     if ( it.Value()->hasEntry() )
671     {
672       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
673       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
674         aRefObj = anObj;
675
676       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
677          aStudyBuilder->RemoveReference( aSObject );
678     }
679   updateObjectBrowser();
680 }
681
682 /*!Private SLOT. */
683 void SalomeApp_Application::onOpenWith()
684 {
685   QApplication::setOverrideCursor( Qt::WaitCursor );
686   SALOME_ListIO aList;
687   LightApp_SelectionMgr* mgr = selectionMgr();
688   mgr->selectedObjects(aList);
689   if (aList.Extent() != 1)
690     {
691       QApplication::restoreOverrideCursor();
692       return;
693     }
694   Handle(SALOME_InteractiveObject) aIObj = aList.First();
695   QString aModuleName(aIObj->getComponentDataType());
696   QString aModuleTitle = moduleTitle(aModuleName);
697   activateModule(aModuleTitle);
698   QApplication::restoreOverrideCursor();
699 }
700
701 /*!
702   Creates new study
703 */
704 SUIT_Study* SalomeApp_Application::createNewStudy()
705 {
706   SalomeApp_Study* aStudy = new SalomeApp_Study( this );
707
708   // Set up processing of major study-related events
709   connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
710   connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
711   connect( aStudy, SIGNAL( saved  ( SUIT_Study* ) ), this, SLOT( onStudySaved  ( SUIT_Study* ) ) );
712   connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
713
714   //to receive signal in application that NoteBook's variable was modified
715   connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
716            this, SIGNAL(notebookVarUpdated(QString)) );
717
718   return aStudy;
719 }
720
721 /*!
722   Enable/Disable menu items and toolbar buttons. Rebuild menu
723 */
724 void SalomeApp_Application::updateCommandsStatus()
725 {
726   LightApp_Application::updateCommandsStatus();
727
728   // Dump study menu
729   QAction* a = action( DumpStudyId );
730   if ( a )
731     a->setEnabled( activeStudy() );
732
733   // Load script menu
734   a = action( LoadScriptId );
735   if ( a )
736     a->setEnabled( activeStudy() );
737
738   // Properties menu
739   a = action( PropertiesId );
740   if( a )
741     a->setEnabled( activeStudy() );
742
743   // Save GUI state menu
744   a = action( SaveGUIStateId );
745   if( a )
746     a->setEnabled( activeStudy() );
747
748   // update state of Copy/Paste menu items
749   onSelectionChanged();
750 }
751
752 /*!
753   \class DumpStudyFileDlg
754   Private class used in Dump Study operation.  Consists 2 check boxes:
755   "Publish in study" and "Save GUI parameters"
756 */
757 class DumpStudyFileDlg : public SUIT_FileDlg
758 {
759 public:
760   DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
761   {
762     QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
763     if ( grid )
764     {
765       QWidget *hB = new QWidget( this );
766       myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
767       myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
768       mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
769
770       QHBoxLayout *layout = new QHBoxLayout;
771       layout->addWidget(myPublishChk);
772       layout->addWidget(myMultiFileChk);
773       layout->addWidget(mySaveGUIChk);
774       hB->setLayout(layout);
775
776       QPushButton* pb = new QPushButton(this);
777
778       int row = grid->rowCount();
779       grid->addWidget( new QLabel("", this), row, 0 );
780       grid->addWidget( hB, row, 1, 1, 3 );
781       grid->addWidget( pb, row, 5 );
782
783       pb->hide();
784     }
785   }
786   QCheckBox* myPublishChk;
787   QCheckBox* myMultiFileChk;
788   QCheckBox* mySaveGUIChk;
789 };
790
791 class DumpStudyFileValidator : public SUIT_FileValidator
792 {
793  public:
794   DumpStudyFileValidator( QWidget* parent) : SUIT_FileValidator ( parent ) {};
795   virtual ~DumpStudyFileValidator() {};
796   virtual bool canSave( const QString& file, bool permissions );
797 };
798
799 bool DumpStudyFileValidator::canSave(const QString& file, bool permissions)
800 {
801   QFileInfo fi( file );
802   if ( !QRegExp( "[A-Za-z_][A-Za-z0-9_]*" ).exactMatch( fi.completeBaseName() ) ) {
803     SUIT_MessageBox::critical( parent(),
804                                QObject::tr("WRN_WARNING"),
805                                QObject::tr("WRN_FILE_NAME_BAD") );
806     return false;
807   }
808   return SUIT_FileValidator::canSave( file, permissions);
809 }
810
811 /*!Private SLOT. On dump study.*/
812 void SalomeApp_Application::onDumpStudy( )
813 {
814   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
815   if ( !appStudy ) return;
816   _PTR(Study) aStudy = appStudy->studyDS();
817
818   QStringList aFilters;
819   aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
820
821   bool anIsPublish = true;
822   bool anIsMultiFile = false;
823   bool anIsSaveGUI = true;
824
825   if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
826     anIsPublish   = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
827     anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
828     anIsSaveGUI   = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
829   }
830
831   DumpStudyFileDlg fd( desktop() );
832   fd.setValidator( new DumpStudyFileValidator( &fd ) );
833   fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
834   fd.setFilters( aFilters );
835   fd.myPublishChk->setChecked( anIsPublish );
836   fd.myMultiFileChk->setChecked( anIsMultiFile );
837   fd.mySaveGUIChk->setChecked( anIsSaveGUI );
838   if ( fd.exec() == QDialog::Accepted )
839   {
840     QString aFileName = fd.selectedFile();
841
842     bool toPublish = fd.myPublishChk->isChecked();
843     bool isMultiFile = fd.myMultiFileChk->isChecked();
844     bool toSaveGUI = fd.mySaveGUIChk->isChecked();
845
846     if ( !aFileName.isEmpty() ) {
847       QFileInfo aFileInfo(aFileName);
848       if( aFileInfo.isDir() ) // IPAL19257
849         return;
850
851       // Issue 21377 - dump study implementation moved to SalomeApp_Study class
852       bool res;
853       {
854         SUIT_OverrideCursor wc;
855         res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
856       }
857       if ( !res )
858         SUIT_MessageBox::warning( desktop(),
859                                   QObject::tr("WRN_WARNING"),
860                                   tr("WRN_DUMP_STUDY_FAILED") );
861     }
862   }
863 }
864
865 /*!Private SLOT. On load script.*/
866 void SalomeApp_Application::onLoadScript( )
867 {
868   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
869   if ( !appStudy ) return;
870   _PTR(Study) aStudy = appStudy->studyDS();
871
872   if ( aStudy->GetProperties()->IsLocked() ) {
873     SUIT_MessageBox::warning( desktop(),
874                               QObject::tr("WRN_WARNING"),
875                               QObject::tr("WRN_STUDY_LOCKED") );
876     return;
877   }
878
879   QStringList filtersList;
880   filtersList.append(tr("PYTHON_FILES_FILTER"));
881   filtersList.append(tr("ALL_FILES_FILTER"));
882
883   QString anInitialPath = "";
884   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
885     anInitialPath = QDir::currentPath();
886   
887 #ifdef WITH_SIMANIO
888   // MPV: if it is SIMAN study, make the initial path as the path to the Siman scripts storage
889   if (myIsSiman) {
890     SALOMEDSClient_StudyManager* aMgr = studyMgr();
891     aMgr->GetSimanStudy()->StudyId();
892     anInitialPath = QString(QDir::separator()) + "tmp" + QDir::separator() + "SimanSalome" + QDir::separator() + 
893       aMgr->GetSimanStudy()->StudyId().c_str() + QDir::separator() +
894       aMgr->GetSimanStudy()->ScenarioId().c_str() + QDir::separator() + aMgr->GetSimanStudy()->UserId().c_str();
895   }
896 #endif
897
898   QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
899
900   if ( !aFile.isEmpty() )
901   {
902     QString command = QString("execfile(r\"%1\")").arg(aFile);
903
904     PyConsole_Console* pyConsole = pythonConsole();
905
906     if ( pyConsole )
907       pyConsole->exec( command );
908   }
909 }
910
911 /*!Private SLOT. On save GUI state.*/
912 void SalomeApp_Application::onSaveGUIState()
913 {
914   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
915   if ( study ) {
916     SalomeApp_VisualState( this ).storeState();
917     updateSavePointDataObjects( study );
918     updateObjectBrowser();
919   }
920   updateActions();
921 }
922
923 /*!Public SLOT. On SIMAN check in operation.*/
924 void SalomeApp_Application::onCheckIn()
925 {
926 #ifdef WITH_SIMANIO
927   setMenuShown(SimanCheckInId, false); // check in may be performed only once
928   setMenuShown(SimanLocalCheckInId, false);
929   SALOMEDSClient_StudyManager* aMgr = studyMgr();
930   aMgr->GetSimanStudy()->CheckIn("");
931 #else
932   printf( "****************************************************************\n" );
933   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
934   printf( "****************************************************************\n" );
935 #endif
936 }
937
938 /*!Public SLOT. On SIMAN local check in operation.*/
939 void SalomeApp_Application::onLocalCheckIn()
940 {
941 #ifdef WITH_SIMANIO
942   // get the active module
943   CAM_Module* aModule = activeModule();
944   if (!aModule) return; // there is no active module
945   
946   setMenuShown(SimanCheckInId, false); // check in may be performed only once
947   setMenuShown(SimanLocalCheckInId, false);
948   SALOMEDSClient_StudyManager* aMgr = studyMgr();
949   aMgr->GetSimanStudy()->CheckIn(aModule->name().toLatin1().data());
950 #else
951   printf( "****************************************************************\n" );
952   printf( "*    Warning: SALOME is built without SIMAN support.\n" );
953   printf( "****************************************************************\n" );
954 #endif
955 }
956
957 /*!Gets file filter.
958  *\retval QString "(*.hdf)"
959  */
960 QString SalomeApp_Application::getFileFilter() const
961 {
962   return "(*.hdf)";
963 }
964
965 /*!Create window.*/
966 QWidget* SalomeApp_Application::createWindow( const int flag )
967 {
968   QWidget* wid = 0;
969   if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
970
971   SUIT_ResourceMgr* resMgr = resourceMgr();
972
973   if ( flag == WT_ObjectBrowser )
974   {
975     SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
976     if ( ob ) {
977       // temporary commented
978       //ob->setUpdater( new SalomeApp_Updater() );
979
980 #ifdef WITH_SALOMEDS_OBSERVER
981       //do not activate the automatic update of Qt tree through signal/slot
982       ob->setAutoUpdate(false);
983       //activate update of modified objects only
984       ob->setUpdateModified(true);
985 #endif
986
987       connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
988
989       QString
990         ValueCol = QObject::tr( "VALUE_COLUMN" ),
991         IORCol = QObject::tr( "IOR_COLUMN" ),
992         RefCol = QObject::tr( "REFENTRY_COLUMN" ),
993         EntryCol = QObject::tr( "ENTRY_COLUMN" );
994
995       SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
996       treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
997       treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
998       treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
999       treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1000       treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1001       treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1002       treeModel->setAppropriate( IORCol, Qtx::Toggled );
1003       treeModel->setAppropriate( RefCol, Qtx::Toggled );
1004
1005       bool autoSize      = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1006       bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1007       bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1008
1009       ob->setAutoSizeFirstColumn(autoSizeFirst);
1010       ob->setAutoSizeColumns(autoSize);
1011       ob->setResizeOnExpandItem(resizeOnExpandItem);
1012       ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1013
1014       // temporary commented
1015       /*
1016       for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1017       {
1018       ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1019       ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1020                                                     QString().sprintf( "visibility_column_%d", i ), true ) );
1021       }
1022       */
1023
1024       // temporary commented
1025       /*
1026         ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1027         ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1028         ob->resize( desktop()->width()/3, ob->height() );
1029       */
1030     }
1031   }
1032   else if ( flag == WT_PyConsole )
1033   {
1034     PyConsole_Console* pyCons = new PyConsole_EnhConsole( desktop(), new SalomeApp_PyInterp() );
1035     pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1036     pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1037     pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1038     pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1039     wid = pyCons;
1040     //pyCons->resize( pyCons->width(), desktop()->height()/4 );
1041     pyCons->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
1042   }
1043   else if ( flag == WT_NoteBook )
1044   {
1045     SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1046     if ( appStudy ) {
1047       _PTR(Study) aStudy = appStudy->studyDS();
1048       setNoteBook( new SalomeApp_NoteBook( desktop(), aStudy ) );
1049       //to receive signal in NoteBook that it's variable was modified
1050       connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1051                getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1052     }
1053     wid = getNoteBook();
1054   }
1055   return wid;
1056 }
1057
1058 /*!Create preferences.*/
1059 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1060 {
1061   LightApp_Application::createPreferences(pref);
1062
1063   if ( !pref )
1064     return;
1065
1066   int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1067   int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1068   int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1069   for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1070   {
1071     pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1072                          LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1073   }
1074   pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1075
1076   // adding preference to LightApp_Application handled preferences..  a bit of hacking with resources..
1077   int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1078   int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1079   pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1080   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1081   pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1082   pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1083   pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1084   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1085   pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1086 }
1087
1088 /*!Update desktop title.*/
1089 void SalomeApp_Application::updateDesktopTitle() {
1090   QString aTitle = applicationName();
1091   QString aVer = applicationVersion();
1092   if ( !aVer.isEmpty() )
1093     aTitle += QString( " " ) + aVer;
1094
1095   if ( activeStudy() )
1096   {
1097     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1098     if ( !sName.isEmpty() ) {
1099       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1100       if ( study ) {
1101         _PTR(Study) stdDS = study->studyDS();
1102         if(stdDS) {
1103           if ( stdDS->GetProperties()->IsLocked() ) {
1104             aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1105           } else {
1106             aTitle += QString( " - [%1]" ).arg( sName );
1107           }
1108         }
1109       }
1110     }
1111   }
1112
1113   desktop()->setWindowTitle( aTitle );
1114 }
1115
1116 int SalomeApp_Application::closeChoice( const QString& docName )
1117 {
1118   int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ), tr( "APPCLOSE_DESCRIPTION" ).arg( docName ),
1119                                           tr ("APPCLOSE_SAVE"), tr ("APPCLOSE_CLOSE"),
1120                                           tr ("APPCLOSE_UNLOAD"), tr ("APPCLOSE_CANCEL"), 0 );
1121
1122   int res = CloseCancel;
1123   if ( answer == 0 )
1124     res = CloseSave;
1125   else if ( answer == 1 )
1126     res = CloseDiscard;
1127   else if ( answer == 2 )
1128     res = CloseUnload;
1129
1130   return res;
1131 }
1132
1133 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1134 {
1135   bool res = true;
1136   switch( choice )
1137   {
1138   case CloseSave:
1139     if ( activeStudy()->isSaved() )
1140       onSaveDoc();
1141     else if ( !onSaveAsDoc() )
1142       res = false;
1143     break;
1144   case CloseDiscard:
1145     break;
1146   case CloseUnload:
1147     closePermanently = false;
1148     break;
1149   case CloseCancel:
1150   default:
1151     res = false;
1152   }
1153
1154   return res;
1155 }
1156
1157 int SalomeApp_Application::openChoice( const QString& aName )
1158 {
1159   int choice = LightApp_Application::openChoice( aName );
1160
1161   if ( QFileInfo( aName ).exists() ) {
1162     if ( choice == OpenNew ) { // The document isn't already open.
1163       bool exist = false;
1164       std::vector<std::string> lst = studyMgr()->GetOpenStudies();
1165       for ( uint i = 0; i < lst.size() && !exist; i++ ) {
1166         if ( aName == QString( lst[i].c_str() ) )
1167           exist = true;
1168       }
1169       // The document already exists in the study manager.
1170       // Do you want to reload it?
1171       if ( exist ) {
1172         int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1173                                                 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1174         if ( answer == SUIT_MessageBox::Yes )
1175           choice = OpenRefresh;
1176         else
1177           choice = OpenCancel;
1178       }
1179     }
1180   } else { // file is not exist on disk
1181     SUIT_MessageBox::warning( desktop(),
1182                               QObject::tr("WRN_WARNING"),
1183                               QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toLatin1().data()));
1184     return false;
1185   }
1186
1187   return choice;
1188 }
1189
1190 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1191 {
1192   bool res = false;
1193   int choice = aChoice;
1194   switch ( choice )
1195   {
1196   case OpenRefresh:
1197     {
1198       _PTR(Study) aStudy = studyMgr()->GetStudyByName( aName.toStdString() );
1199       if ( aStudy )
1200       {
1201         studyMgr()->Close( aStudy );
1202         choice = OpenNew;
1203       }
1204     }
1205   default:
1206     res = LightApp_Application::openAction( choice, aName );
1207     break;
1208   }
1209
1210   return res;
1211 }
1212
1213 /*!
1214   \brief Get map of the operations which can be performed
1215   on the module activation.
1216
1217   The method should return the map of the kind \c {<id>:<name>}
1218   where \c <id> is an integer identifier of the operation and
1219   \c <name> is a title for the button to be added to the
1220   dialog box. After user selects the required operation by the
1221   clicking the corresponding button in the dialog box, its identifier
1222   is passed to the moduleActionSelected() method to process
1223   the made choice.
1224
1225   \return map of the operations
1226   \sa moduleActionSelected()
1227 */
1228 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1229 {
1230   QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1231   opmap.insert( LoadStudyId,     tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1232   opmap.insert( NewAndScriptId,  tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1233   return opmap;
1234 }
1235
1236 /*!
1237   \brief Called when the used selectes required operation chosen
1238   from "Activate module" dialog box.
1239
1240   Performs the required operation according to the user choice.
1241
1242   \param id operation identifier
1243   \sa activateModuleActions()
1244 */
1245 void SalomeApp_Application::moduleActionSelected( const int id )
1246 {
1247   switch ( id ) {
1248   case LoadStudyId:
1249     onLoadDoc();
1250     break;
1251   case NewAndScriptId:
1252     onNewWithScript();
1253     break;
1254   default:
1255     LightApp_Application::moduleActionSelected( id );
1256     break;
1257   }
1258 }
1259
1260 /*!Gets CORBA::ORB_var*/
1261 CORBA::ORB_var SalomeApp_Application::orb()
1262 {
1263   ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1264   static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() );
1265   return _orb;
1266 }
1267
1268 /*!Create and return SALOMEDS_StudyManager.*/
1269 SALOMEDSClient_StudyManager* SalomeApp_Application::studyMgr()
1270 {
1271   static _PTR(StudyManager) _sm;
1272   if(!_sm) _sm = ClientFactory::StudyManager();
1273   return _sm.get();
1274 }
1275
1276 /*!Create and return SALOME_NamingService.*/
1277 SALOME_NamingService* SalomeApp_Application::namingService()
1278 {
1279   static SALOME_NamingService _ns(orb());
1280   return &_ns;
1281 }
1282
1283 /*!Create and return SALOME_LifeCycleCORBA.*/
1284 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1285 {
1286   static SALOME_LifeCycleCORBA _lcc( namingService() );
1287   return &_lcc;
1288 }
1289
1290 /*!Private SLOT. On preferences.*/
1291 void SalomeApp_Application::onProperties()
1292 {
1293   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1294   if( !study )
1295     return;
1296
1297   _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1298   SB->NewCommand();
1299
1300   SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1301   int res = aDlg.exec();
1302   if( res==QDialog::Accepted && aDlg.isChanged() )
1303     SB->CommitCommand();
1304   else
1305     SB->AbortCommand();
1306
1307   //study->updateCaptions();
1308   updateDesktopTitle();
1309   updateActions();
1310 }
1311
1312 /*!Insert items in popup, which necessary for current application*/
1313 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1314 {
1315   LightApp_SelectionMgr* mgr = selectionMgr();
1316   bool cacheIsOn = mgr->isSelectionCacheEnabled();
1317   mgr->setSelectionCacheEnabled( true );
1318
1319   LightApp_Application::contextMenuPopup( type, thePopup, title );
1320
1321   // temporary commented
1322   /*OB_Browser* ob = objectBrowser();
1323   if ( !ob || type != ob->popupClientType() )
1324     return;*/
1325
1326   // Get selected objects
1327   SALOME_ListIO aList;
1328   mgr->selectedObjects( aList, QString(), false );
1329
1330   // add GUI state commands: restore, rename
1331   if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1332        QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1333     thePopup->addSeparator();
1334     thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1335     thePopup->addAction( tr( "MEN_RENAME_VS" ),  objectBrowser(),
1336                          SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1337     thePopup->addAction( tr( "MEN_DELETE_VS" ),  this, SLOT( onDeleteGUIState() ) );
1338   }
1339
1340   // "Delete reference" item should appear only for invalid references
1341
1342   // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1343   bool isInvalidRefs = false;
1344   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(activeStudy());
1345   _PTR(Study) aStudyDS = aStudy->studyDS();
1346   _PTR(SObject) anObj;
1347
1348   for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1349     if( it.Value()->hasEntry() )
1350     {
1351       _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1352       while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1353         aRefObj = anObj;
1354
1355       if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1356         isInvalidRefs = true;
1357     }
1358
1359   // Add "Delete reference" item to popup
1360   if ( isInvalidRefs )
1361   {
1362     thePopup->addSeparator();
1363     thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1364     return;
1365   }
1366
1367   // "Activate module" item should appear only if it's necessary
1368   if ( aList.Extent() == 1 ) {
1369     aList.Clear();
1370     mgr->selectedObjects( aList );
1371
1372     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1373
1374     // add extra popup menu (defined in XML)
1375     if ( myExtActions.size() > 0 ) {
1376       // Use only first selected object
1377       SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1378       if ( study ) {
1379         _PTR(Study) stdDS = study->studyDS();
1380         if ( stdDS ) {
1381           _PTR(SObject) aSO = stdDS->FindObjectID( aIObj->getEntry() );
1382           if ( aSO ) {
1383             _PTR( GenericAttribute ) anAttr;
1384             std::string auid = "AttributeUserID";
1385             auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1386             if ( aSO->FindAttribute( anAttr, auid ) ) {
1387               _PTR(AttributeUserID) aAttrID = anAttr;
1388               QString aId = aAttrID->Value().c_str();
1389               if ( myExtActions.contains( aId ) ) {
1390                 thePopup->addAction(myExtActions[aId]);
1391               }
1392             }
1393           }
1394         }
1395       }
1396     }
1397
1398     // check if item is a "GUI state" item (also a first level object)
1399     QString entry( aIObj->getEntry() );
1400     if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1401       QString aModuleName( aIObj->getComponentDataType() );
1402       QString aModuleTitle = moduleTitle( aModuleName );
1403       CAM_Module* currentModule = activeModule();
1404       if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1405         thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1406     }
1407   }
1408
1409   mgr->setSelectionCacheEnabled( cacheIsOn );
1410 }
1411
1412 /*!Update obect browser:
1413  1.if 'updateModels' true, update existing data models;
1414  2. update "non-existing" (not loaded yet) data models;
1415  3. update object browser if it exists */
1416 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1417 {
1418   // update "non-existing" (not loaded yet) data models
1419   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1420   if ( study )
1421   {
1422     _PTR(Study) stdDS = study->studyDS();
1423     if( stdDS )
1424     {
1425       for ( _PTR(SComponentIterator) it ( stdDS->NewComponentIterator() ); it->More(); it->Next() )
1426       {
1427         _PTR(SComponent) aComponent ( it->Value() );
1428
1429 #ifndef WITH_SALOMEDS_OBSERVER
1430         // with GUI observers this check is not needed anymore
1431         if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1432           continue; // skip the magic "Interface Applicative" component
1433 #endif
1434         if ( !objectBrowser() )
1435           getWindow( WT_ObjectBrowser );
1436         const bool isAutoUpdate = objectBrowser()->autoUpdate();
1437         objectBrowser()->setAutoUpdate( false );
1438         SalomeApp_DataModel::synchronize( aComponent, study );
1439         objectBrowser()->setAutoUpdate( isAutoUpdate );
1440       }
1441     }
1442   }
1443
1444   // create data objects that correspond to GUI state save points
1445   if ( study ) updateSavePointDataObjects( study );
1446
1447   // update existing data models (already loaded SComponents)
1448   LightApp_Application::updateObjectBrowser( updateModels );
1449 }
1450
1451 /*!Display Catalog Genenerator dialog */
1452 void SalomeApp_Application::onCatalogGen()
1453 {
1454   ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1455   aDlg.exec();
1456 }
1457
1458 /*!Display Registry Display dialog */
1459 void SalomeApp_Application::onRegDisplay()
1460 {
1461   CORBA::ORB_var anOrb = orb();
1462   ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1463   regWnd->show();
1464   regWnd->raise();
1465   regWnd->activateWindow();
1466 }
1467
1468 /*!find original object by double click on item */
1469 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1470 {
1471   // Issue 21379: References are supported at LightApp_DataObject level
1472   LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1473
1474   if( obj && obj->isReference() )
1475   {
1476     QString entry = obj->refEntry();
1477
1478     SUIT_DataOwnerPtrList aList;
1479     aList.append( new LightApp_DataOwner( entry ) );
1480     selectionMgr()->setSelected( aList, false );
1481
1482     SUIT_DataBrowser* ob = objectBrowser();
1483
1484     QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1485     if ( !aSelectedIndexes.isEmpty() )
1486       ob->treeView()->scrollTo( aSelectedIndexes.first() );
1487   }
1488 }
1489
1490 /*!
1491   Creates new view manager
1492   \param type - type of view manager
1493 */
1494 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1495 {
1496   return createViewManager(type);
1497 }
1498
1499
1500 /*!Global utility funciton, returns selected GUI Save point object's ID */
1501 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1502 {
1503   SALOME_ListIO aList;
1504   selMgr->selectedObjects( aList );
1505   if( aList.Extent() > 0 ) {
1506     Handle(SALOME_InteractiveObject) aIObj = aList.First();
1507     QString entry( aIObj->getEntry() );
1508     QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1509     if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1510       return -1;
1511     bool ok; // conversion to integer is ok?
1512     int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1513     return ok ? savePoint : -1;
1514   }
1515   return -1;
1516 }
1517
1518 /*!Called on Restore GUI State popup command*/
1519 void SalomeApp_Application::onRestoreGUIState()
1520 {
1521   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1522   if ( savePoint == -1 )
1523     return;
1524   SalomeApp_VisualState( this ).restoreState( savePoint );
1525 }
1526
1527 /*!Called on Delete GUI State popup command*/
1528 void SalomeApp_Application::onDeleteGUIState()
1529 {
1530   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1531   if ( savePoint == -1 )
1532     return;
1533   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1534   if ( !study )
1535     return;
1536
1537   study->removeSavePoint( savePoint );
1538   updateSavePointDataObjects( study );
1539 }
1540
1541 /*!Called on New study operation*/
1542 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1543 {
1544   LightApp_Application::onStudyCreated( study );
1545
1546   desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1547                                windowDock( getWindow( WT_ObjectBrowser ) ) );
1548
1549   loadDockWindowsState();
1550
1551   connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1552            this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1553
1554
1555   objectBrowserColumnsVisibility();
1556 }
1557
1558 /*!Called on Save study operation*/
1559 void SalomeApp_Application::onStudySaved( SUIT_Study* study )
1560 {
1561   LightApp_Application::onStudySaved( study );
1562
1563   // temporary commented
1564   /*if ( objectBrowser() ) {
1565     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1566     objectBrowser()->updateTree( study->root() );
1567   }*/
1568 }
1569
1570 /*!Called on Open study operation*/
1571 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1572 {
1573   LightApp_Application::onStudyOpened( study );
1574
1575   desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1576                                windowDock( getWindow( WT_ObjectBrowser ) ) );
1577
1578   loadDockWindowsState();
1579
1580   connect( this, SIGNAL( viewManagerRemoved( SUIT_ViewManager* ) ),
1581            this, SLOT( onViewManagerRemoved( SUIT_ViewManager* ) ), Qt::UniqueConnection );
1582
1583   objectBrowserColumnsVisibility();
1584
1585   // temporary commented
1586   /*if ( objectBrowser() ) {
1587     updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1588     objectBrowser()->updateTree( study->root() );
1589   }*/
1590 }
1591
1592 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1593 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1594 {
1595
1596   SUIT_DataBrowser* ob = objectBrowser();
1597   LightApp_SelectionMgr* selMgr = selectionMgr();
1598
1599   if ( !study || !ob || !selMgr )
1600     return;
1601
1602   // find GUI states root object
1603   SUIT_DataObject* guiRootObj = 0;
1604   DataObjectList ch;
1605   study->root()->children( ch );
1606   DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1607   for ( ; it != last ; ++it ) {
1608     if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1609       guiRootObj = *it;
1610       break;
1611     }
1612   }
1613   std::vector<int> savePoints = study->getSavePoints();
1614   // case 1: no more save points but they existed in study's tree
1615   if ( savePoints.empty() && guiRootObj ) {
1616     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1617     //    : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1618     const bool isAutoUpdate = ob->autoUpdate();
1619     selMgr->clearSelected();
1620     ob->setAutoUpdate(true);
1621     DataObjectList ch = guiRootObj->children();
1622     for( int i = 0; i < ch.size(); i++ )
1623       delete ch[i];
1624     delete guiRootObj;
1625     ob->setAutoUpdate(isAutoUpdate);
1626     return;
1627   }
1628   // case 2: no more save points but root does not exist either
1629   if ( savePoints.empty() && !guiRootObj )
1630     return;
1631   // case 3: save points but no root for them - create it
1632   if ( !savePoints.empty() && !guiRootObj )
1633     guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1634   // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1635   // to be always the last one in the tree.  Here we check - if it is not the last one - remove and
1636   // re-create it.
1637   if ( guiRootObj->nextBrother() ) {
1638     study->root()->removeChild(guiRootObj);
1639     study->root()->appendChild(guiRootObj);
1640     //study->root()->dump();
1641   }
1642
1643   // store data objects in a map id-to-DataObject
1644   QMap<int,SalomeApp_SavePointObject*> mapDO;
1645   ch.clear();
1646   guiRootObj->children( ch );
1647   for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1648     SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1649     if ( dobj )
1650       mapDO[dobj->getId()] = dobj;
1651   }
1652
1653   // iterate new save points.  if DataObject with such ID not found in map - create DataObject
1654   // if in the map - remove it from map.
1655   for ( int i = 0; i < savePoints.size(); i++ )
1656     if ( !mapDO.contains( savePoints[i] ) )
1657       new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1658     else
1659       mapDO.remove( savePoints[i] );
1660
1661   // delete DataObjects that are still in the map -- their IDs were not found in data model
1662   if( mapDO.size() > 0) {
1663     //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1664     //    : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1665     selMgr->clearSelected();
1666     const bool isAutoUpdate = ob->autoUpdate();
1667     ob->setAutoUpdate(true);
1668     for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1669       delete it.value();
1670     ob->setAutoUpdate(isAutoUpdate);
1671   }
1672 }
1673
1674 /*! Check data object */
1675 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1676 {
1677   if (theObj)
1678     return true;
1679
1680   return false;
1681 }
1682
1683 /*!
1684   Opens other study into active Study. If Study is empty - creates it.
1685   \param theName - name of study
1686 */
1687 bool SalomeApp_Application::useStudy( const QString& theName )
1688 {
1689   createEmptyStudy();
1690   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1691   bool res = false;
1692   if (aStudy)
1693     res = aStudy->loadDocument( theName );
1694   updateDesktopTitle();
1695   updateCommandsStatus();
1696   return res;
1697 }
1698
1699 /*! Show/hide object browser colums according to preferences */
1700 void SalomeApp_Application::objectBrowserColumnsVisibility()
1701 {
1702   if ( objectBrowser() )
1703     for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1704     {
1705       bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1706       objectBrowser()->treeView()->setColumnHidden( i, !shown );
1707     }
1708 }
1709
1710 /*! Set SalomeApp_NoteBook pointer */
1711 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1712 {
1713   myNoteBook = theNoteBook;
1714 }
1715
1716 /*! Return SalomeApp_NoteBook pointer */
1717 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1718 {
1719   return myNoteBook;
1720 }
1721
1722 /*!
1723  * Define extra actions defined in module definition XML file.
1724  * Additional popup items sections can be defined by parameter "popupitems".
1725  * Supported attributes:
1726  * title - title of menu item,
1727  * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1728  * method - method which has to be called when menu item is selected
1729  * Example:
1730  * <section name="MODULENAME">
1731  *   <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1732  * </section>
1733  * <section name="importmed">
1734  *   <parameter name="title" value="My menu"/>
1735  *   <parameter name="objectid" value="VISU.Result"/>
1736  *   <parameter name="method" value="nameOfModuleMethod"/>
1737  * </section>
1738  */
1739 void SalomeApp_Application::createExtraActions()
1740 {
1741   myExtActions.clear();
1742   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1743
1744   QStringList aModules;
1745   modules(aModules, false);
1746   foreach(QString aModile, aModules) {
1747     QString aModName = moduleName(aModile);
1748     QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1749     if (!aSectionStr.isNull()) {
1750       QStringList aSections = aSectionStr.split(':');
1751       foreach(QString aSection, aSections) {
1752         QString aTitle = resMgr->stringValue(aSection, "title",    QString());
1753         QString aId    = resMgr->stringValue(aSection, "objectid", QString());
1754         QString aSlot  = resMgr->stringValue(aSection, "method",   QString());
1755         if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1756           continue;
1757
1758         QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1759         if (aModuleName.isNull())
1760           aModuleName = aModName;
1761
1762         QAction* aAction = new QAction(aTitle, this);
1763         QStringList aData;
1764         aData<<aModuleName<<aSlot;
1765         aAction->setData(aData);
1766         connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1767         myExtActions[aId] = aAction;
1768       }
1769     }
1770   }
1771 }
1772
1773 /*!
1774  * Called when extra action is selected
1775  */
1776 void SalomeApp_Application::onExtAction()
1777 {
1778   QAction* aAction = ::qobject_cast<QAction*>(sender());
1779   if (!aAction)
1780     return;
1781
1782   QVariant aData = aAction->data();
1783   QStringList aDataList = aData.value<QStringList>();
1784   if (aDataList.size() != 2)
1785     return;
1786
1787   LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1788   SALOME_ListIO aListIO;
1789   aSelectionMgr->selectedObjects(aListIO);
1790   const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1791   if (aListIO.Extent() < 1)
1792     return;
1793   if (!anIO->hasEntry())
1794     return;
1795
1796   QString aEntry(anIO->getEntry());
1797
1798   QApplication::setOverrideCursor( Qt::WaitCursor );
1799   QString aModuleTitle = moduleTitle(aDataList[0]);
1800   activateModule(aModuleTitle);
1801   QApplication::restoreOverrideCursor();
1802
1803   QCoreApplication::processEvents();
1804
1805   CAM_Module* aModule = activeModule();
1806   if (!aModule)
1807     return;
1808
1809   if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1810     printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1811 }
1812
1813 /*!
1814  * Called when window activated
1815  */
1816 void SalomeApp_Application::onWindowActivated( SUIT_ViewWindow* theViewWindow )
1817 {
1818   SUIT_DataBrowser* anOB = objectBrowser();
1819   if( !anOB )
1820     return;
1821   SUIT_DataObject* rootObj = anOB->root();
1822   if( !rootObj )
1823     return;
1824
1825   DataObjectList listObj = rootObj->children( true );
1826
1827   SUIT_ViewModel* vmod = 0;
1828   if ( SUIT_ViewManager* vman = theViewWindow->getViewManager() )
1829     vmod = vman->getViewModel();
1830   updateVisibilityState( listObj, vmod );
1831 }
1832
1833 /*!
1834   Update visibility state of given objects
1835  */
1836 void SalomeApp_Application::updateVisibilityState( DataObjectList& theList,
1837                                                    SUIT_ViewModel*  theViewModel )
1838 {
1839   LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1840
1841   if(!theViewModel)
1842     return;
1843
1844   SALOME_View* aView = dynamic_cast<SALOME_View*>( theViewModel );
1845
1846   if (theList.isEmpty() || !aStudy)
1847     return;
1848
1849   for ( DataObjectList::iterator itr = theList.begin(); itr != theList.end(); ++itr ) {
1850     LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>(*itr);
1851
1852     if (!obj || aStudy->isComponent(obj->entry()))
1853       continue;
1854
1855     LightApp_Module* anObjModule = dynamic_cast<LightApp_Module*>(obj->module());
1856     Qtx::VisibilityState anObjState = Qtx::UnpresentableState;
1857
1858     if(anObjModule) {
1859       LightApp_Displayer* aDisplayer = anObjModule->displayer();
1860       if(aDisplayer) {
1861         if( aDisplayer->canBeDisplayed(obj->entry(), theViewModel->getType()) ) {
1862           if(aView && aDisplayer->IsDisplayed(obj->entry(),aView))
1863             anObjState = Qtx::ShownState;
1864           else
1865             anObjState = Qtx::HiddenState;
1866         }
1867         aStudy->setVisibilityState( obj->entry(), anObjState );
1868       }
1869     }
1870   }
1871 }
1872
1873 /*!
1874   Called then view manager removed
1875 */
1876 void SalomeApp_Application::onViewManagerRemoved( SUIT_ViewManager* )
1877 {
1878   ViewManagerList lst;
1879   viewManagers(lst);
1880   if( lst.count() == 1) { // in case if closed last view window
1881     LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>(activeStudy());
1882     if(aStudy)
1883       aStudy->setVisibilityStateForAll(Qtx::UnpresentableState);
1884   }
1885 }
1886
1887 /*!
1888   Checks that an object can be renamed.
1889   \param entry entry of the object
1890   \brief Return \c true if object can be renamed
1891 */
1892 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1893 {
1894   return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1895 }
1896
1897 /*!
1898   Rename object by entry.
1899   \param entry entry of the object
1900   \param name new name of the object
1901   \brief Return \c true if rename operation finished successfully, \c false otherwise.
1902 */
1903 bool SalomeApp_Application::renameObject( const QString& entry, const QString& name )
1904 {
1905   SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1906
1907   int savePoint = ::getSelectedSavePoint( selectionMgr() );
1908
1909   if(!aStudy || savePoint == -1)
1910     return false;
1911
1912   if ( !name.isNull() && !name.isEmpty() ) {
1913     aStudy->setNameOfSavePoint( savePoint, name );
1914     updateSavePointDataObjects( aStudy );
1915
1916     //Mark study as modified
1917     aStudy->Modified();
1918     return true;
1919   }
1920   return false;
1921 }
1922
1923 /*!
1924   \return default windows( Object Browser, Python Console )
1925   Adds to map \a aMap.
1926 */
1927 void SalomeApp_Application::defaultWindows( QMap<int, int>& aMap ) const
1928 {
1929   LightApp_Application::defaultWindows(aMap);
1930   if ( !aMap.contains( WT_NoteBook ) ) {
1931     if ( !myNoteBook ) {
1932       aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1933     }
1934   }
1935 }
1936
1937 /*!
1938   Gets current windows.
1939   \param winMap - output current windows map.
1940 */
1941 void SalomeApp_Application::currentWindows(QMap<int, int>& aMap) const
1942 {
1943   LightApp_Application::currentWindows( aMap );
1944   if ( !aMap.contains( WT_NoteBook) && myNoteBook )
1945     aMap.insert( WT_NoteBook, Qt::LeftDockWidgetArea );
1946 }
1947
1948 //============================================================================
1949 /*! Function : onUpdateStudy
1950  *  Purpose  : Slot to update the study.
1951  */
1952 //============================================================================
1953 void SalomeApp_Application::onUpdateStudy()
1954 {
1955   QApplication::setOverrideCursor( Qt::WaitCursor );
1956
1957   if( !updateStudy() )
1958     SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1959
1960   QApplication::restoreOverrideCursor();
1961 }
1962
1963 //============================================================================
1964 /*! Function : updateStudy
1965  *  Purpose  : Update study by dumping the study to Python script and loading it.
1966  *             It is used to apply variable modifications done in NoteBook to created objects.
1967  */
1968 //============================================================================
1969 bool SalomeApp_Application::updateStudy()
1970 {
1971   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1972   if ( !study || !myNoteBook )
1973     return false;
1974
1975   myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1976   myNoteBook->setDumpedStudyName( study->studyName() );
1977
1978   _PTR(Study) studyDS = study->studyDS();
1979
1980   // get unique temporary directory name
1981   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1982   if( aTmpDir.isEmpty() )
1983     return false;
1984
1985   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1986     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1987
1988   // dump study to the temporary directory
1989   QString aScriptName( "notebook" );
1990   bool toPublish = true;
1991   bool isMultiFile = false;
1992   bool toSaveGUI = true;
1993
1994   int savePoint;
1995   _PTR(AttributeParameter) ap;
1996   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1997   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1998   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1999     ip->setDumpPython(studyDS);
2000     savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
2001   }
2002   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
2003   if ( toSaveGUI )
2004     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
2005
2006   if( ok )
2007     myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
2008   else
2009     return false;
2010
2011   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
2012   int anIndex = aList.indexOf( this );
2013
2014   // Disconnect dialog from application desktop in case if:
2015   // 1) Application is not the first application in the session
2016   // 2) Application is the first application in session but not the only.
2017   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
2018   if( changeDesktop ) {
2019
2020     SalomeApp_Application* app = this;
2021     if( anIndex > 0 && anIndex < aList.count() )
2022       app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
2023     else if(anIndex == 0 && aList.count() > 1)
2024       app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
2025
2026     if( !app )
2027       return false;
2028
2029     // creation a new study and restoring will be done in another application
2030     connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2031              app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2032   }
2033
2034   QString aDumpScript = myNoteBook->getDumpedStudyScript();
2035   QString aStudyName = myNoteBook->getDumpedStudyName();
2036   bool isStudySaved = myNoteBook->isDumpedStudySaved();
2037   // clear a study (delete all objects)
2038   onCloseDoc( false );
2039
2040   if( !changeDesktop ) {
2041     ok = onRestoreStudy( aDumpScript,
2042                          aStudyName,
2043                          isStudySaved );
2044   }
2045
2046   return ok;
2047 }
2048
2049 //============================================================================
2050 /*! Function : onRestoreStudy
2051  *  Purpose  : Load the dumped study from Python script
2052  */
2053 //============================================================================
2054 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2055                                             const QString& theStudyName,
2056                                             bool theIsStudySaved )
2057 {
2058   bool ok = true;
2059
2060   // create a new study
2061   onNewDoc();
2062
2063   // get active application
2064   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2065
2066   // load study from the temporary directory
2067   QString command = QString( "execfile(r\"%1\")" ).arg( theDumpScript );
2068
2069   PyConsole_Console* pyConsole = app->pythonConsole();
2070   if ( pyConsole )
2071     pyConsole->execAndWait( command );
2072
2073   // remove temporary directory
2074   QFileInfo aScriptInfo = QFileInfo( theDumpScript );
2075   QString aStudyName = aScriptInfo.baseName();
2076   QDir aDir = aScriptInfo.absoluteDir();
2077   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2078   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2079     ok = aDir.remove( *it ) && ok;
2080   if( ok )
2081     ok = aDir.rmdir( aDir.absolutePath() );
2082
2083   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2084   {
2085     _PTR(Study) aStudyDS = newStudy->studyDS();
2086     app->getNoteBook()->Init( aStudyDS );
2087     newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2088     newStudy->Modified();
2089     updateDesktopTitle();
2090     updateActions();
2091   }
2092   else
2093     ok = false;
2094
2095   return ok;
2096 }
2097
2098 /*!
2099   Close the Application
2100 */
2101 void SalomeApp_Application::afterCloseDoc()
2102 {
2103   // emit signal to restore study from Python script
2104   if ( myNoteBook ) {
2105     emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2106                             myNoteBook->getDumpedStudyName(),
2107                             myNoteBook->isDumpedStudySaved() );
2108   }
2109   LightApp_Application::afterCloseDoc();
2110 }