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