Salome HOME
DCQ : Update msg File.
[modules/kernel.git] / src / SALOMEGUI / SALOMEGUI_Application.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SALOMEGUI_Application.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SALOME
27 //  $Header$
28
29 #include "SALOMEGUI_Application.h"
30 #include "SALOMEGUI_Desktop.h"
31 #include "SALOMEGUI_ImportOperation.h"
32 #include "SALOMEGUI.h"
33 #include "SALOME_Selection.h"
34 #include "SALOME_ListIO.hxx"
35 #include "SALOME_ListIteratorOfListIO.hxx"
36 #include "SALOME_InteractiveObject.hxx"
37 #include "QAD.h"
38 #include "QAD_Desktop.h"
39 #include "QAD_RightFrame.h"
40 #include "QAD_LeftFrame.h"
41 #include "QAD_ObjectBrowser.h"
42 #include "QAD_Resource.h"
43 #include "QAD_Tools.h"
44 #include "QAD_WaitCursor.h"
45
46 // QT Includes
47 #include <qapplication.h>
48 #include <qpopupmenu.h>
49 #include <qmessagebox.h>
50
51 // Open CASCADE Include
52 #include <Standard_Failure.hxx>
53 #include <TCollection_AsciiString.hxx>
54 using namespace std;
55
56 /*!
57     Constructor
58 */
59 SALOMEGUI_Application::SALOMEGUI_Application( const QString& format,
60                                               const QString& description,
61                                               const QString& filters) :
62 QAD_Application( format, description, filters )
63 {
64     /* load resources */
65   QString message;
66     QAD_ResourceMgr* resMgr = QAD_Desktop::getResourceManager();
67     if ( !resMgr ) resMgr = QAD_Desktop::createResourceManager();
68     if ( resMgr ) resMgr->loadResources( "SALOMEGUI", message );
69
70     QPalette* palette = QAD_Desktop::getPalette();
71     if ( !palette) palette = QAD_Desktop::createPalette();
72     //    if ( !palette) palette->loadPalette();
73
74   //myViewActions.setAutoDelete( true );
75
76     /*  We need to know that the desktop is created to have
77         some additional internal initialization */
78     QAD_ASSERT( connect( this, SIGNAL(desktopCreated()), SLOT(onDesktopCreated()) ));
79 }
80
81 /*!
82     Destructor
83 */
84 SALOMEGUI_Application::~SALOMEGUI_Application()
85 {
86 }
87
88 /*!
89     Creates the actions provided by this application( internal )
90 */
91 void SALOMEGUI_Application::createActions()
92 {
93 #ifdef DEBUG
94     /* this function must be called only once */
95     static bool created = false;
96     QAD_ASSERT_DEBUG_ONLY( !created );
97     created = true;
98 #endif
99
100     /* Create 'View' actions
101     */
102     QToolBar* tbView = createToolBar( ViewToolBarId, tr("MEN_DESK_VIEWERTOOLBAR") );
103
104     QAD_ResourceMgr* rmgr = QAD_Desktop::getResourceManager();
105 #define CREATE_ACTION(ID,NAME) \
106     if(!myViewActions.at(ID)){ \
107       QActionP* action = new QActionP(tr("TOT_APP_VIEW_" #NAME), \
108                             rmgr->loadPixmap("SALOMEGUI", tr("ICON_APP_VIEW_" #NAME)), \
109                             tr("MEN_APP_VIEW_" #NAME), 0, QAD_Application::getDesktop()); \
110       action->setStatusTip(tr("PRP_APP_VIEW_" #NAME)); \
111       myViewActions.insert(ID,action); \
112     }
113
114     CREATE_ACTION(ViewDumpId,DUMP);
115     CREATE_ACTION(ViewTrihedronId,TRIHEDRON);
116     CREATE_ACTION(ViewFitAllId,FITALL);
117     CREATE_ACTION(ViewFitAreaId,FITAREA);
118     CREATE_ACTION(ViewZoomId,ZOOM);
119     CREATE_ACTION(ViewPanId,PAN);
120     CREATE_ACTION(ViewRotateId,ROTATE);
121     CREATE_ACTION(ViewGlobalPanId,GLOBALPAN);
122     CREATE_ACTION(ViewFrontId,FRONT);
123     CREATE_ACTION(ViewBackId,BACK);
124     CREATE_ACTION(ViewTopId,TOP);
125     CREATE_ACTION(ViewBottomId,BOTTOM);
126     CREATE_ACTION(ViewLeftId,LEFT);
127     CREATE_ACTION(ViewRightId,RIGHT);
128     CREATE_ACTION(ViewResetId,RESET);
129
130 #undef CREATE_ACTION
131 }
132
133 /*!
134     Enables/disables the actions provided by this
135     application( internal )
136 */
137 void SALOMEGUI_Application::updateActions()
138 {
139 }
140
141 /*!
142     Creates CAF application
143 */
144 bool SALOMEGUI_Application::initApp(SALOME_NamingService* name_service)
145 {
146   if ( myStudyMgr->_is_nil() ) {
147     try {
148       CORBA::Object_ptr obj = name_service->Resolve("/myStudyManager");
149       myStudyMgr = SALOMEDS::StudyManager::_narrow(obj);
150     }
151     catch ( Standard_Failure ) {
152       return false;
153     }
154   }
155
156   return true;
157 }
158
159 /*!
160     Creates the main desktop
161 */
162 bool SALOMEGUI_Application::createDesktop( SALOME_NamingService* name_service )
163 {
164   QAD_ASSERT_DEBUG_ONLY( !desktop );
165   desktop = new SALOMEGUI_Desktop(name_service);
166   return ( desktop != NULL );
167 }
168
169 /*!
170     Called when the main desktop is created ( internal )
171 */
172 void SALOMEGUI_Application::onDesktopCreated()
173 {
174   createActions();
175 }
176
177 /*!
178     Called for customization when study is created
179 */
180 void SALOMEGUI_Application::onStudyCreated( QAD_Study* study )
181 {
182 }
183
184 /*!
185     Called for customization when study is opened
186 */
187 void SALOMEGUI_Application::onStudyOpened( QAD_Study* study )
188 {
189 }
190
191 /*!
192     Called for customization when study is activated (shown)
193 */
194 void SALOMEGUI_Application::onStudyShown( QAD_Study* study )
195 {
196   SALOMEDS::Study_var aStudy = study->getStudyDocument();
197
198 //srn: Forbid appending Interface Applicative and its children to UseCase
199   aStudy->EnableUseCaseAutoFilling(false); 
200
201   /* mpv: study may be locked */
202   int aLocked = aStudy->GetProperties()->IsLocked();
203   if (aLocked) aStudy->GetProperties()->SetLocked(false);
204
205   /* update Object Browser */
206   SALOMEDS::StudyBuilder_var B = aStudy->NewBuilder();
207   SALOMEDS::SComponentIterator_var itcomp = aStudy->NewComponentIterator();
208   for (; itcomp->More(); itcomp->Next()) {
209     SALOMEDS::SComponent_var SC = itcomp->Value();
210     Standard_CString dataType = SC->ComponentDataType();
211     if ( QString(dataType).compare("Interface Applicative") == 0 ) {
212       SALOMEDS::ChildIterator_var it = aStudy->NewChildIterator(SC);
213       for (; it->More();it->Next()) {
214         SALOMEDS::SObject_var CSO = it->Value();
215         B->RemoveObject(CSO);
216       }
217     }
218   }
219
220   QAD_StudyFrame* sf = myActiveStudy->getActiveStudyFrame();
221   Standard_CString name = strdup(sf->title().latin1());
222   
223   SALOMEDS::SComponent_var father = aStudy->FindComponent("Interface Applicative");
224   SALOMEDS::SObject_var newObj = B->NewObject(father);
225   SALOMEDS::GenericAttribute_var anAttr;
226   SALOMEDS::AttributeName_var    aName;
227   SALOMEDS::AttributeComment_var aComment;
228   SALOMEDS::AttributeSelectable_var aSelAttr;
229
230   anAttr = B->FindOrCreateAttribute(newObj, "AttributeName");
231   aName = SALOMEDS::AttributeName::_narrow(anAttr);
232   aName->SetValue(name);
233
234   anAttr = B->FindOrCreateAttribute(newObj, "AttributeSelectable");
235   aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
236   aSelAttr->SetSelectable(false);
237
238   if (sf->getTypeView() == VIEW_OCC) {
239     anAttr = B->FindOrCreateAttribute(newObj, "AttributeComment");
240     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
241     aComment->SetValue("OCC");
242   }
243   else if (sf->getTypeView() == VIEW_VTK) {
244     anAttr = B->FindOrCreateAttribute(newObj, "AttributeComment");
245     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
246     aComment->SetValue("VTK");
247   } else {
248     anAttr = B->FindOrCreateAttribute(newObj, "AttributeComment");
249     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
250     aComment->SetValue("GRAPH");
251   }   
252   sf->setEntry(newObj->GetID());
253   
254   if (aLocked) aStudy->GetProperties()->SetLocked(true);
255
256   study->updateObjBrowser( false );
257
258   aStudy->EnableUseCaseAutoFilling(true); 
259 }
260
261 /*!
262     Called for customization when the active study is changed
263 */
264 void SALOMEGUI_Application::onActiveStudyChanged( QAD_Study* oldActiveStudy,
265                                                   QAD_Study* newActiveStudy )
266 {
267   //  MESSAGE ("SALOMEGUI_Application::onActiveStudyChanged init.");
268   /* superclass MUST be called */
269   QAD_Application::onActiveStudyChanged( oldActiveStudy, newActiveStudy );
270
271   if ( oldActiveStudy ) {
272     int count = oldActiveStudy->getStudyFramesCount();
273     for ( int i = 0; i < count; i++ ) {
274       disconnectFromViewer( oldActiveStudy->getStudyFrame(i)->getRightFrame()->getViewFrame() );
275     }
276   }
277   
278   if ( newActiveStudy && newActiveStudy->getActiveStudyFrame() ) {
279     connectToViewer( newActiveStudy->getActiveStudyFrame()->getRightFrame()->getViewFrame() );
280   }
281 }
282
283 void SALOMEGUI_Application::connectToViewer( QAD_ViewFrame* vf )
284 {
285 #define CONNECT_ACTION(NAME) \
286   QAD_ASSERT(connect(myViewActions.at(View ##NAME ##Id), SIGNAL(activated()), vf, SLOT(onView ##NAME())))
287
288   if ( vf ) {
289     QToolBar* tbView = getToolBar( ViewToolBarId );
290     for ( int cmd = ViewDumpId; cmd <= ViewResetId; cmd++ )
291       if ( myViewActions.at( cmd ) )
292         myViewActions.at( cmd )->removeFrom(tbView);
293     if( vf->getTypeView() == VIEW_GRAPHSUPERV ) {
294       //myViewActions.at(ViewDumpId)->addTo(tbView);
295       //myViewActions.at(ViewFitAllId)->addTo(tbView);
296       //myViewActions.at(ViewFitAreaId)->addTo(tbView);
297       //myViewActions.at(ViewZoomId)->addTo(tbView);
298       myViewActions.at(ViewPanId)->addTo(tbView);
299       //myViewActions.at(ViewGlobalPanId)->addTo(tbView);
300       myViewActions.at(ViewResetId)->addTo(tbView);
301     }
302     else if( vf->getTypeView() == VIEW_PLOT2D ) {
303       myViewActions.at(ViewDumpId)->addTo(tbView);
304       myViewActions.at(ViewFitAllId)->addTo(tbView);
305       myViewActions.at(ViewFitAreaId)->addTo(tbView);
306       myViewActions.at(ViewZoomId)->addTo(tbView);
307       myViewActions.at(ViewPanId)->addTo(tbView);
308       //myViewActions.at(ViewGlobalPanId)->addTo(tbView);
309       //myViewActions.at(ViewResetId)->addTo(tbView);
310     }
311     else {
312       for ( int cmd = ViewDumpId; cmd <= ViewResetId; cmd++ )
313         if ( myViewActions.at( cmd ) )
314           myViewActions.at( cmd )->addTo(tbView);
315     }
316     //CONNECT_ACTION(Mu4Id)
317     CONNECT_ACTION(Dump);
318     CONNECT_ACTION(Trihedron);
319     CONNECT_ACTION(FitAll);
320     CONNECT_ACTION(FitArea);
321     CONNECT_ACTION(Zoom);
322     CONNECT_ACTION(Pan);
323     CONNECT_ACTION(Rotate);
324     CONNECT_ACTION(GlobalPan);
325     CONNECT_ACTION(Front);
326     CONNECT_ACTION(Back);
327     CONNECT_ACTION(Top);
328     CONNECT_ACTION(Bottom);
329     CONNECT_ACTION(Left);
330     CONNECT_ACTION(Right);
331     CONNECT_ACTION(Reset);
332   }
333
334 #undef CONNECT_ACTION
335 }
336
337 void SALOMEGUI_Application::disconnectFromViewer( QAD_ViewFrame* vf )
338 {
339 #define DISCONNECT_ACTION(NAME) \
340   QAD_ASSERT(disconnect(myViewActions.at(View ##NAME ##Id), SIGNAL(activated()), vf, SLOT(onView ##NAME())));
341
342   if ( !vf || myViewActions.isEmpty() )
343     return;
344   //DISCONNECT_ACTION(Mu4Id)
345   DISCONNECT_ACTION(Dump);
346   DISCONNECT_ACTION(Trihedron);
347   DISCONNECT_ACTION(FitAll);
348   DISCONNECT_ACTION(FitArea);
349   DISCONNECT_ACTION(Zoom);
350   DISCONNECT_ACTION(Pan);
351   DISCONNECT_ACTION(Rotate);
352   DISCONNECT_ACTION(GlobalPan);
353   DISCONNECT_ACTION(Front);
354   DISCONNECT_ACTION(Back);
355   DISCONNECT_ACTION(Top);
356   DISCONNECT_ACTION(Bottom);
357   DISCONNECT_ACTION(Left);
358   DISCONNECT_ACTION(Right);
359   DISCONNECT_ACTION(Reset);
360
361 #undef DISCONNECT_ACTION
362 }
363
364 /*!
365     Customizes 'View' menu of the desktop
366 */
367 int SALOMEGUI_Application::onUpdateViewActions ( QPopupMenu* popup, bool add, int index )
368 {
369   int nItemsAdded = QAD_Application::onUpdateViewActions( popup, add, index );
370   // NRI
371   //    if ( add ) {
372   //      index += nItemsAdded;
373   //      QAD_ASSERT_DEBUG_ONLY( !myViewActions.isEmpty() );
374   //      popup->insertSeparator( index++ );
375   //      myViewActions.at( ViewTrihedronId )->addTo( popup );
376   //      index++;
377   //      popup->insertSeparator( index++ );
378   //      for ( int i = (int)ViewMu4Id; i <= (int)ViewRightId; i++ ) {
379   //        myViewActions.at( i )->addTo( popup );
380   //        index++;
381   //      }
382   //      popup->insertSeparator( index++ );
383   //      myViewActions.at( ViewResetId )->addTo( popup );
384   //      index++;
385   //    } else {
386   //      for ( int i = (int)ViewTrihedronId; i <= (int)ViewResetId; i++ ) {
387   //        popup->removeItemAt(index);
388   //      }
389
390   //      /* remove separators */
391   //      popup->removeItemAt( index );
392   //      popup->removeItemAt( index );
393   //      popup->removeItemAt( index );
394   //    }
395
396   return index;
397 }
398
399 /*!
400     Adds the context popup items
401 */
402 void SALOMEGUI_Application::onCreatePopup()
403 {
404   // Here common menu items should be added (Display, Erase, etc.).
405   // They should be obtained through the standard XML-based mechanism,
406   // i.e. corresponding XML file should be loaded somewhere in advance 
407   // and desktop->getOperatorsMenu() should return the default popup menu.
408   // These items are always added; if necessary any of them can be hidden
409   // during popup customization by means of the corresponding unique ID defined in QAD_Resource.h.
410   SALOME_Selection*      Sel = SALOME_Selection::Selection( myActiveStudy->getSelection() );
411
412   if ( Sel->IObjectCount() > 0 ) {
413     myPopup->insertItem (tr ("MEN_APP_DISPLAY"),      this, SLOT(onDisplay(int)), 0, QAD_Display_Popup_ID);
414     myPopup->insertItem (tr ("MEN_APP_DISPLAY_ONLY"), this, SLOT(onDisplay(int)), 0, QAD_DisplayOnly_Popup_ID);
415     myPopup->insertItem (tr ("MEN_APP_ERASE"),        this, SLOT(onErase()),      0, QAD_Erase_Popup_ID);
416   }
417
418 }
419
420
421 void SALOMEGUI_Application::onDisplay(int id)
422 {
423   QAD_WaitCursor waitCursor;
424
425   // Obtain the component to deal with (according to selected object's parent component)
426   SALOME_Selection* Sel = SALOME_Selection::Selection(myActiveStudy->getSelection() );
427   
428   QString parentComp = ((SALOMEGUI_Desktop*)desktop)->getComponentFromSelection();
429   if (parentComp.isNull()) { // objects from several components are selected -> do nothing
430     return;
431   }
432
433   bool isViewTypeOK     = true;
434   int  viewTypes[VIEW_TYPE_MAX];
435
436   for (int i = 0; i < VIEW_TYPE_MAX; i++)
437     viewTypes[i] = -1;
438
439   // Obtain the component's GUI 
440   SALOMEGUI* aGUI = desktop->getComponentGUI( parentComp );
441   if ( !aGUI )
442     return;
443
444   // Check if another view type is required (if viewToActivate < 0 then any type of view is acceptable)
445   aGUI->SupportedViewType(viewTypes, VIEW_TYPE_MAX);
446   if (viewTypes[0] >= 0) { // not all the view types are supported
447     for (int i = 0; i < VIEW_TYPE_MAX; i++) {
448       if (viewTypes[i] < 0) // no more types supported
449         break;
450       isViewTypeOK = ((int)myActiveStudy->getActiveStudyFrame()->getTypeView() == viewTypes[i]);
451       if (isViewTypeOK) // one of supported views is already active
452         break;
453     }
454   }
455
456   // Try to activate a view of one of supported types
457   if (!isViewTypeOK) {
458     MESSAGE("onDisplay(): view type is not acceptable")
459     unsigned frameCount = myActiveStudy->getStudyFramesCount();
460     for (unsigned i = 0; i < frameCount; i++) {
461       QAD_StudyFrame* frame = myActiveStudy->getStudyFrame(i);
462       for (int j = 0; j < VIEW_TYPE_MAX; j++) {
463         if (frame->getTypeView() == viewTypes[j]) {
464           MESSAGE("onDisplay(): activating other frame")
465             isViewTypeOK = true;
466           frame->setFocus();
467           break;
468         }
469       }
470     }
471     if (!isViewTypeOK) {
472       waitCursor.stop();
473       QMessageBox::warning( desktop,
474                            tr("ERR_ERROR"),
475                            tr("ERR_APP_WRONG_VIEW_TYPE"));
476       return;
477     }
478   }
479
480   QAD_ViewFrame* viewFrame = myActiveStudy->getActiveStudyFrame()->getRightFrame()->getViewFrame();
481
482   // Build the graphic presentation (it is stored in the corresponding viewer)
483
484   // Copy the selection
485   SALOME_ListIteratorOfListIO itInit( Sel->StoredIObjects() );
486   SALOME_ListIO selList;
487   for (; itInit.More(); itInit.Next()) {
488     selList.Append(itInit.Value());
489   }
490   
491   SALOMEDS::Study_var aStudy = myActiveStudy->getStudyDocument();
492
493   bool needRepaint = false;
494     
495   if (id == QAD_DisplayOnly_Popup_ID) 
496     viewFrame->EraseAll();
497
498   SALOME_ListIteratorOfListIO It( selList );
499   for(;It.More();It.Next()) {
500     Handle(SALOME_InteractiveObject) IObject    = It.Value();
501
502     // First check whether the object is a component or a child object
503     bool isComponent = false;
504
505     if (!IObject->hasEntry()) continue; 
506
507     SALOMEDS::SObject_var obj = aStudy->FindObjectID(IObject->getEntry());
508     if (!obj->_is_nil()) {
509       SALOMEDS::SComponent_var comp = obj->GetFatherComponent();
510       isComponent = (strcmp(comp->GetID(), obj->GetID()) == 0);
511     }
512
513     // For component -> display all children
514     if (isComponent) {
515       SALOMEDS::ChildIterator_ptr it = aStudy->NewChildIterator(obj);
516       it->InitEx(true);
517       for ( ; it->More(); it->Next()) {
518         SALOMEDS::SObject_ptr child = it->Value();
519         Handle(SALOME_InteractiveObject) childIObject = new SALOME_InteractiveObject();
520         childIObject->setEntry(child->GetID());
521
522         // Ensure that proper 3D presentation exists for IObject
523         aGUI->BuildPresentation(childIObject);
524         viewFrame->Display(childIObject, false);
525         needRepaint = true;
526       }
527     } else { // for child object -> simply display it (no children are displayed)
528       // Ensure that proper 3D presentation exists for IObject
529       aGUI->BuildPresentation(IObject);
530       viewFrame->Display(IObject, false);
531       needRepaint = true;
532     }
533     
534   }
535
536   if (needRepaint)
537     viewFrame->Repaint();
538
539   myActiveStudy->updateObjBrowser(true);
540 }
541
542
543
544 void SALOMEGUI_Application::onErase()
545 {
546   QAD_WaitCursor waitCursor;
547
548   SALOME_Selection* Sel = SALOME_Selection::Selection(myActiveStudy->getSelection() );
549   SALOMEDS::Study_var aStudy = myActiveStudy->getStudyDocument();
550   QAD_ViewFrame*   viewFrame = myActiveStudy->getActiveStudyFrame()->getRightFrame()->getViewFrame();
551   bool needRepaint = false;
552
553   // Copy the selection
554   SALOME_ListIteratorOfListIO itInit( Sel->StoredIObjects() );
555   SALOME_ListIO selList;
556   for (; itInit.More(); itInit.Next()) {
557     selList.Append(itInit.Value());
558   }
559
560   SALOME_ListIteratorOfListIO It( selList );
561   for(;It.More();It.Next()) {
562     Handle(SALOME_InteractiveObject) IObject = It.Value();
563
564     // First check whether the object is a component or a child object
565     bool isComponent = false;
566     SALOMEDS::SObject_var obj;
567
568     if (IObject->hasEntry()) {
569       obj = aStudy->FindObjectID(IObject->getEntry());
570       if (!obj->_is_nil()) {
571         SALOMEDS::SComponent_var comp = obj->GetFatherComponent();
572         isComponent = (strcmp(comp->GetID(), obj->GetID()) == 0);
573       }
574     }
575
576     // For component -> erase all children
577     if (isComponent) {
578       SALOMEDS::ChildIterator_ptr it = aStudy->NewChildIterator(obj);
579       it->InitEx(true);
580       for ( ; it->More(); it->Next()) {
581         SALOMEDS::SObject_ptr child = it->Value();
582         Handle(SALOME_InteractiveObject) childIObject = new SALOME_InteractiveObject();
583         childIObject->setEntry(child->GetID());
584         viewFrame->Erase(childIObject, false);
585       }
586     } else { // for child object -> simply erase it (no children are erased)
587       viewFrame->Erase(IObject, false);
588     }
589     needRepaint = true;
590   }
591
592   if (needRepaint)
593     viewFrame->Repaint();
594
595 }