1 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File : SMESHGUI_SingleEditDlg.cxx
21 // Author : Sergey LITONIN, Open CASCADE S.A.S.
25 #include "SMESHGUI_SingleEditDlg.h"
28 #include "SMESHGUI_Utils.h"
29 #include "SMESHGUI_VTKUtils.h"
30 #include "SMESHGUI_MeshUtils.h"
32 #include <SMESH_Actor.h>
33 #include <SMDS_Mesh.hxx>
35 // SALOME GUI includes
36 #include <LightApp_SelectionMgr.h>
37 #include <LightApp_Application.h>
38 #include <SUIT_ResourceMgr.h>
39 #include <SUIT_MessageBox.h>
40 #include <SUIT_Desktop.h>
41 #include <SUIT_Session.h>
43 #include <SVTK_Selector.h>
44 #include <SVTK_ViewWindow.h>
45 #include <SALOME_ListIO.hxx>
48 #include <TColStd_MapOfInteger.hxx>
49 #include <TColStd_IndexedMapOfInteger.hxx>
52 #include <QVBoxLayout>
53 #include <QHBoxLayout>
55 #include <QPushButton>
65 * Class : SMESHGUI_DiagValidator
66 * Description : validate munual input of edge like "id1-id2"
68 class SMESHGUI_DiagValidator: public QValidator
71 SMESHGUI_DiagValidator (QWidget* parent):
74 State validate (QString& text, int& pos) const
76 text = text.trimmed();
77 text.replace(QRegExp("[^0-9]+"), "-");
80 int ind = text.indexOf(QRegExp("-[0-9]+-"));
81 if (ind > 0) { // leave only two ids
82 ind = text.indexOf('-', ind + 1);
86 if (pos > text.length())
93 * Class : SMESHGUI_SingleEditDlg
94 * Description : Inversion of the diagonal of a pseudo-quadrangle formed by
95 * 2 neighboring triangles with 1 common edge
98 //=======================================================================
99 // name : SMESHGUI_SingleEditDlg()
100 // Purpose : Constructor
101 //=======================================================================
102 SMESHGUI_SingleEditDlg
103 ::SMESHGUI_SingleEditDlg(SMESHGUI* theModule)
104 : QDialog(SMESH::GetDesktop(theModule)),
105 mySelector(SMESH::GetViewWindow(theModule)->GetSelector()),
106 mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
107 mySMESHGUI(theModule)
111 QVBoxLayout* aDlgLay = new QVBoxLayout(this);
112 aDlgLay->setMargin(MARGIN);
113 aDlgLay->setSpacing(SPACING);
115 QWidget* aMainFrame = createMainFrame (this);
116 QWidget* aBtnFrame = createButtonFrame(this);
118 aDlgLay->addWidget(aMainFrame);
119 aDlgLay->addWidget(aBtnFrame);
124 //=======================================================================
125 // name : createMainFrame()
126 // Purpose : Create frame containing dialog's input fields
127 //=======================================================================
128 QWidget* SMESHGUI_SingleEditDlg::createMainFrame (QWidget* theParent)
130 QGroupBox* aMainGrp = new QGroupBox(tr("EDGE_BETWEEN"), theParent);
131 QHBoxLayout* aLay = new QHBoxLayout(aMainGrp);
132 aLay->setMargin(MARGIN);
133 aLay->setSpacing(SPACING);
135 QPixmap aPix (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT")));
137 QLabel* aLab = new QLabel(tr("SMESH_EDGE"), aMainGrp);
138 QPushButton* aBtn = new QPushButton(aMainGrp);
140 myEdge = new QLineEdit(aMainGrp);
141 myEdge->setValidator(new SMESHGUI_DiagValidator(this));
143 aLay->addWidget(aLab);
144 aLay->addWidget(aBtn);
145 aLay->addWidget(myEdge);
150 //=======================================================================
151 // name : createButtonFrame()
152 // Purpose : Create frame containing buttons
153 //=======================================================================
154 QWidget* SMESHGUI_SingleEditDlg::createButtonFrame (QWidget* theParent)
156 QGroupBox* aFrame = new QGroupBox(theParent);
158 myOkBtn = new QPushButton(tr("SMESH_BUT_OK" ), aFrame);
159 myApplyBtn = new QPushButton(tr("SMESH_BUT_APPLY"), aFrame);
160 myCloseBtn = new QPushButton(tr("SMESH_BUT_CLOSE"), aFrame);
161 myHelpBtn = new QPushButton(tr("SMESH_BUT_HELP"), aFrame);
163 QHBoxLayout* aLay = new QHBoxLayout(aFrame);
164 aLay->setMargin(MARGIN);
165 aLay->setSpacing(SPACING);
167 aLay->addWidget(myOkBtn);
168 aLay->addSpacing(10);
169 aLay->addWidget(myApplyBtn);
170 aLay->addSpacing(10);
172 aLay->addWidget(myCloseBtn);
173 aLay->addWidget(myHelpBtn);
178 //=======================================================================
180 // Purpose : Verify validity of input data
181 //=======================================================================
182 bool SMESHGUI_SingleEditDlg::isValid (const bool theMess) const
185 return getNodeIds(myEdge->text(), id1, id2);
188 //=======================================================================
189 // name : getNodeIds()
190 // Purpose : Retrieve node ids from string
191 //=======================================================================
192 bool SMESHGUI_SingleEditDlg::getNodeIds (const QString& theStr,
193 int& theId1, int& theId2) const
195 if (!theStr.contains('-'))
199 QString str1 = theStr.section('-', 0, 0, QString::SectionSkipEmpty);
200 QString str2 = theStr.section('-', 1, 1, QString::SectionSkipEmpty);
201 theId1 = str1.toInt(&ok1);
202 theId2 = str2.toInt(&ok2);
207 //=======================================================================
208 // name : ~SMESHGUI_SingleEditDlg()
209 // Purpose : Destructor
210 //=======================================================================
211 SMESHGUI_SingleEditDlg::~SMESHGUI_SingleEditDlg()
215 //=======================================================================
217 // Purpose : Init dialog fields, connect signals and slots, show dialog
218 //=======================================================================
219 void SMESHGUI_SingleEditDlg::Init()
221 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
226 connect(myOkBtn, SIGNAL(clicked()), SLOT(onOk()));
227 connect(myCloseBtn, SIGNAL(clicked()), SLOT(onClose()));
228 connect(myApplyBtn, SIGNAL(clicked()), SLOT(onApply()));
229 connect(myHelpBtn, SIGNAL(clicked()), SLOT(onHelp()));
231 // selection and SMESHGUI
232 connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionDone()));
233 connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(onDeactivate()));
234 connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), SLOT(onClose()));
235 connect(myEdge, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&)));
237 myOkBtn->setEnabled(false);
238 myApplyBtn->setEnabled(false);
241 // set selection mode
242 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
243 aViewWindow->SetSelectionMode(EdgeOfCellSelection);
248 //=======================================================================
250 // Purpose : SLOT called when "Ok" button pressed.
251 // Assign filters VTK viewer and close dialog
252 //=======================================================================
253 void SMESHGUI_SingleEditDlg::onOk()
259 //=======================================================================
261 // Purpose : SLOT called when "Close" button pressed. Close dialog
262 //=======================================================================
263 void SMESHGUI_SingleEditDlg::onClose()
265 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
266 aViewWindow->SetSelectionMode(ActorSelection);
267 //mySelectionMgr->clearSelected();
268 disconnect(mySelectionMgr, 0, this, 0);
269 disconnect(mySMESHGUI, 0, this, 0);
270 mySMESHGUI->ResetState();
274 //=================================================================================
275 // function : onHelp()
277 //=================================================================================
278 void SMESHGUI_SingleEditDlg::onHelp()
280 LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
282 app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
286 platform = "winapplication";
288 platform = "application";
290 SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
291 tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
292 arg(app->resourceMgr()->stringValue("ExternalBrowser",
294 arg(myHelpFileName));
298 //=======================================================================
299 //function : findTriangles()
300 //purpose : find triangles sharing theNode1-theNode2 link
301 // THIS IS A PIECE OF SMESH_MeshEditor.cxx
302 // TO DO: make it available in SMDS for ex.
303 //=======================================================================
304 static bool findTriangles (const SMDS_MeshNode * theNode1,
305 const SMDS_MeshNode * theNode2,
306 const SMDS_MeshElement*& theTria1,
307 const SMDS_MeshElement*& theTria2)
309 if (!theNode1 || !theNode2) return false;
311 theTria1 = theTria2 = 0;
313 std::set< const SMDS_MeshElement* > emap;
314 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
316 const SMDS_MeshElement* elem = it->next();
317 if (elem->GetType() == SMDSAbs_Face && elem->NbNodes() == 3)
320 it = theNode2->GetInverseElementIterator();
322 const SMDS_MeshElement* elem = it->next();
323 if (elem->GetType() == SMDSAbs_Face &&
324 emap.find(elem) != emap.end())
332 return (theTria1 && theTria2);
335 //=======================================================================
336 //function : onTextChange()
338 //=======================================================================
339 void SMESHGUI_SingleEditDlg::onTextChange (const QString& theNewText)
343 myOkBtn->setEnabled(false);
344 myApplyBtn->setEnabled(false);
346 // hilight entered edge
348 if(SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh()){
349 myBusy = true; // block onSelectionDone()
350 Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
353 mySelectionMgr->setSelectedObjects(aList,false);
355 TColStd_IndexedMapOfInteger selectedIndices;
356 TColStd_MapOfInteger newIndices;
357 mySelector->GetIndex(anIO,selectedIndices);
360 QStringList aListId = theNewText.split("-", QString::SkipEmptyParts);
361 if (aListId.count() != 2)
366 const SMDS_MeshNode* a2Nodes[2];
367 for (i = 0; i < aListId.count(); i++) {
368 if(const SMDS_MeshNode *aNode = aMesh->FindNode(aListId[ i ].toInt()))
369 a2Nodes[ i ] = aNode;
374 // find a triangle and an edge nb
375 const SMDS_MeshElement* tria[2];
376 allOk &= a2Nodes[0] != a2Nodes[1] && findTriangles(a2Nodes[0],a2Nodes[1],tria[0],tria[1]);
377 myBusy = true; // block onSelectionDone()
380 newIndices.Add(tria[0]->GetID());
382 const SMDS_MeshNode* a3Nodes [3];
383 SMDS_ElemIteratorPtr it;
385 for (i = 0, it = tria[0]->nodesIterator(); it->more(); i++) {
386 a3Nodes[ i ] = static_cast<const SMDS_MeshNode*>(it->next());
388 allOk = (a3Nodes[ i ] == a2Nodes[ 0 ] && a3Nodes[ i - 1] == a2Nodes[ 1 ]) ||
389 (a3Nodes[ i ] == a2Nodes[ 1 ] && a3Nodes[ i - 1] == a2Nodes[ 0 ]);
396 newIndices.Add(-edgeInd-1);
398 myOkBtn->setEnabled(true);
399 myApplyBtn->setEnabled(true);
401 mySelector->AddOrRemoveIndex(anIO,newIndices, false);
402 SMESH::GetViewWindow(mySMESHGUI)->highlight( anIO, true, true );
409 //=======================================================================
410 // name : onSelectionDone()
411 // Purpose : SLOT called when selection changed
412 //=======================================================================
413 void SMESHGUI_SingleEditDlg::onSelectionDone()
417 int anId1 = 0, anId2 = 0;
419 myOkBtn->setEnabled(false);
420 myApplyBtn->setEnabled(false);
423 mySelectionMgr->selectedObjects(aList);
425 if (aList.Extent() != 1) {
430 Handle(SALOME_InteractiveObject) anIO = aList.First();
431 myActor = SMESH::FindActorByEntry(anIO->getEntry());
433 TVisualObjPtr aVisualObj = myActor->GetObject();
434 if(SMDS_Mesh* aMesh = aVisualObj->GetMesh())
436 const SMDS_MeshElement* tria[2];
437 if( SMESH::GetEdgeNodes( mySelector, aVisualObj, anId1, anId2 ) >= 1 &&
438 findTriangles( aMesh->FindNode( anId1 ), aMesh->FindNode( anId2 ), tria[0],tria[1] ) )
440 QString aText = QString("%1-%2").arg(anId1).arg(anId2);
442 myEdge->setText(aText);
445 myOkBtn->setEnabled(true);
446 myApplyBtn->setEnabled(true);
456 //=======================================================================
457 // name : onDeactivate()
458 // Purpose : SLOT called when dialog must be deativated
459 //=======================================================================
460 void SMESHGUI_SingleEditDlg::onDeactivate()
465 //=======================================================================
466 // name : enterEvent()
467 // Purpose : Event filter
468 //=======================================================================
469 void SMESHGUI_SingleEditDlg::enterEvent (QEvent*)
472 mySMESHGUI->EmitSignalDeactivateDialog();
473 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
474 aViewWindow->SetSelectionMode(EdgeOfCellSelection);
479 //=================================================================================
480 // function : closeEvent()
482 //=================================================================================
483 void SMESHGUI_SingleEditDlg::closeEvent (QCloseEvent*)
488 //=======================================================================
489 //function : hideEvent()
490 //purpose : caused by ESC key
491 //=======================================================================
492 void SMESHGUI_SingleEditDlg::hideEvent (QHideEvent*)
498 //=================================================================================
499 // function : onApply()
500 // purpose : SLOT. Called when apply button is pressed
501 //=================================================================================
502 bool SMESHGUI_SingleEditDlg::onApply()
504 if (mySMESHGUI->isActiveStudyLocked())
506 // verify validity of input data
510 // get mesh, actor and nodes
512 mySelectionMgr->selectedObjects(aList);
514 SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(aList.First());
516 if (aMesh->_is_nil()) {
517 SUIT_MessageBox::information(SMESH::GetDesktop(mySMESHGUI),
519 tr("SMESHG_NO_MESH"));
523 SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
524 int anId1= 0, anId2 = 0;
525 if (aMeshEditor->_is_nil() || !getNodeIds(myEdge->text(), anId1, anId2))
529 bool aResult = process(aMeshEditor.in(), anId1, anId2);
533 mySelector->ClearIndex();
534 mySelectionMgr->setSelectedObjects(aList, false);
542 //=================================================================================
543 // function : keyPressEvent()
545 //=================================================================================
546 void SMESHGUI_SingleEditDlg::keyPressEvent( QKeyEvent* e )
548 QDialog::keyPressEvent( e );
549 if ( e->isAccepted() )
552 if ( e->key() == Qt::Key_F1 ) {
559 * Class : SMESHGUI_TrianglesInversionDlg
560 * Description : Inversion of the diagonal of a pseudo-quadrangle formed by
561 * 2 neighboring triangles with 1 common edge
564 SMESHGUI_TrianglesInversionDlg
565 ::SMESHGUI_TrianglesInversionDlg(SMESHGUI* theModule)
566 : SMESHGUI_SingleEditDlg(theModule)
568 setWindowTitle(tr("CAPTION"));
569 myHelpFileName = "diagonal_inversion_of_elements_page.html";
572 SMESHGUI_TrianglesInversionDlg::~SMESHGUI_TrianglesInversionDlg()
576 bool SMESHGUI_TrianglesInversionDlg::process (SMESH::SMESH_MeshEditor_ptr theMeshEditor,
577 const int theId1, const int theId2)
579 return theMeshEditor->InverseDiag(theId1, theId2);
583 * Class : SMESHGUI_UnionOfTwoTrianglesDlg
584 * Description : Construction of a quadrangle by deletion of the
585 * common border of 2 neighboring triangles
588 SMESHGUI_UnionOfTwoTrianglesDlg
589 ::SMESHGUI_UnionOfTwoTrianglesDlg(SMESHGUI* theModule)
590 : SMESHGUI_SingleEditDlg(theModule)
592 setWindowTitle(tr("CAPTION"));
593 myHelpFileName = "uniting_two_triangles_page.html";
596 SMESHGUI_UnionOfTwoTrianglesDlg::~SMESHGUI_UnionOfTwoTrianglesDlg()
600 bool SMESHGUI_UnionOfTwoTrianglesDlg::process (SMESH::SMESH_MeshEditor_ptr theMeshEditor,
601 const int theId1, const int theId2)
603 return theMeshEditor->DeleteDiag(theId1, theId2);