Salome HOME
Merge remote branch 'origin/gdd/translations'
[modules/smesh.git] / src / StdMeshersGUI / StdMeshersGUI_SubShapeSelectorWdg.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : StdMeshersGUI_SubShapeSelectorWdg.cxx
21 // Author : Open CASCADE S.A.S. (dmv)
22 // SMESH includes
23 //
24 #include "StdMeshersGUI_SubShapeSelectorWdg.h"
25
26 // SMESH Includes
27 #include "SMESH_Type.h"
28 #include "SMESHGUI_MeshUtils.h"
29 #include "SMESH_Actor.h"
30 #include "SMESH_PreviewActorsCollection.h"
31 #include "SMESH_ActorUtils.h"
32 #include "SMESHGUI_GroupUtils.h"
33 #include "SMESH_Gen_i.hxx"
34 #include "SMESHGUI_GEOMGenUtils.h"
35 #include "SMESH_LogicalFilter.hxx"
36
37 // SVTK Includes
38 #include <SVTK_ViewWindow.h>
39 #include <SVTK_ViewModel.h>
40 #include <SVTK_ViewWindow.h>
41 #include <SVTK_Selector.h>
42
43 // SALOME GUI includes
44 #include <SALOME_ListIO.hxx>
45 #include <LightApp_SelectionMgr.h>
46
47 // SUIT Includes
48 #include <SUIT_ResourceMgr.h>
49
50 // GEOM Includes
51 #include <GEOMBase.h>
52 #include <GEOM_TypeFilter.h>
53 #include <GEOM_CompoundFilter.h>
54
55 // Qt includes
56 #include <QPushButton>
57 #include <QGridLayout>
58 #include <QListWidget>
59 #include <QCheckBox>
60 #include <QLineEdit>
61
62 // OCCT includes
63 #include <TColStd_MapOfInteger.hxx>
64 #include <TColStd_IndexedMapOfInteger.hxx>
65 #include <TopoDS_Shape.hxx>
66 #include <TopExp.hxx>
67 #include <TopExp_Explorer.hxx>
68 #include <StdSelect_TypeOfEdge.hxx>
69
70
71 #define SPACING 6
72 #define MARGIN 0
73
74 //================================================================================
75 /*!
76  *  Constructor
77  */
78 //================================================================================
79
80 StdMeshersGUI_SubShapeSelectorWdg
81 ::StdMeshersGUI_SubShapeSelectorWdg( QWidget * parent, TopAbs_ShapeEnum aSubShType ): 
82   QWidget( parent ),
83   myPreviewActor( 0 ),
84   myMaxSize( -1 )
85 {
86   QPixmap image0( SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap( "SMESH", tr( "ICON_SELECT" ) ) );
87
88   QGridLayout* edgesLayout = new QGridLayout( this );
89   edgesLayout->setMargin( MARGIN );
90   edgesLayout->setSpacing( SPACING );
91   
92   myListWidget   = new QListWidget( this );
93   myAddButton    = new QPushButton( tr( "SMESH_BUT_ADD" ),    this );
94   myRemoveButton = new QPushButton( tr( "SMESH_BUT_REMOVE" ), this );      
95   myInfoLabel    = new QLabel( this );
96   myPrevButton   = new QPushButton( "<<", this );
97   myNextButton   = new QPushButton( ">>", this );
98   myListWidget->setSelectionMode( QListWidget::ExtendedSelection );
99
100   edgesLayout->addWidget(myListWidget,   0, 0, 3, 3);
101   edgesLayout->addWidget(myAddButton,    0, 3);
102   edgesLayout->addWidget(myRemoveButton, 1, 3);
103   edgesLayout->addWidget(myInfoLabel,    3, 0, 1, 3);
104   edgesLayout->addWidget(myPrevButton,   4, 0);
105   edgesLayout->addWidget(myNextButton,   4, 2);
106
107   edgesLayout->setRowStretch(2, 5);
108   edgesLayout->setColumnStretch(1, 5);
109
110   myListWidget->setMinimumWidth(300);
111   myInfoLabel->setMinimumWidth(300);
112   myInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
113   myInfoLabel->setAlignment(Qt::AlignCenter);
114
115   mySubShType = aSubShType;
116
117   init();
118 }
119
120 //================================================================================
121 /*!
122  *  Destructor
123  */
124 //================================================================================
125
126 StdMeshersGUI_SubShapeSelectorWdg::~StdMeshersGUI_SubShapeSelectorWdg()
127 {
128   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) {
129     if ( myPreviewActor ) {
130       myPreviewActor->RemoveFromRender( myRenderer );
131       aViewWindow->Repaint();
132
133       delete myPreviewActor;
134       myPreviewActor = 0;
135     }
136   }
137   myEntry = "";
138   myParamValue = "";
139   myMainShape.Nullify();
140
141   if ( mySelectionMgr && myFilter )
142     mySelectionMgr->removeFilter( myFilter );
143   delete myFilter; myFilter=0;
144
145   SUIT_SelectionFilter* filter;
146   foreach( filter, myGeomFilters )
147     delete filter;
148 }
149
150 //================================================================================
151 /*!
152  *  Create a layout, initialize fields
153  */
154 //================================================================================
155
156 void StdMeshersGUI_SubShapeSelectorWdg::init()
157 {
158   myParamValue = "";
159   myIsNotCorrected = true; // to dont call the GetCorrectedValue method twice
160   myListOfIDs.clear();
161   mySelectedIDs.clear();
162
163   myAddButton->setEnabled( false );
164   myRemoveButton->setEnabled( false );
165
166   mySMESHGUI     = SMESHGUI::GetSMESHGUI();
167   mySelectionMgr = SMESH::GetSelectionMgr( mySMESHGUI );
168   mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
169
170   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
171     aViewWindow->SetSelectionMode( ActorSelection );
172
173   myFilter=0;
174   //setFilter();
175
176   connect( myAddButton,    SIGNAL(clicked()), SLOT(onAdd()));
177   connect( myRemoveButton, SIGNAL(clicked()), SLOT(onRemove()));
178   connect( myPrevButton,   SIGNAL(clicked()), SLOT(onPrevious()));
179   connect( myNextButton,   SIGNAL(clicked()), SLOT(onNext()));
180   
181   connect( mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
182   connect( myListWidget,   SIGNAL(itemSelectionChanged()),    this, SLOT(onListSelectionChanged()));
183
184   updateState();
185 }
186
187 //================================================================================
188 /*!
189  * \brief Install filters to select sub-shapes of mySubShType or their groups
190  */
191 //================================================================================
192
193 void StdMeshersGUI_SubShapeSelectorWdg::setFilter()
194 {
195   SalomeApp_Study* study = mySMESHGUI->activeStudy();
196   GEOM_TypeFilter* typeFilter = new GEOM_TypeFilter(study, mySubShType, /*isShapeType=*/true );
197   GEOM_CompoundFilter* gpoupFilter = new GEOM_CompoundFilter(study);
198   gpoupFilter->addSubType( mySubShType );
199   myGeomFilters.append( typeFilter );
200   myGeomFilters.append( gpoupFilter );
201   myFilter = new SMESH_LogicalFilter( myGeomFilters, SMESH_LogicalFilter::LO_OR );
202   mySelectionMgr->installFilter( myFilter );
203 }
204
205 //================================================================================
206 /*!
207  *  Create a layout, initialize fields
208  */
209 //================================================================================
210
211 void StdMeshersGUI_SubShapeSelectorWdg::showPreview( bool visible)
212 {
213   if ( !myPreviewActor )
214     return;
215
216   if ( myIsShown != visible ) {
217     myPreviewActor->SetShown( visible );
218     
219     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
220       aViewWindow->Repaint();
221
222     myIsShown = visible;
223   }
224 }
225
226 //=================================================================================
227 // function : SelectionIntoArgument()
228 // purpose  : Called when selection as changed or other case
229 //=================================================================================
230 void StdMeshersGUI_SubShapeSelectorWdg::SelectionIntoArgument()
231 {
232   if ( !myPreviewActor )
233     return;
234
235   mySelectedIDs.clear();
236
237   // get selected mesh
238   SALOME_ListIO aList;
239   mySelectionMgr->selectedObjects( aList );
240   int nbSel = aList.Extent();
241
242   if (nbSel > 0) {
243     SALOME_ListIteratorOfListIO anIt (aList);
244     
245     for ( ; anIt.More(); anIt.Next()) { // Loop on selected objects
246       Handle(SALOME_InteractiveObject) IO = anIt.Value();
247       
248       GEOM::GEOM_Object_var aGeomObj = GetGeomObjectByEntry( IO->getEntry() );
249       if ( !CORBA::is_nil( aGeomObj ) ) { // Selected Object From Study
250         GEOM::GEOM_Object_var aGeomFatherObj = aGeomObj->GetMainShape();
251         QString aFatherEntry = "";
252         QString aMainFatherEntry = "";
253         TopoDS_Shape shape;
254         if ( !CORBA::is_nil( aGeomFatherObj ) ) {
255           // Get Main Shape
256           GEOM::GEOM_Object_var aGeomMain = GetGeomObjectByEntry( myEntry );
257           if ( !CORBA::is_nil( aGeomMain ) && aGeomMain->GetType() == 37 ) {  // Main Shape is a Group
258             GEOM::GEOM_Object_var aMainFatherObj = aGeomMain->GetMainShape();
259             if ( !CORBA::is_nil( aMainFatherObj ) )
260               aMainFatherEntry = aMainFatherObj->GetStudyEntry();
261           }
262           aFatherEntry = aGeomFatherObj->GetStudyEntry();
263         }
264
265         if ( aFatherEntry != "" && ( aFatherEntry == myEntry || aFatherEntry == aMainFatherEntry ) )
266         {
267           if ( aGeomObj->GetType() == 37 /*GEOM_GROUP*/ ) { // Selected Group that belongs the main object
268             GEOMBase::GetShape(aGeomObj, shape); 
269             if ( !shape.IsNull() ) {
270               TopExp_Explorer exp( shape, mySubShType );
271               for ( ; exp.More(); exp.Next() ) {
272                 int index = myPreviewActor->GetIndexByShape( exp.Current() );
273                 if ( index ) {
274                   mySelectedIDs.append( index );
275                   myPreviewActor->HighlightID( index );
276                 }
277               }
278             }
279           } else if ( aGeomObj->GetType() == 28 /*GEOM_SUBSHAPE*/  ) {
280             GEOMBase::GetShape(aGeomObj, shape); 
281             if ( !shape.IsNull() && shape.ShapeType() == mySubShType ) {
282               int index = myPreviewActor->GetIndexByShape( shape );
283               if ( index ) {
284                 mySelectedIDs.append( index );
285                 myPreviewActor->HighlightID( index );
286               }
287             }
288           }
289         }
290       } else { // Selected Actor from Actor Collection
291         QString anEntry = IO->getEntry();
292         QString str = "_";
293         int index = anEntry.lastIndexOf( str );
294         anEntry.remove(0, index+1);
295         int ind = anEntry.toInt();
296         if ( ind )
297           mySelectedIDs.append( ind );
298       }
299     }
300   }
301   // update add button
302   myAddButton->setEnabled( ( myListWidget->count() < myMaxSize || myMaxSize == -1 ) &&
303                            mySelectedIDs.size() > 0 &&
304                            ( mySelectedIDs.size() <= myMaxSize || myMaxSize == -1 ) );
305
306   //Connect Selected Ids in viewer and dialog's Ids list
307   bool signalsBlocked = myListWidget->blockSignals( true );
308   myListWidget->clearSelection();
309   if ( mySelectedIDs.size() > 0 ) {
310     for (int i = 0; i < mySelectedIDs.size(); i++) {
311       QString anID = QString(" %1").arg( mySelectedIDs.at(i) );
312       QList<QListWidgetItem*> anItems = myListWidget->findItems ( anID, Qt::MatchExactly );
313       QListWidgetItem* item;
314       foreach(item, anItems)
315         item->setSelected(true);
316     }
317   }
318   myListWidget->blockSignals( signalsBlocked );
319 }
320
321 //=================================================================================
322 // function : onAdd()
323 // purpose  : Called when Add Button Clicked
324 //=================================================================================
325 void StdMeshersGUI_SubShapeSelectorWdg::onAdd()
326 {
327   if ( mySelectedIDs.size() < 1 )
328     return;
329
330   myListWidget->blockSignals( true );
331   for (int i = 0; i < mySelectedIDs.size() && (myMaxSize == -1 || myListOfIDs.size() < myMaxSize); i++) {
332     if ( myListOfIDs.indexOf( mySelectedIDs.at(i) ) == -1 ) {
333       QString anID = QString(" %1").arg( mySelectedIDs.at(i) );
334
335       QListWidgetItem* anItem = new QListWidgetItem( anID, myListWidget );
336       anItem->setSelected(true);
337       
338       myListOfIDs.append( mySelectedIDs.at(i) );
339     }
340   }
341   onListSelectionChanged();
342   myListWidget->blockSignals( false );
343   myAddButton->setEnabled( myMaxSize == -1 || myListOfIDs.size() < myMaxSize );
344 }
345          
346 //=================================================================================
347 // function : onRemove()
348 // purpose  : Called when Remove Button Clicked
349 //=================================================================================
350 void StdMeshersGUI_SubShapeSelectorWdg::onRemove()
351 {
352   if ( myListWidget->count() < 1 )
353     return;
354
355   myListWidget->blockSignals( true );
356   QList<QListWidgetItem*> selItems = myListWidget->selectedItems();
357   QListWidgetItem* item;
358   foreach(item, selItems) {
359     QString idStr = item->text();
360     int id = idStr.toInt();
361
362     int index = myListOfIDs.indexOf( id );
363     myListOfIDs.removeAt( index );
364     delete item;
365   }
366
367   onListSelectionChanged();
368   myListWidget->blockSignals( false );
369   
370   myAddButton->setEnabled( true );
371 }
372
373 void StdMeshersGUI_SubShapeSelectorWdg::onPrevious()
374 {
375   if ( myPreviewActor ) {
376     myPreviewActor->previous();
377     myListWidget->clearSelection();
378     updateButtons();
379     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
380       aViewWindow->Repaint();
381   }
382 }
383
384 void StdMeshersGUI_SubShapeSelectorWdg::onNext()
385 {
386   if ( myPreviewActor ) {
387     myPreviewActor->next();
388     myListWidget->clearSelection();
389     updateButtons();
390     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
391       aViewWindow->Repaint();
392   }
393 }
394
395 //=================================================================================
396 // function : onListSelectionChanged()
397 // purpose  : Called when selection in element list is changed
398 //=================================================================================
399 void StdMeshersGUI_SubShapeSelectorWdg::onListSelectionChanged()
400 {
401   if ( !myPreviewActor )
402     return;
403
404   mySelectionMgr->clearSelected();
405   TColStd_MapOfInteger aIndexes;
406   QList<QListWidgetItem*> selItems = myListWidget->selectedItems();
407   QListWidgetItem* anItem;
408   foreach(anItem, selItems)
409     myPreviewActor->HighlightID( anItem->text().toInt() );
410
411   // update remove button
412   myRemoveButton->setEnabled( selItems.size() > 0 );
413 }
414
415 //=================================================================================
416 // function : setGeomShape
417 // purpose  : Called to set geometry whose sub-shapes are selected
418 //================================================================================
419 void StdMeshersGUI_SubShapeSelectorWdg::SetGeomShapeEntry( const QString& theEntry )
420 {
421   if ( theEntry != "") {
422     myParamValue = theEntry;
423     myEntry = theEntry;
424     myGeomShape = GetTopoDSByEntry( theEntry );
425     updateState();
426     myIsNotCorrected = true;
427   }
428 }
429
430 //=================================================================================
431 // function : updateState
432 // purpose  : update Widget state
433 //=================================================================================
434 void StdMeshersGUI_SubShapeSelectorWdg::updateState()
435 {
436   bool state = false;
437   if ( !myGeomShape.IsNull() )
438     state = true;
439   myInfoLabel->setVisible( false );
440   myPrevButton->setVisible( false );
441   myNextButton->setVisible( false );
442   
443   myListWidget->setEnabled( state );
444   myAddButton->setEnabled( mySelectedIDs.size() > 0 );
445   
446   if (state) {
447     myPreviewActor = new SMESH_PreviewActorsCollection();
448     myPreviewActor->SetSelector( mySelector );
449     myPreviewActor->Init( myGeomShape, mySubShType, myEntry );
450     myPreviewActor->SetShown( false );
451     myIsShown = false;
452     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) {
453       myRenderer = aViewWindow->getRenderer();
454       myPreviewActor->AddToRender( myRenderer );
455       aViewWindow->Repaint();
456     }
457     updateButtons();
458   }
459 }
460
461 //=================================================================================
462 // function : GetGeomObjectByEntry
463 // purpose  : Called to get GeomObject
464 //=================================================================================
465 GEOM::GEOM_Object_var StdMeshersGUI_SubShapeSelectorWdg::GetGeomObjectByEntry( const QString& theEntry )
466 {
467   GEOM::GEOM_Object_var aGeomObj;
468   SALOMEDS::Study_var aStudy = SMESHGUI::GetSMESHGen()->GetCurrentStudy();
469   if ( !aStudy->_is_nil() )
470   {
471     SALOMEDS::SObject_var aSObj = aStudy->FindObjectID( theEntry.toLatin1().data() );
472     if (!aSObj->_is_nil() )
473     {
474       CORBA::Object_var obj = aSObj->GetObject();
475       aGeomObj = GEOM::GEOM_Object::_narrow(obj);
476       aSObj->UnRegister();
477     }
478   }
479   return aGeomObj._retn();
480 }
481
482 //=================================================================================
483 // function : setObjectByEntry
484 // purpose  : Called to get GeomObject
485 //=================================================================================
486 TopoDS_Shape StdMeshersGUI_SubShapeSelectorWdg::GetTopoDSByEntry( const QString& theEntry )
487 {
488   TopoDS_Shape shape;
489   GEOM::GEOM_Object_var aGeomObj = GetGeomObjectByEntry( theEntry );
490   GEOMBase::GetShape(aGeomObj, shape);
491   return shape;
492 }
493
494 //=================================================================================
495 // function : GetListOfIds
496 // purpose  : Called to get the list of SubShapes IDs
497 //=================================================================================
498 SMESH::long_array_var StdMeshersGUI_SubShapeSelectorWdg::GetListOfIDs()
499 {
500   SMESH::long_array_var anArray = new SMESH::long_array;
501
502   if ( myMainEntry != "" && myIsNotCorrected )
503     myListOfIDs = GetCorrectedListOfIDs( true );
504
505   int size = myListOfIDs.size();
506   anArray->length( size );
507   if ( size ) {
508     for (int i = 0; i < size; i++) {
509         anArray[i] = myListOfIDs.at(i);
510     }
511   }
512   return anArray;
513 }
514
515 //=================================================================================
516 // function : SetListOfIds
517 // purpose  : Called to set the list of SubShapes IDs. Returns false if any ID is invalid
518 //=================================================================================
519 bool StdMeshersGUI_SubShapeSelectorWdg::SetListOfIDs( SMESH::long_array_var theIds)
520 {
521   mySelectedIDs.clear();
522   myListOfIDs.clear();
523   int size = theIds->length();
524   for ( int i = 0; i < size; i++ )
525     mySelectedIDs.append( theIds[ i ] );
526
527   bool isOk;
528   mySelectedIDs = GetCorrectedListOfIDs( false, &isOk );
529   onAdd();
530   return isOk;
531 }
532
533 //=================================================================================
534 // function : SetMainShapeEntry
535 // purpose  : Called to set the Entry of main shape of the mesh
536 //=================================================================================
537 void StdMeshersGUI_SubShapeSelectorWdg::SetMainShapeEntry( const QString& theEntry )
538 {
539   myMainEntry = theEntry;
540   myMainShape = GetTopoDSByEntry( theEntry );
541   myIsNotCorrected = true;
542 }
543
544 //=================================================================================
545 // function : GetMainShapeEntry
546 // purpose  : Called to get the Main Object Entry
547 //=================================================================================
548 const char* StdMeshersGUI_SubShapeSelectorWdg::GetMainShapeEntry()
549 {
550   if ( myMainEntry == "")
551     return myEntry.toLatin1().data();
552
553   return myMainEntry.toLatin1().data();
554 }
555
556 //=================================================================================
557 // function : GetCorrectedListOfIds
558 // purpose  : Called to convert the list of IDs from sub-shape IDs to main shape IDs
559 //=================================================================================
560 QList<int>
561 StdMeshersGUI_SubShapeSelectorWdg::GetCorrectedListOfIDs( bool fromSubshapeToMainshape,
562                                                           bool* isOK )
563 {
564   if (( myMainShape.IsNull() || myGeomShape.IsNull() ) &&  fromSubshapeToMainshape )
565     return myListOfIDs;
566   else if (( myMainShape.IsNull() /*||*/&& myGeomShape.IsNull() ) &&  !fromSubshapeToMainshape )
567     return mySelectedIDs;
568
569   if ( !fromSubshapeToMainshape ) // called from SetListOfIDs
570   {
571     if ( myMainShape.IsNull() )
572       std::swap( myMainShape, myGeomShape );
573   }
574
575   QList<int> aList;
576   TopTools_IndexedMapOfShape aGeomMap, aMainMap;
577   TopExp::MapShapes(myMainShape, aMainMap);
578   if ( !myGeomShape.IsNull() )
579     TopExp::MapShapes(myGeomShape, aGeomMap);
580
581   bool ok = true;
582   if ( fromSubshapeToMainshape ) // convert indexes from sub-shape to mainshape
583   {
584     int size = myListOfIDs.size();
585     for (int i = 0; i < size; i++) {
586       int index = myListOfIDs.at(i);
587       if ( aGeomMap.Extent() < index )
588       {
589         ok = false;
590       }
591       else
592       {
593         TopoDS_Shape aSubShape = aGeomMap.FindKey( index );
594         if ( mySubShType != aSubShape.ShapeType() )
595           ok = false;
596         if ( !aMainMap.Contains( aSubShape ))
597           ok = false;
598         else
599           index = aMainMap.FindIndex( aSubShape );
600       }
601       aList.append( index );
602     }
603     myIsNotCorrected = false;
604   }
605   else // convert indexes from main shape to sub-shape, or just check indices
606   {
607     int size = mySelectedIDs.size();
608     for (int i = 0; i < size; i++) {
609       int index = mySelectedIDs.at(i);
610       if ( aMainMap.Extent() < index )
611       {
612         ok = false;
613       }
614       else
615       {
616         TopoDS_Shape aSubShape = aMainMap.FindKey( index );
617         if ( mySubShType != aSubShape.ShapeType() )
618           ok = false;
619         if ( !aGeomMap.Contains( aSubShape ) && !aGeomMap.IsEmpty() )
620           ok = false;
621         else
622           index = aGeomMap.FindIndex( aSubShape );
623       }
624       aList.append( index );
625     }
626   }
627   if ( isOK ) *isOK = ok;
628
629   return aList;
630 }
631
632 void StdMeshersGUI_SubShapeSelectorWdg::updateButtons()
633 {
634   if ( myPreviewActor ) {
635     int total = myPreviewActor->count();
636     int chunk = myPreviewActor->currentChunk();
637     int chunkSize = myPreviewActor->chunkSize();
638     int imin = chunk*chunkSize+1;
639     int imax = std::min((chunk+1)*chunkSize, total);
640     bool vis = imax > 0 && total > chunkSize;
641     myInfoLabel->setVisible( vis );
642     myPrevButton->setVisible( vis );
643     myNextButton->setVisible( vis );
644     myInfoLabel->setText( tr( "X_FROM_Y_ITEMS_SHOWN" ).arg(imin).arg(imax).arg(total) );
645     myPrevButton->setEnabled( myPreviewActor->hasPrevious() );
646     myNextButton->setEnabled( myPreviewActor->hasNext() );
647   }
648 }