Salome HOME
Fix regressions
[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_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   myPreview->SetResolveCoincidentTopology(true);
372   aMapper->Delete();
373   vtkProperty* aProp = vtkProperty::New();
374   aProp->SetRepresentationToWireframe();
375   aProp->SetColor( 250, 0, 250 );
376   aProp->SetPointSize( 5 );
377   aProp->SetLineWidth( 3 );
378   myPreview->SetProperty( aProp );
379   aProp->Delete();
380 }
381
382 /*!
383   \brief Called when selection is changed
384 */
385 void SMESHGUI_MinDistance::selectionChanged()
386 {
387   SUIT_OverrideCursor wc;
388
389   SALOME_ListIO selected;
390   SMESHGUI::selectionMgr()->selectedObjects( selected );
391
392   if ( selected.Extent() == 1 ) {
393     Handle(SALOME_InteractiveObject) IO = selected.First();
394     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
395     if ( !CORBA::is_nil( obj ) ) {
396       if ( myCurrentTgt == FirstTgt ) {
397         myFirstSrc = obj;
398         myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
399         if ( myFirst->checkedId() == ObjectTgt ) {
400           QString aName;
401           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
402           myFirstTgt->setText( aName );
403         }
404         else {
405           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
406           QString ID;
407           int nb = 0;
408           if ( myFirstActor && selector ) {
409             nb = myFirst->checkedId() == NodeTgt ? 
410               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
411               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
412           }
413           if ( nb == 1 )
414             myFirstTgt->setText( ID.trimmed() );
415           else
416             myFirstTgt->clear();
417         }
418       }
419       else if ( myCurrentTgt == SecondTgt ) {
420         mySecondSrc = obj;
421         mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
422         if ( mySecond->checkedId() == ObjectTgt ) {
423           QString aName;
424           SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
425           mySecondTgt->setText( aName );
426         }
427         else {
428           SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
429           QString ID;
430           int nb = 0;
431           if ( mySecondActor && selector ) {
432             nb = mySecond->checkedId() == NodeTgt ? 
433               SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
434               SMESH::GetNameOfSelectedNodes( selector, IO, ID );
435           }
436           if ( nb == 1 )
437             mySecondTgt->setText( ID.trimmed() );
438           else
439             mySecondTgt->clear();
440         }
441       }
442     }
443   }
444   clear();
445 }
446
447 /*!
448   \brief Called when first target mode is changed by the user
449 */
450 void SMESHGUI_MinDistance::firstChanged()
451 {
452   myFirstSrc = SMESH::SMESH_IDSource::_nil();
453   myFirstTgt->clear();
454   myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
455   myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
456   setTarget( FirstTgt );
457   updateSelection();
458   clear();
459 }
460
461 /*!
462   \brief Called when second target mode is changed by the user
463 */
464 void SMESHGUI_MinDistance::secondChanged()
465 {
466   mySecondSrc = SMESH::SMESH_IDSource::_nil();
467   mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
468   mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
469   mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
470   mySecondTgt->clear();
471   setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
472   updateSelection();
473   clear();
474 }
475
476 /*!
477   \brief Called when first target is edited by the user
478 */
479 void SMESHGUI_MinDistance::firstEdited()
480 {
481   setTarget( FirstTgt );
482   if ( sender() == myFirstTgt )
483     clear();
484   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
485   if ( myFirstActor && selector ) {
486     Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
487     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
488       TColStd_MapOfInteger ID;
489       ID.Add( myFirstTgt->text().toLong() );
490       selector->AddOrRemoveIndex( IO, ID, false );
491     }
492     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
493       aViewWindow->highlight( IO, true, true );
494   }
495 }
496
497 /*!
498   \brief Called when second target is edited by the user
499 */
500 void SMESHGUI_MinDistance::secondEdited()
501 {
502   setTarget( SecondTgt );
503   if ( sender() == mySecondTgt )
504     clear();
505   QString text = mySecondTgt->text();
506   if ( !mySecondActor )
507   {
508     selectionChanged();
509     mySecondTgt->setText( text );
510   }
511   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
512   if ( mySecondActor && selector ) {
513     Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
514     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
515       if ( !text.isEmpty() ) {
516         TColStd_MapOfInteger ID;
517         ID.Add( text.toLong() );
518         selector->AddOrRemoveIndex( IO, ID, false );
519       }
520     }
521     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
522       aViewWindow->highlight( IO, true, true );
523   }
524 }
525
526 /*!
527   \brief Compute the minimum distance between targets
528 */
529 void SMESHGUI_MinDistance::compute()
530 {
531   SUIT_OverrideCursor wc;
532   SMESH::IDSource_wrap s1;
533   SMESH::IDSource_wrap s2;
534   bool isOrigin = mySecond->checkedId() == OriginTgt;
535
536   // process first target
537   if ( !CORBA::is_nil( myFirstSrc ) ) {
538     if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
539       SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
540       long id = myFirstTgt->text().toLong();
541       if ( !CORBA::is_nil( m ) && id ) {
542         SMESH::long_array_var ids = new SMESH::long_array();
543         ids->length( 1 );
544         ids[0] = id;
545         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
546         s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
547       }
548     }
549     else {
550       s1 = myFirstSrc;
551       s1->Register();
552     }
553   }
554
555   // process second target
556   if ( !CORBA::is_nil( mySecondSrc ) ) {
557     if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
558       SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
559       long id = mySecondTgt->text().toLong();
560       if ( !CORBA::is_nil( m ) && id ) {
561         SMESH::long_array_var ids = new SMESH::long_array();
562         ids->length( 1 );
563         ids[0] = id;
564         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
565         s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
566       }
567     }
568     else {
569       s2 = mySecondSrc;
570       s2->Register();
571     }
572   }
573
574   if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
575     // compute min distance
576     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
577     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
578     SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
579     measure->UnRegister();
580     myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
581     myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
582     myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
583     myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
584     // update preview actor
585     erasePreview();
586     double x1, y1, z1, x2, y2, z2;
587     SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 );
588     x1 = coord[0]; y1 = coord[1]; z1 = coord[2];
589     if ( isOrigin ) {
590       x2 = y2 = z2 = 0.;
591     }
592     else {
593       coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
594       x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
595     }
596     createPreview( x1, y1, z1, x2, y2, z2 );
597     displayPreview();
598   }
599   else {
600     clear();
601   }
602 }
603
604 /*!
605   \brief Reset the widget to the initial state (nullify result fields)
606 */
607 void SMESHGUI_MinDistance::clear()
608 {
609   myDX->clear();
610   myDY->clear();
611   myDZ->clear();
612   myDistance->clear();
613   erasePreview();
614 }
615
616 /*!
617   \class SMESHGUI_BoundingBox
618   \brief Bounding box measurement widget.
619   
620   Widget to calculate bounding box of the selected object(s).
621 */
622
623 /*!
624   \brief Constructor.
625   \param parent parent widget
626 */
627 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
628 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
629 {
630   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
631   QRadioButton* aObjects  = new QRadioButton( tr( "OBJECTS" ),  aSourceGrp );
632   QRadioButton* aNodes    = new QRadioButton( tr( "NODES" ),    aSourceGrp );
633   QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
634   mySource = new QLineEdit( aSourceGrp );
635   
636   QGridLayout* fl = new QGridLayout( aSourceGrp );
637   fl->setMargin( MARGIN );
638   fl->setSpacing( SPACING );
639   fl->addWidget( aObjects,   0, 0 );
640   fl->addWidget( aNodes,     0, 1 );
641   fl->addWidget( aElements,  0, 2 );
642   fl->addWidget( mySource,   1, 0, 1, 3 );
643   
644   mySourceMode = new QButtonGroup( this );
645   mySourceMode->addButton( aObjects,  ObjectsSrc );
646   mySourceMode->addButton( aNodes,    NodesSrc );
647   mySourceMode->addButton( aElements, ElementsSrc );
648
649   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
650
651   QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
652   QLabel* aXminLab = new QLabel( "Xmin", aResults );
653   myXmin           = new QLineEdit( aResults );
654   QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
655   myXmax           = new QLineEdit( aResults );
656   QLabel* aDxLab   = new QLabel( "dX", aResults );
657   myDX             = new QLineEdit( aResults );
658   QLabel* aYminLab = new QLabel( "Ymin", aResults );
659   myYmin           = new QLineEdit( aResults );
660   QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
661   myYmax           = new QLineEdit( aResults );
662   QLabel* aDyLab   = new QLabel( "dY", aResults );
663   myDY             = new QLineEdit( aResults );
664   QLabel* aZminLab = new QLabel( "Zmin", aResults );
665   myZmin           = new QLineEdit( aResults );
666   QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
667   myZmax           = new QLineEdit( aResults );
668   QLabel* aDzLab   = new QLabel( "dZ", aResults );
669   myDZ             = new QLineEdit( aResults );
670
671   QGridLayout* rl  = new QGridLayout( aResults );
672   rl->setMargin( MARGIN );
673   rl->setSpacing( SPACING );
674   rl->addWidget( aXminLab,   0, 0 );
675   rl->addWidget( myXmin,     0, 1 );
676   rl->addWidget( aXmaxLab,   0, 2 );
677   rl->addWidget( myXmax,     0, 3 );
678   rl->addWidget( aDxLab,     0, 4 );
679   rl->addWidget( myDX,       0, 5 );
680   rl->addWidget( aYminLab,   1, 0 );
681   rl->addWidget( myYmin,     1, 1 );
682   rl->addWidget( aYmaxLab,   1, 2 );
683   rl->addWidget( myYmax,     1, 3 );
684   rl->addWidget( aDyLab,     1, 4 );
685   rl->addWidget( myDY,       1, 5 );
686   rl->addWidget( aZminLab,   2, 0 );
687   rl->addWidget( myZmin,     2, 1 );
688   rl->addWidget( aZmaxLab,   2, 2 );
689   rl->addWidget( myZmax,     2, 3 );
690   rl->addWidget( aDzLab,     2, 4 );
691   rl->addWidget( myDZ,       2, 5 );
692
693   QGridLayout* l = new QGridLayout( this );
694   l->setMargin( MARGIN );
695   l->setSpacing( SPACING );
696
697   l->addWidget( aSourceGrp, 0, 0, 1, 2 );
698   l->addWidget( aCompute,   1, 0 );
699   l->addWidget( aResults,   2, 0, 1, 2 );
700   l->setColumnStretch( 1, 5 );
701   l->setRowStretch( 3, 5 );
702
703   aObjects->setChecked( true );
704   myXmin->setReadOnly( true );
705   myXmax->setReadOnly( true );
706   myDX->setReadOnly( true );
707   myYmin->setReadOnly( true );
708   myYmax->setReadOnly( true );
709   myDY->setReadOnly( true );
710   myZmin->setReadOnly( true );
711   myZmax->setReadOnly( true );
712   myDZ->setReadOnly( true );
713
714   myValidator = new SMESHGUI_IdValidator( this );
715
716   connect( mySourceMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( sourceChanged() ) );
717   connect( aCompute,     SIGNAL( clicked() ),             this, SLOT( compute() ) );
718   connect( mySource,     SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
719
720   QList<SUIT_SelectionFilter*> filters;
721   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
722   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
723   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
724
725   clear();
726 }
727
728 /*!
729   \brief Destructor
730 */
731 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
732 {
733   erasePreview();
734   if ( myPreview )
735     myPreview->Delete();
736 }
737
738 /*!
739   \brief Setup selection mode depending on the current widget state
740 */
741 void SMESHGUI_BoundingBox::updateSelection()
742 {
743   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
744
745   disconnect( selMgr, 0, this, 0 );
746   selMgr->clearFilters();
747   
748   bool nodeMode = mySourceMode->checkedId() == NodesSrc;
749   bool elemMode = mySourceMode->checkedId() == ElementsSrc;
750   bool objMode  = mySourceMode->checkedId() == ObjectsSrc;
751
752   if ( nodeMode ) {
753     SMESH::SetPointRepresentation( true );
754     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
755       aViewWindow->SetSelectionMode( NodeSelection );
756   }
757   else if ( elemMode ) {
758     SMESH::SetPointRepresentation( false );
759     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
760       aViewWindow->SetSelectionMode( CellSelection );
761   }
762   else if ( objMode ) {
763     SMESH::SetPointRepresentation( false );
764     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
765       aViewWindow->SetSelectionMode( ActorSelection );
766     selMgr->installFilter( myFilter );
767   }
768
769   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
770
771   sourceEdited();
772
773   if ( mySource->text().isEmpty() )
774     selectionChanged();
775 }
776
777 /*!
778   \brief Deactivate widget
779 */
780 void SMESHGUI_BoundingBox::deactivate()
781 {
782   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
783 }
784
785 /*!
786   \brief Erase preview actor
787 */
788 void SMESHGUI_BoundingBox::erasePreview()
789 {
790   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
791   if ( aViewWindow && myPreview ) {
792     aViewWindow->RemoveActor( myPreview );
793     aViewWindow->Repaint();
794   }
795 }
796
797 /*!
798   \brief Display preview actor
799 */
800 void SMESHGUI_BoundingBox::displayPreview()
801 {
802   SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
803   if ( aViewWindow && myPreview ) {
804     aViewWindow->AddActor( myPreview );
805     aViewWindow->Repaint();
806   }
807 }
808
809 /*!
810   \brief Create preview actor
811   \param minX min X coordinate of bounding box
812   \param maxX max X coordinate of bounding box
813   \param minY min Y coordinate of bounding box
814   \param maxY max Y coordinate of bounding box
815   \param minZ min Z coordinate of bounding box
816   \param maxZ max Z coordinate of bounding box
817 */
818 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
819 {
820   if ( myPreview )
821     myPreview->Delete();
822
823   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
824   // create points
825   vtkPoints* aPoints = vtkPoints::New();
826   aPoints->SetNumberOfPoints( 8 );
827   aPoints->SetPoint( 0, minX, minY, minZ );
828   aPoints->SetPoint( 1, maxX, minY, minZ );
829   aPoints->SetPoint( 2, minX, maxY, minZ );
830   aPoints->SetPoint( 3, maxX, maxY, minZ );
831   aPoints->SetPoint( 4, minX, minY, maxZ );
832   aPoints->SetPoint( 5, maxX, minY, maxZ );
833   aPoints->SetPoint( 6, minX, maxY, maxZ );
834   aPoints->SetPoint( 7, maxX, maxY, maxZ );
835   aGrid->SetPoints( aPoints );
836   aPoints->Delete();
837   // create cells
838   // 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
839   vtkIdList* anIdList = vtkIdList::New();
840   anIdList->SetNumberOfIds( 2 );
841   vtkCellArray* aCells = vtkCellArray::New();
842   aCells->Allocate( 2*12, 0);
843   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
844   aCellTypesArray->SetNumberOfComponents( 1 );
845   aCellTypesArray->Allocate( 12 );
846   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
847   aCells->InsertNextCell( anIdList );
848   aCellTypesArray->InsertNextValue( VTK_LINE );
849   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
850   aCells->InsertNextCell( anIdList );
851   aCellTypesArray->InsertNextValue( VTK_LINE );
852   anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
853   aCells->InsertNextCell( anIdList );
854   aCellTypesArray->InsertNextValue( VTK_LINE );
855   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
856   aCells->InsertNextCell( anIdList );
857   aCellTypesArray->InsertNextValue( VTK_LINE );
858   anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
859   aCells->InsertNextCell( anIdList );
860   aCellTypesArray->InsertNextValue( VTK_LINE );
861   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
862   aCells->InsertNextCell( anIdList );
863   aCellTypesArray->InsertNextValue( VTK_LINE );
864   anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
865   aCells->InsertNextCell( anIdList );
866   aCellTypesArray->InsertNextValue( VTK_LINE );
867   anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
868   aCells->InsertNextCell( anIdList );
869   aCellTypesArray->InsertNextValue( VTK_LINE );
870   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
871   aCells->InsertNextCell( anIdList );
872   aCellTypesArray->InsertNextValue( VTK_LINE );
873   anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
874   aCells->InsertNextCell( anIdList );
875   aCellTypesArray->InsertNextValue( VTK_LINE );
876   anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
877   aCells->InsertNextCell( anIdList );
878   aCellTypesArray->InsertNextValue( VTK_LINE );
879   anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
880   aCells->InsertNextCell( anIdList );
881   aCellTypesArray->InsertNextValue( VTK_LINE );
882   anIdList->Delete();
883   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
884   aCellLocationsArray->SetNumberOfComponents( 1 );
885   aCellLocationsArray->SetNumberOfTuples( 12 );
886   aCells->InitTraversal();
887   for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
888     aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
889   aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
890   aCellLocationsArray->Delete();
891   aCellTypesArray->Delete();
892   aCells->Delete();
893   // create actor
894   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
895   aMapper->SetInputData( aGrid );
896   aGrid->Delete();
897   myPreview = SALOME_Actor::New();
898   myPreview->PickableOff();
899   myPreview->SetMapper( aMapper );
900   aMapper->Delete();
901   vtkProperty* aProp = vtkProperty::New();
902   aProp->SetRepresentationToWireframe();
903   aProp->SetColor( 250, 0, 250 );
904   aProp->SetPointSize( 5 );
905   aProp->SetLineWidth( 3 );
906   myPreview->SetProperty( aProp );
907   aProp->Delete();
908 }
909
910 /*!
911   \brief Called when selection is changed
912 */
913 void SMESHGUI_BoundingBox::selectionChanged()
914 {
915   SUIT_OverrideCursor wc;
916
917   SALOME_ListIO selected;
918   SMESHGUI::selectionMgr()->selectedObjects( selected );
919
920   if ( selected.Extent() == 1 ) {
921     Handle(SALOME_InteractiveObject) IO = selected.First();
922     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
923     if ( !CORBA::is_nil( obj ) ) {
924       mySrc.clear();
925       mySrc.append( obj );
926       myActor = SMESH::FindActorByEntry( IO->getEntry() );
927       if ( mySourceMode->checkedId() == ObjectsSrc ) {
928         QString aName;
929         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
930         mySource->setText( aName );
931       }
932       else {
933         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
934         QString ID;
935         int nb = 0;
936         if ( myActor && selector ) {
937           nb = mySourceMode->checkedId() == NodesSrc ? 
938             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
939             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
940         }
941         if ( nb > 0 ) {
942           myIDs = ID.trimmed();
943           if ( nb < MAX_NB_FOR_EDITOR ) {
944             mySource->setReadOnly( false );
945             if ( mySource->validator() != myValidator )
946               mySource->setValidator( myValidator );
947             mySource->setText( ID.trimmed() );
948           }
949           else {
950             mySource->setReadOnly( true );
951             mySource->setValidator( 0 );
952             mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
953                                .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
954           }
955         }
956         else {
957           myIDs = "";
958           mySource->clear();
959           mySource->setReadOnly( false );
960           mySource->setValidator( myValidator );
961         }
962       }
963     }
964   }
965   else if ( selected.Extent() > 1 ) {
966     myIDs = "";
967     SALOME_ListIteratorOfListIO It( selected );
968     mySrc.clear();
969     myActor = 0;
970     if ( mySourceMode->checkedId() == ObjectsSrc ) {
971       for( ; It.More(); It.Next()){
972         Handle(SALOME_InteractiveObject) IO = It.Value();
973         SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
974         if ( !CORBA::is_nil( obj ) ) {
975           mySrc.append( obj );
976         }
977       }
978       QString aName;
979       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
980       mySource->setText( aName );
981     }
982     else {
983       mySource->clear();
984     }
985   }
986   clear();
987 }
988
989 /*!
990   \brief Called when source mode is changed by the user
991 */
992 void SMESHGUI_BoundingBox::sourceChanged()
993 {
994   myIDs = "";
995   mySource->clear();
996   mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
997   mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
998   updateSelection();
999   clear();
1000 }
1001
1002 /*!
1003   \brief Called when source mode is edited by the user
1004 */
1005 void SMESHGUI_BoundingBox::sourceEdited()
1006 {
1007   if ( sender() == mySource )
1008     clear();
1009   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1010   if ( myActor && selector ) {
1011     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1012     if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1013       TColStd_MapOfInteger ID;
1014       if ( !mySource->isReadOnly() )
1015         myIDs = mySource->text();
1016       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1017       foreach ( QString id, ids )
1018         ID.Add( id.trimmed().toLong() );
1019       selector->AddOrRemoveIndex( IO, ID, false );
1020     }
1021     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1022       aViewWindow->highlight( IO, true, true );
1023   }
1024 }
1025
1026 /*!
1027   \brief Calculate bounding box of the selected object(s)
1028 */
1029 void SMESHGUI_BoundingBox::compute()
1030 {
1031   SUIT_OverrideCursor wc;
1032   SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1033   if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1034     if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1035       SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1036       QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1037       if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1038         SMESH::long_array_var ids_in = new SMESH::long_array();
1039         ids_in->length( ids.count() );
1040         for( int i = 0; i < ids.count(); i++ )
1041           ids_in[i] = ids[i].trimmed().toLong();
1042         SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1043         SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE ); 
1044         srcList->length( 1 );
1045         srcList[0] = s;
1046       }
1047     }
1048   }
1049   else {
1050     srcList->length( mySrc.count() );
1051     for( int i = 0; i < mySrc.count(); i++ ) {
1052       srcList[i] = mySrc[i];
1053       mySrc[i]->Register();
1054     }
1055   }
1056   if ( srcList->length() > 0 ) {
1057     // compute bounding box
1058     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1059     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1060     SMESH::Measure result = measure->BoundingBox( srcList.in() );
1061     SALOME::UnRegister( srcList );
1062     measure->UnRegister();
1063     myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1064     myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1065     myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1066     myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1067     myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1068     myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1069     myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1070     myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1071     myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1072     // update preview actor
1073     erasePreview();
1074     createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1075     displayPreview();
1076   }
1077   else {
1078     clear();
1079   }
1080 }
1081
1082 /*!
1083   \brief Reset the widget to the initial state (nullify result fields)
1084 */
1085 void SMESHGUI_BoundingBox::clear()
1086 {
1087   myXmin->clear();
1088   myXmax->clear();
1089   myDX->clear();
1090   myYmin->clear();
1091   myYmax->clear();
1092   myDY->clear();
1093   myZmin->clear();
1094   myZmax->clear();
1095   myDZ->clear();
1096   erasePreview();
1097 }
1098
1099 /*!
1100   \class SMESHGUI_BasicProperties
1101   \brief basic properties measurement widget.
1102   
1103   Widget to calculate length, area or volume for the selected object(s).
1104 */
1105
1106 /*!
1107   \brief Constructor.
1108   \param parent parent widget
1109 */
1110 SMESHGUI_BasicProperties::SMESHGUI_BasicProperties( QWidget* parent )
1111 : QWidget( parent )
1112 {
1113   // Property (length, area or volume)
1114   QGroupBox* aPropertyGrp = new QGroupBox( tr( "PROPERTY" ), this );
1115
1116   QRadioButton* aLength = new QRadioButton( tr( "LENGTH" ), aPropertyGrp );
1117   QRadioButton* anArea = new QRadioButton( tr( "AREA" ), aPropertyGrp );
1118   QRadioButton* aVolume = new QRadioButton( tr( "VOLUME" ), aPropertyGrp );
1119
1120   myMode = new QButtonGroup( this );
1121   myMode->addButton( aLength, Length );
1122   myMode->addButton( anArea, Area );
1123   myMode->addButton( aVolume, Volume );
1124
1125   QHBoxLayout* aPropertyLayout = new QHBoxLayout;
1126   aPropertyLayout->addWidget( aLength );
1127   aPropertyLayout->addWidget( anArea );
1128   aPropertyLayout->addWidget( aVolume );
1129
1130   aPropertyGrp->setLayout( aPropertyLayout );
1131
1132   // Source object
1133   QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE_MESH_SUBMESH_GROUP" ), this );
1134
1135   mySource = new QLineEdit( aSourceGrp );
1136   mySource->setReadOnly( true );
1137     
1138   QHBoxLayout* aSourceLayout = new QHBoxLayout;
1139   aSourceLayout->addWidget( mySource );
1140   
1141   aSourceGrp->setLayout( aSourceLayout );
1142
1143   // Compute button
1144   QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1145
1146   // Result of computation (length, area or volume)
1147   myResultGrp = new QGroupBox( this );
1148
1149   myResult = new QLineEdit;
1150   myResult->setReadOnly( true );
1151
1152   QHBoxLayout* aResultLayout = new QHBoxLayout;
1153   aResultLayout->addWidget( myResult );
1154   
1155   myResultGrp->setLayout( aResultLayout );
1156
1157   // Layout
1158   QGridLayout* aMainLayout = new QGridLayout( this );
1159   aMainLayout->setMargin( MARGIN );
1160   aMainLayout->setSpacing( SPACING );
1161
1162   aMainLayout->addWidget( aPropertyGrp, 0, 0, 1, 2 );
1163   aMainLayout->addWidget( aSourceGrp, 1, 0, 1, 2 );
1164   aMainLayout->addWidget( aCompute,   2, 0 );
1165   aMainLayout->addWidget( myResultGrp, 3, 0, 1, 2 );
1166   aMainLayout->setColumnStretch( 1, 5 );
1167   aMainLayout->setRowStretch( 4, 5 );
1168
1169   // Initial state
1170   setMode( Length );
1171   
1172   // Connections
1173   connect( myMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( modeChanged( int ) ) );
1174   connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
1175   
1176   // Selection filter
1177   QList<SUIT_SelectionFilter*> filters;
1178   filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
1179   filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
1180   myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
1181 }
1182
1183 /*!
1184   \brief Destructor
1185 */
1186 SMESHGUI_BasicProperties::~SMESHGUI_BasicProperties()
1187 {
1188 }
1189
1190 /*!
1191   \brief Sets the measurement mode.
1192   \param theMode the mode to set (length, area or volume meausurement)
1193 */
1194 void SMESHGUI_BasicProperties::setMode( const Mode theMode )
1195 {
1196   QRadioButton* aButton = qobject_cast<QRadioButton*>( myMode->button( theMode ) );
1197   if ( aButton ) {
1198     aButton->setChecked( true );
1199     modeChanged( theMode );
1200   }
1201 }
1202
1203 /*!
1204   \brief Setup the selection mode.
1205 */
1206 void SMESHGUI_BasicProperties::updateSelection()
1207 {
1208   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1209
1210   disconnect( selMgr, 0, this, 0 );
1211   selMgr->clearFilters();
1212   
1213   SMESH::SetPointRepresentation( false );
1214   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
1215     aViewWindow->SetSelectionMode( ActorSelection );
1216   }
1217   selMgr->installFilter( myFilter );
1218   
1219   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
1220
1221   if ( mySource->text().isEmpty() )
1222     selectionChanged();
1223 }
1224
1225 /*!
1226   \brief Deactivate widget
1227 */
1228 void SMESHGUI_BasicProperties::deactivate()
1229 {
1230   disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
1231 }
1232
1233 /*!
1234   \brief Called when selection is changed
1235 */
1236 void SMESHGUI_BasicProperties::selectionChanged()
1237 {
1238   SUIT_OverrideCursor wc;
1239
1240   SALOME_ListIO selected;
1241   SMESHGUI::selectionMgr()->selectedObjects( selected );
1242
1243   if ( selected.Extent() == 1 ) {
1244     Handle(SALOME_InteractiveObject) IO = selected.First();
1245     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1246     if ( !CORBA::is_nil( obj ) ) {
1247       mySrc = obj;
1248
1249       QString aName;
1250       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
1251       mySource->setText( aName );
1252     }
1253   }
1254
1255   clear();
1256 }
1257
1258 /*!
1259   \brief Called when the measurement mode selection is changed.
1260   \param theMode the selected mode
1261 */
1262 void SMESHGUI_BasicProperties::modeChanged( int theMode )
1263 {
1264   clear();
1265
1266   if ( theMode == Length ) {
1267     myResultGrp->setTitle( tr("LENGTH") );
1268   } else if ( theMode == Area ) {
1269     myResultGrp->setTitle( tr("AREA") );
1270   } else if ( theMode == Volume ) {
1271     myResultGrp->setTitle( tr("VOLUME") );
1272   }
1273 }
1274
1275 /*!
1276   \brief Calculate length, area or volume for the selected object(s)
1277 */
1278 void SMESHGUI_BasicProperties::compute()
1279 {
1280   SUIT_OverrideCursor wc;
1281
1282   SMESH::SMESH_IDSource_var source;
1283
1284   if ( !CORBA::is_nil( mySrc ) ) {
1285     // compute
1286     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1287     SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1288
1289     double result = 0;
1290
1291     if ( myMode->checkedId() == Length ) {
1292       result = measure->Length( mySrc.in() );
1293     } else if ( myMode->checkedId() == Area ) {
1294       result = measure->Area( mySrc.in() );
1295     } else if ( myMode->checkedId() == Volume ) {
1296       result = measure->Volume( mySrc.in() );
1297     }
1298     
1299     measure->UnRegister();
1300
1301     myResult->setText( QString::number( result, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1302   } else {
1303     clear();
1304   }
1305 }
1306
1307 /*!
1308   \brief Reset the widget to the initial state (nullify the result field)
1309 */
1310 void SMESHGUI_BasicProperties::clear()
1311 {
1312   myResult->clear();
1313 }
1314
1315 /*!
1316   \class SMESHGUI_MeshInfoDlg
1317   \brief Centralized dialog box for the measurements
1318 */
1319
1320 /*!
1321   \brief Constructor
1322   \param parent parent widget
1323   \param page specifies the dialog page to be shown at the start-up
1324 */
1325 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1326 : QDialog( parent )
1327 {
1328   setModal( false );
1329   setAttribute( Qt::WA_DeleteOnClose, true );
1330   setWindowTitle( tr( "MEASUREMENTS" ) );
1331   setSizeGripEnabled( true );
1332
1333   SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1334
1335   myTabWidget = new QTabWidget( this );
1336
1337   // min distance
1338
1339   myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1340   int aMinDistInd = myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1341
1342   // bounding box
1343   
1344   myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1345   int aBndBoxInd = myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1346
1347   // basic properties
1348   
1349   myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
1350   int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
1351
1352   // buttons
1353   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1354   okBtn->setAutoDefault( true );
1355   okBtn->setDefault( true );
1356   okBtn->setFocus();
1357   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1358   helpBtn->setAutoDefault( true );
1359
1360   QHBoxLayout* btnLayout = new QHBoxLayout;
1361   btnLayout->setSpacing( SPACING );
1362   btnLayout->setMargin( 0 );
1363   btnLayout->addWidget( okBtn );
1364   btnLayout->addStretch( 10 );
1365   btnLayout->addWidget( helpBtn );
1366
1367   QVBoxLayout* l = new QVBoxLayout ( this );
1368   l->setMargin( MARGIN );
1369   l->setSpacing( SPACING );
1370   l->addWidget( myTabWidget );
1371   l->addStretch();
1372   l->addLayout( btnLayout );
1373
1374   int anInd = -1;
1375   if ( page == MinDistance ) {
1376     anInd = aMinDistInd;
1377   } else if ( page == BoundingBox ) {
1378     anInd = aBndBoxInd;
1379   } else if ( page == Length || page == Area || page == Volume ) {
1380     myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
1381     anInd = aBasicPropInd;
1382   }
1383
1384   if ( anInd >= 0 ) {
1385     myTabWidget->setCurrentIndex( anInd );
1386   }
1387
1388   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
1389   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
1390   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
1391   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1392   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
1393
1394   updateSelection();
1395 }
1396
1397 /*!
1398   \brief Destructor
1399 */
1400 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1401 {
1402 }
1403
1404 /*!
1405   \brief Perform clean-up actions on the dialog box closing.
1406 */
1407 void SMESHGUI_MeasureDlg::reject()
1408 {
1409   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1410   selMgr->clearFilters();
1411   SMESH::SetPointRepresentation( false );
1412   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1413     aViewWindow->SetSelectionMode( ActorSelection );
1414   QDialog::reject();
1415 }
1416
1417 /*!
1418   \brief Process keyboard event
1419   \param e key press event
1420 */
1421 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1422 {
1423   QDialog::keyPressEvent( e );
1424   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1425     e->accept();
1426     help();
1427   }
1428 }
1429
1430 /*!
1431   \brief Reactivate dialog box, when mouse pointer goes into it.
1432 */
1433 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1434 {
1435   activate();
1436 }
1437
1438 /*!
1439   \brief Setup selection mode depending on the current dialog box state.
1440 */
1441 void SMESHGUI_MeasureDlg::updateSelection()
1442 {
1443   if ( myTabWidget->currentIndex() == MinDistance )
1444     myMinDist->updateSelection();
1445   else if ( myTabWidget->currentIndex() == BoundingBox )
1446     myBndBox->updateSelection();
1447   else {
1448     myBndBox->erasePreview();
1449     myBasicProps->updateSelection();
1450   }
1451 }
1452
1453 /*!
1454   \brief Show help page
1455 */
1456 void SMESHGUI_MeasureDlg::help()
1457 {
1458   QString aHelpFile;
1459   if ( myTabWidget->currentIndex() == MinDistance ) {
1460     aHelpFile = "measurements_page.html#min_distance_anchor";
1461   } else if ( myTabWidget->currentIndex() == BoundingBox ) {
1462     aHelpFile = "measurements_page.html#bounding_box_anchor";
1463   } else {
1464     aHelpFile = "measurements_page.html#basic_properties_anchor";
1465   }
1466
1467   SMESH::ShowHelpFile( aHelpFile );
1468 }
1469
1470 /*!
1471   \brief Activate dialog box
1472 */
1473 void SMESHGUI_MeasureDlg::activate()
1474 {
1475   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1476   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1477   myTabWidget->setEnabled( true );
1478   updateSelection();
1479 }
1480
1481 /*!
1482   \brief Deactivate dialog box
1483 */
1484 void SMESHGUI_MeasureDlg::deactivate()
1485 {
1486   myBasicProps->deactivate();
1487   myMinDist->deactivate();
1488   myBndBox->deactivate();
1489   myTabWidget->setEnabled( false );
1490   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1491 }