Salome HOME
22455: Error "No mesh elements assigned to a face" is raised instead of a simple...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_ComputeDlg.cxx
1 // Copyright (C) 2007-2013  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.
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   : SMESHGUI_ComputeDlg.cxx
21 // Author : Edward AGAPOV, Open CASCADE S.A.S.
22 // SMESH includes
23 //
24 #include "SMESHGUI_ComputeDlg.h"
25
26 #include "SMESHGUI.h"
27 #include "SMESHGUI_GEOMGenUtils.h"
28 #include "SMESHGUI_MeshUtils.h"
29 #include "SMESHGUI_VTKUtils.h"
30 #include "SMESHGUI_MeshInfosBox.h"
31 #include "SMESHGUI_HypothesesUtils.h"
32 #include "SMESHGUI_MeshEditPreview.h"
33 #include "SMESHGUI_MeshOrderOp.h"
34 #include "SMESHGUI_MeshOrderDlg.h"
35
36 #include "SMESH_Actor.h"
37 #include "SMESH_ActorUtils.h"
38
39 #include <SMDS_SetIterator.hxx>
40 #include <SMDS_Mesh.hxx>
41
42 // SALOME GEOM includes
43 #include <GEOMBase.h>
44 #include <GEOM_Actor.h>
45 #include <GEOM_wrap.hxx>
46
47 // SALOME GUI includes
48 #include <LightApp_SelectionMgr.h>
49 #include <LightApp_UpdateFlags.h>
50 #include <SALOME_ListIO.hxx>
51 #include <SVTK_ViewWindow.h>
52 #include <SVTK_ViewModel.h>
53 #include <SalomeApp_Application.h>
54 #include <SUIT_ResourceMgr.h>
55 #include <SUIT_OverrideCursor.h>
56 #include <SUIT_MessageBox.h>
57 #include <SUIT_Desktop.h>
58 #include <QtxComboBox.h>
59
60 // SALOME KERNEL includes
61 #include <SALOMEDS_SObject.hxx>
62 #include <SALOMEDSClient_SObject.hxx>
63 #include <SALOMEDS_wrap.hxx>
64
65 #include CORBA_SERVER_HEADER(SMESH_Group)
66
67 // OCCT includes
68 #include <BRep_Tool.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_IndexedMapOfShape.hxx>
72 #include <TopoDS.hxx>
73
74 #include <TopLoc_Location.hxx>
75 #include <Poly_Triangulation.hxx>
76 #include <Bnd_Box.hxx>
77 #include <BRepBndLib.hxx>
78 #include <BRepMesh_IncrementalMesh.hxx>
79
80 #include <Standard_ErrorHandler.hxx>
81
82 // Qt includes
83 #include <QFrame>
84 #include <QPushButton>
85 #include <QLabel>
86 #include <QRadioButton>
87 #include <QTableWidget>
88 #include <QHeaderView>
89 #include <QGridLayout>
90 #include <QHBoxLayout>
91 #include <QVBoxLayout>
92 #include <QButtonGroup>
93 #include <QCloseEvent>
94 #include <QTimerEvent>
95 #include <QProgressBar>
96
97 // VTK includes
98 #include <vtkProperty.h>
99
100 // STL includes
101 #include <vector>
102 #include <set>
103
104 #ifndef WIN32
105 #include <sys/sysinfo.h>
106 #endif
107
108 #define SPACING 6
109 #define MARGIN  11
110
111 #define COLONIZE(str)   (QString(str).contains(":") > 0 ? QString(str) : QString(str) + " :" )
112
113 enum TCol {
114   COL_ALGO = 0, COL_SHAPE, COL_ERROR, COL_SHAPEID, COL_PUBLISHED, COL_BAD_MESH, NB_COLUMNS
115 };
116
117 //using namespace SMESH;
118
119 namespace SMESH
120 {
121   //=============================================================================
122   /*!
123    * \brief Allocate some memory at construction and release it at destruction.
124    * Is used to be able to continue working after mesh generation or visualization
125    * break due to lack of memory
126    */
127   //=============================================================================
128
129   struct MemoryReserve
130   {
131     char* myBuf;
132     MemoryReserve(): myBuf( new char[1024*1024*1] ){} // 1M
133     void release() { delete [] myBuf; myBuf = 0; }
134     ~MemoryReserve() { release(); }
135   };
136
137   // =========================================================================================
138   /*!
139    * \brief Class showing shapes without publishing
140    */
141   // =========================================================================================
142
143   class TShapeDisplayer
144   {
145   public:
146     // -----------------------------------------------------------------------
147     TShapeDisplayer(): myViewWindow(0)
148     {
149       myProperty = vtkProperty::New();
150       myProperty->SetRepresentationToWireframe();
151       myProperty->SetColor( 250, 0, 250 );
152       myProperty->SetAmbientColor( 250, 0, 250 );
153       myProperty->SetDiffuseColor( 250, 0, 250 );
154       //myProperty->SetSpecularColor( 250, 0, 250 );
155       myProperty->SetLineWidth( 5 );
156     }
157     // -----------------------------------------------------------------------
158     ~TShapeDisplayer()
159     {
160       DeleteActors();
161       myProperty->Delete();
162     }
163     // -----------------------------------------------------------------------
164     void DeleteActors()
165     {
166       if ( hasViewWindow() ) {
167         TActorIterator actorIt = actorIterator();
168         while ( actorIt.more() )
169           if (VTKViewer_Actor* anActor = actorIt.next()) {
170             myViewWindow->RemoveActor( anActor );
171             //anActor->Delete();
172           }
173       }
174       myIndexToShape.Clear();
175       myActors.clear();
176       myShownActors.clear();
177       myBuiltSubs.clear();
178     }
179     // -----------------------------------------------------------------------
180     void SetVisibility (bool theVisibility)
181     {
182       TActorIterator actorIt = shownIterator();
183       while ( actorIt.more() )
184         if (VTKViewer_Actor* anActor = actorIt.next())
185           anActor->SetVisibility(theVisibility);
186       SMESH::RepaintCurrentView();
187     }
188     // -----------------------------------------------------------------------
189     bool HasReadyActorsFor (int subShapeID, GEOM::GEOM_Object_var aMainShape )
190     {
191       std::string mainEntry;
192       if ( !aMainShape->_is_nil() )
193         mainEntry = aMainShape->GetStudyEntry();
194       return ( myMainEntry == mainEntry &&
195                myBuiltSubs.find( subShapeID ) != myBuiltSubs.end() );
196     }
197     // -----------------------------------------------------------------------
198     void Show( int subShapeID, GEOM::GEOM_Object_var aMainShape, bool only = false)
199     {
200       SVTK_ViewWindow* aViewWindow  = SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() );
201       SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() );
202       std::string mainEntry;
203       if ( !aMainShape->_is_nil() )
204         mainEntry = aMainShape->GetStudyEntry();
205       if ( myMainEntry != mainEntry || aViewWindow != myViewWindow ) { // remove actors
206         DeleteActors();
207         TopoDS_Shape aShape;
208         if ( !aMainShape->_is_nil() && GEOMBase::GetShape(aMainShape, aShape)) {
209           checkTriangulation( aShape );
210           TopExp::MapShapes(aShape, myIndexToShape);
211           myActors.resize( myIndexToShape.Extent(), 0 );
212           myShownActors.reserve( myIndexToShape.Extent() );
213         }
214         myMainEntry  = mainEntry;
215         myViewWindow = aViewWindow;
216       }
217       if ( only ) { // hide shown actors
218         TActorIterator actorIt = shownIterator();
219         while ( actorIt.more() )
220           if (VTKViewer_Actor* anActor = actorIt.next())
221             anActor->SetVisibility(false);
222         myShownActors.clear();
223       }
224       // find actors to show
225       TopoDS_Shape aShape = myIndexToShape( subShapeID );
226       if ( !aShape.IsNull() ) {
227         TopAbs_ShapeEnum type( aShape.ShapeType() >= TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE );
228         for ( TopExp_Explorer exp( aShape, type ); exp.More(); exp.Next() ) {
229           //checkTriangulation( exp.Current() );
230           if ( GEOM_Actor* anActor = getActor( exp.Current() ) ) {
231             int UNbIsos = resMgr->integerValue( "Geometry", "iso_number_u", 1);
232             int VNbIsos = resMgr->integerValue( "Geometry", "iso_number_v", 1);
233             int aNbIsos[2] = { UNbIsos ? UNbIsos : 1, VNbIsos ? VNbIsos : 1 };
234             anActor->SetNbIsos( aNbIsos );
235             myShownActors.push_back( anActor );
236           }
237         }
238         if ( type == TopAbs_FACE ) {
239           for ( TopExp_Explorer exp( aShape, TopAbs_EDGE ); exp.More(); exp.Next() ) {
240             const TopoDS_Edge & edge = TopoDS::Edge( exp.Current() );
241             if ( !BRep_Tool::Degenerated( edge ))
242               if ( GEOM_Actor* anActor = getActor( exp.Current() ))
243                 myShownActors.push_back( anActor );
244           }
245         }
246       }
247       myBuiltSubs.insert( subShapeID );
248       SetVisibility(true);
249     }
250     // -----------------------------------------------------------------------
251
252   private:
253
254     typedef std::vector<GEOM_Actor*> TActorVec;
255     TActorVec                  myActors;
256     TActorVec                  myShownActors;
257     TopTools_IndexedMapOfShape myIndexToShape;
258     std::string                myMainEntry;
259     SVTK_ViewWindow*           myViewWindow;
260     vtkProperty*               myProperty;
261     std::set<int>              myBuiltSubs;
262
263     // -----------------------------------------------------------------------
264     typedef SMDS_SetIterator< GEOM_Actor*, TActorVec::const_iterator> TActorIterator;
265     TActorIterator actorIterator() {
266       return TActorIterator( myActors.begin(), myActors.end() );
267     }
268     TActorIterator shownIterator() {
269       return TActorIterator( myShownActors.begin(), myShownActors.end() );
270     }
271     // -----------------------------------------------------------------------
272     GEOM_Actor* getActor(const TopoDS_Shape& shape)
273     {
274       int index = myIndexToShape.FindIndex( shape ) - 1;
275       if ( index < 0 || index >= myActors.size() )
276         return 0;
277       GEOM_Actor* & actor = myActors[ index ];
278       if ( !actor ) {
279         actor = GEOM_Actor::New();
280         if ( actor ) {
281           actor->SetShape(shape,0,0);
282           actor->SetProperty(myProperty);
283           actor->SetShadingProperty(myProperty);
284           actor->SetWireframeProperty(myProperty);
285           actor->SetPreviewProperty(myProperty);
286           actor->PickableOff();
287           //         if ( shape.ShapeType() == TopAbs_EDGE )
288           //           actor->SubShapeOn();
289           myViewWindow->AddActor( actor );
290         }
291       }
292       return actor;
293     }
294     // -----------------------------------------------------------------------
295     void checkTriangulation(const TopoDS_Shape& shape)
296     {
297       TopLoc_Location aLoc;
298       Standard_Boolean alreadymesh = Standard_True;
299       TopExp_Explorer ex(shape, TopAbs_FACE);
300       if ( ex.More() )
301         for ( ; ex.More(); ex.Next()) {
302           const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
303           Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
304           if(aPoly.IsNull()) { alreadymesh = Standard_False; break; }
305         }
306       else
307         for (ex.Init(shape, TopAbs_EDGE); ex.More(); ex.Next()) {
308           const TopoDS_Edge& edge = TopoDS::Edge(ex.Current());
309           Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(edge, aLoc);
310           if(aPoly.IsNull()) { alreadymesh = Standard_False; break; }
311         }
312       if (alreadymesh) return;
313       // Compute default deflection
314       Bnd_Box B;
315       BRepBndLib::Add(shape, B);
316       Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
317       B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
318       double deflection = Max( aXmax-aXmin, Max ( aYmax-aYmin, aZmax-aZmin)) * 0.01 *4;
319       BRepMesh_IncrementalMesh MESH(shape,deflection);
320     }
321     // -----------------------------------------------------------------------
322     bool hasViewWindow() const
323     {
324       if ( !myViewWindow ) return false;
325
326       if ( SalomeApp_Application* anApp = SMESHGUI::GetSMESHGUI()->getApp() )
327         return FindVtkViewWindow( anApp->getViewManager(SVTK_Viewer::Type(), false ),
328                                   myViewWindow );
329       return false;
330     }
331   };
332
333   // =========================================================================================
334   /*!
335    * \brief Return text describing an error
336    */
337 #define CASE2TEXT(enum) case SMESH::enum: text = QObject::tr( #enum ); break;
338   QString errorText(int errCode, const char* comment)
339   {
340     QString text;
341     switch ( errCode ) {
342       CASE2TEXT( COMPERR_OK               );
343       CASE2TEXT( COMPERR_BAD_INPUT_MESH   );
344       CASE2TEXT( COMPERR_STD_EXCEPTION    );
345       CASE2TEXT( COMPERR_OCC_EXCEPTION    );
346     case SMESH::COMPERR_SLM_EXCEPTION: break; // avoid double "Salome exception"
347       CASE2TEXT( COMPERR_EXCEPTION        );
348       CASE2TEXT( COMPERR_MEMORY_PB        );
349       CASE2TEXT( COMPERR_BAD_SHAPE        );
350       CASE2TEXT( COMPERR_CANCELED         );
351       CASE2TEXT( COMPERR_NO_MESH_ON_SHAPE );
352       CASE2TEXT( COMPERR_BAD_PARMETERS    );
353     case SMESH::COMPERR_ALGO_FAILED:
354       if ( strlen(comment) == 0 )
355         text = QObject::tr("COMPERR_ALGO_FAILED");
356       break;
357     case SMESH::COMPERR_WARNING:
358       text = QObject::tr( (comment && strlen(comment)) ? "COMPERR_WARNING" : "COMPERR_UNKNOWN");
359       break;
360     default:
361       text = QString("#%1").arg( -errCode );
362     }
363     if ( text.length() > 0 ) text += ". ";
364     return text + comment;
365   }
366   // -----------------------------------------------------------------------
367   /*!
368    * \brief Return SO of a sub-shape
369    */
370   _PTR(SObject) getSubShapeSO( int subShapeID, GEOM::GEOM_Object_var aMainShape)
371   {
372     _PTR(SObject) so = SMESH::FindSObject(aMainShape);
373     if ( subShapeID == 1 || !so )
374       return so;
375     _PTR(ChildIterator) it;
376     if (_PTR(Study) study = SMESH::GetActiveStudyDocument())
377       it =  study->NewChildIterator(so);
378     _PTR(SObject) subSO;
379     if ( it ) {
380       for ( it->InitEx(true); !subSO && it->More(); it->Next() ) {
381         GEOM::GEOM_Object_var geom = SMESH::SObjectToInterface<GEOM::GEOM_Object>( it->Value() );
382         if ( !geom->_is_nil() ) {
383           GEOM::ListOfLong_var list = geom->GetSubShapeIndices();
384           if ( list->length() == 1 && list[0] == subShapeID )
385             subSO = it->Value();
386         }
387       }
388     }
389     return subSO;
390   }
391   // -----------------------------------------------------------------------
392   /*!
393    * \brief Return sub-shape by ID. WARNING: UnRegister() must be called on a result
394    */
395   GEOM::GEOM_Object_ptr getSubShape( int subShapeID, GEOM::GEOM_Object_var aMainShape)
396   {
397     GEOM::GEOM_Object_var aSubShape;
398     if ( subShapeID == 1 ) {
399       aSubShape = aMainShape;
400       aSubShape->Register();
401     }
402     else if ( _PTR(SObject) so = getSubShapeSO( subShapeID, aMainShape )) {
403       aSubShape = SMESH::SObjectToInterface<GEOM::GEOM_Object>( so );
404       aSubShape->Register();
405     }
406     else {
407       aSubShape = SMESH::GetSubShape( aMainShape, subShapeID );
408       // future call of UnRegister() will delete a servant of this new object
409     }
410     return aSubShape._retn();
411   }
412   // -----------------------------------------------------------------------
413   /*!
414    * \brief Return shape type name
415    */
416 #define CASE2NAME(enum) case GEOM::enum: name = QObject::tr( "GEOM_" #enum ); break;
417   QString shapeTypeName(GEOM::GEOM_Object_var aShape, const char* dflt = "" )
418   {
419     QString name = dflt;
420     if ( !aShape->_is_nil() ) {
421       switch ( aShape->GetShapeType() ) {
422       CASE2NAME( VERTEX    );
423       CASE2NAME( EDGE      );
424       CASE2NAME( WIRE      );
425       CASE2NAME( FACE      );
426       CASE2NAME( SHELL     );
427       CASE2NAME( SOLID     );
428       CASE2NAME( COMPSOLID );
429       CASE2NAME( COMPOUND  );
430       default:;
431       }
432     }
433     return name;
434   }
435   // -----------------------------------------------------------------------
436   /*!
437    * \brief Return text describing a sub-shape
438    */
439   QString shapeText(int subShapeID, GEOM::GEOM_Object_var aMainShape )
440   {
441     QString text;
442     if ( _PTR(SObject) aSO = getSubShapeSO( subShapeID, aMainShape )) {
443       text  = aSO->GetName().c_str();
444       text += QString(" (%1)").arg( aSO->GetID().c_str() );
445     }
446     else {
447       text = QString("#%1").arg( subShapeID );
448       GEOM::GEOM_Object_wrap shape = getSubShape( subShapeID, aMainShape );
449       QString typeName = shapeTypeName( shape );
450       if ( typeName.length() )
451         text += QString(" (%1)").arg(typeName);
452     }
453     return text;
454   }
455   // -----------------------------------------------------------------------
456   /*!
457    * \brief Return a list of selected rows
458    */
459   int getSelectedRows(QTableWidget* table, QList<int>& rows)
460   {
461     rows.clear();
462     QList<QTableWidgetSelectionRange> selRanges = table->selectedRanges();
463     QTableWidgetSelectionRange range;
464     foreach( range, selRanges )
465     {
466       for ( int row = range.topRow(); row <= range.bottomRow(); ++row )
467         if ( !rows.count( row ))
468              rows.append( row );
469     }
470     if ( rows.isEmpty() && table->currentRow() > -1 )
471       if ( !rows.count( table->currentRow() ))
472         rows.append( table->currentRow() );
473
474     return rows.count();
475   }
476
477 } // namespace SMESH
478
479
480 // =========================================================================================
481 /*!
482  * \brief Dialog to compute a mesh and show computation errors
483  */
484 //=======================================================================
485
486 SMESHGUI_ComputeDlg::SMESHGUI_ComputeDlg( QWidget* parent, bool ForEval )
487  : SMESHGUI_Dialog( parent, false, true, Close/* | Help*/ )
488 {
489   QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame());
490   aDlgLay->setMargin( 0 );
491   aDlgLay->setSpacing( SPACING );
492
493   QFrame* aMainFrame = createMainFrame(mainFrame(),ForEval);
494
495   aDlgLay->addWidget(aMainFrame);
496
497   aDlgLay->setStretchFactor(aMainFrame, 1);
498 }
499
500 // =========================================================================================
501 /*!
502  * \brief Destructor
503  */
504 //=======================================================================
505
506 SMESHGUI_ComputeDlg::~SMESHGUI_ComputeDlg()
507 {
508 }
509
510 //=======================================================================
511 // function : createMainFrame()
512 // purpose  : Create frame containing dialog's fields
513 //=======================================================================
514
515 QFrame* SMESHGUI_ComputeDlg::createMainFrame (QWidget* theParent, bool ForEval)
516 {
517   QFrame* aFrame = new QFrame(theParent);
518
519   SUIT_ResourceMgr* rm = resourceMgr();
520   QPixmap iconCompute (rm->loadPixmap("SMESH", tr("ICON_COMPUTE")));
521
522   // constructor
523
524   QGroupBox* aPixGrp;
525   if(ForEval) {
526     aPixGrp = new QGroupBox(tr("EVAL_DLG"), aFrame);
527   }
528   else {
529     aPixGrp = new QGroupBox(tr("CONSTRUCTOR"), aFrame);
530   }
531   QButtonGroup* aBtnGrp = new QButtonGroup(this);
532   QHBoxLayout* aPixGrpLayout = new QHBoxLayout(aPixGrp);
533   aPixGrpLayout->setMargin(MARGIN); aPixGrpLayout->setSpacing(SPACING);
534
535   QRadioButton* aRBut = new QRadioButton(aPixGrp);
536   aRBut->setIcon(iconCompute);
537   aRBut->setChecked(true);
538   aPixGrpLayout->addWidget(aRBut);
539   aBtnGrp->addButton(aRBut, 0);
540
541   // Mesh name
542
543   QGroupBox* nameBox = new QGroupBox(tr("SMESH_MESHINFO_NAME"), aFrame );
544   QHBoxLayout* nameBoxLayout = new QHBoxLayout(nameBox);
545   nameBoxLayout->setMargin(MARGIN); nameBoxLayout->setSpacing(SPACING);
546   myMeshName = new QLabel(nameBox);
547   nameBoxLayout->addWidget(myMeshName);
548
549   // Mesh Info
550
551   myBriefInfo = new SMESHGUI_MeshInfosBox(false, aFrame);
552   myFullInfo  = new SMESHGUI_MeshInfosBox(true,  aFrame);
553
554   // Computation errors
555
556   myCompErrorGroup = new QGroupBox(tr("ERRORS"), aFrame);
557   myWarningLabel = new QLabel(QString("<b>%1</b>").arg(tr("COMPUTE_WARNING")), myCompErrorGroup);
558   myTable        = new QTableWidget( 1, NB_COLUMNS, myCompErrorGroup);
559   myShowBtn      = new QPushButton(tr("SHOW_SHAPE"), myCompErrorGroup);
560   myPublishBtn   = new QPushButton(tr("PUBLISH_SHAPE"), myCompErrorGroup);
561   myBadMeshBtn   = new QPushButton(tr("SHOW_BAD_MESH"), myCompErrorGroup);
562   myBadMeshToGroupBtn = new QPushButton(tr("GROUP_OF_BAD_MESH"), myCompErrorGroup);
563
564   //myTable->setReadOnly( true ); // VSR: check
565   myTable->setEditTriggers( QAbstractItemView::NoEditTriggers );
566   myTable->hideColumn( COL_PUBLISHED );
567   myTable->hideColumn( COL_SHAPEID );
568   myTable->hideColumn( COL_BAD_MESH );
569   myTable->horizontalHeader()->setResizeMode( COL_ERROR, QHeaderView::Interactive );
570   myTable->setWordWrap( true );
571   myTable->horizontalHeader()->setStretchLastSection( true );
572   myTable->setMinimumWidth( 500 );
573
574   QStringList headers;
575   headers << tr( "COL_ALGO_HEADER" );
576   headers << tr( "COL_SHAPE_HEADER" );
577   headers << tr( "COL_ERROR_HEADER" );
578   headers << tr( "COL_SHAPEID_HEADER" );
579   headers << tr( "COL_PUBLISHED_HEADER" );
580
581   myTable->setHorizontalHeaderLabels( headers );
582
583   // layouting
584   QGridLayout* grpLayout = new QGridLayout(myCompErrorGroup);
585   grpLayout->setSpacing(SPACING);
586   grpLayout->setMargin(MARGIN);
587   grpLayout->addWidget( myWarningLabel,      0, 0, 1, 4 );
588   grpLayout->addWidget( myTable,             1, 0, 1, 4 );
589   grpLayout->addWidget( myShowBtn,           2, 0 );
590   grpLayout->addWidget( myPublishBtn,        2, 1 );
591   grpLayout->addWidget( myBadMeshBtn,        2, 2 );
592   grpLayout->addWidget( myBadMeshToGroupBtn, 2, 3 );
593   grpLayout->setColumnStretch( 3, 1 );
594
595   // Hypothesis definition errors
596
597   myHypErrorGroup = new QGroupBox(tr("SMESH_WRN_MISSING_PARAMETERS"), aFrame);
598   QHBoxLayout* myHypErrorGroupLayout = new QHBoxLayout(myHypErrorGroup);
599   myHypErrorGroupLayout->setMargin(MARGIN);
600   myHypErrorGroupLayout->setSpacing(SPACING);
601   myHypErrorLabel = new QLabel(myHypErrorGroup);
602   myHypErrorGroupLayout->addWidget(myHypErrorLabel);
603
604   // Memory Lack Label
605
606   myMemoryLackGroup = new QGroupBox(tr("ERRORS"), aFrame);
607   QVBoxLayout* myMemoryLackGroupLayout = new QVBoxLayout(myMemoryLackGroup);
608   myMemoryLackGroupLayout->setMargin(MARGIN);
609   myMemoryLackGroupLayout->setSpacing(SPACING);
610   QLabel* memLackLabel = new QLabel(tr("MEMORY_LACK"), myMemoryLackGroup);
611   QFont bold = memLackLabel->font(); bold.setBold(true);
612   memLackLabel->setFont( bold );
613   memLackLabel->setMinimumWidth(300);
614   myMemoryLackGroupLayout->addWidget(memLackLabel);
615
616   // add all widgets to aFrame
617   QVBoxLayout* aLay = new QVBoxLayout(aFrame);
618   aLay->setMargin( 0 );
619   aLay->setSpacing( 0 );
620   aLay->addWidget( aPixGrp );
621   aLay->addWidget( nameBox );
622   aLay->addWidget( myBriefInfo );
623   aLay->addWidget( myFullInfo );
624   aLay->addWidget( myHypErrorGroup );
625   aLay->addWidget( myCompErrorGroup );
626   aLay->addWidget( myMemoryLackGroup );
627   aLay->setStretchFactor( myCompErrorGroup, 1 );
628
629   ((QPushButton*) button( OK ))->setDefault( true );
630
631   return aFrame;
632 }
633
634 //================================================================================
635 /*!
636  * \brief Constructor
637 */
638 //================================================================================
639
640 SMESHGUI_BaseComputeOp::SMESHGUI_BaseComputeOp()
641   : SMESHGUI_Operation(), myCompDlg( 0 )
642 {
643   myTShapeDisplayer = new SMESH::TShapeDisplayer();
644   myBadMeshDisplayer = 0;
645
646   //myHelpFileName = "/files/about_meshes.htm"; // V3
647   myHelpFileName = "about_meshes_page.html"; // V4
648 }
649
650 SMESH::SMESH_Mesh_ptr SMESHGUI_BaseComputeOp::getMesh()
651 {
652   LightApp_SelectionMgr* Sel = selectionMgr();
653   SALOME_ListIO selected; Sel->selectedObjects( selected );
654   Handle(SALOME_InteractiveObject) anIO = selected.First();
655   SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(anIO);
656   return myMesh->_is_nil() ? aMesh._retn() : SMESH::SMESH_Mesh::_duplicate( myMesh );
657 }
658
659 //================================================================================
660 /*!
661  * \brief Start operation
662  * \purpose Init dialog fields, connect signals and slots, show dialog
663  */
664 //================================================================================
665
666 void SMESHGUI_BaseComputeOp::startOperation()
667 {
668   // create compute dialog if not created before
669   computeDlg();
670
671   myMesh      = SMESH::SMESH_Mesh::_nil();
672   myMainShape = GEOM::GEOM_Object::_nil();
673
674   // check selection
675   LightApp_SelectionMgr *Sel = selectionMgr();
676   SALOME_ListIO selected; Sel->selectedObjects( selected );
677
678   int nbSel = selected.Extent();
679   if (nbSel != 1) {
680     SUIT_MessageBox::warning(desktop(),
681                              tr("SMESH_WRN_WARNING"),
682                              tr("SMESH_WRN_NO_AVAILABLE_DATA"));
683     onCancel();
684     return;
685   }
686
687   myIObject = selected.First();
688   myMesh = SMESH::GetMeshByIO(myIObject);
689   if (myMesh->_is_nil()) {
690     SUIT_MessageBox::warning(desktop(),
691                              tr("SMESH_WRN_WARNING"),
692                              tr("SMESH_WRN_NO_AVAILABLE_DATA"));
693     onCancel();
694     return;
695   }
696   myMainShape = myMesh->GetShapeToMesh();
697
698   SMESHGUI_Operation::startOperation();
699 }
700
701 //================================================================================
702 //================================================================================
703
704 SMESHGUI_ComputeDlg_QThread::SMESHGUI_ComputeDlg_QThread(SMESH::SMESH_Gen_var gen,
705                                                          SMESH::SMESH_Mesh_var mesh,
706                                                          GEOM::GEOM_Object_var mainShape)
707 {
708   myResult = false;
709   myGen = gen;
710   myMesh = mesh;
711   myMainShape = mainShape;
712 }
713
714 void SMESHGUI_ComputeDlg_QThread::run()
715 {
716   myResult = myGen->Compute(myMesh, myMainShape);
717 }
718
719 bool SMESHGUI_ComputeDlg_QThread::result()
720 {
721   return myResult;
722 }
723
724 void SMESHGUI_ComputeDlg_QThread::cancel()
725 {
726   myGen->CancelCompute(myMesh, myMainShape);
727 }
728
729 //================================================================================
730 //================================================================================
731
732 SMESHGUI_ComputeDlg_QThreadQDialog::SMESHGUI_ComputeDlg_QThreadQDialog(QWidget             * parent,
733                                                                        SMESH::SMESH_Gen_var  gen,
734                                                                        SMESH::SMESH_Mesh_var mesh,
735                                                                        GEOM::GEOM_Object_var mainShape)
736   : QDialog(parent,
737             Qt::WindowSystemMenuHint |
738             Qt::WindowCloseButtonHint |
739             Qt::Dialog |
740             Qt::WindowMaximizeButtonHint),
741     qthread(gen, mesh, mainShape)
742 {
743   // --
744   setWindowTitle(tr("TITLE"));
745   setMinimumWidth( 200 );
746
747   cancelButton = new QPushButton(tr("CANCEL"));
748   cancelButton->setDefault(true);
749   cancelButton->setCheckable(true);
750
751   QLabel * nbNodesName = new QLabel(tr("SMESH_MESHINFO_NODES"), this );
752   QLabel * nbElemsName = new QLabel(tr("SMESH_MESHINFO_ELEMENTS"), this );
753   nbNodesLabel = new QLabel("0", this );
754   nbElemsLabel = new QLabel("0", this );
755 #ifndef WIN32
756   QLabel * freeRAMName = new QLabel(tr("SMESH_FREERAM"), this );
757   freeRAMLabel = new QLabel("", this );
758 #endif
759   progressBar  = new QProgressBar(this);
760   progressBar->setMinimum( 0 );
761   progressBar->setMaximum( 1000 );
762
763   QGridLayout* layout = new QGridLayout(this);
764   layout->setMargin( MARGIN );
765   layout->setSpacing( SPACING );
766   int row = 0;
767   layout->addWidget(nbNodesName,  row,   0);
768   layout->addWidget(nbNodesLabel, row++, 1);
769   layout->addWidget(nbElemsName,  row,   0);
770   layout->addWidget(nbElemsLabel, row++, 1);
771 #ifndef WIN32
772   layout->addWidget(freeRAMName,  row,   0);
773   layout->addWidget(freeRAMLabel, row++, 1);
774 #endif
775   layout->addWidget(progressBar,  row++, 0, 1, 2);
776   layout->addWidget(cancelButton, row++, 0, 1, 2);
777   adjustSize();
778   update();
779
780   connect(cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
781   // --
782   startTimer(300); // millisecs
783   qthread.start();
784 }
785
786 bool SMESHGUI_ComputeDlg_QThreadQDialog::result()
787 {
788   return qthread.result();
789 }
790
791 void SMESHGUI_ComputeDlg_QThreadQDialog::onCancel()
792 {
793   qthread.cancel();
794   cancelButton->setText( tr("CANCELING"));
795   cancelButton->setEnabled(false);
796 }
797
798 void SMESHGUI_ComputeDlg_QThreadQDialog::timerEvent(QTimerEvent *event)
799 {
800   if ( !cancelButton->isChecked() ) // not yet cancelled
801     progressBar->setValue( progressBar->maximum() * qthread.getMesh()->GetComputeProgress() );
802
803   if(qthread.isFinished())
804   {
805     close();
806   }
807   else
808   {
809     nbNodesLabel->setText( QString("%1").arg( qthread.getMesh()->NbNodes() ));
810     nbElemsLabel->setText( QString("%1").arg( qthread.getMesh()->NbElements() ));
811 #ifndef WIN32
812     struct sysinfo si;
813     const int err = sysinfo( &si );
814     if ( err )
815       freeRAMLabel->setText("");
816     else
817       freeRAMLabel->setText( tr("SMESH_GIGABYTE").arg
818                              ( si.freeram * si.mem_unit /1024./1024./1024., 0, 'f', 2 ));
819 #endif
820   }
821   event->accept();
822 }
823
824 void SMESHGUI_ComputeDlg_QThreadQDialog::closeEvent(QCloseEvent *event)
825 {
826   if(qthread.isRunning())
827   {
828       event->ignore();
829       return;
830     }
831   event->accept();
832 }
833
834 //================================================================================
835 /*!
836  * \brief computeMesh()
837 */
838 //================================================================================
839
840 void SMESHGUI_BaseComputeOp::computeMesh()
841 {
842   // COMPUTE MESH
843
844   SMESH::MemoryReserve aMemoryReserve;
845
846   SMESH::compute_error_array_var aCompErrors;
847   QString                        aHypErrors;
848
849   bool computeFailed = true, memoryLack = false;
850
851   _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh);
852   if ( !aMeshSObj ) // IPAL 21340
853     return;
854   bool hasShape = myMesh->HasShapeToMesh();
855   bool shapeOK = myMainShape->_is_nil() ? !hasShape : hasShape;
856   if ( shapeOK )
857   {
858     myCompDlg->myMeshName->setText( aMeshSObj->GetName().c_str() );
859     SMESH::SMESH_Gen_var gen = getSMESHGUI()->GetSMESHGen();
860     SMESH::algo_error_array_var errors = gen->GetAlgoState(myMesh,myMainShape);
861     if ( errors->length() > 0 ) {
862       aHypErrors = SMESH::GetMessageOnAlgoStateErrors( errors.in() );
863     }
864     if ( myMesh->HasModificationsToDiscard() && // issue 0020693
865          SUIT_MessageBox::question( desktop(), tr( "SMESH_WARNING" ),
866                                     tr( "FULL_RECOMPUTE_QUESTION" ),
867                                     tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 1, 0 ) == 0 )
868       myMesh->Clear();
869     SUIT_OverrideCursor aWaitCursor;
870     try {
871 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
872       OCC_CATCH_SIGNALS;
873 #endif
874       SMESHGUI_ComputeDlg_QThreadQDialog qthreaddialog(desktop(), gen, myMesh, myMainShape);
875       qthreaddialog.exec();
876       computeFailed = !qthreaddialog.result();
877     }
878     catch(const SALOME::SALOME_Exception & S_ex) {
879       memoryLack = true;
880     }
881     try {
882 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
883       OCC_CATCH_SIGNALS;
884 #endif
885       aCompErrors = gen->GetComputeErrors( myMesh, myMainShape );
886       // check if there are memory problems
887       for ( int i = 0; (i < aCompErrors->length()) && !memoryLack; ++i )
888         memoryLack = ( aCompErrors[ i ].code == SMESH::COMPERR_MEMORY_PB );
889     }
890     catch(const SALOME::SALOME_Exception & S_ex) {
891       memoryLack = true;
892     }
893
894     if ( !memoryLack && !SMDS_Mesh::CheckMemory(true) ) { // has memory to show dialog boxes?
895       memoryLack = true;
896     }
897
898     // NPAL16631: if ( !memoryLack )
899     {
900       SMESH::ModifiedMesh(aMeshSObj, !computeFailed, myMesh->NbNodes() == 0);
901       update( UF_ObjBrowser | UF_Model );
902
903       // SHOW MESH
904       // NPAL16631: if ( getSMESHGUI()->automaticUpdate() )
905       SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() );
906       bool limitExceeded;
907       long limitSize = resMgr->integerValue( "SMESH", "update_limit", 500000 );
908       int entities = SMESH_Actor::eAllEntity;
909       int hidden = 0;
910       if ( !memoryLack )
911       {
912         if ( getSMESHGUI()->automaticUpdate( myMesh, &entities, &limitExceeded, &hidden ) )
913         {
914           try {
915 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
916             OCC_CATCH_SIGNALS;
917 #endif
918             SMESH_Actor *anActor = SMESH::FindActorByObject( myMesh );
919             if ( !anActor ) anActor = SMESH::CreateActor( aMeshSObj->GetStudy(), aMeshSObj->GetID().c_str(), true );    
920             if ( anActor ) // actor is not created for an empty mesh
921             {
922               anActor->SetEntityMode( entities );
923               SMESH::DisplayActor( SMESH::GetActiveWindow(), anActor );
924             }
925             SMESH::Update(myIObject, true);
926
927             if ( limitExceeded )
928             {
929               QStringList hiddenMsg;
930               if ( hidden & SMESH_Actor::e0DElements ) hiddenMsg << tr( "SMESH_ELEMS0D" );
931               if ( hidden & SMESH_Actor::eEdges )      hiddenMsg << tr( "SMESH_EDGES" );
932               if ( hidden & SMESH_Actor::eFaces )      hiddenMsg << tr( "SMESH_FACES" );
933               if ( hidden & SMESH_Actor::eVolumes )    hiddenMsg << tr( "SMESH_VOLUMES" );
934               if ( hidden & SMESH_Actor::eBallElem )   hiddenMsg << tr( "SMESH_BALLS" );
935               SUIT_MessageBox::warning( desktop(),
936                                         tr( "SMESH_WRN_WARNING" ),
937                                         tr( "SMESH_WRN_SIZE_INC_LIMIT_EXCEEDED" ).arg( myMesh->NbElements() ).arg( limitSize ).arg( hiddenMsg.join(", ") ) );
938             }
939           }
940           catch (...) {
941 #ifdef _DEBUG_
942             MESSAGE ( "Exception thrown during mesh visualization" );
943 #endif
944             if ( SMDS_Mesh::CheckMemory(true) ) { // has memory to show warning?
945               SMESH::OnVisuException();
946             }
947             else {
948               memoryLack = true;
949             }
950           }
951         }
952         else if ( limitExceeded )
953         {
954           SUIT_MessageBox::warning( desktop(),
955                                     tr( "SMESH_WRN_WARNING" ),
956                                     tr( "SMESH_WRN_SIZE_LIMIT_EXCEEDED" ).arg( myMesh->NbElements() ).arg( limitSize ) );
957         }
958       }
959       LightApp_SelectionMgr *Sel = selectionMgr();
960       if ( Sel )
961       {
962         SALOME_ListIO selected;
963         selected.Append( myIObject );
964         Sel->setSelectedObjects( selected );
965       }
966     }
967   }
968
969   if ( memoryLack )
970     aMemoryReserve.release();
971
972   myCompDlg->setWindowTitle(tr( computeFailed ? "SMESH_WRN_COMPUTE_FAILED" : "SMESH_COMPUTE_SUCCEED"));
973
974   // SHOW ERRORS
975   
976   bool noCompError = ( !aCompErrors.operator->() || aCompErrors->length() == 0 );
977   bool noHypoError = ( aHypErrors.isEmpty() );
978
979   SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() );
980   int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" );
981
982   bool isShowResultDlg = true;
983   switch( aNotifyMode ) {
984   case 0: // show the mesh computation result dialog NEVER
985     isShowResultDlg = false;
986     commit();
987     break;
988   case 1: // show the mesh computation result dialog if there are some errors
989     if ( memoryLack || !noCompError || !noHypoError )
990       isShowResultDlg = true;
991     else
992     {
993       isShowResultDlg = false;
994       commit();
995     }
996     break;
997   default: // show the result dialog after each mesh computation
998     isShowResultDlg = true;
999   }
1000
1001   // SHOW RESULTS
1002   if ( isShowResultDlg )
1003     showComputeResult( memoryLack, noCompError,aCompErrors, noHypoError, aHypErrors );
1004 }
1005
1006 void SMESHGUI_BaseComputeOp::showComputeResult( const bool theMemoryLack,
1007                                                 const bool theNoCompError,
1008                                                 SMESH::compute_error_array_var& theCompErrors,
1009                                                 const bool theNoHypoError,
1010                                                 const QString& theHypErrors )
1011 {
1012   bool hasShape = myMesh->HasShapeToMesh();
1013   SMESHGUI_ComputeDlg* aCompDlg = computeDlg();
1014   aCompDlg->myMemoryLackGroup->hide();
1015
1016   if ( theMemoryLack )
1017   {
1018     aCompDlg->myMemoryLackGroup->show();
1019     aCompDlg->myFullInfo->hide();
1020     aCompDlg->myBriefInfo->hide();
1021     aCompDlg->myHypErrorGroup->hide();
1022     aCompDlg->myCompErrorGroup->hide();
1023   }
1024   else if ( theNoCompError && theNoHypoError )
1025   {
1026     SMESH::long_array_var aRes = myMesh->GetMeshInfo();
1027     aCompDlg->myFullInfo->SetMeshInfo( aRes );
1028     aCompDlg->myFullInfo->show();
1029     aCompDlg->myBriefInfo->hide();
1030     aCompDlg->myHypErrorGroup->hide();
1031     aCompDlg->myCompErrorGroup->hide();
1032   }
1033   else
1034   {
1035     bool onlyWarnings = !theNoCompError; // == valid mesh computed but there are errors reported
1036     for ( int i = 0; i < theCompErrors->length() && onlyWarnings; ++i )
1037       onlyWarnings = ( theCompErrors[ i ].code == SMESH::COMPERR_WARNING ||
1038                        theCompErrors[ i ].code == SMESH::COMPERR_NO_MESH_ON_SHAPE );
1039
1040     // full or brief mesh info
1041     SMESH::long_array_var aRes = myMesh->GetMeshInfo();
1042     if ( onlyWarnings ) {
1043       aCompDlg->myFullInfo->SetMeshInfo( aRes );
1044       aCompDlg->myFullInfo->show();
1045       aCompDlg->myBriefInfo->hide();
1046     } else {
1047       aCompDlg->myBriefInfo->SetMeshInfo( aRes );
1048       aCompDlg->myBriefInfo->show();
1049       aCompDlg->myFullInfo->hide();
1050     }
1051
1052     // pbs of hypo dfinitions
1053     if ( theNoHypoError ) {
1054       aCompDlg->myHypErrorGroup->hide();
1055     } else {
1056       aCompDlg->myHypErrorGroup->show();
1057       aCompDlg->myHypErrorLabel->setText( theHypErrors );
1058     }
1059
1060     // table of errors
1061     if ( theNoCompError )
1062     {
1063       aCompDlg->myCompErrorGroup->hide();
1064     }
1065     else
1066     {
1067       aCompDlg->myCompErrorGroup->show();
1068
1069       if ( onlyWarnings )
1070         aCompDlg->myWarningLabel->show();
1071       else
1072         aCompDlg->myWarningLabel->hide();
1073
1074       if ( !hasShape ) {
1075         aCompDlg->myPublishBtn->hide();
1076         aCompDlg->myShowBtn->hide();
1077       }
1078       else {
1079         aCompDlg->myPublishBtn->show();
1080         aCompDlg->myShowBtn->show();
1081       }
1082
1083       // fill table of errors
1084       QTableWidget* tbl = aCompDlg->myTable;
1085       tbl->setRowCount( theCompErrors->length() );
1086       if ( !hasShape ) tbl->hideColumn( COL_SHAPE );
1087       else             tbl->showColumn( COL_SHAPE );
1088       tbl->setColumnWidth( COL_ERROR, 200 );
1089
1090       bool hasBadMesh = false;
1091       for ( int row = 0; row < theCompErrors->length(); ++row )
1092       {
1093         SMESH::ComputeError & err = theCompErrors[ row ];
1094
1095         QString text = err.algoName.in();
1096         if ( !tbl->item( row, COL_ALGO ) ) tbl->setItem( row, COL_ALGO, new QTableWidgetItem( text ) );
1097         else tbl->item( row, COL_ALGO )->setText( text );
1098
1099         text = SMESH::errorText( err.code, err.comment.in() );
1100         if ( !tbl->item( row, COL_ERROR ) ) tbl->setItem( row, COL_ERROR, new QTableWidgetItem( text ) );
1101         else tbl->item( row, COL_ERROR )->setText( text );
1102
1103         text = QString("%1").arg( err.subShapeID );
1104         if ( !tbl->item( row, COL_SHAPEID ) ) tbl->setItem( row, COL_SHAPEID, new QTableWidgetItem( text ) );
1105         else tbl->item( row, COL_SHAPEID )->setText( text );
1106
1107         text = hasShape ? SMESH::shapeText( err.subShapeID, myMainShape ) : QString("");
1108         if ( !tbl->item( row, COL_SHAPE ) ) tbl->setItem( row, COL_SHAPE, new QTableWidgetItem( text ) );
1109         else tbl->item( row, COL_SHAPE )->setText( text );
1110
1111         text = ( !hasShape || SMESH::getSubShapeSO( err.subShapeID, myMainShape )) ? "PUBLISHED" : "";
1112         if ( !tbl->item( row, COL_PUBLISHED ) ) tbl->setItem( row, COL_PUBLISHED, new QTableWidgetItem( text ) );
1113         else tbl->item( row, COL_PUBLISHED )->setText( text ); // if text=="", "PUBLISH" button enabled
1114
1115         text = err.hasBadMesh ? "hasBadMesh" : "";
1116         if ( !tbl->item( row, COL_BAD_MESH ) ) tbl->setItem( row, COL_BAD_MESH, new QTableWidgetItem( text ) );
1117         else tbl->item( row, COL_BAD_MESH )->setText( text );
1118         if ( err.hasBadMesh ) hasBadMesh = true;
1119
1120         //tbl->item( row, COL_ERROR )->setWordWrap( true ); // VSR: TODO ???
1121         tbl->resizeRowToContents( row );
1122       }
1123       tbl->resizeColumnToContents( COL_ALGO );
1124       tbl->resizeColumnToContents( COL_SHAPE );
1125       tbl->setWordWrap( true );
1126
1127       if ( hasBadMesh ) {
1128         aCompDlg->myBadMeshBtn->show();
1129         aCompDlg->myBadMeshToGroupBtn->show();
1130       }
1131       else {
1132         aCompDlg->myBadMeshBtn->hide();
1133         aCompDlg->myBadMeshToGroupBtn->hide();
1134       }
1135       tbl->setCurrentCell(0,0);
1136       currentCellChanged(); // to update buttons
1137     }
1138   }
1139   // show dialog and wait, becase Compute can be invoked from Preview operation
1140   //aCompDlg->exec(); // this way it becomes modal - impossible to rotate model in the Viewer
1141   aCompDlg->show();
1142 }
1143
1144 //================================================================================
1145 /*!
1146  * \brief Stops operation
1147  */
1148 //================================================================================
1149
1150 void SMESHGUI_BaseComputeOp::stopOperation()
1151 {
1152   SMESHGUI_Operation::stopOperation();
1153   if ( myTShapeDisplayer )
1154     myTShapeDisplayer->SetVisibility( false );
1155   if ( myBadMeshDisplayer ) {
1156     myBadMeshDisplayer->SetVisibility( false );
1157     // delete it in order not to have problems at its destruction when the viewer
1158     // where it worked is dead due to e.g. study closing
1159     delete myBadMeshDisplayer;
1160     myBadMeshDisplayer = 0;
1161   }
1162   myIObject.Nullify();
1163 }
1164
1165 //================================================================================
1166 /*!
1167  * \brief publish selected sub-shape
1168  */
1169 //================================================================================
1170
1171 void SMESHGUI_BaseComputeOp::onPublishShape()
1172 {
1173   GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen();
1174   SALOMEDS::Study_var study = SMESHGUI::GetSMESHGen()->GetCurrentStudy();
1175
1176   QList<int> rows;
1177   SMESH::getSelectedRows( table(), rows );
1178   int row;
1179   foreach ( row, rows )
1180   {
1181     int curSub = table()->item(row, COL_SHAPEID)->text().toInt();
1182     GEOM::GEOM_Object_wrap shape = SMESH::getSubShape( curSub, myMainShape );
1183     if ( !shape->_is_nil() && ! SMESH::getSubShapeSO( curSub, myMainShape ))
1184     {
1185       if ( !SMESH::getSubShapeSO( 1, myMainShape )) // the main shape not published
1186       {
1187         QString name = GEOMBase::GetDefaultName( SMESH::shapeTypeName( myMainShape, "MAIN_SHAPE" ));
1188         SALOMEDS::SObject_wrap so =
1189           geomGen->AddInStudy( study, myMainShape, name.toLatin1().data(), GEOM::GEOM_Object::_nil());
1190         // look for myMainShape in the table
1191         for ( int r = 0, nr = table()->rowCount(); r < nr; ++r ) {
1192           if ( table()->item( r, COL_SHAPEID )->text() == "1" ) {
1193             if ( so->_is_nil() ) {
1194               CORBA::String_var name  = so->GetName();
1195               CORBA::String_var entry = so->GetID();
1196               table()->item( r, COL_SHAPE     )->setText( name.in() );
1197               table()->item( r, COL_PUBLISHED )->setText( entry.in() );
1198             }
1199             break;
1200           }
1201         }
1202         if ( curSub == 1 ) continue;
1203       }
1204       QString name = GEOMBase::GetDefaultName( SMESH::shapeTypeName( shape, "ERROR_SHAPE" ));
1205       SALOMEDS::SObject_wrap so = geomGen->AddInStudy( study, shape, name.toLatin1().data(), myMainShape);
1206       if ( !so->_is_nil() ) {
1207         CORBA::String_var name  = so->GetName();
1208         CORBA::String_var entry = so->GetID();
1209         table()->item( row, COL_SHAPE     )->setText( name.in() );
1210         table()->item( row, COL_PUBLISHED )->setText( entry.in() );
1211       }
1212     }
1213   }
1214   getSMESHGUI()->getApp()->updateObjectBrowser();
1215   currentCellChanged(); // to update buttons
1216 }
1217
1218 //================================================================================
1219 /*!
1220  * \brief show mesh elements preventing computation of a submesh of current row
1221  */
1222 //================================================================================
1223
1224 void SMESHGUI_BaseComputeOp::onShowBadMesh()
1225 {
1226   myTShapeDisplayer->SetVisibility( false );
1227   QList<int> rows;
1228   if ( SMESH::getSelectedRows( table(), rows ) == 1 ) {
1229     bool hasBadMesh = ( !table()->item(rows.front(), COL_BAD_MESH)->text().isEmpty() );
1230     if ( hasBadMesh ) {
1231       int curSub = table()->item(rows.front(), COL_SHAPEID)->text().toInt();
1232       SMESHGUI* gui = getSMESHGUI();
1233       SMESH::SMESH_Gen_var gen = gui->GetSMESHGen();
1234       SVTK_ViewWindow*    view = SMESH::GetViewWindow( gui );
1235       if ( myBadMeshDisplayer ) delete myBadMeshDisplayer;
1236       myBadMeshDisplayer = new SMESHGUI_MeshEditPreview( view );
1237       SMESH::MeshPreviewStruct_var aMeshData = gen->GetBadInputElements(myMesh,curSub);
1238       double aPointSize = SMESH::GetFloat("SMESH:node_size",3);
1239       double aLineWidth = SMESH::GetFloat("SMESH:element_width",1);
1240       vtkProperty* prop = vtkProperty::New();
1241       prop->SetLineWidth( aLineWidth * 3 );
1242       prop->SetPointSize( aPointSize * 3 );
1243       prop->SetColor( 250, 0, 250 );
1244       myBadMeshDisplayer->GetActor()->SetProperty( prop );
1245       myBadMeshDisplayer->SetData( aMeshData._retn() );
1246       prop->Delete();
1247     }
1248   }
1249 }
1250
1251 //================================================================================
1252 /*!
1253  * \brief create groups of bad mesh elements preventing computation of a submesh of current row
1254  */
1255 //================================================================================
1256
1257 void SMESHGUI_BaseComputeOp::onGroupOfBadMesh()
1258 {
1259   QList<int> rows;
1260   SMESH::getSelectedRows( table(), rows );
1261   int row;
1262   foreach ( row, rows )
1263   {
1264     bool hasBadMesh = ( !table()->item(row, COL_BAD_MESH)->text().isEmpty() );
1265     if ( hasBadMesh ) {
1266       int     curSub = table()->item(rows.front(), COL_SHAPEID)->text().toInt();
1267       QString grName = table()->item(rows.front(), COL_SHAPE)->text();
1268       if ( grName.isEmpty() ) grName = "bad mesh";
1269       else                    grName = "bad mesh of " + grName;
1270       SMESH::SMESH_Gen_var gen = getSMESHGUI()->GetSMESHGen();
1271       SMESH::ListOfGroups_var groups
1272         ( gen->MakeGroupsOfBadInputElements(myMesh,curSub,grName.toLatin1().data()) );
1273       update( UF_ObjBrowser | UF_Model );
1274       if( LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( application() ))
1275       {
1276         QStringList anEntryList;
1277         for ( size_t i = 0; i < groups->length(); ++i )
1278           if ( _PTR(SObject) so = SMESH::FindSObject( groups[i] ))
1279             anEntryList.append( so->GetID().c_str() );
1280
1281         if ( !anEntryList.isEmpty())
1282           anApp->browseObjects( anEntryList, true, false );
1283       }
1284     }
1285   }
1286 }
1287
1288 //================================================================================
1289 /*!
1290  * \brief SLOT called when a selected cell in table() changed
1291  */
1292 //================================================================================
1293
1294 void SMESHGUI_BaseComputeOp::currentCellChanged()
1295 {
1296   myTShapeDisplayer->SetVisibility( false );
1297   if ( myBadMeshDisplayer )
1298     myBadMeshDisplayer->SetVisibility( false );
1299
1300   bool publishEnable = 0, showEnable = 0, showOnly = 1, hasBadMesh = 0;
1301   QList<int> rows;
1302   int nbSelected = SMESH::getSelectedRows( table(), rows );
1303   int row;
1304   foreach ( row, rows )
1305   {
1306     bool hasData     = ( !table()->item( row, COL_SHAPE )->text().isEmpty() );
1307     bool isPublished = ( !table()->item( row, COL_PUBLISHED )->text().isEmpty() );
1308     if ( hasData && !isPublished )
1309       publishEnable = true;
1310
1311     int curSub = table()->item( row, COL_SHAPEID )->text().toInt();
1312     bool prsReady = myTShapeDisplayer->HasReadyActorsFor( curSub, myMainShape );
1313     if ( prsReady ) {
1314       myTShapeDisplayer->Show( curSub, myMainShape, showOnly );
1315       showOnly = false;
1316     }
1317     else {
1318       showEnable = true;
1319     }
1320
1321     if ( !table()->item(row, COL_BAD_MESH)->text().isEmpty() )
1322       hasBadMesh = true;
1323   }
1324   myCompDlg->myPublishBtn->setEnabled( publishEnable );
1325   myCompDlg->myShowBtn   ->setEnabled( showEnable );
1326   myCompDlg->myBadMeshBtn->setEnabled( hasBadMesh && ( nbSelected == 1 ));
1327   myCompDlg->myBadMeshToGroupBtn->setEnabled( hasBadMesh && ( nbSelected == 1 ));
1328 }
1329
1330 //================================================================================
1331 /*!
1332  * \brief update preview
1333  */
1334 //================================================================================
1335
1336 void SMESHGUI_BaseComputeOp::onPreviewShape()
1337 {
1338   if ( myTShapeDisplayer )
1339   {
1340     SUIT_OverrideCursor aWaitCursor;
1341     QList<int> rows;
1342     SMESH::getSelectedRows( table(), rows );
1343
1344     bool showOnly = true;
1345     int row;
1346     foreach ( row, rows )
1347     {
1348       int curSub = table()->item( row, COL_SHAPEID )->text().toInt();
1349       if ( curSub > 0 ) {
1350         myTShapeDisplayer->Show( curSub, myMainShape, showOnly );
1351         showOnly = false;
1352       }
1353     }
1354     currentCellChanged(); // to update buttons
1355   }
1356 }
1357
1358 //================================================================================
1359 /*!
1360  * \brief Destructor
1361  */
1362 //================================================================================
1363
1364 SMESHGUI_BaseComputeOp::~SMESHGUI_BaseComputeOp()
1365 {
1366   delete myCompDlg;
1367   myCompDlg = 0;
1368   delete myTShapeDisplayer;
1369   if ( myBadMeshDisplayer )
1370     delete myBadMeshDisplayer;
1371 }
1372
1373 //================================================================================
1374 /*!
1375  * \brief Gets dialog of compute operation
1376  * \retval SMESHGUI_ComputeDlg* - pointer to dialog of this operation
1377  */
1378 //================================================================================
1379
1380 SMESHGUI_ComputeDlg* SMESHGUI_BaseComputeOp::computeDlg() const
1381 {
1382   if ( !myCompDlg )
1383   {
1384     SMESHGUI_BaseComputeOp* me = (SMESHGUI_BaseComputeOp*)this;
1385     me->myCompDlg = new SMESHGUI_ComputeDlg( desktop(), false );
1386     // connect signals and slots
1387     connect(myCompDlg->myShowBtn,           SIGNAL (clicked()), SLOT(onPreviewShape()));
1388     connect(myCompDlg->myPublishBtn,        SIGNAL (clicked()), SLOT(onPublishShape()));
1389     connect(myCompDlg->myBadMeshBtn,        SIGNAL (clicked()), SLOT(onShowBadMesh()));
1390     connect(myCompDlg->myBadMeshToGroupBtn, SIGNAL (clicked()), SLOT(onGroupOfBadMesh()));
1391
1392     QTableWidget* aTable = me->table();
1393     connect(aTable, SIGNAL(itemSelectionChanged()), SLOT(currentCellChanged()));
1394     connect(aTable, SIGNAL(currentCellChanged(int,int,int,int)), SLOT(currentCellChanged()));
1395   }
1396   return myCompDlg;
1397 }
1398
1399 //================================================================================
1400 /*!
1401  * \brief returns from compute mesh result dialog
1402  */
1403 //================================================================================
1404
1405 bool SMESHGUI_BaseComputeOp::onApply()
1406 {
1407   return true;
1408 }
1409
1410 //================================================================================
1411 /*!
1412  * \brief Return a table
1413  */
1414 //================================================================================
1415
1416 QTableWidget* SMESHGUI_BaseComputeOp::table()
1417 {
1418   return myCompDlg->myTable;
1419 }
1420
1421
1422 //================================================================================
1423 /*!
1424  * \brief Constructor
1425 */
1426 //================================================================================
1427
1428 SMESHGUI_ComputeOp::SMESHGUI_ComputeOp()
1429  : SMESHGUI_BaseComputeOp()
1430 {
1431 }
1432
1433
1434 //================================================================================
1435 /*!
1436  * \brief Desctructor
1437 */
1438 //================================================================================
1439
1440 SMESHGUI_ComputeOp::~SMESHGUI_ComputeOp()
1441 {
1442 }
1443
1444 //================================================================================
1445 /*!
1446  * \brief perform it's intention action: compute mesh
1447  */
1448 //================================================================================
1449
1450 void SMESHGUI_ComputeOp::startOperation()
1451 {
1452   SMESHGUI_BaseComputeOp::startOperation();
1453   if (myMesh->_is_nil())
1454     return;
1455   computeMesh();
1456 }
1457
1458 //================================================================================
1459 /*!
1460  * \brief check the same operations on the same mesh
1461  */
1462 //================================================================================
1463
1464 bool SMESHGUI_BaseComputeOp::isValid(  SUIT_Operation* theOp  ) const
1465 {
1466   SMESHGUI_BaseComputeOp* baseOp = dynamic_cast<SMESHGUI_BaseComputeOp*>( theOp );
1467   bool ret = true;
1468   if ( !myMesh->_is_nil() && baseOp ) {
1469     SMESH::SMESH_Mesh_var aMesh = baseOp->getMesh();
1470     if ( !aMesh->_is_nil() && aMesh->GetId() == myMesh->GetId() ) ret = false;
1471   }
1472   return ret;
1473 }
1474
1475 //================================================================================
1476 /*!
1477  * \brief Gets dialog of this operation
1478  * \retval LightApp_Dialog* - pointer to dialog of this operation
1479  */
1480 //================================================================================
1481
1482 LightApp_Dialog* SMESHGUI_ComputeOp::dlg() const
1483 {
1484   return computeDlg();
1485 }
1486
1487 //================================================================================
1488 /*!
1489  * \brief Constructor
1490 */
1491 //================================================================================
1492
1493 SMESHGUI_PrecomputeOp::SMESHGUI_PrecomputeOp()
1494  : SMESHGUI_BaseComputeOp(),
1495  myDlg( 0 ),
1496  myOrderMgr( 0 ),
1497  myActiveDlg( 0 ),
1498  myPreviewDisplayer( 0 )
1499 {
1500   myHelpFileName = "constructing_meshes_page.html#preview_mesh_anchor";
1501 }
1502
1503 //================================================================================
1504 /*!
1505  * \brief Destructor
1506  */
1507 //================================================================================
1508
1509 SMESHGUI_PrecomputeOp::~SMESHGUI_PrecomputeOp()
1510 {
1511   delete myDlg;
1512   myDlg = 0;
1513   delete myOrderMgr;
1514   myOrderMgr = 0;
1515   myActiveDlg = 0;
1516   if ( myPreviewDisplayer )
1517     delete myPreviewDisplayer;
1518   myPreviewDisplayer = 0;
1519 }
1520
1521 //================================================================================
1522 /*!
1523  * \brief Gets current dialog of this operation
1524  * \retval LightApp_Dialog* - pointer to dialog of this operation
1525  */
1526 //================================================================================
1527
1528 LightApp_Dialog* SMESHGUI_PrecomputeOp::dlg() const
1529 {
1530   return myActiveDlg;
1531 }
1532
1533 //================================================================================
1534 /*!
1535  * \brief perform it's intention action: prepare data
1536  */
1537 //================================================================================
1538
1539 void SMESHGUI_PrecomputeOp::startOperation()
1540 {
1541   if ( !myDlg )
1542   {
1543     myDlg = new SMESHGUI_PrecomputeDlg( desktop() );
1544     
1545     // connect signals
1546     connect( myDlg, SIGNAL( preview() ), this, SLOT( onPreview() ) );
1547     connect( myDlg, SIGNAL( dlgOk() ), this, SLOT( onCompute() ) );
1548     connect( myDlg, SIGNAL( dlgApply() ), this, SLOT( onCompute() ) );
1549   }
1550   myActiveDlg = myDlg;
1551
1552   // connect signal to compute dialog. which will be shown after Compute mesh operation
1553   SMESHGUI_ComputeDlg* cmpDlg = computeDlg();
1554   if ( cmpDlg )
1555   {
1556     // disconnect signals
1557     disconnect( cmpDlg, SIGNAL( dlgOk() ), this, SLOT( onOk() ) );
1558     disconnect( cmpDlg, SIGNAL( dlgApply() ), this, SLOT( onApply() ) );
1559     disconnect( cmpDlg, SIGNAL( dlgCancel() ), this, SLOT( onCancel() ) );
1560     disconnect( cmpDlg, SIGNAL( dlgClose() ), this, SLOT( onCancel() ) );
1561     disconnect( cmpDlg, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) );
1562
1563     // connect signals
1564     if( cmpDlg->testButtonFlags( QtxDialog::OK ) )
1565       connect( cmpDlg, SIGNAL( dlgOk() ), this, SLOT( onOk() ) );
1566     if( cmpDlg->testButtonFlags( QtxDialog::Apply ) )
1567       connect( cmpDlg, SIGNAL( dlgApply() ), this, SLOT( onApply() ) );
1568     if( cmpDlg->testButtonFlags( QtxDialog::Help ) )
1569       connect( cmpDlg, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) );
1570     if( cmpDlg->testButtonFlags( QtxDialog::Cancel ) )
1571       connect( cmpDlg, SIGNAL( dlgCancel() ), this, SLOT( onCancel() ) );
1572     if( cmpDlg->testButtonFlags( QtxDialog::Close ) )
1573       connect( cmpDlg, SIGNAL( dlgClose() ), this, SLOT( onCancel() ) );
1574   }
1575
1576   SMESHGUI_BaseComputeOp::startOperation();
1577   if (myMesh->_is_nil())
1578     return;
1579
1580   if (myDlg->getPreviewMode() == -1)
1581   {
1582     // nothing to preview
1583     SUIT_MessageBox::warning(desktop(),
1584                              tr("SMESH_WRN_WARNING"),
1585                              tr("SMESH_WRN_NOTHING_PREVIEW"));
1586     onCancel();
1587     return;
1588   }
1589
1590   // disconnect slot from preview dialog to have Apply from results of compute operation only 
1591   disconnect( myDlg, SIGNAL( dlgOk() ), this, SLOT( onOk() ) );
1592   disconnect( myDlg, SIGNAL( dlgApply() ), this, SLOT( onApply() ) );
1593
1594   myDlg->show();
1595 }
1596
1597 //================================================================================
1598 /*!
1599  * \brief Stops operation
1600  */
1601 //================================================================================
1602
1603 void SMESHGUI_PrecomputeOp::stopOperation()
1604 {
1605   if ( myPreviewDisplayer )
1606   {
1607     myPreviewDisplayer->SetVisibility( false );
1608     delete myPreviewDisplayer;
1609     myPreviewDisplayer = 0;
1610   }
1611   myMapShapeId.clear();
1612   SMESHGUI_BaseComputeOp::stopOperation();
1613 }
1614
1615 //================================================================================
1616 /*!
1617  * \brief reinitialize dialog after operaiton become active again
1618  */
1619 //================================================================================
1620
1621 void SMESHGUI_PrecomputeOp::resumeOperation()
1622 {
1623   if ( myActiveDlg == myDlg )
1624     initDialog();
1625   SMESHGUI_BaseComputeOp::resumeOperation();
1626 }
1627
1628 //================================================================================
1629 /*!
1630  * \brief perform it's intention action: reinitialise dialog
1631  */
1632 //================================================================================
1633
1634 void SMESHGUI_PrecomputeOp::initDialog()
1635 {
1636   QList<int> modes;
1637
1638   QMap<int, int> modeMap;
1639   _PTR(SObject)  pMesh = studyDS()->FindObjectID( myIObject->getEntry() );
1640   getAssignedAlgos( pMesh, modeMap );
1641   if ( modeMap.contains( SMESH::DIM_3D ) )
1642   {
1643     if ( modeMap.contains( SMESH::DIM_2D ) )
1644       modes.append( SMESH::DIM_2D );
1645     if ( modeMap.contains( SMESH::DIM_1D ) )
1646       modes.append( SMESH::DIM_1D );
1647   }
1648   else if ( modeMap.contains( SMESH::DIM_2D ) )
1649   {
1650     if ( modeMap.contains( SMESH::DIM_1D ) )
1651       modes.append( SMESH::DIM_1D );
1652   }
1653
1654   myOrderMgr = new SMESHGUI_MeshOrderMgr( myDlg->getMeshOrderBox() );
1655   myOrderMgr->SetMesh( myMesh );
1656   bool isOrder = myOrderMgr->GetMeshOrder(myPrevOrder);
1657   myDlg->getMeshOrderBox()->setShown(isOrder);
1658   if ( !isOrder ) {
1659     delete myOrderMgr;
1660     myOrderMgr = 0;
1661   }
1662
1663   myDlg->setPreviewModes( modes );
1664 }
1665
1666 //================================================================================
1667 /*!
1668  * \brief detect asigned mesh algorithms
1669  */
1670 //================================================================================
1671
1672 void SMESHGUI_PrecomputeOp::getAssignedAlgos(_PTR(SObject) theMesh,
1673                                              QMap<int,int>& theModeMap)
1674 {
1675   _PTR(SObject)          aHypRoot;
1676   _PTR(GenericAttribute) anAttr;
1677   int aPart = SMESH::Tag_RefOnAppliedAlgorithms;
1678   if ( theMesh && theMesh->FindSubObject( aPart, aHypRoot ) )
1679   {
1680     _PTR(ChildIterator) anIter =
1681       SMESH::GetActiveStudyDocument()->NewChildIterator( aHypRoot );
1682     for ( ; anIter->More(); anIter->Next() )
1683     {
1684       _PTR(SObject) anObj = anIter->Value();
1685       _PTR(SObject) aRefObj;
1686       if ( anObj->ReferencedObject( aRefObj ) )
1687         anObj = aRefObj;
1688       else
1689         continue;
1690       
1691       if ( anObj->FindAttribute( anAttr, "AttributeName" ) )
1692       {
1693         CORBA::Object_var aVar = _CAST(SObject,anObj)->GetObject();
1694         if ( CORBA::is_nil( aVar ) )
1695           continue;
1696         
1697         for( int dim = SMESH::DIM_1D; dim <= SMESH::DIM_3D; dim++ )
1698         {
1699           SMESH::SMESH_Algo_var algo;
1700           switch(dim) {
1701           case SMESH::DIM_1D: algo = SMESH::SMESH_1D_Algo::_narrow( aVar ); break;
1702           case SMESH::DIM_2D: algo = SMESH::SMESH_2D_Algo::_narrow( aVar ); break;
1703           case SMESH::DIM_3D: algo = SMESH::SMESH_3D_Algo::_narrow( aVar ); break;
1704           default: break;
1705           }
1706           if ( !algo->_is_nil() )
1707             theModeMap[ dim ] = 0;
1708         }
1709       }
1710     }
1711   }
1712 }
1713
1714 //================================================================================
1715 /*!
1716  * \brief perform it's intention action: compute mesh
1717  */
1718 //================================================================================
1719
1720 void SMESHGUI_PrecomputeOp::onCompute()
1721 {
1722   myDlg->hide();
1723   if (myOrderMgr && myOrderMgr->IsOrderChanged())
1724     myOrderMgr->SetMeshOrder();
1725   myMapShapeId.clear();
1726   myActiveDlg = computeDlg();
1727   computeMesh();
1728 }
1729
1730 //================================================================================
1731 /*!
1732  * \brief perform it's intention action: compute mesh
1733  */
1734 //================================================================================
1735
1736 void SMESHGUI_PrecomputeOp::onCancel()
1737 {
1738   QObject* curDlg = sender();
1739   if ( curDlg == computeDlg() && myActiveDlg == myDlg )
1740   {
1741     // return from error messages
1742     myDlg->show();
1743     return;
1744   }
1745
1746   bool isRestoreOrder = false;
1747   if ( myActiveDlg == myDlg  && !myMesh->_is_nil() && myMapShapeId.count() )
1748   {
1749     // ask to remove already computed mesh elements
1750     if ( SUIT_MessageBox::question( desktop(), tr( "SMESH_WARNING" ),
1751                                     tr( "CLEAR_SUBMESH_QUESTION" ),
1752                                     tr( "SMESH_BUT_DELETE" ), tr( "SMESH_BUT_NO" ), 0, 1 ) == 0 )
1753     {
1754       // remove all submeshes for collected shapes
1755       QMap<int,int>::const_iterator it = myMapShapeId.constBegin();
1756       for ( ; it != myMapShapeId.constEnd(); ++it )
1757         myMesh->ClearSubMesh( *it );
1758       isRestoreOrder = true;
1759     }
1760   }
1761
1762   // return previous mesh order
1763   if (myOrderMgr && myOrderMgr->IsOrderChanged()) {
1764     if (!isRestoreOrder)
1765       isRestoreOrder = 
1766         (SUIT_MessageBox::question( desktop(), tr( "SMESH_WARNING" ),
1767                                     tr( "SMESH_REJECT_MESH_ORDER" ),
1768                                     tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ) == 0);
1769     if (isRestoreOrder)
1770       myOrderMgr->SetMeshOrder(myPrevOrder);
1771   }
1772
1773   delete myOrderMgr;
1774   myOrderMgr = 0;
1775
1776   myMapShapeId.clear();
1777   SMESHGUI_BaseComputeOp::onCancel();
1778 }
1779
1780 //================================================================================
1781 /*!
1782  * \brief perform it's intention action: preview mesh
1783  */
1784 //================================================================================
1785
1786 void SMESHGUI_PrecomputeOp::onPreview()
1787 {
1788   if ( !myDlg || myMesh->_is_nil() || myMainShape->_is_nil() )
1789     return;
1790
1791   _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh);
1792   if ( !aMeshSObj )
1793     return;
1794
1795   // set modified submesh priority if any
1796   if (myOrderMgr && myOrderMgr->IsOrderChanged())
1797     myOrderMgr->SetMeshOrder();
1798
1799   // Compute preview of mesh, 
1800   // i.e. compute mesh till indicated dimension
1801   int dim = myDlg->getPreviewMode();
1802   
1803   SMESH::MemoryReserve aMemoryReserve;
1804   
1805   SMESH::compute_error_array_var aCompErrors;
1806   QString                        aHypErrors;
1807
1808   bool computeFailed = true, memoryLack = false;
1809
1810   SMESHGUI_ComputeDlg* aCompDlg = computeDlg();
1811     aCompDlg->myMeshName->setText( aMeshSObj->GetName().c_str() );
1812
1813   SMESHGUI* gui = getSMESHGUI();
1814   SMESH::SMESH_Gen_var gen = gui->GetSMESHGen();
1815   SMESH::algo_error_array_var errors = gen->GetAlgoState(myMesh,myMainShape);
1816   if ( errors->length() > 0 ) {
1817     aHypErrors = SMESH::GetMessageOnAlgoStateErrors( errors.in() );
1818   }
1819
1820   SUIT_OverrideCursor aWaitCursor;
1821
1822   SVTK_ViewWindow*    view = SMESH::GetViewWindow( gui );
1823   if ( myPreviewDisplayer ) delete myPreviewDisplayer;
1824   myPreviewDisplayer = new SMESHGUI_MeshEditPreview( view );
1825   
1826   SMESH::long_array_var aShapesId = new SMESH::long_array();
1827   try {
1828 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1829     OCC_CATCH_SIGNALS;
1830 #endif
1831       
1832     SMESH::MeshPreviewStruct_var previewData =
1833       gen->Precompute(myMesh, myMainShape, (SMESH::Dimension)dim, aShapesId);
1834
1835     SMESH::MeshPreviewStruct* previewRes = previewData._retn();
1836     if ( previewRes && previewRes->nodesXYZ.length() > 0 )
1837     {
1838       computeFailed = false;
1839       myPreviewDisplayer->SetData( previewRes );
1840       // append shape indeces with computed mesh entities
1841       for ( int i = 0, n = aShapesId->length(); i < n; i++ )
1842         myMapShapeId[ aShapesId[ i ] ] = 0;
1843     }
1844     else
1845       myPreviewDisplayer->SetVisibility(false);
1846   }
1847   catch(const SALOME::SALOME_Exception & S_ex){
1848     memoryLack = true;
1849     myPreviewDisplayer->SetVisibility(false);
1850   }
1851
1852   try {
1853 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1854     OCC_CATCH_SIGNALS;
1855 #endif
1856     aCompErrors = gen->GetComputeErrors( myMesh, myMainShape );
1857     // check if there are memory problems
1858     for ( int i = 0; (i < aCompErrors->length()) && !memoryLack; ++i )
1859       memoryLack = ( aCompErrors[ i ].code == SMESH::COMPERR_MEMORY_PB );
1860   }
1861   catch(const SALOME::SALOME_Exception & S_ex){
1862     memoryLack = true;
1863   }
1864
1865   if ( memoryLack )
1866     aMemoryReserve.release();
1867
1868   bool noCompError = ( !aCompErrors.operator->() || aCompErrors->length() == 0 );
1869   bool noHypoError = ( aHypErrors.isEmpty() );
1870
1871   SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( gui );
1872   int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" );
1873
1874   bool isShowError = true;
1875   switch( aNotifyMode ) {
1876   case 0: // show the mesh computation result dialog NEVER
1877     isShowError = false;
1878     break;
1879   case 1: // show the mesh computation result dialog if there are some errors
1880   default: // show the result dialog after each mesh computation
1881     if ( !computeFailed && !memoryLack && noCompError && noHypoError )
1882       isShowError = false;
1883     break;
1884   }
1885
1886   aWaitCursor.suspend();
1887   // SHOW ERRORS
1888   if ( isShowError )
1889   {
1890     myDlg->hide();
1891     aCompDlg->setWindowTitle(tr( computeFailed ? "SMESH_WRN_COMPUTE_FAILED" : "SMESH_COMPUTE_SUCCEED"));
1892     showComputeResult( memoryLack, noCompError, aCompErrors, noHypoError, aHypErrors );
1893   }
1894 }
1895
1896
1897 //================================================================================
1898 /*!
1899  * \brief Constructor
1900 */
1901 //================================================================================
1902
1903 SMESHGUI_PrecomputeDlg::SMESHGUI_PrecomputeDlg( QWidget* parent )
1904  : SMESHGUI_Dialog( parent, false, false, OK | Cancel | Help ),
1905    myOrderBox(0)
1906 {
1907   setWindowTitle( tr( "CAPTION" ) );
1908
1909   setButtonText( OK, tr( "COMPUTE" ) );
1910   QFrame* main = mainFrame();
1911
1912   QVBoxLayout* layout = new QVBoxLayout( main );
1913
1914   myOrderBox = new SMESHGUI_MeshOrderBox( main );
1915   layout->addWidget(myOrderBox);
1916
1917   QFrame* frame = new QFrame( main );
1918   layout->setMargin(0); layout->setSpacing(0);
1919   layout->addWidget( frame );
1920
1921   QHBoxLayout* frameLay = new QHBoxLayout( frame );
1922   frameLay->setMargin(0); frameLay->setSpacing(SPACING);
1923   
1924   myPreviewMode = new QtxComboBox( frame );
1925   frameLay->addWidget( myPreviewMode );
1926
1927   myPreviewBtn = new QPushButton( tr( "PREVIEW" ), frame );
1928   frameLay->addWidget( myPreviewBtn );
1929
1930   connect( myPreviewBtn, SIGNAL( clicked( bool ) ), this, SIGNAL( preview() ) );
1931 }
1932
1933 //================================================================================
1934 /*!
1935  * \brief Destructor
1936 */
1937 //================================================================================
1938
1939 SMESHGUI_PrecomputeDlg::~SMESHGUI_PrecomputeDlg()
1940 {
1941 }
1942
1943 //================================================================================
1944 /*!
1945  * \brief Sets available preview modes
1946 */
1947 //================================================================================
1948
1949 void SMESHGUI_PrecomputeDlg::setPreviewModes( const QList<int>& theModes )
1950 {
1951   myPreviewMode->clear();
1952   QList<int>::const_iterator it = theModes.constBegin();
1953   for ( int i = 0; it != theModes.constEnd(); ++it, i++ )
1954   {
1955     QString mode = QString( "PREVIEW_%1" ).arg( *it );
1956     myPreviewMode->addItem( tr( mode.toLatin1().data() ) );
1957     myPreviewMode->setId( i, *it );
1958   }
1959   myPreviewBtn->setEnabled( !theModes.isEmpty() );
1960 }
1961
1962 //================================================================================
1963 /*!
1964  * \brief Returns current preview mesh mode
1965 */
1966 //================================================================================
1967
1968 int SMESHGUI_PrecomputeDlg::getPreviewMode() const
1969 {
1970   return myPreviewMode->currentId();
1971 }
1972
1973 //================================================================================
1974 /*!
1975  * \brief Returns current preview mesh mode
1976 */
1977 //================================================================================
1978
1979 SMESHGUI_MeshOrderBox* SMESHGUI_PrecomputeDlg::getMeshOrderBox() const
1980 {
1981   return myOrderBox;
1982 }
1983
1984
1985 //================================================================================
1986 /*!
1987  * \brief Constructor
1988 */
1989 //================================================================================
1990
1991 SMESHGUI_EvaluateOp::SMESHGUI_EvaluateOp()
1992  : SMESHGUI_BaseComputeOp()
1993 {
1994 }
1995
1996
1997 //================================================================================
1998 /*!
1999  * \brief Desctructor
2000 */
2001 //================================================================================
2002
2003 SMESHGUI_EvaluateOp::~SMESHGUI_EvaluateOp()
2004 {
2005 }
2006
2007 //================================================================================
2008 /*!
2009  * \brief perform it's intention action: compute mesh
2010  */
2011 //================================================================================
2012
2013 void SMESHGUI_EvaluateOp::startOperation()
2014 {
2015   SMESHGUI_BaseComputeOp::evaluateDlg();
2016   SMESHGUI_BaseComputeOp::startOperation();
2017   if (myMesh->_is_nil())
2018     return;
2019   evaluateMesh();
2020 }
2021
2022 //================================================================================
2023 /*!
2024  * \brief Gets dialog of this operation
2025  * \retval LightApp_Dialog* - pointer to dialog of this operation
2026  */
2027 //================================================================================
2028
2029 LightApp_Dialog* SMESHGUI_EvaluateOp::dlg() const
2030 {
2031   return evaluateDlg();
2032 }
2033
2034 //================================================================================
2035 /*!
2036  * \brief evaluateMesh()
2037 */
2038 //================================================================================
2039
2040 void SMESHGUI_BaseComputeOp::evaluateMesh()
2041 {
2042   // EVALUATE MESH
2043
2044   SMESH::MemoryReserve aMemoryReserve;
2045
2046   SMESH::compute_error_array_var aCompErrors;
2047   QString                        aHypErrors;
2048
2049   bool evaluateFailed = true, memoryLack = false;
2050   SMESH::long_array_var aRes;
2051
2052   _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh);
2053   if ( !aMeshSObj ) //  IPAL21340
2054     return;
2055
2056   bool hasShape = myMesh->HasShapeToMesh();
2057   bool shapeOK = myMainShape->_is_nil() ? !hasShape : hasShape;
2058   if ( shapeOK )
2059   {
2060     myCompDlg->myMeshName->setText( aMeshSObj->GetName().c_str() );
2061     SMESH::SMESH_Gen_var gen = getSMESHGUI()->GetSMESHGen();
2062     SMESH::algo_error_array_var errors = gen->GetAlgoState(myMesh,myMainShape);
2063     if ( errors->length() > 0 ) {
2064       aHypErrors = SMESH::GetMessageOnAlgoStateErrors( errors.in() );
2065     }
2066     SUIT_OverrideCursor aWaitCursor;
2067     try {
2068 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2069       OCC_CATCH_SIGNALS;
2070 #endif
2071       aRes = gen->Evaluate(myMesh, myMainShape);
2072     }
2073     catch(const SALOME::SALOME_Exception & S_ex){
2074       memoryLack = true;
2075     }
2076
2077     try {
2078 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2079       OCC_CATCH_SIGNALS;
2080 #endif
2081       aCompErrors = gen->GetComputeErrors( myMesh, myMainShape );
2082     }
2083     catch(const SALOME::SALOME_Exception & S_ex){
2084       memoryLack = true;
2085     }
2086   }
2087
2088   if ( memoryLack )
2089     aMemoryReserve.release();
2090
2091   evaluateFailed =  ( aCompErrors->length() > 0 );
2092   myCompDlg->setWindowTitle(tr( evaluateFailed ? "SMESH_WRN_EVALUATE_FAILED" : "SMESH_EVALUATE_SUCCEED"));
2093
2094   // SHOW ERRORS
2095   
2096   bool noCompError = ( !aCompErrors.operator->() || aCompErrors->length() == 0 );
2097   bool noHypoError = ( aHypErrors.isEmpty() );
2098
2099   //SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() );
2100   //int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" );
2101
2102   bool isShowResultDlg = true;
2103   //if( noHypoError )
2104   //switch( aNotifyMode ) {
2105   //case 0: // show the mesh computation result dialog NEVER
2106   //isShowResultDlg = false;
2107   //commit();
2108   //break;
2109   //case 1: // show the mesh computation result dialog if there are some errors
2110   //if ( memoryLack || !noHypoError )
2111   //  isShowResultDlg = true;
2112   //else
2113   //{
2114   //  isShowResultDlg = false;
2115   //  commit();
2116   //}
2117   //break;
2118   //default: // show the result dialog after each mesh computation
2119   //isShowResultDlg = true;
2120   //}
2121
2122   // SHOW RESULTS
2123   if ( isShowResultDlg )
2124     showEvaluateResult( aRes, memoryLack, noCompError, aCompErrors,
2125                         noHypoError, aHypErrors);
2126 }
2127
2128
2129 void SMESHGUI_BaseComputeOp::showEvaluateResult(const SMESH::long_array& theRes,
2130                                                 const bool theMemoryLack,
2131                                                 const bool theNoCompError,
2132                                                 SMESH::compute_error_array_var& theCompErrors,
2133                                                 const bool theNoHypoError,
2134                                                 const QString& theHypErrors)
2135 {
2136   bool hasShape = myMesh->HasShapeToMesh();
2137   SMESHGUI_ComputeDlg* aCompDlg = evaluateDlg();
2138   aCompDlg->myMemoryLackGroup->hide();
2139
2140   if ( theMemoryLack )
2141   {
2142     aCompDlg->myMemoryLackGroup->show();
2143     aCompDlg->myFullInfo->hide();
2144     aCompDlg->myBriefInfo->hide();
2145     aCompDlg->myHypErrorGroup->hide();
2146     aCompDlg->myCompErrorGroup->hide();
2147   }
2148   else if ( theNoCompError && theNoHypoError )
2149   {
2150     aCompDlg->myFullInfo->SetMeshInfo( theRes );
2151     aCompDlg->myFullInfo->show();
2152     aCompDlg->myBriefInfo->hide();
2153     aCompDlg->myHypErrorGroup->hide();
2154     aCompDlg->myCompErrorGroup->hide();
2155   }
2156   else
2157   {
2158     QTableWidget* tbl = aCompDlg->myTable;
2159     aCompDlg->myBriefInfo->SetMeshInfo( theRes );
2160     aCompDlg->myBriefInfo->show();
2161     aCompDlg->myFullInfo->hide();
2162
2163     if ( theNoHypoError ) {
2164       aCompDlg->myHypErrorGroup->hide();
2165     }
2166     else {
2167       aCompDlg->myHypErrorGroup->show();
2168       aCompDlg->myHypErrorLabel->setText( theHypErrors );
2169     }
2170
2171     if ( theNoCompError ) {
2172       aCompDlg->myCompErrorGroup->hide();
2173     }
2174     else {
2175       aCompDlg->myCompErrorGroup->show();
2176
2177       aCompDlg->myPublishBtn->hide();
2178       aCompDlg->myShowBtn->hide();
2179
2180       // fill table of errors
2181       tbl->setRowCount( theCompErrors->length() );
2182       if ( !hasShape ) tbl->hideColumn( COL_SHAPE );
2183       else             tbl->showColumn( COL_SHAPE );
2184       tbl->setColumnWidth( COL_ERROR, 200 );
2185
2186       bool hasBadMesh = false;
2187       for ( int row = 0; row < theCompErrors->length(); ++row )
2188       {
2189         SMESH::ComputeError & err = theCompErrors[ row ];
2190
2191         QString text = err.algoName.in();
2192         if ( !tbl->item( row, COL_ALGO ) ) tbl->setItem( row, COL_ALGO, new QTableWidgetItem( text ) );
2193         else tbl->item( row, COL_ALGO )->setText( text );
2194
2195         text = SMESH::errorText( err.code, err.comment.in() );
2196         if ( !tbl->item( row, COL_ERROR ) ) tbl->setItem( row, COL_ERROR, new QTableWidgetItem( text ) );
2197         else tbl->item( row, COL_ERROR )->setText( text );
2198
2199         text = QString("%1").arg( err.subShapeID );
2200         if ( !tbl->item( row, COL_SHAPEID ) ) tbl->setItem( row, COL_SHAPEID, new QTableWidgetItem( text ) );
2201         else tbl->item( row, COL_SHAPEID )->setText( text );
2202
2203         text = hasShape ? SMESH::shapeText( err.subShapeID, myMainShape ) : QString("");
2204         if ( !tbl->item( row, COL_SHAPE ) ) tbl->setItem( row, COL_SHAPE, new QTableWidgetItem( text ) );
2205         else tbl->item( row, COL_SHAPE )->setText( text );
2206
2207         text = ( !hasShape || SMESH::getSubShapeSO( err.subShapeID, myMainShape )) ? "PUBLISHED" : "";
2208         if ( !tbl->item( row, COL_PUBLISHED ) ) tbl->setItem( row, COL_PUBLISHED, new QTableWidgetItem( text ) );
2209         else tbl->item( row, COL_PUBLISHED )->setText( text ); // if text=="", "PUBLISH" button enabled
2210
2211         text = err.hasBadMesh ? "hasBadMesh" : "";
2212         if ( !tbl->item( row, COL_BAD_MESH ) ) tbl->setItem( row, COL_BAD_MESH, new QTableWidgetItem( text ) );
2213         else tbl->item( row, COL_BAD_MESH )->setText( text );
2214         if ( err.hasBadMesh ) hasBadMesh = true;
2215
2216         //tbl->item( row, COL_ERROR )->setWordWrap( true ); // VSR: TODO ???
2217         tbl->resizeRowToContents( row );
2218       }
2219       tbl->resizeColumnToContents( COL_ALGO );
2220       tbl->resizeColumnToContents( COL_SHAPE );
2221       tbl->setWordWrap( true );
2222
2223       if ( hasBadMesh )
2224       {
2225         aCompDlg->myBadMeshBtn->show();
2226         aCompDlg->myBadMeshToGroupBtn->show();
2227       }
2228       else
2229       {
2230         aCompDlg->myBadMeshBtn->hide();
2231         aCompDlg->myBadMeshToGroupBtn->hide();
2232       }
2233       tbl->setCurrentCell(0,0);
2234       currentCellChanged(); // to update buttons
2235     }
2236   }
2237   // show dialog and wait, becase Compute can be invoked from Preview operation
2238   //aCompDlg->exec(); // this way it becomes modal - impossible to rotate model in the Viewer
2239   aCompDlg->show();
2240 }
2241
2242
2243 //================================================================================
2244 /*!
2245  * \brief Gets dialog of evaluate operation
2246  * \retval SMESHGUI_ComputeDlg* - pointer to dialog of this operation
2247  */
2248 //================================================================================
2249
2250 SMESHGUI_ComputeDlg* SMESHGUI_BaseComputeOp::evaluateDlg() const
2251 {
2252   if ( !myCompDlg )
2253   {
2254     SMESHGUI_BaseComputeOp* me = (SMESHGUI_BaseComputeOp*)this;
2255     me->myCompDlg = new SMESHGUI_ComputeDlg( desktop(), true );
2256     // connect signals and slots
2257     connect(myCompDlg->myShowBtn,    SIGNAL (clicked()), SLOT(onPreviewShape()));
2258     connect(myCompDlg->myPublishBtn, SIGNAL (clicked()), SLOT(onPublishShape()));
2259     connect(myCompDlg->myBadMeshBtn, SIGNAL (clicked()), SLOT(onShowBadMesh()));
2260     QTableWidget* aTable = me->table();
2261     connect(aTable, SIGNAL(itemSelectionChanged()), SLOT(currentCellChanged()));
2262     connect(aTable, SIGNAL(currentCellChanged(int,int,int,int)), SLOT(currentCellChanged()));
2263   }
2264   return myCompDlg;
2265 }
2266