Salome HOME
Updated copyright comment
[modules/geom.git] / src / MeasureGUI / MeasureGUI_AnnotationDlg.cxx
1 // Copyright (C) 2016-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   : MeasureGUI_AnnotationDlg.cxx
21
22 #include "MeasureGUI.h"
23 #include "MeasureGUI_AnnotationDlg.h"
24 #include "MeasureGUI_AnnotationInteractor.h"
25
26 #include <DlgRef.h>
27 #include <GEOMBase.h>
28 #include <GEOMBase_Skeleton.h>
29 #include <GEOM_Displayer.h>
30 #include <GeometryGUI.h>
31 #include <GEOMGUI_AnnotationMgr.h>
32 #include <GEOMGUI_TextTreeWdg.h>
33
34 #include <SOCC_Prs.h>
35 #include <SOCC_ViewModel.h>
36
37 #include <SalomeApp_Application.h>
38 #include <SalomeApp_Study.h>
39 #include <SalomeApp_Tools.h>
40 #include <SalomeApp_IntSpinBox.h>
41 #include <SalomeApp_DoubleSpinBox.h>
42
43 #include <LightApp_SelectionMgr.h>
44
45 #include <OCCViewer_ViewModel.h>
46 #include <OCCViewer_ViewManager.h>
47 #include <OCCViewer_ViewWindow.h>
48 #include <OCCViewer_ViewPort3d.h>
49 #include <SVTK_ViewModel.h>
50 #include <SALOME_Prs.h>
51 #include <SALOME_ListIO.hxx>
52
53 #include <SUIT_Desktop.h>
54 #include <SUIT_MessageBox.h>
55 #include <SUIT_OverrideCursor.h>
56 #include <SUIT_ResourceMgr.h>
57 #include <SUIT_Session.h>
58 #include <SUIT_ViewWindow.h>
59 #include <SUIT_ViewManager.h>
60
61 #include <QComboBox>
62 #include <QGridLayout>
63 #include <QGroupBox>
64 #include <QHeaderView>
65 #include <QInputDialog>
66 #include <QLabel>
67 #include <QLineEdit>
68 #include <QPushButton>
69 #include <QStack>
70 #include <QTableWidget>
71 #include <QVBoxLayout>
72
73 #include <AIS_InteractiveContext.hxx>
74 #include <AIS_ListOfInteractive.hxx>
75 #include <AIS_ListIteratorOfListOfInteractive.hxx>
76
77 #include <Bnd_Box.hxx>
78 #include <BRepAdaptor_CompCurve.hxx>
79 #include <BRepAdaptor_Curve.hxx>
80 #include <BRepAdaptor_Surface.hxx>
81 #include <BRepBndLib.hxx>
82 #include <BRep_Tool.hxx>
83
84 #include <SelectMgr_ViewerSelector.hxx>
85
86 #include <TopoDS.hxx>
87 #include <TopExp.hxx>
88 #include <TopExp_Explorer.hxx>
89 #include <TopTools_IndexedMapOfShape.hxx>
90 #include <TColStd_IndexedMapOfInteger.hxx>
91 #include <TColStd_MapOfInteger.hxx>
92 #include <TColStd_DataMapIteratorOfDataMapOfIntegerInteger.hxx>
93
94 #include <NCollection_Handle.hxx>
95
96 #include <limits>
97
98 #include <SALOMEDS_wrap.hxx>
99 #include <GEOMImpl_Types.hxx>
100
101 #include <Basics_OCCTVersion.hxx>
102
103 #ifdef max
104 #undef max
105 #endif
106
107 //=======================================================================
108 //function : MeasureGUI_AnnotationDlg
109 //purpose  : 
110 //=======================================================================
111
112 MeasureGUI_AnnotationDlg::MeasureGUI_AnnotationDlg( GeometryGUI* theGeometryGUI, const bool theIsCreate,
113                                                    QWidget* parent, bool modal, Qt::WindowFlags fl )
114 : GEOMBase_Skeleton( theGeometryGUI, parent, modal, fl ),
115   myIsCreation( theIsCreate ), myShapeNameModified( false )
116 {
117   myEditCurrentArgument = 0;
118
119   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
120   QPixmap iconSelect( resMgr->loadPixmap( "GEOM", tr( "ICON_SELECT" ) ) );
121
122   setWindowTitle( myIsCreation ? tr( "CREATE_ANNOTATION_TITLE" ) : tr( "EDIT_ANNOTATION_TITLE" ) );
123
124   // Shape type button group
125   mainFrame()->GroupBoxName->hide();
126   mainFrame()->GroupConstructors->hide();
127
128   // Field properties
129   QGroupBox* propGroup = new QGroupBox( tr( "ANNOTATION_PROPERTIES" ), centralWidget() );
130   QGridLayout* propLayout = new QGridLayout( propGroup );
131   propLayout->setMargin( 9 );
132   propLayout->setSpacing( 6 );
133
134   QLabel* textLabel = new QLabel( tr( "ANNOTATION_TEXT" ), propGroup );
135   myTextEdit = new QLineEdit( propGroup );
136   propLayout->addWidget( textLabel, 0, 0 );
137   propLayout->addWidget( myTextEdit, 0, 1, 1, 2 );
138
139   // shape
140   QLabel* shapeLabel = new QLabel( tr( "ANNOTATION_SHAPE" ), propGroup );
141   myShapeSelBtn = new QPushButton( propGroup );
142   myShapeSelBtn->setIcon( iconSelect );
143   myShapeSelBtn->setEnabled( myIsCreation );
144   myShapeName = new QLineEdit( propGroup );
145   myShapeName->setReadOnly( true );
146   myShapeName->setEnabled( myIsCreation );
147
148   // data type
149   myIsScreenFixed = new QCheckBox( tr( "ANNOTATION_IS_SCREEN_FIXED" ), propGroup );
150   myIsScreenFixed->setChecked( false ); // 3D, not fixed
151
152   propLayout->addWidget( shapeLabel, 1, 0 );
153   propLayout->addWidget( myShapeSelBtn, 1, 1 );
154   propLayout->addWidget( myShapeName, 1, 2 );
155   propLayout->addWidget( myIsScreenFixed, 2, 0, 1, 3 );
156   propLayout->setColumnStretch( 2, 5 );
157
158   QLabel* shapeTypeLabel = new QLabel( tr( "ANNOTATION_SUB_SHAPE" ), propGroup );
159   mySubShapeTypeCombo = new QComboBox( propGroup );
160   mySubShapeTypeCombo->setEnabled( myIsCreation );
161   mySubShapeTypeCombo->addItem( tr( "WHOLE_SHAPE" ), TopAbs_SHAPE );
162   mySubShapeTypeCombo->addItem( tr( "GEOM_VERTEX" ), TopAbs_VERTEX );
163   mySubShapeTypeCombo->addItem( tr( "GEOM_EDGE" ), TopAbs_EDGE );
164   mySubShapeTypeCombo->addItem( tr( "GEOM_FACE" ), TopAbs_FACE );
165   mySubShapeTypeCombo->addItem( tr( "GEOM_SOLID" ), TopAbs_SOLID );
166   mySubShapeTypeCombo->setCurrentIndex( 0 ); // SHAPE
167
168   propLayout->addWidget( shapeTypeLabel, 3, 0 );
169   propLayout->addWidget( mySubShapeTypeCombo, 3, 1, 1, 2 );
170
171   // sub-shape
172   mySubShapeSelBtn = new QPushButton( propGroup );
173   mySubShapeSelBtn->setIcon( iconSelect );
174   mySubShapeSelBtn->setEnabled( myIsCreation );
175   mySubShapeName = new QLineEdit( propGroup );
176   mySubShapeName->setReadOnly( true );
177   mySubShapeName->setEnabled( myIsCreation );
178
179   propLayout->addWidget( mySubShapeSelBtn, 4, 1 );
180   propLayout->addWidget( mySubShapeName, 4, 2 );
181
182   QVBoxLayout* layout = new QVBoxLayout( centralWidget() );
183   layout->setMargin( 0 );
184   layout->setSpacing( 6 );
185   layout->addWidget( propGroup );
186
187   setHelpFileName( "annotation_page.html" );
188
189   LightApp_SelectionMgr* aSelMgr = myGeomGUI->getApp()->selectionMgr();
190   connect( aSelMgr, SIGNAL( currentSelectionChanged() ), this,
191            SLOT( SelectionIntoArgument() ) );
192   connect( buttonOk(), SIGNAL( clicked() ), this, SLOT( ClickOnOk() ) );
193   connect( buttonApply(), SIGNAL( clicked() ), this, SLOT( ClickOnApply() ) );
194
195   myInteractor = new MeasureGUI_AnnotationInteractor( theGeometryGUI, parent );
196   myInteractor->Enable();
197
198   connect( myInteractor, SIGNAL( SignalInteractionFinished( Handle_GEOM_Annotation ) ),
199            this, SLOT( onDragged( Handle_GEOM_Annotation ) ) );
200
201   Init();
202 }
203
204 //=======================================================================
205 //function : ~MeasureGUI_AnnotationDlg
206 //purpose  : 
207 //=======================================================================
208
209 MeasureGUI_AnnotationDlg::~MeasureGUI_AnnotationDlg() {
210 }
211
212 //=================================================================================
213 // function : Init()
214 // purpose  : fills annotation properties with default values( in create mode ) or
215 // the values of modified object
216 //=================================================================================
217 void MeasureGUI_AnnotationDlg::Init()
218 {
219   if ( myIsCreation ) {
220
221     // default presentation values
222     myIsPositionDefined = false;
223     myAnnotationProperties.Text = tr( "ANNOTATION_PREFIX" );
224     myAnnotationProperties.IsVisible = false;
225     myAnnotationProperties.IsScreenFixed = false;
226     myAnnotationProperties.Attach = gp_Pnt( 0, 0, 0 );
227     myAnnotationProperties.ShapeIndex = -1;
228     myAnnotationProperties.ShapeType = ( int ) TopAbs_SHAPE;
229
230     // update internal controls and fields following to default values
231     activateSelectionArgument( myShapeSelBtn );
232
233     myTextEdit->setText( myAnnotationProperties.Text );
234     myShapeNameModified = false;
235     myIsScreenFixed->setChecked( myAnnotationProperties.IsScreenFixed );
236
237     int aSubShapeTypeIndex = -1;
238     int aTypesCount = mySubShapeTypeCombo->count();
239     for ( int i = 0; i < aTypesCount && aSubShapeTypeIndex < 0; i++ ) {
240       int aType = mySubShapeTypeCombo->itemData( i ).toInt();
241       if ( aType == myAnnotationProperties.ShapeType )
242         aSubShapeTypeIndex = i;
243     }
244     mySubShapeTypeCombo->setCurrentIndex( aSubShapeTypeIndex );
245
246     mySelectionMode = ( TopAbs_ShapeEnum ) myAnnotationProperties.ShapeType;
247     SelectionIntoArgument();
248     updateSubShapeEnableState();
249
250     // connect controls
251     connect( myShapeSelBtn, SIGNAL( clicked() ), this,
252         SLOT( SetEditCurrentArgument() ) );
253     connect( mySubShapeSelBtn, SIGNAL( clicked() ), this,
254         SLOT( SetEditCurrentArgument() ) );
255
256     connect( myTextEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChange() ) );
257     connect( myIsScreenFixed, SIGNAL( clicked( bool ) ), this, SLOT( onTypeChange() ) );
258     connect( mySubShapeTypeCombo, SIGNAL( currentIndexChanged( int ) ),
259         this, SLOT( onSubShapeTypeChange() ) );
260
261     //SelectionIntoArgument();
262
263     redisplayPreview();
264   } else { // edition
265     myIsPositionDefined = true;
266     mySelectionMode = TopAbs_SHAPE;
267     // find annotation
268     GEOMGUI_TextTreeWdg* aTextTreeWdg = myGeomGUI->GetTextTreeWdg();
269     // text tree widget should be not empty
270     QMap<QString, QList<int> > anAnnotations;
271     aTextTreeWdg->getSelected( anAnnotations );
272     // there is only one annotation selected when edit is started
273     QMap<QString, QList<int> >::const_iterator anIt = anAnnotations.begin();
274     myEditAnnotationEntry = anIt.key();
275     myEditAnnotationIndex = anIt.value()[0];
276
277     SalomeApp_Study* aStudy = getStudy();
278     _PTR(SObject) aSObj = aStudy->studyDS()->FindObjectID( myEditAnnotationEntry.toStdString() );
279     const Handle(GEOMGUI_AnnotationAttrs) aShapeAnnotations = GEOMGUI_AnnotationAttrs::FindAttributes( aSObj );
280     if ( !aShapeAnnotations.IsNull() ) {
281       aShapeAnnotations->GetProperties( myEditAnnotationIndex, myAnnotationProperties );
282
283       myShape = GEOM::GEOM_Object::_narrow( GeometryGUI::ClientSObjectToObject(aSObj) );
284     }
285
286     /// fill dialog controls
287     myTextEdit->setText( myAnnotationProperties.Text );
288     myShapeNameModified = false;
289     myIsScreenFixed->setChecked( myAnnotationProperties.IsScreenFixed );
290
291     int aSubShapeTypeIndex = -1;
292     int aTypesCount = mySubShapeTypeCombo->count();
293     for ( int i = 0; i < aTypesCount && aSubShapeTypeIndex < 0; i++ ) {
294       int aType = mySubShapeTypeCombo->itemData( i ).toInt();
295       if ( aType == myAnnotationProperties.ShapeType )
296         aSubShapeTypeIndex = i;
297     }
298     mySubShapeTypeCombo->setCurrentIndex( aSubShapeTypeIndex );
299
300     QString aShapeName = "";
301     _PTR(GenericAttribute) anAttr;
302     if ( aSObj && aSObj->FindAttribute( anAttr, "AttributeName") ) {
303       _PTR(AttributeName) aNameAttr( anAttr );
304       aNameAttr->Value();
305       aShapeName = aNameAttr->Value().c_str();
306     }
307     myShapeName->setText( aShapeName );
308
309     QString aSubShapeName = "";
310     TopAbs_ShapeEnum aShapeType = ( TopAbs_ShapeEnum ) myAnnotationProperties.ShapeType;
311     if ( aShapeType != TopAbs_SHAPE ) {
312       aSubShapeName = QString( "%1:%2_%3" ).arg( aShapeName )
313                                            .arg( GEOMBase::TypeName( aShapeType ) )
314                                            .arg( myAnnotationProperties.ShapeIndex );
315     }
316     mySubShapeName->setText( aSubShapeName );
317
318     mySelectionMode = ( TopAbs_ShapeEnum ) myAnnotationProperties.ShapeType;
319     //SelectionIntoArgument();
320     updateSubShapeEnableState();
321
322     // connect controls
323     connect( myTextEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChange() ) );
324     connect( myIsScreenFixed, SIGNAL( clicked( bool ) ), this, SLOT( onTypeChange() ) );
325
326     myGeomGUI->GetAnnotationMgr()->SetPreviewStyle( myEditAnnotationEntry, myEditAnnotationIndex, true );
327
328     SalomeApp_Application* anApp = myGeomGUI->getApp();
329     if ( anApp )
330     {
331       OCCViewer_ViewManager* aVM = (OCCViewer_ViewManager*)anApp->getViewManager( OCCViewer_Viewer::Type(), false );
332       OCCViewer_Viewer* aViewer = (OCCViewer_Viewer*)aVM->getViewModel();
333       aViewer->unHighlightAll( true, true );
334     }
335
336     redisplayPreview();
337   }
338 }
339
340 //=================================================================================
341 // function : activateSelection
342 // purpose  : Activate local selection
343 //=================================================================================
344 void MeasureGUI_AnnotationDlg::activateSelection()
345 {
346   globalSelection( GEOM_ALLOBJECTS );
347   if ( !myShape->_is_nil() && mySelectionMode != TopAbs_SHAPE ) {
348     localSelection( myShape.get(), mySelectionMode );
349   }
350 }
351
352 //=================================================================================
353 // function : getShapeType()
354 // purpose  :
355 //=================================================================================
356 TopAbs_ShapeEnum MeasureGUI_AnnotationDlg::getShapeType() const
357 {
358   return ( TopAbs_ShapeEnum ) mySubShapeTypeCombo->itemData(
359       mySubShapeTypeCombo->currentIndex() ).toInt();
360 }
361
362 //=================================================================================
363 // function : ClickOnOk()
364 // purpose  :
365 //=================================================================================
366 void MeasureGUI_AnnotationDlg::ClickOnOk()
367 {
368   setIsApplyAndClose( true );
369   if ( ClickOnApply() )
370     ClickOnCancel();
371   setIsApplyAndClose( false );
372 }
373
374 //=================================================================================
375 // function : ClickOnApply()
376 // purpose  :
377 //=================================================================================
378 bool MeasureGUI_AnnotationDlg::ClickOnApply()
379 {
380   if ( !isApplyAndClose() ) {
381     setIsDisableBrowsing( true );
382     setIsDisplayResult( false );
383   }
384
385   QString msg;
386   if ( !isValid( msg ) ) {
387     showError( msg );
388     return false;
389   }
390
391   SUIT_OverrideCursor wc;
392   SUIT_Session::session()->activeApplication()->putInfo( "" );
393
394   try {
395     if ( openCommand() )
396       if ( !execute( /*isApplyAndClose()*/ ) ) {
397         abortCommand();
398         showError();
399         return false;
400       }
401   } catch ( const SALOME::SALOME_Exception& e ) {
402     SalomeApp_Tools::QtCatchCorbaException( e );
403     abortCommand();
404     return false;
405   }
406   commitCommand();
407
408   if ( !isApplyAndClose() ) {
409     setIsDisableBrowsing( false );
410     setIsDisplayResult( true );
411   }
412
413   if ( !myShape->_is_nil() ) {
414     redisplay( myShape.get() );
415   }
416
417   if ( myIsCreation ) {
418
419    if ( !isApplyAndClose() )
420      Init();
421   }
422
423   return true;
424 }
425
426 //=================================================================================
427 // function : SetEditCurrentArgument()
428 // purpose  : process click on shape/sub-shape button. It stores as current edit argument
429 // the corresponded line edit, set focus in it and unpress other button if it was pressed
430 //=================================================================================
431 void MeasureGUI_AnnotationDlg::SetEditCurrentArgument()
432 {
433   QPushButton* aSelectButton = ( QPushButton* ) sender();
434
435   activateSelectionArgument( aSelectButton );
436
437   SelectionIntoArgument();
438 }
439
440 //=================================================================================
441 // function : activateSelectionArgument()
442 // purpose  : it stores as current edit argument the corresponded line edit,
443 // sets the focus on it and unpresses other button if it was pressed
444 //=================================================================================
445 void MeasureGUI_AnnotationDlg::activateSelectionArgument
446 (
447   QPushButton* theSelectionButton ) {
448   QPushButton* anOtherButton = 0;
449   if ( theSelectionButton == myShapeSelBtn ) {
450     myEditCurrentArgument = myShapeName;
451     anOtherButton = mySubShapeSelBtn;
452     // throw down current sub-shape selection
453     TopAbs_ShapeEnum aShapeType = TopAbs_SHAPE;
454
455     mySubShapeTypeCombo->setCurrentIndex( 0 );
456     mySubShapeName->setText( "" );
457
458     myAnnotationProperties.ShapeType = aShapeType;
459     myAnnotationProperties.ShapeIndex = -1;
460
461     mySelectionMode = aShapeType;
462
463     updateSubShapeEnableState();
464   } else if ( theSelectionButton == mySubShapeSelBtn ) {
465     myEditCurrentArgument = mySubShapeName;
466     anOtherButton = myShapeSelBtn;
467   } else
468     myEditCurrentArgument = 0;
469
470   if ( myEditCurrentArgument )
471     myEditCurrentArgument->setFocus();
472
473   theSelectionButton->setDown( true );
474   anOtherButton->setDown( false );
475 }
476
477 //=================================================================================
478 // function : SelectionIntoArgument()
479 // purpose  : Called when selection has changed. Sets the current selection in the
480 // annotation property and redisplays presentation
481 //=================================================================================
482 void MeasureGUI_AnnotationDlg::SelectionIntoArgument()
483 {
484   if ( myIsCreation && myEditCurrentArgument )
485   {
486     myEditCurrentArgument->setText( "" );
487
488     GEOM::GeomObjPtr anObj = getSelected( mySelectionMode );
489
490     bool hasAttachPoint = false;
491     gp_Pnt anAttachPoint( 0, 0, 0 );
492     int aSubShapeIndex = -1;
493     if ( myEditCurrentArgument == myShapeName ) { // Selection of a shape is active
494       if ( anObj->_is_nil() || mySelectionMode != TopAbs_SHAPE ) {
495         myShape = GEOM::GEOM_Object::_nil();
496       } else {
497         myShape = anObj;
498         QString aName = GEOMBase::GetName( anObj.get() );
499         myEditCurrentArgument->setText( aName );
500         if ( !myShapeNameModified ) {
501           myTextEdit->setText( aName );
502           onTextChange();
503           // modified state should not be changed as modification was performed not manually
504           myShapeNameModified = false;
505         }
506       }
507
508       bool aNullShape = myShape->_is_nil();
509       mySubShapeTypeCombo->setEnabled( !aNullShape );
510       updateSubShapeEnableState();
511
512       activateSelection();
513
514       if ( !aNullShape ) {
515
516         TopoDS_Shape aShape;
517         GEOMBase::GetShape( myShape.get(), aShape );
518
519         hasAttachPoint = getPickedPoint( anAttachPoint, aShape );
520         if ( !hasAttachPoint ) {
521
522           anAttachPoint = getAttachPoint( aShape, hasAttachPoint );
523         }
524       }
525     } else if ( myEditCurrentArgument == mySubShapeName ) {
526       if ( !myShape->_is_nil() ) {
527
528         if ( anObj->_is_nil() ) {
529           myEditCurrentArgument->setText( QString() );
530         }
531         else {
532
533           QString aName = GEOMBase::GetName( anObj.get() );
534           myEditCurrentArgument->setText( aName );
535
536           TopTools_IndexedMapOfShape aMainMap;
537           TopoDS_Shape aMainShape;
538           TopoDS_Shape aSubShape;
539           GEOMBase::GetShape( myShape.get(), aMainShape );
540           GEOMBase::GetShape( anObj.get(), aSubShape );
541           TopExp::MapShapes( aMainShape, getShapeType(), aMainMap );
542
543           if ( aMainMap.Contains( aSubShape ) ) {
544             aSubShapeIndex = aMainMap.FindIndex( aSubShape );
545           }
546
547           if ( !aSubShape.IsNull() ) {
548
549             TopoDS_Shape aShape;
550             GEOMBase::GetShape( myShape.get(), aShape );
551
552             hasAttachPoint = getPickedPoint( anAttachPoint, aSubShape );
553             if ( !hasAttachPoint ) {
554
555               anAttachPoint = getAttachPoint( aSubShape, hasAttachPoint );
556             }
557           }
558         }
559       }
560       myAnnotationProperties.ShapeIndex = aSubShapeIndex;
561     }
562
563     gp_Trsf aToShapeLCS;
564     if ( !myShape->_is_nil() ) {
565
566       TopoDS_Shape aShape;
567       GEOMBase::GetShape( myShape.get(), aShape );
568       gp_Ax3 aShapeLCS = gp_Ax3().Transformed( aShape.Location().Transformation() );
569       aToShapeLCS.SetTransformation( gp_Ax3(), aShapeLCS );
570     }
571
572     myAnnotationProperties.Attach = anAttachPoint.Transformed( aToShapeLCS );
573
574     if ( hasAttachPoint && !myIsPositionDefined ) {
575
576       gp_Pnt aPosition = getDefaultPosition( anAttachPoint );
577
578       myAnnotationProperties.Position = ( !myAnnotationProperties.IsScreenFixed ) ?
579         aPosition.Transformed( aToShapeLCS ) : aPosition;
580
581       myIsPositionDefined = true;
582     }
583     else if ( !hasAttachPoint ) {
584
585       myIsPositionDefined = false;
586     }
587   }
588   redisplayPreview();
589 }
590
591 //=======================================================================
592 //function : closeEvent
593 //purpose  :
594 //=======================================================================
595 void MeasureGUI_AnnotationDlg::closeEvent( QCloseEvent* theEv )
596 {
597   if ( myInteractor ) {
598     myInteractor->Disable();
599   }
600   GEOMBase_Skeleton::closeEvent( theEv );
601 }
602
603 //=======================================================================
604 //function : onTextChange
605 //purpose  : change annotation text
606 //=======================================================================
607 void MeasureGUI_AnnotationDlg::onTextChange()
608 {
609   myAnnotationProperties.Text = myTextEdit->text();
610   if ( !myShapeNameModified )
611     myShapeNameModified = true;
612   redisplayPreview();
613 }
614
615 //=======================================================================
616 //function : onTypeChange
617 //purpose  : change annotation type: 2D or 3D
618 //=======================================================================
619 void MeasureGUI_AnnotationDlg::onTypeChange()
620 {
621   const bool isScreenFixedBefore = myAnnotationProperties.IsScreenFixed;
622
623   myAnnotationProperties.IsScreenFixed = myIsScreenFixed->isChecked();
624
625   // convert point position from screen space to 3D space
626   if ( myIsPositionDefined ) {
627
628     SUIT_ViewWindow* anActiveView = GEOMBase_Helper::getActiveView();
629     OCCViewer_ViewWindow* anOccView = NULL;
630     if ( anActiveView ) {
631
632       anOccView = qobject_cast<OCCViewer_ViewWindow*>( anActiveView );
633     }
634
635     if ( anOccView ) {
636
637       TopoDS_Shape aShape;
638       GEOMBase::GetShape( myShape.get(), aShape );
639       const gp_Ax3 aShapeLCS = gp_Ax3().Transformed( aShape.Location().Transformation() );
640
641       gp_Trsf aToShapeLCS, aFrShapeLCS;
642       aFrShapeLCS.SetTransformation( aShapeLCS, gp_Ax3() );
643       aToShapeLCS.SetTransformation( gp_Ax3(), aShapeLCS );
644
645       const Handle(V3d_View) aView3d = anOccView->getViewPort()->getView();
646       const gp_Pnt aPosition = myAnnotationProperties.Position;
647       const gp_Pnt aAttach3d = myAnnotationProperties.Attach.Transformed( aFrShapeLCS );
648       if ( !isScreenFixedBefore ) {
649
650         gp_Pnt aPosition3d = aPosition.Transformed( aFrShapeLCS );
651         gp_Pnt aPosition2d = GEOM_Annotation::ConvertPosition2d( aPosition3d, aAttach3d, aView3d );
652         myAnnotationProperties.Position = aPosition2d;
653       }
654       else {
655
656         gp_Pnt aPosition3d = GEOM_Annotation::ConvertPosition3d( aPosition, aAttach3d, aView3d );
657         aPosition3d = aPosition3d.Transformed( aToShapeLCS );
658         myAnnotationProperties.Position = aPosition3d;
659       }
660     }
661   }
662
663   redisplayPreview();
664 }
665
666 //=======================================================================
667 //function : onSubShapeTypeChange
668 //purpose  :
669 //=======================================================================
670 void MeasureGUI_AnnotationDlg::onSubShapeTypeChange()
671 {
672   const TopAbs_ShapeEnum aShapeType = getShapeType();
673   
674   activateSelectionArgument( aShapeType == TopAbs_SHAPE ? myShapeSelBtn : mySubShapeSelBtn );
675
676   myAnnotationProperties.ShapeType = aShapeType;
677
678   if ( aShapeType != mySelectionMode ) {
679     mySubShapeName->setText( "" );
680     myAnnotationProperties.ShapeIndex = -1;
681     mySelectionMode = aShapeType;
682   }
683
684   updateSubShapeEnableState();
685
686   activateSelection();
687   redisplayPreview();
688 }
689
690 //=================================================================================
691 // function : onDragged
692 // purpose  :
693 //=================================================================================
694 void MeasureGUI_AnnotationDlg::onDragged( Handle_GEOM_Annotation theAnnotation )
695 {
696   TopoDS_Shape aShape;
697   GEOMBase::GetShape( myShape.get(), aShape );
698   gp_Ax3 aShapeLCS = gp_Ax3().Transformed( aShape.Location().Transformation() );
699   gp_Trsf aToShapeLCS;
700   aToShapeLCS.SetTransformation( gp_Ax3(), aShapeLCS );
701
702   if ( !myAnnotationProperties.IsScreenFixed ) {
703     myAnnotationProperties.Position = theAnnotation->GetPosition().Transformed( aToShapeLCS );
704
705     if ( !myIsCreation ) {
706       myGeomGUI->GetAnnotationMgr()->storeFixedPosition( myEditAnnotationEntry, 0 );
707     }
708   }
709   else {
710     myAnnotationProperties.Position = theAnnotation->GetPosition();
711   }
712 }
713
714 #define RETURN_WITH_MSG( a, b ) \
715   if ( ( a ) ) { \
716     theMessage += ( b ); \
717     return false; \
718   }
719
720 //=================================================================================
721 // function : createOperation
722 // purpose  :
723 //=================================================================================
724 GEOM::GEOM_IOperations_ptr MeasureGUI_AnnotationDlg::createOperation()
725 {
726   return getGeomEngine()->GetILocalOperations( );
727 }
728
729 //=================================================================================
730 // function : isValid()
731 // purpose  : Verify validity of input data
732 //=================================================================================
733 bool MeasureGUI_AnnotationDlg::isValid( QString& theMessage )
734 {
735   SalomeApp_Study* study = getStudy();
736   RETURN_WITH_MSG( !study, tr( "GEOM_NO_STUDY" ) )
737   RETURN_WITH_MSG( study->studyDS()->GetProperties()->IsLocked(),
738       tr( "GEOM_STUDY_LOCKED" ) )
739
740   if ( myIsCreation ) {
741     RETURN_WITH_MSG( myShape->_is_nil(), tr( "NO_SHAPE" ) )
742   } else {
743     //RETURN_WITH_MSG( CORBA::is_nil( myShape ), tr( "NO_FIELD" ) )
744   }
745
746   if ( getShapeType() != TopAbs_SHAPE ) {
747     if ( myIsCreation ) {
748       RETURN_WITH_MSG( myAnnotationProperties.ShapeIndex < 0, tr( "NO_SUB_SHAPE" ) )
749     } else {
750       //RETURN_WITH_MSG( CORBA::is_nil( myShape ), tr( "NO_FIELD" ) )
751     }
752   }
753
754   if ( myIsCreation ) {
755     RETURN_WITH_MSG( !myIsPositionDefined, tr( "NO_POSITION" ) )
756   }
757
758   return true;
759 }
760
761 //=================================================================================
762 // function : execute
763 // purpose  :
764 //=================================================================================
765 bool MeasureGUI_AnnotationDlg::execute()
766 {
767   QString anError;
768   if ( !isValid( anError ) )
769     return false;
770
771   SalomeApp_Study* aStudy = getStudy();
772   _PTR(SObject) aSObj = aStudy->studyDS()->FindObjectID( myShape->GetStudyEntry() );
773
774   Handle(GEOMGUI_AnnotationAttrs) aShapeAnnotations =
775     GEOMGUI_AnnotationAttrs::FindOrCreateAttributes( aSObj, aStudy );
776
777   if ( myIsCreation ) {
778     myAnnotationProperties.IsVisible = true; // initially created annotation is hidden
779
780     aShapeAnnotations->Append( myAnnotationProperties );
781
782     myGeomGUI->emitAnnotationsUpdated( QString( myShape->GetStudyEntry() ) );
783
784     erasePreview( true );
785
786     globalSelection( myGeomGUI->getLocalSelectionMode() , true );
787
788     myGeomGUI->GetAnnotationMgr()->Display( myShape->GetStudyEntry(), aShapeAnnotations->GetNbAnnotation()-1 );
789   }
790   else {
791
792     aShapeAnnotations->SetProperties( myEditAnnotationIndex, myAnnotationProperties );
793     myGeomGUI->emitAnnotationsUpdated( QString( myShape->GetStudyEntry() ) );
794   }
795   return true;
796 }
797
798 //=================================================================================
799 // function : buildPrs
800 // purpose  : creates annotation presentation object and corresponded SALOME presentation
801 //=================================================================================
802 SALOME_Prs* MeasureGUI_AnnotationDlg::buildPrs()
803 {
804   QString aEntry = myIsCreation ? 
805     myGeomGUI->GetAnnotationMgr()->makeAnnotationEntry( myShape->GetStudyEntry(), - 1 ) :
806     myGeomGUI->GetAnnotationMgr()->makeAnnotationEntry( myEditAnnotationEntry, myEditAnnotationIndex );
807
808   SALOME_Prs* aPrs = myGeomGUI->GetAnnotationMgr()->CreatePresentation(
809     myAnnotationProperties, myShape.get(), 0, aEntry );
810
811   // set preview style for the created presentation
812   AIS_ListOfInteractive aIObjects;
813   ((SOCC_Prs*)aPrs)->GetObjects( aIObjects );
814   AIS_ListOfInteractive::Iterator aIOIt( aIObjects );
815   for ( ; aIOIt.More(); aIOIt.Next() ) {
816   
817     Handle( GEOM_Annotation ) aPresentation = Handle( GEOM_Annotation )::DownCast( aIOIt.Value() );
818     aPresentation->SetTextColor( Quantity_NOC_VIOLET );
819     aPresentation->SetLineColor( Quantity_NOC_VIOLET );
820     aPresentation->SetDepthCulling( Standard_False );
821   }
822
823   return aPrs;
824 }
825
826 //=================================================================================
827 // function : updateSubShapeEnableState
828 // purpose  : creates annotation presentation object and corresponded SALOME presentation
829 //=================================================================================
830 void MeasureGUI_AnnotationDlg::updateSubShapeEnableState()
831 {
832   if ( !myIsCreation )
833     return;
834
835   bool isWholeShape = getShapeType() == TopAbs_SHAPE;
836   bool aNullShape = myShape->_is_nil();
837   mySubShapeSelBtn->setEnabled( !aNullShape && !isWholeShape );
838   mySubShapeName->setEnabled( !aNullShape && !isWholeShape );
839 }
840
841 //=================================================================================
842 // function : redisplayPreview
843 // purpose  : creates annotation presentation object and corresponded SALOME presentation
844 //=================================================================================
845 void MeasureGUI_AnnotationDlg::redisplayPreview()
846 {
847   if ( myIsCreation ) {
848
849     QString aMess;
850     if ( !isValid( aMess ) ) {
851       erasePreview( true );
852       return;
853     }
854
855     erasePreview( false );
856
857     try {
858       SUIT_OverrideCursor wc;
859       getDisplayer()->SetToActivate( true );
860
861       if ( SALOME_Prs* aPrs = buildPrs() )
862         displayPreview( aPrs );
863       } catch ( const SALOME::SALOME_Exception& e ) {
864         SalomeApp_Tools::QtCatchCorbaException( e );
865       } catch ( ... ) {
866     }
867   }
868   else {
869     myGeomGUI->GetAnnotationMgr()->Redisplay( myEditAnnotationEntry, myEditAnnotationIndex,
870                                               myAnnotationProperties );
871   }
872
873   QString anEntry;
874   if ( myIsCreation && !myShape->_is_nil() ) {
875     anEntry = myGeomGUI->GetAnnotationMgr()->makeAnnotationEntry( myShape->GetStudyEntry(), -1 );
876   }
877   else if ( !myIsCreation ) {
878     anEntry = myGeomGUI->GetAnnotationMgr()->makeAnnotationEntry( myEditAnnotationEntry, myEditAnnotationIndex );
879   }
880
881   myInteractor->SetEditEntry( anEntry );
882 }
883
884 //=================================================================================
885 // function : getPickedPoint
886 // purpose  : finds picked point in active viewer on the selected shape
887 //=================================================================================
888 bool MeasureGUI_AnnotationDlg::getPickedPoint( gp_Pnt& thePnt, const TopoDS_Shape& theShape )
889 {
890   if ( theShape.ShapeType() == TopAbs_VERTEX )
891   {
892     bool isOk = false;
893     thePnt = getAttachPoint( theShape, isOk );
894     return isOk;
895   }
896
897   const SUIT_ViewWindow* anActiveView = GEOMBase_Helper::getActiveView();
898   if ( !anActiveView )
899     return false;
900
901   const OCCViewer_ViewWindow* anOccView = qobject_cast<const OCCViewer_ViewWindow*>( anActiveView );
902   if ( !anOccView || !anOccView->underMouse() )
903     return false;
904
905   OCCViewer_ViewManager* aVM = ( OCCViewer_ViewManager* )anOccView->getViewManager();
906   OCCViewer_Viewer* aViewer = aVM->getOCCViewer();
907
908   Handle(AIS_InteractiveContext) anAISContext = aViewer->getAISContext();
909   Handle(SelectMgr_ViewerSelector) aSelector;
910   aSelector = anAISContext->MainSelector();
911
912   if ( aSelector->NbPicked() < 1 )
913     return false;
914
915   thePnt = aSelector->PickedPoint( 1 );
916   return true;
917 }
918
919 //=================================================================================
920 // function : getAttachPoint
921 // purpose  : computes default attachment point on the shape
922 //=================================================================================
923 gp_Pnt MeasureGUI_AnnotationDlg::getAttachPoint( const TopoDS_Shape& theShape, bool& theIsOk )
924 {
925   gp_Pnt aPnt( 0.0, 0.0, 0.0 );
926   theIsOk = true;
927   if ( theShape.ShapeType() == TopAbs_COMPSOLID
928     || theShape.ShapeType() == TopAbs_SOLID
929     || theShape.ShapeType() == TopAbs_SHELL )
930   {
931     Bnd_Box aBox;
932     BRepBndLib::Add( theShape, aBox );
933     const gp_Pnt aMin = aBox.CornerMin();
934     const gp_Pnt aMax = aBox.CornerMax();
935     aPnt = gp_Pnt( (aMin.X() + aMax.X()) / 2.0,
936                    (aMin.Y() + aMax.Y()) / 2.0,
937                    (aMin.Z() + aMax.Z()) / 2.0 );
938   }
939   else if ( theShape.ShapeType() == TopAbs_FACE )
940   {
941     BRepAdaptor_Surface aFace( TopoDS::Face( theShape ) );
942     const Standard_Real aU1 = aFace.FirstUParameter();
943     const Standard_Real aU2 = aFace.LastUParameter();
944     const Standard_Real aV1 = aFace.FirstVParameter();
945     const Standard_Real aV2 = aFace.LastVParameter();
946     aPnt = aFace.Value( ( aU1 + aU2 ) / 2.0, ( aV1 + aV2 ) / 2.0 );
947   }
948   else if ( theShape.ShapeType() == TopAbs_WIRE )
949   {
950     BRepAdaptor_CompCurve aWire( TopoDS::Wire( theShape ) );
951     const Standard_Real aP1 = aWire.FirstParameter();
952     const Standard_Real aP2 = aWire.LastParameter();
953     aPnt = aWire.Value( ( aP1 + aP2 ) / 2.0 );
954   }
955   else if ( theShape.ShapeType() == TopAbs_EDGE )
956   {
957     BRepAdaptor_Curve aEdge( TopoDS::Edge( theShape ) );
958     const Standard_Real aP1 = aEdge.FirstParameter();
959     const Standard_Real aP2 = aEdge.LastParameter();
960     aPnt = aEdge.Value( ( aP1 + aP2 ) / 2.0 );
961   }
962   else if ( theShape.ShapeType() == TopAbs_VERTEX )
963   {
964     aPnt = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) );
965   }
966   else
967   {
968     theIsOk = false;
969   }
970
971   return aPnt;
972 }
973
974 //=================================================================================
975 // function : getDefaultPosition
976 // purpose  : computes default position for the given attachment point
977 //=================================================================================
978 gp_Pnt MeasureGUI_AnnotationDlg::getDefaultPosition( const gp_Pnt& theAttach )
979 {
980   SUIT_ViewWindow* anActiveView = GEOMBase_Helper::getActiveView();
981   if ( !anActiveView ) {
982
983     return myAnnotationProperties.IsScreenFixed ? gp::Origin() : theAttach;
984   }
985
986   OCCViewer_ViewWindow* anOccView = qobject_cast<OCCViewer_ViewWindow*>( anActiveView );
987   if ( !anOccView ) {
988
989     return myAnnotationProperties.IsScreenFixed ? gp::Origin() : theAttach;
990   }
991
992   OCCViewer_ViewPort3d* aViewPort = anOccView->getViewPort();
993
994   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
995
996   const QFont aFont = aResMgr->fontValue( "Geometry", "shape_annotation_font", QFont( "Y14.5M-2009", 24 ) );
997
998   const Handle(V3d_View) aView3d = aViewPort->getView();
999
1000   const Standard_Real aFontHeight =( aFont.pixelSize() != -1 ) ? aFont.pixelSize() : aFont.pointSize();
1001
1002   return GEOM_Annotation::GetDefaultPosition( myAnnotationProperties.IsScreenFixed,
1003     theAttach, aFontHeight * 1.5, aView3d );
1004 }