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