Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / SalomeApp / SalomeApp_NoteBookDlg.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:    SalomeApp_NoteBookDlg.cxx
21 // Author : Roman NIKOLAEV, Open CASCADE S.A.S.
22 // Module : GUI
23 //
24 #include <PyConsole_Interp.h> // this include must be first (see PyInterp_base.h)!
25 #include <PyConsole_Console.h>
26
27 #include "SalomeApp_NoteBookDlg.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Study.h"
30 #include "SalomeApp_VisualState.h"
31
32 #include <Qtx.h>
33
34 #include <CAM_Module.h>
35
36 #include <SUIT_Desktop.h>
37 #include <SUIT_MessageBox.h>
38 #include <SUIT_ResourceMgr.h>
39 #include <SUIT_Session.h>
40
41 #include <SALOMEDS_Tool.hxx>
42
43 #include <QWidget>
44 #include <QDialog>
45 #include <QGridLayout>
46 #include <QTableWidget>
47 #include <QTableWidgetItem>
48 #include <QPushButton>
49 #include <QFont>
50 #include <QGroupBox>
51 #include <QList>
52 #include <QApplication>
53 #include <QDir>
54
55 #include <string>
56 #include <vector>
57
58 #define DEFAULT_MARGIN  11
59 #define DEFAULT_SPACING 6
60 #define SPACER_SIZE     120
61 #define COLUMN_SIZE     180
62
63 #define NAME_COLUMN  0
64 #define VALUE_COLUMN 1
65
66
67 ///////////////////////////////////////////////////////////////////////////
68 //                 NoteBook_TableRow class                               //
69 ///////////////////////////////////////////////////////////////////////////
70 //============================================================================
71 /*! Function : NoteBook_TableRow
72  *  Purpose  : Constructor
73  */
74 //============================================================================
75 NoteBook_TableRow::NoteBook_TableRow(int index, NoteBook_Table* parentTable, QWidget* parent):
76   QWidget(parent),
77   myParentTable(parentTable),
78   myIndex(index),
79   myRowHeader(new QTableWidgetItem()),
80   myVariableName(new QTableWidgetItem()),
81   myVariableValue(new QTableWidgetItem())
82 {
83 }
84
85 //============================================================================
86 /*! Function : ~NoteBook_TableRow
87  *  Purpose  : Destructor
88  */
89 //============================================================================
90 NoteBook_TableRow::~NoteBook_TableRow()
91 {
92 }
93
94 //============================================================================
95 /*! Function : AddToTable
96  *  Purpose  : Add this row to the table theTable
97  */
98 //============================================================================
99 void NoteBook_TableRow::AddToTable(QTableWidget *theTable)
100 {
101   int aPosition = theTable->rowCount();
102   int aRowCount = aPosition+1;
103   theTable->setRowCount(aRowCount);
104   myRowHeader->setText(QString::number(aRowCount));
105
106   theTable->setVerticalHeaderItem(aPosition,myRowHeader);
107   theTable->setItem(aPosition, NAME_COLUMN, myVariableName);
108   theTable->setItem(aPosition, VALUE_COLUMN, myVariableValue);
109 }
110
111 //============================================================================
112 /*! Function : SetName
113  *  Purpose  : 
114  */
115 //============================================================================
116 void NoteBook_TableRow::SetName(const QString theName)
117 {
118   myVariableName->setText(theName);
119 }
120
121 //============================================================================
122 /*! Function : SetValue
123  *  Purpose  : 
124  */
125 //============================================================================
126 void NoteBook_TableRow::SetValue(const QString theValue)
127 {
128   myVariableValue->setText(theValue);
129 }
130
131 //============================================================================
132 /*! Function : GetName
133  *  Purpose  : Return variable name
134  */
135 //============================================================================
136 QString NoteBook_TableRow::GetName() const
137 {
138   return myVariableName->text();
139 }
140
141 //============================================================================
142 /*! Function : GetValue
143  *  Purpose  : Return variable value
144  */
145 //============================================================================
146 QString NoteBook_TableRow::GetValue() const
147 {
148   return myVariableValue->text(); 
149 }
150
151 //============================================================================
152 /*! Function : CheckName
153  *  Purpose  : Return true if variable name correct, otherwise return false
154  */
155 //============================================================================
156 bool NoteBook_TableRow::CheckName()
157 {
158   QString aName = GetName();
159   int aPos = 0;
160   QRegExpValidator aValidator( QRegExp("^([a-zA-Z]+)([a-zA-Z0-9_]*)$"), 0 );
161   if( aName.isEmpty() || !aValidator.validate( aName, aPos ) )
162     return false;
163   return true;
164 }
165
166 //============================================================================
167 /*! Function : CheckValue
168  *  Purpose  : Return true if variable value correct, otherwise return false
169  */
170 //============================================================================
171 bool NoteBook_TableRow::CheckValue()
172 {
173   bool aResult = false;
174   QString aValue = GetValue();
175   if(!aValue.isEmpty() && 
176      (IsRealValue(aValue) ||
177       IsIntegerValue(aValue) ||
178       IsBooleanValue(aValue) ||
179       IsValidStringValue(aValue)))
180     aResult = true;
181   
182   return aResult;
183 }
184
185 //============================================================================
186 /*! Function : GetVariableItem
187  *  Purpose  : 
188  */
189 //============================================================================
190 QTableWidgetItem* NoteBook_TableRow::GetVariableItem()
191 {
192   return myVariableValue;
193 }
194
195 //============================================================================
196 /*! Function : GetNameItem
197  *  Purpose  : 
198  */
199 //============================================================================
200 QTableWidgetItem* NoteBook_TableRow::GetNameItem()
201 {
202   return myVariableName;
203 }
204
205 //============================================================================
206 /*! Function : GetHeaderItem
207  *  Purpose  : 
208  */
209 //============================================================================
210 QTableWidgetItem* NoteBook_TableRow::GetHeaderItem()
211 {
212   return myRowHeader;
213 }
214
215 //============================================================================
216 /*! Function : IsRealValue
217  *  Purpose  : Return true if theValue string is real value, otherwise return 
218  *             false
219  */
220 //============================================================================
221 bool NoteBook_TableRow::IsRealValue(const QString theValue, double* theResult)
222 {
223   bool aResult = false;
224   double aDResult = theValue.toDouble(&aResult);
225   if(aResult && theResult)
226     *theResult = aDResult;
227   
228   return aResult;
229 }
230
231 //============================================================================
232 /*! Function : IsBooleanValue
233  *  Purpose  : Return true if theValue String is boolean value, otherwise return 
234  *             false
235  */
236 //============================================================================
237 bool NoteBook_TableRow::IsBooleanValue(const QString theValue, bool* theResult){
238   bool aResult = false;
239   bool aBResult; 
240   if(theValue.compare("True") == 0) {
241     aBResult = true;
242     aResult = true;
243   }
244   else if(theValue.compare("False") == 0) {
245     aBResult = false;
246     aResult = true;
247   }
248   if(aResult && theResult)
249     *theResult = aBResult;
250   
251   return aResult;
252 }
253
254 //============================================================================
255 /*! Function : IsIntegerValue
256  *  Purpose  : Return true if theValue string is integer value, otherwise return 
257  *             false
258  */
259 //============================================================================
260 bool NoteBook_TableRow::IsIntegerValue(const QString theValue, int* theResult)
261 {
262   bool aResult = false;
263   int anIResult;
264   anIResult = theValue.toInt(&aResult);
265
266   if(aResult && theResult)
267     *theResult = anIResult;  
268   
269   return aResult;
270 }
271
272 //============================================================================
273 /*! Function : IsValidStringValue
274  *  Purpose  : Return true if theValue string is valid, otherwise return 
275  *             false
276  *             The string are always valid for the moment
277  *             The whole notebook is verified on apply
278  */
279 //============================================================================
280 bool NoteBook_TableRow::IsValidStringValue(const QString theValue)
281 {
282   int aNumRows = myParentTable->myRows.count();
283   if( aNumRows == 0 )
284     return true;
285
286   bool aLastRowIsEmpty = myParentTable->myRows[ aNumRows - 1 ]->GetName().isEmpty() &&
287                          myParentTable->myRows[ aNumRows - 1 ]->GetValue().isEmpty();
288
289   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
290   PyConsole_Console* pyConsole = app->pythonConsole();
291   PyConsole_Interp* pyInterp = pyConsole->getInterp();
292   PyLockWrapper aLock = pyInterp->GetLockWrapper();
293   std::string command = "import salome_notebook ; ";
294   command += "salome_notebook.checkThisNoteBook(";
295   for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ ) {
296     command += myParentTable->myRows[i]->GetName().toStdString();
297     command += "=\"";
298     command += myParentTable->myRows[i]->GetValue().toStdString();
299     command += "\", ";
300   }
301   command += ") ";
302
303   //rnv: fix for bug 21947 WinTC5.1.4: Wrong error management of "Salome NoteBook"
304   bool oldSuppressValue = pyConsole->isSuppressOutput();
305   pyConsole->setIsSuppressOutput(true); 
306   bool aResult = pyInterp->run(command.c_str());
307   pyConsole->setIsSuppressOutput(oldSuppressValue);     
308   return !aResult;
309 }
310
311 ///////////////////////////////////////////////////////////////////////////
312 //                      NoteBook_Table class                             //
313 ///////////////////////////////////////////////////////////////////////////
314 //============================================================================
315 /*! Function : NoteBook_Table
316  *  Purpose  : Constructor
317  */
318 //============================================================================
319 NoteBook_Table::NoteBook_Table(QWidget * parent)
320   :QTableWidget(parent),
321    isProcessItemChangedSignal(false),
322    myIsModified(false)
323 {
324   setColumnCount(2);
325   setSelectionMode(QAbstractItemView::SingleSelection);
326   
327   //Add Headers Columns
328   QFont aFont = QFont();
329   aFont.setBold(true);
330   aFont.setPointSize(10);
331   
332   //"Name" column
333   QTableWidgetItem * aNameHeader = new QTableWidgetItem();
334   aNameHeader->setText(tr("VARNAME_COLUMN"));
335   aNameHeader->setFont(aFont);
336   setHorizontalHeaderItem(0,aNameHeader);
337   setColumnWidth ( 0, COLUMN_SIZE);
338
339   //"Value" Column
340   QTableWidgetItem * aValueHeader = new QTableWidgetItem();
341   aValueHeader->setText(tr("VARVALUE_COLUMN"));
342   aValueHeader->setFont(aFont);
343   setHorizontalHeaderItem(1,aValueHeader);
344   setColumnWidth ( 1, COLUMN_SIZE);
345   setSortingEnabled(false);
346   
347   connect(this,SIGNAL(itemChanged(QTableWidgetItem*)),this,SLOT(onItemChanged(QTableWidgetItem*)));
348 }
349
350 //============================================================================
351 /*! Function : ~NoteBook_Table
352  *  Purpose  : Destructor
353  */
354 //============================================================================
355 NoteBook_Table::~NoteBook_Table(){}
356
357 //============================================================================
358 /*! Function : getUniqueIndex
359  *  Purpose  : Get a unique index for the new row
360  */
361 //============================================================================
362 int NoteBook_Table::getUniqueIndex() const
363 {
364   int anIndex = 0;
365   if( !myRows.isEmpty() )
366     if( NoteBook_TableRow* aRow = myRows.last() )
367       anIndex = aRow->GetIndex();
368
369   int aMaxRemovedRow = 0;
370   for( QListIterator<int> anIter( myRemovedRows ); anIter.hasNext(); )
371   {
372     int aRemovedRow = anIter.next();
373     aMaxRemovedRow = qMax( aRemovedRow, aMaxRemovedRow );
374   }
375
376   anIndex = qMax( anIndex, aMaxRemovedRow ) + 1;
377   return anIndex;
378 }
379
380 //============================================================================
381 /*! Function : Init
382  *  Purpose  : Add variables in the table from theStudy
383  */
384 //============================================================================
385 void NoteBook_Table::Init(_PTR(Study) theStudy)
386 {
387   isProcessItemChangedSignal = false;
388
389   int aNumRows = myRows.count();
390   if( aNumRows > 0 )
391   {
392     for( int i = 0; i < myRows.size(); i++ )
393     {
394       NoteBook_TableRow* aRow = myRows[ i ];
395       if( aRow )
396       {
397         delete aRow;
398         aRow = 0;
399       }
400     }
401     myRows.clear();
402   }
403   setRowCount( 0 );
404
405   myRemovedRows.clear();
406   myVariableMapRef.clear();
407   myVariableMap.clear();
408
409   //Add all variables into the table
410   std::vector<std::string> aVariables = theStudy->GetVariableNames();
411   for(int iVar = 0; iVar < aVariables.size(); iVar++ ) {
412     AddRow(QString(aVariables[iVar].c_str()),
413            Variable2String(aVariables[iVar],theStudy));
414   }
415
416   //Add empty row
417   AddEmptyRow();
418   isProcessItemChangedSignal = true;
419
420   ResetMaps();
421
422   myStudy = theStudy;
423 }
424
425 //============================================================================
426 /*! Function : Variable2String
427  *  Purpose  : Convert variable values to QString
428  */
429 //============================================================================
430 QString NoteBook_Table::Variable2String(const std::string& theVarName,
431                                         _PTR(Study) theStudy)
432 {
433   QString aResult;
434   if( theStudy->IsReal(theVarName) )
435     aResult = QString::number(theStudy->GetReal(theVarName));
436   else if( theStudy->IsInteger(theVarName) )
437     aResult = QString::number(theStudy->GetInteger(theVarName));
438   else if( theStudy->IsBoolean(theVarName) )
439     aResult = theStudy->GetBoolean(theVarName) ? QString("True") : QString("False");
440   else if( theStudy->IsString(theVarName) )
441     aResult = theStudy->GetString(theVarName).c_str();
442   
443   return aResult;
444 }
445
446 //============================================================================
447 /*! Function : IsValid
448  *  Purpose  : Check validity of the table data
449  */
450 //============================================================================
451 bool NoteBook_Table::IsValid() const
452 {
453   int aNumRows = myRows.count();
454   if( aNumRows == 0 )
455     return true;
456
457   bool aLastRowIsEmpty = myRows[ aNumRows - 1 ]->GetName().isEmpty() &&
458                          myRows[ aNumRows - 1 ]->GetValue().isEmpty();
459
460   for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ )
461     if( !myRows[i]->CheckName() || !IsUniqueName( myRows[i] ) || !myRows[i]->CheckValue() )
462       return false;
463
464   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
465   PyConsole_Console* pyConsole = app->pythonConsole();
466   PyConsole_Interp* pyInterp = pyConsole->getInterp();
467   PyLockWrapper aLock = pyInterp->GetLockWrapper();
468   std::string command = "import salome_notebook ; ";
469   command += "salome_notebook.checkThisNoteBook(";
470   for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ )
471     {
472       command += myRows[i]->GetName().toStdString();
473       command += "=\"";
474       command += myRows[i]->GetValue().toStdString();
475       command += "\",";
476     }
477   command += ")";
478
479   //rnv: fix for bug 21947 WinTC5.1.4: Wrong error management of "Salome NoteBook"
480   bool oldSuppressValue = pyConsole->isSuppressOutput();
481   pyConsole->setIsSuppressOutput(true); 
482   bool aResult = pyInterp->run(command.c_str());
483   pyConsole->setIsSuppressOutput(oldSuppressValue);     
484
485   return !aResult;
486 }
487
488 //============================================================================
489 /*! Function : RenamberRowItems
490  *  Purpose  : renumber row items
491  */
492 //============================================================================
493 void NoteBook_Table::RenamberRowItems() {
494   for(int i=0; i<myRows.size();i++){
495     myRows[i]->GetHeaderItem()->setText(QString::number(i+1));
496   }
497 }
498
499 //============================================================================
500 /*! Function : AddRow
501  *  Purpose  : Add a row into the table
502  */
503 //============================================================================
504 void NoteBook_Table::AddRow(const QString& theName, const QString& theValue)
505 {
506   int anIndex = getUniqueIndex();
507   NoteBook_TableRow* aRow = new NoteBook_TableRow(anIndex, this, this);
508   aRow->SetName(theName);
509   aRow->SetValue(theValue);
510   aRow->AddToTable(this);
511   myRows.append(aRow);
512
513   myVariableMap.insert( anIndex, NoteBoox_Variable( theName, theValue ) );
514 }
515
516 //============================================================================
517 /*! Function : AddEmptyRow
518  *  Purpose  : Add an empty row into the end of the table
519  */
520 //============================================================================
521 void NoteBook_Table::AddEmptyRow()
522 {
523   isProcessItemChangedSignal = false;
524   AddRow();
525   isProcessItemChangedSignal = true;
526 }
527
528 //============================================================================
529 /*! Function : GetRowByItem
530  *  Purpose  : 
531  */
532 //============================================================================
533 NoteBook_TableRow* NoteBook_Table::GetRowByItem(const QTableWidgetItem* theItem) const
534 {
535   int aCurrentRow = row(theItem);
536   
537   if( (myRows.size() <= aCurrentRow ) && (aCurrentRow < 0))
538     return NULL;
539   else
540     return myRows.at(aCurrentRow);
541 }
542
543 //============================================================================
544 /*! Function : IsLastRow
545  *  Purpose  : Return true if theRow is last row in the table
546  */
547 //============================================================================
548 bool NoteBook_Table::IsLastRow(const NoteBook_TableRow* theRow) const
549 {
550   return (myRows.last() == theRow);
551 }
552
553 //============================================================================
554 /*! Function : onItemChanged
555  *  Purpose  : [slot] called then table item changed
556  */
557 //============================================================================
558 void NoteBook_Table::onItemChanged(QTableWidgetItem* theItem)
559 {
560   if(isProcessItemChangedSignal) {
561     bool isModified = true;
562     NoteBook_TableRow* aRow = GetRowByItem(theItem);
563     if(aRow) {
564       int aCurrentColumn = column(theItem);
565       bool IsCorrect = true, IsVariableComplited = false;
566       QString aMsg;
567
568       if(aCurrentColumn == NAME_COLUMN) {
569         int anIndex = aRow->GetIndex();
570         if( myVariableMap.contains( anIndex ) )
571         {
572           const NoteBoox_Variable& aVariable = myVariableMap[ anIndex ];
573           if( !aVariable.Name.isEmpty() && myStudy->IsVariableUsed( std::string( aVariable.Name.toLatin1().constData() ) ) )
574           {
575             if( QMessageBox::warning( parentWidget(), tr( "WARNING" ),
576                                       tr( "RENAME_VARIABLE_IS_USED" ).arg( aVariable.Name ),
577                                       QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
578             {
579               bool isBlocked = blockSignals( true );
580               aRow->SetName( aVariable.Name );
581               blockSignals( isBlocked );
582               return;
583             }
584           }
585         }
586       }
587
588       //Case then varible name changed. 
589       if(aCurrentColumn == NAME_COLUMN) {
590         if(!aRow->CheckName()) {
591           IsCorrect = false;
592           aMsg = tr( "VARNAME_INCORRECT" ).arg(aRow->GetName());
593         }
594         else if(!IsUniqueName(aRow)) {
595           IsCorrect = false;
596           aMsg = tr( "VARNAME_EXISTS" ).arg(aRow->GetName());
597         }
598         else
599           IsVariableComplited = aRow->CheckValue();
600       }
601       
602       //Case then varible value changed. 
603       else if(aCurrentColumn == VALUE_COLUMN){
604         if(!aRow->CheckValue()) {
605           IsCorrect = false;
606           aMsg = tr( "VARVALUE_INCORRECT" ).arg(aRow->GetName());
607         }
608         else
609           IsVariableComplited = aRow->CheckName() && IsUniqueName(aRow);
610       }
611
612       if(!IsCorrect && !aMsg.isEmpty())
613         SUIT_MessageBox::warning( parentWidget(), tr( "WARNING" ), aMsg );
614
615       bool isBlocked = blockSignals( true );
616       theItem->setForeground( QBrush( IsCorrect ? Qt::black : Qt::red ) );
617       blockSignals( isBlocked );
618
619       int anIndex = aRow->GetIndex();
620       if( myVariableMap.contains( anIndex ) )
621       {
622         NoteBoox_Variable& aVariable = myVariableMap[ anIndex ];
623         if( aVariable.Name.compare( aRow->GetName() ) != 0 ||
624             aVariable.Value.compare( aRow->GetValue() ) != 0 )
625         {
626           aVariable.Name = aRow->GetName();
627           aVariable.Value = aRow->GetValue();
628         }
629         else
630           isModified = false;
631       }
632
633       if(IsCorrect && IsVariableComplited && IsLastRow(aRow))
634         AddEmptyRow();
635     }
636
637     if( !myIsModified )
638       myIsModified = isModified;
639   }
640 }
641
642 //============================================================================
643 /*! Function : IsUniqueName
644  *  Purpose  : Return true if theName is unique name of the Variable
645  */
646 //============================================================================
647 bool NoteBook_Table::IsUniqueName(const NoteBook_TableRow* theRow) const
648 {
649   for(int i=0; i<myRows.size();i++) {
650     if(myRows[i] == theRow ) 
651       continue;
652     if(myRows[i]->GetName().compare(theRow->GetName()) == 0)
653       return false;
654   }
655   return true;
656 }
657
658 //============================================================================
659 /*! Function : RemoveSelected
660  *  Purpose  : Remove selected rows in the table
661  */
662 //============================================================================
663 void NoteBook_Table::RemoveSelected()
664 {
665   isProcessItemChangedSignal = false;
666   QList<QTableWidgetItem*> aSelectedItems = selectedItems();
667   if( !(aSelectedItems.size() > 0)) {
668     isProcessItemChangedSignal = true;
669     return;
670   }
671   bool removedFromStudy = false;
672   for(int i=0; i < aSelectedItems.size(); i++ ) {
673     NoteBook_TableRow* aRow = GetRowByItem(aSelectedItems[i]);
674     if(aRow) {
675       if(IsLastRow(aRow)) {
676         aRow->SetName(QString());
677         aRow->SetValue(QString());
678       }
679       else {
680         int nRow = row(aSelectedItems[i]);
681
682         if( myStudy->IsVariableUsed( std::string( aRow->GetName().toLatin1().constData() ) ) )
683         {
684           if( QMessageBox::warning( parentWidget(), tr( "WARNING" ),
685                                     tr( "REMOVE_VARIABLE_IS_USED" ).arg( aRow->GetName() ),
686                                     QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
687           {
688             isProcessItemChangedSignal = true;
689             return;
690           }
691         }
692
693         int index = aRow->GetIndex();
694         QString aVarName = aRow->GetName();
695         myRemovedRows.append( index );
696         if( myVariableMap.contains( index ) )
697           myVariableMap.remove( index );
698         removeRow(nRow);
699         myRows.removeAt(nRow);
700         if(myStudy->IsVariable(aVarName.toLatin1().constData()))
701           removedFromStudy = true;
702       }
703     }
704   }
705   if(removedFromStudy)
706     myIsModified = true;
707   RenamberRowItems();
708   isProcessItemChangedSignal = true;
709 }
710
711 //============================================================================
712 /*! Function : SetProcessItemChangedSignalFlag
713  *  Purpose  : 
714  */
715 //============================================================================
716 void NoteBook_Table::SetProcessItemChangedSignalFlag(const bool enable)
717 {
718   isProcessItemChangedSignal = enable;
719 }
720
721 //============================================================================
722 /*! Function : GetProcessItemChangedSignalFlag
723  *  Purpose  : 
724  */
725 //============================================================================
726 bool NoteBook_Table::GetProcessItemChangedSignalFlag() const
727 {
728   return isProcessItemChangedSignal;
729 }
730
731 //============================================================================
732 /*! Function : GetRows
733  *  Purpose  : 
734  */
735 //============================================================================
736 QList<NoteBook_TableRow*> NoteBook_Table::GetRows() const
737 {
738   return myRows;
739 }
740
741 //============================================================================
742 /*! Function : ResetMaps
743  *  Purpose  : Reset variable maps
744  */
745 //============================================================================
746 void NoteBook_Table::ResetMaps()
747 {
748   myIsModified = false;
749   myVariableMapRef = myVariableMap;
750   myRemovedRows.clear();
751 }
752
753 ///////////////////////////////////////////////////////////////////////////
754 //                  SalomeApp_NoteBookDlg class                          //
755 ///////////////////////////////////////////////////////////////////////////
756 //============================================================================
757 /*! Function : SalomeApp_NoteBookDlg
758  *  Purpose  : Constructor
759  */
760 //============================================================================
761 SalomeApp_NoteBookDlg::SalomeApp_NoteBookDlg(QWidget * parent, _PTR(Study) theStudy):
762   QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
763   myStudy(theStudy)
764 {
765   setModal(false);
766   setObjectName("SalomeApp_NoteBookDlg");
767   setWindowTitle(tr("NOTEBOOK_TITLE"));
768   QGridLayout* aLayout = new QGridLayout(this);
769   aLayout->setMargin(DEFAULT_MARGIN);
770   aLayout->setSpacing(DEFAULT_SPACING);
771
772   //Table
773   myTable = new NoteBook_Table(this);
774   aLayout->addWidget(myTable, 0, 0, 1, 3);
775   
776   //Buttons
777   myRemoveButton = new QPushButton(tr("BUT_REMOVE"));
778   aLayout->addWidget(myRemoveButton, 1, 0, 1, 1);
779
780   QSpacerItem* spacer =
781     new QSpacerItem(DEFAULT_SPACING, 5 , QSizePolicy::Expanding, QSizePolicy::Minimum);
782   aLayout->addItem(spacer, 1, 1, 2, 1);
783
784   myUpdateStudyBtn = new QPushButton(tr("BUT_UPDATE_STUDY"));
785   aLayout->addWidget(myUpdateStudyBtn, 1, 2, 1, 1);
786   
787   QGroupBox* groupBox = new QGroupBox(this);
788
789   QGridLayout* aLayout1 = new QGridLayout(groupBox);
790
791   aLayout1->setMargin(DEFAULT_MARGIN);
792   aLayout1->setSpacing(DEFAULT_SPACING);
793
794   myOkBtn = new QPushButton(tr("BUT_APPLY_AND_CLOSE"));
795   aLayout1->addWidget(myOkBtn, 0, 0, 1, 1);
796   
797   myApplyBtn = new QPushButton(tr("BUT_APPLY"));
798   aLayout1->addWidget(myApplyBtn, 0, 1, 1, 1);  
799
800   QSpacerItem* spacer1 =
801     new QSpacerItem(DEFAULT_SPACING, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);
802   aLayout1->addItem(spacer1, 0, 2, 1, 1);
803
804   myCancelBtn = new QPushButton(tr("BUT_CLOSE"));
805   aLayout1->addWidget(myCancelBtn, 0, 3, 1, 1);
806
807   myHelpBtn = new QPushButton(tr("BUT_HELP"));
808   aLayout1->addWidget(myHelpBtn, 0, 4, 1, 1);
809   
810   aLayout->addWidget(groupBox, 2, 0, 1, 3);
811
812   QWidgetList aWidgetList;
813   aWidgetList.append( myTable );
814   aWidgetList.append( myOkBtn );
815   aWidgetList.append( myApplyBtn );
816   aWidgetList.append( myCancelBtn );
817   aWidgetList.append( myHelpBtn );
818   aWidgetList.append( myUpdateStudyBtn );
819   aWidgetList.append( myRemoveButton );
820   Qtx::setTabOrder( aWidgetList );
821
822   connect( myOkBtn, SIGNAL(clicked()), this, SLOT(onOK()) );
823   connect( myApplyBtn, SIGNAL(clicked()), this, SLOT(onApply()) );
824   connect( myCancelBtn, SIGNAL(clicked()), this, SLOT(onCancel()) );
825   connect( myUpdateStudyBtn, SIGNAL(clicked()), this, SLOT(onUpdateStudy()) );
826   connect( myRemoveButton, SIGNAL(clicked()), this, SLOT(onRemove()));
827   connect( myHelpBtn, SIGNAL(clicked()), this, SLOT(onHelp()));
828   
829   myTable->Init(myStudy);
830 }
831
832 //============================================================================
833 /*! Function : ~SalomeApp_NoteBookDlg
834  *  Purpose  : Destructor
835  */
836 //============================================================================
837 SalomeApp_NoteBookDlg::~SalomeApp_NoteBookDlg(){}
838
839
840 //============================================================================
841 /*! Function : Init()
842  *  Purpose  : init variable table
843  */
844 //============================================================================
845 void SalomeApp_NoteBookDlg::Init(_PTR(Study) theStudy){
846   if(myStudy!= theStudy)
847     myStudy = theStudy;
848   myTable->Init(myStudy);
849 }
850
851
852 //============================================================================
853 /*! Function : onOK
854  *  Purpose  : [slot]
855  */
856 //============================================================================
857 void SalomeApp_NoteBookDlg::onOK()
858 {
859   onApply();
860   if( myTable->IsValid() )
861     accept();
862 }
863
864 //============================================================================
865 /*! Function : onHelp
866  *  Purpose  : [slot]
867  */
868 //============================================================================
869 void SalomeApp_NoteBookDlg::onHelp()
870 {
871   QString aHelpFileName("using_notebook.html");
872   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
873   if (app)
874     app->onHelpContextModule("GUI",aHelpFileName);
875   else {
876     QString platform;
877 #ifdef WIN32
878     platform = "winapplication";
879 #else
880     platform = "application";
881 #endif
882     SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
883                              tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
884                              arg(app->resourceMgr()->stringValue("ExternalBrowser",
885                                                                  platform)).
886                              arg(aHelpFileName));
887   }
888
889 }
890 //============================================================================
891 /*! Function : onApply
892  *  Purpose  : [slot]
893  */
894 //============================================================================
895 void SalomeApp_NoteBookDlg::onApply()
896 {
897   if( !myTable->IsValid() )
898   {
899     SUIT_MessageBox::warning( this, tr( "WARNING" ), tr( "INCORRECT_DATA" ) );
900     return;
901   }
902
903   double aDVal;
904   int    anIVal;
905   bool   aBVal;
906
907   const QList<int>& aRemovedRows = myTable->GetRemovedRows();
908   const VariableMap& aVariableMap = myTable->GetVariableMap();
909   const VariableMap& aVariableMapRef = myTable->GetVariableMapRef();
910
911   for( QListIterator<int> anIter( aRemovedRows ); anIter.hasNext(); )
912   {
913     int anIndex = anIter.next();
914     if( aVariableMapRef.contains( anIndex ) )
915     {
916       QString aRemovedVariable = aVariableMapRef[ anIndex ].Name;
917       myStudy->RemoveVariable( std::string( aRemovedVariable.toLatin1().constData() ) );
918     }
919   }
920
921   VariableMap::const_iterator it = aVariableMap.constBegin(), itEnd = aVariableMap.constEnd();
922   for( ; it != itEnd; ++it )
923   {
924     int anIndex = it.key();
925     const NoteBoox_Variable& aVariable = it.value();
926     QString aName = aVariable.Name;
927     QString aValue = aVariable.Value;
928
929     if( !aName.isEmpty() && !aValue.isEmpty() )
930     {
931       if( aVariableMapRef.contains( anIndex ) )
932       {
933         const NoteBoox_Variable& aVariableRef = aVariableMapRef[ anIndex ];
934         QString aNameRef = aVariableRef.Name;
935         QString aValueRef = aVariableRef.Value;
936
937         if( !aNameRef.isEmpty() && !aValueRef.isEmpty() && aNameRef != aName )
938         {
939           myStudy->RenameVariable( std::string( aNameRef.toLatin1().constData() ),
940                                    std::string( aName.toLatin1().constData() ) );
941         }
942       }
943
944       if( NoteBook_TableRow::IsIntegerValue(aValue,&anIVal) )
945         myStudy->SetInteger(std::string(aName.toLatin1().constData()),anIVal);
946
947       else if( NoteBook_TableRow::IsRealValue(aValue,&aDVal) )
948         myStudy->SetReal(std::string(aName.toLatin1().constData()),aDVal);
949     
950       else if( NoteBook_TableRow::IsBooleanValue(aValue,&aBVal) )
951         myStudy->SetBoolean(std::string(aName.toLatin1().constData()),aBVal);
952     
953       else
954         myStudy->SetString(std::string(aName.toLatin1().constData()),aValue.toStdString());
955     }
956   }
957   myTable->ResetMaps();
958
959   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
960   if(app)
961     app->updateActions();
962
963 }
964
965 //============================================================================
966 /*! Function : onCancel
967  *  Purpose  : [slot]
968  */
969 //============================================================================
970 void SalomeApp_NoteBookDlg::onCancel()
971 {
972   if( myTable->IsModified() )
973   {
974     int answer = QMessageBox::question( this, tr( "CLOSE_CAPTION" ), tr( "CLOSE_DESCRIPTION" ),
975                                         QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel );
976     switch( answer )
977     {
978       case QMessageBox::Yes    : onOK(); return;
979       case QMessageBox::No     : break;
980       case QMessageBox::Cancel : return;
981       default : break;
982     }
983   }
984   reject();
985 }
986
987 //============================================================================
988 /*! Function : onRemove
989  *  Purpose  : [slot]
990  */
991 //============================================================================
992 void SalomeApp_NoteBookDlg::onRemove()
993 {
994   myTable->RemoveSelected();
995 }
996
997 //============================================================================
998 /*! Function : onUpdateStudy
999  *  Purpose  : [slot]
1000  */
1001 //============================================================================
1002 void SalomeApp_NoteBookDlg::onUpdateStudy()
1003 {
1004   onApply();
1005   if( !myTable->IsValid() )
1006     return;
1007
1008   QApplication::setOverrideCursor( Qt::WaitCursor );
1009
1010   if( !updateStudy() )
1011     SUIT_MessageBox::warning( this, tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1012     
1013   QApplication::restoreOverrideCursor();
1014 }
1015
1016 //============================================================================
1017 /*! Function : updateStudy
1018  *  Purpose  : 
1019  */
1020 //============================================================================
1021 bool SalomeApp_NoteBookDlg::updateStudy()
1022 {
1023   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1024   if( !app )
1025     return false;
1026
1027   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
1028   if( !study )
1029     return false;
1030
1031   bool isStudySaved = study->isSaved();
1032   QString aStudyName = study->studyName();
1033
1034   _PTR(Study) studyDS = study->studyDS();
1035
1036   // get unique temporary directory name
1037   QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1038   if( aTmpDir.isEmpty() )
1039     return false;
1040
1041   if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1042     aTmpDir.remove( aTmpDir.length() - 1, 1 );
1043
1044   // dump study to the temporary directory
1045   QString aFileName( "notebook" );
1046   bool toPublish = true;
1047   bool isMultiFile = false;
1048   bool toSaveGUI = true;
1049
1050   int savePoint;
1051   _PTR(AttributeParameter) ap;
1052   _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1053   if(ip->isDumpPython(studyDS)) ip->setDumpPython(studyDS); //Unset DumpPython flag.
1054   if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1055     ip->setDumpPython(studyDS);
1056     savePoint = SalomeApp_VisualState( app ).storeState(); //SRN: create a temporary save point
1057   }
1058   bool ok = studyDS->DumpStudy( aTmpDir.toStdString(), aFileName.toStdString(), toPublish, isMultiFile );
1059   if ( toSaveGUI )
1060     study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1061
1062   if( !ok )
1063     return false;
1064
1065   // clear a study (delete all objects)
1066   clearStudy();
1067
1068   // get active application
1069   app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1070
1071   // load study from the temporary directory
1072   QString command = QString( "execfile(r\"%1\")" ).arg( aTmpDir + QDir::separator() + aFileName + ".py" );
1073
1074   PyConsole_Console* pyConsole = app->pythonConsole();
1075   if ( pyConsole )
1076     pyConsole->execAndWait( command );
1077
1078   // remove temporary directory
1079   QDir aDir( aTmpDir );
1080   QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
1081   for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
1082     ok = aDir.remove( *it ) && ok;
1083   if( ok )
1084     ok = aDir.rmdir( aTmpDir );
1085
1086   if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
1087   {
1088     myStudy = newStudy->studyDS();
1089     myTable->Init(myStudy);
1090     if(isStudySaved) {
1091       newStudy->markAsSavedIn(aStudyName);
1092     }
1093   }
1094   else
1095     ok = false;
1096
1097   return ok;
1098 }
1099
1100 //============================================================================
1101 /*! Function : clearStudy
1102  *  Purpose  : 
1103  */
1104 //============================================================================
1105 void SalomeApp_NoteBookDlg::clearStudy()
1106 {
1107   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1108   if( !app )
1109     return;
1110
1111   QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1112   int anIndex = aList.indexOf( app );
1113
1114   //Store position and size of the this dialog
1115   int aW = width();
1116   int aH = height();
1117   int aX = x();
1118   int aY = y();
1119
1120   // Disconnect dialog from application desktop in case if:
1121   // 1) Application is not the first application in the session 
1122   // 2) Application is the first application in session but not the only.
1123   bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1124
1125   if( changeDesktop )
1126     setParent( 0 );
1127
1128   app->onCloseDoc( false );
1129   
1130   if( anIndex > 0 && anIndex < aList.count() )
1131     app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1132   else if(anIndex == 0 && aList.count() > 1)
1133     app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1134
1135   if( !app )
1136     return;
1137
1138   app->onNewDoc();
1139
1140   app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1141   if( changeDesktop && app ) {
1142     setParent( app->desktop(), Qt::Dialog );
1143     app->setNoteBook(this);
1144   }
1145   //Set position and size of the this dialog
1146   resize( aW, aH );
1147   move( aX, aY );
1148   show();
1149 }