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