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