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