Salome HOME
f8f129ebd58cadb04b1da7d5f7ef6796baff63af
[modules/geom.git] / src / EntityGUI / EntityGUI_FieldDlg.cxx
1 // Copyright (C) 2007-2013  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.
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 //  File   : EntityGUI_FieldDlg.cxx
23
24 #include "EntityGUI_FieldDlg.h"
25
26 #include <DlgRef.h>
27 #include <GEOMBase.h>
28 #include <GEOMBase_Skeleton.h>
29 #include <GEOM_Displayer.h>
30 #include <GeometryGUI.h>
31
32 #include <SalomeApp_Application.h>
33 #include <SalomeApp_Study.h>
34 #include <SalomeApp_Tools.h>
35 #include <SalomeApp_IntSpinBox.h>
36 #include <SalomeApp_DoubleSpinBox.h>
37
38 #include <LightApp_SelectionMgr.h>
39
40 #include <OCCViewer_ViewModel.h>
41 #include <OCCViewer_ViewManager.h>
42 #include <SVTK_ViewModel.h>
43 #include <SALOME_Prs.h>
44 #include <SALOME_ListIteratorOfListIO.hxx>
45
46 #include <SUIT_Desktop.h>
47 #include <SUIT_MessageBox.h>
48 #include <SUIT_OverrideCursor.h>
49 #include <SUIT_ResourceMgr.h>
50 #include <SUIT_Session.h>
51 #include <SUIT_ViewWindow.h>
52 #include <SUIT_ViewManager.h>
53
54 #include <QComboBox>
55 #include <QGridLayout>
56 #include <QGroupBox>
57 #include <QHeaderView>
58 #include <QInputDialog>
59 #include <QLabel>
60 #include <QLineEdit>
61 #include <QPushButton>
62 #include <QTableWidget>
63 #include <QVBoxLayout>
64
65 #include <AIS_ListOfInteractive.hxx>
66 #include <AIS_ListIteratorOfListOfInteractive.hxx>
67
68 #include <TopExp.hxx>
69 #include <TopExp_Explorer.hxx>
70 #include <TopTools_IndexedMapOfShape.hxx>
71 #include <TColStd_IndexedMapOfInteger.hxx>
72 #include <TColStd_MapOfInteger.hxx>
73 #include <TColStd_DataMapIteratorOfDataMapOfIntegerInteger.hxx>
74
75 #include <limits>
76
77 #include <SALOMEDS_wrap.hxx>
78 #include <GEOMImpl_Types.hxx>
79
80 #ifdef max
81   #undef max
82 #endif
83
84
85 const int theIntLimit = std::numeric_limits<int>::max() - 10;
86
87 /*
88   Class       : EntityGUI_FieldDlg::CheckItem
89   Description : Bool item.
90 */
91 class EntityGUI_FieldDlg::CheckItem : public QTableWidgetItem
92 {
93 public:
94   static int     Type();
95
96   CheckItem( bool = false );
97   ~CheckItem();
98
99   void  setValue( bool );
100   bool  value() const;
101 };
102
103 int EntityGUI_FieldDlg::CheckItem::Type()
104 {
105   return QTableWidgetItem::UserType + 2;
106 }
107
108 EntityGUI_FieldDlg::CheckItem::CheckItem( bool value )
109  : QTableWidgetItem( Type() )
110 {
111   Qt::ItemFlags f = flags();
112   f = f | Qt::ItemIsUserCheckable;
113   f = f & ~Qt::ItemIsTristate;
114   f = f & ~Qt::ItemIsEditable;
115   setFlags( f );
116   setValue(value);
117 }
118
119 EntityGUI_FieldDlg::CheckItem::~CheckItem()
120 {
121 }
122
123 void EntityGUI_FieldDlg::CheckItem::setValue( bool value )
124 {
125   setCheckState( value ? Qt::Checked : Qt::Unchecked );
126 }
127
128 bool EntityGUI_FieldDlg::CheckItem::value() const
129 {
130   return checkState() == Qt::Checked;
131 }
132
133 /*
134   Class       : EntityGUI_FieldDlg::IntSpinItem
135   Description : Integer spin table item.
136 */
137
138 class EntityGUI_FieldDlg::IntSpinItem : public QTableWidgetItem
139 {
140 public:
141   static int     Type();
142
143   IntSpinItem( const int theValue );
144
145   int            value() const;
146   void           setValue( const int theValue );
147
148   void           clear();
149 };
150
151 int EntityGUI_FieldDlg::IntSpinItem::Type()
152 {
153   return QTableWidgetItem::UserType + 3;
154 }
155
156 EntityGUI_FieldDlg::IntSpinItem::IntSpinItem( const int theValue )
157  : QTableWidgetItem( Type() )
158 {
159   setValue( theValue );
160 }
161
162 int EntityGUI_FieldDlg::IntSpinItem::value() const
163 {
164   bool ok = false;
165   int value = data( Qt::UserRole ).toInt( &ok );
166   return ok ? value : 0; 
167 }
168
169 void EntityGUI_FieldDlg::IntSpinItem::setValue( const int theValue )
170 {
171   setData( Qt::UserRole, theValue );
172   setText( QString::number( theValue ) ); 
173 }
174
175 void EntityGUI_FieldDlg::IntSpinItem::clear()
176 {
177   setText( "" );
178 }
179
180 /*
181   Class       : EntityGUI_FieldDlg::DoubleSpinItem
182   Description : Double spin table item.
183 */
184
185 class EntityGUI_FieldDlg::DoubleSpinItem : public QTableWidgetItem
186 {
187 public:
188   static int     Type();
189
190   DoubleSpinItem( const double theValue, const int thePrecision=6 );
191
192   double         value() const;
193   void           setValue( const double theValue );
194
195   int            precision() const;
196   void           setPrecision( const int thePrecision );
197
198   void           clear();
199 };
200
201 int EntityGUI_FieldDlg::DoubleSpinItem::Type()
202 {
203   return QTableWidgetItem::UserType + 4;
204 }
205
206 EntityGUI_FieldDlg::DoubleSpinItem::DoubleSpinItem( const double theValue,
207                                                     const int    thePrecision)
208  : QTableWidgetItem( Type() )
209 {
210   setValue( theValue );
211   setPrecision( thePrecision );
212 }
213
214 double EntityGUI_FieldDlg::DoubleSpinItem::value() const
215 {
216   bool ok = false;
217   double value = data( Qt::UserRole ).toDouble( &ok );
218   return ok ? value : 0; 
219 }
220
221 void EntityGUI_FieldDlg::DoubleSpinItem::setValue( const double theValue )
222 {
223   setData( Qt::UserRole, theValue );
224   setText( QString::number( theValue ) ); 
225 }
226
227 int EntityGUI_FieldDlg::DoubleSpinItem::precision() const
228 {
229   bool ok = false;
230   int precision = data( Qt::UserRole + 1 ).toInt( &ok );
231   return ok ? precision : 0; 
232 }
233
234 void EntityGUI_FieldDlg::DoubleSpinItem::setPrecision( const int thePrecision )
235 {
236   setData( Qt::UserRole + 1, thePrecision );
237 }
238
239 void EntityGUI_FieldDlg::DoubleSpinItem::clear()
240 {
241   setText( "" );
242 }
243
244 /*
245   Class       : EntityGUI_FieldDlg::ComboDelegate
246   Description : Table used by this widget
247 */
248
249 class EntityGUI_FieldDlg::Delegate : public QItemDelegate
250 {
251 public:
252   Delegate( QObject* = 0 );
253   ~Delegate();
254   
255   QWidget*      createEditor( QWidget*, const QStyleOptionViewItem&,
256                               const QModelIndex& ) const;
257   
258   void          setEditorData( QWidget*, const QModelIndex& ) const;
259   void          setModelData( QWidget*, QAbstractItemModel*, const QModelIndex& ) const;
260   
261   void          updateEditorGeometry( QWidget*, const QStyleOptionViewItem&, 
262                                       const QModelIndex& ) const;
263 private:
264   StepTable* myTable;
265 };
266
267 EntityGUI_FieldDlg::Delegate::Delegate( QObject* parent )
268   : QItemDelegate( parent ), 
269     myTable( dynamic_cast<EntityGUI_FieldDlg::StepTable*>( parent ) )
270 {
271 }
272   
273 EntityGUI_FieldDlg::Delegate::~Delegate()
274 {
275 }
276
277 QWidget* EntityGUI_FieldDlg::Delegate::createEditor( QWidget* parent,
278                                                      const QStyleOptionViewItem& option,
279                                                      const QModelIndex& index ) const
280 {
281   QVariant aData = index.data( Qt::UserRole );
282   QVariant::Type aDataType = aData.type();
283   if( aDataType == QVariant::Int ) {
284     bool ok = false;
285     int aValue = aData.toInt( &ok );
286     if ( ok ) {
287       SalomeApp_IntSpinBox* intSpin = new SalomeApp_IntSpinBox( -theIntLimit, theIntLimit, 1, parent, false, true );
288       intSpin->setFrame( false );
289       intSpin->setValue( aValue );
290       return intSpin;
291     }
292   }
293   else if( aDataType == QVariant::Double ) {
294     bool ok = false;
295     double aValue = aData.toDouble( &ok );
296     if ( ok ) {
297       int aPrecision = index.data( Qt::UserRole + 1 ).toInt( &ok );
298       if ( !ok )
299         aPrecision = 0;
300
301       SalomeApp_DoubleSpinBox* dblSpin = new SalomeApp_DoubleSpinBox( -1.e20, 1.e20, 1, aPrecision, 20, parent, false, true );
302       dblSpin->setFrame( false );
303       dblSpin->setValue( aValue );
304       return dblSpin;
305     }
306   }
307   return QItemDelegate::createEditor( parent, option, index );
308 }
309
310 void EntityGUI_FieldDlg::Delegate::setEditorData( QWidget* editor, 
311                                                   const QModelIndex& index ) const
312 {
313   QVariant data = index.model()->data( index, Qt::DisplayRole );
314   QString value = data.toString();
315   bool bOk = false;
316   if ( SalomeApp_DoubleSpinBox* dblSpin = dynamic_cast<SalomeApp_DoubleSpinBox*>( editor ) ) {
317     if( data.type() == QVariant::Double ) {
318       double valueDouble = data.toDouble( &bOk );
319       if( bOk )
320         dblSpin->setValue( valueDouble );
321     }
322   }
323   if ( !bOk ) QItemDelegate::setEditorData( editor, index );
324 }
325
326 void EntityGUI_FieldDlg::Delegate::setModelData( QWidget* editor,
327                                                  QAbstractItemModel* model,
328                                                  const QModelIndex& index) const
329 {
330   QString oldData = myTable->text( index.row(), index.column() );
331
332   if( SalomeApp_IntSpinBox* intSpin = dynamic_cast<SalomeApp_IntSpinBox*>( editor ) )
333     model->setData( index, intSpin->value(), Qt::DisplayRole );
334   else if( SalomeApp_DoubleSpinBox* dblSpin = dynamic_cast<SalomeApp_DoubleSpinBox*>( editor ) )
335     model->setData( index, dblSpin->value(), Qt::DisplayRole );
336   else
337     QItemDelegate::setModelData( editor, model, index );
338
339   QString newData = myTable->text( index.row(), index.column() );
340   if ( newData != oldData )
341     myTable->setIsChanged();
342 }
343
344 void EntityGUI_FieldDlg::Delegate::updateEditorGeometry( QWidget* editor,
345                                                          const QStyleOptionViewItem& option, 
346                                                          const QModelIndex& index ) const
347 {
348   editor->setGeometry( option.rect );
349 }
350
351 //=======================================================================
352 // name    : EntityGUI_FieldDlg::StepTable::Table
353 // Purpose : Constructor
354 //=======================================================================
355 EntityGUI_FieldDlg::StepTable::StepTable (int stepID, int dataType,
356                                           int nbRows, int nbComps,
357                                           QString shapeName, QStringList headers,
358                                           GEOM::GEOM_FieldStep_ptr stepVar,
359                                           QWidget* parent)
360   : QTableWidget(0, nbComps+1, parent),
361     myDataType( dataType ),
362     myStepID( stepID ),
363     myStamp( 0 ),
364     myStep( GEOM::GEOM_FieldStep::_duplicate( stepVar )),
365     myIsChanged( false )
366 {
367   setDim( nbRows, shapeName, stepVar->_is_nil() );
368
369   setHorizontalHeaderLabels( headers );
370   verticalHeader()->hide();
371
372   // set custom item delegate
373   setItemDelegate( new Delegate(this) );
374   // set edit triggers by default
375   setReadOnly( false );
376
377   if ( stepVar->_is_nil() )
378   {
379     connect( horizontalHeader(), SIGNAL( sectionDoubleClicked( int ) ), this, SLOT( headerDblClicked( int ) ) );
380
381     return;
382   }
383   myStamp = stepVar->GetStamp();
384
385   const int nbColumns = nbComps + 1;
386
387   switch ( dataType )
388   {
389   case 0:
390   {
391     GEOM::GEOM_BoolFieldStep_var bs = GEOM::GEOM_BoolFieldStep::_narrow( stepVar );
392     if ( !bs->_is_nil() )
393     {
394       GEOM::short_array_var vals = bs->GetValues();
395       if ( vals->length() == nbRows * nbComps )
396         for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
397           for ( int iC = 1; iC < nbColumns; ++iC )
398             setItem( iR, iC, new CheckItem( vals[ iV++ ]));
399     }
400     connect( this, SIGNAL( itemClicked(QTableWidgetItem *)), this, SLOT( setIsChanged() ));
401     break;
402   }
403   case 1:
404   {
405     GEOM::GEOM_IntFieldStep_var is = GEOM::GEOM_IntFieldStep::_narrow( stepVar );
406     if ( !is->_is_nil() )
407     {
408       GEOM::ListOfLong_var vals = is->GetValues();
409       if ( vals->length() == nbRows * nbComps )
410         for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
411           for ( int iC = 1; iC < nbColumns; ++iC )
412             setItem( iR, iC, new IntSpinItem( vals[ iV++ ]));
413     }
414     break;
415   }
416   case 2:
417   {
418     GEOM::GEOM_DoubleFieldStep_var ds = GEOM::GEOM_DoubleFieldStep::_narrow( stepVar );
419     if ( !ds->_is_nil() )
420     {
421       GEOM::ListOfDouble_var vals = ds->GetValues();
422       if ( vals->length() == nbRows * nbComps )
423         for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
424           for ( int iC = 1; iC < nbColumns; ++iC )
425             setItem( iR, iC, new DoubleSpinItem( vals[ iV++ ]));
426     }
427     break;
428   }
429   default:
430     GEOM::GEOM_StringFieldStep_var ss = GEOM::GEOM_StringFieldStep::_narrow( stepVar );
431     if ( !ss->_is_nil() )
432     {
433       GEOM::string_array_var vals = ss->GetValues();
434       if ( vals->length() == nbRows * nbComps )
435         for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
436           for ( int iC = 1; iC < nbColumns; ++iC )
437             setItem( iR, iC, new QTableWidgetItem( vals[ iV++ ].in() ));
438     }
439     break;
440   }
441 }
442
443 //=======================================================================
444 // name    : EntityGUI_FieldDlg::StepTable::~StepTable
445 // Purpose : Destructor
446 //=======================================================================
447 EntityGUI_FieldDlg::StepTable::~StepTable()
448 {
449 }
450
451 //=======================================================================
452 // name    : EntityGUI_FieldDlg::StepTable::minimumSizeHint
453 // Purpose : Get minimum size for the table
454 //=======================================================================
455 QSize EntityGUI_FieldDlg::StepTable::minimumSizeHint() const
456 {
457   QSize s = QTableWidget::minimumSizeHint();
458   QHeaderView* hv = horizontalHeader();
459   if ( hv )
460     s.setWidth( qMax( s.width(), hv->length() ) );
461   return s;
462 }
463
464 //=======================================================================
465 // name    : EntityGUI_FieldDlg::StepTable::setEditable
466 // Purpose : Set editable of specified cell
467 //=======================================================================
468 void EntityGUI_FieldDlg::StepTable::setEditable (bool isEditable,
469                                                  int row, int col)
470 {
471   QTableWidgetItem* anItem = item( row, col );
472   if ( anItem ) {
473     bool isSignalsBlocked = signalsBlocked();
474     blockSignals( true );
475
476     Qt::ItemFlags f = anItem->flags();
477     if ( !isEditable ) f = f & ~Qt::ItemIsEditable;
478     else f = f | Qt::ItemIsEditable;
479     anItem->setFlags( f );
480     
481     blockSignals( isSignalsBlocked );
482   }
483 }
484
485 //=======================================================================
486 // name    : EntityGUI_FieldDlg::StepTable::isEditable
487 // Purpose : Verify wheter cell is editable
488 //=======================================================================
489 bool EntityGUI_FieldDlg::StepTable::isEditable (int row, int col) const
490 {
491   QTableWidgetItem* anItem = item( row, col );
492   return anItem == 0 || anItem->flags() & Qt::ItemIsEditable;
493 }
494
495 void EntityGUI_FieldDlg::StepTable::setReadOnly( bool on )
496 {
497   setEditTriggers( on ? 
498                    QAbstractItemView::NoEditTriggers  :
499                    QAbstractItemView::AllEditTriggers );
500 }
501
502 bool EntityGUI_FieldDlg::StepTable::isReadOnly() const
503 {
504   return editTriggers() == QAbstractItemView::NoEditTriggers;
505 }
506
507 //=======================================================================
508 // name    : EntityGUI_FieldDlg::StepTable::insertRows
509 // Purpose : Insert rows (virtual redefined)
510 //=======================================================================
511 void EntityGUI_FieldDlg::StepTable::insertRows (int row, int count)
512 {
513   while ( count-- ) insertRow( row );
514 }
515
516 //=======================================================================
517 // name    : EntityGUI_FieldDlg::StepTable::text
518 // Purpose : Get text from cell (virtual redefined)
519 //=======================================================================
520 QString EntityGUI_FieldDlg::StepTable::text (int row, int col)
521 {
522   closePersistentEditor( currentItem() );
523   QTableWidgetItem* anItem = item( row, col );
524   return anItem ? anItem->text() : QString();
525 }
526
527 QList<int> EntityGUI_FieldDlg::StepTable::selectedRows()
528 {
529   QList<QTableWidgetItem*> selItems = selectedItems();
530   QTableWidgetItem* anItem;
531   QList<int> rows;
532
533   foreach( anItem, selItems ) {
534     int r = row( anItem );
535     if ( !rows.contains( r ) ) rows.append( r );
536   }
537
538   qSort( rows );
539   return rows;
540 }
541
542 //=======================================================================
543 //function : selectRows
544 //purpose  : 
545 //=======================================================================
546
547 void EntityGUI_FieldDlg::StepTable::selectRows(const QList<int>& rows)
548 {
549   closePersistentEditor( currentItem() );
550
551   QList<QTableWidgetSelectionRange> ranges = selectedRanges();
552   for ( int i = 0; i < ranges.count(); ++i )
553     setRangeSelected( ranges[i], false );
554
555   QList<int>::const_iterator row = rows.begin();
556   for ( ; row != rows.end(); ++row )
557     // QTableWidgetSelectionRange ( int top, int left, int bottom, int right )
558     setRangeSelected ( QTableWidgetSelectionRange(*row,0,*row,0), true );
559 }
560
561 //=======================================================================
562 //function : setDim
563 //purpose  : change nb rows in the table
564 //=======================================================================
565
566 void EntityGUI_FieldDlg::StepTable::setDim( int nbRows, QString shapeName, bool setDefault )
567 {
568   closePersistentEditor( currentItem() );
569   int curNbRows = rowCount();
570   if ( nbRows < curNbRows )
571   {
572     while ( nbRows < curNbRows )
573       removeRow( --curNbRows );
574   }
575   else if ( nbRows > curNbRows )
576   {
577     int nbColumns = columnCount();
578     for ( ; nbRows > curNbRows; ++curNbRows )
579     {
580       insertRow( curNbRows );
581       if ( setDefault )
582         for ( int iC = 1; iC < nbColumns; ++iC )
583           setItem( curNbRows, iC, newDefaultItem() );
584     }
585   }
586
587   int indexWidth = 1, maxNbR = 10;
588   while ( nbRows >= maxNbR )
589     ++indexWidth, maxNbR *= 10;
590   shapeName = shapeName.toLower() + "_%1";
591   for ( int iR = 0; iR < nbRows; ++iR )
592   {
593     setItem( iR, 0, new QTableWidgetItem( shapeName.arg( iR+1, indexWidth, 10, QChar('0') )));
594     setEditable( false, iR, 0 );
595   }
596 }
597
598 //=======================================================================
599 //function : setNbComps
600 //purpose  : 
601 //=======================================================================
602
603 void EntityGUI_FieldDlg::StepTable::setNbComps( int nbComps )
604 {
605   closePersistentEditor( currentItem() );
606   nbComps++; // add sub-shape column
607   int curNbCols = columnCount();
608   if ( nbComps < curNbCols )
609   {
610     while ( nbComps < curNbCols )
611       removeColumn( --curNbCols );
612   }
613   else if ( nbComps > curNbCols )
614   {
615     int nbRows = rowCount();
616     for ( ; nbComps > curNbCols; ++curNbCols )
617     {
618       insertColumn( curNbCols );
619       setHorizontalHeaderItem( curNbCols,
620                                new QTableWidgetItem(QString("Comp %1").arg( curNbCols )));
621       for ( int iR = 0; iR < nbRows; ++iR )
622         setItem( iR, curNbCols, newDefaultItem() );
623     }
624   }
625 }
626
627 //=======================================================================
628 //function : setDataType
629 //purpose  : change type of data
630 //=======================================================================
631
632 void EntityGUI_FieldDlg::StepTable::setDataType( int dataType )
633 {
634   myDataType = dataType;
635
636   int nbRows = rowCount();
637   int nbColumns = columnCount();
638
639   for ( int iR = 0; iR < nbRows; ++iR )
640     for ( int iC = 1; iC < nbColumns; ++iC )
641       setItem( iR, iC, newDefaultItem() );
642 }
643
644 //=======================================================================
645 //function : newDefaultItem
646 //purpose  : creates a table item with a default value
647 //=======================================================================
648
649 QTableWidgetItem * EntityGUI_FieldDlg::StepTable::newDefaultItem()
650 {
651   switch( myDataType ) {
652   case 0: return new CheckItem(false);
653   case 1: return new IntSpinItem(0);
654   case 2: return new DoubleSpinItem(0);
655   default:;
656   }
657   return new QTableWidgetItem(""); // string
658 }
659
660 //=======================================================================
661 //function : getHeaders
662 //purpose  : 
663 //=======================================================================
664
665 QStringList EntityGUI_FieldDlg::StepTable::getHeaders()
666 {
667   QStringList headers;
668   int nbColumns = columnCount();
669   for ( int iC = 0; iC < nbColumns; ++iC )
670     headers << horizontalHeaderItem( iC )->text();
671   return headers;
672 }
673
674 //=======================================================================
675 //function : setHeaders
676 //purpose  : 
677 //=======================================================================
678
679 void EntityGUI_FieldDlg::StepTable::setHeaders(const QStringList& headers)
680 {
681   setHorizontalHeaderLabels( headers );
682 }
683
684 //=======================================================================
685 //function : setValues
686 //purpose  : store values from this table to a field step
687 //=======================================================================
688
689 void EntityGUI_FieldDlg::StepTable::setValues(GEOM::GEOM_FieldStep_var& step)
690 {
691   closePersistentEditor( currentItem() );
692
693   if ( step->GetStamp() != myStamp )
694     step->SetStamp( myStamp );
695
696   if ( step->_is_equivalent( myStep ) && !myIsChanged )
697     return;
698
699   const int nbColumns = columnCount();
700   const int nbComps = nbColumns - 1;
701   const int nbRows = rowCount();
702
703   switch ( myDataType ) {
704   case 0:
705   {
706     GEOM::GEOM_BoolFieldStep_var bs = GEOM::GEOM_BoolFieldStep::_narrow( step );
707     if ( !bs->_is_nil() )
708     {
709       GEOM::short_array_var vals = new GEOM::short_array();
710       vals->length( nbRows * nbComps );
711       for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
712         for ( int iC = 1; iC < nbColumns; ++iC )
713           vals[ iV++ ] = ((CheckItem*)item( iR, iC ))->value();
714       bs->SetValues( vals );
715     }
716     break;
717   }
718   case 1:
719   {
720     GEOM::GEOM_IntFieldStep_var is = GEOM::GEOM_IntFieldStep::_narrow( step );
721     if ( !is->_is_nil() )
722     {
723       GEOM::ListOfLong_var vals = new GEOM::ListOfLong();
724       vals->length( nbRows * nbComps );
725       for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
726         for ( int iC = 1; iC < nbColumns; ++iC )
727           vals[ iV++ ] = text( iR, iC ).toInt();
728       is->SetValues( vals );
729     }
730     break;
731   }
732   case 2:
733   {
734     GEOM::GEOM_DoubleFieldStep_var ds = GEOM::GEOM_DoubleFieldStep::_narrow( step );
735     if ( !ds->_is_nil() )
736     {
737       GEOM::ListOfDouble_var vals = new GEOM::ListOfDouble();
738       vals->length( nbRows * nbComps );
739       for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
740         for ( int iC = 1; iC < nbColumns; ++iC )
741           vals[ iV++ ] = text( iR, iC ).toDouble();
742       ds->SetValues( vals );
743     }
744     break;
745   }
746   default:
747
748     GEOM::GEOM_StringFieldStep_var ss = GEOM::GEOM_StringFieldStep::_narrow( step );
749     if ( !ss->_is_nil() )
750     {
751       GEOM::string_array_var vals = new GEOM::string_array();
752       vals->length( nbRows * nbComps );
753       for ( int iV = 0, iR = 0; iR < nbRows; ++iR )
754         for ( int iC = 1; iC < nbColumns; ++iC )
755           vals[ iV++ ] = item( iR, iC )->text().toLatin1().constData();
756       ss->SetValues( vals );
757     }
758   }
759
760   myIsChanged = false;
761
762   return;
763 }
764
765 //=======================================================================
766 //function : headerDblClicked
767 //purpose  : rename column, called when used double-clicks on the header
768 //=======================================================================
769
770 void EntityGUI_FieldDlg::StepTable::headerDblClicked( int section )
771 {
772   if ( section > 0 ) {
773     bool bOk;
774     QString label = QInputDialog::getText( this, EntityGUI_FieldDlg::tr( "RENAME_COMPONENT" ),
775                                            EntityGUI_FieldDlg::tr ( "COMPONENT_NAME" ), QLineEdit::Normal,
776                                            horizontalHeaderItem( section )->text(), &bOk );
777     if ( bOk && !label.isEmpty() )
778       horizontalHeaderItem( section )->setText( label );
779   }
780 }
781
782 //=======================================================================
783 //function : EntityGUI_FieldDlg
784 //purpose  : 
785 //=======================================================================
786
787 EntityGUI_FieldDlg::EntityGUI_FieldDlg (GeometryGUI* theGeometryGUI,
788                                         GEOM::GEOM_Field_ptr theField, int stepID,
789                                         QWidget* parent,
790                                         bool modal, Qt::WindowFlags fl)
791   : GEOMBase_Skeleton(theGeometryGUI, parent, modal, fl),
792     myIsCreation( CORBA::is_nil( theField )),
793     myField( GEOM::GEOM_Field::_duplicate( theField )),
794     myCurStepID( stepID ),
795     myCurStepTable( NULL ),
796     myIsHiddenMain( false )
797 {
798   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
799   QPixmap iconSelect (resMgr->loadPixmap("GEOM", tr("ICON_SELECT")));
800
801   setWindowTitle(myIsCreation ? tr("CREATE_FIELD_TITLE") : tr("EDIT_FIELD_TITLE"));
802
803   // Shape type button group
804   mainFrame()->GroupConstructors->hide();
805
806   // Field name
807   mainFrame()->GroupBoxName->setTitle(tr("FIELD_NAME"));
808
809   // Field properties
810
811   QGroupBox* propGroup = new QGroupBox(tr("PROPERTIES"), centralWidget());
812   QGridLayout* propLayout = new QGridLayout(propGroup);
813   propLayout->setMargin(9);
814   propLayout->setSpacing(6);
815
816   // shape
817   QLabel* shapeLabel = new QLabel(tr("SHAPE"), propGroup);
818   myShapeSelBtn = new QPushButton(propGroup);
819   myShapeSelBtn->setIcon(iconSelect);
820   myShapeSelBtn->setEnabled( myIsCreation );
821   myShapeName = new QLineEdit(propGroup);
822   myShapeName->setReadOnly(true);
823   myShapeName->setEnabled( myIsCreation );
824
825   // data type
826   QLabel* typeLabel = new QLabel( tr("DATA_TYPE"), propGroup );
827   myTypeCombo = new QComboBox( propGroup );
828   myTypeCombo->insertItem( GEOM::FDT_Bool,   tr("BOOL"));
829   myTypeCombo->insertItem( GEOM::FDT_Int,    tr("INT"));
830   myTypeCombo->insertItem( GEOM::FDT_Double, tr("DOUBLE"));
831   myTypeCombo->insertItem( GEOM::FDT_String, tr("STRING"));
832   myTypeCombo->setCurrentIndex( GEOM::FDT_Double ); // double
833
834   // dimension
835   QLabel* dimLabel = new QLabel( tr("SHAPE_TYPE"), propGroup );
836   myDimCombo = new QComboBox( propGroup );
837
838   // nb components
839   QLabel* nbCompsLabel = new QLabel( tr("NB_COMPS"), propGroup );
840   myNbCompsSpin = new SalomeApp_IntSpinBox( 1, 1000, 1, propGroup, true, true );
841   myNbCompsSpin->setValue( 1 );
842   propLayout->addWidget(shapeLabel,         0, 0);
843   propLayout->addWidget(myShapeSelBtn,      0, 1);
844   propLayout->addWidget(myShapeName,        0, 2);
845   propLayout->addWidget(typeLabel,          1, 0, 1, 2);
846   propLayout->addWidget(myTypeCombo,        1, 2);
847   propLayout->addWidget(dimLabel,           2, 0, 1, 2);
848   propLayout->addWidget(myDimCombo,         2, 2);
849   propLayout->addWidget(nbCompsLabel,       3, 0, 1, 2);
850   propLayout->addWidget(myNbCompsSpin,      3, 2);
851   // propLayout->addWidget(shapeLabel,         0, 0);
852   // propLayout->addWidget(myShapeName,        0, 1);
853   // propLayout->addWidget(typeLabel,          1, 0);
854   // propLayout->addWidget(myTypeCombo,        1, 1);
855   // propLayout->addWidget(dimLabel,           2, 0);
856   // propLayout->addWidget(myDimCombo,         2, 1);
857   // propLayout->addWidget(nbCompsLabel,       3, 0);
858   // propLayout->addWidget(myNbCompsSpin,      3, 1);
859
860   propLayout->setColumnStretch(2, 5);
861
862   // Field values
863
864   QGroupBox* valsGroup = new QGroupBox(tr("VALUES"), centralWidget());
865   QGridLayout* valsLayout = new QGridLayout(valsGroup);
866   valsLayout->setMargin(9);
867   valsLayout->setSpacing(6);
868
869   // value table
870   mySwitchTableWdg = new QWidget(valsGroup);
871   QVBoxLayout* switchTableGrpLayout = new QVBoxLayout(mySwitchTableWdg);
872   switchTableGrpLayout->setMargin(0);
873   switchTableGrpLayout->setSpacing(0);
874
875   // step add/rm controls
876   QPushButton* addStepBtn = new QPushButton( tr("ADD_STEP"), valsGroup );
877   QLabel* curStepLbl = new QLabel(tr("STEP"), valsGroup );
878   myStepEdit = new QLineEdit( valsGroup );
879   myStepsCombo = new QComboBox(valsGroup);
880   myStepsCombo->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
881   myRmStepBtn = new QPushButton( tr("REMOVE_STEP"), valsGroup );
882
883   // step browse controls
884   myPrevStepBtn = new QPushButton( tr("PREV_STEP"), valsGroup );
885   QLabel* stampLbl = new QLabel(tr("STAMP"), valsGroup );
886   myStampSpin = new SalomeApp_IntSpinBox( -theIntLimit, theIntLimit, 1, valsGroup, true, true);
887   myNextStepBtn = new QPushButton( tr("NEXT_STEP"), valsGroup );
888   
889   valsLayout->addWidget(mySwitchTableWdg,   0, 0, 1, 5);
890   valsLayout->addWidget(addStepBtn,         1, 0);
891   valsLayout->addWidget(curStepLbl,         1, 1);
892   valsLayout->addWidget(myStepEdit,         1, 2);
893   valsLayout->addWidget(myStepsCombo,       1, 3);
894   valsLayout->addWidget(myRmStepBtn,        1, 4);
895   valsLayout->addWidget(myPrevStepBtn,      2, 0);
896   valsLayout->addWidget(stampLbl,           2, 1);
897   valsLayout->addWidget(myStampSpin,        2, 2, 1, 2);
898   valsLayout->addWidget(myNextStepBtn,      2, 4);
899
900   valsLayout->setColumnStretch(3, 5);
901   valsLayout->setRowStretch   (0, 5);
902
903   QVBoxLayout* layout = new QVBoxLayout(centralWidget());
904   layout->setMargin(0); layout->setSpacing(6);
905   layout->addWidget(propGroup);
906   layout->addWidget(valsGroup);
907
908   setHelpFileName("geom_field_page.html");
909
910   LightApp_SelectionMgr* aSelMgr = myGeomGUI->getApp()->selectionMgr();
911   connect(aSelMgr,       SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
912
913   connect(myPrevStepBtn, SIGNAL(clicked()),                 this, SLOT( onPrevStep() ));
914   connect(myNextStepBtn, SIGNAL(clicked()),                 this, SLOT( onNextStep() ));
915   connect(addStepBtn,    SIGNAL(clicked()),                 this, SLOT( onAddStep() ));
916   connect(myRmStepBtn,   SIGNAL(clicked()),                 this, SLOT( onRmStep() ));
917   connect(myStampSpin,   SIGNAL(valueChanged(int)),         this, SLOT( onStampChange() ));
918   connect(myStepsCombo,  SIGNAL(currentIndexChanged(int)),  this, SLOT( showCurStep() ));
919   connect(myStepsCombo,  SIGNAL(activated(int)),            this, SLOT( showCurStep() ));
920
921   connect(buttonOk(),    SIGNAL(clicked()), this, SLOT(ClickOnOk()));
922   connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply()));
923
924   Init();
925   //updateState();
926 }
927
928 //=======================================================================
929 //function : ~EntityGUI_FieldDlg
930 //purpose  : 
931 //=======================================================================
932
933 EntityGUI_FieldDlg::~EntityGUI_FieldDlg()
934 {
935   GEOM_Displayer* aDisplayer = getDisplayer();
936   if (myIsHiddenMain) {
937     aDisplayer->Display(myShape);
938     myIsHiddenMain = false;
939   }
940   // if ( !myField->_is_nil())
941   //   aDisplayer->Display(myField);
942
943   QListIterator<int> anIter( myHiddenFieldStepIds );
944   while( anIter.hasNext() )
945   {
946     const int aStepId = anIter.next();
947     GEOM::GEOM_FieldStep_var step = myField->GetStep( aStepId );
948     if( !step->_is_nil() )
949       aDisplayer->Display( step, false );
950   }
951   aDisplayer->UpdateViewer();
952 }
953
954 //=================================================================================
955 // function : Init()
956 // purpose  :
957 //=================================================================================
958 void EntityGUI_FieldDlg::Init()
959 {
960   myDmMode = -1;
961   myHiddenFieldStepIds.clear();
962   myStepsCombo->clear();
963
964   if ( myIsCreation || myField->_is_nil() )
965   {
966     myIsCreation = true;
967     myStepTables.clear();
968     if ( myCurStepTable )
969       myCurStepTable->hide();
970     myCurStepTable = NULL;
971     myCurStepID = 0;
972
973     initName(tr("FIELD_PREFIX"));
974     myStampSpin->setValue(0);
975
976     SelectionIntoArgument();
977
978     onAddStep();
979
980     connect(myShapeSelBtn, SIGNAL(clicked()),                 this, SLOT(SetEditCurrentArgument()));
981     connect(myTypeCombo,   SIGNAL(currentIndexChanged(int)),  this, SLOT( onTypeChange()));
982     connect(myDimCombo,    SIGNAL(currentIndexChanged(int)),  this, SLOT( onDimChange()));
983     connect(myNbCompsSpin, SIGNAL(valueChanged(int)),         this, SLOT( onNbCompsChange()));
984
985   }
986   else // edition
987   {
988     // 1) get and sort step IDs
989     // 2) hide all displayed field steps' presentations
990     GEOM_Displayer* aDisplayer = getDisplayer();
991     GEOM::ListOfLong_var stepIDs = myField->GetSteps();
992     size_t i;
993     QList< int > stepsList;
994     for ( i = 0; i < stepIDs->length(); ++i )
995     {
996       int aStepId = stepIDs[i];
997       stepsList.push_back( aStepId );
998       GEOM::GEOM_FieldStep_var step = myField->GetStep( aStepId );
999       if( !step->_is_nil() )
1000       {
1001         QString anEntry( step->GetStudyEntry() );
1002         if( aDisplayer->IsDisplayed( anEntry ) )
1003         {
1004           aDisplayer->Erase( step, false, false );
1005           myHiddenFieldStepIds << aStepId;
1006         }
1007       }
1008     }
1009     qSort( stepsList.begin(), stepsList.end() );
1010
1011     myIsCreation = false;
1012
1013     CORBA::String_var fName = myField->GetName();
1014     myMainFrame->ResultName->setText( fName.in() );
1015
1016     myShape = myField->GetShape();
1017     CORBA::String_var sName;
1018     if ( !myShape->_is_nil() )
1019       sName = myShape->GetName();
1020     myShapeName->setText( sName.in() ? sName.in() : "");
1021
1022     myTypeCombo->setCurrentIndex( myField->GetDataType() );
1023
1024     updateDims( myField->GetDimension() );
1025     updateShapeIDs();
1026
1027     GEOM::string_array_var compNames = myField->GetComponents();
1028     myNbCompsSpin->setValue( compNames->length() );
1029
1030     myShapeSelBtn->setEnabled( false );
1031     myShapeName->setEnabled( false );
1032     myTypeCombo->setEnabled( false );
1033     myDimCombo->setEnabled( false );
1034     myNbCompsSpin->setEnabled( false );
1035
1036     myStepsCombo->blockSignals( true );
1037     for ( i = 0; i < stepIDs->length(); ++i )
1038     {
1039       myStepsCombo->insertItem( i, QString::number( stepsList[i] ));
1040       if ( myCurStepID == stepsList[i] )
1041         myStepsCombo->setCurrentIndex( i );
1042     }
1043     // if ( myStepsCombo->count() == 0 )
1044     //   myStepsCombo->insertItem( 0, QString::number( myCurStepID ));
1045     myStepsCombo->blockSignals( false );
1046
1047     showCurStep();
1048     activateSelection();
1049   }
1050 }
1051
1052 //=================================================================================
1053 // function : enterEvent()
1054 // purpose  :
1055 //=================================================================================
1056 void EntityGUI_FieldDlg::enterEvent(QEvent* e)
1057 {
1058   if (!buttonCancel()->isEnabled())
1059     ActivateThisDialog();
1060 }
1061
1062 //=================================================================================
1063 // function : ClickOnOk()
1064 // purpose  :
1065 //=================================================================================
1066 void EntityGUI_FieldDlg::ClickOnOk()
1067 {
1068   setIsApplyAndClose(true);
1069   if (ClickOnApply())
1070     ClickOnCancel();
1071   setIsApplyAndClose(false);
1072 }
1073
1074 //=================================================================================
1075 // function : ClickOnApply()
1076 // purpose  :
1077 //=================================================================================
1078 bool EntityGUI_FieldDlg::ClickOnApply()
1079 {
1080   if(!isApplyAndClose()) {
1081     setIsDisableBrowsing( true );
1082     setIsDisplayResult( false );
1083   }
1084
1085   QString msg;
1086   if ( !isValid( msg ) ) {
1087     showError( msg );
1088     return false;
1089   }
1090   SUIT_OverrideCursor wc;
1091   SUIT_Session::session()->activeApplication()->putInfo( "" );
1092
1093   try {
1094     if ( openCommand() )
1095       if (!execute (/*isApplyAndClose()*/))
1096       {
1097         abortCommand();
1098         showError();
1099         return false;
1100       }
1101   }
1102   catch( const SALOME::SALOME_Exception& e ) {
1103     SalomeApp_Tools::QtCatchCorbaException( e );
1104     abortCommand();
1105     return false;
1106   }
1107   commitCommand();
1108
1109   if(!isApplyAndClose()) {
1110     setIsDisableBrowsing( false );
1111     setIsDisplayResult( true );
1112   }
1113
1114   if ( myIsCreation )
1115   {
1116     myField = GEOM::GEOM_Field::_nil();
1117     if ( !isApplyAndClose() )
1118       Init();
1119   }
1120   return true;
1121 }
1122
1123 //=================================================================================
1124 // function : ActivateThisDialog()
1125 // purpose  :
1126 //=================================================================================
1127 void EntityGUI_FieldDlg::ActivateThisDialog()
1128 {
1129   GEOMBase_Skeleton::ActivateThisDialog();
1130
1131   connect(myGeomGUI->getApp()->selectionMgr(), SIGNAL(currentSelectionChanged()),
1132           this, SLOT(SelectionIntoArgument()));
1133
1134   activateSelection();
1135 }
1136
1137 //=================================================================================
1138 // function : SetEditCurrentArgument()
1139 // purpose  :
1140 //=================================================================================
1141 void EntityGUI_FieldDlg::SetEditCurrentArgument()
1142 {
1143   myEditCurrentArgument = myShapeName;
1144   SelectionIntoArgument();
1145 }
1146
1147 //=================================================================================
1148 // function : SelectionIntoArgument()
1149 // purpose  : Called when selection has changed
1150 //=================================================================================
1151 void EntityGUI_FieldDlg::SelectionIntoArgument()
1152 {
1153   if (myEditCurrentArgument == myShapeName ||  // Selection of a shape is active
1154       myShape->_is_nil())
1155   {
1156     myShapeName->setText("");
1157     myShape = GEOM::GEOM_Object::_nil();
1158
1159     LightApp_SelectionMgr* aSelMgr = myGeomGUI->getApp()->selectionMgr();
1160     SALOME_ListIO aSelList;
1161     aSelMgr->selectedObjects(aSelList);
1162     int nbSel = aSelList.Extent();
1163
1164     if (nbSel == 1) {
1165       GEOM::GEOM_Object_var anObj =
1166         GEOMBase::ConvertIOinGEOMObject(aSelList.First());
1167
1168       if ( GEOMBase::IsShape(anObj) && anObj->IsMainShape() ) {
1169         if (myIsHiddenMain) {
1170           GEOM_Displayer* aDisplayer = getDisplayer();
1171           aDisplayer->Display(myShape);
1172           myIsHiddenMain = false;
1173         }
1174         myShapeName->setText(GEOMBase::GetName(anObj));
1175
1176         if ( !anObj->_is_nil() && !anObj->IsSame( myShape ))
1177         {
1178           myShape = anObj;
1179           myShapeMap.Clear();
1180           myEditCurrentArgument = 0;
1181
1182           // re-fill myDimCombo
1183           //const int curDim = getDim();
1184           updateDims( -100 );
1185
1186           // update table
1187           onDimChange();
1188         }
1189       }
1190     }
1191     else {
1192       if (myIsHiddenMain) {
1193         GEOM_Displayer* aDisplayer = getDisplayer();
1194         aDisplayer->Display(myShape);
1195         myIsHiddenMain = false;
1196       }
1197     }
1198   }
1199   else // select rows of a table according to shape selection
1200   {
1201     if ( !myCurStepTable )
1202       return;
1203
1204     bool isSignalsBlocked = myCurStepTable->signalsBlocked();
1205     myCurStepTable->blockSignals(true);
1206
1207     QList< int > rowsToSelect;
1208     TColStd_IndexedMapOfInteger aMapIndex;
1209     if ( getSelectedSubshapes(aMapIndex ))
1210       for (int ii = 1, nn = aMapIndex.Extent(); ii <= nn; ii++) {
1211         const int shapeID = aMapIndex( ii );
1212         for (int row = 0, n = myShapeIDs.size(); row < n; row++)
1213           if ( myShapeIDs[row] == shapeID ) {
1214             rowsToSelect.push_back( row );
1215             break;
1216           }
1217       }
1218     myCurStepTable->selectRows( rowsToSelect );
1219
1220     myCurStepTable->blockSignals(isSignalsBlocked);
1221   }
1222 }
1223
1224 //=================================================================================
1225 // function : onDimChange()
1226 // purpose  : update dialog at change of dimension
1227 //=================================================================================
1228 void EntityGUI_FieldDlg::onDimChange()
1229 {
1230   // get order of sub-shapes - myShapeIDs
1231   updateShapeIDs();
1232
1233   // update size of tables
1234   const int nbRows = myShapeIDs.size();
1235   QString subName = ( getDim() == -1 ) ? tr("WHOLE_SHAPE_VHEADER") : myDimCombo->currentText();
1236   QMap< int, StepTable* >::iterator tblIt = myStepTables.begin();
1237   for ( ; tblIt != myStepTables.end(); ++tblIt )
1238     if ( tblIt.value() )
1239       tblIt.value()->setDim( nbRows, subName );
1240
1241   activateSelection();
1242 }
1243
1244 //=======================================================================
1245 //function : onNbCompsChange
1246 //purpose  : 
1247 //=======================================================================
1248
1249 void EntityGUI_FieldDlg::onNbCompsChange()
1250 {
1251   QMap< int, StepTable* >::iterator tblIt = myStepTables.begin();
1252   for ( ; tblIt != myStepTables.end(); ++tblIt )
1253     if ( tblIt.value() )
1254       tblIt.value()->setNbComps( getNbComps() );
1255 }
1256
1257 //=======================================================================
1258 //function : onTypeChange
1259 //purpose  : 
1260 //=======================================================================
1261
1262 void EntityGUI_FieldDlg::onTypeChange()
1263 {
1264   QMap< int, StepTable* >::iterator tblIt = myStepTables.begin();
1265   for ( ; tblIt != myStepTables.end(); ++tblIt )
1266     if ( tblIt.value() )
1267       tblIt.value()->setDataType( myTypeCombo->currentIndex() );
1268 }
1269
1270 //=================================================================================
1271 // function : onPrevStep()
1272 // purpose  :
1273 //=================================================================================
1274 void EntityGUI_FieldDlg::onPrevStep()
1275 {
1276   int i = myStepsCombo->currentIndex();
1277   if ( i > 0 )
1278   {
1279     myStepsCombo->setCurrentIndex( i-1 );
1280     showCurStep();
1281   }
1282 }
1283
1284 //=================================================================================
1285 // function : onNextStep()
1286 // purpose  :
1287 //=================================================================================
1288 void EntityGUI_FieldDlg::onNextStep()
1289 {
1290   int i = myStepsCombo->currentIndex();
1291   if ( i+1 < myStepsCombo->count() )
1292   {
1293     myStepsCombo->setCurrentIndex( i+1 );
1294     showCurStep();
1295   }
1296 }
1297
1298 static int findInCombo( QComboBox* where, int what, bool& ok )
1299 {
1300   int idx = 0;
1301   ok = false;
1302
1303   for ( ; idx < where->count() && !ok; idx++ ) {
1304     int step = where->itemText( idx ).toInt();
1305     if ( step == what ) {
1306       ok = true;
1307     }
1308     else if ( step > what )
1309       break;
1310   }
1311   
1312   return idx;
1313 }
1314
1315 //=======================================================================
1316 //function : onAddStep
1317 //purpose  : 
1318 //=======================================================================
1319 void EntityGUI_FieldDlg::onAddStep()
1320 {
1321   int step = 0;
1322
1323   if ( !myStepEdit->text().isEmpty() )
1324     step = myStepEdit->text().toInt();
1325   bool ok = false;
1326   int idx = findInCombo( myStepsCombo, step, ok );
1327   
1328   if ( ok ) {
1329     SUIT_MessageBox::critical(this, QObject::tr("ERR_ERROR"),
1330                               tr("ERR_STEP_EXISTS"));
1331     return;
1332   }
1333
1334   myStepsCombo->insertItem( idx, QString::number( step ));
1335   myStepsCombo->setCurrentIndex( idx );
1336   myRemovedSteps.remove( getCurStepID() );
1337   //showCurStep();
1338 }
1339
1340 //=======================================================================
1341 //function : onRmStep
1342 //purpose  : 
1343 //=======================================================================
1344 void EntityGUI_FieldDlg::onRmStep()
1345 {
1346   if ( myStepsCombo->count() > 1 )
1347   {
1348     myStepTables.remove( getCurStepID() );
1349     myRemovedSteps.insert( getCurStepID() );
1350     if ( myCurStepTable )
1351       myCurStepTable->hide();
1352     myCurStepTable = NULL;
1353     myStepsCombo->removeItem( myStepsCombo->currentIndex() );
1354     //showCurStep();
1355   }
1356 }
1357
1358 //=======================================================================
1359 //function : onStampChange
1360 //purpose  : 
1361 //=======================================================================
1362 void EntityGUI_FieldDlg::onStampChange()
1363 {
1364   if ( myCurStepTable )
1365     myCurStepTable->setStamp( myStampSpin->value() );
1366 }
1367
1368 //=======================================================================
1369 //function : showCurStep
1370 //purpose  : 
1371 //=======================================================================
1372 void EntityGUI_FieldDlg::showCurStep()
1373 {
1374   myCurStepID = getCurStepID(); 
1375   myStepEdit->setText(QString::number( myCurStepID ));
1376
1377   QStringList headers;
1378   if ( myCurStepTable )
1379   {
1380     if ( myCurStepTable->getStepID() == myCurStepID )
1381     {
1382       myCurStepTable->show();
1383       return;
1384     }
1385     else
1386     {
1387       myCurStepTable->hide();
1388       headers = myCurStepTable->getHeaders();
1389       myCurStepTable->getStamp();
1390     }
1391   }
1392
1393   if ( myStepTables.count ( myCurStepID ))
1394   {
1395     myCurStepTable = myStepTables[ myCurStepID ];
1396     myCurStepTable->setHeaders( headers );
1397   }
1398   else
1399   {
1400     // if ( myStepsCombo->count() == 0 )
1401     //   return; // edit a field with no steps
1402
1403     // get step values
1404     GEOM::GEOM_FieldStep_var stepVar;
1405     if ( !myField->_is_nil() )
1406       stepVar = myField->GetStep( myCurStepID );
1407
1408     int nbComps = getNbComps();
1409     if ( headers.count() == 0 )
1410     {
1411       headers << tr("SUB_SHAPE_HEADER");
1412       if ( !myIsCreation && !myField->_is_nil() )
1413       {
1414         GEOM::string_array_var compNames = myField->GetComponents();
1415         for ( int iC = 0; iC < compNames->length(); ++iC )
1416           headers << compNames[ iC ].in();
1417       }
1418       else
1419       {
1420         for ( int iC = 0; iC < nbComps; ++iC )
1421           headers << QString("Comp %1").arg( iC + 1 );
1422       }
1423     }
1424     QString subName = ( getDim() == -1 ) ? tr("WHOLE_SHAPE_VHEADER") : myDimCombo->currentText();
1425     myCurStepTable = new StepTable( myCurStepID, getDataType(), myShapeIDs.size(),
1426                                     nbComps, subName, headers, stepVar, mySwitchTableWdg );
1427     myStepTables[ myCurStepID ] = myCurStepTable;
1428     mySwitchTableWdg->layout()->addWidget( myCurStepTable );
1429   }
1430   myCurStepTable->show();
1431   myStampSpin->setValue( myCurStepTable->getStamp() );
1432
1433   connect(myCurStepTable, SIGNAL(itemSelectionChanged()), this, SLOT( highlightSubShapes() ));
1434
1435   myPrevStepBtn->setEnabled( myStepsCombo->currentIndex() > 0 );
1436   myNextStepBtn->setEnabled( myStepsCombo->currentIndex()+1 < myStepsCombo->count() );
1437   myRmStepBtn->setEnabled( myStepsCombo->count() > 1 );
1438 }
1439
1440 //=================================================================================
1441 // function : getSelectedSubshapes
1442 // purpose  :
1443 //=================================================================================
1444 int EntityGUI_FieldDlg::getSelectedSubshapes (TColStd_IndexedMapOfInteger& theMapIndex)
1445 {
1446   theMapIndex.Clear();
1447
1448   SalomeApp_Application* app = myGeomGUI->getApp();
1449   if (!app || myShape->_is_nil())
1450     return 0;
1451
1452   LightApp_SelectionMgr* aSelMgr = app->selectionMgr();
1453   SALOME_ListIO aSelList;
1454   aSelMgr->selectedObjects(aSelList);
1455
1456   // try to find out and process the global selection
1457   // (of not published objects and of published sub-shapes)
1458   {
1459     SALOME_ListIteratorOfListIO anIter (aSelList);
1460     for (int i = 0; anIter.More(); anIter.Next(), i++)
1461     {
1462       Handle(SALOME_InteractiveObject) anIObj = anIter.Value();
1463       QString anEntry = anIObj->getEntry();
1464       QString str = "_";
1465       int index = anEntry.lastIndexOf(str);
1466       if (index > 0) // selection among special preview
1467       {
1468         anEntry.remove(0, index+1);
1469         int anIndex = anEntry.toInt();
1470         if (anIndex)
1471           theMapIndex.Add(anIndex);
1472       }
1473       else // selection among published shapes
1474       {
1475         SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>(app->activeStudy());
1476         if (!appStudy) return 0;
1477         _PTR(Study) aStudy = appStudy->studyDS();
1478
1479         _PTR(SObject) aSObj (aStudy->FindObjectID(anEntry.toLatin1().constData()));
1480         GEOM::GEOM_Object_var aGeomObj =
1481           GEOM::GEOM_Object::_narrow(GeometryGUI::ClientSObjectToObject(aSObj));
1482         TopoDS_Shape aShape;
1483         if (GEOMBase::GetShape(aGeomObj, aShape)) {
1484           if (aGeomObj->GetType() == GEOM_GROUP || aShape.ShapeType() == getShapeType())
1485           {
1486             TopExp_Explorer anExp (aShape, getShapeType());
1487             for (; anExp.More(); anExp.Next()) {
1488               TopoDS_Shape aSubShape = anExp.Current();
1489               int anIndex = myShapeMap.FindIndex(aSubShape);
1490               if (anIndex == 0) {
1491                 SUIT_MessageBox::warning(app->desktop(), QObject::tr("WRN_WARNING"),
1492                                          tr("WRN_NOT_SUBSHAPE"));
1493               }
1494               theMapIndex.Add(anIndex);
1495             }
1496           }
1497         }
1498       }
1499     } // for aSelList
1500   }
1501
1502   return theMapIndex.Extent();
1503 }
1504
1505 //=================================================================================
1506 // function : getShapeType()
1507 // purpose  :
1508 //=================================================================================
1509 TopAbs_ShapeEnum EntityGUI_FieldDlg::getShapeType(int* dim) const
1510 {
1511   
1512   switch ( dim ? *dim : getDim() )
1513   {
1514   case 0:  return TopAbs_VERTEX;
1515   case 1:  return TopAbs_EDGE;
1516   case 2:  return TopAbs_FACE;
1517   case 3:  return TopAbs_SOLID;
1518   default: return TopAbs_SHAPE;
1519   }
1520 }
1521
1522 //=======================================================================
1523 //function : getDim
1524 //purpose  : 
1525 //=======================================================================
1526 int EntityGUI_FieldDlg::getDim() const
1527 {
1528   int i = myDimCombo->currentIndex();
1529   return ( i < 0 ) ? -1 : myDimCombo->itemData( i ).toInt();
1530 }
1531
1532 //=======================================================================
1533 //function : getDataType
1534 //purpose  : 
1535 //=======================================================================
1536 int EntityGUI_FieldDlg::getDataType() const
1537 {
1538   return myTypeCombo->currentIndex();
1539 }
1540
1541 //=======================================================================
1542 //function : getCurStepID
1543 //purpose  : 
1544 //=======================================================================
1545 int EntityGUI_FieldDlg::getCurStepID() const
1546 {
1547   if ( myStepsCombo->count() > 0 )
1548     return myStepsCombo->currentText().toInt();
1549   return myCurStepID;
1550 }
1551
1552 //=======================================================================
1553 //function : getNbComps
1554 //purpose  : 
1555 //=======================================================================
1556 int EntityGUI_FieldDlg::getNbComps() const
1557 {
1558   return myNbCompsSpin->value();
1559 }
1560
1561 //=================================================================================
1562 // function : updateShapeIDs()
1563 // purpose  : update myShapeIDs
1564 //=================================================================================
1565 void EntityGUI_FieldDlg::updateShapeIDs()
1566 {
1567   myShapeIDs.clear();
1568   //myShapeMap.Clear();
1569   if ( !myShape->_is_nil() )
1570   {
1571     TopoDS_Shape aShape =
1572       GEOM_Client::get_client().GetShape(GeometryGUI::GetGeomGen(), myShape);
1573     if ( myShapeMap.IsEmpty() )
1574       TopExp::MapShapes(aShape, myShapeMap);
1575     TopAbs_ShapeEnum shapeType = getShapeType();
1576     if ( shapeType == TopAbs_SHAPE )
1577     {
1578       myShapeIDs.push_back( 1 );
1579     }
1580     else
1581     {
1582       TopTools_IndexedMapOfShape dimSubShapesMap;
1583       TopExp::MapShapes(aShape, shapeType, dimSubShapesMap);
1584       myShapeIDs.resize( dimSubShapesMap.Extent() );
1585       for ( int i = 1; i <= dimSubShapesMap.Extent(); ++i )
1586         myShapeIDs[i-1] = myShapeMap.FindIndex( dimSubShapesMap(i) );
1587     }
1588   }
1589 }
1590
1591 //=======================================================================
1592 //function : updateDims
1593 //purpose  : update myDimCombo
1594 //=======================================================================
1595 void EntityGUI_FieldDlg::updateDims(int curDim)
1596 {
1597   myDimCombo->blockSignals( true );
1598   myDimCombo->clear();
1599   TopoDS_Shape aShape =
1600     GEOM_Client::get_client().GetShape(GeometryGUI::GetGeomGen(), myShape);
1601
1602   if ( !aShape.IsNull() )
1603   {
1604     const char* subNames[4] = { "VERTEX","EDGE","FACE","SOLID" };
1605     TopExp_Explorer exp;
1606     for ( int dim = 0; dim < 4; ++dim )
1607     {
1608       exp.Init( aShape, getShapeType(&dim));
1609       if ( exp.More() && !aShape.IsSame( exp.Current() ))
1610         myDimCombo->insertItem( dim, tr( subNames[dim] ), dim );
1611     }
1612     myDimCombo->insertItem( 4, tr("WHOLE"), -1 );
1613
1614     int idx = myDimCombo->findData( curDim );
1615     if ( idx != -1 )
1616       myDimCombo->setCurrentIndex( idx );
1617     else 
1618       myDimCombo->setCurrentIndex( myDimCombo->count()-1-(myDimCombo->count()>1?1:0) );
1619   }
1620   myDimCombo->blockSignals( false );
1621 }
1622
1623 //=================================================================================
1624 // function : activateSelection
1625 // purpose  : Activate local selection
1626 //=================================================================================
1627 void EntityGUI_FieldDlg::activateSelection()
1628 {
1629   bool isApply = ((QPushButton*)sender() == buttonApply());
1630   if(!isApplyAndClose())
1631     erasePreview(false);
1632
1633   // local selection
1634   if (!myShape->_is_nil() &&
1635       !myEditCurrentArgument &&
1636       myShapeIDs.size() > 1 ) // shape type is already choosen by user
1637   {
1638     GEOM_Displayer*   aDisplayer = getDisplayer();
1639     CORBA::String_var aMainEntry = myShape->GetStudyEntry();
1640
1641     //display mode for main shape
1642     if ( myDmMode == -1 ) {
1643       SALOME_View* view = GEOM_Displayer::GetActiveView();
1644       if (view) {
1645         Handle(SALOME_InteractiveObject) io =
1646           new SALOME_InteractiveObject (aMainEntry.in(), "GEOM", "TEMP_IO");
1647         if ( view->isVisible( io ) ) {
1648           Handle(GEOM_AISShape) aSh = GEOMBase::ConvertIOinGEOMAISShape( io, true );
1649           if(!aSh.IsNull()) {
1650             myDmMode = aSh->isTopLevel() ? aSh->prevDisplayMode() : aSh->DisplayMode();
1651           }
1652           // Hide main shape, if explode on VERTEX
1653           if(getShapeType() != TopAbs_VERTEX) {
1654             aDisplayer->Erase(myShape, false, false);
1655             myIsHiddenMain = true;
1656           }
1657         }
1658         else
1659           myDmMode = SUIT_Session::session()->resourceMgr()->integerValue( "Geometry", "display_mode" );
1660       }
1661     }
1662     aDisplayer->SetDisplayMode(myDmMode);
1663
1664     // Mantis issue 0021421: do not hide main shape, if explode on VERTEX
1665     if (getShapeType() == TopAbs_VERTEX) {
1666       if (myIsHiddenMain)
1667         aDisplayer->Display(myShape);
1668     }
1669     //aDisplayer->Erase(myField, false, false); ------- NOR YET implemented
1670
1671     QColor aColor = SUIT_Session::session()->resourceMgr()->colorValue( "Geometry", "editField_color" );
1672     Quantity_NameOfColor aCol = SalomeApp_Tools::color( aColor ).Name();
1673
1674     if(!isApplyAndClose()) {
1675       SUIT_ViewWindow* aViewWindow = 0;
1676       SUIT_Study* activeStudy = SUIT_Session::session()->activeApplication()->activeStudy();
1677       if (activeStudy)
1678         aViewWindow = SUIT_Session::session()->activeApplication()->desktop()->activeWindow();
1679       if (aViewWindow == 0) return;
1680
1681       SUIT_ViewManager* aViewManager = aViewWindow->getViewManager();
1682       if (aViewManager->getType() != OCCViewer_Viewer::Type() &&
1683           aViewManager->getType() != SVTK_Viewer::Type())
1684         return;
1685
1686       SUIT_ViewModel* aViewModel = aViewManager->getViewModel();
1687       SALOME_View* aView = dynamic_cast<SALOME_View*>(aViewModel);
1688       if (aView == 0) return;
1689
1690       TopoDS_Shape aMainShape = myShapeMap(1);
1691       for ( int i = 0; i < myShapeIDs.size(); ++i )
1692       {
1693         int index = myShapeIDs[ i ];
1694         TopoDS_Shape aSubShape = myShapeMap( index );
1695         QString anEntry = QString( "TEMP_" ) + aMainEntry.in() + QString("_%1").arg(index);
1696         Handle(SALOME_InteractiveObject) io =
1697           new SALOME_InteractiveObject(anEntry.toAscii(), "GEOM", "TEMP_IO");
1698         aDisplayer->SetColor( aCol );
1699         SALOME_Prs* aPrs = aDisplayer->buildSubshapePresentation(aSubShape, anEntry, aView);
1700         if (aPrs) {
1701           displayPreview(aPrs, true, false); // append, do not update
1702           // TODO: map or delete Prs
1703         }
1704       }
1705       aDisplayer->UnsetDisplayMode();
1706       aDisplayer->UnsetColor();
1707       aDisplayer->UpdateViewer();
1708     }
1709   }
1710
1711   globalSelection(GEOM_ALLSHAPES);
1712
1713   SelectionIntoArgument();
1714 }
1715
1716 //=================================================================================
1717 // function : highlightSubShapes
1718 // purpose  : select objects corresponding to selected table rows
1719 //=================================================================================
1720 void EntityGUI_FieldDlg::highlightSubShapes()
1721 {
1722   if (CORBA::is_nil(myShape) || !myCurStepTable )
1723     return;
1724
1725   TColStd_MapOfInteger anIds;
1726   QList<int> rows = myCurStepTable->selectedRows();
1727   int ii = 0, nn = rows.count();
1728   for (; ii < nn; ii++)
1729   {
1730     int shapeNum = rows[ ii ];
1731     if ( shapeNum < myShapeIDs.size() )
1732       anIds.Add( myShapeIDs[ shapeNum ]);
1733   }
1734
1735   SalomeApp_Application* app = myGeomGUI->getApp();
1736   LightApp_SelectionMgr* aSelMgr = app->selectionMgr();
1737   aSelMgr->clearSelected();
1738   if ( anIds.IsEmpty() )
1739     return;
1740
1741   SUIT_ViewWindow* aViewWindow = 0;
1742   SUIT_Study* activeStudy = app->activeStudy();
1743   if (activeStudy)
1744     aViewWindow = app->desktop()->activeWindow();
1745   if (aViewWindow == 0) return;
1746
1747   SUIT_ViewManager* aViewManager = aViewWindow->getViewManager();
1748   if (aViewManager->getType() != OCCViewer_Viewer::Type() &&
1749       aViewManager->getType() != SVTK_Viewer::Type())
1750     return;
1751
1752   SUIT_ViewModel* aViewModel = aViewManager->getViewModel();
1753   SALOME_View* aView = dynamic_cast<SALOME_View*>(aViewModel);
1754   if (aView == 0) return;
1755
1756   // TODO??: use here GEOMBase_Helper::myPreview instead of ic->DisplayedObjects()
1757
1758   OCCViewer_Viewer* v3d = ((OCCViewer_ViewManager*)aViewManager)->getOCCViewer();
1759   Handle(AIS_InteractiveContext) ic = v3d->getAISContext();
1760   AIS_ListOfInteractive List;
1761   //ic->DisplayedObjects(List);
1762   ic->ObjectsInside(List); // Mantis issue 0021367
1763
1764   SALOME_ListIO aSelList;
1765
1766   // To highlight the selected sub-shape in Object Browser, if it's already published under the main shape
1767   GEOM::GEOM_ILocalOperations_var aLocOp = getGeomEngine()->GetILocalOperations(getStudyId());
1768   QMap<int, QString> childsMap;
1769   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>(app->activeStudy());
1770   if (appStudy) {
1771     _PTR(Study) aStudy = appStudy->studyDS();
1772     CORBA::String_var aMainEntry = myShape->GetStudyEntry();
1773     _PTR(SObject) aSObj = aStudy->FindObjectID( aMainEntry.in() );
1774     _PTR(ChildIterator) anIt = aStudy->NewChildIterator(aSObj);
1775     for (anIt->InitEx(true); anIt->More(); anIt->Next()) {
1776       GEOM::GEOM_Object_var aChild =
1777         GEOM::GEOM_Object::_narrow(GeometryGUI::ClientSObjectToObject(anIt->Value()));
1778       if (!CORBA::is_nil(aChild)) {
1779         int index = aLocOp->GetSubShapeIndex(myShape, aChild);
1780         if ( anIds.Contains( index )) {
1781           CORBA::String_var aChildEntry = aChild->GetStudyEntry();
1782           //childsMap.insert(index, aChildEntry.in());
1783             Handle(SALOME_InteractiveObject) tmpIO =
1784               new SALOME_InteractiveObject( aChildEntry.in(), "GEOM", "TEMP_IO");
1785             aSelList.Append(tmpIO);
1786         }
1787       }
1788     }
1789   }
1790
1791   AIS_ListIteratorOfListOfInteractive ite (List);
1792   for (; ite.More(); ite.Next()) {
1793     if (ite.Value()->IsInstance(STANDARD_TYPE(GEOM_AISShape))) {
1794       Handle(GEOM_AISShape) aSh = Handle(GEOM_AISShape)::DownCast(ite.Value());
1795       if (aSh->hasIO()) {
1796         Handle(SALOME_InteractiveObject) anIO = aSh->getIO();
1797         QString anEntry = anIO->getEntry();
1798         int index = anEntry.lastIndexOf("_");
1799         anEntry.remove(0, index+1);
1800         int anIndex = anEntry.toInt();
1801         if (anIds.Contains(anIndex)) {
1802           aSelList.Append(anIO);
1803           // if (childsMap.contains (anIndex)) {
1804           //   Handle(SALOME_InteractiveObject) tmpIO = new SALOME_InteractiveObject(childsMap.value(anIndex).toLatin1().constData(), "GEOM", "TEMP_IO");
1805           //   aSelList.Append(tmpIO);
1806           // }
1807         }
1808       }
1809     }
1810   }
1811   aSelMgr->setSelectedObjects(aSelList);
1812 }
1813
1814 //=================================================================================
1815 // function : createOperation
1816 // purpose  :
1817 //=================================================================================
1818 GEOM::GEOM_IOperations_ptr EntityGUI_FieldDlg::createOperation()
1819 {
1820   return getGeomEngine()->GetIFieldOperations(getStudyId());
1821 }
1822
1823 #define RETURN_WITH_MSG(a, b) \
1824   if ((a)) { \
1825     theMessage += (b); \
1826     return false; \
1827   }
1828
1829 //=================================================================================
1830 // function : isValid()
1831 // purpose  : Verify validity of input data
1832 //=================================================================================
1833 bool EntityGUI_FieldDlg::isValid(QString& theMessage)
1834 {
1835   SalomeApp_Study* study = getStudy();
1836   RETURN_WITH_MSG  (!study, tr("GEOM_NO_STUDY"))
1837   RETURN_WITH_MSG  (study->studyDS()->GetProperties()->IsLocked(), tr("GEOM_STUDY_LOCKED"))
1838
1839   if ( myIsCreation ) {
1840     RETURN_WITH_MSG(CORBA::is_nil(myShape), tr("NO_SHAPE"))
1841   }
1842   else {
1843     RETURN_WITH_MSG(CORBA::is_nil(myShape), tr("NO_FIELD"))
1844   }
1845
1846   QString aName = getNewObjectName().trimmed();
1847   RETURN_WITH_MSG  (aName.isEmpty(), tr("EMPTY_NAME"))
1848
1849   RETURN_WITH_MSG  ( !myCurStepTable, tr("NO_VALUES"))
1850   return true;
1851 }
1852
1853 //=================================================================================
1854 // function : execute
1855 // purpose  :
1856 //=================================================================================
1857 bool EntityGUI_FieldDlg::execute()
1858 {
1859   SALOMEDS::Study_var aStudyDS = GeometryGUI::ClientStudyToStudy( getStudy()->studyDS() );
1860   SALOMEDS::StudyBuilder_var aBuilder = aStudyDS->NewBuilder();
1861
1862   QString aName = getNewObjectName().trimmed();
1863   QStringList anEntryList;
1864
1865   if ( myField->_is_nil() ) // create field
1866   {
1867     QStringList columnNames = myCurStepTable->getHeaders();
1868     int nbComps = columnNames.count() - 1;
1869     GEOM::string_array_var compNames = new GEOM::string_array();
1870     compNames->length( nbComps );
1871     for ( int iC = 0; iC < nbComps; ++iC )
1872       compNames[ iC ] = columnNames[ iC+1 ].toLatin1().constData();
1873
1874     GEOM::GEOM_IFieldOperations_var anOper = GEOM::GEOM_IFieldOperations::_narrow(getOperation());
1875     myField = anOper->CreateField( myShape,
1876                                    aName.toLatin1().constData(),
1877                                    GEOM::field_data_type( getDataType() ),
1878                                    CORBA::Short( getDim() ),
1879                                    compNames );
1880     if ( myField->_is_nil() )
1881       return false;
1882     
1883     SALOMEDS::SObject_wrap aSO =
1884       getGeomEngine()->AddInStudy( aStudyDS, myField, aName.toLatin1().constData(), myShape );
1885     if ( !aSO->_is_nil() ) {
1886       myField->UnRegister();
1887       CORBA::String_var entry = aSO->GetID();
1888       anEntryList << entry.in();
1889     }
1890   }
1891   else // update field name
1892   {
1893     myField->SetName( aName.toLatin1().constData() );
1894
1895     CORBA::String_var entry = myField->GetStudyEntry();
1896     if ( entry.in() ) {
1897       SALOMEDS::SObject_wrap SO = aStudyDS->FindObjectID( entry.in() );
1898       if ( !SO->_is_nil() ) {
1899         aBuilder->SetName(SO, aName.toLatin1().constData());
1900       }
1901     }
1902   }
1903
1904   // create / update steps
1905   QMap< int, StepTable* >::iterator i_tbl = myStepTables.begin();
1906   for ( ; i_tbl != myStepTables.end(); ++i_tbl )
1907   {
1908     StepTable* tbl = i_tbl.value();
1909     QString stepName = (tr("STEP")+" %1 %2").arg( tbl->getStepID() ).arg( tbl->getStamp() );
1910
1911     GEOM::GEOM_FieldStep_var step = tbl->getStep();
1912     if ( step->_is_nil() )
1913     {
1914       step = myField->GetStep( tbl->getStepID() );
1915       if ( step->_is_nil() )
1916       {
1917         step = myField->AddStep( tbl->getStepID(), tbl->getStamp() );
1918
1919         SALOMEDS::SObject_wrap aSO =
1920           getGeomEngine()->AddInStudy( aStudyDS, step, stepName.toLatin1().constData(), myField );
1921         if ( /*!myIsCreation &&*/ !aSO->_is_nil() ) {
1922           step->UnRegister();
1923           CORBA::String_var entry = aSO->GetID();
1924           anEntryList << entry.in();
1925         }
1926       }
1927     }
1928     else if ( step->GetStamp() != tbl->getStamp() )
1929     {
1930       // update a stamp in the object browser
1931       CORBA::String_var entry = step->GetStudyEntry();
1932       if ( entry.in() ) {
1933         SALOMEDS::SObject_wrap SO = aStudyDS->FindObjectID( entry.in() );
1934         if ( !SO->_is_nil() )
1935           aBuilder->SetName( SO, stepName.toLatin1().constData() );
1936       }
1937     }
1938
1939     tbl->setValues( step );
1940
1941     // update the presentation if it is displayed
1942     CORBA::String_var aStepEntry = step->GetStudyEntry();
1943     Handle(SALOME_InteractiveObject) aStepIO =
1944       new SALOME_InteractiveObject( aStepEntry.in(), "GEOM", "TEMP_IO" );
1945     getDisplayer()->Redisplay( aStepIO, false, false );
1946   }
1947   getDisplayer()->UpdateViewer();
1948
1949   // remove steps
1950   if ( !myIsCreation )
1951   {
1952     QSet< int >::iterator stepID = myRemovedSteps.begin();
1953     for ( ; stepID != myRemovedSteps.end(); ++stepID )
1954     {
1955       GEOM::GEOM_FieldStep_var step = myField->GetStep( *stepID );
1956       if ( !step->_is_nil() )
1957       {
1958         CORBA::String_var entry = step->GetStudyEntry();
1959         myField->RemoveStep( *stepID );
1960
1961         if ( entry.in() ) {
1962           SALOMEDS::SObject_wrap SO = aStudyDS->FindObjectID( entry.in() );
1963           if ( !SO->_is_nil() )
1964             aBuilder->RemoveObjectWithChildren( SO );
1965         }
1966       }
1967     }
1968   }
1969   myRemovedSteps.clear();
1970
1971   updateObjBrowser();
1972
1973   if( SUIT_Application* anApp = SUIT_Session::session()->activeApplication() ) {
1974     LightApp_Application* aLightApp = dynamic_cast<LightApp_Application*>( anApp );
1975     if( aLightApp && !isDisableBrowsing() && anEntryList.count() )
1976     {
1977       aLightApp->browseObjects( anEntryList, isApplyAndClose(), isOptimizedBrowsing() );
1978       anApp->putInfo( QObject::tr("GEOM_PRP_DONE") );
1979     }
1980   }
1981
1982   return true;
1983 }