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