Salome HOME
Bugs 16640, 19050: Improve selection mechanism in GEOM dialog boxes.
[modules/geom.git] / src / BlocksGUI / BlocksGUI_QuadFaceDlg.cxx
1 // GEOM GEOMGUI : GUI for Geometry component
2 //
3 // Copyright (C) 2003  CEA
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 //
19 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 //
21 // File   : BlocksGUI_QuadFaceDlg.cxx
22 // Author : Julia DOROVSKIKH, Open CASCADE S.A.S. (julia.dorovskikh@opencascade.com)
23 //
24
25 #include "BlocksGUI_QuadFaceDlg.h"
26
27 #include <DlgRef.h>
28 #include <GeometryGUI.h>
29 #include <GEOMBase.h>
30
31 #include <SUIT_Session.h>
32 #include <SUIT_ResourceMgr.h>
33 #include <SalomeApp_Application.h>
34 #include <LightApp_SelectionMgr.h>
35
36 // QT Includes
37 #include <qlabel.h>
38
39 // OCCT Includes
40 #include <TopAbs.hxx>
41 #include <TColStd_IndexedMapOfInteger.hxx>
42
43 #include <GEOMImpl_Types.hxx>
44
45 //=================================================================================
46 // class    : BlocksGUI_QuadFaceDlg()
47 // purpose  : Constructs a BlocksGUI_QuadFaceDlg which is a child of 'parent'.
48 //=================================================================================
49 BlocksGUI_QuadFaceDlg::BlocksGUI_QuadFaceDlg (GeometryGUI* theGeometryGUI, QWidget* parent)
50   : GEOMBase_Skeleton(theGeometryGUI, parent),
51     myInitial(true)
52 {
53   SUIT_ResourceMgr* aResMgr = myGeomGUI->getApp()->resourceMgr();
54   QPixmap image1 (aResMgr->loadPixmap("GEOM", tr("ICON_DLG_QUAD_FACE_4_VERT")));
55   QPixmap image2 (aResMgr->loadPixmap("GEOM", tr("ICON_DLG_QUAD_FACE_2_EDGE")));
56   QPixmap image3 (aResMgr->loadPixmap("GEOM", tr("ICON_DLG_QUAD_FACE_4_EDGE")));
57   QPixmap imageS (aResMgr->loadPixmap("GEOM", tr("ICON_SELECT")));
58
59   setWindowTitle(tr("GEOM_QUAD_FACE_TITLE"));
60
61   /***************************************************************/
62   mainFrame()->GroupConstructors->setTitle(tr("GEOM_QUAD_FACE"));
63
64   mainFrame()->RadioButton1->setIcon(image1);
65   mainFrame()->RadioButton2->setIcon(image2);
66   mainFrame()->RadioButton3->setIcon(image3);
67
68   // Create first group
69   myGrp1 = new QGroupBox(tr("GEOM_ARGUMENTS"), centralWidget());
70
71   createSelWg(tr("VERTEX_1"), imageS, myGrp1, Vertex1);
72   createSelWg(tr("VERTEX_2"), imageS, myGrp1, Vertex2);
73   createSelWg(tr("VERTEX_3"), imageS, myGrp1, Vertex3);
74   createSelWg(tr("VERTEX_4"), imageS, myGrp1, Vertex4);
75
76   // Create second group
77   myGrp2 = new QGroupBox(tr("GEOM_ARGUMENTS"), centralWidget());
78
79   createSelWg(tr("EDGE_1"), imageS, myGrp2, Edge12);
80   createSelWg(tr("EDGE_2"), imageS, myGrp2, Edge22);
81
82   // Create fird group
83   myGrp3 = new QGroupBox(tr("GEOM_ARGUMENTS"), centralWidget());
84
85   createSelWg(tr("EDGE_1"), imageS, myGrp3, Edge14);
86   createSelWg(tr("EDGE_2"), imageS, myGrp3, Edge24);
87   createSelWg(tr("EDGE_3"), imageS, myGrp3, Edge34);
88   createSelWg(tr("EDGE_4"), imageS, myGrp3, Edge44);
89
90   // Add groups to layout
91   QVBoxLayout* layout = new QVBoxLayout(centralWidget());
92   layout->setMargin(0); layout->setSpacing(6);
93   layout->addWidget(myGrp1);
94   layout->addWidget(myGrp2);
95   layout->addWidget(myGrp3);
96   /***************************************************************/
97
98   setHelpFileName("build_by_blocks_page.html#quad_face_anchor");
99
100   Init();
101 }
102
103 //=================================================================================
104 // function : ~BlocksGUI_QuadFaceDlg()
105 // purpose  : Destroys the object and frees any allocated resources
106 //=================================================================================
107 BlocksGUI_QuadFaceDlg::~BlocksGUI_QuadFaceDlg()
108 {
109   // no need to delete child widgets, Qt does it all for us
110 }
111
112 //=================================================================================
113 // function : Init()
114 // purpose  :
115 //=================================================================================
116 void BlocksGUI_QuadFaceDlg::Init()
117 {
118   // signals and slots connections
119   connect(buttonOk(),    SIGNAL(clicked()), this, SLOT(ClickOnOk()));
120   connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply()));
121
122   connect(this, SIGNAL(constructorsClicked(int)), this, SLOT(ConstructorsClicked(int)));
123
124   QMap<int, QPushButton*>::iterator anIterBtn;
125   for (anIterBtn = mySelBtn.begin(); anIterBtn != mySelBtn.end(); ++anIterBtn)
126     connect(anIterBtn.value(), SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument()));
127
128   // init controls and fields
129   initName(tr("GEOM_QUAD_FACE"));
130
131   myConstructorId = -1;
132   ConstructorsClicked(0);
133 }
134
135 //=================================================================================
136 // function : ConstructorsClicked()
137 // purpose  : Radio button management
138 //=================================================================================
139 void BlocksGUI_QuadFaceDlg::ConstructorsClicked (int constructorId)
140 {
141   if (myConstructorId == constructorId)
142     return;
143
144   myConstructorId = constructorId;
145
146   // init fields
147   myShape1 = myShape2 = GEOM::GEOM_Object::_nil();
148   myShape3 = myShape4 = myShape1;
149
150   // clear line edits
151   QMap<int, QLineEdit*>::iterator anIterLE;
152   for (anIterLE = mySelName.begin(); anIterLE != mySelName.end(); ++anIterLE)
153     anIterLE.value()->setText("");
154
155   switch (constructorId) {
156   case 0:
157     myGrp2->hide();
158     myGrp3->hide();
159     myGrp1->show();
160     mySelBtn[Vertex1]->click();
161     break;
162   case 1:
163     myGrp1->hide();
164     myGrp3->hide();
165     myGrp2->show();
166     mySelBtn[Edge12]->click();
167     break;
168   case 2:
169     myGrp1->hide();
170     myGrp2->hide();
171     myGrp3->show();
172     mySelBtn[Edge14]->click();
173     break;
174   default:
175     break;
176   }
177
178   qApp->processEvents();
179   updateGeometry();
180   resize(minimumSize());
181
182   // on dialog initialization we init the first field with a selected object (if any)
183   SelectionIntoArgument();
184 }
185
186 //=================================================================================
187 // function : ClickOnOk()
188 // purpose  :
189 //=================================================================================
190 void BlocksGUI_QuadFaceDlg::ClickOnOk()
191 {
192   if (ClickOnApply())
193     ClickOnCancel();
194 }
195
196 //=================================================================================
197 // function : ClickOnApply()
198 // purpose  :
199 //=================================================================================
200 bool BlocksGUI_QuadFaceDlg::ClickOnApply()
201 {
202   if (!onAccept())
203     return false;
204
205   initName();
206   return true;
207 }
208
209 //=================================================================================
210 // function : SelectionIntoArgument()
211 // purpose  : Called when selection is changed or on dialog initialization or activation
212 //=================================================================================
213 void BlocksGUI_QuadFaceDlg::SelectionIntoArgument()
214 {
215   erasePreview();
216
217   // Get index of current selection focus
218   int aCurrFocus = -1;
219   QMap<int, QLineEdit*>::iterator anIter;
220   for (anIter = mySelName.begin(); anIter != mySelName.end(); ++anIter) {
221     if (myEditCurrentArgument == anIter.value()) {
222       aCurrFocus = anIter.key();
223       break;
224     }
225   }
226
227   LightApp_SelectionMgr* aSelMgr = myGeomGUI->getApp()->selectionMgr();
228   SALOME_ListIO aSelList;
229   aSelMgr->selectedObjects(aSelList);
230
231   TopAbs_ShapeEnum aType = TopAbs_EDGE;
232   if (aCurrFocus == Vertex1 || aCurrFocus == Vertex2 ||
233       aCurrFocus == Vertex3 || aCurrFocus == Vertex4)
234     aType = TopAbs_VERTEX;
235
236   QString aName;
237   GEOM::GEOM_Object_var anObj = GEOM::GEOM_Object::_nil();
238
239   if (aSelList.Extent() == 1) {
240     Standard_Boolean aResult = Standard_False;
241     anObj = GEOMBase::ConvertIOinGEOMObject(aSelList.First(), aResult);
242     if (aResult && !anObj->_is_nil()) {
243       aName = GEOMBase::GetName(anObj);
244
245       // Get Selected object if selected subshape
246       TopoDS_Shape aShape;
247       if (GEOMBase::GetShape(anObj, aShape, TopAbs_SHAPE) && !aShape.IsNull())
248       {
249         TColStd_IndexedMapOfInteger aMap;
250         aSelMgr->GetIndexes(aSelList.First(), aMap);
251         if (aMap.Extent() == 1) // Local Selection
252         {
253           int anIndex = aMap(1);
254           if (aType == TopAbs_VERTEX)
255             aName += QString(":vertex_%1").arg(anIndex);
256           else
257             aName += QString(":edge_%1").arg(anIndex);
258
259           //Find SubShape Object in Father
260           GEOM::GEOM_Object_var aFindedObject = GEOMBase_Helper::findObjectInFather(anObj, aName);
261
262           if (aFindedObject == GEOM::GEOM_Object::_nil()) { // Object not found in study
263             GEOM::GEOM_IShapesOperations_var aShapesOp = getGeomEngine()->GetIShapesOperations(getStudyId());
264             anObj = aShapesOp->GetSubShape(anObj, anIndex);
265           }
266           else
267             anObj = aFindedObject; // get Object from study
268         }
269         else // Global Selection
270         {
271           if (aShape.ShapeType() != aType) {
272             anObj = GEOM::GEOM_Object::_nil();
273             aName = "";
274           }
275         }
276       }
277     }
278   }
279
280   myEditCurrentArgument->setText(aName);
281
282   switch (aCurrFocus) {
283     // four vertices
284   case Vertex1:
285     myShape1 = anObj;
286     if (!myShape1->_is_nil() && myShape2->_is_nil())
287       mySelBtn[Vertex2]->click();
288     break;
289   case Vertex2:
290     myShape2 = anObj;
291     if (!myShape2->_is_nil() && myShape3->_is_nil())
292       mySelBtn[Vertex3]->click();
293     break;
294   case Vertex3:
295     myShape3 = anObj;
296     if (!myShape3->_is_nil() && myShape4->_is_nil())
297       mySelBtn[Vertex4]->click();
298     break;
299   case Vertex4:
300     myShape4 = anObj;
301     if (!myShape4->_is_nil() && myShape1->_is_nil())
302       mySelBtn[Vertex1]->click();
303     break;
304
305     // two edges
306   case Edge12:
307     myShape1 = anObj;
308     if (!myShape1->_is_nil() && myShape2->_is_nil())
309       mySelBtn[Edge22]->click();
310     break;
311   case Edge22:
312     myShape2 = anObj;
313     if (!myShape2->_is_nil() && myShape1->_is_nil())
314       mySelBtn[Edge12]->click();
315     break;
316
317     // four edges
318   case Edge14:
319     myShape1 = anObj;
320     if (!myShape1->_is_nil() && myShape2->_is_nil())
321       mySelBtn[Edge24]->click();
322     break;
323   case Edge24:
324     myShape2 = anObj;
325     if (!myShape2->_is_nil() && myShape3->_is_nil())
326       mySelBtn[Edge34]->click();
327     break;
328   case Edge34:
329     myShape3 = anObj;
330     if (!myShape3->_is_nil() && myShape4->_is_nil())
331       mySelBtn[Edge44]->click();
332     break;
333   case Edge44:
334     myShape4 = anObj;
335     if (!myShape4->_is_nil() && myShape1->_is_nil())
336       mySelBtn[Edge14]->click();
337     break;
338
339   default:
340     break;
341   }
342
343   displayPreview();
344 }
345
346 //=================================================================================
347 // function : SetEditCurrentArgument()
348 // purpose  :
349 //=================================================================================
350 void BlocksGUI_QuadFaceDlg::SetEditCurrentArgument()
351 {
352   QPushButton* aSender = (QPushButton*)sender();
353
354   // clear selection
355   disconnect(myGeomGUI->getApp()->selectionMgr(), 0, this, 0);
356   if (myInitial)
357     myInitial = false;
358   else
359     myGeomGUI->getApp()->selectionMgr()->clearSelected();
360
361   // disable all
362   switch (myConstructorId) {
363   case 0:
364     mySelBtn[Vertex1]->setDown(false);
365     mySelBtn[Vertex2]->setDown(false);
366     mySelBtn[Vertex3]->setDown(false);
367     mySelBtn[Vertex4]->setDown(false);
368
369     mySelName[Vertex1]->setEnabled(false);
370     mySelName[Vertex2]->setEnabled(false);
371     mySelName[Vertex3]->setEnabled(false);
372     mySelName[Vertex4]->setEnabled(false);
373     break;
374   case 1:
375     mySelBtn[Edge12]->setDown(false);
376     mySelBtn[Edge22]->setDown(false);
377
378     mySelName[Edge12]->setEnabled(false);
379     mySelName[Edge22]->setEnabled(false);
380     break;
381   case 2:
382     mySelBtn[Edge14]->setDown(false);
383     mySelBtn[Edge24]->setDown(false);
384     mySelBtn[Edge34]->setDown(false);
385     mySelBtn[Edge44]->setDown(false);
386
387     mySelName[Edge14]->setEnabled(false);
388     mySelName[Edge24]->setEnabled(false);
389     mySelName[Edge34]->setEnabled(false);
390     mySelName[Edge44]->setEnabled(false);
391     break;
392   default:
393     break;
394   }
395
396   // set line edit as current argument
397   QMap<int, QPushButton*>::iterator anIter;
398   for (anIter = mySelBtn.begin(); anIter != mySelBtn.end(); ++anIter) {
399     if (anIter.value() == aSender) {
400       myEditCurrentArgument = mySelName[anIter.key()];
401       break;
402     }
403   }
404
405   // enable line edit
406   myEditCurrentArgument->setEnabled(true);
407   myEditCurrentArgument->setFocus();
408
409   // enable push button
410   // after setFocus(), because it will be setDown(false) then loses focus
411   aSender->setDown(true);
412
413   activateSelection();
414 }
415
416 //=================================================================================
417 // function : ActivateThisDialog()
418 // purpose  :
419 //=================================================================================
420 void BlocksGUI_QuadFaceDlg::ActivateThisDialog()
421 {
422   GEOMBase_Skeleton::ActivateThisDialog();
423   activateSelection();
424
425   // ??
426   displayPreview();
427 }
428
429 //=================================================================================
430 // function : enterEvent()
431 // purpose  :
432 //=================================================================================
433 void BlocksGUI_QuadFaceDlg::enterEvent (QEvent*)
434 {
435   if (!mainFrame()->GroupConstructors->isEnabled())
436     ActivateThisDialog();
437 }
438
439 //=================================================================================
440 // function : createSelWg()
441 // purpose  :
442 //=================================================================================
443 void BlocksGUI_QuadFaceDlg::createSelWg (const QString& theLbl,
444                                          QPixmap&       thePix,
445                                          QWidget*       theParent,
446                                          const int      theId)
447 {
448   QLabel* lab = new QLabel(theLbl, theParent);
449   mySelBtn[theId] = new QPushButton(theParent);
450   mySelBtn[theId]->setIcon(thePix);
451   mySelBtn[theId]->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
452   mySelName[theId] = new QLineEdit(theParent);
453   mySelName[theId]->setReadOnly(true);
454   QGridLayout* l = 0;
455   if (!theParent->layout()) {
456     l = new QGridLayout(theParent);
457     l->setMargin(9); l->setSpacing(6);
458   }
459   else {
460     l = qobject_cast<QGridLayout*>(theParent->layout());
461   }
462   int row = l->rowCount();
463   l->addWidget(lab,              row, 0);
464   l->addWidget(mySelBtn[theId],  row, 1);
465   l->addWidget(mySelName[theId], row, 2);
466 }
467
468 //=================================================================================
469 // function : activateSelection
470 // purpose  : Activate selection in accordance with myEditCurrentArgument
471 //=================================================================================
472 void BlocksGUI_QuadFaceDlg::activateSelection()
473 {
474   globalSelection(); // close local contexts, if any
475   if (myEditCurrentArgument == mySelName[Vertex1] ||
476       myEditCurrentArgument == mySelName[Vertex2] ||
477       myEditCurrentArgument == mySelName[Vertex3] ||
478       myEditCurrentArgument == mySelName[Vertex4])
479   {
480     localSelection(GEOM::GEOM_Object::_nil(), TopAbs_VERTEX); //Select Vertices on All Shapes
481   }
482   else
483   {
484     localSelection(GEOM::GEOM_Object::_nil(), TopAbs_EDGE); //Select Edges on All Shapes
485   }
486   connect(myGeomGUI->getApp()->selectionMgr(), SIGNAL(currentSelectionChanged()),
487           this, SLOT(SelectionIntoArgument()));
488 }
489
490 //=================================================================================
491 // function : createOperation
492 // purpose  :
493 //=================================================================================
494 GEOM::GEOM_IOperations_ptr BlocksGUI_QuadFaceDlg::createOperation()
495 {
496   return getGeomEngine()->GetIBlocksOperations(getStudyId());
497 }
498
499 //=================================================================================
500 // function : isValid
501 // purpose  : Verify validity of input data
502 //=================================================================================
503 bool BlocksGUI_QuadFaceDlg::isValid (QString&)
504 {
505   bool ok = false;
506   switch (getConstructorId()) {
507   case 0:
508     ok = (!myShape1->_is_nil() && !myShape2->_is_nil() &&
509           !myShape3->_is_nil() && !myShape4->_is_nil());
510     break;
511   case 1:
512     ok = (!myShape1->_is_nil() && !myShape2->_is_nil());
513     break;
514   case 2:
515     ok = (!myShape1->_is_nil() && !myShape2->_is_nil() &&
516           !myShape3->_is_nil() && !myShape4->_is_nil());
517     break;
518   default:
519     break;
520   }
521   return ok;
522 }
523
524 //=================================================================================
525 // function : execute
526 // purpose  :
527 //=================================================================================
528 bool BlocksGUI_QuadFaceDlg::execute (ObjectList& objects)
529 {
530   bool res = false;
531
532   GEOM::GEOM_Object_var anObj;
533
534   switch (getConstructorId()) {
535   case 0:
536     anObj = GEOM::GEOM_IBlocksOperations::_narrow(getOperation())->
537       MakeQuad4Vertices(myShape1, myShape2, myShape3, myShape4);
538     res = true;
539     break;
540   case 1:
541     anObj = GEOM::GEOM_IBlocksOperations::_narrow(getOperation())->
542       MakeQuad2Edges(myShape1, myShape2);
543     res = true;
544     break;
545   case 2:
546     anObj = GEOM::GEOM_IBlocksOperations::_narrow(getOperation())->
547       MakeQuad(myShape1, myShape2, myShape3, myShape4);
548     res = true;
549     break;
550   default:
551     break;
552   }
553
554   if (!anObj->_is_nil())
555     objects.push_back(anObj._retn());
556
557   return res;
558 }
559
560 //=================================================================================
561 // function : addSubshapeToStudy
562 // purpose  : virtual method to add new SubObjects if local selection
563 //=================================================================================
564 void BlocksGUI_QuadFaceDlg::addSubshapesToStudy()
565 {
566   QMap<QString, GEOM::GEOM_Object_var> objMap;
567
568   switch (getConstructorId()) {
569   case 0:
570     objMap[mySelName[Vertex1]->text()] = myShape1;
571     objMap[mySelName[Vertex2]->text()] = myShape2;
572     objMap[mySelName[Vertex3]->text()] = myShape3;
573     objMap[mySelName[Vertex4]->text()] = myShape4;
574     break;
575   case 1:
576     objMap[mySelName[Edge12]->text()] = myShape1;
577     objMap[mySelName[Edge22]->text()] = myShape2;
578     break;
579   case 2:
580     objMap[mySelName[Edge14]->text()] = myShape1;
581     objMap[mySelName[Edge24]->text()] = myShape2;
582     objMap[mySelName[Edge34]->text()] = myShape3;
583     objMap[mySelName[Edge44]->text()] = myShape4;
584     break;
585   }
586   addSubshapesToFather(objMap);
587 }