Salome HOME
Integration of PAL/SALOME V2.1.0c from OCC
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_SingleEditDlg.cxx
1 //  SMESH SMESHGUI : GUI for SMESH component
2 //
3 //  Copyright (C) 2003  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. 
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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SMESHGUI_SingleEditDlg.cxx
25 //  Author : Sergey LITONIN
26 //  Module : SMESH
27
28 #include "SMESHGUI_SingleEditDlg.h"
29
30 #include "QAD_Desktop.h"
31
32 #include "SMESHGUI.h"
33 #include "SMESHGUI_Utils.h"
34 #include "SMESHGUI_VTKUtils.h"
35 #include "SMESHGUI_MeshUtils.h"
36
37 #include "SMESHGUI_SpinBox.h"
38
39 #include "utilities.h"
40 #include "SALOME_Selection.h"
41 #include "SMESH_Actor.h"
42 #include "SMDS_Mesh.hxx"
43
44 #include <qframe.h>
45 #include <qlayout.h>
46 #include <qlineedit.h>
47 #include <qpushbutton.h>
48 #include <qgroupbox.h>
49 #include <qlabel.h>
50 #include <qmessagebox.h>
51 #include <qvalidator.h>
52
53
54 #define SPACING 5
55 #define MARGIN  10
56
57
58 /*
59   Class       : SMESHGUI_DiagValidator
60   Description : validate munual input of edge like "id1-id2"
61 */
62 class SMESHGUI_DiagValidator: public QValidator
63 {
64  public:
65
66   SMESHGUI_DiagValidator(QWidget * parent, const char * name = 0):
67     QValidator(parent,name) {}
68
69   State validate ( QString & text, int & pos) const
70   {
71     text.stripWhiteSpace();
72     text.replace( QRegExp("[^0-9]+"), "-" );
73     if ( text == "-" )
74       text = "";
75     int ind = text.find( QRegExp("-[0-9]+-"));
76     if ( ind > 0 ) { // leave only two ids
77       ind = text.find( '-', ind + 1 );
78       if ( ind > 0 )
79         text.truncate( ind );
80     }
81     if ( pos > text.length() )
82       pos = text.length();
83     return Acceptable;
84   }
85 };
86
87 /*
88   Class       : SMESHGUI_SingleEditDlg
89   Description : Inversion of the diagonal of a pseudo-quadrangle formed by 
90                 2 neighboring triangles with 1 common edge
91 */
92
93 //=======================================================================
94 // name    : SMESHGUI_SingleEditDlg::SMESHGUI_SingleEditDlg
95 // Purpose : Constructor
96 //=======================================================================
97 SMESHGUI_SingleEditDlg::SMESHGUI_SingleEditDlg( QWidget*          theParent, 
98                                                       SALOME_Selection* theSelection,
99                                                       const char*       theName )
100 : QDialog( theParent, theName, false, 
101            WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu )
102 {
103   //setCaption( tr( "CAPTION" ) );
104
105   QVBoxLayout* aDlgLay = new QVBoxLayout( this, MARGIN, SPACING );
106
107   QFrame* aMainFrame = createMainFrame  ( this );
108   QFrame* aBtnFrame  = createButtonFrame( this );
109
110   aDlgLay->addWidget( aMainFrame );
111   aDlgLay->addWidget( aBtnFrame );
112
113   aDlgLay->setStretchFactor( aMainFrame, 1 );
114
115   Init( theSelection ) ; 
116 }
117
118 //=======================================================================
119 // name    : SMESHGUI_SingleEditDlg::createMainFrame
120 // Purpose : Create frame containing dialog's input fields
121 //=======================================================================
122 QFrame* SMESHGUI_SingleEditDlg::createMainFrame( QWidget* theParent )
123 {
124   QGroupBox* aMainGrp = new QGroupBox( 1, Qt::Vertical, tr( "EDGE_BETWEEN" ), theParent );
125
126   QPixmap aPix( QAD_Desktop::getResourceManager()->loadPixmap( "SMESH",tr( "ICON_SELECT" ) ) );
127   
128   new QLabel( tr( "SMESH_EDGE" ), aMainGrp );
129   ( new QPushButton( aMainGrp ) )->setPixmap( aPix );
130   myEdge = new QLineEdit( aMainGrp );
131   myEdge->setValidator( new SMESHGUI_DiagValidator( this, "validator" ));
132
133   return aMainGrp;
134 }
135
136 //=======================================================================
137 // name    : SMESHGUI_SingleEditDlg::createButtonFrame
138 // Purpose : Create frame containing buttons
139 //=======================================================================
140 QFrame* SMESHGUI_SingleEditDlg::createButtonFrame( QWidget* theParent )
141 {
142   QFrame* aFrame = new QFrame( theParent );
143   aFrame->setFrameStyle( QFrame::Box | QFrame::Sunken );
144
145   myOkBtn     = new QPushButton( tr( "SMESH_BUT_OK"    ), aFrame );
146   myApplyBtn  = new QPushButton( tr( "SMESH_BUT_APPLY" ), aFrame );
147   myCloseBtn  = new QPushButton( tr( "SMESH_BUT_CLOSE" ), aFrame );
148
149   QSpacerItem* aSpacer = new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
150
151   QHBoxLayout* aLay = new QHBoxLayout( aFrame, MARGIN, SPACING );
152
153   aLay->addWidget( myOkBtn );
154   aLay->addWidget( myApplyBtn );
155   aLay->addItem( aSpacer);
156   aLay->addWidget( myCloseBtn );
157
158   return aFrame;
159 }
160
161 //=======================================================================
162 // name    : SMESHGUI_SingleEditDlg::isValid
163 // Purpose : Verify validity of input data
164 //=======================================================================
165 bool SMESHGUI_SingleEditDlg::isValid( const bool theMess ) const
166 {
167   int id1, id2;
168   return getNodeIds( myEdge->text(), id1, id2 );
169 }
170
171 //=======================================================================
172 // name    : SMESHGUI_SingleEditDlg::getNodeIds
173 // Purpose : Retrieve node ids from string
174 //=======================================================================
175 bool SMESHGUI_SingleEditDlg::getNodeIds( const QString& theStr, int& theId1, int&  theId2 ) const
176 {
177   if ( !theStr.contains( '-' ) )
178     return false;
179
180   bool ok1, ok2;
181   QString str1 = theStr.section( '-', 0, 0, QString::SectionSkipEmpty );
182   QString str2 = theStr.section( '-', 1, 1, QString::SectionSkipEmpty );
183   theId1 = str1.toInt( &ok1 );
184   theId2 = str2.toInt( &ok2 );
185   
186   return ok1 & ok2;
187 }
188
189 //=======================================================================
190 // name    : SMESHGUI_SingleEditDlg::~SMESHGUI_SingleEditDlg
191 // Purpose : Destructor
192 //=======================================================================
193 SMESHGUI_SingleEditDlg::~SMESHGUI_SingleEditDlg()
194 {
195 }
196
197 //=======================================================================
198 // name    : SMESHGUI_SingleEditDlg::Init
199 // Purpose : Init dialog fields, connect signals and slots, show dialog
200 //=======================================================================
201 void SMESHGUI_SingleEditDlg::Init( SALOME_Selection* theSelection )
202 {
203   mySelection = theSelection;  
204   SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI();
205   aSMESHGUI->SetActiveDialogBox( ( QDialog* )this ) ;
206   myBusy = false;
207   myActor = 0;
208  
209   // main buttons
210   connect( myOkBtn,    SIGNAL( clicked() ), SLOT( onOk() ) );
211   connect( myCloseBtn, SIGNAL( clicked() ), SLOT( onClose() ) ) ;
212   connect( myApplyBtn, SIGNAL( clicked() ), SLOT( onApply() ) );
213
214   // selection and SMESHGUI
215   connect( mySelection, SIGNAL( currentSelectionChanged() ), SLOT( onSelectionDone() ) );
216   connect( aSMESHGUI, SIGNAL( SignalDeactivateActiveDialog() ), SLOT( onDeactivate() ) );
217   connect( aSMESHGUI, SIGNAL( SignalCloseAllDialogs() ), SLOT( onClose() ) );
218   connect( myEdge, SIGNAL( textChanged(const QString&)), SLOT( onTextChange(const QString&)));
219
220   myOkBtn->setEnabled( false );
221   myApplyBtn->setEnabled( false );
222   setEnabled( true );
223
224   int x, y ;
225   aSMESHGUI->DefineDlgPosition( this, x, y );
226   this->move( x, y );
227   this->show(); 
228
229   // set selection mode
230   QAD_Application::getDesktop()->SetSelectionMode( EdgeOfCellSelection, true );
231
232   onSelectionDone();
233
234   return;
235 }
236
237 //=======================================================================
238 // name    : SMESHGUI_SingleEditDlg::onOk
239 // Purpose : SLOT called when "Ok" button pressed. 
240 //           Assign filters VTK viewer and close dialog
241 //=======================================================================
242 void SMESHGUI_SingleEditDlg::onOk()
243 {
244   if ( onApply() )
245     onClose();
246 }
247
248 //=======================================================================
249 // name    : SMESHGUI_SingleEditDlg::onClose
250 // Purpose : SLOT called when "Close" button pressed. Close dialog
251 //=======================================================================
252 void SMESHGUI_SingleEditDlg::onClose()
253 {
254   QAD_Application::getDesktop()->SetSelectionMode( ActorSelection );
255   mySelection->ClearIObjects();
256   disconnect( mySelection, 0, this, 0 );
257   disconnect( SMESHGUI::GetSMESHGUI(), 0, this, 0 );
258   SMESHGUI::GetSMESHGUI()->ResetState() ;
259   reject();
260 }
261
262 //=======================================================================
263 //function : findTriangles
264 //purpose  : find triangles sharing theNode1-theNode2 link
265 //    THIS IS A PIECE OF SMESH_MeshEditor.cxx
266 //    TO DO: make it available in SMDS for ex.
267 //=======================================================================
268
269 static bool findTriangles(const SMDS_MeshNode *    theNode1,
270                           const SMDS_MeshNode *    theNode2,
271                           const SMDS_MeshElement*& theTria1,
272                           const SMDS_MeshElement*& theTria2)
273 {
274   if ( !theNode1 || !theNode2 ) return false;
275
276   theTria1 = theTria2 = 0;
277
278   set< const SMDS_MeshElement* > emap;
279   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
280   while (it->more()) {
281     const SMDS_MeshElement* elem = it->next();
282     if ( elem->GetType() == SMDSAbs_Face && elem->NbNodes() == 3 )
283       emap.insert( elem );
284   }
285   it = theNode2->GetInverseElementIterator();
286   while (it->more()) {
287     const SMDS_MeshElement* elem = it->next();
288     if ( elem->GetType() == SMDSAbs_Face &&
289          emap.find( elem ) != emap.end() )
290       if ( theTria1 ) {
291         theTria2 = elem;
292         break;
293       } else {
294         theTria1 = elem;
295       }
296   }
297   return ( theTria1 && theTria2 );
298 }
299
300 //=======================================================================
301 //function : onTextChange
302 //purpose  : 
303 //=======================================================================
304
305 void SMESHGUI_SingleEditDlg::onTextChange( const QString& theNewText )
306 {
307   if ( myBusy ) return;
308
309   myOkBtn->setEnabled( false );
310   myApplyBtn->setEnabled( false );
311
312   // hilight entered edge
313   SMDS_Mesh* aMesh = 0;
314   if ( myActor )
315     aMesh = myActor->GetObject()->GetMesh();
316   if ( aMesh ) {
317
318     myBusy = true; // block onSelectionDone()
319     mySelection->ClearIObjects();
320     mySelection->AddIObject( myActor->getIO() );
321     myBusy = false;
322
323     QStringList aListId = QStringList::split( "-", theNewText, false);
324     if ( aListId.count() != 2 )
325       return;
326     const SMDS_MeshNode* a2Nodes[2];
327     bool allOk = true;
328     int i;
329     for ( i = 0; i < aListId.count(); i++ ) {
330       const SMDS_MeshNode * n = aMesh->FindNode( aListId[ i ].toInt() );
331       if ( n )
332         a2Nodes[ i ] = n;
333       else
334         allOk = false;
335     }
336
337     // find a triangle and an edge nb
338     const SMDS_MeshElement* tria[2];
339     if (allOk &&
340         a2Nodes[0] != a2Nodes[1] &&
341         findTriangles( a2Nodes[0],
342                       a2Nodes[1],
343                       tria[0],
344                       tria[1])) {
345       myBusy = true; // block onSelectionDone()
346       mySelection->AddOrRemoveIndex (myActor->getIO(), tria[0]->GetID(), true, false);
347
348       const SMDS_MeshNode* a3Nodes [3];
349       SMDS_ElemIteratorPtr it;
350       int edgeInd = 2;
351       for (i = 0, it = tria[0]->nodesIterator(); it->more(); i++ ) {
352         a3Nodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
353         if ( i > 0 )
354           if (( a3Nodes[ i ] == a2Nodes[ 0 ] && a3Nodes[ i - 1] == a2Nodes[ 1 ] ) ||
355               ( a3Nodes[ i ] == a2Nodes[ 1 ] && a3Nodes[ i - 1] == a2Nodes[ 0 ] ) ) {
356             edgeInd = i - 1;
357             break;
358           }
359       }
360
361       mySelection->AddOrRemoveIndex( myActor->getIO(), -edgeInd-1, true, true );
362       myBusy = false;
363
364       myOkBtn->setEnabled( true );
365       myApplyBtn->setEnabled( true );
366     }
367   }
368 }
369 //=======================================================================
370 // name    : SMESHGUI_SingleEditDlg::onSelectionDone
371 // Purpose : SLOT called when selection changed
372 //=======================================================================
373 void SMESHGUI_SingleEditDlg::onSelectionDone()
374 {
375   if ( myBusy ) return;
376
377   int anId1 = 0, anId2 = 0;
378
379   myOkBtn->setEnabled( false );
380   myApplyBtn->setEnabled( false );
381
382   if ( mySelection->IObjectCount() != 1 )
383   {
384     myEdge->clear();
385     return;
386   }
387
388   myActor = SMESH::FindActorByEntry( mySelection->firstIObject()->getEntry() );
389   SMDS_Mesh* aMesh = 0;
390   if ( myActor )
391     aMesh = myActor->GetObject()->GetMesh();
392   if ( !aMesh )
393     return;
394
395   if (SMESH::GetEdgeNodes( mySelection, anId1, anId2 ) >= 1 ) {
396     QString aText = QString( "%1-%2" ).arg( anId1 ).arg( anId2 );
397     myBusy = true;
398     myEdge->setText( aText );    
399     myBusy = false;
400
401     const SMDS_MeshElement* tria[2];
402     if ( findTriangles( aMesh->FindNode( anId1 ), aMesh->FindNode( anId2 ), tria[0],tria[1]))
403     {
404       myOkBtn->setEnabled( true );
405       myApplyBtn->setEnabled( true );
406     }
407   }
408   else
409     myEdge->clear();
410 }
411
412 //=======================================================================
413 // name    : SMESHGUI_SingleEditDlg::onDeactivate
414 // Purpose : SLOT called when dialog must be deativated
415 //=======================================================================
416 void SMESHGUI_SingleEditDlg::onDeactivate()
417 {
418   setEnabled( false );
419 }
420
421 //=======================================================================
422 // name    : SMESHGUI_SingleEditDlg::enterEvent
423 // Purpose : Event filter
424 //=======================================================================
425 void SMESHGUI_SingleEditDlg::enterEvent( QEvent* )
426 {
427   if ( !isEnabled() ) {
428     SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
429     // set selection mode
430     QAD_Application::getDesktop()->SetSelectionMode( EdgeOfCellSelection, true ); 
431     setEnabled( true );
432   }
433 }
434
435
436 //=================================================================================
437 // function : closeEvent()
438 // purpose  :
439 //=================================================================================
440 void SMESHGUI_SingleEditDlg::closeEvent( QCloseEvent* e )
441 {
442   onClose() ;
443 }
444 //=======================================================================
445 //function : hideEvent
446 //purpose  : caused by ESC key
447 //=======================================================================
448
449 void SMESHGUI_SingleEditDlg::hideEvent ( QHideEvent * e )
450 {
451   if ( !isMinimized() )
452     onClose();
453 }
454
455 //=================================================================================
456 // function : onApply
457 // purpose  : SLOT. Called when apply button is pressed
458 //=================================================================================
459 bool SMESHGUI_SingleEditDlg::onApply()
460 {
461   if (SMESHGUI::GetSMESHGUI()->ActiveStudyLocked())
462     return false;
463   // verify validity of input data
464   if ( !isValid( true ) )
465     return false;
466
467   // get mesh, actor and nodes    
468   SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO( mySelection->firstIObject() );
469
470   if ( aMesh->_is_nil() )
471   {
472     QMessageBox::information( SMESHGUI::GetSMESHGUI()->GetDesktop(),
473     tr( "SMESH_ERROR" ), tr( "SMESHG_NO_MESH" ), QMessageBox::Ok );
474     return false;
475   }
476
477   SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
478   int anId1= 0, anId2 = 0;
479   if ( aMeshEditor->_is_nil() || !getNodeIds( myEdge->text(), anId1, anId2 ) )
480     return false;
481
482   // perform operation
483   bool aResult = process( aMeshEditor.in(), anId1, anId2 );
484
485   // update actor
486   if ( aResult )
487   {
488     Handle(SALOME_InteractiveObject) anIO = mySelection->firstIObject();
489     mySelection->ClearIObjects();
490     SMESH::UpdateView();
491     mySelection->AddIObject( anIO, false );
492   }
493
494   return aResult;
495 }
496
497 /*
498   Class       : SMESHGUI_TrianglesInversionDlg
499   Description : Inversion of the diagonal of a pseudo-quadrangle formed by
500                 2 neighboring triangles with 1 common edge
501 */
502
503 SMESHGUI_TrianglesInversionDlg::SMESHGUI_TrianglesInversionDlg( QWidget*          theParent,
504                                                                 SALOME_Selection* theSelection,
505                                                                 const char*       theName )
506 : SMESHGUI_SingleEditDlg( theParent, theSelection, theName )
507 {
508   setCaption( tr( "CAPTION" ) );
509 }
510
511 SMESHGUI_TrianglesInversionDlg::~SMESHGUI_TrianglesInversionDlg()
512 {
513 }
514
515 bool SMESHGUI_TrianglesInversionDlg::process(
516   SMESH::SMESH_MeshEditor_ptr theMeshEditor, const int theId1, const int theId2 )
517 {
518   return theMeshEditor->InverseDiag( theId1, theId2 );
519 }
520
521 /*
522   Class       : SMESHGUI_UnionOfTwoTrianglesDlg
523   Description : Construction of a quadrangle by deletion of the 
524                 common border of 2 neighboring triangles
525 */
526
527 SMESHGUI_UnionOfTwoTrianglesDlg::SMESHGUI_UnionOfTwoTrianglesDlg( QWidget*          theParent, 
528                                                                   SALOME_Selection* theSelection,
529                                                                   const char*       theName )
530 : SMESHGUI_SingleEditDlg( theParent, theSelection, theName )
531 {
532   setCaption( tr( "CAPTION" ) );
533 }
534
535 SMESHGUI_UnionOfTwoTrianglesDlg::~SMESHGUI_UnionOfTwoTrianglesDlg()
536 {
537 }
538
539 bool SMESHGUI_UnionOfTwoTrianglesDlg::process(
540   SMESH::SMESH_MeshEditor_ptr theMeshEditor, const int theId1, const int theId2 )
541 {
542   return theMeshEditor->DeleteDiag( theId1, theId2 );
543 }
544