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