Salome HOME
Porting SMESH module to Qt 4
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_EditMeshDlg.cxx
1 // SMESH SMESHGUI : GUI for SMESH component
2 //
3 // Copyright (C) 2005  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. 
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_EditMeshDlg.cxx
23 // Author : Open CASCADE S.A.S.
24 //
25
26 // SMESH includes
27 #include "SMESHGUI_EditMeshDlg.h"
28
29 #include "SMESHGUI.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include "SMESHGUI_MeshUtils.h"
33 #include "SMESHGUI_SpinBox.h"
34
35 #include <SMESH_Actor.h>
36 #include <SMESH_TypeFilter.hxx>
37 #include <SMESH_LogicalFilter.hxx>
38 #include <SMDS_Mesh.hxx>
39
40 // SALOME GUI includes
41 #include <SUIT_Desktop.h>
42 #include <SUIT_ResourceMgr.h>
43 #include <SUIT_Session.h>
44 #include <SUIT_MessageBox.h>
45
46 #include <LightApp_Application.h>
47 #include <LightApp_SelectionMgr.h>
48
49 #include <SVTK_ViewModel.h>
50 #include <SVTK_ViewWindow.h>
51 #include <SALOME_ListIO.hxx>
52
53 // OCCT includes
54 #include <TColStd_MapOfInteger.hxx>
55 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
56
57 // IDL includes
58 #include <SALOMEconfig.h>
59 #include CORBA_SERVER_HEADER(SMESH_Group)
60 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
61
62 // VTK includes
63 #include <vtkUnstructuredGrid.h>
64 #include <vtkRenderer.h>
65 #include <vtkActor2D.h>
66 #include <vtkPoints.h>
67 #include <vtkDataSetMapper.h>
68 #include <vtkMaskPoints.h>
69 #include <vtkSelectVisiblePoints.h>
70 #include <vtkLabeledDataMapper.h>
71 #include <vtkTextProperty.h>
72 #include <vtkIntArray.h>
73 #include <vtkProperty2D.h>
74 #include <vtkPointData.h>
75
76 // Qt includes
77 #include <QApplication>
78 #include <QGroupBox>
79 #include <QLabel>
80 #include <QLineEdit>
81 #include <QListWidget>
82 #include <QPushButton>
83 #include <QRadioButton>
84 #include <QCheckBox>
85 #include <QHBoxLayout>
86 #include <QVBoxLayout>
87 #include <QGridLayout>
88 #include <QKeyEvent>
89
90 #define SPACING 6
91 #define MARGIN  11
92
93 namespace SMESH
94 {
95   class TIdPreview
96   { // to display in the viewer IDs of the selected elements
97     SVTK_ViewWindow* myViewWindow;
98
99     vtkUnstructuredGrid* myIdGrid;
100     SALOME_Actor* myIdActor;
101
102     vtkUnstructuredGrid* myPointsNumDataSet;
103     vtkMaskPoints* myPtsMaskPoints;
104     vtkSelectVisiblePoints* myPtsSelectVisiblePoints;
105     vtkLabeledDataMapper* myPtsLabeledDataMapper;
106     vtkTextProperty* aPtsTextProp;
107     bool myIsPointsLabeled;
108     vtkActor2D* myPointLabels;
109
110     vector<int> myIDs;
111
112   public:
113     TIdPreview(SVTK_ViewWindow* theViewWindow):
114       myViewWindow(theViewWindow)
115     {
116       myIdGrid = vtkUnstructuredGrid::New();
117
118       // Create and display actor
119       vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
120       aMapper->SetInput( myIdGrid );
121
122       myIdActor = SALOME_Actor::New();
123       myIdActor->SetInfinitive(true);
124       myIdActor->VisibilityOff();
125       myIdActor->PickableOff();
126
127       myIdActor->SetMapper( aMapper );
128       aMapper->Delete();
129
130       myViewWindow->AddActor(myIdActor);
131
132       //Definition of points numbering pipeline
133       myPointsNumDataSet = vtkUnstructuredGrid::New();
134
135       myPtsMaskPoints = vtkMaskPoints::New();
136       myPtsMaskPoints->SetInput(myPointsNumDataSet);
137       myPtsMaskPoints->SetOnRatio(1);
138
139       myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New();
140       myPtsSelectVisiblePoints->SetInput(myPtsMaskPoints->GetOutput());
141       myPtsSelectVisiblePoints->SelectInvisibleOff();
142       myPtsSelectVisiblePoints->SetTolerance(0.1);
143     
144       myPtsLabeledDataMapper = vtkLabeledDataMapper::New();
145       myPtsLabeledDataMapper->SetInput(myPtsSelectVisiblePoints->GetOutput());
146       myPtsLabeledDataMapper->SetLabelFormat("%g");
147       myPtsLabeledDataMapper->SetLabelModeToLabelScalars();
148     
149       vtkTextProperty* aPtsTextProp = vtkTextProperty::New();
150       aPtsTextProp->SetFontFamilyToTimes();
151       static int aPointsFontSize = 12;
152       aPtsTextProp->SetFontSize(aPointsFontSize);
153       aPtsTextProp->SetBold(1);
154       aPtsTextProp->SetItalic(0);
155       aPtsTextProp->SetShadow(0);
156       myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp);
157       aPtsTextProp->Delete();
158   
159       myIsPointsLabeled = false;
160
161       myPointLabels = vtkActor2D::New();
162       myPointLabels->SetMapper(myPtsLabeledDataMapper);
163       myPointLabels->GetProperty()->SetColor(1,1,1);
164       myPointLabels->SetVisibility(myIsPointsLabeled);
165
166       AddToRender(myViewWindow->getRenderer());
167     }
168
169     void SetPointsData ( SMDS_Mesh* theMesh, 
170                          TColStd_MapOfInteger & theNodesIdMap )
171     {
172       vtkPoints* aPoints = vtkPoints::New();
173       aPoints->SetNumberOfPoints(theNodesIdMap.Extent());
174       myIDs.clear();
175       
176       TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap );
177       for( int i = 0; idIter.More(); idIter.Next(), i++ ) {
178         const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key());
179         aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() );
180         myIDs.push_back(idIter.Key());
181       }
182
183       myIdGrid->SetPoints(aPoints);
184
185       aPoints->Delete();
186
187       myIdActor->GetMapper()->Update();
188     }
189
190     void SetElemsData( TColStd_MapOfInteger & theElemsIdMap, 
191                        list<gp_XYZ> & aGrCentersXYZ )
192     {
193       vtkPoints* aPoints = vtkPoints::New();
194       aPoints->SetNumberOfPoints(theElemsIdMap.Extent());
195       myIDs.clear();
196       
197       TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
198       for( ; idIter.More(); idIter.Next() ) {
199         myIDs.push_back(idIter.Key());
200       }
201
202       gp_XYZ aXYZ;
203       list<gp_XYZ>::iterator coordIt = aGrCentersXYZ.begin();
204       for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ ) {
205         aXYZ = *coordIt;
206         aPoints->SetPoint( i, aXYZ.X(), aXYZ.Y(), aXYZ.Z() );
207       }
208       myIdGrid->SetPoints(aPoints);
209       aPoints->Delete();
210       
211       myIdActor->GetMapper()->Update();
212     }
213
214     void AddToRender(vtkRenderer* theRenderer)
215     {
216       myIdActor->AddToRender(theRenderer);
217
218       myPtsSelectVisiblePoints->SetRenderer(theRenderer);
219       theRenderer->AddActor2D(myPointLabels);
220     }
221
222     void RemoveFromRender(vtkRenderer* theRenderer)
223     {
224       myIdActor->RemoveFromRender(theRenderer);
225
226       myPtsSelectVisiblePoints->SetRenderer(theRenderer);
227       theRenderer->RemoveActor(myPointLabels);
228     }
229
230     void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true )
231     {
232       myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints();
233       
234       if ( myIsPointsLabeled ) {
235         myPointsNumDataSet->ShallowCopy(myIdGrid);
236         vtkDataSet *aDataSet = myPointsNumDataSet;
237         int aNbElem = myIDs.size();
238         vtkIntArray *anArray = vtkIntArray::New();
239         anArray->SetNumberOfValues( aNbElem );
240         for ( int i = 0; i < aNbElem; i++ )
241           anArray->SetValue( i, myIDs[i] );
242         aDataSet->GetPointData()->SetScalars( anArray );
243         anArray->Delete();
244         myPtsMaskPoints->SetInput( aDataSet );
245         myPointLabels->SetVisibility( theIsActorVisible );
246       }
247       else {
248         myPointLabels->SetVisibility( false );
249       }
250     }
251     
252     ~TIdPreview()
253     {
254       RemoveFromRender(myViewWindow->getRenderer());
255
256       myIdGrid->Delete();
257
258       myViewWindow->RemoveActor(myIdActor);
259       myIdActor->Delete();
260
261       //Deleting of points numbering pipeline
262       //---------------------------------------
263       myPointsNumDataSet->Delete();
264       
265       //myPtsLabeledDataMapper->RemoveAllInputs();        //vtk 5.0 porting
266       myPtsLabeledDataMapper->Delete();
267
268       //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting
269       myPtsSelectVisiblePoints->Delete();
270
271       //myPtsMaskPoints->UnRegisterAllOutputs();          //vtk 5.0 porting
272       myPtsMaskPoints->Delete();
273
274       myPointLabels->Delete();
275
276 //       myTimeStamp->Delete();
277     }
278   };
279 }
280
281 static const char * IconFirst[] = {
282 "18 10 2 1",
283 "       g None",
284 ".      g #000000",
285 "         .     .  ",
286 "  ..    ..    ..  ",
287 "  ..   ...   ...  ",
288 "  ..  ....  ....  ",
289 "  .. ..... .....  ",
290 "  .. ..... .....  ",
291 "  ..  ....  ....  ",
292 "  ..   ...   ...  ",
293 "  ..    ..    ..  ",
294 "         .     .  "};
295
296 //=================================================================================
297 // class    : SMESHGUI_EditMeshDlg()
298 // purpose  :
299 //=================================================================================
300 SMESHGUI_EditMeshDlg::SMESHGUI_EditMeshDlg (SMESHGUI* theModule, 
301                                             int theAction)
302   : QDialog(SMESH::GetDesktop(theModule)),
303     mySMESHGUI(theModule),
304     mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
305     myAction(theAction)
306 {
307   setModal(false);
308   setAttribute(Qt::WA_DeleteOnClose, true);
309   setWindowTitle(myAction == 1 ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
310
311   myIdPreview = new SMESH::TIdPreview(SMESH::GetViewWindow( mySMESHGUI ));
312
313   SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
314   QPixmap IconMergeNodes (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_MERGE_NODES")));
315   QPixmap IconMergeElems (aResMgr->loadPixmap("SMESH", tr("ICON_DLG_MERGE_ELEMENTS")));
316   QPixmap IconSelect     (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT")));
317   QPixmap IconAdd        (aResMgr->loadPixmap("SMESH", tr("ICON_APPEND")));
318   QPixmap IconRemove     (aResMgr->loadPixmap("SMESH", tr("ICON_REMOVE")));
319
320   setSizeGripEnabled(true);
321
322   QVBoxLayout* DlgLayout = new QVBoxLayout(this);
323   DlgLayout->setSpacing(SPACING);
324   DlgLayout->setMargin(MARGIN);
325
326   /***************************************************************/
327   GroupConstructors = new QGroupBox(myAction == 1 ? 
328                                     tr("SMESH_MERGE_ELEMENTS") : 
329                                     tr("SMESH_MERGE_NODES"), 
330                                     this);
331
332   QHBoxLayout* GroupConstructorsLayout = new QHBoxLayout(GroupConstructors);
333   GroupConstructorsLayout->setSpacing(SPACING);
334   GroupConstructorsLayout->setMargin(MARGIN);
335
336   RadioButton = new QRadioButton(GroupConstructors);
337   RadioButton->setIcon(myAction == 1 ? IconMergeElems : IconMergeNodes);
338   RadioButton->setChecked(true);
339   GroupConstructorsLayout->addWidget(RadioButton);
340   GroupConstructorsLayout->addStretch();
341
342   /***************************************************************/
343   // Controls for mesh defining
344   GroupMesh = new QGroupBox(tr("SMESH_SELECT_WHOLE_MESH"), this);
345   QHBoxLayout* GroupMeshLayout = new QHBoxLayout(GroupMesh);
346   GroupMeshLayout->setSpacing(SPACING);
347   GroupMeshLayout->setMargin(MARGIN);
348
349   TextLabelName = new QLabel(tr("SMESH_NAME"), GroupMesh);
350   SelectMeshButton = new QPushButton(GroupMesh);
351   SelectMeshButton->setIcon(IconSelect);
352   LineEditMesh = new QLineEdit(GroupMesh);
353   LineEditMesh->setReadOnly(true);
354
355   GroupMeshLayout->addWidget(TextLabelName);
356   GroupMeshLayout->addWidget(SelectMeshButton);
357   GroupMeshLayout->addWidget(LineEditMesh);
358
359   /***************************************************************/
360   // Controls for coincident elements detecting
361   GroupCoincident = new QGroupBox(myAction == 1 ? 
362                                   tr("COINCIDENT_ELEMENTS") : 
363                                   tr("COINCIDENT_NODES"), 
364                                   this);
365
366   QGridLayout* GroupCoincidentLayout = new QGridLayout(GroupCoincident);
367   GroupCoincidentLayout->setSpacing(SPACING);
368   GroupCoincidentLayout->setMargin(MARGIN);
369   
370   if (myAction == 0) { // case merge nodes
371     TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), GroupCoincident);
372     SpinBoxTolerance = new SMESHGUI_SpinBox(GroupCoincident);
373     SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
374
375     GroupCoincidentLayout->addWidget(TextLabelTolerance, 0, 0);
376     GroupCoincidentLayout->addWidget(SpinBoxTolerance,   0, 1);
377   }
378   else {
379     TextLabelTolerance = 0;
380     SpinBoxTolerance = 0;
381   }
382
383   int row = GroupCoincidentLayout->rowCount();
384
385   ListCoincident = new QListWidget(GroupCoincident);
386   ListCoincident->setSelectionMode(QListWidget::ExtendedSelection);
387
388   DetectButton      = new QPushButton(tr("DETECT"),           GroupCoincident);
389   AddGroupButton    = new QPushButton(tr("SMESH_BUT_ADD"),    GroupCoincident);
390   RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincident);
391
392   SelectAllCB = new QCheckBox(tr("SELECT_ALL"), GroupCoincident);
393
394   GroupCoincidentLayout->addWidget(ListCoincident,    row,   0, 4, 2);
395   GroupCoincidentLayout->addWidget(DetectButton,      row,   2);
396   GroupCoincidentLayout->addWidget(AddGroupButton,    row+2, 2);
397   GroupCoincidentLayout->addWidget(RemoveGroupButton, row+3, 2);
398   GroupCoincidentLayout->addWidget(SelectAllCB,       row+4, 0, 1, 3);
399   GroupCoincidentLayout->setRowMinimumHeight(row+1, 10);
400   GroupCoincidentLayout->setRowStretch(row+1, 5);
401
402   /***************************************************************/
403   // Controls for editing the selected group
404   GroupEdit = new QGroupBox(tr("EDIT_SELECTED_GROUP"), this);
405   QGridLayout* GroupEditLayout = new QGridLayout(GroupEdit);
406   GroupEditLayout->setSpacing(SPACING);
407   GroupEditLayout->setMargin(MARGIN);
408
409   ListEdit = new QListWidget(GroupEdit);
410   //ListEdit->setRowMode(QListBox::FixedNumber);
411   //ListEdit->setHScrollBarMode(QScrollView::AlwaysOn);
412   //ListEdit->setVScrollBarMode(QScrollView::AlwaysOff);
413   ListEdit->setSelectionMode(QListWidget::ExtendedSelection);
414
415   AddElemButton = new QPushButton(GroupEdit);
416   AddElemButton->setIcon(IconAdd);
417   RemoveElemButton = new QPushButton(GroupEdit);
418   RemoveElemButton->setIcon(IconRemove);
419   SetFirstButton = new QPushButton(GroupEdit);
420   SetFirstButton->setIcon(QPixmap(IconFirst));
421
422   GroupEditLayout->addWidget(ListEdit,         0, 0, 2, 1);
423   GroupEditLayout->addWidget(AddElemButton,    0, 1);
424   GroupEditLayout->addWidget(RemoveElemButton, 0, 2);
425   GroupEditLayout->addWidget(SetFirstButton,   1, 1, 1, 2);
426
427   /***************************************************************/
428   GroupButtons = new QGroupBox(this);
429   QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons);
430   GroupButtonsLayout->setSpacing(SPACING);
431   GroupButtonsLayout->setMargin(MARGIN);
432
433   buttonOk = new QPushButton(tr("SMESH_BUT_OK"), GroupButtons);
434   buttonOk->setAutoDefault(true);
435   buttonOk->setDefault(true);
436   buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons);
437   buttonApply->setAutoDefault(true);
438   buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons);
439   buttonCancel->setAutoDefault(true);
440   buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons);
441   buttonHelp->setAutoDefault(true);
442
443   GroupButtonsLayout->addWidget(buttonOk);
444   GroupButtonsLayout->addSpacing(10);
445   GroupButtonsLayout->addWidget(buttonApply);
446   GroupButtonsLayout->addSpacing(10);
447   GroupButtonsLayout->addStretch();
448   GroupButtonsLayout->addWidget(buttonCancel);
449   GroupButtonsLayout->addWidget(buttonHelp);
450
451   /***************************************************************/
452   DlgLayout->addWidget(GroupConstructors);
453   DlgLayout->addWidget(GroupMesh);
454   DlgLayout->addWidget(GroupCoincident);
455   DlgLayout->addWidget(GroupEdit);
456   DlgLayout->addWidget(GroupButtons);
457
458   Init(); // Initialisations
459 }
460
461 //=================================================================================
462 // function : ~SMESHGUI_EditMeshDlg()
463 // purpose  : Destroys the object and frees any allocated resources
464 //=================================================================================
465 SMESHGUI_EditMeshDlg::~SMESHGUI_EditMeshDlg()
466 {
467   delete myIdPreview;
468 }
469
470 //=================================================================================
471 // function : Init()
472 // purpose  :
473 //=================================================================================
474 void SMESHGUI_EditMeshDlg::Init()
475 {
476   if (myAction == 0) {
477     SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.1, 3);
478     SpinBoxTolerance->SetValue(1e-05);
479   }
480
481   RadioButton->setChecked(true);
482
483   myEditCurrentArgument = (QWidget*)LineEditMesh; 
484
485   myActor = 0;
486   mySubMeshOrGroup = SMESH::SMESH_subMesh::_nil();
487
488   mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
489
490   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
491   myIsBusy = false;
492   
493   // Costruction of the logical filter
494   SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (MESHorSUBMESH);
495   SMESH_TypeFilter* aSmeshGroupFilter    = new SMESH_TypeFilter (GROUP);
496   
497   QList<SUIT_SelectionFilter*> aListOfFilters;
498   if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter);
499   if (aSmeshGroupFilter)    aListOfFilters.append(aSmeshGroupFilter);
500
501   myMeshOrSubMeshOrGroupFilter =
502     new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR);
503   
504   /* signals and slots connections */
505   connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
506   connect(buttonCancel, SIGNAL(clicked()), this, SLOT(ClickOnCancel()));
507   connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
508   connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
509
510   connect(SelectMeshButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
511   connect(DetectButton, SIGNAL (clicked()), this, SLOT(onDetect()));
512   connect(ListCoincident, SIGNAL (selectionChanged()), this, SLOT(onSelectGroup()));
513   connect(AddGroupButton, SIGNAL (clicked()), this, SLOT(onAddGroup()));
514   connect(RemoveGroupButton, SIGNAL (clicked()), this, SLOT(onRemoveGroup()));
515   connect(SelectAllCB, SIGNAL(toggled(bool)), this, SLOT(onSelectAll(bool)));
516   connect(ListEdit, SIGNAL (selectionChanged()), this, SLOT(onSelectElementFromGroup()));
517   connect(AddElemButton, SIGNAL (clicked()), this, SLOT(onAddElement()));
518   connect(RemoveElemButton, SIGNAL (clicked()), this, SLOT(onRemoveElement()));
519   connect(SetFirstButton, SIGNAL( clicked() ), this, SLOT( onSetFirst() ) );
520
521   connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
522   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
523   /* to close dialog if study change */
524   connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(ClickOnCancel()));
525
526   SetFirstButton->setEnabled(false);
527   buttonOk->setEnabled(false);
528   buttonApply->setEnabled(false);
529
530   // Init Mesh field from selection
531   SelectionIntoArgument();
532
533   myHelpFileName = "merging_elements_page.html";
534 }
535
536 //=================================================================================
537 // function : FindGravityCenter()
538 // purpose  :
539 //=================================================================================
540 void SMESHGUI_EditMeshDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, 
541                                              std::list< gp_XYZ > & theGrCentersXYZ)
542 {
543   if (!myActor)
544     return;
545
546   SMDS_Mesh* aMesh = 0;
547   aMesh = myActor->GetObject()->GetMesh();
548   if (!aMesh)
549     return;
550
551   int nbNodes;
552
553   TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
554   for( ; idIter.More(); idIter.Next() ) {
555     const SMDS_MeshElement* anElem = aMesh->FindElement(idIter.Key());
556     if ( !anElem )
557       continue;
558
559     gp_XYZ anXYZ(0., 0., 0.);
560     SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator();
561     for ( nbNodes = 0; nodeIt->more(); nbNodes++ ) {
562       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
563       anXYZ.Add( gp_XYZ( node->X(), node->Y(), node->Z() ) );
564     }
565     anXYZ.Divide( nbNodes );
566     
567     theGrCentersXYZ.push_back( anXYZ );
568   }
569 }
570
571 //=================================================================================
572 // function : ClickOnApply()
573 // purpose  :
574 //=================================================================================
575 bool SMESHGUI_EditMeshDlg::ClickOnApply()
576 {
577   if (mySMESHGUI->isActiveStudyLocked() || myMesh->_is_nil())
578     return false;
579
580   try {
581     SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
582
583     QApplication::setOverrideCursor(Qt::WaitCursor);
584
585     SMESH::long_array_var anIds = new SMESH::long_array;
586     SMESH::array_of_long_array_var aGroupsOfElements = new SMESH::array_of_long_array;
587
588     aGroupsOfElements->length(ListCoincident->count());
589
590     int anArrayNum = 0;
591     for (int i = 0; i < ListCoincident->count(); i++) {
592       QStringList aListIds = ListCoincident->item(i)->text().split(" ", QString::SkipEmptyParts);
593
594       anIds->length(aListIds.count());
595       for (int i = 0; i < aListIds.count(); i++)
596         anIds[i] = aListIds[i].toInt();
597
598       aGroupsOfElements[anArrayNum++] = anIds.inout();
599     }
600
601     if( myAction == 0 )
602       aMeshEditor->MergeNodes (aGroupsOfElements.inout());
603     else
604       aMeshEditor->MergeElements (aGroupsOfElements.inout());
605
606     QApplication::restoreOverrideCursor();
607   } catch(...) {
608   }
609   
610   SMESH::UpdateView();
611
612   onDetect();
613   return true;
614 }
615
616 //=================================================================================
617 // function : ClickOnOk()
618 // purpose  :
619 //=================================================================================
620 void SMESHGUI_EditMeshDlg::ClickOnOk()
621 {
622   if (ClickOnApply())
623     ClickOnCancel();
624 }
625
626 //=================================================================================
627 // function : ClickOnCancel()
628 // purpose  :
629 //=================================================================================
630 void SMESHGUI_EditMeshDlg::ClickOnCancel()
631 {
632   myIdPreview->SetPointsLabeled(false);
633   mySelectionMgr->clearFilters();
634   //mySelectionMgr->clearSelected();
635   SMESH::SetPointRepresentation(false);
636   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
637     aViewWindow->SetSelectionMode(ActorSelection);
638   disconnect(mySelectionMgr, 0, this, 0);
639   mySMESHGUI->ResetState();
640   reject();
641 }
642
643 //=================================================================================
644 // function : ClickOnHelp()
645 // purpose  :
646 //=================================================================================
647 void SMESHGUI_EditMeshDlg::ClickOnHelp()
648 {
649   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
650   if (app) 
651     app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
652   else {
653     QString platform;
654 #ifdef WIN32
655     platform = "winapplication";
656 #else
657     platform = "application";
658 #endif
659     SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
660                              tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
661                              arg(app->resourceMgr()->stringValue("ExternalBrowser", 
662                                                                  platform)).
663                              arg(myHelpFileName));
664   }
665 }
666
667 //=================================================================================
668 // function : onEditGroup()
669 // purpose  :
670 //=================================================================================
671 void SMESHGUI_EditMeshDlg::onEditGroup()
672 {
673   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
674   if ( selItems.count() != 1 ) {
675     ListEdit->clear();
676     return;
677   }
678
679   QStringList aNewIds;
680
681   for (int i = 0; i < ListEdit->count(); i++ )
682     aNewIds.append(ListEdit->item(i)->text());
683
684   ListCoincident->currentItem()->setText(aNewIds.join(" "));
685   ListCoincident->currentItem()->setSelected(true);
686 }
687
688 //=================================================================================
689 // function : updateControls()
690 // purpose  :
691 //=================================================================================
692 void SMESHGUI_EditMeshDlg::updateControls()
693 {
694   if (ListEdit->count() == 0)
695     SetFirstButton->setEnabled(false);
696   bool enable = !(myMesh->_is_nil()) && ListCoincident->count();
697   buttonOk->setEnabled(enable);
698   buttonApply->setEnabled(enable);
699 }
700
701 //=================================================================================
702 // function : onDetect()
703 // purpose  :
704 //=================================================================================
705 void SMESHGUI_EditMeshDlg::onDetect()
706 {
707   if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() )
708     return;
709
710   try {
711     SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
712
713     QApplication::setOverrideCursor(Qt::WaitCursor);
714     ListCoincident->clear();
715     ListEdit->clear();
716
717     SMESH::array_of_long_array_var aGroupsArray;
718
719     switch (myAction) {
720     case 0 :
721       if(!mySubMeshOrGroup->_is_nil())
722         aMeshEditor->FindCoincidentNodesOnPart(mySubMeshOrGroup, SpinBoxTolerance->GetValue(), aGroupsArray);
723       else
724         aMeshEditor->FindCoincidentNodes(SpinBoxTolerance->GetValue(), aGroupsArray);
725       break;
726     case 1 :
727       if(!mySubMeshOrGroup->_is_nil())
728         aMeshEditor->FindEqualElements(mySubMeshOrGroup, aGroupsArray);
729       else
730         aMeshEditor->FindEqualElements(myMesh, aGroupsArray);
731       break;
732     }
733     
734     for (int i = 0; i < aGroupsArray->length(); i++) {
735       SMESH::long_array& aGroup = aGroupsArray[i];
736
737       QStringList anIDs;
738       for (int j = 0; j < aGroup.length(); j++)
739         anIDs.append(QString::number(aGroup[j]));
740
741       ListCoincident->addItem(anIDs.join(" "));
742     }
743     QApplication::restoreOverrideCursor();
744   } catch(...) {
745   }
746
747   ListCoincident->selectAll();
748   updateControls();
749 }
750
751 //=================================================================================
752 // function : onSelectGroup()
753 // purpose  :
754 //=================================================================================
755 void SMESHGUI_EditMeshDlg::onSelectGroup()
756 {
757   if (myIsBusy || !myActor)
758     return;
759   myEditCurrentArgument = (QWidget*)ListCoincident;
760
761   ListEdit->clear();
762   
763   TColStd_MapOfInteger anIndices;
764   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
765   QListWidgetItem* anItem;
766   QStringList aListIds;
767
768   ListEdit->clear();
769
770   foreach(anItem, selItems) {
771     aListIds = anItem->text().split(" ", QString::SkipEmptyParts);
772     for (int i = 0; i < aListIds.count(); i++)
773       anIndices.Add(aListIds[i].toInt());
774   }
775   
776   if (selItems.count() == 1) {
777     ListEdit->addItems(aListIds);
778     ListEdit->selectAll();
779   }
780
781   mySelector->AddOrRemoveIndex(myActor->getIO(), anIndices, false);
782   SALOME_ListIO aList;
783   aList.Append(myActor->getIO());
784   mySelectionMgr->setSelectedObjects(aList,false);
785   
786   if (myAction == 0) {
787     myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
788     myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
789   }
790   else {
791     list< gp_XYZ > aGrCentersXYZ;
792     FindGravityCenter(anIndices, aGrCentersXYZ);
793     myIdPreview->SetElemsData( anIndices, aGrCentersXYZ);
794     myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
795   }
796
797   updateControls();
798 }
799
800 //=================================================================================
801 // function : onSelectAll()
802 // purpose  :
803 //=================================================================================
804 void SMESHGUI_EditMeshDlg::onSelectAll (bool isToggled)
805 {
806   if ( isToggled )
807     ListCoincident->selectAll();
808   else
809     ListCoincident->clearSelection();
810 }
811
812 //=================================================================================
813 // function : onSelectElementFromGroup()
814 // purpose  :
815 //=================================================================================
816 void SMESHGUI_EditMeshDlg::onSelectElementFromGroup()
817 {
818   if (myIsBusy || !myActor)
819     return;
820
821   TColStd_MapOfInteger anIndices;
822   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
823   QListWidgetItem* anItem;
824
825   foreach(anItem, selItems)
826     anIndices.Add(anItem->text().toInt());
827
828   SetFirstButton->setEnabled(selItems.count() == 1);
829
830   mySelector->AddOrRemoveIndex(myActor->getIO(), anIndices, false);
831   SALOME_ListIO aList;
832   aList.Append(myActor->getIO());
833   mySelectionMgr->setSelectedObjects(aList);
834
835   if (myAction == 0) {
836     myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
837     myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
838   }
839   else {
840     list< gp_XYZ > aGrCentersXYZ;
841     FindGravityCenter(anIndices, aGrCentersXYZ);
842     myIdPreview->SetElemsData(anIndices, aGrCentersXYZ);
843     myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
844   }
845 }
846
847 //=================================================================================
848 // function : onAddGroup()
849 // purpose  :
850 //=================================================================================
851 void SMESHGUI_EditMeshDlg::onAddGroup()
852 {
853   if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() )
854     return;
855
856   QString anIDs = "";
857   SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
858   
859   ListCoincident->clearSelection();
860   ListCoincident->addItem(anIDs);
861   int nbGroups = ListCoincident->count();
862   if (nbGroups) {
863     ListCoincident->setCurrentRow(nbGroups-1);
864     ListCoincident->item(nbGroups-1)->setSelected(true);
865   }
866   else {
867     // VSR ? this code seems to be never executed!!!
868     ListCoincident->setCurrentRow(0);
869     //ListCoincident->setSelected(0, true); // VSR: no items - no selection
870   }
871
872   updateControls();
873 }
874
875 //=================================================================================
876 // function : onRemoveGroup()
877 // purpose  :
878 //=================================================================================
879 void SMESHGUI_EditMeshDlg::onRemoveGroup()
880 {
881   if (myEditCurrentArgument != (QWidget*)ListCoincident)
882     return;
883   myIsBusy = true;
884
885   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
886   QListWidgetItem* anItem;
887
888   foreach(anItem, selItems)
889     delete anItem;
890
891   ListEdit->clear();
892   updateControls();
893
894   myIsBusy = false;
895 }
896
897 //=================================================================================
898 // function : onAddElement()
899 // purpose  :
900 //=================================================================================
901 void SMESHGUI_EditMeshDlg::onAddElement()
902 {
903   if (!myActor)
904     return;
905   myIsBusy = true;
906
907   QString aListStr = "";
908   int aNbNnodes = 0;
909
910   aNbNnodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), aListStr);
911   if (aNbNnodes < 1)
912     return;
913
914   QStringList aNodes = aListStr.split(" ", QString::SkipEmptyParts);
915
916   for (QStringList::iterator it = aNodes.begin(); it != aNodes.end(); ++it) {
917     QList<QListWidgetItem*> found = ListEdit->findItems(*it, Qt::MatchExactly);
918     if ( found.count() == 0 ) {
919       QListWidgetItem* anItem = new QListWidgetItem(*it);
920       ListEdit->addItem(anItem);
921       anItem->setSelected(true);
922     }
923     else {
924       QListWidgetItem* anItem;
925       foreach(anItem, found) anItem->setSelected(true);
926     }
927   }
928
929   myIsBusy = false;
930   onEditGroup();
931 }
932
933 //=================================================================================
934 // function : onRemoveElement()
935 // purpose  :
936 //=================================================================================
937 void SMESHGUI_EditMeshDlg::onRemoveElement()
938 {
939   if (myEditCurrentArgument != (QWidget*)ListCoincident)
940     return;
941   myIsBusy = true;
942
943   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
944   QListWidgetItem* anItem;
945
946   foreach(anItem, selItems)
947     delete anItem;
948   
949   myIsBusy = false;
950   onEditGroup();
951 }
952
953 //=================================================================================
954 // function : onSetFirst()
955 // purpose  :
956 //=================================================================================
957 void SMESHGUI_EditMeshDlg::onSetFirst()
958 {
959   if (myEditCurrentArgument != (QWidget*)ListCoincident)
960     return;
961   myIsBusy = true;
962   
963   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
964   QListWidgetItem* anItem;
965   
966   foreach(anItem, selItems) {
967     ListEdit->takeItem(ListEdit->row(anItem));
968     ListEdit->insertItem(0, anItem);
969   }
970
971   myIsBusy = false;
972   onEditGroup();
973 }
974
975 //=================================================================================
976 // function : SetEditCurrentArgument()
977 // purpose  :
978 //=================================================================================
979 void SMESHGUI_EditMeshDlg::SetEditCurrentArgument()
980 {
981   QPushButton* send = (QPushButton*)sender();
982
983   disconnect(mySelectionMgr, 0, this, 0);
984   mySelectionMgr->clearSelected();
985   mySelectionMgr->clearFilters();
986
987   if (send == SelectMeshButton) {
988     myEditCurrentArgument = (QWidget*)LineEditMesh;
989     SMESH::SetPointRepresentation(false);
990     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
991       aViewWindow->SetSelectionMode(ActorSelection);
992     mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
993   }
994
995   myEditCurrentArgument->setFocus();
996   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
997   SelectionIntoArgument();
998 }
999
1000 //=================================================================================
1001 // function : SelectionIntoArgument()
1002 // purpose  : Called when selection as changed or other case
1003 //=================================================================================
1004 void SMESHGUI_EditMeshDlg::SelectionIntoArgument()
1005 {
1006   if (myEditCurrentArgument == (QWidget*)LineEditMesh) {
1007     QString aString = "";
1008     LineEditMesh->setText(aString);
1009     
1010     ListCoincident->clear();
1011     ListEdit->clear();
1012     myActor = 0;
1013     
1014     int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
1015     if (nbSel != 1)
1016       return;
1017
1018     SALOME_ListIO aList;
1019     mySelectionMgr->selectedObjects(aList, SVTK_Viewer::Type());
1020     
1021     Handle(SALOME_InteractiveObject) IO = aList.First();
1022     myMesh = SMESH::GetMeshByIO(IO);
1023     
1024     if (myMesh->_is_nil())
1025       return;
1026     
1027     myActor = SMESH::FindActorByEntry(IO->getEntry());
1028     if (!myActor)
1029       myActor = SMESH::FindActorByObject(myMesh);
1030     if(!myActor)
1031       return;
1032     
1033     mySubMeshOrGroup = SMESH::SMESH_IDSource::_nil();
1034     
1035     if ((!SMESH::IObjectToInterface<SMESH::SMESH_subMesh>(IO)->_is_nil() || //SUBMESH OR GROUP
1036          !SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>(IO)->_is_nil()) &&
1037         !SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO)->_is_nil())
1038       mySubMeshOrGroup = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
1039      
1040     LineEditMesh->setText(aString);
1041
1042     if (myAction == 0) {
1043       SMESH::SetPointRepresentation(true);
1044       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1045         aViewWindow->SetSelectionMode(NodeSelection);
1046     }
1047     else
1048       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1049         aViewWindow->SetSelectionMode(CellSelection);
1050   }
1051 }
1052
1053 //=================================================================================
1054 // function : DeactivateActiveDialog()
1055 // purpose  :
1056 //=================================================================================
1057 void SMESHGUI_EditMeshDlg::DeactivateActiveDialog()
1058 {
1059   if (GroupConstructors->isEnabled()) {
1060     GroupConstructors->setEnabled(false);
1061     GroupMesh->setEnabled(false);
1062     GroupCoincident->setEnabled(false);
1063     GroupEdit->setEnabled(false);
1064     GroupButtons->setEnabled(false);
1065     mySMESHGUI->ResetState();
1066     mySMESHGUI->SetActiveDialogBox(0);
1067   }
1068 }
1069
1070 //=================================================================================
1071 // function : ActivateThisDialog()
1072 // purpose  :
1073 //=================================================================================
1074 void SMESHGUI_EditMeshDlg::ActivateThisDialog()
1075 {
1076   /* Emit a signal to deactivate the active dialog */
1077   mySMESHGUI->EmitSignalDeactivateDialog();
1078   GroupConstructors->setEnabled(true);
1079   GroupMesh->setEnabled(true);
1080   GroupCoincident->setEnabled(true);
1081   GroupEdit->setEnabled(true);
1082   GroupButtons->setEnabled(true);
1083
1084   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
1085   SelectionIntoArgument();
1086 }
1087
1088 //=================================================================================
1089 // function : enterEvent()
1090 // purpose  :
1091 //=================================================================================
1092 void SMESHGUI_EditMeshDlg::enterEvent(QEvent*)
1093 {
1094   if (!GroupConstructors->isEnabled())
1095     ActivateThisDialog();
1096 }
1097
1098 //=================================================================================
1099 // function : closeEvent()
1100 // purpose  :
1101 //=================================================================================
1102 void SMESHGUI_EditMeshDlg::closeEvent(QCloseEvent*)
1103 {
1104   /* same than click on cancel button */
1105   ClickOnCancel();
1106 }
1107
1108 //=======================================================================
1109 //function : hideEvent
1110 //purpose  : caused by ESC key
1111 //=======================================================================
1112 void SMESHGUI_EditMeshDlg::hideEvent (QHideEvent *)
1113 {
1114   if (!isMinimized())
1115     ClickOnCancel();
1116 }
1117
1118 //=================================================================================
1119 // function : keyPressEvent()
1120 // purpose  :
1121 //=================================================================================
1122 void SMESHGUI_EditMeshDlg::keyPressEvent( QKeyEvent* e)
1123 {
1124   QDialog::keyPressEvent( e );
1125   if ( e->isAccepted() )
1126     return;
1127
1128   if ( e->key() == Qt::Key_F1 ) {
1129     e->accept();
1130     ClickOnHelp();
1131   }
1132 }