Salome HOME
Modify 'Modification of orientation' dialog box: implement processing of 'Bad oriente...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MultiEditDlg.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_MultiEditDlg.cxx
25 //  Author : Sergey LITONIN
26 //  Module : SMESH
27
28 #include "SMESHGUI_MultiEditDlg.h"
29 #include "SMESHGUI_FilterDlg.h"
30 #include "SMESHGUI_Filter.h"
31
32 #include "SMESHGUI.h"
33 #include "SMESHGUI_Utils.h"
34 #include "SMESHGUI_VTKUtils.h"
35 #include "SMESHGUI_MeshUtils.h"
36
37 #include "QAD_Desktop.h"
38 #include "QAD_RightFrame.h"
39
40 #include "VTKViewer_ViewFrame.h"
41
42 #include "SMESH_Actor.h"
43 #include "SMDS_Mesh.hxx"
44 #include "SMDS_MeshElement.hxx"
45
46 #include "SALOME_Selection.h"
47 #include "SALOME_ListIteratorOfListIO.hxx"
48 #include "VTKViewer_InteractorStyleSALOME.h"
49
50 #include <vtkCell3D.h>
51 #include <vtkQuad.h>
52 #include <vtkTriangle.h>
53 #include <vtkIdList.h>
54 #include <vtkIntArray.h>
55 #include <vtkCellArray.h>
56 #include <vtkUnsignedCharArray.h>
57 #include <vtkUnstructuredGrid.h>
58 #include <vtkDataSetMapper.h>
59
60 #include <TColStd_IndexedMapOfInteger.hxx>
61 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
62 #include <Precision.hxx>
63 #include <TColStd_DataMapOfIntegerInteger.hxx>
64
65 #include <qcheckbox.h>
66 #include <qframe.h>
67 #include <qgroupbox.h>
68 #include <qlabel.h>
69 #include <qlayout.h>
70 #include <qlineedit.h>
71 #include <qlistbox.h>
72 #include <qpushbutton.h>
73 #include <qapplication.h>
74 #include <qhbuttongroup.h>
75 #include <qradiobutton.h>
76
77 // IDL Headers
78 #include "SALOMEconfig.h"
79 #include CORBA_SERVER_HEADER(SMESH_Group)
80
81 #define SPACING 5
82 #define MARGIN  10
83
84 /*
85   Class       : SMESHGUI_MultiEditDlg
86   Description : Description : Inversion of the diagonal of a pseudo-quadrangle formed by 
87                 2 neighboring triangles with 1 common edge
88 */
89
90 //=======================================================================
91 // name    : SMESHGUI_MultiEditDlg::SMESHGUI_MultiEditDlg
92 // Purpose : Constructor
93 //=======================================================================
94 SMESHGUI_MultiEditDlg::SMESHGUI_MultiEditDlg( QWidget*              theParent, 
95                                               SALOME_Selection*     theSelection,
96                                               const int             theMode,
97                                               const bool            the3d2d,
98                                               const char*           theName )
99 : QDialog( theParent, theName, false, 
100            WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu )
101 {
102   myFilterDlg = 0;
103   mySubmeshFilter = new SMESH_TypeFilter( SUBMESH );
104   myGroupFilter = new SMESH_TypeFilter( GROUP );
105
106   myEntityType = 0;
107
108   myFilterType = theMode;
109   QVBoxLayout* aDlgLay = new QVBoxLayout( this, MARGIN, SPACING );
110
111   QFrame* aMainFrame = createMainFrame  ( this, the3d2d );
112   QFrame* aBtnFrame  = createButtonFrame( this );
113
114   aDlgLay->addWidget( aMainFrame );
115   aDlgLay->addWidget( aBtnFrame );
116
117   aDlgLay->setStretchFactor( aMainFrame, 1 );
118   aDlgLay->setStretchFactor( aBtnFrame, 0 );
119   Init( theSelection ) ;
120 }
121
122 //=======================================================================
123 // name    : SMESHGUI_MultiEditDlg::createMainFrame
124 // Purpose : Create frame containing dialog's input fields
125 //=======================================================================
126 QFrame* SMESHGUI_MultiEditDlg::createMainFrame( QWidget* theParent, const bool the3d2d )
127 {
128   QGroupBox* aMainGrp = new QGroupBox( 1, Qt::Horizontal, theParent );
129   aMainGrp->setFrameStyle( QFrame::NoFrame );
130   aMainGrp->setInsideMargin( 0 );
131
132   QPixmap aPix( QAD_Desktop::getResourceManager()->loadPixmap( "SMESH",tr( "ICON_SELECT" ) ) );
133   
134   // "Selected cells" group
135   mySelGrp = new QGroupBox( 1, Qt::Horizontal,  aMainGrp );
136
137   myEntityTypeGrp = 0;
138   if ( the3d2d ) {
139     myEntityTypeGrp = new QHButtonGroup( tr("SMESH_ELEMENTS_TYPE"), mySelGrp );
140     (new QRadioButton( tr("SMESH_FACE"),   myEntityTypeGrp ))->setChecked( true );
141     (new QRadioButton( tr("SMESH_VOLUME"), myEntityTypeGrp ));
142     myEntityType = myEntityTypeGrp->id( myEntityTypeGrp->selected() );
143   }
144
145   QFrame* aFrame = new QFrame( mySelGrp );
146   
147   myListBox = new QListBox( aFrame );
148   myListBox->setSelectionMode( QListBox::Extended );
149   myListBox->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) );
150 //  myListBox->setColumnMode( QListBox::FitToHeight );
151   
152   myFilterBtn = new QPushButton( tr( "FILTER" )   , aFrame );
153   myAddBtn    = new QPushButton( tr( "ADD" )      , aFrame );
154   myRemoveBtn = new QPushButton( tr( "REMOVE" )   , aFrame );
155   mySortBtn   = new QPushButton( tr( "SORT_LIST" ), aFrame );
156
157   QGridLayout* aLay = new QGridLayout( aFrame, 5, 2, 0, 5 );
158   aLay->addMultiCellWidget( myListBox, 0, 4, 0, 0 );
159   aLay->addWidget( myFilterBtn, 0, 1 );
160   aLay->addWidget( myAddBtn, 1, 1 );
161   aLay->addWidget( myRemoveBtn, 2, 1 );
162   aLay->addWidget( mySortBtn, 3, 1 );
163   
164   QSpacerItem* aSpacer = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding );
165   aLay->addItem( aSpacer, 4, 1 );
166   
167   myToAllChk = new QCheckBox( tr( "TO_ALL" ), mySelGrp );
168
169   // "Select from" group
170   QGroupBox* aGrp = new QGroupBox( 3, Qt::Horizontal, tr( "SELECT_FROM" ), aMainGrp );
171   
172   mySubmeshChk = new QCheckBox( tr( "SMESH_SUBMESH" ), aGrp );
173   mySubmeshBtn = new QPushButton( aGrp );
174   mySubmesh = new QLineEdit( aGrp );
175   mySubmesh->setReadOnly( true );
176   mySubmeshBtn->setPixmap( aPix );
177   
178   myGroupChk = new QCheckBox( tr( "GROUP" ), aGrp );
179   myGroupBtn = new QPushButton( aGrp );
180   myGroup = new QLineEdit( aGrp );
181   myGroup->setReadOnly( true );
182   myGroupBtn->setPixmap( aPix );
183
184   return aMainGrp;
185 }
186
187 //=======================================================================
188 // name    : SMESHGUI_MultiEditDlg::createButtonFrame
189 // Purpose : Create frame containing buttons
190 //=======================================================================
191 QFrame* SMESHGUI_MultiEditDlg::createButtonFrame( QWidget* theParent )
192 {
193   QFrame* aFrame = new QFrame( theParent );
194   aFrame->setFrameStyle( QFrame::Box | QFrame::Sunken );
195
196   myOkBtn     = new QPushButton( tr( "SMESH_BUT_OK"    ), aFrame );
197   myApplyBtn  = new QPushButton( tr( "SMESH_BUT_APPLY" ), aFrame );
198   myCloseBtn  = new QPushButton( tr( "SMESH_BUT_CLOSE" ), aFrame );
199
200   QSpacerItem* aSpacer = new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
201
202   QHBoxLayout* aLay = new QHBoxLayout( aFrame, MARGIN, SPACING );
203
204   aLay->addWidget( myOkBtn );
205   aLay->addWidget( myApplyBtn );
206   aLay->addItem( aSpacer);
207   aLay->addWidget( myCloseBtn );
208
209   return aFrame;
210 }
211
212 //=======================================================================
213 // name    : SMESHGUI_MultiEditDlg::isValid
214 // Purpose : Verify validity of input data
215 //=======================================================================
216 bool SMESHGUI_MultiEditDlg::isValid( const bool /*theMess*/ ) const
217 {
218   return (!myMesh->_is_nil() &&
219           (myListBox->count() > 0 || (myToAllChk->isChecked() && myActor)));
220 }
221
222 //=======================================================================
223 // name    : SMESHGUI_MultiEditDlg::~SMESHGUI_MultiEditDlg
224 // Purpose : Destructor
225 //=======================================================================
226 SMESHGUI_MultiEditDlg::~SMESHGUI_MultiEditDlg()
227 {
228   if ( myFilterDlg != 0 )
229   {
230     myFilterDlg->reparent( 0, QPoint() );
231     delete myFilterDlg;
232   }
233 }
234
235 //=======================================================================
236 // name    : SMESHGUI_MultiEditDlg::Init
237 // Purpose : Init dialog fields, connect signals and slots, show dialog
238 //=======================================================================
239 void SMESHGUI_MultiEditDlg::Init( SALOME_Selection* theSelection )
240 {
241   SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI();
242   mySelection = theSelection;
243   aSMESHGUI->SetActiveDialogBox( ( QDialog* )this ) ;
244   myListBox->clear();
245   myIds.Clear();
246   myBusy = false;
247   myActor = 0;
248   emit ListContensChanged();
249
250   // main buttons
251   connect( myOkBtn,    SIGNAL( clicked() ), SLOT( onOk() ) );
252   connect( myCloseBtn, SIGNAL( clicked() ), SLOT( onClose() ) ) ;
253   connect( myApplyBtn, SIGNAL( clicked() ), SLOT( onApply() ) );
254
255   // selection and SMESHGUI
256   connect( mySelection, SIGNAL( currentSelectionChanged() ), SLOT( onSelectionDone() ) );
257   connect( aSMESHGUI, SIGNAL( SignalDeactivateActiveDialog() ), SLOT( onDeactivate() ) );
258   connect( aSMESHGUI, SIGNAL( SignalCloseAllDialogs() ), SLOT( onClose() ) );
259
260   // dialog controls
261   connect( myFilterBtn, SIGNAL( clicked() ), SLOT( onFilterBtn()   ) );
262   connect( myAddBtn   , SIGNAL( clicked() ), SLOT( onAddBtn()      ) );
263   connect( myRemoveBtn, SIGNAL( clicked() ), SLOT( onRemoveBtn()   ) );
264   connect( mySortBtn  , SIGNAL( clicked() ), SLOT( onSortListBtn() ) );
265   
266   connect( mySubmeshChk, SIGNAL( stateChanged( int ) ), SLOT( onSubmeshChk() ) );
267   connect( myGroupChk  , SIGNAL( stateChanged( int ) ), SLOT( onGroupChk()   ) );
268   connect( myToAllChk  , SIGNAL( stateChanged( int ) ), SLOT( onToAllChk()   ) );
269
270   if ( myEntityTypeGrp )
271     connect( myEntityTypeGrp, SIGNAL( clicked(int) ), SLOT( on3d2dChanged(int) ) );
272
273   connect( myListBox, SIGNAL( selectionChanged() ), SLOT( onListSelectionChanged() ) );
274
275   onSelectionDone();
276
277   // set selection mode
278   setSelectionMode();
279   updateButtons();
280 }
281
282 //=======================================================================
283 // name    : SMESHGUI_MultiEditDlg::onOk
284 // Purpose : SLOT called when "Ok" button pressed. 
285 //           Assign filters VTK viewer and close dialog
286 //=======================================================================
287 void SMESHGUI_MultiEditDlg::onOk()
288 {
289   if ( onApply() )
290     onClose();
291 }
292
293 //=======================================================================
294 // name    : SMESHGUI_MultiEditDlg::getIds
295 // Purpose : Retrive identifiers from list box
296 //=======================================================================
297 SMESH::long_array_var SMESHGUI_MultiEditDlg::getIds()
298 {
299   SMESH::long_array_var anIds = new SMESH::long_array;
300   
301   if ( myToAllChk->isChecked() )
302   {
303     myIds.Clear();
304     if ( myActor != 0 )
305     {
306       TVisualObjPtr aVisualObj = myActor->GetObject();
307       vtkUnstructuredGrid* aGrid = aVisualObj->GetUnstructuredGrid();
308       if ( aGrid != 0 )
309       {
310         for ( int i = 0, n = aGrid->GetNumberOfCells(); i < n; i++ )
311         {
312           vtkCell* aCell = aGrid->GetCell( i );
313           if ( aCell != 0 )
314           {
315             vtkTriangle* aTri = vtkTriangle::SafeDownCast(aCell);
316             vtkQuad*     aQua = vtkQuad::SafeDownCast(aCell);
317             vtkCell3D*   a3d  = vtkCell3D::SafeDownCast(aCell);
318
319             if ( aTri && myFilterType == SMESHGUI_TriaFilter || 
320                  aQua && myFilterType == SMESHGUI_QuadFilter ||
321                  ( aTri || aQua ) && myFilterType == SMESHGUI_FaceFilter ||
322                  a3d && myFilterType == SMESHGUI_VolumeFilter )
323             {
324               int anObjId = aVisualObj->GetElemObjId( i );
325               myIds.Add( anObjId );
326             }
327           }
328         }
329       }
330     }
331   }
332
333   anIds->length( myIds.Extent() );
334   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
335   for ( int i = 0; anIter.More(); anIter.Next()  )
336   {
337     anIds[ i++ ] = anIter.Key();
338   }
339   return anIds._retn();
340 }
341
342 //=======================================================================
343 // name    : SMESHGUI_MultiEditDlg::onClose
344 // Purpose : SLOT called when "Close" button pressed. Close dialog
345 //=======================================================================
346 void SMESHGUI_MultiEditDlg::onClose()
347 {
348   QAD_Application::getDesktop()->SetSelectionMode( ActorSelection );
349   disconnect( mySelection, 0, this, 0 );
350   disconnect( SMESHGUI::GetSMESHGUI(), 0, this, 0 );
351   SMESHGUI::GetSMESHGUI()->ResetState();
352   
353   SMESH::RemoveFilter(SMESHGUI_EdgeFilter);
354   SMESH::RemoveFilter(SMESHGUI_FaceFilter);
355   SMESH::RemoveFilter(SMESHGUI_VolumeFilter);
356   SMESH::RemoveFilter(SMESHGUI_QuadFilter);
357   SMESH::RemoveFilter(SMESHGUI_TriaFilter);
358   SMESH::SetPickable();
359
360   mySelection->ClearIObjects();
361   mySelection->ClearFilters();
362   
363   reject();
364 }
365
366 //=======================================================================
367 // name    : SMESHGUI_MultiEditDlg::onSelectionDone
368 // Purpose : SLOT called when selection changed
369 //=======================================================================
370 void SMESHGUI_MultiEditDlg::onSelectionDone()
371 {
372   if ( myBusy || !isEnabled() ) return;
373   myBusy = true;
374
375   int nbSel = mySelection->IObjectCount();
376   myListBox->clearSelection();
377
378   if ( mySubmeshChk->isChecked() || myGroupChk->isChecked() )
379   {
380     QLineEdit* aNameEdit = mySubmeshChk->isChecked() ? mySubmesh : myGroup;
381     int nbSel = mySelection->IObjectCount();
382     if ( nbSel == 1 )
383     {
384       Handle(SALOME_InteractiveObject) anIO = mySelection->firstIObject();
385       anIO.IsNull() ? aNameEdit->clear() : aNameEdit->setText( anIO->getName() );
386
387       if ( mySubmeshChk->isChecked() )
388       {
389         SMESH::SMESH_subMesh_var aSubMesh =
390           SMESH::IObjectToInterface<SMESH::SMESH_subMesh>( anIO );
391         if ( !aSubMesh->_is_nil() )
392           myMesh = aSubMesh->GetFather();
393       }
394       else
395       {
396         SMESH::SMESH_GroupBase_var aGroup =
397           SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>( anIO );
398         if ( !aGroup->_is_nil() )
399           myMesh = aGroup->GetMesh();
400       }
401     }
402     else if ( nbSel > 1 )
403     {
404       QString aStr = mySubmeshChk->isChecked() ? 
405         tr( "SMESH_SUBMESH_SELECTED" ) : tr( "SMESH_GROUP_SELECTED" );
406       aNameEdit->setText( aStr.arg( nbSel ) );
407     }
408     else
409       aNameEdit->clear();
410   }
411   else if ( nbSel == 1 )
412   {
413     QString aListStr = "";
414     int aNbItems = SMESH::GetNameOfSelectedElements(mySelection, aListStr);
415     if ( aNbItems > 0 )
416     {
417       QStringList anElements = QStringList::split(" ", aListStr);
418       QListBoxItem* anItem = 0;
419       for ( QStringList::iterator it = anElements.begin(); it != anElements.end(); ++it)
420       {
421         anItem = myListBox->findItem( *it, Qt::ExactMatch );
422         if (anItem) myListBox->setSelected( anItem, true );
423       }
424     }
425
426     myMesh = SMESH::GetMeshByIO( mySelection->firstIObject() );
427   }
428
429   if ( nbSel == 1 ) {
430     myActor = SMESH::FindActorByEntry(mySelection->firstIObject()->getEntry());
431     if (!myActor)
432       myActor = SMESH::FindActorByObject( myMesh );
433     VTKViewer_InteractorStyleSALOME* aStyle = SMESH::GetInteractorStyle();
434     Handle(VTKViewer_Filter) aFilter1 = aStyle->GetFilter( myFilterType );
435     Handle(VTKViewer_Filter) aFilter2 = aStyle->GetFilter( SMESHGUI_FaceFilter );
436     if ( !aFilter1.IsNull() )
437       aFilter1->SetActor( myActor );
438     if ( !aFilter2.IsNull() )
439       aFilter2->SetActor( myActor );
440     if ( myActor )
441       SMESH::SetPickable(myActor);
442   }
443   myBusy = false;
444
445   updateButtons();
446 }
447
448 //=======================================================================
449 // name    : SMESHGUI_MultiEditDlg::onDeactivate
450 // Purpose : SLOT called when dialog must be deativated
451 //=======================================================================
452 void SMESHGUI_MultiEditDlg::onDeactivate()
453 {
454   setEnabled( false );
455 }
456
457 //=======================================================================
458 // name    : SMESHGUI_MultiEditDlg::enterEvent
459 // Purpose : Event filter
460 //=======================================================================
461 void SMESHGUI_MultiEditDlg::enterEvent( QEvent* )
462 {
463   if ( !isEnabled() ) {
464     SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
465     setEnabled( true );
466     setSelectionMode();
467   }
468 }
469
470
471 //=================================================================================
472 // function : closeEvent()
473 // purpose  :
474 //=================================================================================
475 void SMESHGUI_MultiEditDlg::closeEvent( QCloseEvent* e )
476 {
477   onClose() ;
478 }
479 //=======================================================================
480 //function : hideEvent
481 //purpose  : caused by ESC key
482 //=======================================================================
483
484 void SMESHGUI_MultiEditDlg::hideEvent ( QHideEvent * e )
485 {
486   if ( !isMinimized() )
487     onClose();
488 }
489
490 //=======================================================================
491 // name    : SMESHGUI_MultiEditDlg::onFilterBtn
492 // Purpose : SLOT. Called when "Filter" button pressed.
493 //           Start "Selection filters" dialog
494 //=======================================================================
495 void SMESHGUI_MultiEditDlg::onFilterBtn()
496 {
497   if ( myFilterDlg == 0 )
498   {
499     myFilterDlg = new SMESHGUI_FilterDlg( (QWidget*)parent(), entityType() ? SMESH::VOLUME : SMESH::FACE );
500     connect( myFilterDlg, SIGNAL( Accepted() ), SLOT( onFilterAccepted() ) );
501   }
502   else
503     myFilterDlg->Init( entityType() ? SMESH::VOLUME : SMESH::FACE );
504
505   myFilterDlg->SetSelection( mySelection );
506   myFilterDlg->SetMesh( myMesh );
507   myFilterDlg->SetSourceWg( myListBox );
508
509   myFilterDlg->show();
510 }
511
512 //=================================================================================
513 // function : onFilterAccepted()
514 // purpose  : SLOT. Called when Filter dlg closed with OK button.
515 //            Uncheck "Select submesh" and "Select group" checkboxes
516 //=================================================================================
517 void SMESHGUI_MultiEditDlg::onFilterAccepted()
518 {
519   myIds.Clear();
520   for ( int i = 0, n = myListBox->count(); i < n; i++ )
521     myIds.Add( myListBox->text( i ).toInt() );
522
523   emit ListContensChanged();
524
525   if ( mySubmeshChk->isChecked() || myGroupChk->isChecked() )
526   {
527     mySubmeshChk->blockSignals( true );
528     myGroupChk->blockSignals( true );
529     mySubmeshChk->setChecked( false );
530     myGroupChk->setChecked( false );
531     mySubmeshChk->blockSignals( false );
532     myGroupChk->blockSignals( false );
533   }
534   updateButtons();
535 }
536
537 //=======================================================================
538 // name    : SMESHGUI_MultiEditDlg::onAddBtn
539 // Purpose : Verify whether Id of element satisfies to filters from viewer
540 //=======================================================================
541 bool SMESHGUI_MultiEditDlg::isIdValid( const int theId ) const
542 {
543   VTKViewer_InteractorStyleSALOME* aStyle = SMESH::GetInteractorStyle();
544   Handle(SMESHGUI_Filter) aFilter1 =
545     Handle(SMESHGUI_Filter)::DownCast( aStyle->GetFilter( myFilterType ) );
546   Handle(SMESHGUI_Filter) aFilter2 =
547     Handle(SMESHGUI_Filter)::DownCast( aStyle->GetFilter( SMESHGUI_FaceFilter ) );
548   return ( aFilter1.IsNull() || aFilter1->IsObjValid( theId ) ) &&
549          ( aFilter2.IsNull() || aFilter2->IsObjValid( theId ) );
550 }
551
552 //=======================================================================
553 // name    : SMESHGUI_MultiEditDlg::onAddBtn
554 // Purpose : SLOT. Called when "Add" button pressed.
555 //           Add selected in viewer entities in list box
556 //=======================================================================
557 void SMESHGUI_MultiEditDlg::onAddBtn()
558 {
559   int nbSelected = mySelection->IObjectCount();
560   if ( nbSelected == 0 ) 
561     return;
562
563   TColStd_IndexedMapOfInteger toBeAdded;
564   
565   if ( !mySubmeshChk->isChecked() && !myGroupChk->isChecked() ) 
566   {
567     if ( nbSelected == 1 ) 
568       SMESH::GetSelected( mySelection, toBeAdded );
569   }
570   else if ( mySubmeshChk->isChecked() ) 
571   {
572     SALOME_ListIteratorOfListIO anIter( mySelection->StoredIObjects() );
573     for ( ; anIter.More(); anIter.Next() )
574     {
575       SMESH::SMESH_subMesh_var aSubMesh = SMESH::IObjectToInterface<SMESH::SMESH_subMesh>( anIter.Value() );
576       if ( !aSubMesh->_is_nil() )
577       {
578         if ( aSubMesh->GetFather()->GetId() == myMesh->GetId() )
579         {
580           SMESH::long_array_var anIds = aSubMesh->GetElementsId();
581           for ( int i = 0, n = anIds->length(); i < n; i++ )
582           {
583             if ( isIdValid( anIds[ i ] ) )
584               toBeAdded.Add( anIds[ i ] );
585           }
586         }
587       }
588     }
589   }
590   else if ( myGroupChk->isChecked() ) 
591   {
592     SALOME_ListIteratorOfListIO anIter( mySelection->StoredIObjects() );
593     for ( ; anIter.More(); anIter.Next() )
594     {
595       SMESH::SMESH_GroupBase_var aGroup =
596         SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>( anIter.Value() );
597       if ( !aGroup->_is_nil() && aGroup->GetType() == SMESH::FACE )
598       {
599         if ( aGroup->GetMesh()->GetId() == myMesh->GetId() )
600         {
601           SMESH::long_array_var anIds = aGroup->GetListOfID();
602           for ( int i = 0, n = anIds->length(); i < n; i++ )
603           {
604             if ( isIdValid( anIds[ i ] ) )
605               toBeAdded.Add( anIds[ i ] );
606           }
607         }
608       }
609     }
610   }
611
612   myBusy = true;
613   bool isGroupOrSubmesh = ( mySubmeshChk->isChecked() || myGroupChk->isChecked() );
614   mySubmeshChk->setChecked( false );
615   myGroupChk->setChecked( false );
616   for( int i = 1; i <= toBeAdded.Extent(); i++ )
617     if ( myIds.Add( toBeAdded(i) ) ) {
618       QListBoxItem * item = new QListBoxText( QString( "%1" ).arg( toBeAdded(i) ));
619       myListBox->insertItem( item );
620       myListBox->setSelected( item, true );
621     }
622   myBusy = false;
623
624   emit ListContensChanged(); 
625
626   if ( isGroupOrSubmesh )
627     onListSelectionChanged();
628
629   updateButtons();
630 }
631
632 //=======================================================================
633 // name    : SMESHGUI_MultiEditDlg::updateButtons
634 // Purpose : Enable/disable buttons of dialog in accordance with current state
635 //=======================================================================
636 void SMESHGUI_MultiEditDlg::updateButtons()
637 {
638   bool isOk = isValid(false);
639   myOkBtn->setEnabled( isOk );
640   myApplyBtn->setEnabled( isOk );
641
642   bool isListBoxNonEmpty = myListBox->count() > 0;
643   bool isToAll = myToAllChk->isChecked();
644   myFilterBtn->setEnabled( !isToAll );
645   myRemoveBtn->setEnabled( isListBoxNonEmpty && !isToAll );
646   mySortBtn->setEnabled( isListBoxNonEmpty &&!isToAll );
647   
648   if ( isToAll ||
649        myMesh->_is_nil() ||
650        mySelection->IObjectCount() != 1 ||
651        (SMESH::IObjectToInterface<SMESH::SMESH_subMesh>( mySelection->firstIObject() )->_is_nil() &&
652         SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>( mySelection->firstIObject() )->_is_nil() &&
653         SMESH::IObjectToInterface<SMESH::SMESH_Mesh>( mySelection->firstIObject() )->_is_nil()) )
654     myAddBtn->setEnabled( false );
655   else
656     myAddBtn->setEnabled( true );
657   
658   mySubmeshChk->setEnabled( !isToAll );
659   mySubmeshBtn->setEnabled( mySubmeshChk->isChecked() );
660   mySubmesh->setEnabled( mySubmeshChk->isChecked() );
661   
662   myGroupChk->setEnabled( !isToAll );
663   myGroupBtn->setEnabled( myGroupChk->isChecked() );
664   myGroup->setEnabled( myGroupChk->isChecked() );
665   
666   if ( !mySubmeshChk->isChecked() )
667     mySubmesh->clear();
668   if ( !myGroupChk->isChecked() )
669     myGroup->clear();
670     
671 }
672
673 //=======================================================================
674 // name    : SMESHGUI_MultiEditDlg::onRemoveBtn
675 // Purpose : SLOT. Called when "Remove" button pressed.
676 //           Remove selected in list box entities
677 //=======================================================================
678 void SMESHGUI_MultiEditDlg::onRemoveBtn()
679 {
680   myBusy = true;
681   
682   for ( int i = 0, n = myListBox->count(); i < n; i++ )
683   {
684     for ( int i = myListBox->count(); i > 0; i--) {
685       if ( myListBox->isSelected( i - 1 ) ) 
686       {
687         int anId = myListBox->text( i - 1 ).toInt();
688         myIds.Remove( anId );
689         myIds.Remove( anId );
690               myListBox->removeItem( i-1 );
691       }
692     }        
693   }
694   myBusy = false;
695
696   emit ListContensChanged();  
697   updateButtons();
698 }
699
700 //=======================================================================
701 // name    : SMESHGUI_MultiEditDlg::onSortListBtn
702 // Purpose : SLOT. Called when "Sort list" button pressed.
703 //           Sort entities of list box
704 //=======================================================================
705 void SMESHGUI_MultiEditDlg::onSortListBtn()
706 {
707   myBusy = true;
708
709   int i, k = myListBox->count();
710   if ( k > 0 ) 
711   {
712     QStringList aSelected;
713     std::vector<int> anArray( k );
714     QListBoxItem* anItem;
715     for ( anItem = myListBox->firstItem(), i = 0; anItem != 0; anItem = anItem->next(), i++) 
716     {
717       anArray[ i ] = anItem->text().toInt();
718       if ( anItem->isSelected() ) 
719         aSelected.append( anItem->text() );
720     }
721     
722     std::sort( anArray.begin(), anArray.end() );
723     myListBox->clear();
724     for ( i = 0; i < k; i++ ) 
725       myListBox->insertItem( QString::number( anArray[ i ] ) );
726
727     for ( QStringList::iterator it = aSelected.begin(); it != aSelected.end(); ++it ) 
728     {
729       anItem = myListBox->findItem( *it, Qt::ExactMatch );
730       if ( anItem ) 
731         myListBox->setSelected( anItem, true );
732     }
733   }
734   myBusy = false;
735 }
736
737 //=======================================================================
738 // name    : SMESHGUI_MultiEditDlg::onListSelectionChanged
739 // Purpose : SLOT. Called when selection in list box changed.
740 //           Highlight in selected entities
741 //=======================================================================
742 void SMESHGUI_MultiEditDlg::onListSelectionChanged()
743 {
744   if ( myActor == 0 || myBusy )
745     return;
746   
747   if ( mySubmeshChk->isChecked() || myGroupChk->isChecked() ) 
748     return;
749
750   SMESH_Actor * anActor = SMESH::FindActorByObject( myMesh );
751   if ( !anActor )
752     anActor = myActor;
753   TVisualObjPtr anObj = anActor->GetObject();
754
755   TColStd_MapOfInteger anIndexes;
756   for ( QListBoxItem* anItem = myListBox->firstItem(); anItem != 0; anItem = anItem->next() ) 
757   {
758     if ( anItem->isSelected() ) 
759     {
760       int anId = anItem->text().toInt();
761       if ( anObj->GetElemVTKId( anId ) >= 0 ) // avoid exception in hilight
762         anIndexes.Add(anId);
763     }
764   }
765   
766   mySelection->ClearIObjects();
767   mySelection->AddOrRemoveIndex( anActor->getIO(), anIndexes, false, false );
768   mySelection->AddIObject( anActor->getIO() );
769 }
770
771 //=======================================================================
772 // name    : SMESHGUI_MultiEditDlg::onSubmeshChk
773 // Purpose : SLOT. Called when state of "SubMesh" check box changed.
774 //           Activate/deactivate selection of submeshes
775 //=======================================================================
776 void SMESHGUI_MultiEditDlg::onSubmeshChk()
777 {
778   bool isChecked = mySubmeshChk->isChecked();
779   mySubmeshBtn->setEnabled( isChecked );
780   mySubmesh->setEnabled( isChecked );
781   if ( !isChecked )
782     mySubmesh->clear();
783   if ( isChecked && myGroupChk->isChecked() )
784       myGroupChk->setChecked( false );
785       
786   setSelectionMode();      
787 }
788
789 //=======================================================================
790 // name    : SMESHGUI_MultiEditDlg::onGroupChk
791 // Purpose : SLOT. Called when state of "Group" check box changed.
792 //           Activate/deactivate selection of groupes
793 //=======================================================================
794 void SMESHGUI_MultiEditDlg::onGroupChk()
795 {
796   bool isChecked = myGroupChk->isChecked();
797   myGroupBtn->setEnabled( isChecked );
798   myGroup->setEnabled( isChecked );
799   if ( !isChecked )
800     myGroup->clear();
801   if ( isChecked && mySubmeshChk->isChecked() )
802       mySubmeshChk->setChecked( false );
803
804   setSelectionMode();
805 }
806
807 //=======================================================================
808 // name    : SMESHGUI_MultiEditDlg::onToAllChk
809 // Purpose : SLOT. Called when state of "Apply to all" check box changed.
810 //           Activate/deactivate selection 
811 //=======================================================================
812 void SMESHGUI_MultiEditDlg::onToAllChk()
813 {
814   bool isChecked = myToAllChk->isChecked();
815
816   if ( isChecked )
817     myListBox->clear();
818
819   myIds.Clear();
820
821   emit ListContensChanged();
822     
823   updateButtons();
824   setSelectionMode();
825
826   if ( myActor )
827     mySelection->AddIObject( myActor->getIO(), true );
828 }
829
830
831 //=======================================================================
832 // name    : SMESHGUI_MultiEditDlg::setSelectionMode
833 // Purpose : Set selection mode
834 //=======================================================================
835 void SMESHGUI_MultiEditDlg::setSelectionMode()
836 {
837   SMESH::RemoveFilter(SMESHGUI_EdgeFilter);
838   SMESH::RemoveFilter(SMESHGUI_FaceFilter);
839   SMESH::RemoveFilter(SMESHGUI_VolumeFilter);
840   SMESH::RemoveFilter(SMESHGUI_QuadFilter);
841   SMESH::RemoveFilter(SMESHGUI_TriaFilter);
842   SMESH::SetPickable();
843
844   mySelection->ClearIObjects();
845   mySelection->ClearFilters();
846   
847   if ( mySubmeshChk->isChecked() )
848   {
849     QAD_Application::getDesktop()->SetSelectionMode( ActorSelection, true );
850     mySelection->AddFilter( mySubmeshFilter );
851   }
852   else if ( myGroupChk->isChecked() )
853   {
854     QAD_Application::getDesktop()->SetSelectionMode( ActorSelection, true );
855     mySelection->AddFilter( myGroupFilter );
856   }
857   else
858   {
859     if ( myFilterType == SMESHGUI_VolumeFilter ) {
860       QAD_Application::getDesktop()->SetSelectionMode( VolumeSelection, true );
861     }
862     else {
863       QAD_Application::getDesktop()->SetSelectionMode( FaceSelection, true );
864       if ( myFilterType == SMESHGUI_TriaFilter )
865         SMESH::SetFilter( new SMESHGUI_TriangleFilter() );
866       else if ( myFilterType == SMESHGUI_QuadFilter )
867         SMESH::SetFilter( new SMESHGUI_QuadrangleFilter() );
868     }
869   }
870 }
871
872 //=======================================================================
873 // name    : SMESHGUI_MultiEditDlg::onApply
874 // Purpose : SLOT. Called when "Apply" button clicked. 
875 //=======================================================================
876 bool SMESHGUI_MultiEditDlg::onApply()
877 {
878   if ( SMESHGUI::GetSMESHGUI()->ActiveStudyLocked() )
879     return false;
880   if ( !isValid( true ) )
881     return false;
882
883   SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
884   if ( aMeshEditor->_is_nil()  )
885     return false;
886
887   SMESH::long_array_var anIds = getIds();
888
889   bool aResult = process( aMeshEditor, anIds.inout() );
890   if ( aResult )
891   {
892     if ( myActor )
893     {
894       mySelection->ClearIObjects();
895       SMESH::UpdateView();
896       mySelection->AddIObject( myActor->getIO(), false );
897     }
898
899     myListBox->clear();
900     myIds.Clear();
901     emit ListContensChanged();
902
903     updateButtons();
904   }
905
906   return aResult;
907 }
908
909 //=======================================================================
910 // name    : SMESHGUI_MultiEditDlg::on3d2dChanged
911 // Purpose : 
912 //=======================================================================
913 void SMESHGUI_MultiEditDlg::on3d2dChanged(int type)
914 {
915   if ( myEntityType != type ) {
916     myEntityType = type;
917     
918     myListBox->clear();
919     myIds.Clear();
920
921     emit ListContensChanged();
922     
923     updateButtons();
924
925     if ( type )
926       myFilterType = SMESHGUI_VolumeFilter;
927     else 
928       myFilterType = SMESHGUI_FaceFilter;
929     setSelectionMode();
930
931     if ( myActor )
932       mySelection->AddIObject( myActor->getIO(), true );
933   }
934 }
935
936 //=======================================================================
937 // name    : SMESHGUI_MultiEditDlg::entityType
938 // Purpose : 
939 //=======================================================================
940
941 int SMESHGUI_MultiEditDlg::entityType() 
942 {
943   return myEntityType;
944 }
945
946 /*
947   Class       : SMESHGUI_ChangeOrientationDlg
948   Description : Modification of orientation of faces
949 */
950
951 SMESHGUI_ChangeOrientationDlg::SMESHGUI_ChangeOrientationDlg( QWidget*          theParent, 
952                                                               SALOME_Selection* theSelection,
953                                                               const char*       theName )
954 : SMESHGUI_MultiEditDlg( theParent, theSelection, SMESHGUI_FaceFilter, true, theName )
955 {
956   setCaption( tr( "CAPTION" ) );
957 }
958
959 SMESHGUI_ChangeOrientationDlg::~SMESHGUI_ChangeOrientationDlg()
960 {
961 }
962
963 bool SMESHGUI_ChangeOrientationDlg::process( SMESH::SMESH_MeshEditor_ptr theEditor,
964                                              const SMESH::long_array&    theIds )
965 {
966   return theEditor->Reorient( theIds );
967 }
968
969 /*
970   Class       : SMESHGUI_UnionOfTrianglesDlg
971   Description : Construction of quadrangles by automatic association of triangles
972 */
973
974 SMESHGUI_UnionOfTrianglesDlg::SMESHGUI_UnionOfTrianglesDlg( QWidget*          theParent,
975                                                             SALOME_Selection* theSelection,
976                                                             const char*       theName )
977 : SMESHGUI_MultiEditDlg( theParent, theSelection, SMESHGUI_TriaFilter, false, theName )
978 {
979   setCaption( tr( "CAPTION" ) );
980 }
981
982 SMESHGUI_UnionOfTrianglesDlg::~SMESHGUI_UnionOfTrianglesDlg()
983 {
984 }
985
986 bool SMESHGUI_UnionOfTrianglesDlg::process( SMESH::SMESH_MeshEditor_ptr theEditor,
987                                             const SMESH::long_array&    theIds )
988 {
989   return theEditor->TriToQuad(theIds, SMESH::NumericalFunctor::_nil(), 1. );
990 }
991
992 /*
993   Class       : SMESHGUI_CuttingOfQuadsDlg
994   Description : Construction of quadrangles by automatic association of triangles
995 */
996
997 SMESHGUI_CuttingOfQuadsDlg::SMESHGUI_CuttingOfQuadsDlg( QWidget*          theParent,
998                                                         SALOME_Selection* theSelection,
999                                                         const char*       theName )
1000 : SMESHGUI_MultiEditDlg( theParent, theSelection, SMESHGUI_QuadFilter, false, theName )
1001 {
1002
1003   setCaption( tr( "CAPTION" ) );
1004   myPreviewActor = 0;
1005
1006   myUseDiagChk = new QCheckBox( tr( "USE_DIAGONAL_2_4" ), mySelGrp );
1007   myPreviewChk = new QCheckBox( tr( "PREVIEW" ), mySelGrp );
1008
1009   connect( myPreviewChk, SIGNAL( stateChanged( int ) ), this, SLOT( onPreviewChk() ) );
1010   connect( myUseDiagChk, SIGNAL( stateChanged( int ) ), this, SLOT( onPreviewChk() ) );
1011   connect( this, SIGNAL( ListContensChanged() ), this, SLOT( onPreviewChk() ) );
1012 }
1013
1014 SMESHGUI_CuttingOfQuadsDlg::~SMESHGUI_CuttingOfQuadsDlg()
1015 {
1016 }
1017
1018 void SMESHGUI_CuttingOfQuadsDlg::onClose()
1019 {
1020   erasePreview();
1021   SMESHGUI_MultiEditDlg::onClose();
1022 }
1023
1024 bool SMESHGUI_CuttingOfQuadsDlg::process( SMESH::SMESH_MeshEditor_ptr theEditor,
1025                                           const SMESH::long_array&    theIds )
1026 {
1027   return theEditor->SplitQuad( theIds, !myUseDiagChk->isChecked() );
1028 }
1029
1030 void SMESHGUI_CuttingOfQuadsDlg::onPreviewChk()
1031 {
1032   myPreviewChk->isChecked() ? displayPreview() : erasePreview();
1033 }
1034
1035 void SMESHGUI_CuttingOfQuadsDlg::erasePreview()
1036 {
1037   if ( myPreviewActor == 0 )
1038     return;
1039     
1040   if ( VTKViewer_ViewFrame* vf = SMESH::GetCurrentVtkView() )
1041   {
1042     vf->RemoveActor(myPreviewActor);
1043     vf->Repaint();
1044   }
1045   myPreviewActor->Delete();
1046   myPreviewActor = 0;
1047 }
1048
1049 void SMESHGUI_CuttingOfQuadsDlg::displayPreview()
1050 {
1051   if ( myActor == 0 )
1052     return;
1053
1054   if ( myPreviewActor != 0 )
1055     erasePreview();
1056
1057   // get Ids of elements
1058   SMESH::long_array_var anElemIds = getIds();
1059   if ( getIds()->length() == 0 )
1060     return;
1061
1062   SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh();
1063   if ( aMesh == 0 )
1064     return;
1065
1066   bool isDiag24 = myUseDiagChk->isChecked();
1067
1068   //Create grid
1069   vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
1070     
1071   vtkIdType aNbCells = anElemIds->length() * 2;
1072   vtkIdType aCellsSize = 4 * aNbCells;
1073   vtkCellArray* aConnectivity = vtkCellArray::New();
1074   aConnectivity->Allocate( aCellsSize, 0 );
1075
1076   vtkPoints* aPoints = vtkPoints::New();
1077   aPoints->SetNumberOfPoints( anElemIds->length() * 4 );
1078   
1079   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
1080   aCellTypesArray->SetNumberOfComponents( 1 );
1081   aCellTypesArray->Allocate( aNbCells * aCellTypesArray->GetNumberOfComponents() );
1082
1083   vtkIdList *anIdList = vtkIdList::New();
1084   anIdList->SetNumberOfIds( 3 );
1085
1086   TColStd_DataMapOfIntegerInteger anIdToVtk;
1087
1088   int aNodes[ 4 ];
1089   int nbPoints = -1;
1090   for ( int i = 0, n = anElemIds->length(); i < n; i++ )
1091   {
1092     const SMDS_MeshElement* anElem = aMesh->FindElement( anElemIds[ i ] );
1093     if ( anElem == 0 || anElem->NbNodes() != 4 )
1094       continue;
1095       
1096     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
1097     int k = 0;
1098     while( anIter->more() )
1099       if ( const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next() )
1100       {
1101         if ( !anIdToVtk.IsBound( aNode->GetID() ) )
1102         {
1103           aPoints->SetPoint( ++nbPoints, aNode->X(), aNode->Y(), aNode->Z() );
1104           anIdToVtk.Bind( aNode->GetID(), nbPoints );
1105         }
1106         
1107         aNodes[ k++ ] = aNode->GetID();
1108       }
1109
1110     if ( k != 4 )
1111       continue;
1112
1113     if ( !isDiag24 )
1114     {
1115       anIdList->SetId( 0, anIdToVtk( aNodes[ 0 ] ) );
1116       anIdList->SetId( 1, anIdToVtk( aNodes[ 1 ] ) );
1117       anIdList->SetId( 2, anIdToVtk( aNodes[ 2 ] ) );
1118       aConnectivity->InsertNextCell( anIdList );
1119       aCellTypesArray->InsertNextValue( VTK_TRIANGLE );
1120
1121       anIdList->SetId( 0, anIdToVtk( aNodes[ 2 ] ) );
1122       anIdList->SetId( 1, anIdToVtk( aNodes[ 3 ] ) );
1123       anIdList->SetId( 2, anIdToVtk( aNodes[ 0 ] ) );
1124       aConnectivity->InsertNextCell( anIdList );
1125       aCellTypesArray->InsertNextValue( VTK_TRIANGLE );
1126     }
1127     else
1128     {
1129       anIdList->SetId( 0, anIdToVtk( aNodes[ 1 ] ) );
1130       anIdList->SetId( 1, anIdToVtk( aNodes[ 2 ] ) );
1131       anIdList->SetId( 2, anIdToVtk( aNodes[ 3 ] ) );
1132       aConnectivity->InsertNextCell( anIdList );
1133       aCellTypesArray->InsertNextValue( VTK_TRIANGLE );
1134
1135       anIdList->SetId( 0, anIdToVtk( aNodes[ 3 ] ) );
1136       anIdList->SetId( 1, anIdToVtk( aNodes[ 0 ] ) );
1137       anIdList->SetId( 2, anIdToVtk( aNodes[ 1 ] ) );
1138       aConnectivity->InsertNextCell( anIdList );
1139       aCellTypesArray->InsertNextValue( VTK_TRIANGLE );
1140     }
1141   }
1142
1143   vtkIntArray* aCellLocationsArray = vtkIntArray::New();
1144   aCellLocationsArray->SetNumberOfComponents( 1 );
1145   aCellLocationsArray->SetNumberOfTuples( aNbCells );
1146
1147   aConnectivity->InitTraversal();
1148   for( vtkIdType idType = 0, *pts, npts; aConnectivity->GetNextCell( npts, pts ); idType++ )
1149     aCellLocationsArray->SetValue( idType, aConnectivity->GetTraversalLocation( npts ) );
1150
1151   aGrid->SetPoints( aPoints );
1152   aGrid->SetCells( aCellTypesArray, aCellLocationsArray,aConnectivity );
1153
1154   // Create and display actor
1155   vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
1156   aMapper->SetInput( aGrid );
1157   
1158   myPreviewActor = SALOME_Actor::New();
1159   myPreviewActor->PickableOff();
1160   myPreviewActor->SetMapper( aMapper );
1161
1162   vtkProperty* aProp = vtkProperty::New();
1163   aProp->SetRepresentationToWireframe();
1164   aProp->SetColor( 250, 0, 250 );
1165   aProp->SetLineWidth( myActor->GetLineWidth() + 1 );
1166   myPreviewActor->SetProperty( aProp );
1167
1168   SMESH::GetCurrentVtkView()->AddActor( myPreviewActor );
1169   SMESH::GetCurrentVtkView()->Repaint();
1170
1171   aProp->Delete();
1172   aPoints->Delete();
1173   aConnectivity->Delete();
1174   aGrid->Delete();
1175   aMapper->Delete();
1176   anIdList->Delete();
1177   aCellTypesArray->Delete();
1178   aCellLocationsArray->Delete();
1179 }
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202