Salome HOME
IPAL52933: Selection disappears in the "Move node" dialog
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_Measurements.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESHGUI_Measurements.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24
25 #include "SMESHGUI_Measurements.h"
26
27 #include "SMESH_Actor.h"
28 #include "SMESHGUI.h"
29 #include "SMESHGUI_IdValidator.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include <SMESH_TypeFilter.hxx>
33 #include <SMESH_LogicalFilter.hxx>
34
35 #include <LightApp_SelectionMgr.h>
36 #include <SUIT_OverrideCursor.h>
37 #include <SUIT_ResourceMgr.h>
38 #include <SVTK_ViewWindow.h>
39 #include <SALOME_ListIO.hxx>
40
41 #include <QButtonGroup>
42 #include <QGridLayout>
43 #include <QGroupBox>
44 #include <QHBoxLayout>
45 #include <QKeyEvent>
46 #include <QLabel>
47 #include <QLineEdit>
48 #include <QPushButton>
49 #include <QRadioButton>
50 #include <QTabWidget>
51 #include <QVBoxLayout>
52
53 #include <vtkPoints.h>
54 #include <vtkUnstructuredGrid.h>
55 #include <vtkIdList.h>
56 #include <vtkCellArray.h>
57 #include <vtkUnsignedCharArray.h>
58 #include <vtkDataSetMapper.h>
59 #include <VTKViewer_CellLocationsArray.h>
60 #include <vtkProperty.h>
61
62 #include <SALOMEconfig.h>
63 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
64 #include CORBA_SERVER_HEADER(SMESH_Measurements)
65
66 const int SPACING = 6;            // layout spacing
67 const int MARGIN  = 9;            // layout margin
68 const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field
69
70 // Uncomment as soon as elements are supported by Min Distance operation
71 //#define MINDIST_ENABLE_ELEMENT
72
73 // Uncomment as soon as objects are supported by Min Distance operation
74 //#define MINDIST_ENABLE_OBJECT
75
76 /*!
77   \class SMESHGUI_MinDistance
78   \brief Minimum distance measurement widget.
79   
80   Widget to calculate minimum distance between two objects.
81 */
82
83 /*!
84   \brief Constructor.
85   \param parent parent widget
86 */
87 SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
88 : QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 )
89 {
90   QGroupBox*    aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this );
91   QRadioButton* aFNode       = new QRadioButton( tr( "NODE" ),    aFirstTgtGrp );
92   QRadioButton* aFElem       = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp );
93   QRadioButton* aFObject     = new QRadioButton( tr( "OBJECT" ),  aFirstTgtGrp );
94   myFirstTgt                 = new QLineEdit( aFirstTgtGrp );
95
96   QGridLayout* fl = new QGridLayout( aFirstTgtGrp );
97   fl->setMargin( MARGIN );
98   fl->setSpacing( SPACING );
99   fl->addWidget( aFNode,     0, 0 );
100   fl->addWidget( aFElem,     0, 1 );
101   fl->addWidget( aFObject,   0, 2 );
102   fl->addWidget( myFirstTgt, 1, 0, 1, 3 );
103
104   myFirst = new QButtonGroup( this );
105   myFirst->addButton( aFNode,   NodeTgt );
106   myFirst->addButton( aFElem,   ElementTgt );
107   myFirst->addButton( aFObject, ObjectTgt );
108
109   QGroupBox*    aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this );
110   QRadioButton* aSOrigin      = new QRadioButton( tr( "ORIGIN" ),  aSecondTgtGrp );
111   QRadioButton* aSNode        = new QRadioButton( tr( "NODE" ),    aSecondTgtGrp );
112   QRadioButton* aSElem        = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp );
113   QRadioButton* aSObject      = new QRadioButton( tr( "OBJECT" ),  aSecondTgtGrp );
114   mySecondTgt                 = new QLineEdit( aSecondTgtGrp );
115
116   QGridLayout* sl = new QGridLayout( aSecondTgtGrp );
117   sl->setMargin( MARGIN );
118   sl->setSpacing( SPACING );
119   sl->addWidget( aSOrigin,   0, 0 );
120   sl->addWidget( aSNode,     0, 1 );
121   sl->addWidget( aSElem,     0, 2 );
122   sl->addWidget( aSObject,   0, 3 );
123   sl->addWidget( mySecondTgt, 1, 0, 1, 4 );
124
125   mySecond = new QButtonGroup( this );
126   mySecond->addButton( aSOrigin, OriginTgt );
127   mySecond->addButton( aSNode,   NodeTgt );
128   mySecond->addButton( aSElem,   ElementTgt );
129   mySecond->addButton( aSObject, ObjectTgt );
130
131   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
132   
133   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
134   QLabel* aDxLab   = new QLabel( "dX", aResults );
135   myDX             = new QLineEdit( aResults );
136   QLabel* aDyLab   = new QLabel( "dY", aResults );
137   myDY             = new QLineEdit( aResults );
138   QLabel* aDzLab   = new QLabel( "dZ", aResults );
139   myDZ             = new QLineEdit( aResults );
140   QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults );
141   myDistance       = new QLineEdit( aResults );
142
143   QGridLayout* rl = new QGridLayout( aResults );
144   rl->setMargin( MARGIN );
145   rl->setSpacing( SPACING );
146   rl->addWidget( aDxLab,     0, 0 );
147   rl->addWidget( myDX,       0, 1 );
148   rl->addWidget( aDyLab,     1, 0 );
149   rl->addWidget( myDY,       1, 1 );
150   rl->addWidget( aDzLab,     2, 0 );
151   rl->addWidget( myDZ,       2, 1 );
152   rl->addWidget( aDistLab,   0, 2 );
153   rl->addWidget( myDistance, 0, 3 );
154
155   QGridLayout* l = new QGridLayout( this );
156   l->setMargin( MARGIN );
157   l->setSpacing( SPACING );
158
159   l->addWidget( aFirstTgtGrp,  0, 0, 1, 2 );
160   l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 );
161   l->addWidget( aCompute,      2, 0 );
162   l->addWidget( aResults,      3, 0, 1, 2 );
163   l->setColumnStretch( 1, 5 );
164   l->setRowStretch( 4, 5 );
165
166   aFNode->setChecked( true );
167   aSOrigin->setChecked( true );
168 #ifndef MINDIST_ENABLE_ELEMENT
169   aFElem->setEnabled( false );   // NOT AVAILABLE YET
170   aSElem->setEnabled( false );   // NOT AVAILABLE YET
171 #endif
172 #ifndef MINDIST_ENABLE_OBJECT
173   aFObject->setEnabled( false ); // NOT AVAILABLE YET
174   aSObject->setEnabled( false ); // NOT AVAILABLE YET
175 #endif
176   myDX->setReadOnly( true );
177   myDY->setReadOnly( true );
178   myDZ->setReadOnly( true );
179   myDistance->setReadOnly( true );
180
181   myValidator = new SMESHGUI_IdValidator( this, 1 );
182
183   myFirstTgt->installEventFilter( this );
184   mySecondTgt->installEventFilter( this );
185
186   connect( myFirst,     SIGNAL( buttonClicked( int ) ),  this, SLOT( firstChanged() ) );
187   connect( mySecond,    SIGNAL( buttonClicked( int ) ),  this, SLOT( secondChanged() ) );
188   connect( aCompute,    SIGNAL( clicked() ),             this, SLOT( compute() ) );
189   connect( myFirstTgt,  SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) );
190   connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) );
191
192   QList<SUIT_SelectionFilter*> filters;
193   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
194   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
195   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
196
197   mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
198   clear();
199
200   //setTarget( FirstTgt );
201 }
202
203 /*!
204   \brief Destructor
205 */
206 SMESHGUI_MinDistance::~SMESHGUI_MinDistance()
207 {
208   erasePreview();
209   if ( myPreview )
210     myPreview->Delete();
211 }
212
213 /*!
214   \brief Event filter
215   \param o object
216   \param o event
217   \return \c true if event is filtered or \c false otherwise
218 */
219 bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e )
220 {
221   if ( e->type() == QEvent::FocusIn ) {
222     if ( o == myFirstTgt )
223       setTarget( FirstTgt );
224     else if ( o == mySecondTgt )
225       setTarget( SecondTgt );
226   }
227   return QWidget::eventFilter( o, e );
228 }
229
230 /*!
231   \brief Setup selection mode depending on the current widget state
232 */
233 void SMESHGUI_MinDistance::updateSelection()
234 {
235   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
236
237   disconnect( selMgr, 0, this, 0 );
238   selMgr->clearFilters();
239   
240   bool nodeMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == NodeTgt ) ||
241                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt );
242   bool elemMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ElementTgt ) ||
243                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt );
244   bool objMode  = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ObjectTgt ) ||
245                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) ||
246                   ( myCurrentTgt == NoTgt );
247
248   if ( nodeMode ) {
249     SMESH::SetPointRepresentation( true );
250     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
251       aViewWindow->SetSelectionMode( NodeSelection );
252   }
253   else if ( elemMode ) {
254     SMESH::SetPointRepresentation( false );
255     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
256       aViewWindow->SetSelectionMode( CellSelection );
257   }
258   else if ( objMode ) {
259     SMESH::SetPointRepresentation( false );
260     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
261       aViewWindow->SetSelectionMode( ActorSelection );
262     selMgr->installFilter( myFilter );
263   }
264
265   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
266
267   if ( myCurrentTgt == FirstTgt )
268     firstEdited();
269   else if ( myCurrentTgt == SecondTgt )
270     secondEdited();
271
272   //selectionChanged();
273 }
274
275 /*!
276   \brief Deactivate widget
277 */
278 void SMESHGUI_MinDistance::deactivate()
279 {
280   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
281 }
282
283 /*!
284   \brief Set current target for selection
285   \param target new target ID
286 */
287 void SMESHGUI_MinDistance::setTarget( int target )
288 {
289   if ( myCurrentTgt != target ) {
290     myCurrentTgt = target;
291     updateSelection();
292   }
293 }
294
295 /*!
296   \brief Erase preview actor
297 */
298 void SMESHGUI_MinDistance::erasePreview()
299 {
300   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
301   if ( aViewWindow && myPreview ) {
302     aViewWindow->RemoveActor( myPreview );
303     aViewWindow->Repaint();
304   }
305 }
306
307 /*!
308   \brief Display preview actor
309 */
310 void SMESHGUI_MinDistance::displayPreview()
311 {
312   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
313   if ( aViewWindow && myPreview ) {
314     aViewWindow->AddActor( myPreview );
315     aViewWindow->Repaint();
316   }
317 }
318
319 /*!
320   \brief Create preview actor
321   \param x1 X coordinate of first point
322   \param y1 X coordinate of first point
323   \param z1 Y coordinate of first point
324   \param x2 Y coordinate of second point
325   \param y2 Z coordinate of second point
326   \param z2 Z coordinate of second point
327 */
328 void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 )
329 {
330   if ( myPreview )
331     myPreview->Delete();
332
333   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
334   // create points
335   vtkPoints* aPoints = vtkPoints::New();
336   aPoints->SetNumberOfPoints( 2 );
337   aPoints->SetPoint( 0, x1, y1, z1 );
338   aPoints->SetPoint( 1, x2, y2, z2 );
339   aGrid->SetPoints( aPoints );
340   aPoints->Delete();
341   // create cells
342   vtkIdList* anIdList = vtkIdList::New();
343   anIdList->SetNumberOfIds( 2 );
344   vtkCellArray* aCells = vtkCellArray::New();
345   aCells->Allocate( 2, 0);
346   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
347   aCellTypesArray->SetNumberOfComponents( 1 );
348   aCellTypesArray->Allocate( 1 );
349   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
350   aCells->InsertNextCell( anIdList );
351   aCellTypesArray->InsertNextValue( VTK_LINE );
352   anIdList->Delete();
353   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
354   aCellLocationsArray->SetNumberOfComponents( 1 );
355   aCellLocationsArray->SetNumberOfTuples( 1 );
356   aCells->InitTraversal();
357   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
358     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
359   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
360   aCellLocationsArray->Delete();
361   aCellTypesArray->Delete();
362   aCells->Delete();
363   // create actor
364   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
365   aMapper->SetInputData( aGrid );
366   aGrid->Delete();
367   myPreview = SALOME_Actor::New();
368   myPreview->PickableOff();
369   myPreview->SetMapper( aMapper );
370   aMapper->Delete();
371   vtkProperty* aProp = vtkProperty::New();
372   aProp->SetRepresentationToWireframe();
373   aProp->SetColor( 250, 0, 250 );
374   aProp->SetPointSize( 5 );
375   aProp->SetLineWidth( 3 );
376   myPreview->SetProperty( aProp );
377   aProp->Delete();
378 }
379
380 /*!
381   \brief Called when selection is changed
382 */
383 void SMESHGUI_MinDistance::selectionChanged()
384 {
385   SUIT_OverrideCursor wc;
386
387   SALOME_ListIO selected;
388   SMESHGUI::selectionMgr()->selectedObjects( selected );
389
390   if ( selected.Extent() == 1 ) {
391     Handle(SALOME_InteractiveObject) IO = selected.First();
392     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
393     if ( !CORBA::is_nil( obj ) ) {
394       if ( myCurrentTgt == FirstTgt ) {
395         myFirstSrc = obj;
396         myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
397         if ( myFirst->checkedId() == ObjectTgt ) {
398           QString aName;
399           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
400           myFirstTgt->setText( aName );
401         }
402         else {
403           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
404           QString ID;
405           int nb = 0;
406           if ( myFirstActor && selector ) {
407             nb = myFirst->checkedId() == NodeTgt ? 
408               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
409               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
410           }
411           if ( nb == 1 )
412             myFirstTgt->setText( ID.trimmed() );
413           else
414             myFirstTgt->clear();
415         }
416       }
417       else if ( myCurrentTgt == SecondTgt ) {
418         mySecondSrc = obj;
419         mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
420         if ( mySecond->checkedId() == ObjectTgt ) {
421           QString aName;
422           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
423           mySecondTgt->setText( aName );
424         }
425         else {
426           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
427           QString ID;
428           int nb = 0;
429           if ( mySecondActor && selector ) {
430             nb = mySecond->checkedId() == NodeTgt ? 
431               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
432               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
433           }
434           if ( nb == 1 )
435             mySecondTgt->setText( ID.trimmed() );
436           else
437             mySecondTgt->clear();
438         }
439       }
440     }
441   }
442   clear();
443 }
444
445 /*!
446   \brief Called when first target mode is changed by the user
447 */
448 void SMESHGUI_MinDistance::firstChanged()
449 {
450   myFirstSrc = SMESH::SMESH_IDSource::_nil();
451   myFirstTgt->clear();
452   myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
453   myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
454   setTarget( FirstTgt );
455   updateSelection();
456   clear();
457 }
458
459 /*!
460   \brief Called when second target mode is changed by the user
461 */
462 void SMESHGUI_MinDistance::secondChanged()
463 {
464   mySecondSrc = SMESH::SMESH_IDSource::_nil();
465   mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
466   mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
467   mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
468   mySecondTgt->clear();
469   setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
470   updateSelection();
471   clear();
472 }
473
474 /*!
475   \brief Called when first target is edited by the user
476 */
477 void SMESHGUI_MinDistance::firstEdited()
478 {
479   setTarget( FirstTgt );
480   if ( sender() == myFirstTgt )
481     clear();
482   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
483   if ( myFirstActor && selector ) {
484     Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
485     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
486       TColStd_MapOfInteger ID;
487       ID.Add( myFirstTgt->text().toLong() );
488       selector->AddOrRemoveIndex( IO, ID, false );
489     }
490     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
491       aViewWindow->highlight( IO, true, true );
492   }
493 }
494
495 /*!
496   \brief Called when second target is edited by the user
497 */
498 void SMESHGUI_MinDistance::secondEdited()
499 {
500   setTarget( SecondTgt );
501   if ( sender() == mySecondTgt )
502     clear();
503   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
504   if ( mySecondActor && selector ) {
505     Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
506     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
507       TColStd_MapOfInteger ID;
508       ID.Add( mySecondTgt->text().toLong() );
509       selector->AddOrRemoveIndex( IO, ID, false );
510     }
511     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
512       aViewWindow->highlight( IO, true, true );
513   }
514 }
515
516 /*!
517   \brief Compute the minimum distance between targets
518 */
519 void SMESHGUI_MinDistance::compute()
520 {
521   SUIT_OverrideCursor wc;
522   SMESH::IDSource_wrap s1;
523   SMESH::IDSource_wrap s2;
524   bool isOrigin = mySecond->checkedId() == OriginTgt;
525
526   // process first target
527   if ( !CORBA::is_nil( myFirstSrc ) ) {
528     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
529       SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
530       long id = myFirstTgt->text().toLong();
531       if ( !CORBA::is_nil( m ) && id ) {
532         SMESH::long_array_var ids = new SMESH::long_array();
533         ids->length( 1 );
534         ids[0] = id;
535         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
536         s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
537       }
538     }
539     else {
540       s1 = myFirstSrc;
541       s1->Register();
542     }
543   }
544
545   // process second target
546   if ( !CORBA::is_nil( mySecondSrc ) ) {
547     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
548       SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
549       long id = mySecondTgt->text().toLong();
550       if ( !CORBA::is_nil( m ) && id ) {
551         SMESH::long_array_var ids = new SMESH::long_array();
552         ids->length( 1 );
553         ids[0] = id;
554         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
555         s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
556       }
557     }
558     else {
559       s2 = mySecondSrc;
560       s2->Register();
561     }
562   }
563
564   if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
565     // compute min distance
566     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
567     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
568     SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
569     measure->UnRegister();
570     myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
571     myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
572     myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
573     myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
574     // update preview actor
575     erasePreview();
576     double x1, y1, z1, x2, y2, z2;
577     SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 );
578     x1 = coord[0]; y1 = coord[1]; z1 = coord[2];
579     if ( isOrigin ) {
580       x2 = y2 = z2 = 0.;
581     }
582     else {
583       coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
584       x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
585     }
586     createPreview( x1, y1, z1, x2, y2, z2 );
587     displayPreview();
588   }
589   else {
590     clear();
591   }
592 }
593
594 /*!
595   \brief Reset the widget to the initial state (nullify result fields)
596 */
597 void SMESHGUI_MinDistance::clear()
598 {
599   myDX->clear();
600   myDY->clear();
601   myDZ->clear();
602   myDistance->clear();
603   erasePreview();
604 }
605
606 /*!
607   \class SMESHGUI_BoundingBox
608   \brief Bounding box measurement widget.
609   
610   Widget to calculate bounding box of the selected object(s).
611 */
612
613 /*!
614   \brief Constructor.
615   \param parent parent widget
616 */
617 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
618 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
619 {
620   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
621   QRadioButton* aObjects  = new QRadioButton( tr( "OBJECTS" ),  aSourceGrp );
622   QRadioButton* aNodes    = new QRadioButton( tr( "NODES" ),    aSourceGrp );
623   QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
624   mySource = new QLineEdit( aSourceGrp );
625   
626   QGridLayout* fl = new QGridLayout( aSourceGrp );
627   fl->setMargin( MARGIN );
628   fl->setSpacing( SPACING );
629   fl->addWidget( aObjects,   0, 0 );
630   fl->addWidget( aNodes,     0, 1 );
631   fl->addWidget( aElements,  0, 2 );
632   fl->addWidget( mySource,   1, 0, 1, 3 );
633   
634   mySourceMode = new QButtonGroup( this );
635   mySourceMode->addButton( aObjects,  ObjectsSrc );
636   mySourceMode->addButton( aNodes,    NodesSrc );
637   mySourceMode->addButton( aElements, ElementsSrc );
638
639   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
640
641   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
642   QLabel* aXminLab = new QLabel( "Xmin", aResults );
643   myXmin           = new QLineEdit( aResults );
644   QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
645   myXmax           = new QLineEdit( aResults );
646   QLabel* aDxLab   = new QLabel( "dX", aResults );
647   myDX             = new QLineEdit( aResults );
648   QLabel* aYminLab = new QLabel( "Ymin", aResults );
649   myYmin           = new QLineEdit( aResults );
650   QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
651   myYmax           = new QLineEdit( aResults );
652   QLabel* aDyLab   = new QLabel( "dY", aResults );
653   myDY             = new QLineEdit( aResults );
654   QLabel* aZminLab = new QLabel( "Zmin", aResults );
655   myZmin           = new QLineEdit( aResults );
656   QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
657   myZmax           = new QLineEdit( aResults );
658   QLabel* aDzLab   = new QLabel( "dZ", aResults );
659   myDZ             = new QLineEdit( aResults );
660
661   QGridLayout* rl  = new QGridLayout( aResults );
662   rl->setMargin( MARGIN );
663   rl->setSpacing( SPACING );
664   rl->addWidget( aXminLab,   0, 0 );
665   rl->addWidget( myXmin,     0, 1 );
666   rl->addWidget( aXmaxLab,   0, 2 );
667   rl->addWidget( myXmax,     0, 3 );
668   rl->addWidget( aDxLab,     0, 4 );
669   rl->addWidget( myDX,       0, 5 );
670   rl->addWidget( aYminLab,   1, 0 );
671   rl->addWidget( myYmin,     1, 1 );
672   rl->addWidget( aYmaxLab,   1, 2 );
673   rl->addWidget( myYmax,     1, 3 );
674   rl->addWidget( aDyLab,     1, 4 );
675   rl->addWidget( myDY,       1, 5 );
676   rl->addWidget( aZminLab,   2, 0 );
677   rl->addWidget( myZmin,     2, 1 );
678   rl->addWidget( aZmaxLab,   2, 2 );
679   rl->addWidget( myZmax,     2, 3 );
680   rl->addWidget( aDzLab,     2, 4 );
681   rl->addWidget( myDZ,       2, 5 );
682
683   QGridLayout* l = new QGridLayout( this );
684   l->setMargin( MARGIN );
685   l->setSpacing( SPACING );
686
687   l->addWidget( aSourceGrp, 0, 0, 1, 2 );
688   l->addWidget( aCompute,   1, 0 );
689   l->addWidget( aResults,   2, 0, 1, 2 );
690   l->setColumnStretch( 1, 5 );
691   l->setRowStretch( 3, 5 );
692
693   aObjects->setChecked( true );
694   myXmin->setReadOnly( true );
695   myXmax->setReadOnly( true );
696   myDX->setReadOnly( true );
697   myYmin->setReadOnly( true );
698   myYmax->setReadOnly( true );
699   myDY->setReadOnly( true );
700   myZmin->setReadOnly( true );
701   myZmax->setReadOnly( true );
702   myDZ->setReadOnly( true );
703
704   myValidator = new SMESHGUI_IdValidator( this );
705
706   connect( mySourceMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( sourceChanged() ) );
707   connect( aCompute,     SIGNAL( clicked() ),             this, SLOT( compute() ) );
708   connect( mySource,     SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
709
710   QList<SUIT_SelectionFilter*> filters;
711   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
712   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
713   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
714
715   clear();
716 }
717
718 /*!
719   \brief Destructor
720 */
721 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
722 {
723   erasePreview();
724   if ( myPreview )
725     myPreview->Delete();
726 }
727
728 /*!
729   \brief Setup selection mode depending on the current widget state
730 */
731 void SMESHGUI_BoundingBox::updateSelection()
732 {
733   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
734
735   disconnect( selMgr, 0, this, 0 );
736   selMgr->clearFilters();
737   
738   bool nodeMode = mySourceMode->checkedId() == NodesSrc;
739   bool elemMode = mySourceMode->checkedId() == ElementsSrc;
740   bool objMode  = mySourceMode->checkedId() == ObjectsSrc;
741
742   if ( nodeMode ) {
743     SMESH::SetPointRepresentation( true );
744     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
745       aViewWindow->SetSelectionMode( NodeSelection );
746   }
747   else if ( elemMode ) {
748     SMESH::SetPointRepresentation( false );
749     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
750       aViewWindow->SetSelectionMode( CellSelection );
751   }
752   else if ( objMode ) {
753     SMESH::SetPointRepresentation( false );
754     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
755       aViewWindow->SetSelectionMode( ActorSelection );
756     selMgr->installFilter( myFilter );
757   }
758
759   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
760
761   sourceEdited();
762
763   if ( mySource->text().isEmpty() )
764     selectionChanged();
765 }
766
767 /*!
768   \brief Deactivate widget
769 */
770 void SMESHGUI_BoundingBox::deactivate()
771 {
772   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
773 }
774
775 /*!
776   \brief Erase preview actor
777 */
778 void SMESHGUI_BoundingBox::erasePreview()
779 {
780   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
781   if ( aViewWindow && myPreview ) {
782     aViewWindow->RemoveActor( myPreview );
783     aViewWindow->Repaint();
784   }
785 }
786
787 /*!
788   \brief Display preview actor
789 */
790 void SMESHGUI_BoundingBox::displayPreview()
791 {
792   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
793   if ( aViewWindow && myPreview ) {
794     aViewWindow->AddActor( myPreview );
795     aViewWindow->Repaint();
796   }
797 }
798
799 /*!
800   \brief Create preview actor
801   \param minX min X coordinate of bounding box
802   \param maxX max X coordinate of bounding box
803   \param minY min Y coordinate of bounding box
804   \param maxY max Y coordinate of bounding box
805   \param minZ min Z coordinate of bounding box
806   \param maxZ max Z coordinate of bounding box
807 */
808 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
809 {
810   if ( myPreview )
811     myPreview->Delete();
812
813   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
814   // create points
815   vtkPoints* aPoints = vtkPoints::New();
816   aPoints->SetNumberOfPoints( 8 );
817   aPoints->SetPoint( 0, minX, minY, minZ );
818   aPoints->SetPoint( 1, maxX, minY, minZ );
819   aPoints->SetPoint( 2, minX, maxY, minZ );
820   aPoints->SetPoint( 3, maxX, maxY, minZ );
821   aPoints->SetPoint( 4, minX, minY, maxZ );
822   aPoints->SetPoint( 5, maxX, minY, maxZ );
823   aPoints->SetPoint( 6, minX, maxY, maxZ );
824   aPoints->SetPoint( 7, maxX, maxY, maxZ );
825   aGrid->SetPoints( aPoints );
826   aPoints->Delete();
827   // create cells
828   // connectivity: 0-1 0-4 0-2 1-5 1-3 2-6 2-3 3-7 4-6 4-5 5-7 6-7
829   vtkIdList* anIdList = vtkIdList::New();
830   anIdList->SetNumberOfIds( 2 );
831   vtkCellArray* aCells = vtkCellArray::New();
832   aCells->Allocate( 2*12, 0);
833   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
834   aCellTypesArray->SetNumberOfComponents( 1 );
835   aCellTypesArray->Allocate( 12 );
836   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
837   aCells->InsertNextCell( anIdList );
838   aCellTypesArray->InsertNextValue( VTK_LINE );
839   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
840   aCells->InsertNextCell( anIdList );
841   aCellTypesArray->InsertNextValue( VTK_LINE );
842   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
843   aCells->InsertNextCell( anIdList );
844   aCellTypesArray->InsertNextValue( VTK_LINE );
845   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
846   aCells->InsertNextCell( anIdList );
847   aCellTypesArray->InsertNextValue( VTK_LINE );
848   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
849   aCells->InsertNextCell( anIdList );
850   aCellTypesArray->InsertNextValue( VTK_LINE );
851   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
852   aCells->InsertNextCell( anIdList );
853   aCellTypesArray->InsertNextValue( VTK_LINE );
854   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
855   aCells->InsertNextCell( anIdList );
856   aCellTypesArray->InsertNextValue( VTK_LINE );
857   anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
858   aCells->InsertNextCell( anIdList );
859   aCellTypesArray->InsertNextValue( VTK_LINE );
860   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
861   aCells->InsertNextCell( anIdList );
862   aCellTypesArray->InsertNextValue( VTK_LINE );
863   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
864   aCells->InsertNextCell( anIdList );
865   aCellTypesArray->InsertNextValue( VTK_LINE );
866   anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
867   aCells->InsertNextCell( anIdList );
868   aCellTypesArray->InsertNextValue( VTK_LINE );
869   anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
870   aCells->InsertNextCell( anIdList );
871   aCellTypesArray->InsertNextValue( VTK_LINE );
872   anIdList->Delete();
873   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
874   aCellLocationsArray->SetNumberOfComponents( 1 );
875   aCellLocationsArray->SetNumberOfTuples( 12 );
876   aCells->InitTraversal();
877   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
878     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
879   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
880   aCellLocationsArray->Delete();
881   aCellTypesArray->Delete();
882   aCells->Delete();
883   // create actor
884   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
885   aMapper->SetInputData( aGrid );
886   aGrid->Delete();
887   myPreview = SALOME_Actor::New();
888   myPreview->PickableOff();
889   myPreview->SetMapper( aMapper );
890   aMapper->Delete();
891   vtkProperty* aProp = vtkProperty::New();
892   aProp->SetRepresentationToWireframe();
893   aProp->SetColor( 250, 0, 250 );
894   aProp->SetPointSize( 5 );
895   aProp->SetLineWidth( 3 );
896   myPreview->SetProperty( aProp );
897   aProp->Delete();
898 }
899
900 /*!
901   \brief Called when selection is changed
902 */
903 void SMESHGUI_BoundingBox::selectionChanged()
904 {
905   SUIT_OverrideCursor wc;
906
907   SALOME_ListIO selected;
908   SMESHGUI::selectionMgr()->selectedObjects( selected );
909
910   if ( selected.Extent() == 1 ) {
911     Handle(SALOME_InteractiveObject) IO = selected.First();
912     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
913     if ( !CORBA::is_nil( obj ) ) {
914       mySrc.clear();
915       mySrc.append( obj );
916       myActor = SMESH::FindActorByEntry( IO->getEntry() );
917       if ( mySourceMode->checkedId() == ObjectsSrc ) {
918         QString aName;
919         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
920         mySource->setText( aName );
921       }
922       else {
923         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
924         QString ID;
925         int nb = 0;
926         if ( myActor && selector ) {
927           nb = mySourceMode->checkedId() == NodesSrc ? 
928             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
929             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
930         }
931         if ( nb > 0 ) {
932           myIDs = ID.trimmed();
933           if ( nb < MAX_NB_FOR_EDITOR ) {
934             mySource->setReadOnly( false );
935             if ( mySource->validator() != myValidator )
936               mySource->setValidator( myValidator );
937             mySource->setText( ID.trimmed() );
938           }
939           else {
940             mySource->setReadOnly( true );
941             mySource->setValidator( 0 );
942             mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
943                                .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
944           }
945         }
946         else {
947           myIDs = "";
948           mySource->clear();
949           mySource->setReadOnly( false );
950           mySource->setValidator( myValidator );
951         }
952       }
953     }
954   }
955   else if ( selected.Extent() > 1 ) {
956     myIDs = "";
957     SALOME_ListIteratorOfListIO It( selected );
958     mySrc.clear();
959     myActor = 0;
960     if ( mySourceMode->checkedId() == ObjectsSrc ) {
961       for( ; It.More(); It.Next()){
962         Handle(SALOME_InteractiveObject) IO = It.Value();
963         SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
964         if ( !CORBA::is_nil( obj ) ) {
965           mySrc.append( obj );
966         }
967       }
968       QString aName;
969       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
970       mySource->setText( aName );
971     }
972     else {
973       mySource->clear();
974     }
975   }
976   clear();
977 }
978
979 /*!
980   \brief Called when source mode is changed by the user
981 */
982 void SMESHGUI_BoundingBox::sourceChanged()
983 {
984   myIDs = "";
985   mySource->clear();
986   mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
987   mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
988   updateSelection();
989   clear();
990 }
991
992 /*!
993   \brief Called when source mode is edited by the user
994 */
995 void SMESHGUI_BoundingBox::sourceEdited()
996 {
997   if ( sender() == mySource )
998     clear();
999   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1000   if ( myActor && selector ) {
1001     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1002     if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1003       TColStd_MapOfInteger ID;
1004       if ( !mySource->isReadOnly() )
1005         myIDs = mySource->text();
1006       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1007       foreach ( QString id, ids )
1008         ID.Add( id.trimmed().toLong() );
1009       selector->AddOrRemoveIndex( IO, ID, false );
1010     }
1011     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1012       aViewWindow->highlight( IO, true, true );
1013   }
1014 }
1015
1016 /*!
1017   \brief Calculate bounding box of the selected object(s)
1018 */
1019 void SMESHGUI_BoundingBox::compute()
1020 {
1021   SUIT_OverrideCursor wc;
1022   SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1023   if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1024     if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1025       SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1026       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1027       if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1028         SMESH::long_array_var ids_in = new SMESH::long_array();
1029         ids_in->length( ids.count() );
1030         for( int i = 0; i < ids.count(); i++ )
1031           ids_in[i] = ids[i].trimmed().toLong();
1032         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1033         SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); 
1034         srcList->length( 1 );
1035         srcList[0] = s;
1036       }
1037     }
1038   }
1039   else {
1040     srcList->length( mySrc.count() );
1041     for( int i = 0; i < mySrc.count(); i++ ) {
1042       srcList[i] = mySrc[i];
1043       mySrc[i]->Register();
1044     }
1045   }
1046   if ( srcList->length() > 0 ) {
1047     // compute bounding box
1048     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1049     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1050     SMESH::Measure result = measure->BoundingBox( srcList.in() );
1051     SALOME::UnRegister( srcList );
1052     measure->UnRegister();
1053     myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1054     myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1055     myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1056     myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1057     myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1058     myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1059     myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1060     myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1061     myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1062     // update preview actor
1063     erasePreview();
1064     createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1065     displayPreview();
1066   }
1067   else {
1068     clear();
1069   }
1070 }
1071
1072 /*!
1073   \brief Reset the widget to the initial state (nullify result fields)
1074 */
1075 void SMESHGUI_BoundingBox::clear()
1076 {
1077   myXmin->clear();
1078   myXmax->clear();
1079   myDX->clear();
1080   myYmin->clear();
1081   myYmax->clear();
1082   myDY->clear();
1083   myZmin->clear();
1084   myZmax->clear();
1085   myDZ->clear();
1086   erasePreview();
1087 }
1088
1089 /*!
1090   \class SMESHGUI_BasicProperties
1091   \brief basic properties measurement widget.
1092   
1093   Widget to calculate length, area or volume for the selected object(s).
1094 */
1095
1096 /*!
1097   \brief Constructor.
1098   \param parent parent widget
1099 */
1100 SMESHGUI_BasicProperties::SMESHGUI_BasicProperties( QWidget* parent )
1101 : QWidget( parent )
1102 {
1103   // Property (length, area or volume)
1104   QGroupBox* aPropertyGrp = new QGroupBox( tr( "PROPERTY" ), this );
1105
1106   QRadioButton* aLength = new QRadioButton( tr( "LENGTH" ), aPropertyGrp );
1107   QRadioButton* anArea = new QRadioButton( tr( "AREA" ), aPropertyGrp );
1108   QRadioButton* aVolume = new QRadioButton( tr( "VOLUME" ), aPropertyGrp );
1109
1110   myMode = new QButtonGroup( this );
1111   myMode->addButton( aLength, Length );
1112   myMode->addButton( anArea, Area );
1113   myMode->addButton( aVolume, Volume );
1114
1115   QHBoxLayout* aPropertyLayout = new QHBoxLayout;
1116   aPropertyLayout->addWidget( aLength );
1117   aPropertyLayout->addWidget( anArea );
1118   aPropertyLayout->addWidget( aVolume );
1119
1120   aPropertyGrp->setLayout( aPropertyLayout );
1121
1122   // Source object
1123   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE_MESH_SUBMESH_GROUP" ), this );
1124
1125   mySource = new QLineEdit( aSourceGrp );
1126   mySource->setReadOnly( true );
1127     
1128   QHBoxLayout* aSourceLayout = new QHBoxLayout;
1129   aSourceLayout->addWidget( mySource );
1130   
1131   aSourceGrp->setLayout( aSourceLayout );
1132
1133   // Compute button
1134   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1135
1136   // Result of computation (length, area or volume)
1137   myResultGrp = new QGroupBox( this );
1138
1139   myResult = new QLineEdit;
1140   myResult->setReadOnly( true );
1141
1142   QHBoxLayout* aResultLayout = new QHBoxLayout;
1143   aResultLayout->addWidget( myResult );
1144   
1145   myResultGrp->setLayout( aResultLayout );
1146
1147   // Layout
1148   QGridLayout* aMainLayout = new QGridLayout( this );
1149   aMainLayout->setMargin( MARGIN );
1150   aMainLayout->setSpacing( SPACING );
1151
1152   aMainLayout->addWidget( aPropertyGrp, 0, 0, 1, 2 );
1153   aMainLayout->addWidget( aSourceGrp, 1, 0, 1, 2 );
1154   aMainLayout->addWidget( aCompute,   2, 0 );
1155   aMainLayout->addWidget( myResultGrp, 3, 0, 1, 2 );
1156   aMainLayout->setColumnStretch( 1, 5 );
1157   aMainLayout->setRowStretch( 4, 5 );
1158
1159   // Initial state
1160   setMode( Length );
1161   
1162   // Connections
1163   connect( myMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( modeChanged( int ) ) );
1164   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
1165   
1166   // Selection filter
1167   QList<SUIT_SelectionFilter*> filters;
1168   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
1169   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
1170   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
1171 }
1172
1173 /*!
1174   \brief Destructor
1175 */
1176 SMESHGUI_BasicProperties::~SMESHGUI_BasicProperties()
1177 {
1178 }
1179
1180 /*!
1181   \brief Sets the measurement mode.
1182   \param theMode the mode to set (length, area or volume meausurement)
1183 */
1184 void SMESHGUI_BasicProperties::setMode( const Mode theMode )
1185 {
1186   QRadioButton* aButton = qobject_cast<QRadioButton*>( myMode->button( theMode ) );
1187   if ( aButton ) {
1188     aButton->setChecked( true );
1189     modeChanged( theMode );
1190   }
1191 }
1192
1193 /*!
1194   \brief Setup the selection mode.
1195 */
1196 void SMESHGUI_BasicProperties::updateSelection()
1197 {
1198   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1199
1200   disconnect( selMgr, 0, this, 0 );
1201   selMgr->clearFilters();
1202   
1203   SMESH::SetPointRepresentation( false );
1204   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
1205     aViewWindow->SetSelectionMode( ActorSelection );
1206   }
1207   selMgr->installFilter( myFilter );
1208   
1209   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
1210
1211   if ( mySource->text().isEmpty() )
1212     selectionChanged();
1213 }
1214
1215 /*!
1216   \brief Deactivate widget
1217 */
1218 void SMESHGUI_BasicProperties::deactivate()
1219 {
1220   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
1221 }
1222
1223 /*!
1224   \brief Called when selection is changed
1225 */
1226 void SMESHGUI_BasicProperties::selectionChanged()
1227 {
1228   SUIT_OverrideCursor wc;
1229
1230   SALOME_ListIO selected;
1231   SMESHGUI::selectionMgr()->selectedObjects( selected );
1232
1233   if ( selected.Extent() == 1 ) {
1234     Handle(SALOME_InteractiveObject) IO = selected.First();
1235     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1236     if ( !CORBA::is_nil( obj ) ) {
1237       mySrc = obj;
1238
1239       QString aName;
1240       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
1241       mySource->setText( aName );
1242     }
1243   }
1244
1245   clear();
1246 }
1247
1248 /*!
1249   \brief Called when the measurement mode selection is changed.
1250   \param theMode the selected mode
1251 */
1252 void SMESHGUI_BasicProperties::modeChanged( int theMode )
1253 {
1254   clear();
1255
1256   if ( theMode == Length ) {
1257     myResultGrp->setTitle( tr("LENGTH") );
1258   } else if ( theMode == Area ) {
1259     myResultGrp->setTitle( tr("AREA") );
1260   } else if ( theMode == Volume ) {
1261     myResultGrp->setTitle( tr("VOLUME") );
1262   }
1263 }
1264
1265 /*!
1266   \brief Calculate length, area or volume for the selected object(s)
1267 */
1268 void SMESHGUI_BasicProperties::compute()
1269 {
1270   SUIT_OverrideCursor wc;
1271
1272   SMESH::SMESH_IDSource_var source;
1273
1274   if ( !CORBA::is_nil( mySrc ) ) {
1275     // compute
1276     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1277     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1278
1279     double result = 0;
1280
1281     if ( myMode->checkedId() == Length ) {
1282       result = measure->Length( mySrc.in() );
1283     } else if ( myMode->checkedId() == Area ) {
1284       result = measure->Area( mySrc.in() );
1285     } else if ( myMode->checkedId() == Volume ) {
1286       result = measure->Volume( mySrc.in() );
1287     }
1288     
1289     measure->UnRegister();
1290
1291     myResult->setText( QString::number( result, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1292   } else {
1293     clear();
1294   }
1295 }
1296
1297 /*!
1298   \brief Reset the widget to the initial state (nullify the result field)
1299 */
1300 void SMESHGUI_BasicProperties::clear()
1301 {
1302   myResult->clear();
1303 }
1304
1305 /*!
1306   \class SMESHGUI_MeshInfoDlg
1307   \brief Centralized dialog box for the measurements
1308 */
1309
1310 /*!
1311   \brief Constructor
1312   \param parent parent widget
1313   \param page specifies the dialog page to be shown at the start-up
1314 */
1315 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1316 : QDialog( parent )
1317 {
1318   setModal( false );
1319   setAttribute( Qt::WA_DeleteOnClose, true );
1320   setWindowTitle( tr( "MEASUREMENTS" ) );
1321   setSizeGripEnabled( true );
1322
1323   SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1324
1325   myTabWidget = new QTabWidget( this );
1326
1327   // min distance
1328
1329   myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1330   int aMinDistInd = myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1331
1332   // bounding box
1333   
1334   myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1335   int aBndBoxInd = myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1336
1337   // basic properties
1338   
1339   myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
1340   int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
1341
1342   // buttons
1343   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1344   okBtn->setAutoDefault( true );
1345   okBtn->setDefault( true );
1346   okBtn->setFocus();
1347   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1348   helpBtn->setAutoDefault( true );
1349
1350   QHBoxLayout* btnLayout = new QHBoxLayout;
1351   btnLayout->setSpacing( SPACING );
1352   btnLayout->setMargin( 0 );
1353   btnLayout->addWidget( okBtn );
1354   btnLayout->addStretch( 10 );
1355   btnLayout->addWidget( helpBtn );
1356
1357   QVBoxLayout* l = new QVBoxLayout ( this );
1358   l->setMargin( MARGIN );
1359   l->setSpacing( SPACING );
1360   l->addWidget( myTabWidget );
1361   l->addStretch();
1362   l->addLayout( btnLayout );
1363
1364   int anInd = -1;
1365   if ( page == MinDistance ) {
1366     anInd = aMinDistInd;
1367   } else if ( page == BoundingBox ) {
1368     anInd = aBndBoxInd;
1369   } else if ( page == Length || page == Area || page == Volume ) {
1370     myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
1371     anInd = aBasicPropInd;
1372   }
1373
1374   if ( anInd >= 0 ) {
1375     myTabWidget->setCurrentIndex( anInd );
1376   }
1377
1378   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
1379   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
1380   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
1381   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1382   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
1383
1384   updateSelection();
1385 }
1386
1387 /*!
1388   \brief Destructor
1389 */
1390 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1391 {
1392 }
1393
1394 /*!
1395   \brief Perform clean-up actions on the dialog box closing.
1396 */
1397 void SMESHGUI_MeasureDlg::reject()
1398 {
1399   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1400   selMgr->clearFilters();
1401   SMESH::SetPointRepresentation( false );
1402   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1403     aViewWindow->SetSelectionMode( ActorSelection );
1404   QDialog::reject();
1405 }
1406
1407 /*!
1408   \brief Process keyboard event
1409   \param e key press event
1410 */
1411 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1412 {
1413   QDialog::keyPressEvent( e );
1414   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1415     e->accept();
1416     help();
1417   }
1418 }
1419
1420 /*!
1421   \brief Reactivate dialog box, when mouse pointer goes into it.
1422 */
1423 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1424 {
1425   activate();
1426 }
1427
1428 /*!
1429   \brief Setup selection mode depending on the current dialog box state.
1430 */
1431 void SMESHGUI_MeasureDlg::updateSelection()
1432 {
1433   if ( myTabWidget->currentIndex() == MinDistance )
1434     myMinDist->updateSelection();
1435   else if ( myTabWidget->currentIndex() == BoundingBox )
1436     myBndBox->updateSelection();
1437   else {
1438     myBndBox->erasePreview();
1439     myBasicProps->updateSelection();
1440   }
1441 }
1442
1443 /*!
1444   \brief Show help page
1445 */
1446 void SMESHGUI_MeasureDlg::help()
1447 {
1448   QString aHelpFile;
1449   if ( myTabWidget->currentIndex() == MinDistance ) {
1450     aHelpFile = "measurements_page.html#min_distance_anchor";
1451   } else if ( myTabWidget->currentIndex() == BoundingBox ) {
1452     aHelpFile = "measurements_page.html#bounding_box_anchor";
1453   } else {
1454     aHelpFile = "measurements_page.html#basic_properties_anchor";
1455   }
1456
1457   SMESH::ShowHelpFile( aHelpFile );
1458 }
1459
1460 /*!
1461   \brief Activate dialog box
1462 */
1463 void SMESHGUI_MeasureDlg::activate()
1464 {
1465   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1466   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1467   myTabWidget->setEnabled( true );
1468   updateSelection();
1469 }
1470
1471 /*!
1472   \brief Deactivate dialog box
1473 */
1474 void SMESHGUI_MeasureDlg::deactivate()
1475 {
1476   myBasicProps->deactivate();
1477   myMinDist->deactivate();
1478   myBndBox->deactivate();
1479   myTabWidget->setEnabled( false );
1480   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1481 }