1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : SMESHGUI_SingleEditDlg.cxx
24 // Author : Sergey LITONIN, Open CASCADE S.A.S.
26 #include <SVTK_Selector.h>
30 #include "SMESHGUI_SingleEditDlg.h"
33 #include "SMESHGUI_Utils.h"
34 #include "SMESHGUI_VTKUtils.h"
35 #include "SMESHGUI_MeshUtils.h"
37 #include <SMESH_Actor.h>
38 #include <SMDS_Mesh.hxx>
40 // SALOME GUI includes
41 #include <LightApp_SelectionMgr.h>
42 #include <LightApp_Application.h>
43 #include <SUIT_ResourceMgr.h>
44 #include <SUIT_MessageBox.h>
45 #include <SUIT_Desktop.h>
46 #include <SUIT_Session.h>
48 #include <SVTK_ViewWindow.h>
49 #include <SALOME_ListIO.hxx>
52 #include <TColStd_MapOfInteger.hxx>
53 #include <TColStd_IndexedMapOfInteger.hxx>
56 #include <QVBoxLayout>
57 #include <QHBoxLayout>
59 #include <QPushButton>
70 \brief Simple 'busy state' flag locker.
77 //! Constructor. Sets passed boolean flag to \c true.
78 BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; }
79 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
80 ~BusyLocker() { myBusy = false; }
82 bool& myBusy; //! External 'busy state' boolean flag
86 * Class : SMESHGUI_SingleEditDlg
87 * Description : Inversion of the diagonal of a pseudo-quadrangle formed by
88 * 2 neighboring triangles with 1 common edge
91 //=======================================================================
92 // name : SMESHGUI_SingleEditDlg()
93 // Purpose : Constructor
94 //=======================================================================
95 SMESHGUI_SingleEditDlg
96 ::SMESHGUI_SingleEditDlg(SMESHGUI* theModule)
97 : QDialog(SMESH::GetDesktop(theModule)),
98 mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
99 mySelector(SMESH::GetViewWindow(theModule)->GetSelector()),
100 mySMESHGUI(theModule)
104 QVBoxLayout* aDlgLay = new QVBoxLayout(this);
105 aDlgLay->setMargin(MARGIN);
106 aDlgLay->setSpacing(SPACING);
108 QWidget* aMainFrame = createMainFrame (this);
109 QWidget* aBtnFrame = createButtonFrame(this);
111 aDlgLay->addWidget(aMainFrame);
112 aDlgLay->addWidget(aBtnFrame);
117 //=======================================================================
118 // name : createMainFrame()
119 // Purpose : Create frame containing dialog's input fields
120 //=======================================================================
121 QWidget* SMESHGUI_SingleEditDlg::createMainFrame (QWidget* theParent)
123 QGroupBox* aMainGrp = new QGroupBox(tr("EDGE_BETWEEN"), theParent);
124 QHBoxLayout* aLay = new QHBoxLayout(aMainGrp);
125 aLay->setMargin(MARGIN);
126 aLay->setSpacing(SPACING);
128 QPixmap aPix (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT")));
130 QLabel* aLab = new QLabel(tr("SMESH_EDGE"), aMainGrp);
131 QPushButton* aBtn = new QPushButton(aMainGrp);
133 myEdge = new QLineEdit(aMainGrp);
134 myEdge->setValidator(new QRegExpValidator(QRegExp("[\\d]*-[\\d]*"), this));
136 aLay->addWidget(aLab);
137 aLay->addWidget(aBtn);
138 aLay->addWidget(myEdge);
143 //=======================================================================
144 // name : createButtonFrame()
145 // Purpose : Create frame containing buttons
146 //=======================================================================
147 QWidget* SMESHGUI_SingleEditDlg::createButtonFrame (QWidget* theParent)
149 QGroupBox* aFrame = new QGroupBox(theParent);
151 myOkBtn = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), aFrame);
152 myApplyBtn = new QPushButton(tr("SMESH_BUT_APPLY"), aFrame);
153 myCloseBtn = new QPushButton(tr("SMESH_BUT_CLOSE"), aFrame);
154 myHelpBtn = new QPushButton(tr("SMESH_BUT_HELP"), aFrame);
156 QHBoxLayout* aLay = new QHBoxLayout(aFrame);
157 aLay->setMargin(MARGIN);
158 aLay->setSpacing(SPACING);
160 aLay->addWidget(myOkBtn);
161 aLay->addSpacing(10);
162 aLay->addWidget(myApplyBtn);
163 aLay->addSpacing(10);
165 aLay->addWidget(myCloseBtn);
166 aLay->addWidget(myHelpBtn);
171 //=======================================================================
173 // Purpose : Verify validity of input data
174 //=======================================================================
175 bool SMESHGUI_SingleEditDlg::isValid (const bool /*theMess*/) const
178 return getNodeIds(myEdge->text(), id1, id2);
181 //=======================================================================
182 // name : getNodeIds()
183 // Purpose : Retrieve node ids from string
184 //=======================================================================
185 bool SMESHGUI_SingleEditDlg::getNodeIds (const QString& theStr,
186 int& theId1, int& theId2) const
188 if (!theStr.contains('-'))
192 QString str1 = theStr.section('-', 0, 0, QString::SectionSkipEmpty);
193 QString str2 = theStr.section('-', 1, 1, QString::SectionSkipEmpty);
194 theId1 = str1.toInt(&ok1);
195 theId2 = str2.toInt(&ok2);
200 //=======================================================================
201 // name : ~SMESHGUI_SingleEditDlg()
202 // Purpose : Destructor
203 //=======================================================================
204 SMESHGUI_SingleEditDlg::~SMESHGUI_SingleEditDlg()
208 //=======================================================================
210 // Purpose : Init dialog fields, connect signals and slots, show dialog
211 //=======================================================================
212 void SMESHGUI_SingleEditDlg::Init()
214 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
219 connect(myOkBtn, SIGNAL(clicked()), SLOT(onOk()));
220 connect(myCloseBtn, SIGNAL(clicked()), SLOT(reject()));
221 connect(myApplyBtn, SIGNAL(clicked()), SLOT(onApply()));
222 connect(myHelpBtn, SIGNAL(clicked()), SLOT(onHelp()));
224 // selection and SMESHGUI
225 connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionDone()));
226 connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(onDeactivate()));
227 connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), SLOT(reject()));
228 connect(mySMESHGUI, SIGNAL(SignalActivatedViewManager()), SLOT(onOpenView()));
229 connect(mySMESHGUI, SIGNAL(SignalCloseView()), SLOT(onCloseView()));
230 connect(myEdge, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&)));
232 myOkBtn->setEnabled(false);
233 myApplyBtn->setEnabled(false);
236 // set selection mode
237 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
238 aViewWindow->SetSelectionMode(EdgeOfCellSelection);
243 //=======================================================================
245 // Purpose : SLOT called when "Ok" button pressed.
246 // Assign filters VTK viewer and close dialog
247 //=======================================================================
248 void SMESHGUI_SingleEditDlg::onOk()
254 //=======================================================================
256 // Purpose : SLOT called when "Close" button pressed. Close dialog
257 //=======================================================================
258 void SMESHGUI_SingleEditDlg::reject()
260 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
261 aViewWindow->SetSelectionMode(ActorSelection);
262 //mySelectionMgr->clearSelected();
263 disconnect(mySelectionMgr, 0, this, 0);
264 disconnect(mySMESHGUI, 0, this, 0);
265 mySMESHGUI->ResetState();
269 //=================================================================================
270 // function : onHelp()
272 //=================================================================================
273 void SMESHGUI_SingleEditDlg::onHelp()
275 LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
277 app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
281 platform = "winapplication";
283 platform = "application";
285 SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
286 tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
287 arg(app->resourceMgr()->stringValue("ExternalBrowser",
289 arg(myHelpFileName));
293 //=======================================================================
294 //function : findTriangles()
295 //purpose : find triangles sharing theNode1-theNode2 link
296 // THIS IS A PIECE OF SMESH_MeshEditor.cxx
297 // TO DO: make it available in SMDS for ex.
298 //=======================================================================
299 static bool findTriangles (const SMDS_MeshNode * theNode1,
300 const SMDS_MeshNode * theNode2,
301 const SMDS_MeshElement*& theTria1,
302 const SMDS_MeshElement*& theTria2)
304 if (!theNode1 || !theNode2) return false;
306 theTria1 = theTria2 = 0;
308 std::set< const SMDS_MeshElement* > emap;
309 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
311 const SMDS_MeshElement* elem = it->next();
312 if (elem->GetType() == SMDSAbs_Face && elem->NbCornerNodes() == 3)
315 it = theNode2->GetInverseElementIterator();
317 const SMDS_MeshElement* elem = it->next();
318 if (elem->GetType() == SMDSAbs_Face &&
319 emap.find(elem) != emap.end())
329 return (theTria1 && theTria2);
332 //=======================================================================
333 //function : onTextChange()
335 //=======================================================================
336 void SMESHGUI_SingleEditDlg::onTextChange (const QString& /*theNewText*/)
339 BusyLocker lock(myBusy);
341 myOkBtn->setEnabled(false);
342 myApplyBtn->setEnabled(false);
344 // highlight entered edge
346 if(SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh()){
347 Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
350 mySelectionMgr->setSelectedObjects(aList,false);
352 SVTK_IndexedMapOfVtkIds selectedIndices;
353 SVTK_ListOfVtk newIndices;
354 mySelector->GetCompositeIndex(anIO,selectedIndices);
357 if ( !getNodeIds(myEdge->text(), id1, id2) )
360 const SMDS_MeshNode* aNode1 = aMesh->FindNode( id1 );
361 const SMDS_MeshNode* aNode2 = aMesh->FindNode( id2 );
363 if ( !aNode1 || !aNode2 || aNode1 == aNode2 )
366 // find a triangle and an edge index
367 const SMDS_MeshElement* tria1;
368 const SMDS_MeshElement* tria2;
370 if ( findTriangles(aNode1,aNode2,tria1,tria2) )
372 newIndices.push_back( aNode1->GetID() );
373 newIndices.push_back( aNode2->GetID() );
375 myOkBtn->setEnabled(true);
376 myApplyBtn->setEnabled(true);
378 mySelector->AddOrRemoveCompositeIndex(anIO, newIndices, false);
379 SMESH::GetViewWindow(mySMESHGUI)->highlight( anIO, true, true );
384 //=======================================================================
385 // name : onSelectionDone()
386 // Purpose : SLOT called when selection changed
387 //=======================================================================
388 void SMESHGUI_SingleEditDlg::onSelectionDone()
391 BusyLocker lock(myBusy);
393 int anId1 = 0, anId2 = 0;
395 myOkBtn->setEnabled(false);
396 myApplyBtn->setEnabled(false);
399 mySelectionMgr->selectedObjects(aList);
401 if (aList.Extent() != 1) {
406 Handle(SALOME_InteractiveObject) anIO = aList.First();
407 myActor = SMESH::FindActorByEntry(anIO->getEntry());
409 TVisualObjPtr aVisualObj = myActor->GetObject();
410 if(SMDS_Mesh* aMesh = aVisualObj->GetMesh())
412 const SMDS_MeshElement* tria[2];
415 SVTK_IndexedMapOfVtkIds anIds;
416 mySelector->GetCompositeIndex(anIO,anIds);
417 if( anIds.Extent() == 1 && anIds(1).size() == 2 ) {
424 findTriangles( aMesh->FindNode( anId1 ), aMesh->FindNode( anId2 ), tria[0],tria[1] ) )
426 QString aText = QString("%1-%2").arg(anId1).arg(anId2);
427 myEdge->setText(aText);
429 myOkBtn->setEnabled(true);
430 myApplyBtn->setEnabled(true);
440 //=======================================================================
441 // name : onDeactivate()
442 // Purpose : SLOT called when dialog must be deactivated
443 //=======================================================================
444 void SMESHGUI_SingleEditDlg::onDeactivate()
449 //=================================================================================
450 // function : onOpenView()
452 //=================================================================================
453 void SMESHGUI_SingleEditDlg::onOpenView()
456 mySelector = SMESH::GetViewWindow( mySMESHGUI )->GetSelector();
457 mySMESHGUI->EmitSignalDeactivateDialog();
462 //=================================================================================
463 // function : onCloseView()
465 //=================================================================================
466 void SMESHGUI_SingleEditDlg::onCloseView()
472 //=======================================================================
473 // name : enterEvent()
474 // Purpose : Event filter
475 //=======================================================================
476 void SMESHGUI_SingleEditDlg::enterEvent (QEvent*)
479 mySMESHGUI->EmitSignalDeactivateDialog();
480 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI );
482 aViewWindow->SetSelectionMode(EdgeOfCellSelection);
484 mySelector = aViewWindow->GetSelector();
490 //=================================================================================
491 // function : onApply()
492 // purpose : SLOT. Called when apply button is pressed
493 //=================================================================================
494 bool SMESHGUI_SingleEditDlg::onApply()
496 if (SMESHGUI::isStudyLocked())
498 // verify validity of input data
502 // get mesh, actor and nodes
504 mySelectionMgr->selectedObjects(aList);
506 SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(aList.First());
508 if (aMesh->_is_nil()) {
509 SUIT_MessageBox::information(SMESH::GetDesktop(mySMESHGUI),
511 tr("SMESHG_NO_MESH"));
515 SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
516 int anId1= 0, anId2 = 0;
517 if (aMeshEditor->_is_nil() || !getNodeIds(myEdge->text(), anId1, anId2))
521 bool aResult = process(aMeshEditor.in(), anId1, anId2);
525 mySelector->ClearIndex();
526 mySelector->ClearCompositeIndex();
527 mySelectionMgr->setSelectedObjects(aList, false);
530 SMESHGUI::Modified();
536 //=================================================================================
537 // function : keyPressEvent()
539 //=================================================================================
540 void SMESHGUI_SingleEditDlg::keyPressEvent( QKeyEvent* e )
542 QDialog::keyPressEvent( e );
543 if ( e->isAccepted() )
546 if ( e->key() == Qt::Key_F1 ) {
553 * Class : SMESHGUI_TrianglesInversionDlg
554 * Description : Inversion of the diagonal of a pseudo-quadrangle formed by
555 * 2 neighboring triangles with 1 common edge
558 SMESHGUI_TrianglesInversionDlg
559 ::SMESHGUI_TrianglesInversionDlg(SMESHGUI* theModule)
560 : SMESHGUI_SingleEditDlg(theModule)
562 setWindowTitle(tr("CAPTION"));
563 myHelpFileName = "diagonal_inversion_of_elements.html";
566 SMESHGUI_TrianglesInversionDlg::~SMESHGUI_TrianglesInversionDlg()
570 bool SMESHGUI_TrianglesInversionDlg::process (SMESH::SMESH_MeshEditor_ptr theMeshEditor,
571 const int theId1, const int theId2)
573 return theMeshEditor->InverseDiag(theId1, theId2);
577 * Class : SMESHGUI_UnionOfTwoTrianglesDlg
578 * Description : Construction of a quadrangle by deletion of the
579 * common border of 2 neighboring triangles
582 SMESHGUI_UnionOfTwoTrianglesDlg
583 ::SMESHGUI_UnionOfTwoTrianglesDlg(SMESHGUI* theModule)
584 : SMESHGUI_SingleEditDlg(theModule)
586 setWindowTitle(tr("CAPTION"));
587 myHelpFileName = "uniting_two_triangles.html";
590 SMESHGUI_UnionOfTwoTrianglesDlg::~SMESHGUI_UnionOfTwoTrianglesDlg()
594 bool SMESHGUI_UnionOfTwoTrianglesDlg::process (SMESH::SMESH_MeshEditor_ptr theMeshEditor,
595 const int theId1, const int theId2)
597 return theMeshEditor->DeleteDiag(theId1, theId2);