Salome HOME
23627: [IMACS] ASERIS: project point to the mesh and create a slot
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_Measurements.cxx
1 // Copyright (C) 2007-2016  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_MeshEditPreview.h"
32 #include "SMESHGUI_VTKUtils.h"
33 #include <SMESH_TypeFilter.hxx>
34 #include <SMESH_MeshAlgos.hxx>
35 #include <SMESH_LogicalFilter.hxx>
36 #include <SMDS_Mesh.hxx>
37 #include <SMDS_MeshNode.hxx>
38
39 #include <LightApp_SelectionMgr.h>
40 #include <SUIT_OverrideCursor.h>
41 #include <SUIT_ResourceMgr.h>
42 #include <SVTK_ViewWindow.h>
43 #include <SALOME_ListIO.hxx>
44
45 #include <QButtonGroup>
46 #include <QGridLayout>
47 #include <QGroupBox>
48 #include <QHBoxLayout>
49 #include <QKeyEvent>
50 #include <QLabel>
51 #include <QLineEdit>
52 #include <QPushButton>
53 #include <QRadioButton>
54 #include <QTabWidget>
55 #include <QVBoxLayout>
56
57 #include <vtkPoints.h>
58 #include <vtkUnstructuredGrid.h>
59 #include <vtkIdList.h>
60 #include <vtkCellArray.h>
61 #include <vtkUnsignedCharArray.h>
62 #include <vtkDataSetMapper.h>
63 #include <VTKViewer_CellLocationsArray.h>
64 #include <vtkProperty.h>
65
66 #include <ElCLib.hxx>
67
68 #include <SALOMEconfig.h>
69 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
70 #include CORBA_SERVER_HEADER(SMESH_Measurements)
71
72 const int SPACING = 6;            // layout spacing
73 const int MARGIN  = 9;            // layout margin
74 const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field
75
76 // Uncomment as soon as elements are supported by Min Distance operation
77 //#define MINDIST_ENABLE_ELEMENT
78
79 // Uncomment as soon as objects are supported by Min Distance operation
80 //#define MINDIST_ENABLE_OBJECT
81
82 /*!
83   \class SMESHGUI_MinDistance
84   \brief Minimum distance measurement widget.
85   
86   Widget to calculate minimum distance between two objects.
87 */
88
89 /*!
90   \brief Constructor.
91   \param parent parent widget
92 */
93 SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
94 : QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 )
95 {
96   QGroupBox*    aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this );
97   QRadioButton* aFNode       = new QRadioButton( tr( "NODE" ),    aFirstTgtGrp );
98   QRadioButton* aFElem       = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp );
99   QRadioButton* aFObject     = new QRadioButton( tr( "OBJECT" ),  aFirstTgtGrp );
100   myFirstTgt                 = new QLineEdit( aFirstTgtGrp );
101
102   QGridLayout* fl = new QGridLayout( aFirstTgtGrp );
103   fl->setMargin( MARGIN );
104   fl->setSpacing( SPACING );
105   fl->addWidget( aFNode,     0, 0 );
106   fl->addWidget( aFElem,     0, 1 );
107   fl->addWidget( aFObject,   0, 2 );
108   fl->addWidget( myFirstTgt, 1, 0, 1, 3 );
109
110   myFirst = new QButtonGroup( this );
111   myFirst->addButton( aFNode,   NodeTgt );
112   myFirst->addButton( aFElem,   ElementTgt );
113   myFirst->addButton( aFObject, ObjectTgt );
114
115   QGroupBox*    aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this );
116   QRadioButton* aSOrigin      = new QRadioButton( tr( "ORIGIN" ),  aSecondTgtGrp );
117   QRadioButton* aSNode        = new QRadioButton( tr( "NODE" ),    aSecondTgtGrp );
118   QRadioButton* aSElem        = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp );
119   QRadioButton* aSObject      = new QRadioButton( tr( "OBJECT" ),  aSecondTgtGrp );
120   mySecondTgt                 = new QLineEdit( aSecondTgtGrp );
121
122   QGridLayout* sl = new QGridLayout( aSecondTgtGrp );
123   sl->setMargin( MARGIN );
124   sl->setSpacing( SPACING );
125   sl->addWidget( aSOrigin,   0, 0 );
126   sl->addWidget( aSNode,     0, 1 );
127   sl->addWidget( aSElem,     0, 2 );
128   sl->addWidget( aSObject,   0, 3 );
129   sl->addWidget( mySecondTgt, 1, 0, 1, 4 );
130
131   mySecond = new QButtonGroup( this );
132   mySecond->addButton( aSOrigin, OriginTgt );
133   mySecond->addButton( aSNode,   NodeTgt );
134   mySecond->addButton( aSElem,   ElementTgt );
135   mySecond->addButton( aSObject, ObjectTgt );
136
137   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
138   
139   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
140   QLabel* aDxLab   = new QLabel( "dX", aResults );
141   myDX             = new QLineEdit( aResults );
142   QLabel* aDyLab   = new QLabel( "dY", aResults );
143   myDY             = new QLineEdit( aResults );
144   QLabel* aDzLab   = new QLabel( "dZ", aResults );
145   myDZ             = new QLineEdit( aResults );
146   QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults );
147   myDistance       = new QLineEdit( aResults );
148
149   QGridLayout* rl = new QGridLayout( aResults );
150   rl->setMargin( MARGIN );
151   rl->setSpacing( SPACING );
152   rl->addWidget( aDxLab,     0, 0 );
153   rl->addWidget( myDX,       0, 1 );
154   rl->addWidget( aDyLab,     1, 0 );
155   rl->addWidget( myDY,       1, 1 );
156   rl->addWidget( aDzLab,     2, 0 );
157   rl->addWidget( myDZ,       2, 1 );
158   rl->addWidget( aDistLab,   0, 2 );
159   rl->addWidget( myDistance, 0, 3 );
160
161   QGridLayout* l = new QGridLayout( this );
162   l->setMargin( MARGIN );
163   l->setSpacing( SPACING );
164
165   l->addWidget( aFirstTgtGrp,  0, 0, 1, 2 );
166   l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 );
167   l->addWidget( aCompute,      2, 0 );
168   l->addWidget( aResults,      3, 0, 1, 2 );
169   l->setColumnStretch( 1, 5 );
170   l->setRowStretch( 4, 5 );
171
172   aFNode->setChecked( true );
173   aSOrigin->setChecked( true );
174 #ifndef MINDIST_ENABLE_ELEMENT
175   aFElem->setEnabled( false );   // NOT AVAILABLE YET
176   //aSElem->setEnabled( false );   // NOT AVAILABLE YET
177 #endif
178 #ifndef MINDIST_ENABLE_OBJECT
179   aFObject->setEnabled( false ); // NOT AVAILABLE YET
180   //aSObject->setEnabled( false ); // NOT AVAILABLE YET
181 #endif
182   myDX->setReadOnly( true );
183   myDY->setReadOnly( true );
184   myDZ->setReadOnly( true );
185   myDistance->setReadOnly( true );
186
187   myValidator = new SMESHGUI_IdValidator( this, 1 );
188
189   myFirstTgt->installEventFilter( this );
190   mySecondTgt->installEventFilter( this );
191
192   connect( myFirst,     SIGNAL( buttonClicked( int ) ),  this, SLOT( firstChanged() ) );
193   connect( mySecond,    SIGNAL( buttonClicked( int ) ),  this, SLOT( secondChanged() ) );
194   connect( aCompute,    SIGNAL( clicked() ),             this, SLOT( compute() ) );
195   connect( myFirstTgt,  SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) );
196   connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) );
197
198   QList<SUIT_SelectionFilter*> filters;
199   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
200   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
201   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
202
203   mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
204   clear();
205
206   //setTarget( FirstTgt );
207   selectionChanged();
208 }
209
210 /*!
211   \brief Destructor
212 */
213 SMESHGUI_MinDistance::~SMESHGUI_MinDistance()
214 {
215   erasePreview();
216   if ( myPreview )
217     myPreview->Delete();
218 }
219
220 /*!
221   \brief Event filter
222   \param o object
223   \param o event
224   \return \c true if event is filtered or \c false otherwise
225 */
226 bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e )
227 {
228   if ( e->type() == QEvent::FocusIn ) {
229     if ( o == myFirstTgt )
230       setTarget( FirstTgt );
231     else if ( o == mySecondTgt )
232       setTarget( SecondTgt );
233   }
234   return QWidget::eventFilter( o, e );
235 }
236
237 /*!
238   \brief Setup selection mode depending on the current widget state
239 */
240 void SMESHGUI_MinDistance::updateSelection()
241 {
242   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
243
244   disconnect( selMgr, 0, this, 0 );
245   selMgr->clearFilters();
246   
247   bool nodeMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == NodeTgt ) ||
248                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt );
249   bool elemMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ElementTgt ) ||
250                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt );
251   bool objMode  = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ObjectTgt ) ||
252                   ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) ||
253                   ( myCurrentTgt == NoTgt );
254
255   if ( nodeMode ) {
256     SMESH::SetPointRepresentation( true );
257     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
258       aViewWindow->SetSelectionMode( NodeSelection );
259   }
260   else if ( elemMode ) {
261     SMESH::SetPointRepresentation( false );
262     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
263       aViewWindow->SetSelectionMode( CellSelection );
264   }
265   else if ( objMode ) {
266     SMESH::SetPointRepresentation( false );
267     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
268       aViewWindow->SetSelectionMode( ActorSelection );
269     selMgr->installFilter( myFilter );
270   }
271
272   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
273
274   if ( myCurrentTgt == FirstTgt )
275     firstEdited();
276   else if ( myCurrentTgt == SecondTgt )
277     secondEdited();
278
279   //selectionChanged();
280 }
281
282 /*!
283   \brief Deactivate widget
284 */
285 void SMESHGUI_MinDistance::deactivate()
286 {
287   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
288 }
289
290 /*!
291   \brief Set current target for selection
292   \param target new target ID
293 */
294 void SMESHGUI_MinDistance::setTarget( int target )
295 {
296   if ( myCurrentTgt != target ) {
297     myCurrentTgt = target;
298     updateSelection();
299   }
300 }
301
302 /*!
303   \brief Erase preview actor
304 */
305 void SMESHGUI_MinDistance::erasePreview()
306 {
307   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
308   if ( aViewWindow && myPreview ) {
309     aViewWindow->RemoveActor( myPreview );
310     aViewWindow->Repaint();
311   }
312 }
313
314 /*!
315   \brief Display preview actor
316 */
317 void SMESHGUI_MinDistance::displayPreview()
318 {
319   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
320   if ( aViewWindow && myPreview ) {
321     aViewWindow->AddActor( myPreview );
322     aViewWindow->Repaint();
323   }
324 }
325
326 /*!
327   \brief Create preview actor
328   \param x1 X coordinate of first point
329   \param y1 X coordinate of first point
330   \param z1 Y coordinate of first point
331   \param x2 Y coordinate of second point
332   \param y2 Z coordinate of second point
333   \param z2 Z coordinate of second point
334 */
335 void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 )
336 {
337   if ( myPreview )
338     myPreview->Delete();
339
340   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
341   // create points
342   vtkPoints* aPoints = vtkPoints::New();
343   aPoints->SetNumberOfPoints( 2 );
344   aPoints->SetPoint( 0, x1, y1, z1 );
345   aPoints->SetPoint( 1, x2, y2, z2 );
346   aGrid->SetPoints( aPoints );
347   aPoints->Delete();
348   // create cells
349   vtkIdList* anIdList = vtkIdList::New();
350   anIdList->SetNumberOfIds( 2 );
351   vtkCellArray* aCells = vtkCellArray::New();
352   aCells->Allocate( 2, 0);
353   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
354   aCellTypesArray->SetNumberOfComponents( 1 );
355   aCellTypesArray->Allocate( 1 );
356   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
357   aCells->InsertNextCell( anIdList );
358   aCellTypesArray->InsertNextValue( VTK_LINE );
359   anIdList->Delete();
360   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
361   aCellLocationsArray->SetNumberOfComponents( 1 );
362   aCellLocationsArray->SetNumberOfTuples( 1 );
363   aCells->InitTraversal();
364   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
365     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
366   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
367   aCellLocationsArray->Delete();
368   aCellTypesArray->Delete();
369   aCells->Delete();
370   // create actor
371   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
372   aMapper->SetInputData( aGrid );
373   aGrid->Delete();
374   myPreview = SALOME_Actor::New();
375   myPreview->PickableOff();
376   myPreview->SetMapper( aMapper );
377   myPreview->SetResolveCoincidentTopology(true);
378   aMapper->Delete();
379   vtkProperty* aProp = vtkProperty::New();
380   aProp->SetRepresentationToWireframe();
381   aProp->SetColor( 250, 0, 250 );
382   aProp->SetPointSize( 5 );
383   aProp->SetLineWidth( 3 );
384   myPreview->SetProperty( aProp );
385   aProp->Delete();
386 }
387
388 /*!
389   \brief Called when selection is changed
390 */
391 void SMESHGUI_MinDistance::selectionChanged()
392 {
393   SUIT_OverrideCursor wc;
394
395   SALOME_ListIO selected;
396   SMESHGUI::selectionMgr()->selectedObjects( selected );
397
398   if ( selected.Extent() == 1 ) {
399     Handle(SALOME_InteractiveObject) IO = selected.First();
400     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
401     if ( !CORBA::is_nil( obj ) ) {
402       if ( myCurrentTgt == FirstTgt ) {
403         myFirstSrc = obj;
404         myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
405         if ( myFirst->checkedId() == ObjectTgt ) {
406           QString aName;
407           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
408           myFirstTgt->setText( aName );
409         }
410         else {
411           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
412           QString ID;
413           int nb = 0;
414           if ( myFirstActor && selector ) {
415             nb = myFirst->checkedId() == NodeTgt ? 
416               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
417               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
418           }
419           if ( nb == 1 )
420             myFirstTgt->setText( ID.trimmed() );
421           else
422             myFirstTgt->clear();
423         }
424       }
425       else if ( myCurrentTgt == SecondTgt ) {
426         mySecondSrc = obj;
427         mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
428         if ( mySecond->checkedId() == ObjectTgt ) {
429           QString aName;
430           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
431           mySecondTgt->setText( aName );
432         }
433         else {
434           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
435           QString ID;
436           int nb = 0;
437           if ( mySecondActor && selector ) {
438             nb = mySecond->checkedId() == NodeTgt ? 
439               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
440               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
441           }
442           if ( nb == 1 )
443             mySecondTgt->setText( ID.trimmed() );
444           else
445             mySecondTgt->clear();
446         }
447       }
448     }
449   }
450   clear();
451 }
452
453 /*!
454   \brief Called when first target mode is changed by the user
455 */
456 void SMESHGUI_MinDistance::firstChanged()
457 {
458   myFirstSrc = SMESH::SMESH_IDSource::_nil();
459   myFirstTgt->clear();
460   myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
461   myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
462   setTarget( FirstTgt );
463   updateSelection();
464   clear();
465 }
466
467 /*!
468   \brief Called when second target mode is changed by the user
469 */
470 void SMESHGUI_MinDistance::secondChanged()
471 {
472   mySecondSrc = SMESH::SMESH_IDSource::_nil();
473   mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
474   mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
475   mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
476   mySecondTgt->clear();
477   setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
478   updateSelection();
479   clear();
480 }
481
482 /*!
483   \brief Called when first target is edited by the user
484 */
485 void SMESHGUI_MinDistance::firstEdited()
486 {
487   setTarget( FirstTgt );
488   if ( sender() == myFirstTgt )
489     clear();
490   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
491   if ( myFirstActor && selector ) {
492     Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
493     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
494       TColStd_MapOfInteger ID;
495       ID.Add( myFirstTgt->text().toLong() );
496       selector->AddOrRemoveIndex( IO, ID, false );
497     }
498     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
499       aViewWindow->highlight( IO, true, true );
500   }
501 }
502
503 /*!
504   \brief Called when second target is edited by the user
505 */
506 void SMESHGUI_MinDistance::secondEdited()
507 {
508   setTarget( SecondTgt );
509   if ( sender() == mySecondTgt )
510     clear();
511   QString text = mySecondTgt->text();
512   if ( !mySecondActor )
513   {
514     selectionChanged();
515     mySecondTgt->setText( text );
516   }
517   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
518   if ( mySecondActor && selector ) {
519     Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
520     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
521       if ( !text.isEmpty() ) {
522         TColStd_MapOfInteger ID;
523         ID.Add( text.toLong() );
524         selector->AddOrRemoveIndex( IO, ID, false );
525       }
526     }
527     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
528       aViewWindow->highlight( IO, true, true );
529   }
530 }
531
532 /*!
533   \brief Compute the minimum distance between targets
534 */
535 void SMESHGUI_MinDistance::compute()
536 {
537   SUIT_OverrideCursor wc;
538   SMESH::IDSource_wrap s1;
539   SMESH::IDSource_wrap s2;
540   bool isOrigin = mySecond->checkedId() == OriginTgt;
541
542   // process first target
543   if ( !CORBA::is_nil( myFirstSrc ) ) {
544     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
545       SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
546       long id = myFirstTgt->text().toLong();
547       if ( !CORBA::is_nil( m ) && id ) {
548         SMESH::long_array_var ids = new SMESH::long_array();
549         ids->length( 1 );
550         ids[0] = id;
551         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
552         s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
553       }
554     }
555     else {
556       s1 = myFirstSrc;
557       s1->Register();
558     }
559   }
560
561   // process second target
562   if ( !CORBA::is_nil( mySecondSrc ) ) {
563     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
564       SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
565       long id = mySecondTgt->text().toLong();
566       if ( !CORBA::is_nil( m ) && id ) {
567         SMESH::long_array_var ids = new SMESH::long_array();
568         ids->length( 1 );
569         ids[0] = id;
570         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
571         s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
572       }
573     }
574     else {
575       s2 = mySecondSrc;
576       s2->Register();
577     }
578   }
579
580   if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
581     // compute min distance
582     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
583     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
584     SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
585     measure->UnRegister();
586     myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
587     myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
588     myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
589     myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
590     // update preview actor
591     erasePreview();
592     double x1, y1, z1, x2, y2, z2;
593     SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 );
594     x1 = coord[0]; y1 = coord[1]; z1 = coord[2];
595     if ( isOrigin ) {
596       x2 = y2 = z2 = 0.;
597     }
598     else if ( mySecond->checkedId() == NodeTgt ) {
599       coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
600       x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
601     }
602     else
603     {
604       x2 = result.maxX; y2 = result.maxY; z2 = result.maxZ; 
605     }
606     createPreview( x1, y1, z1, x2, y2, z2 );
607     displayPreview();
608   }
609   else {
610     clear();
611   }
612 }
613
614 /*!
615   \brief Reset the widget to the initial state (nullify result fields)
616 */
617 void SMESHGUI_MinDistance::clear()
618 {
619   myDX->clear();
620   myDY->clear();
621   myDZ->clear();
622   myDistance->clear();
623   erasePreview();
624 }
625
626 /*!
627   \class SMESHGUI_BoundingBox
628   \brief Bounding box measurement widget.
629   
630   Widget to calculate bounding box of the selected object(s).
631 */
632
633 /*!
634   \brief Constructor.
635   \param parent parent widget
636 */
637 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
638 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
639 {
640   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
641   QRadioButton* aObjects  = new QRadioButton( tr( "OBJECTS" ),  aSourceGrp );
642   QRadioButton* aNodes    = new QRadioButton( tr( "NODES" ),    aSourceGrp );
643   QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
644   mySource = new QLineEdit( aSourceGrp );
645   
646   QGridLayout* fl = new QGridLayout( aSourceGrp );
647   fl->setMargin( MARGIN );
648   fl->setSpacing( SPACING );
649   fl->addWidget( aObjects,   0, 0 );
650   fl->addWidget( aNodes,     0, 1 );
651   fl->addWidget( aElements,  0, 2 );
652   fl->addWidget( mySource,   1, 0, 1, 3 );
653   
654   mySourceMode = new QButtonGroup( this );
655   mySourceMode->addButton( aObjects,  ObjectsSrc );
656   mySourceMode->addButton( aNodes,    NodesSrc );
657   mySourceMode->addButton( aElements, ElementsSrc );
658
659   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
660
661   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
662   QLabel* aXminLab = new QLabel( "Xmin", aResults );
663   myXmin           = new QLineEdit( aResults );
664   QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
665   myXmax           = new QLineEdit( aResults );
666   QLabel* aDxLab   = new QLabel( "dX", aResults );
667   myDX             = new QLineEdit( aResults );
668   QLabel* aYminLab = new QLabel( "Ymin", aResults );
669   myYmin           = new QLineEdit( aResults );
670   QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
671   myYmax           = new QLineEdit( aResults );
672   QLabel* aDyLab   = new QLabel( "dY", aResults );
673   myDY             = new QLineEdit( aResults );
674   QLabel* aZminLab = new QLabel( "Zmin", aResults );
675   myZmin           = new QLineEdit( aResults );
676   QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
677   myZmax           = new QLineEdit( aResults );
678   QLabel* aDzLab   = new QLabel( "dZ", aResults );
679   myDZ             = new QLineEdit( aResults );
680
681   QGridLayout* rl  = new QGridLayout( aResults );
682   rl->setMargin( MARGIN );
683   rl->setSpacing( SPACING );
684   rl->addWidget( aXminLab,   0, 0 );
685   rl->addWidget( myXmin,     0, 1 );
686   rl->addWidget( aXmaxLab,   0, 2 );
687   rl->addWidget( myXmax,     0, 3 );
688   rl->addWidget( aDxLab,     0, 4 );
689   rl->addWidget( myDX,       0, 5 );
690   rl->addWidget( aYminLab,   1, 0 );
691   rl->addWidget( myYmin,     1, 1 );
692   rl->addWidget( aYmaxLab,   1, 2 );
693   rl->addWidget( myYmax,     1, 3 );
694   rl->addWidget( aDyLab,     1, 4 );
695   rl->addWidget( myDY,       1, 5 );
696   rl->addWidget( aZminLab,   2, 0 );
697   rl->addWidget( myZmin,     2, 1 );
698   rl->addWidget( aZmaxLab,   2, 2 );
699   rl->addWidget( myZmax,     2, 3 );
700   rl->addWidget( aDzLab,     2, 4 );
701   rl->addWidget( myDZ,       2, 5 );
702
703   QGridLayout* l = new QGridLayout( this );
704   l->setMargin( MARGIN );
705   l->setSpacing( SPACING );
706
707   l->addWidget( aSourceGrp, 0, 0, 1, 2 );
708   l->addWidget( aCompute,   1, 0 );
709   l->addWidget( aResults,   2, 0, 1, 2 );
710   l->setColumnStretch( 1, 5 );
711   l->setRowStretch( 3, 5 );
712
713   aObjects->setChecked( true );
714   myXmin->setReadOnly( true );
715   myXmax->setReadOnly( true );
716   myDX->setReadOnly( true );
717   myYmin->setReadOnly( true );
718   myYmax->setReadOnly( true );
719   myDY->setReadOnly( true );
720   myZmin->setReadOnly( true );
721   myZmax->setReadOnly( true );
722   myDZ->setReadOnly( true );
723
724   myValidator = new SMESHGUI_IdValidator( this );
725
726   connect( mySourceMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( sourceChanged() ) );
727   connect( aCompute,     SIGNAL( clicked() ),             this, SLOT( compute() ) );
728   connect( mySource,     SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
729
730   QList<SUIT_SelectionFilter*> filters;
731   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
732   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
733   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
734
735   clear();
736 }
737
738 /*!
739   \brief Destructor
740 */
741 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
742 {
743   erasePreview();
744   if ( myPreview )
745     myPreview->Delete();
746 }
747
748 /*!
749   \brief Setup selection mode depending on the current widget state
750 */
751 void SMESHGUI_BoundingBox::updateSelection()
752 {
753   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
754
755   disconnect( selMgr, 0, this, 0 );
756   selMgr->clearFilters();
757   
758   bool nodeMode = mySourceMode->checkedId() == NodesSrc;
759   bool elemMode = mySourceMode->checkedId() == ElementsSrc;
760   bool objMode  = mySourceMode->checkedId() == ObjectsSrc;
761
762   if ( nodeMode ) {
763     SMESH::SetPointRepresentation( true );
764     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
765       aViewWindow->SetSelectionMode( NodeSelection );
766   }
767   else if ( elemMode ) {
768     SMESH::SetPointRepresentation( false );
769     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
770       aViewWindow->SetSelectionMode( CellSelection );
771   }
772   else if ( objMode ) {
773     SMESH::SetPointRepresentation( false );
774     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
775       aViewWindow->SetSelectionMode( ActorSelection );
776     selMgr->installFilter( myFilter );
777   }
778
779   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
780
781   sourceEdited();
782
783   if ( mySource->text().isEmpty() )
784     selectionChanged();
785 }
786
787 /*!
788   \brief Deactivate widget
789 */
790 void SMESHGUI_BoundingBox::deactivate()
791 {
792   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
793 }
794
795 /*!
796   \brief Erase preview actor
797 */
798 void SMESHGUI_BoundingBox::erasePreview()
799 {
800   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
801   if ( aViewWindow && myPreview ) {
802     aViewWindow->RemoveActor( myPreview );
803     aViewWindow->Repaint();
804   }
805 }
806
807 /*!
808   \brief Display preview actor
809 */
810 void SMESHGUI_BoundingBox::displayPreview()
811 {
812   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
813   if ( aViewWindow && myPreview ) {
814     aViewWindow->AddActor( myPreview );
815     aViewWindow->Repaint();
816   }
817 }
818
819 /*!
820   \brief Create preview actor
821   \param minX min X coordinate of bounding box
822   \param maxX max X coordinate of bounding box
823   \param minY min Y coordinate of bounding box
824   \param maxY max Y coordinate of bounding box
825   \param minZ min Z coordinate of bounding box
826   \param maxZ max Z coordinate of bounding box
827 */
828 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
829 {
830   if ( myPreview )
831     myPreview->Delete();
832
833   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
834   // create points
835   vtkPoints* aPoints = vtkPoints::New();
836   aPoints->SetNumberOfPoints( 8 );
837   aPoints->SetPoint( 0, minX, minY, minZ );
838   aPoints->SetPoint( 1, maxX, minY, minZ );
839   aPoints->SetPoint( 2, minX, maxY, minZ );
840   aPoints->SetPoint( 3, maxX, maxY, minZ );
841   aPoints->SetPoint( 4, minX, minY, maxZ );
842   aPoints->SetPoint( 5, maxX, minY, maxZ );
843   aPoints->SetPoint( 6, minX, maxY, maxZ );
844   aPoints->SetPoint( 7, maxX, maxY, maxZ );
845   aGrid->SetPoints( aPoints );
846   aPoints->Delete();
847   // create cells
848   // 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
849   vtkIdList* anIdList = vtkIdList::New();
850   anIdList->SetNumberOfIds( 2 );
851   vtkCellArray* aCells = vtkCellArray::New();
852   aCells->Allocate( 2*12, 0);
853   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
854   aCellTypesArray->SetNumberOfComponents( 1 );
855   aCellTypesArray->Allocate( 12 );
856   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
857   aCells->InsertNextCell( anIdList );
858   aCellTypesArray->InsertNextValue( VTK_LINE );
859   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
860   aCells->InsertNextCell( anIdList );
861   aCellTypesArray->InsertNextValue( VTK_LINE );
862   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
863   aCells->InsertNextCell( anIdList );
864   aCellTypesArray->InsertNextValue( VTK_LINE );
865   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
866   aCells->InsertNextCell( anIdList );
867   aCellTypesArray->InsertNextValue( VTK_LINE );
868   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
869   aCells->InsertNextCell( anIdList );
870   aCellTypesArray->InsertNextValue( VTK_LINE );
871   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
872   aCells->InsertNextCell( anIdList );
873   aCellTypesArray->InsertNextValue( VTK_LINE );
874   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
875   aCells->InsertNextCell( anIdList );
876   aCellTypesArray->InsertNextValue( VTK_LINE );
877   anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
878   aCells->InsertNextCell( anIdList );
879   aCellTypesArray->InsertNextValue( VTK_LINE );
880   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
881   aCells->InsertNextCell( anIdList );
882   aCellTypesArray->InsertNextValue( VTK_LINE );
883   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
884   aCells->InsertNextCell( anIdList );
885   aCellTypesArray->InsertNextValue( VTK_LINE );
886   anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
887   aCells->InsertNextCell( anIdList );
888   aCellTypesArray->InsertNextValue( VTK_LINE );
889   anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
890   aCells->InsertNextCell( anIdList );
891   aCellTypesArray->InsertNextValue( VTK_LINE );
892   anIdList->Delete();
893   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
894   aCellLocationsArray->SetNumberOfComponents( 1 );
895   aCellLocationsArray->SetNumberOfTuples( 12 );
896   aCells->InitTraversal();
897   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
898     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
899   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
900   aCellLocationsArray->Delete();
901   aCellTypesArray->Delete();
902   aCells->Delete();
903   // create actor
904   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
905   aMapper->SetInputData( aGrid );
906   aGrid->Delete();
907   myPreview = SALOME_Actor::New();
908   myPreview->PickableOff();
909   myPreview->SetMapper( aMapper );
910   aMapper->Delete();
911   vtkProperty* aProp = vtkProperty::New();
912   aProp->SetRepresentationToWireframe();
913   aProp->SetColor( 250, 0, 250 );
914   aProp->SetPointSize( 5 );
915   aProp->SetLineWidth( 3 );
916   myPreview->SetProperty( aProp );
917   aProp->Delete();
918 }
919
920 /*!
921   \brief Called when selection is changed
922 */
923 void SMESHGUI_BoundingBox::selectionChanged()
924 {
925   SUIT_OverrideCursor wc;
926
927   SALOME_ListIO selected;
928   SMESHGUI::selectionMgr()->selectedObjects( selected );
929
930   if ( selected.Extent() == 1 ) {
931     Handle(SALOME_InteractiveObject) IO = selected.First();
932     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
933     if ( !CORBA::is_nil( obj ) ) {
934       mySrc.clear();
935       mySrc.append( obj );
936       myActor = SMESH::FindActorByEntry( IO->getEntry() );
937       if ( mySourceMode->checkedId() == ObjectsSrc ) {
938         QString aName;
939         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
940         mySource->setText( aName );
941       }
942       else {
943         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
944         QString ID;
945         int nb = 0;
946         if ( myActor && selector ) {
947           nb = mySourceMode->checkedId() == NodesSrc ? 
948             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
949             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
950         }
951         if ( nb > 0 ) {
952           myIDs = ID.trimmed();
953           if ( nb < MAX_NB_FOR_EDITOR ) {
954             mySource->setReadOnly( false );
955             if ( mySource->validator() != myValidator )
956               mySource->setValidator( myValidator );
957             mySource->setText( ID.trimmed() );
958           }
959           else {
960             mySource->setReadOnly( true );
961             mySource->setValidator( 0 );
962             mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
963                                .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
964           }
965         }
966         else {
967           myIDs = "";
968           mySource->clear();
969           mySource->setReadOnly( false );
970           mySource->setValidator( myValidator );
971         }
972       }
973     }
974   }
975   else if ( selected.Extent() > 1 ) {
976     myIDs = "";
977     SALOME_ListIteratorOfListIO It( selected );
978     mySrc.clear();
979     myActor = 0;
980     if ( mySourceMode->checkedId() == ObjectsSrc ) {
981       for( ; It.More(); It.Next()){
982         Handle(SALOME_InteractiveObject) IO = It.Value();
983         SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
984         if ( !CORBA::is_nil( obj ) ) {
985           mySrc.append( obj );
986         }
987       }
988       QString aName;
989       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
990       mySource->setText( aName );
991     }
992     else {
993       mySource->clear();
994     }
995   }
996   clear();
997 }
998
999 /*!
1000   \brief Called when source mode is changed by the user
1001 */
1002 void SMESHGUI_BoundingBox::sourceChanged()
1003 {
1004   myIDs = "";
1005   mySource->clear();
1006   mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
1007   mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
1008   updateSelection();
1009   clear();
1010 }
1011
1012 /*!
1013   \brief Called when source mode is edited by the user
1014 */
1015 void SMESHGUI_BoundingBox::sourceEdited()
1016 {
1017   if ( sender() == mySource )
1018     clear();
1019   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1020   if ( myActor && selector ) {
1021     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1022     if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1023       TColStd_MapOfInteger ID;
1024       if ( !mySource->isReadOnly() )
1025         myIDs = mySource->text();
1026       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1027       foreach ( QString id, ids )
1028         ID.Add( id.trimmed().toLong() );
1029       selector->AddOrRemoveIndex( IO, ID, false );
1030     }
1031     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1032       aViewWindow->highlight( IO, true, true );
1033   }
1034 }
1035
1036 /*!
1037   \brief Calculate bounding box of the selected object(s)
1038 */
1039 void SMESHGUI_BoundingBox::compute()
1040 {
1041   SUIT_OverrideCursor wc;
1042   SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1043   if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1044     if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1045       SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1046       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1047       if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1048         SMESH::long_array_var ids_in = new SMESH::long_array();
1049         ids_in->length( ids.count() );
1050         for( int i = 0; i < ids.count(); i++ )
1051           ids_in[i] = ids[i].trimmed().toLong();
1052         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1053         SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); 
1054         srcList->length( 1 );
1055         srcList[0] = s;
1056       }
1057     }
1058   }
1059   else {
1060     srcList->length( mySrc.count() );
1061     for( int i = 0; i < mySrc.count(); i++ ) {
1062       srcList[i] = mySrc[i];
1063       mySrc[i]->Register();
1064     }
1065   }
1066   if ( srcList->length() > 0 ) {
1067     // compute bounding box
1068     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1069     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1070     SMESH::Measure result = measure->BoundingBox( srcList.in() );
1071     SALOME::UnRegister( srcList );
1072     measure->UnRegister();
1073     myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1074     myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1075     myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1076     myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1077     myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1078     myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1079     myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1080     myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1081     myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1082     // update preview actor
1083     erasePreview();
1084     createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1085     displayPreview();
1086   }
1087   else {
1088     clear();
1089   }
1090 }
1091
1092 /*!
1093   \brief Reset the widget to the initial state (nullify result fields)
1094 */
1095 void SMESHGUI_BoundingBox::clear()
1096 {
1097   myXmin->clear();
1098   myXmax->clear();
1099   myDX->clear();
1100   myYmin->clear();
1101   myYmax->clear();
1102   myDY->clear();
1103   myZmin->clear();
1104   myZmax->clear();
1105   myDZ->clear();
1106   erasePreview();
1107 }
1108
1109 /*!
1110   \class SMESHGUI_BasicProperties
1111   \brief basic properties measurement widget.
1112   
1113   Widget to calculate length, area or volume for the selected object(s).
1114 */
1115
1116 /*!
1117   \brief Constructor.
1118   \param parent parent widget
1119 */
1120 SMESHGUI_BasicProperties::SMESHGUI_BasicProperties( QWidget* parent )
1121 : QWidget( parent )
1122 {
1123   // Property (length, area or volume)
1124   QGroupBox* aPropertyGrp = new QGroupBox( tr( "PROPERTY" ), this );
1125
1126   QRadioButton* aLength = new QRadioButton( tr( "LENGTH" ), aPropertyGrp );
1127   QRadioButton* anArea = new QRadioButton( tr( "AREA" ), aPropertyGrp );
1128   QRadioButton* aVolume = new QRadioButton( tr( "VOLUME" ), aPropertyGrp );
1129
1130   myMode = new QButtonGroup( this );
1131   myMode->addButton( aLength, Length );
1132   myMode->addButton( anArea, Area );
1133   myMode->addButton( aVolume, Volume );
1134
1135   QHBoxLayout* aPropertyLayout = new QHBoxLayout;
1136   aPropertyLayout->addWidget( aLength );
1137   aPropertyLayout->addWidget( anArea );
1138   aPropertyLayout->addWidget( aVolume );
1139
1140   aPropertyGrp->setLayout( aPropertyLayout );
1141
1142   // Source object
1143   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE_MESH_SUBMESH_GROUP" ), this );
1144
1145   mySource = new QLineEdit( aSourceGrp );
1146   mySource->setReadOnly( true );
1147     
1148   QHBoxLayout* aSourceLayout = new QHBoxLayout;
1149   aSourceLayout->addWidget( mySource );
1150   
1151   aSourceGrp->setLayout( aSourceLayout );
1152
1153   // Compute button
1154   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1155
1156   // Result of computation (length, area or volume)
1157   myResultGrp = new QGroupBox( this );
1158
1159   myResult = new QLineEdit;
1160   myResult->setReadOnly( true );
1161
1162   QHBoxLayout* aResultLayout = new QHBoxLayout;
1163   aResultLayout->addWidget( myResult );
1164   
1165   myResultGrp->setLayout( aResultLayout );
1166
1167   // Layout
1168   QGridLayout* aMainLayout = new QGridLayout( this );
1169   aMainLayout->setMargin( MARGIN );
1170   aMainLayout->setSpacing( SPACING );
1171
1172   aMainLayout->addWidget( aPropertyGrp, 0, 0, 1, 2 );
1173   aMainLayout->addWidget( aSourceGrp, 1, 0, 1, 2 );
1174   aMainLayout->addWidget( aCompute,   2, 0 );
1175   aMainLayout->addWidget( myResultGrp, 3, 0, 1, 2 );
1176   aMainLayout->setColumnStretch( 1, 5 );
1177   aMainLayout->setRowStretch( 4, 5 );
1178
1179   // Initial state
1180   setMode( Length );
1181   
1182   // Connections
1183   connect( myMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( modeChanged( int ) ) );
1184   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
1185   
1186   // Selection filter
1187   QList<SUIT_SelectionFilter*> filters;
1188   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
1189   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
1190   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
1191 }
1192
1193 /*!
1194   \brief Destructor
1195 */
1196 SMESHGUI_BasicProperties::~SMESHGUI_BasicProperties()
1197 {
1198 }
1199
1200 /*!
1201   \brief Sets the measurement mode.
1202   \param theMode the mode to set (length, area or volume meausurement)
1203 */
1204 void SMESHGUI_BasicProperties::setMode( const Mode theMode )
1205 {
1206   QRadioButton* aButton = qobject_cast<QRadioButton*>( myMode->button( theMode ) );
1207   if ( aButton ) {
1208     aButton->setChecked( true );
1209     modeChanged( theMode );
1210   }
1211 }
1212
1213 /*!
1214   \brief Setup the selection mode.
1215 */
1216 void SMESHGUI_BasicProperties::updateSelection()
1217 {
1218   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1219
1220   disconnect( selMgr, 0, this, 0 );
1221   selMgr->clearFilters();
1222   
1223   SMESH::SetPointRepresentation( false );
1224   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
1225     aViewWindow->SetSelectionMode( ActorSelection );
1226   }
1227   selMgr->installFilter( myFilter );
1228   
1229   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
1230
1231   if ( mySource->text().isEmpty() )
1232     selectionChanged();
1233 }
1234
1235 /*!
1236   \brief Deactivate widget
1237 */
1238 void SMESHGUI_BasicProperties::deactivate()
1239 {
1240   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
1241 }
1242
1243 /*!
1244   \brief Called when selection is changed
1245 */
1246 void SMESHGUI_BasicProperties::selectionChanged()
1247 {
1248   SUIT_OverrideCursor wc;
1249
1250   SALOME_ListIO selected;
1251   SMESHGUI::selectionMgr()->selectedObjects( selected );
1252
1253   if ( selected.Extent() == 1 ) {
1254     Handle(SALOME_InteractiveObject) IO = selected.First();
1255     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1256     if ( !CORBA::is_nil( obj ) ) {
1257       mySrc = obj;
1258
1259       QString aName;
1260       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
1261       mySource->setText( aName );
1262     }
1263   }
1264
1265   clear();
1266 }
1267
1268 /*!
1269   \brief Called when the measurement mode selection is changed.
1270   \param theMode the selected mode
1271 */
1272 void SMESHGUI_BasicProperties::modeChanged( int theMode )
1273 {
1274   clear();
1275
1276   if ( theMode == Length ) {
1277     myResultGrp->setTitle( tr("LENGTH") );
1278   } else if ( theMode == Area ) {
1279     myResultGrp->setTitle( tr("AREA") );
1280   } else if ( theMode == Volume ) {
1281     myResultGrp->setTitle( tr("VOLUME") );
1282   }
1283 }
1284
1285 /*!
1286   \brief Calculate length, area or volume for the selected object(s)
1287 */
1288 void SMESHGUI_BasicProperties::compute()
1289 {
1290   SUIT_OverrideCursor wc;
1291
1292   SMESH::SMESH_IDSource_var source;
1293
1294   if ( !CORBA::is_nil( mySrc ) ) {
1295     // compute
1296     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1297     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1298
1299     double result = 0;
1300
1301     if ( myMode->checkedId() == Length ) {
1302       result = measure->Length( mySrc.in() );
1303     } else if ( myMode->checkedId() == Area ) {
1304       result = measure->Area( mySrc.in() );
1305     } else if ( myMode->checkedId() == Volume ) {
1306       result = measure->Volume( mySrc.in() );
1307     }
1308     
1309     measure->UnRegister();
1310
1311     myResult->setText( QString::number( result, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1312   } else {
1313     clear();
1314   }
1315 }
1316
1317 /*!
1318   \brief Reset the widget to the initial state (nullify the result field)
1319 */
1320 void SMESHGUI_BasicProperties::clear()
1321 {
1322   myResult->clear();
1323 }
1324
1325 /*!
1326   \class SMESHGUI_Angle
1327   \brief Angle measurement widget.
1328   
1329   Widget to calculate angle between 3 nodes.
1330 */
1331
1332 /*!
1333   \brief Constructor.
1334   \param parent parent widget
1335 */
1336 SMESHGUI_Angle::SMESHGUI_Angle( QWidget* parent )
1337   : QWidget( parent )
1338 {
1339   // 3 nodes
1340
1341   QGroupBox* aNodesGrp = new QGroupBox( tr( "NODES_GROUP" ), this );
1342   myNodes = new QLineEdit( aNodesGrp );
1343   myNodes->setValidator( new SMESHGUI_IdValidator( this, 3 ));
1344   QHBoxLayout* aNodesLayout = new QHBoxLayout( aNodesGrp );
1345   aNodesLayout->addWidget( myNodes );
1346   
1347   // Compute button
1348   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1349
1350   // Angle
1351
1352   QGroupBox* aResultGrp = new QGroupBox( tr( "RESULT" ), this );
1353
1354   myResult = new QLineEdit;
1355   myResult->setReadOnly( true );
1356
1357   QHBoxLayout* aResultLayout = new QHBoxLayout( aResultGrp );
1358   aResultLayout->addWidget( myResult );
1359   
1360   // Layout
1361
1362   QGridLayout* aMainLayout = new QGridLayout( this );
1363   aMainLayout->setMargin( MARGIN );
1364   aMainLayout->setSpacing( SPACING );
1365
1366   aMainLayout->addWidget( aNodesGrp,   0, 0, 1, 2 );
1367   aMainLayout->addWidget( aCompute,    1, 0 );
1368   aMainLayout->addWidget( aResultGrp, 2, 0, 1, 2 );
1369   aMainLayout->setColumnStretch( 1, 5 );
1370   aMainLayout->setRowStretch( 3, 5 );
1371
1372   // Connections
1373   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ));
1374
1375   // preview
1376   myPreview = 0;
1377   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1378   {
1379     myPreview = new SMESHGUI_MeshEditPreview( aViewWindow );
1380     if ( myPreview && myPreview->GetActor() )
1381       myPreview->GetActor()->GetProperty()->SetLineWidth( 5 );
1382   }
1383   myActor = 0;
1384 }
1385
1386 SMESHGUI_Angle::~SMESHGUI_Angle()
1387 {
1388   if ( myPreview )
1389     delete myPreview;
1390 }
1391
1392 /*!
1393   \brief Setup selection mode
1394 */
1395 void SMESHGUI_Angle::updateSelection()
1396 {
1397   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1398
1399   disconnect( selMgr, 0, this, 0 );
1400   selMgr->clearFilters();
1401
1402   SMESH::SetPointRepresentation( true );
1403   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1404     aViewWindow->SetSelectionMode( NodeSelection );
1405
1406   connect( selMgr,  SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ));
1407   connect( myNodes, SIGNAL( textEdited( QString ) ),     this, SLOT( nodesEdited() ));
1408
1409   if ( myPoints.empty() )
1410     selectionChanged();
1411 }
1412
1413 /*!
1414   \brief Called when selection is changed
1415 */
1416 void SMESHGUI_Angle::selectionChanged()
1417 {
1418   clear();
1419   QString nodesString;
1420
1421   TColStd_IndexedMapOfInteger idsMap;
1422   SALOME_ListIO selected;
1423   SMESHGUI::selectionMgr()->selectedObjects( selected );
1424   selected.Reverse(); // to keep order of selection
1425
1426   SALOME_ListIteratorOfListIO ioIterator( selected );
1427   for ( ; ioIterator.More(); ioIterator.Next() )
1428   {
1429     Handle(SALOME_InteractiveObject) IO = ioIterator.Value();
1430
1431     idsMap.Clear();
1432     if ( SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector() )
1433       selector->GetIndex( IO, idsMap );
1434
1435     if ( SMESH_Actor* actor = SMESH::FindActorByEntry( IO->getEntry() ))
1436     {
1437       myActor = actor;
1438       for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1439         if ( addPointByActor( idsMap(i) ))
1440           nodesString += QString(" %1").arg( idsMap(i) );
1441       idsMap.Clear();
1442     }
1443     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1444     if ( !CORBA::is_nil( obj ) )
1445     {
1446       myIDSrc = obj;
1447       for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1448         if ( addPointByIDSource( idsMap(i) ))
1449           nodesString += QString(" %1").arg( idsMap(i) );
1450     }
1451   }
1452
1453   myNodes->setText( nodesString );
1454 }
1455
1456 //=======================================================================
1457 //function : clear
1458 //purpose  : Erase preview and result
1459 //=======================================================================
1460
1461 void SMESHGUI_Angle::clear()
1462 {
1463   myPoints.clear();
1464   myResult->clear();
1465   if ( myPreview && myPreview->GetActor())
1466   {
1467     myPreview->GetActor()->SetVisibility( false );
1468     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1469       aViewWindow->Repaint();
1470   }
1471 }
1472
1473 //=======================================================================
1474 //function : addPointByActor
1475 //purpose  : append to myPoints XYZ got from myActor
1476 //=======================================================================
1477
1478 bool SMESHGUI_Angle::addPointByActor( int id )
1479 {
1480   size_t nbP = myPoints.size();
1481
1482   if ( myActor )
1483   {
1484     TVisualObjPtr obj = myActor->GetObject();
1485     if ( SMDS_Mesh* mesh = obj->GetMesh() )
1486       if ( const SMDS_MeshNode* node = mesh->FindNode( id ))
1487       {
1488         SMESH::PointStruct p = { node->X(), node->Y(), node->Z() };
1489         myPoints.push_back( p );
1490       }
1491   }
1492   return nbP < myPoints.size();
1493 }
1494
1495 //=======================================================================
1496 //function : addPointByIDSource
1497 //purpose  : append to myPoints XYZ got from myIDSrc
1498 //=======================================================================
1499
1500 bool SMESHGUI_Angle::addPointByIDSource( int id )
1501 {
1502   size_t nbP = myPoints.size();
1503
1504   if ( !myIDSrc->_is_nil() )
1505   {
1506     SMESH::SMESH_Mesh_var mesh = myIDSrc->GetMesh();
1507     if ( !mesh->_is_nil() )
1508     {
1509       SMESH::double_array_var xyz = mesh->GetNodeXYZ( id );
1510       if ( xyz->length() == 3 )
1511       {
1512         SMESH::PointStruct p = { xyz[0], xyz[1], xyz[2] };
1513         myPoints.push_back( p );
1514       }
1515     }
1516   }
1517   return nbP < myPoints.size();
1518 }
1519
1520 //=======================================================================
1521 //function : nodesEdited
1522 //purpose  : SLOT called when the user types node IDs
1523 //=======================================================================
1524
1525 void SMESHGUI_Angle::nodesEdited()
1526 {
1527   clear();
1528
1529   TColStd_MapOfInteger ID;
1530   QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1531   foreach ( QString idStr, ids )
1532   {
1533     int id = idStr.trimmed().toLong();
1534     if (( !ID.Contains( id )) &&
1535         ( addPointByActor( id ) || addPointByIDSource( id )))
1536       ID.Add( id );
1537   }
1538
1539   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1540   if ( myActor && selector )
1541   {
1542     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1543     selector->AddOrRemoveIndex( IO, ID, false );
1544     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1545       aViewWindow->highlight( IO, true, true );
1546   }
1547 }
1548
1549 //=======================================================================
1550 //function : compute
1551 //purpose  : SLOT. Compute angle and show preview
1552 //=======================================================================
1553
1554 void SMESHGUI_Angle::compute()
1555 {
1556   if ( myPoints.size() != 3 )
1557     return;
1558
1559   // --------------
1560   // compute angle
1561   // --------------
1562
1563   SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1564   double radians = measure->Angle( myPoints[0], myPoints[1], myPoints[2] );
1565   measure->UnRegister();
1566   if ( radians < 0 )
1567     return;
1568
1569   int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1570   myResult->setText( QString::number( radians * 180 / M_PI,
1571                                       precision > 0 ? 'f' : 'g', qAbs( precision )));
1572
1573   // -------------
1574   // show preview
1575   // -------------
1576
1577   if ( !myPreview || !myPreview->GetActor() )
1578     return;
1579
1580   SMESH::MeshPreviewStruct preveiwData;
1581
1582   const double     anglePerSeg = 5 * M_PI/180; // angle per an arc segment
1583   const double arcRadiusFactor = 0.5;          // arc position, from p1
1584
1585   gp_Pnt p0 ( myPoints[0].x, myPoints[0].y, myPoints[0].z );
1586   gp_Pnt p1 ( myPoints[1].x, myPoints[1].y, myPoints[1].z );
1587   gp_Pnt p2 ( myPoints[2].x, myPoints[2].y, myPoints[2].z );
1588   gp_Vec vec10( p1, p0 ), vec12( p1, p2 ), norm( vec10 ^ vec12 );
1589
1590   if ( norm.Magnitude() <= gp::Resolution() ) // 180 degrees
1591     norm = getNormal( vec10 );
1592
1593   double     len10 = vec10.Magnitude();
1594   double     len12 = vec12.Magnitude();
1595   double    lenMax = Max( len10, len12 );
1596   double arcRadius = arcRadiusFactor * lenMax;
1597
1598   p0 = p1.Translated( lenMax * vec10.Normalized() );
1599   p2 = p1.Translated( lenMax * vec12.Normalized() );
1600
1601   gp_Circ arc( gp_Ax2( p1, norm, vec10 ), arcRadius );
1602
1603   int nbRadialSegmensts = ceil( radians / anglePerSeg ) + 1;
1604   int           nbNodes = 3 + ( nbRadialSegmensts + 1 );
1605
1606   // coordinates
1607   preveiwData.nodesXYZ.length( nbNodes );
1608   int iP = 0;
1609   for ( ; iP < nbRadialSegmensts + 1; ++iP )
1610   {
1611     double u = double( iP ) / nbRadialSegmensts * radians;
1612     gp_Pnt p = ElCLib::Value( u, arc );
1613     preveiwData.nodesXYZ[ iP ].x = p.X();
1614     preveiwData.nodesXYZ[ iP ].y = p.Y();
1615     preveiwData.nodesXYZ[ iP ].z = p.Z();
1616   }
1617   int iP0 = iP;
1618   preveiwData.nodesXYZ[ iP ].x = p0.X();
1619   preveiwData.nodesXYZ[ iP ].y = p0.Y();
1620   preveiwData.nodesXYZ[ iP ].z = p0.Z();
1621   int iP1 = ++iP;
1622   preveiwData.nodesXYZ[ iP ].x = p1.X();
1623   preveiwData.nodesXYZ[ iP ].y = p1.Y();
1624   preveiwData.nodesXYZ[ iP ].z = p1.Z();
1625   int iP2 = ++iP;
1626   preveiwData.nodesXYZ[ iP ].x = p2.X();
1627   preveiwData.nodesXYZ[ iP ].y = p2.Y();
1628   preveiwData.nodesXYZ[ iP ].z = p2.Z();
1629
1630   // connectivity
1631   preveiwData.elementConnectivities.length( 2 * ( 2 + nbRadialSegmensts ));
1632   for ( int iSeg = 0; iSeg < nbRadialSegmensts; ++iSeg )
1633   {
1634     preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iSeg;
1635     preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iSeg + 1;
1636   }
1637   int iSeg = nbRadialSegmensts;
1638   preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP0;
1639   preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP1;
1640   ++iSeg;
1641   preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP1;
1642   preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP2;
1643
1644   // types
1645   preveiwData.elementTypes.length( 2 + nbRadialSegmensts );
1646   SMESH::ElementSubType type = { SMESH::EDGE, /*isPoly=*/false, /*nbNodesInElement=*/2 };
1647   for ( CORBA::ULong i = 0; i < preveiwData.elementTypes.length(); ++i )
1648     preveiwData.elementTypes[ i ] = type;
1649
1650   myPreview->SetData( preveiwData );
1651 }
1652
1653 //================================================================================
1654 /*!
1655  * \brief Return normal to a plane of drawing in the case of 180 degrees angle
1656  */
1657 //================================================================================
1658
1659 gp_Vec SMESHGUI_Angle::getNormal(const gp_Vec& vec10 )
1660 {
1661   gp_XYZ norm;
1662
1663   // try to get normal by a face at the 2nd node
1664   if ( myActor && myActor->GetObject()->GetMesh() )
1665   {
1666     QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1667     SMDS_Mesh* mesh = myActor->GetObject()->GetMesh();
1668     if ( const SMDS_MeshNode* n = mesh->FindNode( ids[1].trimmed().toLong() ))
1669     {
1670       SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face );
1671       while ( faceIt->more() )
1672         if ( SMESH_MeshAlgos::FaceNormal( faceIt->next(), norm ))
1673           return norm;
1674     }
1675   }
1676   int iMinCoord = 1;
1677   if ( vec10.Coord( iMinCoord ) > vec10.Y() ) iMinCoord = 2;
1678   if ( vec10.Coord( iMinCoord ) > vec10.Z() ) iMinCoord = 3;
1679
1680   gp_Vec vec = vec10;
1681   vec.SetCoord( iMinCoord, vec10.Coord( iMinCoord ) + 1. );
1682
1683   return vec ^ vec10;
1684 }
1685
1686 /*!
1687   \class SMESHGUI_MeshInfoDlg
1688   \brief Centralized dialog box for the measurements
1689 */
1690
1691 /*!
1692   \brief Constructor
1693   \param parent parent widget
1694   \param page specifies the dialog page to be shown at the start-up
1695 */
1696 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1697   : QDialog( parent )
1698 {
1699   setModal( false );
1700   setAttribute( Qt::WA_DeleteOnClose, true );
1701   setWindowTitle( tr( "MEASUREMENTS" ) );
1702   setSizeGripEnabled( true );
1703
1704   SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1705
1706   myTabWidget = new QTabWidget( this );
1707
1708   // min distance
1709
1710   myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1711   int aMinDistInd = myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1712
1713   // bounding box
1714   
1715   myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1716   int aBndBoxInd = myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1717
1718   // basic properties
1719   
1720   myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
1721   int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
1722
1723   myAngle = new SMESHGUI_Angle( myTabWidget );
1724   int aAngleInd = myTabWidget->addTab( myAngle, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_ANGLE" ) ), tr( "ANGLE" ) );
1725
1726   // buttons
1727   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1728   okBtn->setAutoDefault( true );
1729   okBtn->setDefault( true );
1730   okBtn->setFocus();
1731   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1732   helpBtn->setAutoDefault( true );
1733
1734   QHBoxLayout* btnLayout = new QHBoxLayout;
1735   btnLayout->setSpacing( SPACING );
1736   btnLayout->setMargin( 0 );
1737   btnLayout->addWidget( okBtn );
1738   btnLayout->addStretch( 10 );
1739   btnLayout->addWidget( helpBtn );
1740
1741   QVBoxLayout* l = new QVBoxLayout ( this );
1742   l->setMargin( MARGIN );
1743   l->setSpacing( SPACING );
1744   l->addWidget( myTabWidget );
1745   l->addStretch();
1746   l->addLayout( btnLayout );
1747
1748   int anInd = -1;
1749   if ( page == MinDistance ) {
1750     anInd = aMinDistInd;
1751   } else if ( page == BoundingBox ) {
1752     anInd = aBndBoxInd;
1753   } else if ( page == Angle ) {
1754     anInd = aAngleInd;
1755   } else if ( page == Length || page == Area || page == Volume ) {
1756     myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
1757     anInd = aBasicPropInd;
1758   }
1759
1760   if ( anInd >= 0 ) {
1761     myTabWidget->setCurrentIndex( anInd );
1762   }
1763
1764   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
1765   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
1766   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
1767   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1768   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
1769
1770   updateSelection();
1771 }
1772
1773 /*!
1774   \brief Destructor
1775 */
1776 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1777 {
1778 }
1779
1780 /*!
1781   \brief Perform clean-up actions on the dialog box closing.
1782 */
1783 void SMESHGUI_MeasureDlg::reject()
1784 {
1785   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1786   selMgr->clearFilters();
1787   SMESH::SetPointRepresentation( false );
1788   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1789     aViewWindow->SetSelectionMode( ActorSelection );
1790   QDialog::reject();
1791 }
1792
1793 /*!
1794   \brief Process keyboard event
1795   \param e key press event
1796 */
1797 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1798 {
1799   QDialog::keyPressEvent( e );
1800   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1801     e->accept();
1802     help();
1803   }
1804 }
1805
1806 /*!
1807   \brief Reactivate dialog box, when mouse pointer goes into it.
1808 */
1809 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1810 {
1811   activate();
1812 }
1813
1814 /*!
1815   \brief Setup selection mode depending on the current dialog box state.
1816 */
1817 void SMESHGUI_MeasureDlg::updateSelection()
1818 {
1819   if ( myTabWidget->currentIndex() == MinDistance )
1820     myMinDist->updateSelection();
1821   else if ( myTabWidget->currentIndex() == BoundingBox )
1822     myBndBox->updateSelection();
1823   else if ( myTabWidget->currentWidget() == myAngle )
1824     myAngle->updateSelection();
1825   else {
1826     myBndBox->erasePreview();
1827     myBasicProps->updateSelection();
1828   }
1829 }
1830
1831 /*!
1832   \brief Show help page
1833 */
1834 void SMESHGUI_MeasureDlg::help()
1835 {
1836   QString aHelpFile;
1837   if ( myTabWidget->currentIndex() == MinDistance ) {
1838     aHelpFile = "measurements.html#min-distance-anchor";
1839   } else if ( myTabWidget->currentIndex() == BoundingBox ) {
1840     aHelpFile = "measurements.html#bounding-box-anchor";
1841   } else if ( myTabWidget->currentWidget() == myAngle ) {
1842     aHelpFile = "measurements.html#angle-anchor";
1843   } else {
1844     aHelpFile = "measurements.html#basic-properties-anchor";
1845   }
1846
1847   SMESH::ShowHelpFile( aHelpFile );
1848 }
1849
1850 /*!
1851   \brief Activate dialog box
1852 */
1853 void SMESHGUI_MeasureDlg::activate()
1854 {
1855   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1856   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1857   myTabWidget->setEnabled( true );
1858   updateSelection();
1859 }
1860
1861 /*!
1862   \brief Deactivate dialog box
1863 */
1864 void SMESHGUI_MeasureDlg::deactivate()
1865 {
1866   myBasicProps->deactivate();
1867   myMinDist->deactivate();
1868   myBndBox->deactivate();
1869   myTabWidget->setEnabled( false );
1870   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1871 }