Salome HOME
23151: EDF 9626 SMESH: Opening an existing study makes salome end with an allocation...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MergeDlg.cxx
index 8a615d35ef8e4684115379e76afa9a0f5cde3482..92642d384dfc542ddc83f431682057c81b84a0bd 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 #include <vtkIntArray.h>
 #include <vtkProperty2D.h>
 #include <vtkPointData.h>
-#include <vtkConfigure.h>
-#if !defined(VTK_XVERSION)
-#define VTK_XVERSION (VTK_MAJOR_VERSION<<16)+(VTK_MINOR_VERSION<<8)+(VTK_BUILD_VERSION)
-#endif
 
 // Qt includes
 #include <QApplication>
 #define SPACING 6
 #define MARGIN  11
 
+namespace
+{
+  enum ActionType { MERGE_NODES, MERGE_ELEMENTS, TYPE_AUTO=0, TYPE_MANUAL };
+}
 namespace SMESH
 {
   class TIdPreview
@@ -150,9 +150,6 @@ namespace SMESH
     
       myPtsLabeledDataMapper = vtkLabeledDataMapper::New();
       myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort());
-#if (VTK_XVERSION < 0x050200)
-      myPtsLabeledDataMapper->SetLabelFormat("%g");
-#endif
       myPtsLabeledDataMapper->SetLabelModeToLabelScalars();
     
       vtkTextProperty* aPtsTextProp = vtkTextProperty::New();
@@ -314,7 +311,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
 {
   setModal(false);
   setAttribute(Qt::WA_DeleteOnClose, true);
-  setWindowTitle(myAction == 1 ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
+  setWindowTitle(myAction == MERGE_ELEMENTS ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
 
   myIdPreview = new SMESH::TIdPreview(SMESH::GetViewWindow( mySMESHGUI ));
 
@@ -332,7 +329,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   DlgLayout->setMargin(MARGIN);
 
   /***************************************************************/
-  GroupConstructors = new QGroupBox(myAction == 1 ? 
+  GroupConstructors = new QGroupBox(myAction == MERGE_ELEMENTS ? 
                                     tr("SMESH_MERGE_ELEMENTS") : 
                                     tr("SMESH_MERGE_NODES"), 
                                     this);
@@ -343,7 +340,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   GroupConstructorsLayout->setMargin(MARGIN);
 
   RadioButton = new QRadioButton(GroupConstructors);
-  RadioButton->setIcon(myAction == 1 ? IconMergeElems : IconMergeNodes);
+  RadioButton->setIcon(myAction == MERGE_ELEMENTS ? IconMergeElems : IconMergeNodes);
   RadioButton->setChecked(true);
   GroupConstructorsLayout->addWidget(RadioButton);
   ButtonGroup->addButton(RadioButton, 0);
@@ -366,7 +363,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   GroupMeshLayout->addWidget(LineEditMesh);
 
   /***************************************************************/
-  // Controls for switch dialog behaviour
+  // Controls for switch dialog behaviour (myTypeId)
 
   TypeBox = new QGroupBox( tr( "SMESH_MODE" ), this );
   GroupType = new QButtonGroup( this );
@@ -381,11 +378,11 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   aTypeBoxLayout->addWidget( rb1 );
   aTypeBoxLayout->addWidget( rb2 );
 
-  myTypeId = 0;
+  myTypeId = TYPE_AUTO;
 
   /***************************************************************/
   // Controls for coincident elements detecting
-  GroupCoincident = new QGroupBox(myAction == 1 ? 
+  GroupCoincident = new QGroupBox(myAction == MERGE_ELEMENTS ? 
                                   tr("COINCIDENT_ELEMENTS") : 
                                   tr("COINCIDENT_NODES"), 
                                   this);
@@ -394,12 +391,16 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   aCoincidentLayout->setSpacing(SPACING);
   aCoincidentLayout->setMargin(MARGIN);
 
-  if (myAction == 0) { // case merge nodes
+  if (myAction == MERGE_NODES) // case merge nodes
+  {
     QWidget* foo = new QWidget(GroupCoincident);
     TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), foo);
     SpinBoxTolerance = new SMESHGUI_SpinBox(foo);
     SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
 
+    SeparateCornersAndMedium = new QCheckBox(tr("SEPARATE_CORNERS_AND_MEDIUM"), foo);
+    SeparateCornersAndMedium->setEnabled( false );
+
     GroupExclude = new QGroupBox(tr("EXCLUDE_GROUPS"), foo);
     GroupExclude->setCheckable( true );
     GroupExclude->setChecked( false );
@@ -409,19 +410,60 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     GroupExcludeLayout->setMargin(MARGIN);
     GroupExcludeLayout->addWidget(ListExclude);
 
+    QGroupBox*  GroupKeep = new QGroupBox(tr("KEEP_NODES"), foo);
+    SelectKeepNodesButton = new QPushButton( GroupKeep );
+    SelectKeepNodesButton->setIcon( IconSelect );
+    QLabel*       selectLabel = new QLabel(tr("SELECT"));
+    QRadioButton*   idsButton = new QRadioButton(tr("NODE_IDS"), GroupKeep);
+    QRadioButton* groupButton = new QRadioButton(tr("GROUP_SUBMESH"), GroupKeep);
+    KeepFromButGroup = new QButtonGroup( this );
+    KeepFromButGroup->addButton( idsButton,   0 );
+    KeepFromButGroup->addButton( groupButton, 1 );
+    groupButton->setChecked( true );
+    KeepList = new QListWidget( GroupKeep );
+    KeepList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+    KeepList->setFlow(QListView::TopToBottom);
+    AddKeepNodesButton    = new QPushButton(tr("SMESH_BUT_ADD"), GroupKeep );
+    RemoveKeepNodesButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupKeep );
+    QGridLayout* GroupKeepLayout = new QGridLayout(GroupKeep);
+    GroupKeepLayout->setSpacing( SPACING );
+    GroupKeepLayout->setMargin ( MARGIN );
+    GroupKeepLayout->addWidget( SelectKeepNodesButton, 0, 0 );
+    GroupKeepLayout->addWidget( selectLabel,           0, 1 );
+    GroupKeepLayout->addWidget( idsButton,             0, 2 );
+    GroupKeepLayout->addWidget( groupButton,           0, 3, 1, 2 );
+    GroupKeepLayout->addWidget( KeepList,              1, 0, 2, 4 );
+    GroupKeepLayout->addWidget( AddKeepNodesButton,    1, 4, 1, 1 );
+    GroupKeepLayout->addWidget( RemoveKeepNodesButton, 2, 4, 1, 1 );
+
     QGridLayout* fooLayout = new QGridLayout( foo );
     fooLayout->setSpacing(SPACING);
     fooLayout->setMargin(0);
-    fooLayout->addWidget(TextLabelTolerance, 0, 0 );
-    fooLayout->addWidget(SpinBoxTolerance,   0, 1 );
-    fooLayout->addWidget(GroupExclude,       1, 0, 1, 2 );
+    fooLayout->addWidget(TextLabelTolerance,       0, 0 );
+    fooLayout->addWidget(SpinBoxTolerance,         0, 1 );
+    fooLayout->addWidget(SeparateCornersAndMedium, 1, 0 );
+    fooLayout->addWidget(GroupExclude,             2, 0, 1, 2 );
+    fooLayout->addWidget(GroupKeep,                3, 0, 1, 2 );
     aCoincidentLayout->addWidget(foo);
+
+    // Costruction of the logical filter
+    QList<SUIT_SelectionFilter*> aListOfFilters;
+    aListOfFilters << new SMESH_TypeFilter (SMESH::SUBMESH)
+                   << new SMESH_TypeFilter (SMESH::GROUP);
+    mySubMeshOrGroupFilter =
+      new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true);
   }
   else {
-    TextLabelTolerance = 0;
-    SpinBoxTolerance = 0;
-    GroupExclude = 0;
-    ListExclude = 0;
+    TextLabelTolerance     = 0;
+    SpinBoxTolerance       = 0;
+    GroupExclude           = 0;
+    ListExclude            = 0;
+    KeepFromButGroup       = 0;
+    SelectKeepNodesButton  = 0;
+    AddKeepNodesButton     = 0;
+    RemoveKeepNodesButton  = 0;
+    KeepList               = 0;
+    mySubMeshOrGroupFilter = 0;
   }
 
   GroupCoincidentWidget = new QWidget(GroupCoincident);
@@ -437,12 +479,14 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincidentWidget);
 
   SelectAllCB = new QCheckBox(tr("SELECT_ALL"), GroupCoincidentWidget);
+  ShowIDs = new QCheckBox(myAction == MERGE_ELEMENTS ? tr("SHOW_ELEMS_IDS") : tr("SHOW_NODES_IDS"), GroupCoincidentWidget);
 
   GroupCoincidentLayout->addWidget(ListCoincident,    0,   0, 4, 2);
   GroupCoincidentLayout->addWidget(DetectButton,      0,   2);
   GroupCoincidentLayout->addWidget(AddGroupButton,    2, 2);
   GroupCoincidentLayout->addWidget(RemoveGroupButton, 3, 2);
-  GroupCoincidentLayout->addWidget(SelectAllCB,       4, 0, 1, 3);
+  GroupCoincidentLayout->addWidget(SelectAllCB,       4, 0);
+  GroupCoincidentLayout->addWidget(ShowIDs,           4, 1);
   GroupCoincidentLayout->setRowMinimumHeight(1, 10);
   GroupCoincidentLayout->setRowStretch(1, 5);
 
@@ -506,13 +550,15 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   DlgLayout->addWidget(GroupEdit);
   DlgLayout->addWidget(GroupButtons);
 
-  GroupCoincidentWidget->setVisible( myAction != 0 );
-  GroupCoincident->setVisible( myAction == 0 );
-  //if GroupExclude->setVisible( myAction == 0 );
+  GroupCoincidentWidget->setVisible( myAction != MERGE_NODES );
+  GroupCoincident      ->setVisible( myAction == MERGE_NODES );
+  //if GroupExclude->setVisible( myAction == MERGE_NODES );
   GroupEdit->hide();
 
   this->resize(10,10);
 
+  ShowIDs->setChecked( true );
+
   Init(); // Initialisations
 }
 
@@ -531,7 +577,7 @@ SMESHGUI_MergeDlg::~SMESHGUI_MergeDlg()
 //=================================================================================
 void SMESHGUI_MergeDlg::Init()
 {
-  if (myAction == 0) {
+  if ( myAction == MERGE_NODES ) {
     SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision");
     SpinBoxTolerance->SetValue(1e-05);
   }
@@ -540,7 +586,7 @@ void SMESHGUI_MergeDlg::Init()
 
   GroupType->button(0)->setChecked(true);
 
-  myEditCurrentArgument = (QWidget*)LineEditMesh; 
+  myEditCurrentArgument = (QWidget*)LineEditMesh;
 
   myActor = 0;
   mySubMeshOrGroup = SMESH::SMESH_subMesh::_nil();
@@ -549,37 +595,47 @@ void SMESHGUI_MergeDlg::Init()
 
   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
   myIsBusy = false;
-  
+
   /* signals and slots connections */
   connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
   connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
   connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
   connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
 
+  if ( KeepList )
+  {
+    connect(SelectKeepNodesButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
+    connect(KeepFromButGroup, SIGNAL (buttonClicked(int)), SLOT(onKeepNodeSourceChanged(int)));
+    connect(AddKeepNodesButton, SIGNAL (clicked()), this, SLOT(onAddKeepNode()));
+    connect(RemoveKeepNodesButton, SIGNAL (clicked()), this, SLOT(onRemoveKeepNode()));
+    connect(KeepList, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectKeepNode()));
+  }
   connect(SelectMeshButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
   connect(DetectButton, SIGNAL (clicked()), this, SLOT(onDetect()));
   connect(ListCoincident, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectGroup()));
   connect(AddGroupButton, SIGNAL (clicked()), this, SLOT(onAddGroup()));
   connect(RemoveGroupButton, SIGNAL (clicked()), this, SLOT(onRemoveGroup()));
   connect(SelectAllCB, SIGNAL(toggled(bool)), this, SLOT(onSelectAll(bool)));
+  connect(ShowIDs, SIGNAL(toggled(bool)), this, SLOT(onSelectGroup()));
   connect(ListEdit, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectElementFromGroup()));
   connect(AddElemButton, SIGNAL (clicked()), this, SLOT(onAddElement()));
   connect(RemoveElemButton, SIGNAL (clicked()), this, SLOT(onRemoveElement()));
-  connect(SetFirstButton, SIGNAL( clicked() ), this, SLOT( onSetFirst() ) );
+  connect(SetFirstButton, SIGNAL( clicked() ), this, SLOT( onSetFirst()));
   connect(GroupType, SIGNAL(buttonClicked(int)), this, SLOT(onTypeChanged(int)));
 
   connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
   /* to close dialog if study change */
   connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(reject()));
-
+  connect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this,  SLOT(onOpenView()));
+  connect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView()));
   // Init Mesh field from selection
   SelectionIntoArgument();
 
   // Update Buttons
   updateControls();
   
-  if (myAction == 0)
+  if ( myAction == MERGE_NODES )
     myHelpFileName = "merging_nodes_page.html";
   else
     myHelpFileName = "merging_elements_page.html";
@@ -630,7 +686,7 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
     return false;
 
   try {
-    if (myTypeId == 0)
+    if (myTypeId == TYPE_AUTO)
       onDetect();
 
     SUIT_OverrideCursor aWaitCursor;
@@ -640,7 +696,7 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
     SMESH::array_of_long_array_var aGroupsOfElements = new SMESH::array_of_long_array;
 
     if ( ListCoincident->count() == 0) {
-      if (myAction == 0)
+      if ( myAction == MERGE_NODES )
         SUIT_MessageBox::warning(this,
                                  tr("SMESH_WARNING"),
                                  tr("SMESH_NO_NODES_DETECTED"));
@@ -664,29 +720,71 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
       aGroupsOfElements[anArrayNum++] = anIds.inout();
     }
 
-    if( myAction == 0 )
-      aMeshEditor->MergeNodes (aGroupsOfElements.inout());
+    SMESH::ListOfIDSources_var nodesToKeep;
+    SMESH::IDSource_wrap tmpIdSource;
+    if ( myAction == MERGE_NODES )
+    {
+      nodesToKeep = new SMESH::ListOfIDSources();
+      int i, nb = KeepList->count();
+      if ( isKeepNodesIDsSelection() )
+      {
+        SMESH::long_array_var anIdList = new SMESH::long_array();
+        anIdList->length(nb);
+        for (i = 0; i < nb; i++)
+          anIdList[i] = KeepList->item(i)->text().toInt();
+
+        if ( nb > 0 )
+        {
+          tmpIdSource = aMeshEditor->MakeIDSource( anIdList, SMESH::NODE );
+          nodesToKeep->length( 1 );
+          nodesToKeep[0] = SMESH::SMESH_IDSource::_duplicate( tmpIdSource.in() );
+        }
+      }
+      else
+      {
+        nodesToKeep->length( nb );
+        int nbObj = 0;
+        for (i = 0; i < nb; i++)
+        {
+          QString entry = KeepList->item( i )->data( Qt::UserRole ).toString();
+          Handle(SALOME_InteractiveObject) anIO =
+            new SALOME_InteractiveObject( entry.toStdString().c_str(), "SMESH" );
+          SMESH::SMESH_IDSource_var idSrc =
+            SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( anIO );
+          if ( !idSrc->_is_nil() )
+            nodesToKeep[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( idSrc );
+        }
+        nodesToKeep->length( nbObj );
+      }
+      KeepList->clear();
+    }
+
+    if( myAction == MERGE_NODES )
+      aMeshEditor->MergeNodes (aGroupsOfElements.inout(), nodesToKeep);
     else
       aMeshEditor->MergeElements (aGroupsOfElements.inout());
 
-    if ( myTypeId == 0 ) {
-      if (myAction == 0 )
+    if ( myTypeId == TYPE_AUTO ) {
+      if (myAction == MERGE_NODES )
         SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
                                      tr("SMESH_MERGED_NODES").arg(QString::number(ListCoincident->count()).toLatin1().data()));
       else
         SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
                                      tr("SMESH_MERGED_ELEMENTS").arg(QString::number(ListCoincident->count()).toLatin1().data()));
     }
-      
+    nodesToKeep->length(0); // release before tmpIdSource calls UnRegister()
 
-  } catch(...) {
   }
-  
+  catch(...) {
+  }
+
   ListCoincident->clear();
-  
+
+  myEditCurrentArgument = (QWidget*)LineEditMesh;
+
   SMESH::UpdateView();
   SMESHGUI::Modified();
-  
+
   return true;
 }
 
@@ -721,6 +819,31 @@ void SMESHGUI_MergeDlg::reject()
   QDialog::reject();
 }
 
+//=================================================================================
+// function : onOpenView()
+// purpose  :
+//=================================================================================
+void SMESHGUI_MergeDlg::onOpenView()
+{
+  if ( mySelector ) {
+    SMESH::SetPointRepresentation(false);
+  }
+  else {
+    mySelector = SMESH::GetViewWindow( mySMESHGUI )->GetSelector();
+    ActivateThisDialog();
+  }
+}
+
+//=================================================================================
+// function : onCloseView()
+// purpose  :
+//=================================================================================
+void SMESHGUI_MergeDlg::onCloseView()
+{
+  DeactivateActiveDialog();
+  mySelector = 0;
+}
+
 //=================================================================================
 // function : ClickOnHelp()
 // purpose  :
@@ -775,9 +898,33 @@ void SMESHGUI_MergeDlg::updateControls()
 {
   if (ListEdit->count() == 0)
     SetFirstButton->setEnabled(false);
-  bool enable = !(myMesh->_is_nil()) && (ListCoincident->count() || (myTypeId == 0));
+
+  bool groupsEmpty = ( myTypeId != TYPE_AUTO );
+  for (int i = 0; i < ListCoincident->count() && groupsEmpty; i++) {
+    QStringList aListIds = ListCoincident->item(i)->text().split(" ", QString::SkipEmptyParts);
+    groupsEmpty = ( aListIds.count() < 2 );
+  }
+  bool enable = ( !myMesh->_is_nil() && !groupsEmpty );
   buttonOk->setEnabled(enable);
   buttonApply->setEnabled(enable);
+  DetectButton->setEnabled( !myMesh->_is_nil() );
+
+  if ( myAction == MERGE_NODES )
+  {
+    bool has2ndOrder = (( !myMesh->_is_nil() ) &&
+                        ( myMesh->NbEdgesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ||
+                          myMesh->NbFacesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ||
+                          myMesh->NbVolumesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ));
+
+    SeparateCornersAndMedium->setEnabled( has2ndOrder );
+
+    if ( myEditCurrentArgument != KeepList )
+    {
+      AddKeepNodesButton->setEnabled( false );
+      RemoveKeepNodesButton->setEnabled( false );
+      KeepList->clearSelection();
+    }
+  }
 }
 
 //=================================================================================
@@ -804,7 +951,7 @@ void SMESHGUI_MergeDlg::onDetect()
     else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup );
 
     switch (myAction) {
-    case 0 :
+    case MERGE_NODES :
       for ( int i = 0; GroupExclude->isChecked() && i < ListExclude->count(); i++ ) {
         if ( ListExclude->item( i )->checkState() == Qt::Checked ) {
           aExcludeGroups->length( aExcludeGroups->length()+1 );
@@ -814,9 +961,11 @@ void SMESHGUI_MergeDlg::onDetect()
       aMeshEditor->FindCoincidentNodesOnPartBut(src.in(),
                                                 SpinBoxTolerance->GetValue(), 
                                                 aGroupsArray.out(),
-                                                aExcludeGroups.in());
+                                                aExcludeGroups.in(),
+                                                SeparateCornersAndMedium->isEnabled() &&
+                                                SeparateCornersAndMedium->isChecked());
       break;
-    case 1 :
+    case MERGE_ELEMENTS :
       aMeshEditor->FindEqualElements(src.in(), aGroupsArray.out());
       break;
     }
@@ -830,11 +979,12 @@ void SMESHGUI_MergeDlg::onDetect()
 
       ListCoincident->addItem(anIDs.join(" "));
     }
-   } catch(...) {
+  } catch(...) {
   }
 
   ListCoincident->selectAll();
   updateControls();
+  SMESH::UpdateView();
 }
 
 //=================================================================================
@@ -845,10 +995,15 @@ void SMESHGUI_MergeDlg::onSelectGroup()
 {
   if (myIsBusy || !myActor)
     return;
+
+  if( ListCoincident->count() != ListCoincident->selectedItems().count() )
+    SelectAllCB->setChecked( false );
+
   myEditCurrentArgument = (QWidget*)ListCoincident;
 
+  myIsBusy = true;
   ListEdit->clear();
-  
+
   TColStd_MapOfInteger anIndices;
   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
   QListWidgetItem* anItem;
@@ -861,7 +1016,7 @@ void SMESHGUI_MergeDlg::onSelectGroup()
     for (int i = 0; i < aListIds.count(); i++)
       anIndices.Add(aListIds[i].toInt());
   }
-  
+
   if (selItems.count() == 1) {
     ListEdit->addItems(aListIds);
     ListEdit->selectAll();
@@ -872,18 +1027,22 @@ void SMESHGUI_MergeDlg::onSelectGroup()
   aList.Append(myActor->getIO());
   mySelectionMgr->setSelectedObjects(aList,false);
   
-  if (myAction == 0) {
-    myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
-    myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
-  }
-  else {
-    std::list< gp_XYZ > aGrCentersXYZ;
-    FindGravityCenter(anIndices, aGrCentersXYZ);
-    myIdPreview->SetElemsData( anIndices, aGrCentersXYZ);
-    myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
-  }
+  if (ShowIDs->isChecked()) 
+    if ( myAction == MERGE_NODES ) {
+      myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
+      myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
+    }
+    else {
+      std::list< gp_XYZ > aGrCentersXYZ;
+      FindGravityCenter(anIndices, aGrCentersXYZ);
+      myIdPreview->SetElemsData( anIndices, aGrCentersXYZ);
+      myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
+    }
+  else
+    myIdPreview->SetPointsLabeled(false);
 
   updateControls();
+  myIsBusy = false;
 }
 
 //=================================================================================
@@ -920,17 +1079,20 @@ void SMESHGUI_MergeDlg::onSelectElementFromGroup()
   SALOME_ListIO aList;
   aList.Append(myActor->getIO());
   mySelectionMgr->setSelectedObjects(aList);
-
-  if (myAction == 0) {
-    myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
-    myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
-  }
-  else {
-    std::list< gp_XYZ > aGrCentersXYZ;
-    FindGravityCenter(anIndices, aGrCentersXYZ);
-    myIdPreview->SetElemsData(anIndices, aGrCentersXYZ);
-    myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
-  }
+  
+  if (ShowIDs->isChecked())
+    if (myAction == MERGE_NODES) {
+      myIdPreview->SetPointsData(myActor->GetObject()->GetMesh(), anIndices);
+      myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
+    }
+    else {
+      std::list< gp_XYZ > aGrCentersXYZ;
+      FindGravityCenter(anIndices, aGrCentersXYZ);
+      myIdPreview->SetElemsData(anIndices, aGrCentersXYZ);
+      myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
+    }
+  else 
+    myIdPreview->SetPointsLabeled(false);
 }
 
 //=================================================================================
@@ -982,9 +1144,15 @@ void SMESHGUI_MergeDlg::onRemoveGroup()
     delete anItem;
 
   ListEdit->clear();
+  myIdPreview->SetPointsLabeled(false);
   updateControls();
-
+  SMESH::UpdateView();
   myIsBusy = false;
+
+  if( ListCoincident->count() == 0 ) {
+    myEditCurrentArgument = (QWidget*)LineEditMesh;
+    SelectAllCB->setChecked( false );
+  }
 }
 
 //=================================================================================
@@ -1041,6 +1209,11 @@ void SMESHGUI_MergeDlg::onRemoveElement()
   
   myIsBusy = false;
   onEditGroup();
+
+  if( ListCoincident->count() == 0 ) {
+    myEditCurrentArgument = (QWidget*)LineEditMesh;
+    SelectAllCB->setChecked( false );
+  }
 }
 
 //=================================================================================
@@ -1077,14 +1250,32 @@ void SMESHGUI_MergeDlg::SetEditCurrentArgument()
   mySelectionMgr->clearSelected();
   mySelectionMgr->clearFilters();
 
-  if (send == SelectMeshButton) {
+  if (send == SelectMeshButton)
+  {
     myEditCurrentArgument = (QWidget*)LineEditMesh;
     SMESH::SetPointRepresentation(false);
     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
       aViewWindow->SetSelectionMode(ActorSelection);
-    if (myTypeId == 1)
+    if (myTypeId == TYPE_MANUAL)
       mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
   }
+  else if ( send == SelectKeepNodesButton && send )
+  {
+    myEditCurrentArgument = (QWidget*)KeepList;
+    KeepList->setWrapping( isKeepNodesIDsSelection() );
+    if ( isKeepNodesIDsSelection() )
+    {
+      SMESH::SetPointRepresentation( true );
+      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+        aViewWindow->SetSelectionMode( NodeSelection );
+    }
+    else
+    {
+      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+        aViewWindow->SetSelectionMode( ActorSelection );
+      mySelectionMgr->installFilter( mySubMeshOrGroupFilter );
+    }
+  }
 
   myEditCurrentArgument->setFocus();
   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
@@ -1093,19 +1284,21 @@ void SMESHGUI_MergeDlg::SetEditCurrentArgument()
 
 //=================================================================================
 // function : SelectionIntoArgument()
-// purpose  : Called when selection as changed or other case
+// purpose  : Called when selection has changed or other case
 //=================================================================================
 void SMESHGUI_MergeDlg::SelectionIntoArgument()
 {
-  if (myEditCurrentArgument == (QWidget*)LineEditMesh) {
+  if (myEditCurrentArgument == (QWidget*)LineEditMesh)
+  {
     QString aString = "";
     LineEditMesh->setText(aString);
-    
+
     ListCoincident->clear();
     ListEdit->clear();
     myActor = 0;
+    myMesh = SMESH::SMESH_Mesh::_nil();
     QString aCurrentEntry = myEntry;
-    
+
     int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
     if (nbSel != 1) {
       myIdPreview->SetPointsLabeled(false);
@@ -1118,30 +1311,33 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
 
     SALOME_ListIO aList;
     mySelectionMgr->selectedObjects(aList);
-    
+
     Handle(SALOME_InteractiveObject) IO = aList.First();
     myEntry = IO->getEntry();
     myMesh = SMESH::GetMeshByIO(IO);
-    
+
+    if ( myEntry != aCurrentEntry && KeepList )
+      KeepList->clear();
+
     if (myMesh->_is_nil())
       return;
 
     LineEditMesh->setText(aString);
-    
+
     myActor = SMESH::FindActorByEntry(IO->getEntry());
     if (!myActor)
       myActor = SMESH::FindActorByObject(myMesh);
-    
-    if ( myActor && myTypeId ==1 ) {
+
+    if ( myActor && myTypeId == TYPE_MANUAL && mySelector->IsSelectionEnabled() ) {
       mySubMeshOrGroup = SMESH::SMESH_IDSource::_nil();
       mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
-      
+
       if ((!SMESH::IObjectToInterface<SMESH::SMESH_subMesh>(IO)->_is_nil() || //SUBMESH OR GROUP
            !SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>(IO)->_is_nil()) &&
           !SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO)->_is_nil())
         mySubMeshOrGroup = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
-      
-      if (myAction == 0) {
+
+      if (myAction == MERGE_NODES) {
         SMESH::SetPointRepresentation(true);
         if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
           aViewWindow->SetSelectionMode(NodeSelection);
@@ -1152,7 +1348,7 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
     }
 
     // process groups
-    if ( myAction == 0 && !myMesh->_is_nil() && myEntry != aCurrentEntry ) {
+    if ( myAction == MERGE_NODES && !myMesh->_is_nil() && myEntry != aCurrentEntry ) {
       myGroups.clear();
       ListExclude->clear();
       SMESH::ListOfGroups_var aListOfGroups = myMesh->GetGroups();
@@ -1173,6 +1369,59 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
 
     updateControls();
   }
+
+  else if (myEditCurrentArgument == (QWidget*)KeepList && KeepList)
+  {
+    AddKeepNodesButton->setEnabled( false );
+    RemoveKeepNodesButton->setEnabled( false );
+    if ( isKeepNodesIDsSelection() )
+    {
+      if (!myMesh->_is_nil() && !myActor)
+        myActor = SMESH::FindActorByObject(myMesh);
+
+      if ( mySelector && myActor )
+      {
+        KeepList->clearSelection();
+        QString anIDs = "";
+        int aNbNodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
+        if (aNbNodes > 0)
+        {
+          QStringList anNodes = anIDs.split( " ", QString::SkipEmptyParts);
+          QList<QListWidgetItem*> listItemsToSel;
+          QListWidgetItem* anItem;
+          int nbFound = 0;
+          for (QStringList::iterator it = anNodes.begin(); it != anNodes.end(); ++it)
+          {
+            QList<QListWidgetItem*> found = KeepList->findItems(*it, Qt::MatchExactly);
+            foreach(anItem, found)
+              if (!anItem->isSelected())
+                listItemsToSel.push_back(anItem);
+            nbFound += found.count();
+          }
+          bool blocked = KeepList->signalsBlocked();
+          KeepList->blockSignals(true);
+          foreach(anItem, listItemsToSel) anItem->setSelected(true);
+          KeepList->blockSignals(blocked);
+          //onSelectKeepNode();
+          AddKeepNodesButton->setEnabled( nbFound < aNbNodes );
+          RemoveKeepNodesButton->setEnabled( nbFound > 0 );
+        }
+      }
+    }
+    else if ( !myMesh->_is_nil() )
+    {
+      SALOME_ListIO aList;
+      mySelectionMgr->selectedObjects(aList);
+      bool hasNewSelected = false;
+      SALOME_ListIteratorOfListIO anIt (aList);
+      for ( ; anIt.More() && !hasNewSelected; anIt.Next())
+        if ( anIt.Value()->hasEntry() )
+          hasNewSelected = isNewKeepNodesGroup( anIt.Value()->getEntry() );
+
+      AddKeepNodesButton->setEnabled( hasNewSelected );
+      //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+    }
+  }
 }
 
 //=================================================================================
@@ -1220,10 +1469,15 @@ void SMESHGUI_MergeDlg::ActivateThisDialog()
 // function : enterEvent()
 // purpose  :
 //=================================================================================
-void SMESHGUI_MergeDlg::enterEvent(QEvent*)
+void SMESHGUI_MergeDlg::enterEvent (QEvent*)
 {
-  if (!GroupConstructors->isEnabled())
+  if ( !GroupConstructors->isEnabled() ) {
+    SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI );
+    if ( aViewWindow && !mySelector) {
+      mySelector = aViewWindow->GetSelector();
+    }
     ActivateThisDialog();
+  }
 }
 
 //=================================================================================
@@ -1254,20 +1508,22 @@ void SMESHGUI_MergeDlg::onTypeChanged (int id)
   myTypeId = id;
   switch (id)
   {
-  case 0: // automatic
+  case TYPE_AUTO: // automatic
+
     myIdPreview->SetPointsLabeled(false);
     SMESH::SetPointRepresentation(false);
     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
       aViewWindow->SetSelectionMode(ActorSelection);
     mySelectionMgr->clearFilters();
-    if (myAction == 0)
+    if (myAction == MERGE_NODES)
       GroupCoincidentWidget->hide();
     else
       GroupCoincident->hide();
     GroupEdit->hide();
     break;
 
-  case 1: // manual
+  case TYPE_MANUAL: // manual
+
     SMESH::UpdateView();
 
     // Costruction of the logical filter
@@ -1281,16 +1537,18 @@ void SMESHGUI_MergeDlg::onTypeChanged (int id)
     myMeshOrSubMeshOrGroupFilter =
       new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR);
 
-    if (myAction == 0) {
+    if (myAction == MERGE_NODES) {
       GroupCoincidentWidget->show();
       SMESH::SetPointRepresentation(true);
       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-        aViewWindow->SetSelectionMode(NodeSelection);
+        if( mySelector->IsSelectionEnabled() )
+          aViewWindow->SetSelectionMode(NodeSelection);
     }
     else {
       GroupCoincident->show();
       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-        aViewWindow->SetSelectionMode(CellSelection);
+        if( mySelector->IsSelectionEnabled() )
+          aViewWindow->SetSelectionMode(CellSelection);
     }
     GroupEdit->show();
     break;
@@ -1303,3 +1561,168 @@ void SMESHGUI_MergeDlg::onTypeChanged (int id)
 
   SelectionIntoArgument();
 }
+
+//=======================================================================
+//function : isKeepNodesIDsSelection
+//purpose  : Return true of Nodes to keep are selected by IDs
+//=======================================================================
+
+bool SMESHGUI_MergeDlg::isKeepNodesIDsSelection()
+{
+  return KeepFromButGroup && KeepFromButGroup->checkedId() == 0;
+}
+
+//=======================================================================
+//function : isNewKeepNodesGroup
+//purpose  : Return true if an object with given entry is NOT present in KeepList
+//=======================================================================
+
+bool SMESHGUI_MergeDlg::isNewKeepNodesGroup( const char* entry )
+{
+  if ( !entry || isKeepNodesIDsSelection() )
+    return false;
+
+  for ( int i = 0; i < KeepList->count(); i++ )
+    if ( KeepList->item( i )->data( Qt::UserRole ).toString() == entry )
+      return false;
+
+  return true;
+}
+
+//=======================================================================
+//function : onAddKeepNode
+//purpose  : SLOT called when [Add] of Nodes To Keep group is pressed
+//=======================================================================
+
+void SMESHGUI_MergeDlg::onAddKeepNode()
+{
+  if ( myIsBusy )
+    return;
+  myIsBusy = true;
+
+  if ( isKeepNodesIDsSelection() )
+  {
+    //KeepList->clearSelection();
+    QString anIDs = "";
+    int aNbNodes = 0;
+    if ( myActor )
+      aNbNodes = SMESH::GetNameOfSelectedNodes(mySelector, myActor->getIO(), anIDs);
+    if (aNbNodes > 0)
+    {
+      QStringList anNodes = anIDs.split( " ", QString::SkipEmptyParts);
+      QList<QListWidgetItem*> listItemsToSel;
+      QListWidgetItem* anItem;
+      for (QStringList::iterator it = anNodes.begin(); it != anNodes.end(); ++it)
+      {
+        QList<QListWidgetItem*> found = KeepList->findItems(*it, Qt::MatchExactly);
+        if (found.count() == 0) {
+          anItem = new QListWidgetItem(*it);
+          KeepList->addItem(anItem);
+          if (!anItem->isSelected())
+            listItemsToSel.push_back(anItem);
+        }
+        else {
+          foreach(anItem, found)
+            if (!anItem->isSelected())
+              listItemsToSel.push_back(anItem);
+        }
+      }
+      bool blocked = KeepList->signalsBlocked();
+      KeepList->blockSignals(true);
+      foreach(anItem, listItemsToSel) anItem->setSelected(true);
+      KeepList->blockSignals(blocked);
+      //onSelectKeepNode();
+    }
+    RemoveKeepNodesButton->setEnabled( aNbNodes > 0 );
+  }
+  else
+  {
+    SALOME_ListIO aList;
+    mySelectionMgr->selectedObjects(aList);
+    SALOME_ListIteratorOfListIO anIt (aList);
+    for ( ; anIt.More(); anIt.Next()) {
+      Handle(SALOME_InteractiveObject) anIO = anIt.Value();
+      if ( isNewKeepNodesGroup( anIO->getEntry() ))
+      {
+        QListWidgetItem* anItem = new QListWidgetItem( anIO->getName() );
+        anItem->setData( Qt::UserRole, QString( anIO->getEntry() ));
+        KeepList->addItem(anItem);
+      }
+    }
+    //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+  }
+
+  AddKeepNodesButton->setEnabled( false );
+
+  myIsBusy = false;
+}
+
+//=======================================================================
+//function : onRemoveKeepNode
+//purpose  : SLOT called when [Remove] of Nodes To Keep group is pressed
+//=======================================================================
+
+void SMESHGUI_MergeDlg::onRemoveKeepNode()
+{
+  // if ( isKeepNodesIDsSelection() )
+  // {
+  // }
+  // else
+  {
+    QList<QListWidgetItem*> selItems = KeepList->selectedItems();
+    QListWidgetItem* item;
+    foreach(item, selItems) delete item;
+  }
+  if ( isKeepNodesIDsSelection() )
+  {
+    AddKeepNodesButton->setEnabled( false );
+  }
+  RemoveKeepNodesButton->setEnabled( false );
+}
+
+//=======================================================================
+//function : onSelectKeepNode
+//purpose  : SLOT called when selection in KeepList changes
+//=======================================================================
+
+void SMESHGUI_MergeDlg::onSelectKeepNode()
+{
+  if ( myIsBusy || !isEnabled() ) return;
+  myIsBusy = true;
+
+  if ( isKeepNodesIDsSelection() )
+  {
+    if ( myActor )
+    {
+      mySelectionMgr->clearSelected();
+      TColStd_MapOfInteger aIndexes;
+      QList<QListWidgetItem*> selItems = KeepList->selectedItems();
+      QListWidgetItem* anItem;
+      foreach(anItem, selItems) aIndexes.Add(anItem->text().toInt());
+      mySelector->AddOrRemoveIndex(myActor->getIO(), aIndexes, false);
+      SALOME_ListIO aList;
+      aList.Append(myActor->getIO());
+      mySelectionMgr->setSelectedObjects(aList,false);
+
+      AddKeepNodesButton->setEnabled( false );
+      RemoveKeepNodesButton->setEnabled( aIndexes.Extent() > 0 );
+    }
+  }
+  else
+  {
+    RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+  }
+  myIsBusy = false;
+}
+
+//=======================================================================
+//function : onKeepNodeSourceChanged
+//purpose  : SLOT called when type of source of Nodes To Keep change from
+//           IDs to groups or vice versa
+//=======================================================================
+
+void SMESHGUI_MergeDlg::onKeepNodeSourceChanged(int isGroup)
+{
+  KeepList->clear();
+  SelectKeepNodesButton->click();
+}