Salome HOME
0023326: [CEA 1934] Error when extracting a shape
[modules/geom.git] / src / OperationGUI / OperationGUI_ExtractionDlg.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "OperationGUI_ExtractionDlg.h"
24
25 #include <GEOMBase.h>
26 #include <GeometryGUI.h>
27
28 #include <LightApp_SelectionMgr.h>
29 #include <SalomeApp_Application.h>
30 #include <SalomeApp_Tools.h>
31 #include <SUIT_ResourceMgr.h>
32 #include <SUIT_Session.h>
33
34 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
35 #include <TopExp.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <TopoDS_Iterator.hxx>
38 #include <TopTools_IndexedMapOfShape.hxx>
39 #include <TopTools_MapOfShape.hxx>
40
41 #include <QComboBox>
42 #include <QGridLayout>
43 #include <QGroupBox>
44 #include <QHBoxLayout>
45 #include <QLabel>
46 #include <QLineEdit>
47 #include <QListWidget>
48 #include <QPushButton>
49 #include <QRadioButton>
50 #include <QTreeWidget>
51 #include <QVBoxLayout>
52 #include <QtGlobal>
53
54 #if QT_VERSION >= 0x050300
55   #include <QSignalBlocker>
56 #else
57   /**
58    * This class is named as QT class as it is introduced since Qt 5.3.
59    * It should not be compiled when Salome is ported on Qt 5.3.
60    */
61   class QSignalBlocker
62   {
63   public:
64     QSignalBlocker(QObject *object)
65       : myObject    (object),
66         myIsBlocked (object && object->signalsBlocked()) {
67       if (myObject) {
68         myObject->blockSignals(true);
69       }
70     }
71
72     ~QSignalBlocker() {
73       if (myObject) {
74         myObject->blockSignals(myIsBlocked);
75       }
76     }
77
78   private:
79     QObject *myObject;    ///< Blocked object.
80     bool     myIsBlocked; ///< Initial blocked state.
81   };
82 #endif
83
84
85 #define ID_ROLE   Qt::DisplayRole
86 #define TYPE_ROLE Qt::UserRole
87
88 static const char* const TMP_STR = "TEMP";
89
90 static const char* const SINGLE_SHAPE_TYPE_TR_CODES [] = {
91   "GEOM_COMPOUND",
92   "GEOM_COMPOUNDSOLID",
93   "GEOM_SOLID",
94   "GEOM_SHELL",
95   "GEOM_FACE",
96   "GEOM_WIRE",
97   "GEOM_EDGE",
98   "GEOM_VERTEX"
99 };
100
101 static const char* const PLURAL_SHAPE_TYPE_TR_CODES [] = {
102   "GEOM_COMPOUND",   // Not used
103   "GEOM_COMPSOLIDS",
104   "GEOM_SOLIDS",
105   "GEOM_SHELLS",
106   "GEOM_FACES",
107   "GEOM_WIREZ",
108   "GEOM_EDGES",
109   "GEOM_VERTEXES"
110 };
111
112
113 /**
114  * This static function creates a new list widget item with given ID and
115  * returns it.
116  *
117  * \param theID the item ID.
118  * \param theListWidget the list widget.
119  * \return the created list widget item.
120  */
121 static QListWidgetItem *addNewItem(const int    theID,
122                                    QListWidget *theListWidget)
123 {
124   QListWidgetItem *aResult = new QListWidgetItem;
125
126   aResult->setData(ID_ROLE, theID);
127   theListWidget->addItem(aResult);
128
129   return aResult;
130 }
131
132 /**
133  * This static function creates a new tree widget item as a child of the input
134  * one with given ID and returns it.
135  *
136  * \param theID the item ID.
137  * \param theParentItem the parent item.
138  * \return the created tree widget item.
139  */
140 static QTreeWidgetItem *addChildItem(const int        theID,
141                                      QTreeWidgetItem *theParentItem)
142 {
143   QTreeWidgetItem *aResult = new QTreeWidgetItem;
144
145   aResult->setData(0, ID_ROLE, theID);
146   theParentItem->addChild(aResult);
147
148   return aResult;
149 }
150
151 /**
152  * This static function returns the maximal shape type of sub-shapes stored in
153  * the input compound. If it is not a compound, it returns TopAbs_SHAPE.
154  *
155  * \param theCompound the compound.
156  * \return the maximal shape type of sub-shapes stored in the input compound.
157  */
158 static TopAbs_ShapeEnum GetMaxShapeTypeInComp(const TopoDS_Shape &theCompound)
159 {
160   TopAbs_ShapeEnum aResult = TopAbs_SHAPE;
161
162   if (theCompound.IsNull() || theCompound.ShapeType() != TopAbs_COMPOUND) {
163     return aResult;
164   }
165
166   TopoDS_Iterator anIt(theCompound, Standard_False, Standard_False);
167
168   for (; anIt.More(); anIt.Next()) {
169     const TopoDS_Shape &aSubShape = anIt.Value();
170
171     if (aSubShape.IsNull()) {
172       continue;
173     }
174
175     // Get the sub-shape type.
176     TopAbs_ShapeEnum aSubType = aSubShape.ShapeType();
177
178     if (aSubType == TopAbs_COMPOUND) {
179       aSubType = GetMaxShapeTypeInComp(aSubShape);
180     }
181
182     if (aSubType == TopAbs_SHAPE) {
183       continue;
184     }
185
186     if (aResult == TopAbs_SHAPE) {
187       // This is an initialization.
188       aResult = aSubType;
189     } else if (aResult > aSubType) {
190       aResult = aSubType;
191     }
192   }
193
194   return aResult;
195 }
196
197 //=================================================================================
198 // class    : OperationGUI_ExtractionDlg()
199 // purpose  : 
200 //=================================================================================
201 OperationGUI_ExtractionDlg::OperationGUI_ExtractionDlg
202                         (GeometryGUI* GUI, QWidget* parent)
203   : GEOMBase_Skeleton (GUI, parent, false),
204     mySelBtn          (0),
205     myMainShapeEdit   (0),
206     mySubShTypeCompo  (0),
207     myFilteredList    (0),
208     myExtractedTree   (0),
209     myRemovedList     (0),
210     myModifiedList    (0),
211     myAddedList       (0),
212     myRebuildBtn      (0),
213     myIsHiddenMain    (false)
214 {
215   QPixmap image0(SUIT_Session::session()->resourceMgr()->loadPixmap(
216     "GEOM", tr("ICON_DLG_EXTRACTION")));
217   QPixmap image1(SUIT_Session::session()->resourceMgr()->loadPixmap(
218     "GEOM", tr("ICON_SELECT")));
219
220   setWindowTitle(tr("GEOM_EXTRACT_TITLE"));
221
222   /***************************************************************/
223
224   mainFrame()->GroupConstructors->setTitle(tr("GEOM_EXTRACT_TYPE"));
225   mainFrame()->RadioButton1->setIcon( image0 );
226   mainFrame()->RadioButton2->setAttribute(Qt::WA_DeleteOnClose);
227   mainFrame()->RadioButton2->close();
228   mainFrame()->RadioButton3->setAttribute(Qt::WA_DeleteOnClose);
229   mainFrame()->RadioButton3->close();
230
231   // Create an input group.
232   QGroupBox   *anInputGrp      = new QGroupBox(tr("GEOM_EXTRACT_INPUT_PARAMS"), centralWidget());
233   QGridLayout *anInputLayout   = new QGridLayout(anInputGrp);
234   QHBoxLayout *aShapeLayout    = new QHBoxLayout(anInputGrp);
235   QVBoxLayout *aViewBtnsLayout = new QVBoxLayout(anInputGrp);
236   QVBoxLayout *aMoveBtnsLayout = new QVBoxLayout(anInputGrp);
237   QLabel      *aMainObjLbl     = new QLabel(tr("GEOM_MAIN_OBJECT"), anInputGrp);
238   QLabel      *aSubShTypeLbl   = new QLabel(tr("GEOM_EXTRACT_SUB_SHAPE_TYPE"), anInputGrp);
239   QLabel      *aFilteredLbl    = new QLabel(tr("GEOM_EXTRACT_FILTERED_SHAPES"), anInputGrp);
240   QLabel      *anExtractedLbl  = new QLabel(tr("GEOM_EXTRACT_SHAPES_TO_EXTRACT"), anInputGrp);
241   QPushButton *aShowOnlySelBtn = new QPushButton(tr("SHOW_ONLY_SELECTED"), anInputGrp);
242   QPushButton *aHideSelBtn     = new QPushButton(tr("HIDE_SELECTED"), anInputGrp);
243   QPushButton *aShowAllBtn     = new QPushButton(tr("SHOW_ALL_SUB_SHAPES"), anInputGrp);
244   QPushButton *anAddBtn        = new QPushButton(">>", anInputGrp);
245   QPushButton *aRemoveBtn      = new QPushButton("<<", anInputGrp);
246
247   myRebuildBtn     = new QPushButton(tr("GEOM_EXTRACT_REBUILD"), anInputGrp);
248   mySelBtn         = new QPushButton(anInputGrp);
249   myMainShapeEdit  = new QLineEdit(anInputGrp);
250   mySubShTypeCompo = new QComboBox(anInputGrp);
251   myFilteredList   = new QListWidget(anInputGrp);
252   myExtractedTree  = new QTreeWidget(anInputGrp);
253   mySelBtn->setIcon(image1);
254   myMainShapeEdit->setReadOnly(true);
255
256   aShapeLayout->addWidget(mySelBtn);
257   aShapeLayout->addWidget(myMainShapeEdit);
258
259   aViewBtnsLayout->addStretch();
260   aViewBtnsLayout->addWidget(aShowOnlySelBtn);
261   aViewBtnsLayout->addWidget(aHideSelBtn);
262   aViewBtnsLayout->addWidget(aShowAllBtn);
263   aViewBtnsLayout->addStretch();
264
265   aMoveBtnsLayout->addStretch();
266   aMoveBtnsLayout->addWidget(anAddBtn);
267   aMoveBtnsLayout->addWidget(aRemoveBtn);
268   aMoveBtnsLayout->addStretch();
269
270   anInputLayout->setSpacing(6);
271   anInputLayout->setContentsMargins(9, 9, 9, 9);
272   anInputLayout->addWidget(aMainObjLbl,      0, 0);
273   anInputLayout->addLayout(aShapeLayout,     0, 1, 1, 3);
274   anInputLayout->addWidget(aSubShTypeLbl,    1, 0);
275   anInputLayout->addWidget(mySubShTypeCompo, 1, 1, 1, 3);
276   anInputLayout->addWidget(aFilteredLbl,     2, 1);
277   anInputLayout->addWidget(anExtractedLbl,   2, 3);
278   anInputLayout->addLayout(aViewBtnsLayout,  3, 0);
279   anInputLayout->addWidget(myFilteredList,   3, 1);
280   anInputLayout->addLayout(aMoveBtnsLayout,  3, 2);
281   anInputLayout->addWidget(myExtractedTree,  3, 3);
282   anInputLayout->addWidget(myRebuildBtn,     4, 0, 1, 4);
283
284   // Create a statistics group.
285   QGroupBox   *aStatGrp     = new QGroupBox(tr("GEOM_EXTRACT_STATISTICS"), centralWidget());
286   QGridLayout *aStatLayout  = new QGridLayout(aStatGrp);
287   QLabel      *aRemovedLbl  = new QLabel(tr("GEOM_EXTRACT_REMOVED"), aStatGrp);
288   QLabel      *aModifiedLbl = new QLabel(tr("GEOM_EXTRACT_MODIFIED"), aStatGrp);
289   QLabel      *anAddedLbl   = new QLabel(tr("GEOM_EXTRACT_ADDED"), aStatGrp);
290
291   myRemovedList  = new QListWidget(aStatGrp);
292   myModifiedList = new QListWidget(aStatGrp);
293   myAddedList    = new QListWidget(aStatGrp);
294
295   aStatLayout->setSpacing(6);
296   aStatLayout->setContentsMargins(9, 9, 9, 9);
297   aStatLayout->addWidget(aRemovedLbl,    0, 0);
298   aStatLayout->addWidget(aModifiedLbl,   0, 1);
299   aStatLayout->addWidget(anAddedLbl,     0, 2);
300   aStatLayout->addWidget(myRemovedList,  1, 0);
301   aStatLayout->addWidget(myModifiedList, 1, 1);
302   aStatLayout->addWidget(myAddedList,    1, 2);
303
304   // Create a main layout.
305   QVBoxLayout* aLayout = new QVBoxLayout(centralWidget());
306
307   aLayout->setMargin(0);
308   aLayout->setSpacing(6);
309   aLayout->addWidget(anInputGrp);
310   aLayout->addWidget(aStatGrp);
311
312   // signals and slots connections
313   connect(anAddBtn,        SIGNAL(clicked()), this, SLOT(onAddExtracted()));
314   connect(aRemoveBtn,      SIGNAL(clicked()), this, SLOT(onRemoveExtracted()));
315   connect(aShowOnlySelBtn, SIGNAL(clicked()), this, SLOT(showOnlySelected()));
316   connect(aHideSelBtn,     SIGNAL(clicked()), this, SLOT(hideSelected()));
317   connect(aShowAllBtn,     SIGNAL(clicked()), this, SLOT(showAllSelected()));
318
319   /***************************************************************/
320   myHelpFileName = "extract_and_rebuild_page.html";
321
322   resize(525, 600);
323
324   /* Initialisation */
325   Init();
326 }
327
328 //=================================================================================
329 // function : ~OperationGUI_ExtractionDlg()
330 // purpose  : Destroys the object and frees any allocated resources
331 //=================================================================================
332 OperationGUI_ExtractionDlg::~OperationGUI_ExtractionDlg()
333 {
334   restoreViewer();
335 }
336
337 //=================================================================================
338 // function : Init()
339 // purpose  :
340 //=================================================================================
341 void OperationGUI_ExtractionDlg::Init()
342 {
343   mySelBtn->setCheckable(true);
344   mySelBtn->setChecked(true);
345   myFilteredList->setSelectionMode(QAbstractItemView::ExtendedSelection);
346   myFilteredList->setSortingEnabled(true);
347   myExtractedTree->setHeaderHidden(true);
348   myExtractedTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
349   myExtractedTree->setColumnCount(1);
350   myRebuildBtn->setEnabled(false);
351   myRemovedList->setSelectionMode(QAbstractItemView::NoSelection);
352   myModifiedList->setSelectionMode(QAbstractItemView::NoSelection);
353   myAddedList->setSelectionMode(QAbstractItemView::NoSelection);
354
355   // Fill in the extracted tree with initial elements.
356   myTopItems[0] = 0; // No need to create a item for compound.
357
358   int i;
359
360   for (i = 1; i < 8; i++) {
361     myTopItems[i] = new QTreeWidgetItem;
362     myTopItems[i]->setText(0, tr(PLURAL_SHAPE_TYPE_TR_CODES[i]));
363     myTopItems[i]->setData(0, TYPE_ROLE, i);
364   
365     myExtractedTree->addTopLevelItem(myTopItems[i]);
366     myTopItems[i]->setHidden(true);
367   }
368
369   // signals and slots connections
370   connect(mySelBtn,         SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument()));
371   connect(buttonOk(),       SIGNAL(clicked()), this, SLOT(ClickOnOk()));
372   connect(buttonApply(),    SIGNAL(clicked()), this, SLOT(ClickOnApply()));
373   connect(mySubShTypeCompo, SIGNAL(currentIndexChanged(int)),
374           this,             SLOT(onShapeTypeChanged()));
375   connect(myRebuildBtn,     SIGNAL(clicked()), this, SLOT(onRebuild()));
376   connect(myGeomGUI->getApp()->selectionMgr(), SIGNAL(currentSelectionChanged()),
377           this, SLOT(SelectionIntoArgument()));
378   connect(myFilteredList,   SIGNAL(itemSelectionChanged()),
379           this,             SLOT(onListSelectionChanged()));
380   connect(myExtractedTree,  SIGNAL(itemSelectionChanged()),
381           this,             SLOT(onListSelectionChanged()));
382
383   initName(tr("GEOM_EXTRACT_NAME"));
384
385   activateSelection();
386   SelectionIntoArgument();
387 }
388
389 //=================================================================================
390 // function : updateSubShTypeCompo()
391 // purpose  :
392 //=================================================================================
393 bool OperationGUI_ExtractionDlg::updateSubShTypeCompo()
394 {
395   bool         isValid  = true;
396   int          anIStart = TopAbs_COMPOUND;
397   const int    anIEnd   = TopAbs_VERTEX;
398   TopoDS_Shape aShape;
399
400   if (GEOMBase::GetShape(myObj, aShape)) {
401     const TopAbs_ShapeEnum aType = aShape.ShapeType();
402
403     if (aType == TopAbs_COMPOUND) {
404       anIStart = GetMaxShapeTypeInComp(aShape);
405       isValid  = anIStart != TopAbs_SHAPE;
406     } else {
407       anIStart = aType + 1;
408     }
409   }
410
411   QSignalBlocker aBlocker(mySubShTypeCompo);
412   mySubShTypeCompo->clear();
413
414   if (isValid) {
415     int i;
416
417     for (i = anIStart; i <= anIEnd; i++) {
418       mySubShTypeCompo->addItem(tr(SINGLE_SHAPE_TYPE_TR_CODES[i]), i);
419     }
420
421     updateFilteredList();
422   }
423
424   return isValid;
425 }
426
427 //=================================================================================
428 // function : updateFilteredList()
429 // purpose  :
430 //=================================================================================
431 void OperationGUI_ExtractionDlg::updateFilteredList()
432 {
433   TopoDS_Shape   aShape;
434   QSignalBlocker aBlocker(myFilteredList);
435
436   myFilteredList->clear();
437
438   if (GEOMBase::GetShape(myObj, aShape)) {
439     const TopAbs_ShapeEnum aType = (TopAbs_ShapeEnum)
440       mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt();
441     TopExp_Explorer        anExp(aShape, aType);
442
443     if (anExp.More()) {
444       TopTools_MapOfShape aMapFence;
445
446       for (; anExp.More(); anExp.Next()) {
447         const TopoDS_Shape &aSubShape = anExp.Current();
448
449         if (!aSubShape.IsNull() && aMapFence.Add(aSubShape)) {
450           int anIndex = myIndices.FindIndex(aSubShape);
451
452           if (!myMapExtractedIDs.Contains(anIndex)) {
453             addNewItem(anIndex, myFilteredList);
454           }
455         }
456       }
457     }
458   }
459 }
460
461 //=================================================================================
462 // function : resetBuildData()
463 // purpose  :
464 //=================================================================================
465 void OperationGUI_ExtractionDlg::resetBuildData(const bool isEnableBuild)
466 {
467   // Clear result data.
468   myRemovedList->clear();
469   myModifiedList->clear();
470   myAddedList->clear();
471   myRebuildBtn->setEnabled(isEnableBuild);
472 }
473
474 //=================================================================================
475 // function : isEmptyExtracted()
476 // purpose  :
477 //=================================================================================
478 bool OperationGUI_ExtractionDlg::isEmptyExtracted()
479 {
480   bool isEmpty = true;
481   int  i;
482
483   // Check if there are sub-shapes to be extracted.
484   for (i = 1; i < 8; i++) {
485     if (!myTopItems[i]->isHidden()) {
486       isEmpty = false;
487
488       break;
489     }
490   }
491
492   return isEmpty;
493 }
494
495 //=================================================================================
496 // function : selectMainShape
497 // purpose  :
498 //=================================================================================
499 void OperationGUI_ExtractionDlg::selectMainShape()
500 {
501   LightApp_SelectionMgr *aSelMgr = myGeomGUI->getApp()->selectionMgr();
502   SALOME_ListIO          aSelList;
503
504   aSelMgr->selectedObjects(aSelList);
505
506   if (aSelList.Extent() == 1) {
507     GEOM::GEOM_Object_var aSelObject =
508       GEOMBase::ConvertIOinGEOMObject(aSelList.First());
509     TopoDS_Shape          aSelShape;
510
511     if (GEOMBase::GetShape(aSelObject, aSelShape)) {
512       const TopAbs_ShapeEnum aType = aSelShape.ShapeType();
513
514       // Skip verices.
515       if (aType != TopAbs_VERTEX) {
516         myObj = aSelObject;
517
518         // Initialize map of indices. Note that myIndices should be empty.
519         TopExp::MapShapes(aSelShape, myIndices);
520       }
521     }
522   }
523
524   if (!updateSubShTypeCompo()) {
525     // Invalid selected object.
526     myObj = GEOM::GEOM_Object::_nil();
527   }
528
529   if (!CORBA::is_nil(myObj)) {
530     mySelBtn->setChecked(false);
531     myMainShapeEdit->setEnabled(false);
532     myMainShapeEdit->setText(GEOMBase::GetName(myObj));
533
534     // Hide the main object from the viewer.
535     SALOME_View* aView = GEOM_Displayer::GetActiveView();
536
537     if (aView) {
538       CORBA::String_var                aMainEntry = myObj->GetStudyEntry();
539       Handle(SALOME_InteractiveObject) anIO       = createIO(aMainEntry.in());
540
541       if (aView->isVisible(anIO)) {
542         GEOM_Displayer *aDisplayer = getDisplayer();
543
544         aDisplayer->Erase(myObj, false, true);
545         myIsHiddenMain = true;
546       }
547     }
548   }
549 }
550
551 //=================================================================================
552 // function : selectSubShapes
553 // purpose  :
554 //=================================================================================
555 void OperationGUI_ExtractionDlg::selectSubShapes()
556 {
557   QSignalBlocker aBlocker(myFilteredList);
558
559   // Clear current selection.
560   myFilteredList->clearSelection();
561
562   LightApp_SelectionMgr *aSelMgr  = myGeomGUI->getApp()->selectionMgr();
563   SALOME_ListIO          aSelList;
564   const int              aCurType =
565       mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt();
566
567   aSelMgr->selectedObjects(aSelList);
568
569   // try to find out and process the global selection
570   // (of not published objects and of published sub-shapes)
571   SALOME_ListIteratorOfListIO anIter(aSelList);
572
573   for (; anIter.More(); anIter.Next()) {
574     Handle(SALOME_InteractiveObject) anIObj      = anIter.Value();
575     QString                          anEntry     = anIObj->getEntry();
576     QStringList                      aParts      = anEntry.split("_");
577     int                              aSubShapeId = -1;
578
579     if (!aParts.isEmpty()) {
580       if (aParts.first() == TMP_STR) {
581         bool      isOk    = false;
582         const int anIndex = aParts.last().toInt(&isOk);
583
584         if (isOk && anIndex > 0) {
585           // This is a sub-shape.
586           aSubShapeId = anIndex;
587         }
588       }
589     }
590
591     if (aSubShapeId < 0) {
592       // This is a published shape.
593       GEOM::GEOM_Object_var aSelObject =
594                     GEOMBase::ConvertIOinGEOMObject(anIObj);
595       TopoDS_Shape          aSelShape;
596
597       if (GEOMBase::GetShape(aSelObject, aSelShape)) {
598
599         if (aSelShape.ShapeType() == aCurType) {
600           const int anIndex = myIndices.FindIndex(aSelShape);
601
602           if (anIndex > 0) {
603             // This is a sub-shape. Select it in the filtered list.
604             aSubShapeId = anIndex;
605           }
606         }
607       }
608     }
609
610     // Select a list widget item by Id.
611     if (aSubShapeId > 0) {
612       QString                  anIdText = QString("%1").arg(aSubShapeId);
613       QList<QListWidgetItem *> aFound   =
614                     myFilteredList->findItems(anIdText, Qt::MatchExactly);
615
616       foreach (QListWidgetItem *anItem, aFound) {
617         anItem->setSelected(true);
618       }
619     }
620   }
621 }
622
623 //=================================================================================
624 // function : ClickOnOk()
625 // purpose  :
626 //=================================================================================
627 void OperationGUI_ExtractionDlg::ClickOnOk()
628 {
629   if (ClickOnApply()) {
630     ClickOnCancel();
631   }
632 }
633
634 //=================================================================================
635 // function : ClickOnApply()
636 // purpose  :
637 //=================================================================================
638 bool OperationGUI_ExtractionDlg::ClickOnApply()
639 {
640   if (!onAccept()) {
641     return false;
642   }
643
644   initName();
645
646   return true;
647 }
648
649 //=================================================================================
650 // function : onShapeTypeChanged
651 // purpose  :
652 //=================================================================================
653 void OperationGUI_ExtractionDlg::onShapeTypeChanged()
654 {
655   updateFilteredList();
656   eraseAll();
657 }
658
659 //=================================================================================
660 // function : onAddExtracted
661 // purpose  :
662 //=================================================================================
663 void OperationGUI_ExtractionDlg::onAddExtracted()
664 {
665   QList<QListWidgetItem *> aListSelected = myFilteredList->selectedItems();
666
667   if (aListSelected.empty()) {
668     return;
669   }
670
671   const int aShapeType =
672       mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt();
673   bool  isTreeUpdated  = false;
674
675   foreach (QListWidgetItem *anItem, aListSelected) {
676     const int anIndex = anItem->data(ID_ROLE).toInt();
677
678     if (myMapExtractedIDs.Add(anIndex)) {
679       addChildItem(anIndex, myTopItems[aShapeType]);
680       isTreeUpdated = true;
681     }
682
683     // Remove anItem from the list.
684     myFilteredList->removeItemWidget(anItem);
685     delete anItem;
686   }
687
688   if (isTreeUpdated) {
689     myTopItems[aShapeType]->sortChildren(0, Qt::AscendingOrder);
690
691     // Reset build data
692     resetBuildData(true);
693   }
694
695   myFilteredList->clearSelection();
696   myTopItems[aShapeType]->setHidden(false);
697 }
698
699 //=================================================================================
700 // function : onRemoveExtracted
701 // purpose  :
702 //=================================================================================
703 void OperationGUI_ExtractionDlg::onRemoveExtracted()
704 {
705   QList<QTreeWidgetItem *> aListSelected = myExtractedTree->selectedItems();
706
707   if (aListSelected.empty()) {
708     return;
709   }
710
711   const int               aShapeType =
712       mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt();
713   QSet<QTreeWidgetItem *> aSetFence;
714   bool                    isTreeUpdated = false;
715
716   foreach (QTreeWidgetItem *anItem, aListSelected) {
717     if (!aSetFence.contains(anItem)) {
718       aSetFence.insert(anItem);
719
720       QTreeWidgetItem *aParent = anItem->parent();
721
722       if (aParent) {
723         const int anIndex = anItem->data(0, ID_ROLE).toInt();
724         // This is a ID item. Remove the ID from myMapExtractedIDs.
725         if (myMapExtractedIDs.Remove(anIndex)) {
726           // The item is not removed yet. Get parent index.
727           const int aParentIndex = aParent->data(0, TYPE_ROLE).toInt();
728
729           if (aShapeType == aParentIndex) {
730             // Create an item in the filtered list.
731             addNewItem(anIndex, myFilteredList);
732           }
733
734           aParent->removeChild(anItem);
735           delete anItem;
736           isTreeUpdated = true;
737
738           // Hilde an empty parent item.
739           if (aParent->childCount() == 0) {
740             aParent->setHidden(true);
741           }
742         }
743       } else {
744         // This is a top level item. Remove all its children.
745         QList<QTreeWidgetItem *> aChildItems = anItem->takeChildren();
746         const int                anIndex     = anItem->data(0, TYPE_ROLE).toInt();
747
748         // Remove IDs from myMapExtractedIDs.
749         foreach (QTreeWidgetItem *aChild, aChildItems) {
750           if (!aSetFence.contains(aChild)) {
751             aSetFence.insert(aChild);
752
753             const int aChildIndex = aChild->data(0, ID_ROLE).toInt();
754
755             if (myMapExtractedIDs.Remove(aChildIndex)) {
756               if (aShapeType == anIndex) {
757                 // Create items in the filtered list.
758                 addNewItem(aChildIndex, myFilteredList);
759               }
760
761               delete aChild;
762               isTreeUpdated = true;
763             }
764           }
765         }
766
767         // Hilde an empty item.
768         anItem->setHidden(true);
769       }
770     }
771   }
772
773   myExtractedTree->clearSelection();
774
775   if (isTreeUpdated) {
776     // Reset build data
777     const bool isEnableRebuild = !isEmptyExtracted();
778
779     resetBuildData(isEnableRebuild);
780   }
781 }
782
783 //=================================================================================
784 // function : onListSelectionChanged
785 // purpose  :
786 //=================================================================================
787 void OperationGUI_ExtractionDlg::onListSelectionChanged()
788 {
789   SALOME_ListIO            anIOList;
790   QList<QListWidgetItem *> aListSel = myFilteredList->selectedItems();
791   QList<QTreeWidgetItem *> aTreeSel = myExtractedTree->selectedItems();
792
793   // Collect selected items from myFilteredList
794   foreach (QListWidgetItem *anItem, aListSel) {
795     const int anIndex = anItem->data(ID_ROLE).toInt();
796
797     if (myMapDisplayedIDs.Contains(anIndex)) {
798       // Collect only displayed sub-shapes for selection in the viewer.
799       QString                          anEntry = getSubShapeEntry(anIndex);
800       Handle(SALOME_InteractiveObject) anIO    =
801                                       createIO(anEntry.toLatin1().data());
802
803       anIOList.Append(anIO);
804     }
805   }
806
807   // Collect selected items from myExtractedTree
808   foreach (QTreeWidgetItem *anItem, aTreeSel) {
809     if (anItem->parent()) {
810       // This is a ID item.
811       const int anIndex = anItem->data(0, ID_ROLE).toInt();
812
813       if (myMapDisplayedIDs.Contains(anIndex)) {
814         // Collect only displayed sub-shapes for selection in the viewer.
815         QString                          anEntry = getSubShapeEntry(anIndex);
816         Handle(SALOME_InteractiveObject) anIO    =
817                                     createIO(anEntry.toLatin1().data());
818
819         anIOList.Append(anIO);
820       }
821     }
822   }
823
824   // Select object in viewer.
825   LightApp_SelectionMgr *aSelMgr = myGeomGUI->getApp()->selectionMgr();
826
827   aSelMgr->setSelectedObjects(anIOList);
828 }
829
830 //=================================================================================
831 // function : showOnlySelected
832 // purpose  :
833 //=================================================================================
834 void OperationGUI_ExtractionDlg::showOnlySelected()
835 {
836   TColStd_MapOfInteger aMapIDsSelected;
837   TColStd_MapOfInteger aMapIDsToDisplay;
838   const int            aNbItems = myFilteredList->count();
839   int                  i;
840   QSet<QString>        aSelEntry;
841
842   // Get sub-shape IDs to be displayed.
843   for (i = 0; i < aNbItems; ++i) {
844     QListWidgetItem *anItem = myFilteredList->item(i);
845     const int       anIndex = anItem->data(ID_ROLE).toInt();
846
847     if (anItem->isSelected()) {
848       aMapIDsSelected.Add(anIndex);
849       aSelEntry.insert(getSubShapeEntry(anIndex));
850
851       if (!myMapDisplayedIDs.Contains(anIndex)) {
852         aMapIDsToDisplay.Add(anIndex);
853       }
854     }
855   }
856
857   // Get sub-shape IDs to be erased.
858   TColStd_MapOfInteger              aMapIDsToHide;
859   TColStd_MapIteratorOfMapOfInteger anIter(myMapDisplayedIDs);
860
861   for (; anIter.More(); anIter.Next()) {
862     const int anIndex = anIter.Key();
863
864     if (!aMapIDsSelected.Contains(anIndex)) {
865       aMapIDsToHide.Add(anIndex);
866     }
867   }
868
869   // Display sub-shapes.
870   for (anIter.Initialize(aMapIDsToDisplay); anIter.More(); anIter.Next()) {
871     displaySubShape(anIter.Key());
872   }
873
874   // Hide sub-shapes.
875   for (anIter.Initialize(aMapIDsToHide); anIter.More(); anIter.Next()) {
876     eraseSubShape(anIter.Key());
877   }
878
879   // Hide all objects except already displayed sub-shapes.
880   SALOME_ListIO  aDisplayed;
881   SALOME_View   *aView = GEOM_Displayer::GetActiveView();
882
883   if (aView) {
884     aView->GetVisible(aDisplayed);
885   }
886
887   SALOME_ListIteratorOfListIO  aDispIt(aDisplayed);
888   GEOM_Displayer              *aDisplayer = getDisplayer();
889
890   for (; aDispIt.More(); aDispIt.Next()) {
891     Handle(SALOME_InteractiveObject) anIO = aDispIt.Value();
892
893     if (!aSelEntry.contains(anIO->getEntry())) {
894       aDisplayer->Erase(anIO, false, false);
895     }
896   }
897
898   onListSelectionChanged();
899   aDisplayer->UpdateViewer();
900 }
901
902 //=================================================================================
903 // function : hideSelected
904 // purpose  :
905 //=================================================================================
906 void OperationGUI_ExtractionDlg::hideSelected()
907 {
908   QList<QListWidgetItem *> aListSelected = myFilteredList->selectedItems();
909
910   foreach (QListWidgetItem *anItem, aListSelected) {
911     const int anIndex = anItem->data(ID_ROLE).toInt();
912
913     eraseSubShape(anIndex);
914   }
915
916   getDisplayer()->UpdateViewer();
917 }
918
919 //=================================================================================
920 // function : showAllSelected
921 // purpose  :
922 //=================================================================================
923 void OperationGUI_ExtractionDlg::showAllSelected()
924 {
925   const int aNbItems = myFilteredList->count();
926   int       i;
927
928   for (i = 0; i < aNbItems; ++i) {
929     QListWidgetItem *anItem = myFilteredList->item(i);
930     const int anIndex = anItem->data(ID_ROLE).toInt();
931
932     displaySubShape(anIndex);
933   }
934
935   onListSelectionChanged();
936   getDisplayer()->UpdateViewer();
937 }
938
939 //=================================================================================
940 // function : onRebuild
941 // purpose  :
942 //=================================================================================
943 void OperationGUI_ExtractionDlg::onRebuild()
944 {
945   GEOM::GEOM_Object_var                         aResShape;
946   GEOM::GEOM_IShapesOperations::ExtractionStats aStats;
947
948   if (!getResult(aResShape.out(), aStats)) {
949     resetBuildData(false);
950     return;
951   }
952
953   TopoDS_Shape               anOldShape;
954   TopoDS_Shape               aNewShape;
955   TopTools_IndexedMapOfShape aNewIndices;
956
957   if (!GEOMBase::GetShape(aResShape, aNewShape)) {
958     resetBuildData(false);
959     return;
960   }
961
962   TopExp::MapShapes(aNewShape, aNewIndices);
963
964   const int aNbStat = aStats.length();
965   int       i;
966
967   for (i = 0; i < aNbStat; ++i) {
968     // Compute number of sub-shapes of each type.
969     const int aNbSubShapes = aStats[i].indices.length();
970     int       aNbShapes [] = { 0, 0, 0, 0, 0, 0, 0, 0 };
971     int       j;
972
973     TopTools_IndexedMapOfShape *aMapShapes =
974       (aStats[i].type == GEOM::GEOM_IShapesOperations::EST_Added) ?
975             &aNewIndices : &myIndices;
976
977     for (j = 0; j < aNbSubShapes; ++j) {
978       const int anIndex = aStats[i].indices[j];
979
980       if (anIndex < 1 || anIndex > aMapShapes->Extent()) {
981         resetBuildData(false);
982         return;
983       }
984
985       const TopoDS_Shape &aSubShape = aMapShapes->FindKey(anIndex);
986
987       aNbShapes[aSubShape.ShapeType()]++;
988     }
989
990     // Fill the statistics.
991     QListWidget *aListWidget = 0;
992
993     switch (aStats[i].type) {
994       case GEOM::GEOM_IShapesOperations::EST_Removed:
995         aListWidget = myRemovedList;
996         break;
997       case GEOM::GEOM_IShapesOperations::EST_Modified:
998         aListWidget = myModifiedList;
999         break;
1000       case GEOM::GEOM_IShapesOperations::EST_Added:
1001         aListWidget = myAddedList;
1002         break;
1003       default:
1004         resetBuildData(false);
1005         return;
1006     }
1007
1008     QStringList aStrList;
1009
1010     for (j = 0; j < 8; ++j) {
1011       if (aNbShapes[j] >= 1) {
1012         const char *aShapeType = aNbShapes[j] == 1 ?
1013           SINGLE_SHAPE_TYPE_TR_CODES[j] : PLURAL_SHAPE_TYPE_TR_CODES[j];
1014
1015         aStrList.append(QString("%1 %2").arg(aNbShapes[j]).arg(tr(aShapeType)));
1016       }
1017     }
1018
1019     aListWidget->addItems(aStrList);
1020   }
1021
1022   myRebuildBtn->setEnabled(false);
1023 }
1024
1025 //=================================================================================
1026 // function : SelectionIntoArgument
1027 // purpose  :
1028 //=================================================================================
1029 void OperationGUI_ExtractionDlg::SelectionIntoArgument()
1030 {
1031   if (myMainShapeEdit->isEnabled()) {
1032     // Selection of main object
1033     selectMainShape();
1034   } else {
1035     // Selection of filtered shapes
1036     selectSubShapes();
1037   }
1038 }
1039
1040 //=================================================================================
1041 // function : SetEditCurrentArgument
1042 // purpose  :
1043 //=================================================================================
1044 void OperationGUI_ExtractionDlg::SetEditCurrentArgument()
1045 {
1046   QSignalBlocker aBlockerList(myFilteredList);
1047   QSignalBlocker aBlockerTree(myExtractedTree);
1048
1049   restoreViewer();
1050   myObj = GEOM::GEOM_Object::_nil();
1051   myMainShapeEdit->setEnabled(true);
1052   myMainShapeEdit->setText("");
1053   myMainShapeEdit->setFocus();
1054
1055   updateSubShTypeCompo();
1056
1057   myFilteredList->clear();
1058   myRemovedList->clear();
1059   myModifiedList->clear();
1060   myAddedList->clear();
1061   myIndices.Clear();
1062
1063   // Clear myExtractedTree.
1064   int i;
1065
1066   for (i = 1; i < 8; i++) {
1067     QList<QTreeWidgetItem *> aListItems = myTopItems[i]->takeChildren();
1068
1069     foreach (QTreeWidgetItem *anItem, aListItems) {
1070       delete anItem;
1071     }
1072
1073     myTopItems[i]->setHidden(true);
1074   }
1075
1076   myExtractedTree->clearSelection();
1077
1078   myMapExtractedIDs.Clear();
1079
1080   // Update viewer
1081   eraseAll();
1082 }
1083
1084 //=================================================================================
1085 // function : ActivateThisDialog()
1086 // purpose  :
1087 //=================================================================================
1088 void OperationGUI_ExtractionDlg::ActivateThisDialog()
1089 {
1090   GEOMBase_Skeleton::ActivateThisDialog();
1091
1092   LightApp_SelectionMgr* aSel = myGeomGUI->getApp()->selectionMgr();
1093
1094   if (aSel) {
1095     connect(aSel, SIGNAL(currentSelectionChanged()),
1096             this, SLOT(SelectionIntoArgument()));
1097   }
1098
1099   activateSelection();
1100 }
1101
1102 //=================================================================================
1103 // function : activateSelection
1104 // purpose  : activate selection of all shapes
1105 //=================================================================================
1106 void OperationGUI_ExtractionDlg::activateSelection()
1107 {
1108   globalSelection(GEOM_ALLSHAPES);
1109 }
1110
1111 //=================================================================================
1112 // function : enterEvent()
1113 // purpose  :
1114 //=================================================================================
1115 void OperationGUI_ExtractionDlg::enterEvent(QEvent *)
1116 {
1117   if (!mainFrame()->GroupConstructors->isEnabled()) {
1118     ActivateThisDialog();
1119   }
1120 }
1121
1122 //=================================================================================
1123 // function : getResult
1124 // purpose  :
1125 //=================================================================================
1126 bool OperationGUI_ExtractionDlg::getResult
1127              (GEOM::GEOM_Object_ptr                         &theResult,
1128               GEOM::GEOM_IShapesOperations::ExtractionStats &theStats)
1129 {
1130   if (myObj->_is_nil()) {
1131     return false;
1132   }
1133
1134   // Get IDs of extracted shapes.
1135   int i;
1136   int aNbShapes = 0;
1137
1138   for (i = 1; i < 8; i++) {
1139     aNbShapes += myTopItems[i]->childCount();
1140   }
1141
1142   if (aNbShapes == 0) {
1143     return false;
1144   }
1145
1146   GEOM::ListOfLong_var aSubShapeIDs = new GEOM::ListOfLong;
1147   int                  j;
1148   int                  jCur;
1149
1150   aSubShapeIDs->length(aNbShapes);
1151
1152   for (jCur = 0, i = 1; i < 8; ++i) {
1153     aNbShapes = myTopItems[i]->childCount();
1154     
1155     for (j = 0; j < aNbShapes; ++j, ++jCur) {
1156       aSubShapeIDs[jCur] = myTopItems[i]->child(j)->data(0, ID_ROLE).toInt();
1157     }
1158   }
1159
1160   GEOM::GEOM_IShapesOperations_var anOper =
1161     GEOM::GEOM_IShapesOperations::_narrow(getOperation());
1162
1163   try {
1164     GEOM::GEOM_Object_var                             anObj;
1165     GEOM::GEOM_IShapesOperations::ExtractionStats_var aStats;
1166
1167     anObj = anOper->MakeExtraction(myObj, aSubShapeIDs, aStats);
1168
1169     if (anOper->IsDone() && aStats->length() > 0) {
1170       theStats = aStats;
1171     }
1172
1173     if (!CORBA::is_nil(anObj)) {
1174       theResult = anObj._retn();
1175     }
1176   }
1177   catch (const SALOME::SALOME_Exception& e) {
1178     SalomeApp_Tools::QtCatchCorbaException(e);
1179     return false;
1180   }
1181
1182   return anOper->IsDone();
1183 }
1184
1185 //=================================================================================
1186 // function : isValid
1187 // purpose  :
1188 //=================================================================================
1189 bool OperationGUI_ExtractionDlg::isValid(QString &)
1190 {
1191   bool isOk = !myObj->_is_nil() && !isEmptyExtracted();
1192
1193   return isOk;
1194 }
1195
1196 //=================================================================================
1197 // function : createOperation
1198 // purpose  :
1199 //=================================================================================
1200 GEOM::GEOM_IOperations_ptr OperationGUI_ExtractionDlg::createOperation()
1201 {
1202   return getGeomEngine()->GetIShapesOperations(getStudyId());
1203 }
1204
1205 //=================================================================================
1206 // function : execute
1207 // purpose  :
1208 //=================================================================================
1209 bool OperationGUI_ExtractionDlg::execute(ObjectList &objects)
1210 {
1211   GEOM::GEOM_Object_var                         aResShape;
1212   GEOM::GEOM_IShapesOperations::ExtractionStats aStats;
1213
1214   if (!getResult(aResShape.out(), aStats)) {
1215     return false;
1216   }
1217
1218   if (!aResShape->_is_nil()) {
1219     objects.push_back(aResShape._retn());
1220   }
1221
1222   return true;
1223 }
1224
1225 //=================================================================================
1226 // function : getSubShapeEntry
1227 // purpose  :
1228 //=================================================================================
1229 QString OperationGUI_ExtractionDlg::getSubShapeEntry(const int theId)
1230 {
1231   CORBA::String_var aMainEntry = myObj->GetStudyEntry();
1232   QString           anEntry    = QString("%1_").arg(TMP_STR) +
1233                                  aMainEntry.in() + QString("_%1").arg(theId);
1234
1235   return anEntry;
1236 }
1237
1238 //=================================================================================
1239 // function : createIO
1240 // purpose  :
1241 //=================================================================================
1242 Handle_SALOME_InteractiveObject OperationGUI_ExtractionDlg::createIO
1243                                                       (const char *theEntry)
1244 {
1245   Handle(SALOME_InteractiveObject) anIO = new SALOME_InteractiveObject
1246                               (theEntry, "GEOM", "TEMP_IO");
1247
1248   return anIO;
1249 }
1250
1251 //=================================================================================
1252 // function : displaySubShape
1253 // purpose  :
1254 //=================================================================================
1255 void OperationGUI_ExtractionDlg::displaySubShape(const int theId)
1256 {
1257   if (theId < 1 || theId > myIndices.Extent()) {
1258     return;
1259   }
1260
1261   // Create a presentation
1262   const TopoDS_Shape &aSubShape  = myIndices.FindKey(theId);
1263   QString             anEntry    = getSubShapeEntry(theId);
1264   SALOME_View        *aView      = GEOM_Displayer::GetActiveView();
1265   GEOM_Displayer     *aDisplayer = getDisplayer();
1266   SALOME_Prs         *aPrs       = aDisplayer->buildSubshapePresentation
1267                                   (aSubShape, anEntry, aView);
1268
1269   if (aPrs) {
1270     if (aView) {
1271       aView->Display(aDisplayer, aPrs);
1272     }
1273
1274     delete aPrs;
1275
1276     myMapDisplayedIDs.Add(theId);
1277   }
1278 }
1279
1280 //=================================================================================
1281 // function : eraseSubShape
1282 // purpose  :
1283 //=================================================================================
1284 void OperationGUI_ExtractionDlg::eraseSubShape(const int theId)
1285 {
1286   QString                          anEntry = getSubShapeEntry(theId);
1287   Handle(SALOME_InteractiveObject) anIO    =
1288                                       createIO(anEntry.toLatin1().data());
1289
1290   getDisplayer()->Erase(anIO, false, false);
1291   myMapDisplayedIDs.Remove(theId);
1292 }
1293
1294 //=================================================================================
1295 // function : eraseAll
1296 // purpose  :
1297 //=================================================================================
1298 void OperationGUI_ExtractionDlg::eraseAll()
1299 {
1300   TColStd_MapIteratorOfMapOfInteger anIter(myMapDisplayedIDs);
1301   TColStd_ListOfInteger             aDisplayedIDs;
1302
1303   for (; anIter.More(); anIter.Next()) {
1304     aDisplayedIDs.Append(anIter.Key());
1305   }
1306
1307   TColStd_ListIteratorOfListOfInteger aListIter(aDisplayedIDs);
1308
1309   for (; aListIter.More(); aListIter.Next()) {
1310     eraseSubShape(aListIter.Value());
1311   }
1312
1313   getDisplayer()->UpdateViewer();
1314 }
1315
1316 //=================================================================================
1317 // function : restoreViewer
1318 // purpose  :
1319 //=================================================================================
1320 void OperationGUI_ExtractionDlg::restoreViewer()
1321 {
1322   if (!CORBA::is_nil(myObj)) {
1323     if (myIsHiddenMain) {
1324       getDisplayer()->Display(myObj, false);
1325       myIsHiddenMain = false;
1326     }
1327
1328     eraseAll();
1329   }
1330 }