Salome HOME
Orientation of faces is added for new elements' preview (remark for issue 0017291...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_AddQuadraticElementDlg.cxx
1 // SMESH SMESHGUI : GUI for SMESH component
2 //
3 // Copyright (C) 2005  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.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File   : SMESHGUI_AddMeshElementDlg.cxx
23 // Author : Nicolas REJNERI, Open CASCADE S.A.S.
24 //
25
26 // SMESH includes
27 #include "SMESHGUI_AddQuadraticElementDlg.h"
28
29 #include "SMESHGUI.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include "SMESHGUI_MeshUtils.h"
33 #include "SMESHGUI_IdValidator.h"
34
35 #include <SMESH_Actor.h>
36 #include <SMESH_ActorUtils.h>
37 #include <SMESH_FaceOrientationFilter.h>
38 #include <SMDS_Mesh.hxx>
39
40 // SALOME GUI includes
41 #include <SUIT_Desktop.h>
42 #include <SUIT_Session.h>
43 #include <SUIT_MessageBox.h>
44 #include <SUIT_ResourceMgr.h>
45 #include <SUIT_ViewManager.h>
46
47 #include <LightApp_SelectionMgr.h>
48
49 #include <SVTK_ViewModel.h>
50 #include <SVTK_ViewWindow.h>
51
52 #include <SALOME_ListIO.hxx>
53
54 #include <SalomeApp_Application.h>
55
56 // IDL includes
57 #include <SALOMEconfig.h>
58 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
59
60 // OCCT includes
61 #include <TColStd_MapOfInteger.hxx>
62
63 // VTK includes
64 #include <vtkIdList.h>
65 #include <vtkUnstructuredGrid.h>
66 #include <vtkDataSetMapper.h>
67 #include <vtkPolyDataMapper.h>
68 #include <vtkProperty.h>
69 #include <vtkCellType.h>
70
71 // Qt includes
72 #include <QGroupBox>
73 #include <QLabel>
74 #include <QLineEdit>
75 #include <QPushButton>
76 #include <QRadioButton>
77 #include <QVBoxLayout>
78 #include <QHBoxLayout>
79 #include <QGridLayout>
80 #include <QCheckBox>
81 #include <QTableWidget>
82 #include <QKeyEvent>
83 #include <QButtonGroup>
84
85 // STL includes
86 #include <vector>
87
88 #define SPACING 6
89 #define MARGIN  11
90
91 namespace SMESH
92 {
93   void ReverseConnectivity( std::vector<int> & ids, int type )
94   {
95     // for reverse connectivity of other types keeping the first id, see
96     // void SMESH_VisualObjDef::buildElemPrs() in SMESH_Object.cxx:900
97     const int* conn = 0;
98    
99     switch ( type ) {
100     case QUAD_TETRAHEDRON: {
101       static int aConn[] = {0,2,1,3,6,5,4,7,9,8};
102       conn = aConn;
103       break;
104     }
105     case QUAD_PYRAMID: {
106       static int aConn[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
107       conn = aConn;
108       break;
109     }
110     case QUAD_PENTAHEDRON: {
111       static int aConn[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
112       conn = aConn;
113       break;
114     }
115     case QUAD_HEXAHEDRON: {
116       static int aConn[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
117       conn = aConn;
118       break;
119     }
120     case QUAD_EDGE: {
121       static int aConn[] = {1,0,2};
122       conn = aConn;
123       break;
124     }
125     case QUAD_TRIANGLE: {
126       static int aConn[] = {0,2,1,5,4,3};
127       conn = aConn;
128       break;
129     }
130     case QUAD_QUADRANGLE: {
131       static int aConn[] = {0,3,2,1,7,6,5,4};
132       conn = aConn;
133       break;
134     }
135     default:;
136     }
137     if ( !conn ) {
138       reverse( ids.begin(), ids.end() );
139     }
140     else {
141       std::vector<int> aRevIds( ids.size() );
142       for ( int i = 0; i < ids.size(); i++)
143         aRevIds[ i ] = ids[ conn[ i ]];
144       ids = aRevIds;
145     }
146   }
147
148   class TElementSimulation {
149     SalomeApp_Application* myApplication;
150     SUIT_ViewWindow* myViewWindow;
151     SVTK_ViewWindow* myVTKViewWindow;
152
153     SALOME_Actor* myPreviewActor;
154     vtkDataSetMapper* myMapper;
155     vtkUnstructuredGrid* myGrid;
156     //vtkProperty* myBackProp, *myProp;
157
158     vtkFloatingPointType myRGB[3], myBackRGB[3];
159
160     SALOME_Actor* myFaceOrientation;
161     vtkPolyDataMapper* myFaceOrientationDataMapper;
162     SMESH_FaceOrientationFilter* myFaceOrientationFilter;
163
164   public:
165     TElementSimulation (SalomeApp_Application* theApplication)
166     {
167       myApplication = theApplication;
168       SUIT_ViewManager* mgr = theApplication->activeViewManager();
169       if (!mgr) return;
170       myViewWindow = mgr->getActiveView();
171       myVTKViewWindow = GetVtkViewWindow(myViewWindow);
172
173       myGrid = vtkUnstructuredGrid::New();
174
175       // Create and display actor
176       myMapper = vtkDataSetMapper::New();
177       myMapper->SetInput(myGrid);
178
179       myPreviewActor = SALOME_Actor::New();
180       myPreviewActor->PickableOff();
181       myPreviewActor->VisibilityOff();
182       myPreviewActor->SetMapper(myMapper);
183
184       vtkProperty* myProp = vtkProperty::New();
185       GetColor( "SMESH", "fill_color", myRGB[0], myRGB[1], myRGB[2], QColor( 0, 170, 255 ) );
186       myProp->SetColor( myRGB[0], myRGB[1], myRGB[2] );
187       myPreviewActor->SetProperty( myProp );
188       myProp->Delete();
189
190       vtkProperty* myBackProp = vtkProperty::New();
191       GetColor( "SMESH", "backface_color", myBackRGB[0], myBackRGB[1], myBackRGB[2], QColor( 0, 0, 255 ) );
192       myBackProp->SetColor( myBackRGB[0], myBackRGB[1], myBackRGB[2] );
193       myPreviewActor->SetBackfaceProperty( myBackProp );
194       myBackProp->Delete();
195
196       myVTKViewWindow->AddActor(myPreviewActor);
197
198       // Orientation of faces
199       myFaceOrientationFilter = SMESH_FaceOrientationFilter::New();
200       myFaceOrientationFilter->SetInput(myGrid);
201
202       myFaceOrientationDataMapper = vtkPolyDataMapper::New();
203       myFaceOrientationDataMapper->SetInput(myFaceOrientationFilter->GetOutput());
204
205       myFaceOrientation = SALOME_Actor::New();
206       myFaceOrientation->PickableOff();
207       myFaceOrientation->VisibilityOff();
208       myFaceOrientation->SetMapper(myFaceOrientationDataMapper);
209
210       vtkProperty* anOrientationProp = vtkProperty::New();
211       GetColor( "SMESH", "orientation_color", myRGB[0], myRGB[1], myRGB[2], QColor( 255, 255, 255 ) );
212       anOrientationProp->SetColor( myRGB[0], myRGB[1], myRGB[2] );
213       myFaceOrientation->SetProperty( anOrientationProp );
214       anOrientationProp->Delete();
215
216       myVTKViewWindow->AddActor(myFaceOrientation);
217     }
218
219     typedef std::vector<vtkIdType> TVTKIds;
220     void SetPosition (SMESH_Actor* theActor,
221                       const int    theType,
222                       TVTKIds&     theIds,
223                       const int    theMode,
224                       const bool   theReverse)
225     {
226       vtkUnstructuredGrid *aGrid = theActor->GetUnstructuredGrid();
227       myGrid->SetPoints(aGrid->GetPoints());
228
229       //add points
230
231       vtkIdType aType = 0;
232
233       switch (theType) {
234       case QUAD_EDGE:
235         aType = VTK_QUADRATIC_EDGE;
236         break;
237       case QUAD_TRIANGLE:
238         aType = VTK_QUADRATIC_TRIANGLE; 
239         break;
240       case QUAD_QUADRANGLE:
241         aType = VTK_QUADRATIC_QUAD; 
242         break;
243       case QUAD_TETRAHEDRON:
244         aType = VTK_QUADRATIC_TETRA; 
245         break;
246       case QUAD_PYRAMID:
247         //aType = VTK_QUADRATIC_PYRAMID; // NOT SUPPORTED IN VTK4.2
248         aType = VTK_CONVEX_POINT_SET;
249         break;
250       case QUAD_PENTAHEDRON:
251         aType = VTK_QUADRATIC_WEDGE;
252         //aType = VTK_CONVEX_POINT_SET;
253         break; 
254       case QUAD_HEXAHEDRON:
255         aType = VTK_QUADRATIC_HEXAHEDRON;
256         break;
257       }
258
259       // take care of orientation
260       if ( aType == VTK_CONVEX_POINT_SET ) {
261         if ( theReverse && theMode == VTK_SURFACE ) {
262           //myPreviewActor->GetProperty()->SetColor( myBackRGB[0], myBackRGB[1], myBackRGB[2] );
263         }
264       }
265       else {
266         // VTK cell connectivity opposites the MED one for volumic elements
267         if( aType != VTK_QUADRATIC_WEDGE) {
268           if ( theIds.size() > 8 ? !theReverse : theReverse ) {
269             ReverseConnectivity( theIds, theType );
270           }
271         }
272         else if(theReverse)
273           ReverseConnectivity( theIds, theType );          
274       }
275             
276       myGrid->Reset();
277       vtkIdList *anIds = vtkIdList::New();
278       
279       for (int i = 0, iEnd = theIds.size(); i < iEnd; i++) {
280         anIds->InsertId(i,theIds[i]);
281         //std::cout << i<< ": " << theIds[i] << std::endl;
282       }
283       
284       myGrid->InsertNextCell(aType,anIds);
285       anIds->Delete();
286       
287       myGrid->Modified();
288
289       myPreviewActor->GetMapper()->Update();
290       myPreviewActor->SetRepresentation( theMode );
291       SetVisibility(true, theActor->GetFacesOriented());
292
293       // restore normal orientation
294       if ( aType == VTK_CONVEX_POINT_SET ) {
295         if ( theReverse  && theMode == VTK_SURFACE ) {
296           //myPreviewActor->GetProperty()->SetColor( myRGB[0], myRGB[1], myRGB[2] );
297         }
298       }
299     }
300
301
302     void SetVisibility (bool theVisibility, bool theShowOrientation = false)
303     {
304       myPreviewActor->SetVisibility(theVisibility);
305       myFaceOrientation->SetVisibility(theShowOrientation);
306       RepaintCurrentView();
307     }
308
309
310     ~TElementSimulation()
311     {
312       if (FindVtkViewWindow(myApplication->activeViewManager(), myViewWindow)) {
313         myVTKViewWindow->RemoveActor(myPreviewActor);
314         myVTKViewWindow->RemoveActor(myFaceOrientation);
315       }
316       myPreviewActor->Delete();
317       myFaceOrientation->Delete();
318
319       myMapper->RemoveAllInputs();
320       myMapper->Delete();
321
322       myFaceOrientationFilter->Delete();
323
324       myFaceOrientationDataMapper->RemoveAllInputs();
325       myFaceOrientationDataMapper->Delete();
326
327       myGrid->Delete();
328
329 //       myProp->Delete();
330 //       myBackProp->Delete();
331     }
332   };
333 }
334
335
336 // Define the sequences of ids
337 static int FirstEdgeIds[] = {0};
338 static int LastEdgeIds[] =  {1};
339
340 static int FirstTriangleIds[] = {0,1,2};
341 static int LastTriangleIds[] =  {1,2,0};
342
343 static int FirstQuadrangleIds[] = {0,1,2,3};
344 static int LastQuadrangleIds[] =  {1,2,3,0};
345
346 static int FirstTetrahedronIds[] = {0,1,2,3,3,3};
347 static int LastTetrahedronIds[] =  {1,2,0,0,1,2};
348
349 static int FirstPyramidIds[] = {0,1,2,3,4,4,4,4};
350 static int LastPyramidIds[] =  {1,2,3,0,0,1,2,3};
351
352 static int FirstPentahedronIds[] = {0,1,2,3,4,5,0,1,2};
353 static int LastPentahedronIds[] =  {1,2,0,4,5,3,3,4,5};
354
355 static int FirstHexahedronIds[] = {0,1,2,3,4,5,6,7,0,1,2,3};
356 static int LastHexahedronIds[] =  {1,2,3,0,5,6,7,4,4,5,6,7};
357
358
359
360 /*!
361   \class BusyLocker
362   \brief Simple 'busy state' flag locker.
363   \internal
364 */
365
366 class BusyLocker
367 {
368 public:
369   //! Constructor. Sets passed boolean flag to \c true.
370   BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; }
371   //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
372   ~BusyLocker() { myBusy = false; }
373 private:
374   bool& myBusy; //! External 'busy state' boolean flag
375 };
376
377 /*!
378   \class IdEditItem
379   \brief Simple editable table item.
380   \internal
381 */
382
383 class IdEditItem: public QTableWidgetItem
384 {
385 public:
386   IdEditItem(const QString& text );
387   ~IdEditItem();
388
389   QWidget* createEditor() const;
390 };
391
392 IdEditItem::IdEditItem(const QString& text )
393   : QTableWidgetItem(text, QTableWidgetItem::UserType+100)
394 {
395 }
396
397 IdEditItem::~IdEditItem()
398 {
399 }
400
401 QWidget* IdEditItem::createEditor() const
402 {
403   QLineEdit *aLineEdit = new QLineEdit(text(), tableWidget());
404   aLineEdit->setValidator( new SMESHGUI_IdValidator(tableWidget(), 1) );
405   return aLineEdit;
406 }
407
408 //=================================================================================
409 // function : SMESHGUI_AddQuadraticElementDlg()
410 // purpose  : constructor
411 //=================================================================================
412 SMESHGUI_AddQuadraticElementDlg::SMESHGUI_AddQuadraticElementDlg( SMESHGUI* theModule,
413                                                                   const int theType )
414   : QDialog( SMESH::GetDesktop( theModule ) ),
415     mySMESHGUI( theModule ),
416     mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ),
417     myType( theType ),
418     myBusy( false )
419 {
420   setModal( false );
421   setAttribute( Qt::WA_DeleteOnClose, true );
422
423   SalomeApp_Application* anApp = dynamic_cast<SalomeApp_Application*>
424     (SUIT_Session::session()->activeApplication());
425   
426   mySimulation = new SMESH::TElementSimulation (anApp);
427   mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
428
429   QString anElementName;
430
431   switch ( myType ) {
432   case QUAD_EDGE:
433     anElementName = QString("QUADRATIC_EDGE");
434     break;
435   case QUAD_TRIANGLE:
436     anElementName = QString("QUADRATIC_TRIANGLE");
437     break; 
438   case QUAD_QUADRANGLE:
439     anElementName = QString("QUADRATIC_QUADRANGLE");
440     break;
441   case QUAD_TETRAHEDRON:
442     anElementName = QString("QUADRATIC_TETRAHEDRON");
443     break;
444   case QUAD_PYRAMID:
445     anElementName = QString("QUADRATIC_PYRAMID");
446     break;
447   case QUAD_PENTAHEDRON:
448     anElementName = QString("QUADRATIC_PENTAHEDRON");
449     break;
450   case QUAD_HEXAHEDRON:
451     anElementName = QString("QUADRATIC_HEXAHEDRON");
452     break;
453   default:
454     myType = QUAD_EDGE;
455     anElementName = QString("QUADRATIC_EDGE");
456   }
457
458   QString iconName           = tr(QString("ICON_DLG_%1").arg(anElementName).toLatin1().data());
459   QString caption            = tr(QString("SMESH_ADD_%1_TITLE").arg(anElementName).toLatin1().data());
460   QString argumentsGrTitle   = tr(QString("SMESH_ADD_%1").arg(anElementName).toLatin1().data());
461   QString constructorGrTitle = tr(QString("SMESH_%1").arg(anElementName).toLatin1().data());
462   
463   QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", iconName));
464   QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT")));
465
466   setWindowTitle(caption);
467   
468   setSizeGripEnabled(true);
469
470   QVBoxLayout* aDialogLayout = new QVBoxLayout(this);
471   aDialogLayout->setSpacing(SPACING);
472   aDialogLayout->setMargin(MARGIN);
473
474   /***************************************************************/
475   GroupConstructors = new QGroupBox(constructorGrTitle, this);
476   QButtonGroup* ButtonGroup = new QButtonGroup(this);
477   QHBoxLayout* aGroupConstructorsLayout = new QHBoxLayout(GroupConstructors);
478   aGroupConstructorsLayout->setSpacing(SPACING);
479   aGroupConstructorsLayout->setMargin(MARGIN);
480
481   myRadioButton1 = new QRadioButton(GroupConstructors);
482   myRadioButton1->setIcon(image0);
483   aGroupConstructorsLayout->addWidget(myRadioButton1);
484   ButtonGroup->addButton(myRadioButton1, 0);
485
486   /***************************************************************/
487   GroupArguments = new QGroupBox(argumentsGrTitle, this);
488   QGridLayout* aGroupArgumentsLayout = new QGridLayout(GroupArguments);
489   aGroupArgumentsLayout->setSpacing(SPACING);
490   aGroupArgumentsLayout->setMargin(MARGIN);
491
492   QLabel* aCornerNodesLabel = new QLabel(tr("SMESH_CORNER_NODES"), GroupArguments);
493   mySelectButton = new QPushButton(GroupArguments);
494   mySelectButton->setIcon(image1);
495   myCornerNodes = new QLineEdit(GroupArguments);
496
497   myTable = new QTableWidget(GroupArguments);
498
499   myReverseCB = new QCheckBox(tr("SMESH_REVERSE"), GroupArguments);
500
501   aGroupArgumentsLayout->addWidget(aCornerNodesLabel, 0, 0);
502   aGroupArgumentsLayout->addWidget(mySelectButton,    0, 1);
503   aGroupArgumentsLayout->addWidget(myCornerNodes,     0, 2);
504   aGroupArgumentsLayout->addWidget(myTable,           1, 0, 1, 3); 
505   aGroupArgumentsLayout->addWidget(myReverseCB,       2, 0, 1, 3);
506   
507   /***************************************************************/
508   GroupButtons = new QGroupBox(this);
509   QHBoxLayout* aGroupButtonsLayout = new QHBoxLayout(GroupButtons);
510   aGroupButtonsLayout->setSpacing(SPACING);
511   aGroupButtonsLayout->setMargin(MARGIN);
512
513   buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons);
514   buttonOk->setAutoDefault(true);
515   buttonOk->setDefault(true);
516   buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons);
517   buttonApply->setAutoDefault(true);
518   buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons);
519   buttonCancel->setAutoDefault(true);
520   buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons);
521   buttonHelp->setAutoDefault(true);
522
523   aGroupButtonsLayout->addWidget(buttonOk);
524   aGroupButtonsLayout->addSpacing(10);
525   aGroupButtonsLayout->addWidget(buttonApply);
526   aGroupButtonsLayout->addSpacing(10);
527   aGroupButtonsLayout->addStretch();
528   aGroupButtonsLayout->addWidget(buttonCancel);
529   aGroupButtonsLayout->addWidget(buttonHelp);
530
531   /***************************************************************/
532   aDialogLayout->addWidget(GroupConstructors);
533   aDialogLayout->addWidget(GroupArguments);
534   aDialogLayout->addWidget(GroupButtons);
535
536   Init(); /* Initialisations */
537 }
538
539 //=================================================================================
540 // function : ~SMESHGUI_AddQuadraticElementDlg()
541 // purpose  : Destroys the object and frees any allocated resources
542 //=================================================================================
543 SMESHGUI_AddQuadraticElementDlg::~SMESHGUI_AddQuadraticElementDlg()
544 {
545   delete mySimulation;
546 }
547
548 //=================================================================================
549 // function : Init()
550 // purpose  :
551 //=================================================================================
552 void SMESHGUI_AddQuadraticElementDlg::Init()
553 {
554   myRadioButton1->setChecked(true);
555   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
556   
557   myActor = 0;
558
559   int aNumRows;
560
561   switch (myType) {
562   case QUAD_EDGE:
563     aNumRows = 1;
564     myNbCorners = 2;
565     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_edges
566     break;
567   case QUAD_TRIANGLE:
568     aNumRows = 3;
569     myNbCorners = 3;
570     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_triangles
571     break;
572   case QUAD_QUADRANGLE:
573     aNumRows = 4;
574     myNbCorners = 4;
575     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_quadrangles
576     break;
577   case QUAD_TETRAHEDRON:
578     aNumRows = 6;
579     myNbCorners = 4;
580     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_tetrahedrons
581     break;
582   case QUAD_PYRAMID:
583     aNumRows = 8;
584     myNbCorners = 5;
585     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_pyramids
586     break;
587   case QUAD_PENTAHEDRON:
588     aNumRows = 9;
589     myNbCorners = 6;
590     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_pentahedrons
591     break; 
592   case QUAD_HEXAHEDRON:
593     aNumRows = 12;
594     myNbCorners = 8;
595     myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_hexahedrons
596     break;
597   }
598     
599   myCornerNodes->setValidator(new SMESHGUI_IdValidator(this, myNbCorners));
600
601   /* initialize table */
602   myTable->setColumnCount(3);
603   myTable->setRowCount(aNumRows);
604
605   QStringList aColLabels;
606   aColLabels.append(tr("SMESH_FIRST"));
607   aColLabels.append(tr("SMESH_MIDDLE"));
608   aColLabels.append(tr("SMESH_LAST"));
609   myTable->setHorizontalHeaderLabels(aColLabels);
610   
611   for ( int col = 0; col < myTable->columnCount(); col++ )
612     myTable->setColumnWidth(col, 80);
613
614   //myTable->setColumnReadOnly(0, true); // VSR: TODO
615   //myTable->setColumnReadOnly(2, true); // VSR: TODO
616
617   myTable->setEnabled( false );
618   
619   for ( int row = 0; row < myTable->rowCount(); row++ )
620   {
621     myTable->setItem( row, 0, new QTableWidgetItem( "" ) );
622     myTable->item( row, 0 )->setFlags(0);
623
624     IdEditItem* anEditItem = new IdEditItem( "" );
625     anEditItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled);
626     myTable->setItem(row, 1, anEditItem);
627
628     myTable->setItem( row, 2, new QTableWidgetItem( "" ) );
629     myTable->item( row, 2 )->setFlags(0);
630   }
631   
632   /* signals and slots connections */
633   connect(mySelectButton, SIGNAL(clicked()), SLOT(SetEditCorners()));
634   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(SelectionIntoArgument()));
635   connect(myTable,        SIGNAL(cellDoubleClicked(int, int)), SLOT(onCellDoubleClicked(int, int)));
636   connect(myTable,        SIGNAL(cellChanged (int, int)), SLOT(onCellTextChange(int, int)));
637   connect(myCornerNodes,  SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&)));
638   connect(myReverseCB,    SIGNAL(stateChanged(int)), SLOT(onReverse(int)));
639
640   connect(buttonOk, SIGNAL(clicked()),     SLOT(ClickOnOk()));
641   connect(buttonCancel, SIGNAL(clicked()), SLOT(ClickOnCancel()));
642   connect(buttonApply, SIGNAL(clicked()),  SLOT(ClickOnApply()));
643   connect(buttonHelp, SIGNAL(clicked()),   SLOT(ClickOnHelp()));
644
645   connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), SLOT(DeactivateActiveDialog()));
646   connect(mySMESHGUI, SIGNAL (SignalStudyFrameChanged()), SLOT(ClickOnCancel()));
647
648   // set selection mode
649   SMESH::SetPointRepresentation(true);
650
651   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
652     aViewWindow->SetSelectionMode( NodeSelection );
653
654   SetEditCorners();
655 }
656
657 //=================================================================================
658 // function : ClickOnApply()
659 // purpose  :
660 //=================================================================================
661 void SMESHGUI_AddQuadraticElementDlg::ClickOnApply()
662 {
663   if ( mySMESHGUI->isActiveStudyLocked() || myBusy || !IsValid() )
664     return;
665
666   BusyLocker lock( myBusy );
667
668   std::vector<int> anIds;
669
670   switch (myType) {
671   case QUAD_EDGE:
672     anIds.push_back(myTable->item(0, 0)->text().toInt());
673     anIds.push_back(myTable->item(0, 2)->text().toInt());
674     anIds.push_back(myTable->item(0, 1)->text().toInt());
675     break;
676   case QUAD_TRIANGLE:
677   case QUAD_QUADRANGLE:
678   case QUAD_TETRAHEDRON:
679   case QUAD_PYRAMID:
680   case QUAD_PENTAHEDRON:
681   case QUAD_HEXAHEDRON:
682     for ( int row = 0; row < myNbCorners; row++ )
683       anIds.push_back(myTable->item(row, 0)->text().toInt());
684     for ( int row = 0; row < myTable->rowCount(); row++ )
685       anIds.push_back(myTable->item(row, 1)->text().toInt());
686     break;
687   }
688   if ( myReverseCB->isChecked())
689     SMESH::ReverseConnectivity( anIds, myType );
690     
691   int aNumberOfIds =  anIds.size();
692   SMESH::long_array_var anArrayOfIdeces = new SMESH::long_array;
693   anArrayOfIdeces->length( aNumberOfIds );
694     
695   for (int i = 0; i < aNumberOfIds; i++)
696     anArrayOfIdeces[i] = anIds[ i ];
697
698   SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
699   switch (myType) {
700   case QUAD_EDGE:
701     aMeshEditor->AddEdge(anArrayOfIdeces.inout()); break;
702   case QUAD_TRIANGLE:
703   case QUAD_QUADRANGLE:
704     aMeshEditor->AddFace(anArrayOfIdeces.inout()); break;
705   case QUAD_TETRAHEDRON:
706   case QUAD_PYRAMID:
707   case QUAD_PENTAHEDRON: 
708   case QUAD_HEXAHEDRON:
709     aMeshEditor->AddVolume(anArrayOfIdeces.inout()); break;
710   }
711     
712   SALOME_ListIO aList; aList.Append( myActor->getIO() );
713   mySelector->ClearIndex();
714   mySelectionMgr->setSelectedObjects( aList, false );
715
716   mySimulation->SetVisibility(false);
717   SMESH::UpdateView();
718     
719   UpdateTable();
720   SetEditCorners();
721
722   updateButtons();
723 }
724
725 //=================================================================================
726 // function : ClickOnOk()
727 // purpose  :
728 //=================================================================================
729 void SMESHGUI_AddQuadraticElementDlg::ClickOnOk()
730 {
731   ClickOnApply();
732   ClickOnCancel();
733 }
734
735 //=================================================================================
736 // function : ClickOnCancel()
737 // purpose  :
738 //=================================================================================
739 void SMESHGUI_AddQuadraticElementDlg::ClickOnCancel()
740 {
741   mySelectionMgr->clearSelected();
742   mySimulation->SetVisibility(false);
743   SMESH::SetPointRepresentation(false);
744   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
745     aViewWindow->SetSelectionMode( ActorSelection );
746   disconnect(mySelectionMgr, 0, this, 0);
747   mySMESHGUI->ResetState();
748   reject();
749 }
750
751 //=================================================================================
752 // function : ClickOnHelp()
753 // purpose  :
754 //=================================================================================
755 void SMESHGUI_AddQuadraticElementDlg::ClickOnHelp()
756 {
757   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
758   if (app) 
759     app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
760   else {
761     QString platform;
762 #ifdef WIN32
763     platform = "winapplication";
764 #else
765     platform = "application";
766 #endif
767     SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
768                              tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
769                              arg(app->resourceMgr()->stringValue("ExternalBrowser", 
770                                                                  platform)).
771                              arg(myHelpFileName));
772   }
773 }
774
775 //=================================================================================
776 // function : onTextChange()
777 // purpose  :
778 //=================================================================================
779 void SMESHGUI_AddQuadraticElementDlg::onTextChange (const QString& theNewText)
780 {
781   if (myBusy) return;
782   BusyLocker lock( myBusy );
783   
784   mySimulation->SetVisibility(false);
785
786   // hilight entered nodes
787   SMDS_Mesh* aMesh = 0;
788   if (myActor)
789     aMesh = myActor->GetObject()->GetMesh();
790
791   if (aMesh) {
792     TColStd_MapOfInteger newIndices;
793     
794     QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts);
795     bool allOk = true;
796     for (int i = 0; i < aListId.count(); i++) {
797       if ( const SMDS_MeshNode * n = aMesh->FindNode( aListId[ i ].toInt() ) )
798       {
799         newIndices.Add( n->GetID() );
800       }
801       else
802       {
803         allOk = false;
804         break;
805       }
806     }
807     
808     mySelector->AddOrRemoveIndex( myActor->getIO(), newIndices, false );
809     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
810       aViewWindow->highlight( myActor->getIO(), true, true );
811     
812     if ( sender() == myCornerNodes )
813       UpdateTable( allOk );
814   }
815   
816   updateButtons();
817   displaySimulation();
818 }
819
820 //=================================================================================
821 // function : SelectionIntoArgument()
822 // purpose  : Called when selection has changed
823 //=================================================================================
824 void SMESHGUI_AddQuadraticElementDlg::SelectionIntoArgument()
825 {
826   if (myBusy) return;
827   BusyLocker lock( myBusy );
828   
829   if ( myIsEditCorners )
830   {
831     // clear
832     myActor = 0;
833     
834     myCornerNodes->setText("");
835     
836     if (!GroupButtons->isEnabled()) // inactive
837       return;
838     
839     mySimulation->SetVisibility(false);
840       
841     // get selected mesh
842     SALOME_ListIO aList;
843     mySelectionMgr->selectedObjects(aList,SVTK_Viewer::Type());
844     
845     if (aList.Extent() != 1)
846     {
847       UpdateTable();
848       updateButtons();
849       return;
850     }
851       
852     Handle(SALOME_InteractiveObject) anIO = aList.First();
853     myMesh = SMESH::GetMeshByIO(anIO);
854     if (myMesh->_is_nil()) {
855       updateButtons();
856       return;
857     }
858       
859     myActor = SMESH::FindActorByEntry(anIO->getEntry());
860   
861   }
862   
863   if (!myActor) {
864     updateButtons();
865     return;
866   }
867   
868   // get selected nodes
869   QString aString = "";
870   int nbNodes = SMESH::GetNameOfSelectedNodes(mySelector,myActor->getIO(),aString);
871   
872   if ( myIsEditCorners )
873   {
874     myCornerNodes->setText(aString);
875     
876     UpdateTable();
877   }
878   else if ( myTable->isEnabled() && nbNodes == 1 )
879   {
880     int theRow = myTable->currentRow(), theCol = myTable->currentColumn();
881     if ( theCol == 1 )
882       myTable->item(theRow, 1)->setText(aString);
883   }
884   
885   updateButtons();
886   displaySimulation();
887 }
888
889 //=================================================================================
890 // function : displaySimulation()
891 // purpose  :
892 //=================================================================================
893 void SMESHGUI_AddQuadraticElementDlg::displaySimulation()
894 {
895   if ( IsValid() )
896   {
897     SMESH::TElementSimulation::TVTKIds anIds;
898     
899     // Collect ids from the dialog
900     int anID;
901     bool ok;
902     int aDisplayMode = VTK_SURFACE;
903     
904     if ( myType == QUAD_EDGE )
905     {
906       anIds.push_back( myActor->GetObject()->GetNodeVTKId( myTable->item(0, 0)->text().toInt() ) );
907       anIds.push_back( myActor->GetObject()->GetNodeVTKId( myTable->item(0, 2)->text().toInt() ) );
908       anID = myTable->item(0, 1)->text().toInt(&ok);
909       if (!ok) anID = myTable->item(0, 0)->text().toInt();
910       anIds.push_back( myActor->GetObject()->GetNodeVTKId(anID) );
911       aDisplayMode = VTK_WIREFRAME;
912     }
913     else
914     {
915       for ( int row = 0; row < myNbCorners; row++ )
916         anIds.push_back( myActor->GetObject()->GetNodeVTKId( myTable->item(row, 0)->text().toInt() ) );
917       
918       for ( int row = 0; row < myTable->rowCount(); row++ )
919       {
920         anID = myTable->item(row, 1)->text().toInt(&ok);
921         if (!ok) {
922           anID = myTable->item(row, 0)->text().toInt();
923           aDisplayMode = VTK_WIREFRAME;
924         }
925         anIds.push_back( myActor->GetObject()->GetNodeVTKId(anID) );
926       }
927     }
928     
929     mySimulation->SetPosition(myActor,myType,anIds,aDisplayMode,myReverseCB->isChecked());
930   }
931   else
932   {
933     mySimulation->SetVisibility(false);
934   }
935   SMESH::UpdateView();
936 }
937
938 //=================================================================================
939 // function : SetEditCorners()
940 // purpose  :
941 //=================================================================================
942 void SMESHGUI_AddQuadraticElementDlg::SetEditCorners()
943 {
944   myCornerNodes->setFocus();
945   myIsEditCorners = true;
946   SelectionIntoArgument();
947   updateButtons();
948 }
949
950 //=================================================================================
951 // function : DeactivateActiveDialog()
952 // purpose  :
953 //=================================================================================
954 void SMESHGUI_AddQuadraticElementDlg::DeactivateActiveDialog()
955 {
956   if (GroupConstructors->isEnabled()) {
957     GroupConstructors->setEnabled(false);
958     GroupArguments->setEnabled(false);
959     GroupButtons->setEnabled(false);
960     mySimulation->SetVisibility(false);
961     mySMESHGUI->ResetState();
962     mySMESHGUI->SetActiveDialogBox(0);
963   }
964 }
965
966 //=================================================================================
967 // function : ActivateThisDialog()
968 // purpose  :
969 //=================================================================================
970 void SMESHGUI_AddQuadraticElementDlg::ActivateThisDialog()
971 {
972   /* Emit a signal to deactivate the active dialog */
973   mySMESHGUI->EmitSignalDeactivateDialog();
974
975   GroupConstructors->setEnabled(true);
976   GroupArguments->setEnabled(true);
977   GroupButtons->setEnabled(true);
978
979   SMESH::SetPointRepresentation(true);
980
981   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
982     aViewWindow->SetSelectionMode( NodeSelection );
983   SelectionIntoArgument();
984 }
985
986 //=================================================================================
987 // function : enterEvent()
988 // purpose  :
989 //=================================================================================
990 void SMESHGUI_AddQuadraticElementDlg::enterEvent (QEvent*)
991 {
992   if (GroupConstructors->isEnabled())
993     return;
994   ActivateThisDialog();
995 }
996
997 //=================================================================================
998 // function : closeEvent()
999 // purpose  :
1000 //=================================================================================
1001 void SMESHGUI_AddQuadraticElementDlg::closeEvent (QCloseEvent*)
1002 {
1003   /* same than click on cancel button */
1004   ClickOnCancel();
1005 }
1006
1007 //=================================================================================
1008 // function : hideEvent()
1009 // purpose  : caused by ESC key
1010 //=================================================================================
1011 void SMESHGUI_AddQuadraticElementDlg::hideEvent (QHideEvent*)
1012 {
1013   if (!isMinimized())
1014     ClickOnCancel();
1015 }
1016
1017 //=================================================================================
1018 // function : onReverse()
1019 // purpose  :
1020 //=================================================================================
1021 void SMESHGUI_AddQuadraticElementDlg::onReverse (int state)
1022 {
1023   mySimulation->SetVisibility(false);
1024   displaySimulation();
1025   updateButtons();
1026 }
1027
1028
1029 //=================================================================================
1030 // function : IsValid()
1031 // purpose  :
1032 //=================================================================================
1033 bool SMESHGUI_AddQuadraticElementDlg::IsValid()
1034 {
1035   SMDS_Mesh* aMesh = 0;
1036   if (myActor)
1037     aMesh = myActor->GetObject()->GetMesh();
1038   if (!aMesh)
1039     return false;
1040
1041   bool ok;
1042   
1043   for ( int row = 0; row < myTable->rowCount(); row++ )
1044   {
1045     int anID =  myTable->item(row, 1)->text().toInt(&ok);
1046     if ( !ok )
1047       return false;
1048     
1049     const SMDS_MeshNode * aNode = aMesh->FindNode(anID);
1050     if ( !aNode )
1051       return false;
1052   }
1053   
1054   return true;
1055 }
1056
1057 //=================================================================================
1058 // function : UpdateTable()
1059 // purpose  :
1060 //=================================================================================
1061 void SMESHGUI_AddQuadraticElementDlg::UpdateTable( bool theConersValidity )
1062 {
1063   QStringList aListCorners = myCornerNodes->text().split(" ", QString::SkipEmptyParts);
1064   
1065   if ( aListCorners.count() == myNbCorners && theConersValidity )
1066   {
1067     myTable->setEnabled( true );
1068     
1069     // clear the Middle column 
1070     for ( int row = 0; row < myTable->rowCount(); row++ )
1071       myTable->item( row, 1 )->setText("");
1072     
1073     int* aFirstColIds;
1074     int* aLastColIds;
1075     
1076     switch (myType) {
1077     case QUAD_EDGE:
1078       aFirstColIds = FirstEdgeIds;
1079       aLastColIds  = LastEdgeIds;
1080       break;
1081     case QUAD_TRIANGLE:
1082       aFirstColIds = FirstTriangleIds;
1083       aLastColIds  = LastTriangleIds;
1084       break;
1085     case QUAD_QUADRANGLE:
1086       aFirstColIds = FirstQuadrangleIds;
1087       aLastColIds  = LastQuadrangleIds;
1088       break;
1089     case QUAD_TETRAHEDRON:
1090       aFirstColIds = FirstTetrahedronIds;
1091       aLastColIds  = LastTetrahedronIds;
1092       break;
1093     case QUAD_PYRAMID:
1094       aFirstColIds = FirstPyramidIds;
1095       aLastColIds  = LastPyramidIds;
1096       break;
1097     case QUAD_PENTAHEDRON:
1098       aFirstColIds = FirstPentahedronIds;
1099       aLastColIds  = LastPentahedronIds;
1100       break; 
1101     case QUAD_HEXAHEDRON:
1102       aFirstColIds = FirstHexahedronIds;
1103       aLastColIds  = LastHexahedronIds;
1104       break;
1105     }
1106     
1107     // fill the First and the Last columns
1108     for (int i = 0, iEnd = myTable->rowCount(); i < iEnd; i++)
1109       myTable->item( i, 0 )->setText( aListCorners[ aFirstColIds[i] ] );
1110     
1111     for (int i = 0, iEnd = myTable->rowCount(); i < iEnd; i++)
1112       myTable->item( i, 2 )->setText( aListCorners[ aLastColIds[i] ] );
1113   }
1114   else
1115   {
1116     // clear table
1117     for ( int row = 0; row < myTable->rowCount(); row++ )
1118       for ( int col = 0; col < myTable->columnCount(); col++ )
1119         if ( QTableWidgetItem* aTWI = myTable->item(row, col) ) aTWI->setText("");
1120     
1121     myTable->setEnabled( false );
1122   }
1123 }
1124
1125
1126 //=================================================================================
1127 // function : onTableActivate()
1128 // purpose  :
1129 //=================================================================================
1130 void SMESHGUI_AddQuadraticElementDlg::onCellDoubleClicked( int theRow, int theCol )
1131 {
1132   myIsEditCorners = false;
1133   displaySimulation();
1134   updateButtons();
1135 }
1136
1137
1138 //=================================================================================
1139 // function : onCellTextChange()
1140 // purpose  :
1141 //=================================================================================
1142 void SMESHGUI_AddQuadraticElementDlg::onCellTextChange(int theRow, int theCol)
1143 {
1144   myIsEditCorners = false;
1145   displaySimulation();
1146   updateButtons();
1147 }
1148
1149 //=================================================================================
1150 // function : keyPressEvent()
1151 // purpose  :
1152 //=================================================================================
1153 void SMESHGUI_AddQuadraticElementDlg::keyPressEvent( QKeyEvent* e )
1154 {
1155   QDialog::keyPressEvent( e );
1156   if ( e->isAccepted() )
1157     return;
1158
1159   if ( e->key() == Qt::Key_F1 ) {
1160     e->accept();
1161     ClickOnHelp();
1162   }
1163 }
1164
1165 void SMESHGUI_AddQuadraticElementDlg::updateButtons()
1166 {
1167   bool valid = IsValid();
1168   buttonOk->setEnabled( valid );
1169   buttonApply->setEnabled( valid );
1170 }