Salome HOME
23081: [CEA 1496] Control merge nodes behaviour: set fixed nodes
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MergeDlg.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESHGUI : GUI for SMESH component
24 // File   : SMESHGUI_MergeDlg.cxx
25 // Author : Open CASCADE S.A.S.
26 // SMESH includes
27 //
28 #include "SMESHGUI_MergeDlg.h"
29
30 #include "SMESHGUI.h"
31 #include "SMESHGUI_Utils.h"
32 #include "SMESHGUI_VTKUtils.h"
33 #include "SMESHGUI_MeshUtils.h"
34 #include "SMESHGUI_SpinBox.h"
35
36 #include <SMESH_Actor.h>
37 #include <SMESH_TypeFilter.hxx>
38 #include <SMESH_LogicalFilter.hxx>
39 #include <SMDS_Mesh.hxx>
40
41 // SALOME GUI includes
42 #include <SUIT_Desktop.h>
43 #include <SUIT_ResourceMgr.h>
44 #include <SUIT_Session.h>
45 #include <SUIT_MessageBox.h>
46 #include <SUIT_OverrideCursor.h>
47
48 #include <LightApp_Application.h>
49 #include <LightApp_SelectionMgr.h>
50
51 #include <SVTK_ViewModel.h>
52 #include <SVTK_ViewWindow.h>
53 #include <SALOME_ListIO.hxx>
54
55 // OCCT includes
56 #include <TColStd_MapOfInteger.hxx>
57 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
58
59 // IDL includes
60 #include <SALOMEconfig.h>
61 #include CORBA_SERVER_HEADER(SMESH_Group)
62 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
63
64 // VTK includes
65 #include <vtkUnstructuredGrid.h>
66 #include <vtkRenderer.h>
67 #include <vtkActor2D.h>
68 #include <vtkPoints.h>
69 #include <vtkDataSetMapper.h>
70 #include <vtkMaskPoints.h>
71 #include <vtkSelectVisiblePoints.h>
72 #include <vtkLabeledDataMapper.h>
73 #include <vtkTextProperty.h>
74 #include <vtkIntArray.h>
75 #include <vtkProperty2D.h>
76 #include <vtkPointData.h>
77
78 // Qt includes
79 #include <QApplication>
80 #include <QGroupBox>
81 #include <QLabel>
82 #include <QLineEdit>
83 #include <QListWidget>
84 #include <QPushButton>
85 #include <QRadioButton>
86 #include <QCheckBox>
87 #include <QHBoxLayout>
88 #include <QVBoxLayout>
89 #include <QGridLayout>
90 #include <QKeyEvent>
91 #include <QButtonGroup>
92
93 #define SPACING 6
94 #define MARGIN  11
95
96 namespace
97 {
98   enum ActionType { MERGE_NODES, MERGE_ELEMENTS, TYPE_AUTO=0, TYPE_MANUAL };
99 }
100 namespace SMESH
101 {
102   class TIdPreview
103   { // to display in the viewer IDs of the selected elements
104     SVTK_ViewWindow* myViewWindow;
105
106     vtkUnstructuredGrid* myIdGrid;
107     SALOME_Actor* myIdActor;
108
109     vtkUnstructuredGrid* myPointsNumDataSet;
110     vtkMaskPoints* myPtsMaskPoints;
111     vtkSelectVisiblePoints* myPtsSelectVisiblePoints;
112     vtkLabeledDataMapper* myPtsLabeledDataMapper;
113     vtkTextProperty* aPtsTextProp;
114     bool myIsPointsLabeled;
115     vtkActor2D* myPointLabels;
116
117     std::vector<int> myIDs;
118
119   public:
120     TIdPreview(SVTK_ViewWindow* theViewWindow):
121       myViewWindow(theViewWindow)
122     {
123       myIdGrid = vtkUnstructuredGrid::New();
124
125       // Create and display actor
126       vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
127       aMapper->SetInputData( myIdGrid );
128
129       myIdActor = SALOME_Actor::New();
130       myIdActor->SetInfinitive(true);
131       myIdActor->VisibilityOff();
132       myIdActor->PickableOff();
133
134       myIdActor->SetMapper( aMapper );
135       aMapper->Delete();
136
137       myViewWindow->AddActor(myIdActor);
138
139       //Definition of points numbering pipeline
140       myPointsNumDataSet = vtkUnstructuredGrid::New();
141
142       myPtsMaskPoints = vtkMaskPoints::New();
143       myPtsMaskPoints->SetInputData(myPointsNumDataSet);
144       myPtsMaskPoints->SetOnRatio(1);
145
146       myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New();
147       myPtsSelectVisiblePoints->SetInputConnection(myPtsMaskPoints->GetOutputPort());
148       myPtsSelectVisiblePoints->SelectInvisibleOff();
149       myPtsSelectVisiblePoints->SetTolerance(0.1);
150     
151       myPtsLabeledDataMapper = vtkLabeledDataMapper::New();
152       myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort());
153       myPtsLabeledDataMapper->SetLabelModeToLabelScalars();
154     
155       vtkTextProperty* aPtsTextProp = vtkTextProperty::New();
156       aPtsTextProp->SetFontFamilyToTimes();
157       static int aPointsFontSize = 12;
158       aPtsTextProp->SetFontSize(aPointsFontSize);
159       aPtsTextProp->SetBold(1);
160       aPtsTextProp->SetItalic(0);
161       aPtsTextProp->SetShadow(0);
162       myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp);
163       aPtsTextProp->Delete();
164   
165       myIsPointsLabeled = false;
166
167       myPointLabels = vtkActor2D::New();
168       myPointLabels->SetMapper(myPtsLabeledDataMapper);
169       myPointLabels->GetProperty()->SetColor(1,1,1);
170       myPointLabels->SetVisibility(myIsPointsLabeled);
171
172       AddToRender(myViewWindow->getRenderer());
173     }
174
175     void SetPointsData ( SMDS_Mesh* theMesh, 
176                          TColStd_MapOfInteger & theNodesIdMap )
177     {
178       vtkPoints* aPoints = vtkPoints::New();
179       aPoints->SetNumberOfPoints(theNodesIdMap.Extent());
180       myIDs.clear();
181       
182       TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap );
183       for( int i = 0; idIter.More(); idIter.Next(), i++ ) {
184         const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key());
185         aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() );
186         myIDs.push_back(idIter.Key());
187       }
188
189       myIdGrid->SetPoints(aPoints);
190
191       aPoints->Delete();
192
193       myIdActor->GetMapper()->Update();
194     }
195
196     void SetElemsData( TColStd_MapOfInteger & theElemsIdMap, 
197                        std::list<gp_XYZ> & aGrCentersXYZ )
198     {
199       vtkPoints* aPoints = vtkPoints::New();
200       aPoints->SetNumberOfPoints(theElemsIdMap.Extent());
201       myIDs.clear();
202       
203       TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
204       for( ; idIter.More(); idIter.Next() ) {
205         myIDs.push_back(idIter.Key());
206       }
207
208       gp_XYZ aXYZ;
209       std::list<gp_XYZ>::iterator coordIt = aGrCentersXYZ.begin();
210       for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ ) {
211         aXYZ = *coordIt;
212         aPoints->SetPoint( i, aXYZ.X(), aXYZ.Y(), aXYZ.Z() );
213       }
214       myIdGrid->SetPoints(aPoints);
215       aPoints->Delete();
216       
217       myIdActor->GetMapper()->Update();
218     }
219
220     void AddToRender(vtkRenderer* theRenderer)
221     {
222       myIdActor->AddToRender(theRenderer);
223
224       myPtsSelectVisiblePoints->SetRenderer(theRenderer);
225       theRenderer->AddActor2D(myPointLabels);
226     }
227
228     void RemoveFromRender(vtkRenderer* theRenderer)
229     {
230       myIdActor->RemoveFromRender(theRenderer);
231
232       myPtsSelectVisiblePoints->SetRenderer(theRenderer);
233       theRenderer->RemoveActor(myPointLabels);
234     }
235
236     void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true )
237     {
238       myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints();
239       
240       if ( myIsPointsLabeled ) {
241         myPointsNumDataSet->ShallowCopy(myIdGrid);
242         vtkDataSet *aDataSet = myPointsNumDataSet;
243         int aNbElem = myIDs.size();
244         vtkIntArray *anArray = vtkIntArray::New();
245         anArray->SetNumberOfValues( aNbElem );
246         for ( int i = 0; i < aNbElem; i++ )
247           anArray->SetValue( i, myIDs[i] );
248         aDataSet->GetPointData()->SetScalars( anArray );
249         anArray->Delete();
250         myPtsMaskPoints->SetInputData( aDataSet );
251         myPointLabels->SetVisibility( theIsActorVisible );
252       }
253       else {
254         myPointLabels->SetVisibility( false );
255       }
256     }
257     
258     ~TIdPreview()
259     {
260       RemoveFromRender(myViewWindow->getRenderer());
261
262       myIdGrid->Delete();
263
264       myViewWindow->RemoveActor(myIdActor);
265       myIdActor->Delete();
266
267       //Deleting of points numbering pipeline
268       //---------------------------------------
269       myPointsNumDataSet->Delete();
270       
271       //myPtsLabeledDataMapper->RemoveAllInputs();        //vtk 5.0 porting
272       myPtsLabeledDataMapper->Delete();
273
274       //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting
275       myPtsSelectVisiblePoints->Delete();
276
277       //myPtsMaskPoints->UnRegisterAllOutputs();          //vtk 5.0 porting
278       myPtsMaskPoints->Delete();
279
280       myPointLabels->Delete();
281
282 //       myTimeStamp->Delete();
283     }
284   };
285 }
286
287 static const char * IconFirst[] = {
288 "18 10 2 1",
289 "       g None",
290 ".      g #000000",
291 "         .     .  ",
292 "  ..    ..    ..  ",
293 "  ..   ...   ...  ",
294 "  ..  ....  ....  ",
295 "  .. ..... .....  ",
296 "  .. ..... .....  ",
297 "  ..  ....  ....  ",
298 "  ..   ...   ...  ",
299 "  ..    ..    ..  ",
300 "         .     .  "};
301
302 //=================================================================================
303 // class    : SMESHGUI_MergeDlg()
304 // purpose  :
305 //=================================================================================
306 SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
307   : QDialog(SMESH::GetDesktop(theModule)),
308     mySMESHGUI(theModule),
309     mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
310     myAction(theAction)
311 {
312   setModal(false);
313   setAttribute(Qt::WA_DeleteOnClose, true);
314   setWindowTitle(myAction == MERGE_ELEMENTS ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
315
316   myIdPreview = new SMESH::TIdPreview(SMESH::GetViewWindow( mySMESHGUI ));
317
318   SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
319   QPixmap IconMergeNodes (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_MERGE_NODES")));
320   QPixmap IconMergeElems (aResMgr->loadPixmap("SMESH", tr("ICON_DLG_MERGE_ELEMENTS")));
321   QPixmap IconSelect     (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT")));
322   QPixmap IconAdd        (aResMgr->loadPixmap("SMESH", tr("ICON_APPEND")));
323   QPixmap IconRemove     (aResMgr->loadPixmap("SMESH", tr("ICON_REMOVE")));
324
325   setSizeGripEnabled(true);
326
327   QVBoxLayout* DlgLayout = new QVBoxLayout(this);
328   DlgLayout->setSpacing(SPACING);
329   DlgLayout->setMargin(MARGIN);
330
331   /***************************************************************/
332   GroupConstructors = new QGroupBox(myAction == MERGE_ELEMENTS ? 
333                                     tr("SMESH_MERGE_ELEMENTS") : 
334                                     tr("SMESH_MERGE_NODES"), 
335                                     this);
336
337   QButtonGroup* ButtonGroup = new QButtonGroup(this);
338   QHBoxLayout* GroupConstructorsLayout = new QHBoxLayout(GroupConstructors);
339   GroupConstructorsLayout->setSpacing(SPACING);
340   GroupConstructorsLayout->setMargin(MARGIN);
341
342   RadioButton = new QRadioButton(GroupConstructors);
343   RadioButton->setIcon(myAction == MERGE_ELEMENTS ? IconMergeElems : IconMergeNodes);
344   RadioButton->setChecked(true);
345   GroupConstructorsLayout->addWidget(RadioButton);
346   ButtonGroup->addButton(RadioButton, 0);
347
348   /***************************************************************/
349   // Controls for mesh defining
350   GroupMesh = new QGroupBox(tr("SMESH_SELECT_WHOLE_MESH"), this);
351   QHBoxLayout* GroupMeshLayout = new QHBoxLayout(GroupMesh);
352   GroupMeshLayout->setSpacing(SPACING);
353   GroupMeshLayout->setMargin(MARGIN);
354
355   TextLabelName = new QLabel(tr("SMESH_NAME"), GroupMesh);
356   SelectMeshButton = new QPushButton(GroupMesh);
357   SelectMeshButton->setIcon(IconSelect);
358   LineEditMesh = new QLineEdit(GroupMesh);
359   LineEditMesh->setReadOnly(true);
360
361   GroupMeshLayout->addWidget(TextLabelName);
362   GroupMeshLayout->addWidget(SelectMeshButton);
363   GroupMeshLayout->addWidget(LineEditMesh);
364
365   /***************************************************************/
366   // Controls for switch dialog behaviour (myTypeId)
367
368   TypeBox = new QGroupBox( tr( "SMESH_MODE" ), this );
369   GroupType = new QButtonGroup( this );
370   QHBoxLayout* aTypeBoxLayout = new QHBoxLayout( TypeBox );
371   aTypeBoxLayout->setMargin( MARGIN );
372   aTypeBoxLayout->setSpacing( SPACING );
373
374   QRadioButton* rb1 = new QRadioButton( tr( "SMESH_AUTOMATIC" ), TypeBox );
375   QRadioButton* rb2 = new QRadioButton( tr( "SMESH_MANUAL" ),   TypeBox );
376   GroupType->addButton( rb1, 0 );
377   GroupType->addButton( rb2, 1 );
378   aTypeBoxLayout->addWidget( rb1 );
379   aTypeBoxLayout->addWidget( rb2 );
380
381   myTypeId = TYPE_AUTO;
382
383   /***************************************************************/
384   // Controls for coincident elements detecting
385   GroupCoincident = new QGroupBox(myAction == MERGE_ELEMENTS ? 
386                                   tr("COINCIDENT_ELEMENTS") : 
387                                   tr("COINCIDENT_NODES"), 
388                                   this);
389
390   QVBoxLayout* aCoincidentLayout = new QVBoxLayout(GroupCoincident);
391   aCoincidentLayout->setSpacing(SPACING);
392   aCoincidentLayout->setMargin(MARGIN);
393
394   if (myAction == MERGE_NODES) // case merge nodes
395   {
396     QWidget* foo = new QWidget(GroupCoincident);
397     TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), foo);
398     SpinBoxTolerance = new SMESHGUI_SpinBox(foo);
399     SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
400
401     SeparateCornersAndMedium = new QCheckBox(tr("SEPARATE_CORNERS_AND_MEDIUM"), foo);
402     SeparateCornersAndMedium->setEnabled( false );
403
404     GroupExclude = new QGroupBox(tr("EXCLUDE_GROUPS"), foo);
405     GroupExclude->setCheckable( true );
406     GroupExclude->setChecked( false );
407     ListExclude = new QListWidget( GroupExclude );
408     QVBoxLayout* GroupExcludeLayout = new QVBoxLayout(GroupExclude);
409     GroupExcludeLayout->setSpacing(SPACING);
410     GroupExcludeLayout->setMargin(MARGIN);
411     GroupExcludeLayout->addWidget(ListExclude);
412
413     QGroupBox*  GroupKeep = new QGroupBox(tr("KEEP_NODES"), foo);
414     SelectKeepNodesButton = new QPushButton( GroupKeep );
415     SelectKeepNodesButton->setIcon( IconSelect );
416     QLabel*       selectLabel = new QLabel(tr("SELECT"));
417     QRadioButton*   idsButton = new QRadioButton(tr("NODE_IDS"), GroupKeep);
418     QRadioButton* groupButton = new QRadioButton(tr("GROUP_SUBMESH"), GroupKeep);
419     KeepFromButGroup = new QButtonGroup( this );
420     KeepFromButGroup->addButton( idsButton,   0 );
421     KeepFromButGroup->addButton( groupButton, 1 );
422     groupButton->setChecked( true );
423     KeepList = new QListWidget( GroupKeep );
424     KeepList->setSelectionMode(QAbstractItemView::ExtendedSelection);
425     KeepList->setFlow(QListView::TopToBottom);
426     AddKeepNodesButton    = new QPushButton(tr("SMESH_BUT_ADD"), GroupKeep );
427     RemoveKeepNodesButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupKeep );
428     QGridLayout* GroupKeepLayout = new QGridLayout(GroupKeep);
429     GroupKeepLayout->setSpacing( SPACING );
430     GroupKeepLayout->setMargin ( MARGIN );
431     GroupKeepLayout->addWidget( SelectKeepNodesButton, 0, 0 );
432     GroupKeepLayout->addWidget( selectLabel,           0, 1 );
433     GroupKeepLayout->addWidget( idsButton,             0, 2 );
434     GroupKeepLayout->addWidget( groupButton,           0, 3, 1, 2 );
435     GroupKeepLayout->addWidget( KeepList,              1, 0, 2, 4 );
436     GroupKeepLayout->addWidget( AddKeepNodesButton,    1, 4, 1, 1 );
437     GroupKeepLayout->addWidget( RemoveKeepNodesButton, 2, 4, 1, 1 );
438
439     QGridLayout* fooLayout = new QGridLayout( foo );
440     fooLayout->setSpacing(SPACING);
441     fooLayout->setMargin(0);
442     fooLayout->addWidget(TextLabelTolerance,       0, 0 );
443     fooLayout->addWidget(SpinBoxTolerance,         0, 1 );
444     fooLayout->addWidget(SeparateCornersAndMedium, 1, 0 );
445     fooLayout->addWidget(GroupExclude,             2, 0, 1, 2 );
446     fooLayout->addWidget(GroupKeep,                3, 0, 1, 2 );
447     aCoincidentLayout->addWidget(foo);
448
449     // Costruction of the logical filter
450     QList<SUIT_SelectionFilter*> aListOfFilters;
451     aListOfFilters << new SMESH_TypeFilter (SMESH::SUBMESH)
452                    << new SMESH_TypeFilter (SMESH::GROUP);
453     mySubMeshOrGroupFilter =
454       new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true);
455   }
456   else {
457     TextLabelTolerance     = 0;
458     SpinBoxTolerance       = 0;
459     GroupExclude           = 0;
460     ListExclude            = 0;
461     KeepFromButGroup       = 0;
462     SelectKeepNodesButton  = 0;
463     AddKeepNodesButton     = 0;
464     RemoveKeepNodesButton  = 0;
465     KeepList               = 0;
466     mySubMeshOrGroupFilter = 0;
467   }
468
469   GroupCoincidentWidget = new QWidget(GroupCoincident);
470   QGridLayout* GroupCoincidentLayout = new QGridLayout(GroupCoincidentWidget);
471   GroupCoincidentLayout->setSpacing(SPACING);
472   GroupCoincidentLayout->setMargin(0);
473
474   ListCoincident = new QListWidget(GroupCoincidentWidget);
475   ListCoincident->setSelectionMode(QListWidget::ExtendedSelection);
476
477   DetectButton      = new QPushButton(tr("DETECT"),           GroupCoincidentWidget);
478   AddGroupButton    = new QPushButton(tr("SMESH_BUT_ADD"),    GroupCoincidentWidget);
479   RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincidentWidget);
480
481   SelectAllCB = new QCheckBox(tr("SELECT_ALL"), GroupCoincidentWidget);
482   ShowIDs = new QCheckBox(myAction == MERGE_ELEMENTS ? tr("SHOW_ELEMS_IDS") : tr("SHOW_NODES_IDS"), GroupCoincidentWidget);
483
484   GroupCoincidentLayout->addWidget(ListCoincident,    0,   0, 4, 2);
485   GroupCoincidentLayout->addWidget(DetectButton,      0,   2);
486   GroupCoincidentLayout->addWidget(AddGroupButton,    2, 2);
487   GroupCoincidentLayout->addWidget(RemoveGroupButton, 3, 2);
488   GroupCoincidentLayout->addWidget(SelectAllCB,       4, 0);
489   GroupCoincidentLayout->addWidget(ShowIDs,           4, 1);
490   GroupCoincidentLayout->setRowMinimumHeight(1, 10);
491   GroupCoincidentLayout->setRowStretch(1, 5);
492
493   aCoincidentLayout->addWidget(GroupCoincidentWidget);
494
495   /***************************************************************/
496   // Controls for editing the selected group
497   GroupEdit = new QGroupBox(tr("EDIT_SELECTED_GROUP"), this);
498   QGridLayout* GroupEditLayout = new QGridLayout(GroupEdit);
499   GroupEditLayout->setSpacing(SPACING);
500   GroupEditLayout->setMargin(MARGIN);
501
502   ListEdit = new QListWidget(GroupEdit);
503   //ListEdit->setRowMode(QListBox::FixedNumber);
504   //ListEdit->setHScrollBarMode(QScrollView::AlwaysOn);
505   //ListEdit->setVScrollBarMode(QScrollView::AlwaysOff);
506   ListEdit->setFlow( QListView::LeftToRight );
507   ListEdit->setSelectionMode(QListWidget::ExtendedSelection);
508
509   AddElemButton = new QPushButton(GroupEdit);
510   AddElemButton->setIcon(IconAdd);
511   RemoveElemButton = new QPushButton(GroupEdit);
512   RemoveElemButton->setIcon(IconRemove);
513   SetFirstButton = new QPushButton(GroupEdit);
514   SetFirstButton->setIcon(QPixmap(IconFirst));
515
516   GroupEditLayout->addWidget(ListEdit,         0, 0, 2, 1);
517   GroupEditLayout->addWidget(AddElemButton,    0, 1);
518   GroupEditLayout->addWidget(RemoveElemButton, 0, 2);
519   GroupEditLayout->addWidget(SetFirstButton,   1, 1, 1, 2);
520
521   /***************************************************************/
522   GroupButtons = new QGroupBox(this);
523   QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons);
524   GroupButtonsLayout->setSpacing(SPACING);
525   GroupButtonsLayout->setMargin(MARGIN);
526
527   buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons);
528   buttonOk->setAutoDefault(true);
529   buttonOk->setDefault(true);
530   buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons);
531   buttonApply->setAutoDefault(true);
532   buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons);
533   buttonCancel->setAutoDefault(true);
534   buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons);
535   buttonHelp->setAutoDefault(true);
536
537   GroupButtonsLayout->addWidget(buttonOk);
538   GroupButtonsLayout->addSpacing(10);
539   GroupButtonsLayout->addWidget(buttonApply);
540   GroupButtonsLayout->addSpacing(10);
541   GroupButtonsLayout->addStretch();
542   GroupButtonsLayout->addWidget(buttonCancel);
543   GroupButtonsLayout->addWidget(buttonHelp);
544
545   /***************************************************************/
546   DlgLayout->addWidget(GroupConstructors);
547   DlgLayout->addWidget(GroupMesh);
548   DlgLayout->addWidget(TypeBox);
549   DlgLayout->addWidget(GroupCoincident);
550   DlgLayout->addWidget(GroupEdit);
551   DlgLayout->addWidget(GroupButtons);
552
553   GroupCoincidentWidget->setVisible( myAction != MERGE_NODES );
554   GroupCoincident      ->setVisible( myAction == MERGE_NODES );
555   //if GroupExclude->setVisible( myAction == MERGE_NODES );
556   GroupEdit->hide();
557
558   this->resize(10,10);
559
560   ShowIDs->setChecked( true );
561
562   Init(); // Initialisations
563 }
564
565 //=================================================================================
566 // function : ~SMESHGUI_MergeDlg()
567 // purpose  : Destroys the object and frees any allocated resources
568 //=================================================================================
569 SMESHGUI_MergeDlg::~SMESHGUI_MergeDlg()
570 {
571   delete myIdPreview;
572 }
573
574 //=================================================================================
575 // function : Init()
576 // purpose  :
577 //=================================================================================
578 void SMESHGUI_MergeDlg::Init()
579 {
580   if ( myAction == MERGE_NODES ) {
581     SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision");
582     SpinBoxTolerance->SetValue(1e-05);
583   }
584
585   RadioButton->setChecked(true);
586
587   GroupType->button(0)->setChecked(true);
588
589   myEditCurrentArgument = (QWidget*)LineEditMesh;
590
591   myActor = 0;
592   mySubMeshOrGroup = SMESH::SMESH_subMesh::_nil();
593
594   mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
595
596   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
597   myIsBusy = false;
598
599   /* signals and slots connections */
600   connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
601   connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
602   connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
603   connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
604
605   if ( KeepList )
606   {
607     connect(SelectKeepNodesButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
608     connect(KeepFromButGroup, SIGNAL (buttonClicked(int)), SLOT(onKeepNodeSourceChanged(int)));
609     connect(AddKeepNodesButton, SIGNAL (clicked()), this, SLOT(onAddKeepNode()));
610     connect(RemoveKeepNodesButton, SIGNAL (clicked()), this, SLOT(onRemoveKeepNode()));
611     connect(KeepList, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectKeepNode()));
612   }
613   connect(SelectMeshButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
614   connect(DetectButton, SIGNAL (clicked()), this, SLOT(onDetect()));
615   connect(ListCoincident, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectGroup()));
616   connect(AddGroupButton, SIGNAL (clicked()), this, SLOT(onAddGroup()));
617   connect(RemoveGroupButton, SIGNAL (clicked()), this, SLOT(onRemoveGroup()));
618   connect(SelectAllCB, SIGNAL(toggled(bool)), this, SLOT(onSelectAll(bool)));
619   connect(ShowIDs, SIGNAL(toggled(bool)), this, SLOT(onSelectGroup()));
620   connect(ListEdit, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectElementFromGroup()));
621   connect(AddElemButton, SIGNAL (clicked()), this, SLOT(onAddElement()));
622   connect(RemoveElemButton, SIGNAL (clicked()), this, SLOT(onRemoveElement()));
623   connect(SetFirstButton, SIGNAL( clicked() ), this, SLOT( onSetFirst()));
624   connect(GroupType, SIGNAL(buttonClicked(int)), this, SLOT(onTypeChanged(int)));
625
626   connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
627   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
628   /* to close dialog if study change */
629   connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(reject()));
630   connect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this,  SLOT(onOpenView()));
631   connect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView()));
632   // Init Mesh field from selection
633   SelectionIntoArgument();
634
635   // Update Buttons
636   updateControls();
637   
638   if ( myAction == MERGE_NODES )
639     myHelpFileName = "merging_nodes_page.html";
640   else
641     myHelpFileName = "merging_elements_page.html";
642 }
643
644 //=================================================================================
645 // function : FindGravityCenter()
646 // purpose  :
647 //=================================================================================
648 void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, 
649                                           std::list< gp_XYZ > & theGrCentersXYZ)
650 {
651   if (!myActor)
652     return;
653
654   SMDS_Mesh* aMesh = 0;
655   aMesh = myActor->GetObject()->GetMesh();
656   if (!aMesh)
657     return;
658
659   int nbNodes;
660
661   TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
662   for( ; idIter.More(); idIter.Next() ) {
663     const SMDS_MeshElement* anElem = aMesh->FindElement(idIter.Key());
664     if ( !anElem )
665       continue;
666
667     gp_XYZ anXYZ(0., 0., 0.);
668     SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator();
669     for ( nbNodes = 0; nodeIt->more(); nbNodes++ ) {
670       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
671       anXYZ.Add( gp_XYZ( node->X(), node->Y(), node->Z() ) );
672     }
673     anXYZ.Divide( nbNodes );
674     
675     theGrCentersXYZ.push_back( anXYZ );
676   }
677 }
678
679 //=================================================================================
680 // function : ClickOnApply()
681 // purpose  :
682 //=================================================================================
683 bool SMESHGUI_MergeDlg::ClickOnApply()
684 {
685   if (mySMESHGUI->isActiveStudyLocked() || myMesh->_is_nil())
686     return false;
687
688   try {
689     if (myTypeId == TYPE_AUTO)
690       onDetect();
691
692     SUIT_OverrideCursor aWaitCursor;
693     SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
694
695     SMESH::long_array_var anIds = new SMESH::long_array;
696     SMESH::array_of_long_array_var aGroupsOfElements = new SMESH::array_of_long_array;
697
698     if ( ListCoincident->count() == 0) {
699       if ( myAction == MERGE_NODES )
700         SUIT_MessageBox::warning(this,
701                                  tr("SMESH_WARNING"),
702                                  tr("SMESH_NO_NODES_DETECTED"));
703       else
704         SUIT_MessageBox::warning(this,
705                                  tr("SMESH_WARNING"),
706                                  tr("SMESH_NO_ELEMENTS_DETECTED"));
707       return false;
708     }
709
710     aGroupsOfElements->length(ListCoincident->count());
711
712     int anArrayNum = 0;
713     for (int i = 0; i < ListCoincident->count(); i++) {
714       QStringList aListIds = ListCoincident->item(i)->text().split(" ", QString::SkipEmptyParts);
715
716       anIds->length(aListIds.count());
717       for (int i = 0; i < aListIds.count(); i++)
718         anIds[i] = aListIds[i].toInt();
719
720       aGroupsOfElements[anArrayNum++] = anIds.inout();
721     }
722
723     SMESH::ListOfIDSources_var nodesToKeep;
724     SMESH::IDSource_wrap tmpIdSource;
725     if ( myAction == MERGE_NODES )
726     {
727       nodesToKeep = new SMESH::ListOfIDSources();
728       int i, nb = KeepList->count();
729       if ( isKeepNodesIDsSelection() )
730       {
731         SMESH::long_array_var anIdList = new SMESH::long_array();
732         anIdList->length(nb);
733         for (i = 0; i < nb; i++)
734           anIdList[i] = KeepList->item(i)->text().toInt();
735
736         if ( nb > 0 )
737         {
738           tmpIdSource = aMeshEditor->MakeIDSource( anIdList, SMESH::NODE );
739           nodesToKeep->length( 1 );
740           nodesToKeep[0] = SMESH::SMESH_IDSource::_duplicate( tmpIdSource.in() );
741         }
742       }
743       else
744       {
745         nodesToKeep->length( nb );
746         int nbObj = 0;
747         for (i = 0; i < nb; i++)
748         {
749           QString entry = KeepList->item( i )->data( Qt::UserRole ).toString();
750           Handle(SALOME_InteractiveObject) anIO =
751             new SALOME_InteractiveObject( entry.toStdString().c_str(), "SMESH" );
752           SMESH::SMESH_IDSource_var idSrc =
753             SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( anIO );
754           if ( !idSrc->_is_nil() )
755             nodesToKeep[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( idSrc );
756         }
757         nodesToKeep->length( nbObj );
758       }
759       KeepList->clear();
760     }
761
762     if( myAction == MERGE_NODES )
763       aMeshEditor->MergeNodes (aGroupsOfElements.inout(), nodesToKeep);
764     else
765       aMeshEditor->MergeElements (aGroupsOfElements.inout());
766
767     if ( myTypeId == TYPE_AUTO ) {
768       if (myAction == MERGE_NODES )
769         SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
770                                      tr("SMESH_MERGED_NODES").arg(QString::number(ListCoincident->count()).toLatin1().data()));
771       else
772         SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
773                                      tr("SMESH_MERGED_ELEMENTS").arg(QString::number(ListCoincident->count()).toLatin1().data()));
774     }
775     nodesToKeep->length(0); // release before tmpIdSource calls UnRegister()
776
777   }
778   catch(...) {
779   }
780
781   ListCoincident->clear();
782
783   myEditCurrentArgument = (QWidget*)LineEditMesh;
784
785   SMESH::UpdateView();
786   SMESHGUI::Modified();
787
788   return true;
789 }
790
791 //=================================================================================
792 // function : ClickOnOk()
793 // purpose  :
794 //=================================================================================
795 void SMESHGUI_MergeDlg::ClickOnOk()
796 {
797   if (ClickOnApply())
798     reject();
799 }
800
801 //=================================================================================
802 // function : reject()
803 // purpose  :
804 //=================================================================================
805 void SMESHGUI_MergeDlg::reject()
806 {
807   myIdPreview->SetPointsLabeled(false);
808   SMESH::SetPointRepresentation(false);
809   disconnect(mySelectionMgr, 0, this, 0);
810   disconnect(mySMESHGUI, 0, this, 0);
811   mySMESHGUI->ResetState();
812
813   mySelectionMgr->clearFilters();
814   //mySelectionMgr->clearSelected();
815
816   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
817     aViewWindow->SetSelectionMode(ActorSelection);
818
819   QDialog::reject();
820 }
821
822 //=================================================================================
823 // function : onOpenView()
824 // purpose  :
825 //=================================================================================
826 void SMESHGUI_MergeDlg::onOpenView()
827 {
828   if ( mySelector ) {
829     SMESH::SetPointRepresentation(false);
830   }
831   else {
832     mySelector = SMESH::GetViewWindow( mySMESHGUI )->GetSelector();
833     ActivateThisDialog();
834   }
835 }
836
837 //=================================================================================
838 // function : onCloseView()
839 // purpose  :
840 //=================================================================================
841 void SMESHGUI_MergeDlg::onCloseView()
842 {
843   DeactivateActiveDialog();
844   mySelector = 0;
845 }
846
847 //=================================================================================
848 // function : ClickOnHelp()
849 // purpose  :
850 //=================================================================================
851 void SMESHGUI_MergeDlg::ClickOnHelp()
852 {
853   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
854   if (app) 
855     app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
856   else {
857     QString platform;
858 #ifdef WIN32
859     platform = "winapplication";
860 #else
861     platform = "application";
862 #endif
863     SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
864                              tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
865                              arg(app->resourceMgr()->stringValue("ExternalBrowser", 
866                                                                  platform)).
867                              arg(myHelpFileName));
868   }
869 }
870
871 //=================================================================================
872 // function : onEditGroup()
873 // purpose  :
874 //=================================================================================
875 void SMESHGUI_MergeDlg::onEditGroup()
876 {
877   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
878   if ( selItems.count() != 1 ) {
879     ListEdit->clear();
880     return;
881   }
882
883   QStringList aNewIds;
884
885   for (int i = 0; i < ListEdit->count(); i++ )
886     aNewIds.append(ListEdit->item(i)->text());
887
888   ListCoincident->clearSelection();
889   selItems.first()->setText(aNewIds.join(" "));
890   selItems.first()->setSelected(true);
891 }
892
893 //=================================================================================
894 // function : updateControls()
895 // purpose  :
896 //=================================================================================
897 void SMESHGUI_MergeDlg::updateControls()
898 {
899   if (ListEdit->count() == 0)
900     SetFirstButton->setEnabled(false);
901   bool enable = !(myMesh->_is_nil()) && (ListCoincident->count() || (myTypeId == TYPE_AUTO));
902   buttonOk->setEnabled(enable);
903   buttonApply->setEnabled(enable);
904   DetectButton->setEnabled( !myMesh->_is_nil() );
905
906   if ( myAction == MERGE_NODES )
907   {
908     bool has2ndOrder = (( !myMesh->_is_nil() ) &&
909                         ( myMesh->NbEdgesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ||
910                           myMesh->NbFacesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ||
911                           myMesh->NbVolumesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ));
912
913     SeparateCornersAndMedium->setEnabled( has2ndOrder );
914
915     if ( myEditCurrentArgument != KeepList )
916     {
917       AddKeepNodesButton->setEnabled( false );
918       RemoveKeepNodesButton->setEnabled( false );
919       KeepList->clearSelection();
920     }
921   }
922 }
923
924 //=================================================================================
925 // function : onDetect()
926 // purpose  :
927 //=================================================================================
928 void SMESHGUI_MergeDlg::onDetect()
929 {
930   if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() )
931     return;
932
933   try {
934     SUIT_OverrideCursor aWaitCursor;
935     SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
936
937     ListCoincident->clear();
938     ListEdit->clear();
939
940     SMESH::array_of_long_array_var aGroupsArray;
941     SMESH::ListOfIDSources_var aExcludeGroups = new SMESH::ListOfIDSources;
942
943     SMESH::SMESH_IDSource_var src;
944     if ( mySubMeshOrGroup->_is_nil() ) src = SMESH::SMESH_IDSource::_duplicate( myMesh );
945     else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup );
946
947     switch (myAction) {
948     case MERGE_NODES :
949       for ( int i = 0; GroupExclude->isChecked() && i < ListExclude->count(); i++ ) {
950         if ( ListExclude->item( i )->checkState() == Qt::Checked ) {
951           aExcludeGroups->length( aExcludeGroups->length()+1 );
952           aExcludeGroups[ aExcludeGroups->length()-1 ] = SMESH::SMESH_IDSource::_duplicate( myGroups[i] );
953         }
954       }
955       aMeshEditor->FindCoincidentNodesOnPartBut(src.in(),
956                                                 SpinBoxTolerance->GetValue(), 
957                                                 aGroupsArray.out(),
958                                                 aExcludeGroups.in(),
959                                                 SeparateCornersAndMedium->isEnabled() &&
960                                                 SeparateCornersAndMedium->isChecked());
961       break;
962     case MERGE_ELEMENTS :
963       aMeshEditor->FindEqualElements(src.in(), aGroupsArray.out());
964       break;
965     }
966     
967     for (int i = 0; i < aGroupsArray->length(); i++) {
968       SMESH::long_array& aGroup = aGroupsArray[i];
969
970       QStringList anIDs;
971       for (int j = 0; j < aGroup.length(); j++)
972         anIDs.append(QString::number(aGroup[j]));
973
974       ListCoincident->addItem(anIDs.join(" "));
975     }
976    } catch(...) {
977   }
978
979   ListCoincident->selectAll();
980   updateControls();
981   SMESH::UpdateView();
982 }
983
984 //=================================================================================
985 // function : onSelectGroup()
986 // purpose  :
987 //=================================================================================
988 void SMESHGUI_MergeDlg::onSelectGroup()
989 {
990   if (myIsBusy || !myActor)
991     return;
992
993   if( ListCoincident->count() != ListCoincident->selectedItems().count() )
994     SelectAllCB->setChecked( false );
995
996   myEditCurrentArgument = (QWidget*)ListCoincident;
997
998   myIsBusy = true;
999   ListEdit->clear();
1000   
1001   TColStd_MapOfInteger anIndices;
1002   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
1003   QListWidgetItem* anItem;
1004   QStringList aListIds;
1005
1006   ListEdit->clear();
1007
1008   foreach(anItem, selItems) {
1009     aListIds = anItem->text().split(" ", QString::SkipEmptyParts);
1010     for (int i = 0; i < aListIds.count(); i++)
1011       anIndices.Add(aListIds[i].toInt());
1012   }
1013   
1014   if (selItems.count() == 1) {
1015     ListEdit->addItems(aListIds);
1016     ListEdit->selectAll();
1017   }
1018
1019   mySelector->AddOrRemoveIndex(myActor->getIO(), anIndices, false);
1020   SALOME_ListIO aList;
1021   aList.Append(myActor->getIO());
1022   mySelectionMgr->setSelectedObjects(aList,false);
1023   
1024   if (ShowIDs->isChecked()) 
1025     if ( myAction == MERGE_NODES ) {
1026       myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
1027       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
1028     }
1029     else {
1030       std::list< gp_XYZ > aGrCentersXYZ;
1031       FindGravityCenter(anIndices, aGrCentersXYZ);
1032       myIdPreview->SetElemsData( anIndices, aGrCentersXYZ);
1033       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
1034     }
1035   else
1036     myIdPreview->SetPointsLabeled(false);
1037
1038   updateControls();
1039   myIsBusy = false;
1040 }
1041
1042 //=================================================================================
1043 // function : onSelectAll()
1044 // purpose  :
1045 //=================================================================================
1046 void SMESHGUI_MergeDlg::onSelectAll (bool isToggled)
1047 {
1048   if ( isToggled )
1049     ListCoincident->selectAll();
1050   else
1051     ListCoincident->clearSelection();
1052 }
1053
1054 //=================================================================================
1055 // function : onSelectElementFromGroup()
1056 // purpose  :
1057 //=================================================================================
1058 void SMESHGUI_MergeDlg::onSelectElementFromGroup()
1059 {
1060   if (myIsBusy || !myActor)
1061     return;
1062
1063   TColStd_MapOfInteger anIndices;
1064   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
1065   QListWidgetItem* anItem;
1066
1067   foreach(anItem, selItems)
1068     anIndices.Add(anItem->text().toInt());
1069
1070   SetFirstButton->setEnabled(selItems.count() == 1);
1071
1072   mySelector->AddOrRemoveIndex(myActor->getIO(), anIndices, false);
1073   SALOME_ListIO aList;
1074   aList.Append(myActor->getIO());
1075   mySelectionMgr->setSelectedObjects(aList);
1076   
1077   if (ShowIDs->isChecked())
1078     if (myAction == MERGE_NODES) {
1079       myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
1080       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
1081     }
1082     else {
1083       std::list< gp_XYZ > aGrCentersXYZ;
1084       FindGravityCenter(anIndices, aGrCentersXYZ);
1085       myIdPreview->SetElemsData(anIndices, aGrCentersXYZ);
1086       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
1087     }
1088   else 
1089     myIdPreview->SetPointsLabeled(false);
1090 }
1091
1092 //=================================================================================
1093 // function : onAddGroup()
1094 // purpose  :
1095 //=================================================================================
1096 void SMESHGUI_MergeDlg::onAddGroup()
1097 {
1098   if ( myMesh->_is_nil() || LineEditMesh->text().isEmpty() )
1099     return;
1100
1101   QString anIDs = "";
1102   int aNbElements = 0;
1103   aNbElements = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
1104
1105   if (aNbElements < 1)
1106     return;
1107   
1108   ListCoincident->clearSelection();
1109   ListCoincident->addItem(anIDs);
1110   int nbGroups = ListCoincident->count();
1111   if (nbGroups) {
1112     ListCoincident->setCurrentRow(nbGroups-1);
1113     ListCoincident->item(nbGroups-1)->setSelected(true);
1114   }
1115   else {
1116     // VSR ? this code seems to be never executed!!!
1117     ListCoincident->setCurrentRow(0);
1118     //ListCoincident->setSelected(0, true); // VSR: no items - no selection
1119   }
1120
1121   updateControls();
1122 }
1123
1124 //=================================================================================
1125 // function : onRemoveGroup()
1126 // purpose  :
1127 //=================================================================================
1128 void SMESHGUI_MergeDlg::onRemoveGroup()
1129 {
1130   if (myEditCurrentArgument != (QWidget*)ListCoincident)
1131     return;
1132   myIsBusy = true;
1133
1134   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
1135   QListWidgetItem* anItem;
1136
1137   foreach(anItem, selItems)
1138     delete anItem;
1139
1140   ListEdit->clear();
1141   myIdPreview->SetPointsLabeled(false);
1142   updateControls();
1143   SMESH::UpdateView();
1144   myIsBusy = false;
1145
1146   if( ListCoincident->count() == 0 ) {
1147     myEditCurrentArgument = (QWidget*)LineEditMesh;
1148     SelectAllCB->setChecked( false );
1149   }
1150 }
1151
1152 //=================================================================================
1153 // function : onAddElement()
1154 // purpose  :
1155 //=================================================================================
1156 void SMESHGUI_MergeDlg::onAddElement()
1157 {
1158   if (!myActor)
1159     return;
1160   myIsBusy = true;
1161
1162   QString aListStr = "";
1163   int aNbNnodes = 0;
1164
1165   aNbNnodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), aListStr);
1166   if (aNbNnodes < 1)
1167     return;
1168
1169   QStringList aNodes = aListStr.split(" ", QString::SkipEmptyParts);
1170
1171   for (QStringList::iterator it = aNodes.begin(); it != aNodes.end(); ++it) {
1172     QList<QListWidgetItem*> found = ListEdit->findItems(*it, Qt::MatchExactly);
1173     if ( found.count() == 0 ) {
1174       QListWidgetItem* anItem = new QListWidgetItem(*it);
1175       ListEdit->addItem(anItem);
1176       anItem->setSelected(true);
1177     }
1178     else {
1179       QListWidgetItem* anItem;
1180       foreach(anItem, found) anItem->setSelected(true);
1181     }
1182   }
1183
1184   myIsBusy = false;
1185   onEditGroup();
1186 }
1187
1188 //=================================================================================
1189 // function : onRemoveElement()
1190 // purpose  :
1191 //=================================================================================
1192 void SMESHGUI_MergeDlg::onRemoveElement()
1193 {
1194   if (myEditCurrentArgument != (QWidget*)ListCoincident)
1195     return;
1196   myIsBusy = true;
1197
1198   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
1199   QListWidgetItem* anItem;
1200
1201   foreach(anItem, selItems)
1202     delete anItem;
1203   
1204   myIsBusy = false;
1205   onEditGroup();
1206
1207   if( ListCoincident->count() == 0 ) {
1208     myEditCurrentArgument = (QWidget*)LineEditMesh;
1209     SelectAllCB->setChecked( false );
1210   }
1211 }
1212
1213 //=================================================================================
1214 // function : onSetFirst()
1215 // purpose  :
1216 //=================================================================================
1217 void SMESHGUI_MergeDlg::onSetFirst()
1218 {
1219   if (myEditCurrentArgument != (QWidget*)ListCoincident)
1220     return;
1221   myIsBusy = true;
1222   
1223   QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
1224   QListWidgetItem* anItem;
1225   
1226   foreach(anItem, selItems) {
1227     ListEdit->takeItem(ListEdit->row(anItem));
1228     ListEdit->insertItem(0, anItem);
1229   }
1230
1231   myIsBusy = false;
1232   onEditGroup();
1233 }
1234
1235 //=================================================================================
1236 // function : SetEditCurrentArgument()
1237 // purpose  :
1238 //=================================================================================
1239 void SMESHGUI_MergeDlg::SetEditCurrentArgument()
1240 {
1241   QPushButton* send = (QPushButton*)sender();
1242
1243   disconnect(mySelectionMgr, 0, this, 0);
1244   mySelectionMgr->clearSelected();
1245   mySelectionMgr->clearFilters();
1246
1247   if (send == SelectMeshButton)
1248   {
1249     myEditCurrentArgument = (QWidget*)LineEditMesh;
1250     SMESH::SetPointRepresentation(false);
1251     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1252       aViewWindow->SetSelectionMode(ActorSelection);
1253     if (myTypeId == TYPE_MANUAL)
1254       mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
1255   }
1256   else if ( send == SelectKeepNodesButton && send )
1257   {
1258     myEditCurrentArgument = (QWidget*)KeepList;
1259     KeepList->setWrapping( isKeepNodesIDsSelection() );
1260     if ( isKeepNodesIDsSelection() )
1261     {
1262       SMESH::SetPointRepresentation( true );
1263       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1264         aViewWindow->SetSelectionMode( NodeSelection );
1265     }
1266     else
1267     {
1268       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1269         aViewWindow->SetSelectionMode( ActorSelection );
1270       mySelectionMgr->installFilter( mySubMeshOrGroupFilter );
1271     }
1272   }
1273
1274   myEditCurrentArgument->setFocus();
1275   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
1276   SelectionIntoArgument();
1277 }
1278
1279 //=================================================================================
1280 // function : SelectionIntoArgument()
1281 // purpose  : Called when selection has changed or other case
1282 //=================================================================================
1283 void SMESHGUI_MergeDlg::SelectionIntoArgument()
1284 {
1285   if (myEditCurrentArgument == (QWidget*)LineEditMesh)
1286   {
1287     QString aString = "";
1288     LineEditMesh->setText(aString);
1289
1290     ListCoincident->clear();
1291     ListEdit->clear();
1292     myActor = 0;
1293     myMesh = SMESH::SMESH_Mesh::_nil();
1294     QString aCurrentEntry = myEntry;
1295
1296     int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
1297     if (nbSel != 1) {
1298       myIdPreview->SetPointsLabeled(false);
1299       SMESH::SetPointRepresentation(false);
1300       mySelectionMgr->clearFilters();
1301       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1302         aViewWindow->SetSelectionMode(ActorSelection);
1303       return;
1304     }
1305
1306     SALOME_ListIO aList;
1307     mySelectionMgr->selectedObjects(aList);
1308
1309     Handle(SALOME_InteractiveObject) IO = aList.First();
1310     myEntry = IO->getEntry();
1311     myMesh = SMESH::GetMeshByIO(IO);
1312
1313     if ( myEntry != aCurrentEntry && KeepList )
1314       KeepList->clear();
1315
1316     if (myMesh->_is_nil())
1317       return;
1318
1319     LineEditMesh->setText(aString);
1320
1321     myActor = SMESH::FindActorByEntry(IO->getEntry());
1322     if (!myActor)
1323       myActor = SMESH::FindActorByObject(myMesh);
1324
1325     if ( myActor && myTypeId == TYPE_MANUAL && mySelector->IsSelectionEnabled() ) {
1326       mySubMeshOrGroup = SMESH::SMESH_IDSource::_nil();
1327       mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
1328
1329       if ((!SMESH::IObjectToInterface<SMESH::SMESH_subMesh>(IO)->_is_nil() || //SUBMESH OR GROUP
1330            !SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>(IO)->_is_nil()) &&
1331           !SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO)->_is_nil())
1332         mySubMeshOrGroup = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
1333
1334       if (myAction == MERGE_NODES) {
1335         SMESH::SetPointRepresentation(true);
1336         if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1337           aViewWindow->SetSelectionMode(NodeSelection);
1338       }
1339       else
1340         if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1341           aViewWindow->SetSelectionMode(CellSelection);
1342     }
1343
1344     // process groups
1345     if ( myAction == MERGE_NODES && !myMesh->_is_nil() && myEntry != aCurrentEntry ) {
1346       myGroups.clear();
1347       ListExclude->clear();
1348       SMESH::ListOfGroups_var aListOfGroups = myMesh->GetGroups();
1349       for( int i = 0, n = aListOfGroups->length(); i < n; i++ ) {
1350         SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i];
1351         if ( !aGroup->_is_nil() ) { // && aGroup->GetType() == SMESH::NODE
1352           QString aGroupName( aGroup->GetName() );
1353           if ( !aGroupName.isEmpty() ) {
1354             myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup));
1355             QListWidgetItem* item = new QListWidgetItem( aGroupName );
1356             item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
1357             item->setCheckState( Qt::Unchecked );
1358             ListExclude->addItem( item );
1359           }
1360         }
1361       }
1362     }
1363
1364     updateControls();
1365   }
1366
1367   else if (myEditCurrentArgument == (QWidget*)KeepList && KeepList)
1368   {
1369     AddKeepNodesButton->setEnabled( false );
1370     RemoveKeepNodesButton->setEnabled( false );
1371     if ( isKeepNodesIDsSelection() )
1372     {
1373       if (!myMesh->_is_nil() && !myActor)
1374         myActor = SMESH::FindActorByObject(myMesh);
1375
1376       if ( mySelector && myActor )
1377       {
1378         KeepList->clearSelection();
1379         QString anIDs = "";
1380         int aNbNodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
1381         if (aNbNodes > 0)
1382         {
1383           QStringList anNodes = anIDs.split( " ", QString::SkipEmptyParts);
1384           QList<QListWidgetItem*> listItemsToSel;
1385           QListWidgetItem* anItem;
1386           int nbFound = 0;
1387           for (QStringList::iterator it = anNodes.begin(); it != anNodes.end(); ++it)
1388           {
1389             QList<QListWidgetItem*> found = KeepList->findItems(*it, Qt::MatchExactly);
1390             foreach(anItem, found)
1391               if (!anItem->isSelected())
1392                 listItemsToSel.push_back(anItem);
1393             nbFound += found.count();
1394           }
1395           bool blocked = KeepList->signalsBlocked();
1396           KeepList->blockSignals(true);
1397           foreach(anItem, listItemsToSel) anItem->setSelected(true);
1398           KeepList->blockSignals(blocked);
1399           //onSelectKeepNode();
1400           AddKeepNodesButton->setEnabled( nbFound < aNbNodes );
1401           RemoveKeepNodesButton->setEnabled( nbFound > 0 );
1402         }
1403       }
1404     }
1405     else if ( !myMesh->_is_nil() )
1406     {
1407       SALOME_ListIO aList;
1408       mySelectionMgr->selectedObjects(aList);
1409       bool hasNewSelected = false;
1410       SALOME_ListIteratorOfListIO anIt (aList);
1411       for ( ; anIt.More() && !hasNewSelected; anIt.Next())
1412         if ( anIt.Value()->hasEntry() )
1413           hasNewSelected = isNewKeepNodesGroup( anIt.Value()->getEntry() );
1414
1415       AddKeepNodesButton->setEnabled( hasNewSelected );
1416       //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
1417     }
1418   }
1419 }
1420
1421 //=================================================================================
1422 // function : DeactivateActiveDialog()
1423 // purpose  :
1424 //=================================================================================
1425 void SMESHGUI_MergeDlg::DeactivateActiveDialog()
1426 {
1427   if (GroupConstructors->isEnabled()) {
1428     GroupConstructors->setEnabled(false);
1429     TypeBox->setEnabled(false);
1430     GroupMesh->setEnabled(false);
1431     GroupCoincident->setEnabled(false);
1432     GroupEdit->setEnabled(false);
1433     GroupButtons->setEnabled(false);
1434     mySMESHGUI->ResetState();
1435     mySMESHGUI->SetActiveDialogBox(0);
1436   }
1437
1438   mySelectionMgr->clearSelected();
1439   disconnect(mySelectionMgr, 0, this, 0);
1440 }
1441
1442 //=================================================================================
1443 // function : ActivateThisDialog()
1444 // purpose  :
1445 //=================================================================================
1446 void SMESHGUI_MergeDlg::ActivateThisDialog()
1447 {
1448   /* Emit a signal to deactivate the active dialog */
1449   mySMESHGUI->EmitSignalDeactivateDialog();
1450   GroupConstructors->setEnabled(true);
1451   TypeBox->setEnabled(true);
1452   GroupMesh->setEnabled(true);
1453   GroupCoincident->setEnabled(true);
1454   GroupEdit->setEnabled(true);
1455   GroupButtons->setEnabled(true);
1456
1457   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
1458   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
1459   SelectionIntoArgument();
1460 }
1461
1462 //=================================================================================
1463 // function : enterEvent()
1464 // purpose  :
1465 //=================================================================================
1466 void SMESHGUI_MergeDlg::enterEvent (QEvent*)
1467 {
1468   if ( !GroupConstructors->isEnabled() ) {
1469     SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI );
1470     if ( aViewWindow && !mySelector) {
1471       mySelector = aViewWindow->GetSelector();
1472     }
1473     ActivateThisDialog();
1474   }
1475 }
1476
1477 //=================================================================================
1478 // function : keyPressEvent()
1479 // purpose  :
1480 //=================================================================================
1481 void SMESHGUI_MergeDlg::keyPressEvent( QKeyEvent* e)
1482 {
1483   QDialog::keyPressEvent( e );
1484   if ( e->isAccepted() )
1485     return;
1486
1487   if ( e->key() == Qt::Key_F1 ) {
1488     e->accept();
1489     ClickOnHelp();
1490   }
1491 }
1492
1493 //=================================================================================
1494 // function : onTypeChanged()
1495 // purpose  : the type radio button management
1496 //=================================================================================
1497 void SMESHGUI_MergeDlg::onTypeChanged (int id)
1498 {
1499   if (myTypeId == id)
1500     return;
1501
1502   myTypeId = id;
1503   switch (id)
1504   {
1505   case TYPE_AUTO: // automatic
1506
1507     myIdPreview->SetPointsLabeled(false);
1508     SMESH::SetPointRepresentation(false);
1509     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1510       aViewWindow->SetSelectionMode(ActorSelection);
1511     mySelectionMgr->clearFilters();
1512     if (myAction == MERGE_NODES)
1513       GroupCoincidentWidget->hide();
1514     else
1515       GroupCoincident->hide();
1516     GroupEdit->hide();
1517     break;
1518
1519   case TYPE_MANUAL: // manual
1520
1521     SMESH::UpdateView();
1522
1523     // Costruction of the logical filter
1524     SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (SMESH::MESHorSUBMESH);
1525     SMESH_TypeFilter* aSmeshGroupFilter    = new SMESH_TypeFilter (SMESH::GROUP);
1526     
1527     QList<SUIT_SelectionFilter*> aListOfFilters;
1528     if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter);
1529     if (aSmeshGroupFilter)    aListOfFilters.append(aSmeshGroupFilter);
1530     
1531     myMeshOrSubMeshOrGroupFilter =
1532       new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR);
1533
1534     if (myAction == MERGE_NODES) {
1535       GroupCoincidentWidget->show();
1536       SMESH::SetPointRepresentation(true);
1537       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1538         if( mySelector->IsSelectionEnabled() )
1539           aViewWindow->SetSelectionMode(NodeSelection);
1540     }
1541     else {
1542       GroupCoincident->show();
1543       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
1544         if( mySelector->IsSelectionEnabled() )
1545           aViewWindow->SetSelectionMode(CellSelection);
1546     }
1547     GroupEdit->show();
1548     break;
1549   }
1550   updateControls();
1551
1552   qApp->processEvents();
1553   updateGeometry();
1554   resize(10,10);
1555
1556   SelectionIntoArgument();
1557 }
1558
1559 //=======================================================================
1560 //function : isKeepNodesIDsSelection
1561 //purpose  : Return true of Nodes to keep are selected by IDs
1562 //=======================================================================
1563
1564 bool SMESHGUI_MergeDlg::isKeepNodesIDsSelection()
1565 {
1566   return KeepFromButGroup && KeepFromButGroup->checkedId() == 0;
1567 }
1568
1569 //=======================================================================
1570 //function : isNewKeepNodesGroup
1571 //purpose  : Return true if an object with given entry is NOT present in KeepList
1572 //=======================================================================
1573
1574 bool SMESHGUI_MergeDlg::isNewKeepNodesGroup( const char* entry )
1575 {
1576   if ( !entry || isKeepNodesIDsSelection() )
1577     return false;
1578
1579   for ( int i = 0; i < KeepList->count(); i++ )
1580     if ( KeepList->item( i )->data( Qt::UserRole ).toString() == entry )
1581       return false;
1582
1583   return true;
1584 }
1585
1586 //=======================================================================
1587 //function : onAddKeepNode
1588 //purpose  : SLOT called when [Add] of Nodes To Keep group is pressed
1589 //=======================================================================
1590
1591 void SMESHGUI_MergeDlg::onAddKeepNode()
1592 {
1593   if ( myIsBusy )
1594     return;
1595   myIsBusy = true;
1596
1597   if ( isKeepNodesIDsSelection() )
1598   {
1599     //KeepList->clearSelection();
1600     QString anIDs = "";
1601     int aNbNodes = 0;
1602     if ( myActor )
1603       aNbNodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
1604     if (aNbNodes > 0)
1605     {
1606       QStringList anNodes = anIDs.split( " ", QString::SkipEmptyParts);
1607       QList<QListWidgetItem*> listItemsToSel;
1608       QListWidgetItem* anItem;
1609       for (QStringList::iterator it = anNodes.begin(); it != anNodes.end(); ++it)
1610       {
1611         QList<QListWidgetItem*> found = KeepList->findItems(*it, Qt::MatchExactly);
1612         if (found.count() == 0) {
1613           anItem = new QListWidgetItem(*it);
1614           KeepList->addItem(anItem);
1615           if (!anItem->isSelected())
1616             listItemsToSel.push_back(anItem);
1617         }
1618         else {
1619           foreach(anItem, found)
1620             if (!anItem->isSelected())
1621               listItemsToSel.push_back(anItem);
1622         }
1623       }
1624       bool blocked = KeepList->signalsBlocked();
1625       KeepList->blockSignals(true);
1626       foreach(anItem, listItemsToSel) anItem->setSelected(true);
1627       KeepList->blockSignals(blocked);
1628       //onSelectKeepNode();
1629     }
1630     RemoveKeepNodesButton->setEnabled( aNbNodes > 0 );
1631   }
1632   else
1633   {
1634     SALOME_ListIO aList;
1635     mySelectionMgr->selectedObjects(aList);
1636     SALOME_ListIteratorOfListIO anIt (aList);
1637     for ( ; anIt.More(); anIt.Next()) {
1638       Handle(SALOME_InteractiveObject) anIO = anIt.Value();
1639       if ( isNewKeepNodesGroup( anIO->getEntry() ))
1640       {
1641         QListWidgetItem* anItem = new QListWidgetItem( anIO->getName() );
1642         anItem->setData( Qt::UserRole, QString( anIO->getEntry() ));
1643         KeepList->addItem(anItem);
1644       }
1645     }
1646     //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
1647   }
1648
1649   AddKeepNodesButton->setEnabled( false );
1650
1651   myIsBusy = false;
1652 }
1653
1654 //=======================================================================
1655 //function : onRemoveKeepNode
1656 //purpose  : SLOT called when [Remove] of Nodes To Keep group is pressed
1657 //=======================================================================
1658
1659 void SMESHGUI_MergeDlg::onRemoveKeepNode()
1660 {
1661   // if ( isKeepNodesIDsSelection() )
1662   // {
1663   // }
1664   // else
1665   {
1666     QList<QListWidgetItem*> selItems = KeepList->selectedItems();
1667     QListWidgetItem* item;
1668     foreach(item, selItems) delete item;
1669   }
1670   if ( isKeepNodesIDsSelection() )
1671   {
1672     AddKeepNodesButton->setEnabled( false );
1673   }
1674   RemoveKeepNodesButton->setEnabled( false );
1675 }
1676
1677 //=======================================================================
1678 //function : onSelectKeepNode
1679 //purpose  : SLOT called when selection in KeepList changes
1680 //=======================================================================
1681
1682 void SMESHGUI_MergeDlg::onSelectKeepNode()
1683 {
1684   if ( myIsBusy || !isEnabled() ) return;
1685   myIsBusy = true;
1686
1687   if ( isKeepNodesIDsSelection() )
1688   {
1689     if ( myActor )
1690     {
1691       mySelectionMgr->clearSelected();
1692       TColStd_MapOfInteger aIndexes;
1693       QList<QListWidgetItem*> selItems = KeepList->selectedItems();
1694       QListWidgetItem* anItem;
1695       foreach(anItem, selItems) aIndexes.Add(anItem->text().toInt());
1696       mySelector->AddOrRemoveIndex(myActor->getIO(), aIndexes, false);
1697       SALOME_ListIO aList;
1698       aList.Append(myActor->getIO());
1699       mySelectionMgr->setSelectedObjects(aList,false);
1700
1701       AddKeepNodesButton->setEnabled( false );
1702       RemoveKeepNodesButton->setEnabled( aIndexes.Extent() > 0 );
1703     }
1704   }
1705   else
1706   {
1707     RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
1708   }
1709   myIsBusy = false;
1710 }
1711
1712 //=======================================================================
1713 //function : onKeepNodeSourceChanged
1714 //purpose  : SLOT called when type of source of Nodes To Keep change from
1715 //           IDs to groups or vice versa
1716 //=======================================================================
1717
1718 void SMESHGUI_MergeDlg::onKeepNodeSourceChanged(int isGroup)
1719 {
1720   KeepList->clear();
1721   SelectKeepNodesButton->click();
1722 }