Salome HOME
IMP 23612: EDF 14143 - Compute angle from 3 points
[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 {
599       coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
600       x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
601     }
602     createPreview( x1, y1, z1, x2, y2, z2 );
603     displayPreview();
604   }
605   else {
606     clear();
607   }
608 }
609
610 /*!
611   \brief Reset the widget to the initial state (nullify result fields)
612 */
613 void SMESHGUI_MinDistance::clear()
614 {
615   myDX->clear();
616   myDY->clear();
617   myDZ->clear();
618   myDistance->clear();
619   erasePreview();
620 }
621
622 /*!
623   \class SMESHGUI_BoundingBox
624   \brief Bounding box measurement widget.
625   
626   Widget to calculate bounding box of the selected object(s).
627 */
628
629 /*!
630   \brief Constructor.
631   \param parent parent widget
632 */
633 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
634 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
635 {
636   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
637   QRadioButton* aObjects  = new QRadioButton( tr( "OBJECTS" ),  aSourceGrp );
638   QRadioButton* aNodes    = new QRadioButton( tr( "NODES" ),    aSourceGrp );
639   QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
640   mySource = new QLineEdit( aSourceGrp );
641   
642   QGridLayout* fl = new QGridLayout( aSourceGrp );
643   fl->setMargin( MARGIN );
644   fl->setSpacing( SPACING );
645   fl->addWidget( aObjects,   0, 0 );
646   fl->addWidget( aNodes,     0, 1 );
647   fl->addWidget( aElements,  0, 2 );
648   fl->addWidget( mySource,   1, 0, 1, 3 );
649   
650   mySourceMode = new QButtonGroup( this );
651   mySourceMode->addButton( aObjects,  ObjectsSrc );
652   mySourceMode->addButton( aNodes,    NodesSrc );
653   mySourceMode->addButton( aElements, ElementsSrc );
654
655   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
656
657   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
658   QLabel* aXminLab = new QLabel( "Xmin", aResults );
659   myXmin           = new QLineEdit( aResults );
660   QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
661   myXmax           = new QLineEdit( aResults );
662   QLabel* aDxLab   = new QLabel( "dX", aResults );
663   myDX             = new QLineEdit( aResults );
664   QLabel* aYminLab = new QLabel( "Ymin", aResults );
665   myYmin           = new QLineEdit( aResults );
666   QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
667   myYmax           = new QLineEdit( aResults );
668   QLabel* aDyLab   = new QLabel( "dY", aResults );
669   myDY             = new QLineEdit( aResults );
670   QLabel* aZminLab = new QLabel( "Zmin", aResults );
671   myZmin           = new QLineEdit( aResults );
672   QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
673   myZmax           = new QLineEdit( aResults );
674   QLabel* aDzLab   = new QLabel( "dZ", aResults );
675   myDZ             = new QLineEdit( aResults );
676
677   QGridLayout* rl  = new QGridLayout( aResults );
678   rl->setMargin( MARGIN );
679   rl->setSpacing( SPACING );
680   rl->addWidget( aXminLab,   0, 0 );
681   rl->addWidget( myXmin,     0, 1 );
682   rl->addWidget( aXmaxLab,   0, 2 );
683   rl->addWidget( myXmax,     0, 3 );
684   rl->addWidget( aDxLab,     0, 4 );
685   rl->addWidget( myDX,       0, 5 );
686   rl->addWidget( aYminLab,   1, 0 );
687   rl->addWidget( myYmin,     1, 1 );
688   rl->addWidget( aYmaxLab,   1, 2 );
689   rl->addWidget( myYmax,     1, 3 );
690   rl->addWidget( aDyLab,     1, 4 );
691   rl->addWidget( myDY,       1, 5 );
692   rl->addWidget( aZminLab,   2, 0 );
693   rl->addWidget( myZmin,     2, 1 );
694   rl->addWidget( aZmaxLab,   2, 2 );
695   rl->addWidget( myZmax,     2, 3 );
696   rl->addWidget( aDzLab,     2, 4 );
697   rl->addWidget( myDZ,       2, 5 );
698
699   QGridLayout* l = new QGridLayout( this );
700   l->setMargin( MARGIN );
701   l->setSpacing( SPACING );
702
703   l->addWidget( aSourceGrp, 0, 0, 1, 2 );
704   l->addWidget( aCompute,   1, 0 );
705   l->addWidget( aResults,   2, 0, 1, 2 );
706   l->setColumnStretch( 1, 5 );
707   l->setRowStretch( 3, 5 );
708
709   aObjects->setChecked( true );
710   myXmin->setReadOnly( true );
711   myXmax->setReadOnly( true );
712   myDX->setReadOnly( true );
713   myYmin->setReadOnly( true );
714   myYmax->setReadOnly( true );
715   myDY->setReadOnly( true );
716   myZmin->setReadOnly( true );
717   myZmax->setReadOnly( true );
718   myDZ->setReadOnly( true );
719
720   myValidator = new SMESHGUI_IdValidator( this );
721
722   connect( mySourceMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( sourceChanged() ) );
723   connect( aCompute,     SIGNAL( clicked() ),             this, SLOT( compute() ) );
724   connect( mySource,     SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
725
726   QList<SUIT_SelectionFilter*> filters;
727   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
728   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
729   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
730
731   clear();
732 }
733
734 /*!
735   \brief Destructor
736 */
737 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
738 {
739   erasePreview();
740   if ( myPreview )
741     myPreview->Delete();
742 }
743
744 /*!
745   \brief Setup selection mode depending on the current widget state
746 */
747 void SMESHGUI_BoundingBox::updateSelection()
748 {
749   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
750
751   disconnect( selMgr, 0, this, 0 );
752   selMgr->clearFilters();
753   
754   bool nodeMode = mySourceMode->checkedId() == NodesSrc;
755   bool elemMode = mySourceMode->checkedId() == ElementsSrc;
756   bool objMode  = mySourceMode->checkedId() == ObjectsSrc;
757
758   if ( nodeMode ) {
759     SMESH::SetPointRepresentation( true );
760     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
761       aViewWindow->SetSelectionMode( NodeSelection );
762   }
763   else if ( elemMode ) {
764     SMESH::SetPointRepresentation( false );
765     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
766       aViewWindow->SetSelectionMode( CellSelection );
767   }
768   else if ( objMode ) {
769     SMESH::SetPointRepresentation( false );
770     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
771       aViewWindow->SetSelectionMode( ActorSelection );
772     selMgr->installFilter( myFilter );
773   }
774
775   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
776
777   sourceEdited();
778
779   if ( mySource->text().isEmpty() )
780     selectionChanged();
781 }
782
783 /*!
784   \brief Deactivate widget
785 */
786 void SMESHGUI_BoundingBox::deactivate()
787 {
788   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
789 }
790
791 /*!
792   \brief Erase preview actor
793 */
794 void SMESHGUI_BoundingBox::erasePreview()
795 {
796   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
797   if ( aViewWindow && myPreview ) {
798     aViewWindow->RemoveActor( myPreview );
799     aViewWindow->Repaint();
800   }
801 }
802
803 /*!
804   \brief Display preview actor
805 */
806 void SMESHGUI_BoundingBox::displayPreview()
807 {
808   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
809   if ( aViewWindow && myPreview ) {
810     aViewWindow->AddActor( myPreview );
811     aViewWindow->Repaint();
812   }
813 }
814
815 /*!
816   \brief Create preview actor
817   \param minX min X coordinate of bounding box
818   \param maxX max X coordinate of bounding box
819   \param minY min Y coordinate of bounding box
820   \param maxY max Y coordinate of bounding box
821   \param minZ min Z coordinate of bounding box
822   \param maxZ max Z coordinate of bounding box
823 */
824 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
825 {
826   if ( myPreview )
827     myPreview->Delete();
828
829   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
830   // create points
831   vtkPoints* aPoints = vtkPoints::New();
832   aPoints->SetNumberOfPoints( 8 );
833   aPoints->SetPoint( 0, minX, minY, minZ );
834   aPoints->SetPoint( 1, maxX, minY, minZ );
835   aPoints->SetPoint( 2, minX, maxY, minZ );
836   aPoints->SetPoint( 3, maxX, maxY, minZ );
837   aPoints->SetPoint( 4, minX, minY, maxZ );
838   aPoints->SetPoint( 5, maxX, minY, maxZ );
839   aPoints->SetPoint( 6, minX, maxY, maxZ );
840   aPoints->SetPoint( 7, maxX, maxY, maxZ );
841   aGrid->SetPoints( aPoints );
842   aPoints->Delete();
843   // create cells
844   // 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
845   vtkIdList* anIdList = vtkIdList::New();
846   anIdList->SetNumberOfIds( 2 );
847   vtkCellArray* aCells = vtkCellArray::New();
848   aCells->Allocate( 2*12, 0);
849   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
850   aCellTypesArray->SetNumberOfComponents( 1 );
851   aCellTypesArray->Allocate( 12 );
852   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
853   aCells->InsertNextCell( anIdList );
854   aCellTypesArray->InsertNextValue( VTK_LINE );
855   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
856   aCells->InsertNextCell( anIdList );
857   aCellTypesArray->InsertNextValue( VTK_LINE );
858   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
859   aCells->InsertNextCell( anIdList );
860   aCellTypesArray->InsertNextValue( VTK_LINE );
861   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
862   aCells->InsertNextCell( anIdList );
863   aCellTypesArray->InsertNextValue( VTK_LINE );
864   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
865   aCells->InsertNextCell( anIdList );
866   aCellTypesArray->InsertNextValue( VTK_LINE );
867   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
868   aCells->InsertNextCell( anIdList );
869   aCellTypesArray->InsertNextValue( VTK_LINE );
870   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
871   aCells->InsertNextCell( anIdList );
872   aCellTypesArray->InsertNextValue( VTK_LINE );
873   anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
874   aCells->InsertNextCell( anIdList );
875   aCellTypesArray->InsertNextValue( VTK_LINE );
876   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
877   aCells->InsertNextCell( anIdList );
878   aCellTypesArray->InsertNextValue( VTK_LINE );
879   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
880   aCells->InsertNextCell( anIdList );
881   aCellTypesArray->InsertNextValue( VTK_LINE );
882   anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
883   aCells->InsertNextCell( anIdList );
884   aCellTypesArray->InsertNextValue( VTK_LINE );
885   anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
886   aCells->InsertNextCell( anIdList );
887   aCellTypesArray->InsertNextValue( VTK_LINE );
888   anIdList->Delete();
889   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
890   aCellLocationsArray->SetNumberOfComponents( 1 );
891   aCellLocationsArray->SetNumberOfTuples( 12 );
892   aCells->InitTraversal();
893   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
894     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
895   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
896   aCellLocationsArray->Delete();
897   aCellTypesArray->Delete();
898   aCells->Delete();
899   // create actor
900   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
901   aMapper->SetInputData( aGrid );
902   aGrid->Delete();
903   myPreview = SALOME_Actor::New();
904   myPreview->PickableOff();
905   myPreview->SetMapper( aMapper );
906   aMapper->Delete();
907   vtkProperty* aProp = vtkProperty::New();
908   aProp->SetRepresentationToWireframe();
909   aProp->SetColor( 250, 0, 250 );
910   aProp->SetPointSize( 5 );
911   aProp->SetLineWidth( 3 );
912   myPreview->SetProperty( aProp );
913   aProp->Delete();
914 }
915
916 /*!
917   \brief Called when selection is changed
918 */
919 void SMESHGUI_BoundingBox::selectionChanged()
920 {
921   SUIT_OverrideCursor wc;
922
923   SALOME_ListIO selected;
924   SMESHGUI::selectionMgr()->selectedObjects( selected );
925
926   if ( selected.Extent() == 1 ) {
927     Handle(SALOME_InteractiveObject) IO = selected.First();
928     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
929     if ( !CORBA::is_nil( obj ) ) {
930       mySrc.clear();
931       mySrc.append( obj );
932       myActor = SMESH::FindActorByEntry( IO->getEntry() );
933       if ( mySourceMode->checkedId() == ObjectsSrc ) {
934         QString aName;
935         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
936         mySource->setText( aName );
937       }
938       else {
939         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
940         QString ID;
941         int nb = 0;
942         if ( myActor && selector ) {
943           nb = mySourceMode->checkedId() == NodesSrc ? 
944             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
945             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
946         }
947         if ( nb > 0 ) {
948           myIDs = ID.trimmed();
949           if ( nb < MAX_NB_FOR_EDITOR ) {
950             mySource->setReadOnly( false );
951             if ( mySource->validator() != myValidator )
952               mySource->setValidator( myValidator );
953             mySource->setText( ID.trimmed() );
954           }
955           else {
956             mySource->setReadOnly( true );
957             mySource->setValidator( 0 );
958             mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
959                                .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
960           }
961         }
962         else {
963           myIDs = "";
964           mySource->clear();
965           mySource->setReadOnly( false );
966           mySource->setValidator( myValidator );
967         }
968       }
969     }
970   }
971   else if ( selected.Extent() > 1 ) {
972     myIDs = "";
973     SALOME_ListIteratorOfListIO It( selected );
974     mySrc.clear();
975     myActor = 0;
976     if ( mySourceMode->checkedId() == ObjectsSrc ) {
977       for( ; It.More(); It.Next()){
978         Handle(SALOME_InteractiveObject) IO = It.Value();
979         SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
980         if ( !CORBA::is_nil( obj ) ) {
981           mySrc.append( obj );
982         }
983       }
984       QString aName;
985       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
986       mySource->setText( aName );
987     }
988     else {
989       mySource->clear();
990     }
991   }
992   clear();
993 }
994
995 /*!
996   \brief Called when source mode is changed by the user
997 */
998 void SMESHGUI_BoundingBox::sourceChanged()
999 {
1000   myIDs = "";
1001   mySource->clear();
1002   mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
1003   mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
1004   updateSelection();
1005   clear();
1006 }
1007
1008 /*!
1009   \brief Called when source mode is edited by the user
1010 */
1011 void SMESHGUI_BoundingBox::sourceEdited()
1012 {
1013   if ( sender() == mySource )
1014     clear();
1015   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1016   if ( myActor && selector ) {
1017     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1018     if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1019       TColStd_MapOfInteger ID;
1020       if ( !mySource->isReadOnly() )
1021         myIDs = mySource->text();
1022       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1023       foreach ( QString id, ids )
1024         ID.Add( id.trimmed().toLong() );
1025       selector->AddOrRemoveIndex( IO, ID, false );
1026     }
1027     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1028       aViewWindow->highlight( IO, true, true );
1029   }
1030 }
1031
1032 /*!
1033   \brief Calculate bounding box of the selected object(s)
1034 */
1035 void SMESHGUI_BoundingBox::compute()
1036 {
1037   SUIT_OverrideCursor wc;
1038   SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1039   if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1040     if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1041       SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1042       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1043       if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1044         SMESH::long_array_var ids_in = new SMESH::long_array();
1045         ids_in->length( ids.count() );
1046         for( int i = 0; i < ids.count(); i++ )
1047           ids_in[i] = ids[i].trimmed().toLong();
1048         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1049         SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); 
1050         srcList->length( 1 );
1051         srcList[0] = s;
1052       }
1053     }
1054   }
1055   else {
1056     srcList->length( mySrc.count() );
1057     for( int i = 0; i < mySrc.count(); i++ ) {
1058       srcList[i] = mySrc[i];
1059       mySrc[i]->Register();
1060     }
1061   }
1062   if ( srcList->length() > 0 ) {
1063     // compute bounding box
1064     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1065     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1066     SMESH::Measure result = measure->BoundingBox( srcList.in() );
1067     SALOME::UnRegister( srcList );
1068     measure->UnRegister();
1069     myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1070     myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1071     myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1072     myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1073     myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1074     myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1075     myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1076     myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1077     myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1078     // update preview actor
1079     erasePreview();
1080     createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1081     displayPreview();
1082   }
1083   else {
1084     clear();
1085   }
1086 }
1087
1088 /*!
1089   \brief Reset the widget to the initial state (nullify result fields)
1090 */
1091 void SMESHGUI_BoundingBox::clear()
1092 {
1093   myXmin->clear();
1094   myXmax->clear();
1095   myDX->clear();
1096   myYmin->clear();
1097   myYmax->clear();
1098   myDY->clear();
1099   myZmin->clear();
1100   myZmax->clear();
1101   myDZ->clear();
1102   erasePreview();
1103 }
1104
1105 /*!
1106   \class SMESHGUI_BasicProperties
1107   \brief basic properties measurement widget.
1108   
1109   Widget to calculate length, area or volume for the selected object(s).
1110 */
1111
1112 /*!
1113   \brief Constructor.
1114   \param parent parent widget
1115 */
1116 SMESHGUI_BasicProperties::SMESHGUI_BasicProperties( QWidget* parent )
1117 : QWidget( parent )
1118 {
1119   // Property (length, area or volume)
1120   QGroupBox* aPropertyGrp = new QGroupBox( tr( "PROPERTY" ), this );
1121
1122   QRadioButton* aLength = new QRadioButton( tr( "LENGTH" ), aPropertyGrp );
1123   QRadioButton* anArea = new QRadioButton( tr( "AREA" ), aPropertyGrp );
1124   QRadioButton* aVolume = new QRadioButton( tr( "VOLUME" ), aPropertyGrp );
1125
1126   myMode = new QButtonGroup( this );
1127   myMode->addButton( aLength, Length );
1128   myMode->addButton( anArea, Area );
1129   myMode->addButton( aVolume, Volume );
1130
1131   QHBoxLayout* aPropertyLayout = new QHBoxLayout;
1132   aPropertyLayout->addWidget( aLength );
1133   aPropertyLayout->addWidget( anArea );
1134   aPropertyLayout->addWidget( aVolume );
1135
1136   aPropertyGrp->setLayout( aPropertyLayout );
1137
1138   // Source object
1139   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE_MESH_SUBMESH_GROUP" ), this );
1140
1141   mySource = new QLineEdit( aSourceGrp );
1142   mySource->setReadOnly( true );
1143     
1144   QHBoxLayout* aSourceLayout = new QHBoxLayout;
1145   aSourceLayout->addWidget( mySource );
1146   
1147   aSourceGrp->setLayout( aSourceLayout );
1148
1149   // Compute button
1150   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1151
1152   // Result of computation (length, area or volume)
1153   myResultGrp = new QGroupBox( this );
1154
1155   myResult = new QLineEdit;
1156   myResult->setReadOnly( true );
1157
1158   QHBoxLayout* aResultLayout = new QHBoxLayout;
1159   aResultLayout->addWidget( myResult );
1160   
1161   myResultGrp->setLayout( aResultLayout );
1162
1163   // Layout
1164   QGridLayout* aMainLayout = new QGridLayout( this );
1165   aMainLayout->setMargin( MARGIN );
1166   aMainLayout->setSpacing( SPACING );
1167
1168   aMainLayout->addWidget( aPropertyGrp, 0, 0, 1, 2 );
1169   aMainLayout->addWidget( aSourceGrp, 1, 0, 1, 2 );
1170   aMainLayout->addWidget( aCompute,   2, 0 );
1171   aMainLayout->addWidget( myResultGrp, 3, 0, 1, 2 );
1172   aMainLayout->setColumnStretch( 1, 5 );
1173   aMainLayout->setRowStretch( 4, 5 );
1174
1175   // Initial state
1176   setMode( Length );
1177   
1178   // Connections
1179   connect( myMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( modeChanged( int ) ) );
1180   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
1181   
1182   // Selection filter
1183   QList<SUIT_SelectionFilter*> filters;
1184   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
1185   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
1186   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
1187 }
1188
1189 /*!
1190   \brief Destructor
1191 */
1192 SMESHGUI_BasicProperties::~SMESHGUI_BasicProperties()
1193 {
1194 }
1195
1196 /*!
1197   \brief Sets the measurement mode.
1198   \param theMode the mode to set (length, area or volume meausurement)
1199 */
1200 void SMESHGUI_BasicProperties::setMode( const Mode theMode )
1201 {
1202   QRadioButton* aButton = qobject_cast<QRadioButton*>( myMode->button( theMode ) );
1203   if ( aButton ) {
1204     aButton->setChecked( true );
1205     modeChanged( theMode );
1206   }
1207 }
1208
1209 /*!
1210   \brief Setup the selection mode.
1211 */
1212 void SMESHGUI_BasicProperties::updateSelection()
1213 {
1214   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1215
1216   disconnect( selMgr, 0, this, 0 );
1217   selMgr->clearFilters();
1218   
1219   SMESH::SetPointRepresentation( false );
1220   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
1221     aViewWindow->SetSelectionMode( ActorSelection );
1222   }
1223   selMgr->installFilter( myFilter );
1224   
1225   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
1226
1227   if ( mySource->text().isEmpty() )
1228     selectionChanged();
1229 }
1230
1231 /*!
1232   \brief Deactivate widget
1233 */
1234 void SMESHGUI_BasicProperties::deactivate()
1235 {
1236   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
1237 }
1238
1239 /*!
1240   \brief Called when selection is changed
1241 */
1242 void SMESHGUI_BasicProperties::selectionChanged()
1243 {
1244   SUIT_OverrideCursor wc;
1245
1246   SALOME_ListIO selected;
1247   SMESHGUI::selectionMgr()->selectedObjects( selected );
1248
1249   if ( selected.Extent() == 1 ) {
1250     Handle(SALOME_InteractiveObject) IO = selected.First();
1251     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1252     if ( !CORBA::is_nil( obj ) ) {
1253       mySrc = obj;
1254
1255       QString aName;
1256       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
1257       mySource->setText( aName );
1258     }
1259   }
1260
1261   clear();
1262 }
1263
1264 /*!
1265   \brief Called when the measurement mode selection is changed.
1266   \param theMode the selected mode
1267 */
1268 void SMESHGUI_BasicProperties::modeChanged( int theMode )
1269 {
1270   clear();
1271
1272   if ( theMode == Length ) {
1273     myResultGrp->setTitle( tr("LENGTH") );
1274   } else if ( theMode == Area ) {
1275     myResultGrp->setTitle( tr("AREA") );
1276   } else if ( theMode == Volume ) {
1277     myResultGrp->setTitle( tr("VOLUME") );
1278   }
1279 }
1280
1281 /*!
1282   \brief Calculate length, area or volume for the selected object(s)
1283 */
1284 void SMESHGUI_BasicProperties::compute()
1285 {
1286   SUIT_OverrideCursor wc;
1287
1288   SMESH::SMESH_IDSource_var source;
1289
1290   if ( !CORBA::is_nil( mySrc ) ) {
1291     // compute
1292     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1293     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1294
1295     double result = 0;
1296
1297     if ( myMode->checkedId() == Length ) {
1298       result = measure->Length( mySrc.in() );
1299     } else if ( myMode->checkedId() == Area ) {
1300       result = measure->Area( mySrc.in() );
1301     } else if ( myMode->checkedId() == Volume ) {
1302       result = measure->Volume( mySrc.in() );
1303     }
1304     
1305     measure->UnRegister();
1306
1307     myResult->setText( QString::number( result, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1308   } else {
1309     clear();
1310   }
1311 }
1312
1313 /*!
1314   \brief Reset the widget to the initial state (nullify the result field)
1315 */
1316 void SMESHGUI_BasicProperties::clear()
1317 {
1318   myResult->clear();
1319 }
1320
1321 /*!
1322   \class SMESHGUI_Angle
1323   \brief Angle measurement widget.
1324   
1325   Widget to calculate angle between 3 nodes.
1326 */
1327
1328 /*!
1329   \brief Constructor.
1330   \param parent parent widget
1331 */
1332 SMESHGUI_Angle::SMESHGUI_Angle( QWidget* parent )
1333   : QWidget( parent )
1334 {
1335   // 3 nodes
1336
1337   QGroupBox* aNodesGrp = new QGroupBox( tr( "NODES_GROUP" ), this );
1338   myNodes = new QLineEdit( aNodesGrp );
1339   myNodes->setValidator( new SMESHGUI_IdValidator( this, 3 ));
1340   QHBoxLayout* aNodesLayout = new QHBoxLayout( aNodesGrp );
1341   aNodesLayout->addWidget( myNodes );
1342   
1343   // Compute button
1344   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1345
1346   // Angle
1347
1348   QGroupBox* aResultGrp = new QGroupBox( tr( "RESULT" ), this );
1349
1350   myResult = new QLineEdit;
1351   myResult->setReadOnly( true );
1352
1353   QHBoxLayout* aResultLayout = new QHBoxLayout( aResultGrp );
1354   aResultLayout->addWidget( myResult );
1355   
1356   // Layout
1357
1358   QGridLayout* aMainLayout = new QGridLayout( this );
1359   aMainLayout->setMargin( MARGIN );
1360   aMainLayout->setSpacing( SPACING );
1361
1362   aMainLayout->addWidget( aNodesGrp,   0, 0, 1, 2 );
1363   aMainLayout->addWidget( aCompute,    1, 0 );
1364   aMainLayout->addWidget( aResultGrp, 2, 0, 1, 2 );
1365   aMainLayout->setColumnStretch( 1, 5 );
1366   aMainLayout->setRowStretch( 3, 5 );
1367
1368   // Connections
1369   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ));
1370
1371   // preview
1372   myPreview = 0;
1373   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1374   {
1375     myPreview = new SMESHGUI_MeshEditPreview( aViewWindow );
1376     if ( myPreview && myPreview->GetActor() )
1377       myPreview->GetActor()->GetProperty()->SetLineWidth( 5 );
1378   }
1379   myActor = 0;
1380 }
1381
1382 SMESHGUI_Angle::~SMESHGUI_Angle()
1383 {
1384   if ( myPreview )
1385     delete myPreview;
1386 }
1387
1388 /*!
1389   \brief Setup selection mode
1390 */
1391 void SMESHGUI_Angle::updateSelection()
1392 {
1393   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1394
1395   disconnect( selMgr, 0, this, 0 );
1396   selMgr->clearFilters();
1397
1398   SMESH::SetPointRepresentation( true );
1399   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1400     aViewWindow->SetSelectionMode( NodeSelection );
1401
1402   connect( selMgr,  SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ));
1403   connect( myNodes, SIGNAL( textEdited( QString ) ),     this, SLOT( nodesEdited() ));
1404
1405   if ( myPoints.empty() )
1406     selectionChanged();
1407 }
1408
1409 /*!
1410   \brief Called when selection is changed
1411 */
1412 void SMESHGUI_Angle::selectionChanged()
1413 {
1414   clear();
1415   QString nodesString;
1416
1417   TColStd_IndexedMapOfInteger idsMap;
1418   SALOME_ListIO selected;
1419   SMESHGUI::selectionMgr()->selectedObjects( selected );
1420   selected.Reverse(); // to keep order of selection
1421
1422   SALOME_ListIteratorOfListIO ioIterator( selected );
1423   for ( ; ioIterator.More(); ioIterator.Next() )
1424   {
1425     Handle(SALOME_InteractiveObject) IO = ioIterator.Value();
1426
1427     idsMap.Clear();
1428     if ( SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector() )
1429       selector->GetIndex( IO, idsMap );
1430
1431     if ( SMESH_Actor* actor = SMESH::FindActorByEntry( IO->getEntry() ))
1432     {
1433       myActor = actor;
1434       for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1435         if ( addPointByActor( idsMap(i) ))
1436           nodesString += QString(" %1").arg( idsMap(i) );
1437       idsMap.Clear();
1438     }
1439     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1440     if ( !CORBA::is_nil( obj ) )
1441     {
1442       myIDSrc = obj;
1443       for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1444         if ( addPointByIDSource( idsMap(i) ))
1445           nodesString += QString(" %1").arg( idsMap(i) );
1446     }
1447   }
1448
1449   myNodes->setText( nodesString );
1450 }
1451
1452 //=======================================================================
1453 //function : clear
1454 //purpose  : Erase preview and result
1455 //=======================================================================
1456
1457 void SMESHGUI_Angle::clear()
1458 {
1459   myPoints.clear();
1460   myResult->clear();
1461   if ( myPreview && myPreview->GetActor())
1462   {
1463     myPreview->GetActor()->SetVisibility( false );
1464     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1465       aViewWindow->Repaint();
1466   }
1467 }
1468
1469 //=======================================================================
1470 //function : addPointByActor
1471 //purpose  : append to myPoints XYZ got from myActor
1472 //=======================================================================
1473
1474 bool SMESHGUI_Angle::addPointByActor( int id )
1475 {
1476   size_t nbP = myPoints.size();
1477
1478   if ( myActor )
1479   {
1480     TVisualObjPtr obj = myActor->GetObject();
1481     if ( SMDS_Mesh* mesh = obj->GetMesh() )
1482       if ( const SMDS_MeshNode* node = mesh->FindNode( id ))
1483       {
1484         SMESH::PointStruct p = { node->X(), node->Y(), node->Z() };
1485         myPoints.push_back( p );
1486       }
1487   }
1488   return nbP < myPoints.size();
1489 }
1490
1491 //=======================================================================
1492 //function : addPointByIDSource
1493 //purpose  : append to myPoints XYZ got from myIDSrc
1494 //=======================================================================
1495
1496 bool SMESHGUI_Angle::addPointByIDSource( int id )
1497 {
1498   size_t nbP = myPoints.size();
1499
1500   if ( !myIDSrc->_is_nil() )
1501   {
1502     SMESH::SMESH_Mesh_var mesh = myIDSrc->GetMesh();
1503     if ( !mesh->_is_nil() )
1504     {
1505       SMESH::double_array_var xyz = mesh->GetNodeXYZ( id );
1506       if ( xyz->length() == 3 )
1507       {
1508         SMESH::PointStruct p = { xyz[0], xyz[1], xyz[2] };
1509         myPoints.push_back( p );
1510       }
1511     }
1512   }
1513   return nbP < myPoints.size();
1514 }
1515
1516 //=======================================================================
1517 //function : nodesEdited
1518 //purpose  : SLOT called when the user types node IDs
1519 //=======================================================================
1520
1521 void SMESHGUI_Angle::nodesEdited()
1522 {
1523   clear();
1524
1525   TColStd_MapOfInteger ID;
1526   QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1527   foreach ( QString idStr, ids )
1528   {
1529     int id = idStr.trimmed().toLong();
1530     if (( !ID.Contains( id )) &&
1531         ( addPointByActor( id ) || addPointByIDSource( id )))
1532       ID.Add( id );
1533   }
1534
1535   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1536   if ( myActor && selector )
1537   {
1538     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1539     selector->AddOrRemoveIndex( IO, ID, false );
1540     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1541       aViewWindow->highlight( IO, true, true );
1542   }
1543 }
1544
1545 //=======================================================================
1546 //function : compute
1547 //purpose  : SLOT. Compute angle and show preview
1548 //=======================================================================
1549
1550 void SMESHGUI_Angle::compute()
1551 {
1552   if ( myPoints.size() != 3 )
1553     return;
1554
1555   // --------------
1556   // compute angle
1557   // --------------
1558
1559   SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1560   double radians = measure->Angle( myPoints[0], myPoints[1], myPoints[2] );
1561   measure->UnRegister();
1562   if ( radians < 0 )
1563     return;
1564
1565   int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1566   myResult->setText( QString::number( radians * 180 / M_PI,
1567                                       precision > 0 ? 'f' : 'g', qAbs( precision )));
1568
1569   // -------------
1570   // show preview
1571   // -------------
1572
1573   if ( !myPreview || !myPreview->GetActor() )
1574     return;
1575
1576   SMESH::MeshPreviewStruct preveiwData;
1577
1578   const double     anglePerSeg = 5 * M_PI/180; // angle per an arc segment
1579   const double arcRadiusFactor = 0.5;          // arc position, from p1
1580
1581   gp_Pnt p0 ( myPoints[0].x, myPoints[0].y, myPoints[0].z );
1582   gp_Pnt p1 ( myPoints[1].x, myPoints[1].y, myPoints[1].z );
1583   gp_Pnt p2 ( myPoints[2].x, myPoints[2].y, myPoints[2].z );
1584   gp_Vec vec10( p1, p0 ), vec12( p1, p2 ), norm( vec10 ^ vec12 );
1585
1586   if ( norm.Magnitude() <= gp::Resolution() ) // 180 degrees
1587     norm = getNormal( vec10 );
1588
1589   double     len10 = vec10.Magnitude();
1590   double     len12 = vec12.Magnitude();
1591   double    lenMax = Max( len10, len12 );
1592   double arcRadius = arcRadiusFactor * lenMax;
1593
1594   p0 = p1.Translated( lenMax * vec10.Normalized() );
1595   p2 = p1.Translated( lenMax * vec12.Normalized() );
1596
1597   gp_Circ arc( gp_Ax2( p1, norm, vec10 ), arcRadius );
1598
1599   int nbRadialSegmensts = ceil( radians / anglePerSeg ) + 1;
1600   int           nbNodes = 3 + ( nbRadialSegmensts + 1 );
1601
1602   // coordinates
1603   preveiwData.nodesXYZ.length( nbNodes );
1604   int iP = 0;
1605   for ( ; iP < nbRadialSegmensts + 1; ++iP )
1606   {
1607     double u = double( iP ) / nbRadialSegmensts * radians;
1608     gp_Pnt p = ElCLib::Value( u, arc );
1609     preveiwData.nodesXYZ[ iP ].x = p.X();
1610     preveiwData.nodesXYZ[ iP ].y = p.Y();
1611     preveiwData.nodesXYZ[ iP ].z = p.Z();
1612   }
1613   int iP0 = iP;
1614   preveiwData.nodesXYZ[ iP ].x = p0.X();
1615   preveiwData.nodesXYZ[ iP ].y = p0.Y();
1616   preveiwData.nodesXYZ[ iP ].z = p0.Z();
1617   int iP1 = ++iP;
1618   preveiwData.nodesXYZ[ iP ].x = p1.X();
1619   preveiwData.nodesXYZ[ iP ].y = p1.Y();
1620   preveiwData.nodesXYZ[ iP ].z = p1.Z();
1621   int iP2 = ++iP;
1622   preveiwData.nodesXYZ[ iP ].x = p2.X();
1623   preveiwData.nodesXYZ[ iP ].y = p2.Y();
1624   preveiwData.nodesXYZ[ iP ].z = p2.Z();
1625
1626   // connectivity
1627   preveiwData.elementConnectivities.length( 2 * ( 2 + nbRadialSegmensts ));
1628   for ( int iSeg = 0; iSeg < nbRadialSegmensts; ++iSeg )
1629   {
1630     preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iSeg;
1631     preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iSeg + 1;
1632   }
1633   int iSeg = nbRadialSegmensts;
1634   preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP0;
1635   preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP1;
1636   ++iSeg;
1637   preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP1;
1638   preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP2;
1639
1640   // types
1641   preveiwData.elementTypes.length( 2 + nbRadialSegmensts );
1642   SMESH::ElementSubType type = { SMESH::EDGE, /*isPoly=*/false, /*nbNodesInElement=*/2 };
1643   for ( CORBA::ULong i = 0; i < preveiwData.elementTypes.length(); ++i )
1644     preveiwData.elementTypes[ i ] = type;
1645
1646   myPreview->SetData( preveiwData );
1647 }
1648
1649 //================================================================================
1650 /*!
1651  * \brief Return normal to a plane of drawing in the case of 180 degrees angle
1652  */
1653 //================================================================================
1654
1655 gp_Vec SMESHGUI_Angle::getNormal(const gp_Vec& vec10 )
1656 {
1657   gp_XYZ norm;
1658
1659   // try to get normal by a face at the 2nd node
1660   if ( myActor && myActor->GetObject()->GetMesh() )
1661   {
1662     QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1663     SMDS_Mesh* mesh = myActor->GetObject()->GetMesh();
1664     if ( const SMDS_MeshNode* n = mesh->FindNode( ids[1].trimmed().toLong() ))
1665     {
1666       SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face );
1667       while ( faceIt->more() )
1668         if ( SMESH_MeshAlgos::FaceNormal( faceIt->next(), norm ))
1669           return norm;
1670     }
1671   }
1672   int iMinCoord = 1;
1673   if ( vec10.Coord( iMinCoord ) > vec10.Y() ) iMinCoord = 2;
1674   if ( vec10.Coord( iMinCoord ) > vec10.Z() ) iMinCoord = 3;
1675
1676   gp_Vec vec = vec10;
1677   vec.SetCoord( iMinCoord, vec10.Coord( iMinCoord ) + 1. );
1678
1679   return vec ^ vec10;
1680 }
1681
1682 /*!
1683   \class SMESHGUI_MeshInfoDlg
1684   \brief Centralized dialog box for the measurements
1685 */
1686
1687 /*!
1688   \brief Constructor
1689   \param parent parent widget
1690   \param page specifies the dialog page to be shown at the start-up
1691 */
1692 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1693   : QDialog( parent )
1694 {
1695   setModal( false );
1696   setAttribute( Qt::WA_DeleteOnClose, true );
1697   setWindowTitle( tr( "MEASUREMENTS" ) );
1698   setSizeGripEnabled( true );
1699
1700   SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1701
1702   myTabWidget = new QTabWidget( this );
1703
1704   // min distance
1705
1706   myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1707   int aMinDistInd = myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1708
1709   // bounding box
1710   
1711   myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1712   int aBndBoxInd = myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1713
1714   // basic properties
1715   
1716   myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
1717   int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
1718
1719   myAngle = new SMESHGUI_Angle( myTabWidget );
1720   int aAngleInd = myTabWidget->addTab( myAngle, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_ANGLE" ) ), tr( "ANGLE" ) );
1721
1722   // buttons
1723   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1724   okBtn->setAutoDefault( true );
1725   okBtn->setDefault( true );
1726   okBtn->setFocus();
1727   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1728   helpBtn->setAutoDefault( true );
1729
1730   QHBoxLayout* btnLayout = new QHBoxLayout;
1731   btnLayout->setSpacing( SPACING );
1732   btnLayout->setMargin( 0 );
1733   btnLayout->addWidget( okBtn );
1734   btnLayout->addStretch( 10 );
1735   btnLayout->addWidget( helpBtn );
1736
1737   QVBoxLayout* l = new QVBoxLayout ( this );
1738   l->setMargin( MARGIN );
1739   l->setSpacing( SPACING );
1740   l->addWidget( myTabWidget );
1741   l->addStretch();
1742   l->addLayout( btnLayout );
1743
1744   int anInd = -1;
1745   if ( page == MinDistance ) {
1746     anInd = aMinDistInd;
1747   } else if ( page == BoundingBox ) {
1748     anInd = aBndBoxInd;
1749   } else if ( page == Angle ) {
1750     anInd = aAngleInd;
1751   } else if ( page == Length || page == Area || page == Volume ) {
1752     myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
1753     anInd = aBasicPropInd;
1754   }
1755
1756   if ( anInd >= 0 ) {
1757     myTabWidget->setCurrentIndex( anInd );
1758   }
1759
1760   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
1761   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
1762   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
1763   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1764   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
1765
1766   updateSelection();
1767 }
1768
1769 /*!
1770   \brief Destructor
1771 */
1772 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1773 {
1774 }
1775
1776 /*!
1777   \brief Perform clean-up actions on the dialog box closing.
1778 */
1779 void SMESHGUI_MeasureDlg::reject()
1780 {
1781   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1782   selMgr->clearFilters();
1783   SMESH::SetPointRepresentation( false );
1784   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1785     aViewWindow->SetSelectionMode( ActorSelection );
1786   QDialog::reject();
1787 }
1788
1789 /*!
1790   \brief Process keyboard event
1791   \param e key press event
1792 */
1793 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1794 {
1795   QDialog::keyPressEvent( e );
1796   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1797     e->accept();
1798     help();
1799   }
1800 }
1801
1802 /*!
1803   \brief Reactivate dialog box, when mouse pointer goes into it.
1804 */
1805 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1806 {
1807   activate();
1808 }
1809
1810 /*!
1811   \brief Setup selection mode depending on the current dialog box state.
1812 */
1813 void SMESHGUI_MeasureDlg::updateSelection()
1814 {
1815   if ( myTabWidget->currentIndex() == MinDistance )
1816     myMinDist->updateSelection();
1817   else if ( myTabWidget->currentIndex() == BoundingBox )
1818     myBndBox->updateSelection();
1819   else if ( myTabWidget->currentWidget() == myAngle )
1820     myAngle->updateSelection();
1821   else {
1822     myBndBox->erasePreview();
1823     myBasicProps->updateSelection();
1824   }
1825 }
1826
1827 /*!
1828   \brief Show help page
1829 */
1830 void SMESHGUI_MeasureDlg::help()
1831 {
1832   QString aHelpFile;
1833   if ( myTabWidget->currentIndex() == MinDistance ) {
1834     aHelpFile = "measurements.html#min-distance-anchor";
1835   } else if ( myTabWidget->currentIndex() == BoundingBox ) {
1836     aHelpFile = "measurements.html#bounding-box-anchor";
1837   } else if ( myTabWidget->currentWidget() == myAngle ) {
1838     aHelpFile = "measurements.html#angle-anchor";
1839   } else {
1840     aHelpFile = "measurements.html#basic-properties-anchor";
1841   }
1842
1843   SMESH::ShowHelpFile( aHelpFile );
1844 }
1845
1846 /*!
1847   \brief Activate dialog box
1848 */
1849 void SMESHGUI_MeasureDlg::activate()
1850 {
1851   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1852   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1853   myTabWidget->setEnabled( true );
1854   updateSelection();
1855 }
1856
1857 /*!
1858   \brief Deactivate dialog box
1859 */
1860 void SMESHGUI_MeasureDlg::deactivate()
1861 {
1862   myBasicProps->deactivate();
1863   myMinDist->deactivate();
1864   myBndBox->deactivate();
1865   myTabWidget->setEnabled( false );
1866   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1867 }