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