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