Salome HOME
Merge branch V7_3_1_BR
[modules/gui.git] / src / GraphicsView / GraphicsView_ViewPort.cxx
1 // Copyright (C) 2013-2014  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 #include "GraphicsView_ViewPort.h"
21
22 #include "GraphicsView_Object.h"
23 #include "GraphicsView_Scene.h"
24 #include "GraphicsView_ViewTransformer.h"
25
26 #include "SUIT_ResourceMgr.h"
27 #include "SUIT_Session.h"
28
29 #include <QCursor>
30 #include <QGraphicsSceneMouseEvent>
31 #include <QGridLayout>
32 #include <QLabel>
33 #include <QMoveEvent>
34 #include <QRectF>
35 #include <QRubberBand>
36 #include <QScrollBar>
37
38 #include <math.h>
39
40 #define FOREGROUND_Z_VALUE -2
41 #define GRID_Z_VALUE       -1
42 #define SKETCH_Z_VALUE     3000
43
44 int GraphicsView_ViewPort::nCounter = 0;
45 QCursor* GraphicsView_ViewPort::defCursor = 0;
46 QCursor* GraphicsView_ViewPort::handCursor = 0;
47 QCursor* GraphicsView_ViewPort::panCursor = 0;
48 QCursor* GraphicsView_ViewPort::panglCursor = 0;
49 QCursor* GraphicsView_ViewPort::zoomCursor = 0;
50 QCursor* GraphicsView_ViewPort::sketchCursor = 0;
51
52 //=======================================================================
53 // Name    : GraphicsView_ViewPort::ViewLabel
54 // Purpose : Wrapper for label, which can ignore move events sent from
55 //           QGraphicsView::scrollContentsBy() method, which,
56 //           in its turn, called from GraphicsView_ViewPort::pan()
57 //=======================================================================
58 class GraphicsView_ViewPort::ViewLabel : public QLabel
59 {
60 public:
61   ViewLabel( QWidget* theParent )
62   : QLabel( theParent ),
63     myAcceptMoveEvents( false )
64   {
65   }
66   ~ViewLabel() {}
67
68   void setAcceptMoveEvents( bool theFlag )
69   {
70     myAcceptMoveEvents = theFlag;
71   }
72
73 protected:
74   virtual void moveEvent( QMoveEvent* theEvent )
75   {
76     if( myAcceptMoveEvents )
77       QLabel::moveEvent( theEvent );
78     else // return the label to the initial position
79     {
80       myAcceptMoveEvents = true;
81       move( theEvent->oldPos() );
82       myAcceptMoveEvents = false;
83     }
84   }
85
86 private:
87   bool myAcceptMoveEvents;
88 };
89
90 //================================================================
91 // Function : createCursors
92 // Purpose  : 
93 //================================================================
94 void GraphicsView_ViewPort::createCursors ()
95 {
96   defCursor   = new QCursor( Qt::ArrowCursor );
97   handCursor  = new QCursor( Qt::PointingHandCursor );
98   panCursor   = new QCursor( Qt::SizeAllCursor );
99   panglCursor = new QCursor( Qt::CrossCursor );
100
101   SUIT_ResourceMgr* rmgr = SUIT_Session::session()->resourceMgr();
102   zoomCursor   = new QCursor( rmgr->loadPixmap( "GraphicsView", tr( "ICON_GV_CURSOR_ZOOM" ) ) );
103
104   sketchCursor = new QCursor( Qt::CrossCursor );
105 }
106
107 //================================================================
108 // Function : destroyCursors
109 // Purpose  : 
110 //================================================================
111 void GraphicsView_ViewPort::destroyCursors()
112 {
113   delete defCursor;    defCursor    = 0;
114   delete handCursor;   handCursor   = 0;
115   delete panCursor;    panCursor    = 0;
116   delete panglCursor;  panglCursor  = 0;
117   delete zoomCursor;   zoomCursor   = 0;
118   delete sketchCursor; sketchCursor = 0;
119 }
120
121 //=======================================================================
122 // Name    : GraphicsView_ViewPort
123 // Purpose : Constructor
124 //=======================================================================
125 GraphicsView_ViewPort::GraphicsView_ViewPort( QWidget* theParent )
126 : QGraphicsView( theParent ),
127   myInteractionFlags( 0 ),
128   myViewLabel( 0 ),
129   myViewLabelPosition( VLP_None ),
130   myViewLabelLayout( 0 ),
131   myIsMousePositionEnabled( false ),
132   myForegroundItem( 0 ),
133   myGridItem( 0 ),
134   myIsTransforming( false ),
135   myHighlightedObject( 0 ),
136   myHighlightX( 0 ),
137   myHighlightY( 0 ),
138   myIsHighlighting( false ),
139   mySelectionIterator( 0 ),
140   myRectBand( 0 ),
141   myAreSelectionPointsInitialized( false ),
142   mySketchingItem( 0 ),
143   myIsPrepareToSketch( false ),
144   myIsSketching( false ),
145   myIsSketchingByPath( false ),
146   myIsDragging( false ),
147   myIsDragPositionInitialized( false ),
148   myIsPulling( false ),
149   myPullingObject( 0 ),
150   myStoredCursor( Qt::ArrowCursor )
151 {
152   // scene
153   myScene = new GraphicsView_Scene( this );
154   setScene( myScene );
155
156   mySceneGap = 20;
157   myFitAllGap = 40;
158
159   // interaction flags
160   setInteractionFlags( EditFlags );
161   //setInteractionFlag( TraceBoundingRect );
162   //setInteractionFlag( DraggingByMiddleButton );
163   //setInteractionFlag( ImmediateContextMenu );
164   //setInteractionFlag( ImmediateSelection );
165   //setInteractionFlag( Sketching );
166
167   // background
168   setBackgroundBrush( QBrush( Qt::white ) );
169
170   // foreground
171   myIsForegroundEnabled = false;
172   myForegroundSize = QSizeF( 100, 30 );
173   myForegroundMargin = 0.0;
174   myForegroundColor = Qt::white;
175   myForegroundFrameColor = Qt::black;
176   myForegroundFrameLineWidth = 1.0;
177
178   // grid
179   myIsGridEnabled = false;
180   myGridCellSize = 100;
181   myGridLineStyle = Qt::DotLine;
182   myGridLineColor = Qt::darkGray;
183
184   // default index method (BspTreeIndex) leads to
185   // crashes in QGraphicsView::paintEvent() method
186   myScene->setItemIndexMethod( QGraphicsScene::NoIndex );
187
188   // render hints (default - TextAntialiasing only)
189   setRenderHints( QPainter::Antialiasing |
190                   QPainter::TextAntialiasing |
191                   QPainter::SmoothPixmapTransform |
192                   QPainter::HighQualityAntialiasing );
193
194   connect( myScene, SIGNAL( gsKeyEvent( QKeyEvent* ) ),
195            this, SLOT( onKeyEvent( QKeyEvent* ) ) );
196   connect( myScene, SIGNAL( gsMouseEvent( QGraphicsSceneMouseEvent* ) ),
197            this, SLOT( onMouseEvent( QGraphicsSceneMouseEvent* ) ) );
198   connect( myScene, SIGNAL( gsWheelEvent( QGraphicsSceneWheelEvent* ) ),
199            this, SLOT( onWheelEvent( QGraphicsSceneWheelEvent* ) ) );
200   connect( myScene, SIGNAL( gsContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ),
201            this, SLOT( onContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ) );
202
203   connect( myScene, SIGNAL( gsBoundingRectChanged() ),
204            this, SLOT( onBoundingRectChanged() ) );
205
206   initialize();
207 }
208
209 //=======================================================================
210 // Name    : GraphicsView_ViewPort
211 // Purpose : Destructor
212 //=======================================================================
213 GraphicsView_ViewPort::~GraphicsView_ViewPort()
214 {
215   cleanup();
216
217   if( myScene )
218   {
219     delete myScene;
220     myScene = 0;
221   }
222 }
223
224 //================================================================
225 // Function : initialize
226 // Purpose  : 
227 //================================================================
228 void GraphicsView_ViewPort::initialize()
229 {
230   if ( nCounter++ == 0 )
231     createCursors();
232
233   setMouseTracking( true );
234   setFocusPolicy( Qt::StrongFocus );
235 }
236
237 //================================================================
238 // Function : cleanup
239 // Purpose  : 
240 //================================================================
241 void GraphicsView_ViewPort::cleanup()
242 {
243   if ( --nCounter == 0 )
244     destroyCursors();
245 }
246
247 //================================================================
248 // Function : addItem
249 // Purpose  : 
250 //================================================================
251 void GraphicsView_ViewPort::addItem( QGraphicsItem* theItem )
252 {
253   if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
254   {
255     int aPriority = anObject->getPriority();
256     GraphicsView_ObjectList::iterator anIter, anIterEnd = myObjects.end();
257     for( anIter = myObjects.begin(); anIter != anIterEnd; anIter++ )
258     {
259       if( GraphicsView_Object* anObjectRef = *anIter )
260       {
261         if( anObjectRef->getPriority() > aPriority )
262           break;
263       }
264     }
265     myObjects.insert( anIter, anObject );
266     anObject->setViewTransform( transform() );
267     anObject->addTo( this );
268   }
269   else
270     myScene->addItem( theItem );
271   onBoundingRectChanged();
272 }
273
274 //================================================================
275 // Function : removeItem
276 // Purpose  : 
277 //================================================================
278 void GraphicsView_ViewPort::removeItem( QGraphicsItem* theItem )
279 {
280   if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
281   {
282     if( myHighlightedObject == anObject )
283       myHighlightedObject = 0;
284     mySelectedObjects.removeAll( anObject );
285     myObjects.removeAll( anObject );
286     anObject->removeFrom( this );
287   }
288   else
289     myScene->removeItem( theItem );
290   onBoundingRectChanged();
291 }
292
293 //================================================================
294 // Function : getObjects
295 // Purpose  : 
296 //================================================================
297 GraphicsView_ObjectList GraphicsView_ViewPort::getObjects( SortType theSortType ) const
298 {
299   if( theSortType == SelectedFirst )
300   {
301     // to append selected objects after their non-selected siblings with similar priority
302     int aCurrentPriority = -1;
303     GraphicsView_ObjectList aSelectedObjects;
304     GraphicsView_ObjectList aTopmostObjects;
305
306     GraphicsView_ObjectList aList;
307     GraphicsView_ObjectListIterator anIter( myObjects );
308     while( anIter.hasNext() )
309     {
310       if( GraphicsView_Object* anObject = anIter.next() )
311       {
312         if( anObject->isOnTop() )
313         {
314           aTopmostObjects.append( anObject );
315           continue;
316         }
317
318         int aPriority = anObject->getPriority();
319         if( aPriority > aCurrentPriority  )
320         {
321           if( !aSelectedObjects.isEmpty() )
322           {
323             aList.append( aSelectedObjects );
324             aSelectedObjects.clear();
325           }
326           aCurrentPriority = aPriority;
327         }
328
329         if( anObject->isSelected() )
330           aSelectedObjects.append( anObject );
331         else
332           aList.append( anObject );
333       }
334     }
335
336     // for selected objects with highest priority,
337     // which were not pushed to the result list yet
338     if( !aSelectedObjects.isEmpty() )
339     {
340       aList.append( aSelectedObjects );
341       aSelectedObjects.clear();
342     }
343
344     aList.append( aTopmostObjects );
345
346     return aList;
347   }
348
349   if( theSortType == SortByZLevel ) // double loop, needs to be optimized
350   {
351     GraphicsView_ObjectList aList;
352
353     GraphicsView_ObjectListIterator anIter( myObjects );
354     while( anIter.hasNext() )
355     {
356       if( GraphicsView_Object* anObject = anIter.next() )
357       {
358         double aZValue = anObject->zValue();
359         GraphicsView_ObjectList::iterator anIter1, anIter1End = aList.end();
360         for( anIter1 = aList.begin(); anIter1 != anIter1End; anIter1++ )
361           if( GraphicsView_Object* anObjectRef = *anIter1 )
362             if( anObjectRef->zValue() > aZValue )
363               break;
364         aList.insert( anIter1, anObject );
365       }
366     }
367     return aList;
368   }
369
370   return myObjects; // theSortType == NoSorting
371 }
372
373 //================================================================
374 // Function : objectsBoundingRect
375 // Purpose  : 
376 //================================================================
377 QRectF GraphicsView_ViewPort::objectsBoundingRect( bool theOnlyVisible ) const
378 {
379   QRectF aRect;
380   QListIterator<QGraphicsItem*> anIter( items() );
381   while( anIter.hasNext() )
382   {
383     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
384     {
385       if( theOnlyVisible && !anObject->isVisible() )
386         continue;
387
388       QRectF anObjectRect = anObject->getRect();
389       if( !anObjectRect.isNull() )
390       {
391         if( aRect.isNull() )
392           aRect = anObject->getRect();
393         else
394           aRect |= anObject->getRect();
395       }
396     }
397   }
398   return aRect;
399 }
400
401 //================================================================
402 // Function : dumpView
403 // Purpose  : 
404 //================================================================
405 QImage GraphicsView_ViewPort::dumpView( bool theWholeScene,
406                                         QSizeF theSize )
407 {
408   if( !theWholeScene ) // just grab the view contents
409   {
410     QPixmap aPixmap = QPixmap::grabWindow( viewport()->winId() );
411     return aPixmap.toImage();
412   }
413
414   // get a bounding rect of all presented objects
415   // (itemsBoundingRect() method is unsuitable)
416   QRectF aRect = objectsBoundingRect();
417   if( aRect.isNull() )
418     return QImage();
419
420   QRectF aTargetRect( 0, 0, aRect.width(), aRect.height() );
421   if( theSize.isValid() )
422   {
423     double aRatioX = theSize.width() / aTargetRect.width();
424     double aRatioY = theSize.height() / aTargetRect.height();
425     double aRatio = qMin( aRatioX, aRatioY );
426     aTargetRect.setWidth( aTargetRect.width() * aRatio );
427     aTargetRect.setHeight( aTargetRect.height() * aRatio );
428   }
429
430   // render the scene to an image
431   QImage anImage( aTargetRect.toRect().size(), QImage::Format_RGB32 );
432   QPainter aPainter( &anImage );
433   aPainter.setRenderHints( renderHints() );
434
435   myScene->render( &aPainter, aTargetRect, aRect );
436
437   return anImage;
438 }
439
440 //================================================================
441 // Function : setSceneGap
442 // Purpose  : 
443 //================================================================
444 void GraphicsView_ViewPort::setSceneGap( double theSceneGap )
445 {
446   mySceneGap = theSceneGap;
447   onBoundingRectChanged();
448 }
449
450 //================================================================
451 // Function : setFitAllGap
452 // Purpose  : 
453 //================================================================
454 void GraphicsView_ViewPort::setFitAllGap( double theFitAllGap )
455 {
456   myFitAllGap = theFitAllGap;
457 }
458
459 //================================================================
460 // Function : interactionFlags
461 // Purpose  : 
462 //================================================================
463 int GraphicsView_ViewPort::interactionFlags() const
464 {
465   return myInteractionFlags;
466 }
467
468 //================================================================
469 // Function : hasInteractionFlag
470 // Purpose  : 
471 //================================================================
472 bool GraphicsView_ViewPort::hasInteractionFlag( InteractionFlag theFlag )
473 {
474   return ( interactionFlags() & theFlag ) == theFlag;
475 }
476
477 //================================================================
478 // Function : setInteractionFlag
479 // Purpose  : 
480 //================================================================
481 void GraphicsView_ViewPort::setInteractionFlag( InteractionFlag theFlag,
482                                                 bool theIsEnabled )
483 {
484   if( theIsEnabled )
485     setInteractionFlags( myInteractionFlags | theFlag );
486   else
487     setInteractionFlags( myInteractionFlags & ~theFlag );
488 }
489
490 //================================================================
491 // Function : setInteractionFlags
492 // Purpose  : 
493 //================================================================
494 void GraphicsView_ViewPort::setInteractionFlags( InteractionFlags theFlags )
495 {
496   myInteractionFlags = theFlags;
497 }
498
499 //================================================================
500 // Function : setViewLabelPosition
501 // Purpose  : 
502 //================================================================
503 void GraphicsView_ViewPort::setViewLabelPosition( ViewLabelPosition thePosition,
504                                                   bool theIsForced )
505 {
506   if( theIsForced && !myViewLabel )
507     myViewLabel = new ViewLabel( viewport() );
508
509   if( !myViewLabel )
510     return;
511
512   if( thePosition == VLP_None )
513   {
514     myViewLabel->setVisible( false );
515     return;
516   }
517
518   if( myViewLabelLayout )
519     delete myViewLabelLayout;
520
521   myViewLabelLayout = new QGridLayout( viewport() );
522   myViewLabelLayout->setMargin( 10 );
523   myViewLabelLayout->setSpacing( 0 );
524
525   int aRow = 0, aColumn = 0;
526   switch( thePosition )
527   {
528     case VLP_TopLeft:     aRow = 0; aColumn = 0; break;
529     case VLP_TopRight:    aRow = 0; aColumn = 1; break;
530     case VLP_BottomLeft:  aRow = 1; aColumn = 0; break;
531     case VLP_BottomRight: aRow = 1; aColumn = 1; break;
532     default: break;
533   }
534
535   myViewLabelLayout->addWidget( myViewLabel, aRow, aColumn );
536   myViewLabelLayout->setRowStretch( 1 - aRow, 1 );
537   myViewLabelLayout->setColumnStretch( 1 - aColumn, 1 );
538
539   myViewLabel->setVisible( true );
540 }
541
542 //================================================================
543 // Function : setViewLabelText
544 // Purpose  : 
545 //================================================================
546 void GraphicsView_ViewPort::setViewLabelText( const QString& theText )
547 {
548   if( myViewLabel )
549     myViewLabel->setText( theText );
550 }
551
552 //================================================================
553 // Function : setMousePositionEnabled
554 // Purpose  : 
555 //================================================================
556 void GraphicsView_ViewPort::setMousePositionEnabled( bool theState )
557 {
558   myIsMousePositionEnabled = theState;
559
560   if( theState )
561   {
562     setViewLabelPosition( VLP_BottomLeft, true );
563
564     int aMouseX = 0, aMouseY = 0;
565     setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
566   }
567   else
568     setViewLabelPosition( VLP_None );
569 }
570
571 //================================================================
572 // Function : backgroundColor
573 // Purpose  : 
574 //================================================================
575 QColor GraphicsView_ViewPort::backgroundColor() const
576 {
577   return backgroundBrush().color();
578 }
579
580 //================================================================
581 // Function : setBackgroundColor
582 // Purpose  : 
583 //================================================================
584 void GraphicsView_ViewPort::setBackgroundColor( const QColor& theColor )
585 {
586   setBackgroundBrush( QBrush( theColor ) );
587 }
588
589 //================================================================
590 // Function : setForegroundEnabled
591 // Purpose  : 
592 //================================================================
593 void GraphicsView_ViewPort::setForegroundEnabled( bool theState )
594 {
595   myIsForegroundEnabled = theState;
596 }
597
598 //================================================================
599 // Function : setForegroundSize
600 // Purpose  : 
601 //================================================================
602 void GraphicsView_ViewPort::setForegroundSize( const QSizeF& theSize )
603 {
604   myForegroundSize = theSize;
605 }
606
607 //================================================================
608 // Function : setForegroundMargin
609 // Purpose  : 
610 //================================================================
611 void GraphicsView_ViewPort::setForegroundMargin( double theMargin )
612 {
613   myForegroundMargin = theMargin;
614 }
615
616 //================================================================
617 // Function : setForegroundColor
618 // Purpose  : 
619 //================================================================
620 void GraphicsView_ViewPort::setForegroundColor( const QColor& theColor )
621 {
622   myForegroundColor = theColor;
623 }
624
625 //================================================================
626 // Function : setForegroundFrameColor
627 // Purpose  : 
628 //================================================================
629 void GraphicsView_ViewPort::setForegroundFrameColor( const QColor& theColor )
630 {
631   myForegroundFrameColor = theColor;
632 }
633
634 //================================================================
635 // Function : setForegroundFrameLineWidth
636 // Purpose  : 
637 //================================================================
638 void GraphicsView_ViewPort::setForegroundFrameLineWidth( double theLineWidth )
639 {
640   myForegroundFrameLineWidth = theLineWidth;
641 }
642
643 //================================================================
644 // Function : updateForeground
645 // Purpose  : 
646 //================================================================
647 void GraphicsView_ViewPort::updateForeground()
648 {
649   if( myIsForegroundEnabled )
650   {
651     if( !myForegroundItem )
652       myForegroundItem = myScene->addRect( QRectF(), QPen(), QBrush( Qt::white ) );
653     myForegroundItem->setZValue( FOREGROUND_Z_VALUE );
654
655     QPointF aPoint = QPointF();
656     QRectF aRect( aPoint, myForegroundSize );
657     aRect.adjust( -myForegroundMargin, -myForegroundMargin,
658                   myForegroundMargin, myForegroundMargin );
659     myForegroundItem->setRect( aRect );
660
661     QBrush aBrush = myForegroundItem->brush();
662     aBrush.setColor( myForegroundColor );
663     myForegroundItem->setBrush( aBrush );
664
665     QPen aPen = myForegroundItem->pen();
666     aPen.setColor( myForegroundFrameColor );
667     aPen.setWidthF( myForegroundFrameLineWidth );
668     myForegroundItem->setPen( aPen );
669
670     myForegroundItem->setVisible( true );
671
672     myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
673   }
674   else
675   {
676     if( myForegroundItem )
677       myForegroundItem->setVisible( false );
678   }
679
680   updateGrid(); // foreground size could be changed
681 }
682
683 //================================================================
684 // Function : setGridEnabled
685 // Purpose  : 
686 //================================================================
687 void GraphicsView_ViewPort::setGridEnabled( bool theState )
688 {
689   myIsGridEnabled = theState;
690 }
691
692 //================================================================
693 // Function : setGridCellSize
694 // Purpose  : 
695 //================================================================
696 void GraphicsView_ViewPort::setGridCellSize( int theCellSize )
697 {
698   myGridCellSize = theCellSize;
699 }
700
701 //================================================================
702 // Function : setGridLineStyle
703 // Purpose  : 
704 //================================================================
705 void GraphicsView_ViewPort::setGridLineStyle( int theLineStyle )
706 {
707   myGridLineStyle = theLineStyle;
708 }
709
710 //================================================================
711 // Function : setGridLineColor
712 // Purpose  : 
713 //================================================================
714 void GraphicsView_ViewPort::setGridLineColor( const QColor& theLineColor )
715 {
716   myGridLineColor = theLineColor;
717 }
718
719 //================================================================
720 // Function : updateGrid
721 // Purpose  : 
722 //================================================================
723 void GraphicsView_ViewPort::updateGrid()
724 {
725   if( myIsGridEnabled )
726   {
727     if( !myGridItem )
728       myGridItem = myScene->addPath( QPainterPath() );
729     myGridItem->setZValue( GRID_Z_VALUE );
730
731     double aWidth = myForegroundSize.width();
732     double aHeight = myForegroundSize.height();
733
734     int aGridNbX = int( aWidth / myGridCellSize ) + 1;
735     int aGridNbY = int( aHeight / myGridCellSize ) + 1;
736
737     int anIndex;
738     QPainterPath aPath;
739     for( anIndex = 0; anIndex < aGridNbX; anIndex++ )
740     {
741       double x = myGridCellSize * (double)anIndex;
742       aPath.moveTo( x, 0 );
743       aPath.lineTo( x, aHeight );
744     }
745     for( anIndex = 0; anIndex < aGridNbY; anIndex++ )
746     {
747       double y = myGridCellSize * (double)anIndex;
748       aPath.moveTo( 0, y );
749       aPath.lineTo( aWidth, y );
750     }
751     myGridItem->setPath( aPath );
752
753     QPen aPen = myGridItem->pen();
754     aPen.setStyle( (Qt::PenStyle)myGridLineStyle );
755     aPen.setColor( myGridLineColor );
756     myGridItem->setPen( aPen );
757
758     myGridItem->setVisible( true );
759   }
760   else
761   {
762     if( myGridItem )
763       myGridItem->setVisible( false );
764   }
765 }
766
767 //================================================================
768 // Function : reset
769 // Purpose  : 
770 //================================================================
771 void GraphicsView_ViewPort::reset()
772 {
773   fitAll();
774 }
775
776 //================================================================
777 // Function : pan
778 // Purpose  : 
779 //================================================================
780 void GraphicsView_ViewPort::pan( double theDX, double theDY )
781 {
782   myIsTransforming = true;
783
784   if( myViewLabel )
785     myViewLabel->setAcceptMoveEvents( false );
786
787   if( QScrollBar* aHBar = horizontalScrollBar() )
788     aHBar->setValue( aHBar->value() - theDX );
789   if( QScrollBar* aVBar = verticalScrollBar() )
790     aVBar->setValue( aVBar->value() + theDY );
791
792   if( myViewLabel )
793     myViewLabel->setAcceptMoveEvents( true );
794
795   myIsTransforming = false;
796
797   applyTransform();
798 }
799
800 //================================================================
801 // Function : setCenter
802 // Purpose  : 
803 //================================================================
804 void GraphicsView_ViewPort::setCenter( double theX, double theY )
805 {
806   myIsTransforming = true;
807
808   setTransform( myCurrentTransform );
809   centerOn( theX, theY );
810
811   myIsTransforming = false;
812
813   applyTransform();
814 }
815
816 //================================================================
817 // Function : zoom
818 // Purpose  : 
819 //================================================================
820 void GraphicsView_ViewPort::zoom( double theX1, double theY1, double theX2, double theY2 )
821 {
822   myIsTransforming = true;
823
824   double aDX = theX2 - theX1;
825   double aDY = theY2 - theY1;
826   double aZoom = sqrt( aDX * aDX + aDY * aDY ) / 100 + 1;
827   aZoom = ( aDX > 0 ) ?  aZoom : 1 / aZoom;
828
829   QTransform aTransform = transform();
830   aTransform.scale( aZoom, aZoom );
831   double aM11 = aTransform.m11();
832   double aM22 = aTransform.m22();
833   // increasing of diagonal coefficients (>300) leads to a crash sometimes
834   // at the values of 100 some primitives are drawn incorrectly
835   if( qMax( aM11, aM22 ) < 100 )
836     setTransform( aTransform );
837
838   myIsTransforming = false;
839
840   applyTransform();
841 }
842
843 //================================================================
844 // Function : fitRect
845 // Purpose  : 
846 //================================================================
847 void GraphicsView_ViewPort::fitRect( const QRectF& theRect )
848 {
849   myIsTransforming = true;
850
851   fitInView( theRect, Qt::KeepAspectRatio );
852
853   myIsTransforming = false;
854
855   applyTransform();
856 }
857
858 //================================================================
859 // Function : fitSelect
860 // Purpose  : 
861 //================================================================
862 void GraphicsView_ViewPort::fitSelect()
863 {
864   myIsTransforming = true;
865
866   QRectF aGlobalRect;
867   for( initSelected(); moreSelected(); nextSelected() )
868   {
869     if( GraphicsView_Object* aMovingObject = selectedObject() )
870     {
871       QRectF aRect = aMovingObject->getRect();
872       if( aGlobalRect.isNull() )
873         aGlobalRect = aRect;
874       else
875         aGlobalRect |= aRect;
876     }
877   }
878
879   if( !aGlobalRect.isNull() )
880   {
881     double aGap = qMax( aGlobalRect.width(), aGlobalRect.height() ) / 5;
882     aGlobalRect.adjust( -aGap, -aGap, aGap, aGap );
883     fitInView( aGlobalRect, Qt::KeepAspectRatio );
884   }
885
886   myIsTransforming = false;
887
888   applyTransform();
889 }
890
891 //================================================================
892 // Function : fitAll
893 // Purpose  : 
894 //================================================================
895 void GraphicsView_ViewPort::fitAll( bool theKeepScale )
896 {
897   myIsTransforming = true;
898
899   if( theKeepScale )
900     myCurrentTransform = transform();
901
902   double aGap = myFitAllGap;
903   QRectF aRect = objectsBoundingRect( true );
904   fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
905
906   myIsTransforming = false;
907
908   applyTransform();
909 }
910
911 //================================================================
912 // Function : fitWidth
913 // Purpose  : 
914 //================================================================
915 void GraphicsView_ViewPort::fitWidth()
916 {
917   myIsTransforming = true;
918
919   double aGap = myFitAllGap;
920   QRectF aRect = objectsBoundingRect( true );
921
922   double aTop = aRect.top();
923   double aLeft = aRect.left();
924   double aMargin = 10;
925
926   aRect.setY( aRect.center().y() );
927   aRect.setHeight( aMargin );
928
929   fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
930   ensureVisible( aLeft, aTop, aMargin, aMargin, 0, aGap );
931
932   myIsTransforming = false;
933
934   applyTransform();
935 }
936
937 //================================================================
938 // Function : applyTransform
939 // Purpose  : 
940 //================================================================
941 void GraphicsView_ViewPort::applyTransform()
942 {
943   GraphicsView_ObjectListIterator anIter( getObjects() );
944   while( anIter.hasNext() )
945     if( GraphicsView_Object* anObject = anIter.next() )
946       anObject->setViewTransform( transform() );
947 }
948
949 //================================================================
950 // Function : currentBlock
951 // Purpose  : 
952 //================================================================
953 GraphicsView_ViewPort::BlockStatus GraphicsView_ViewPort::currentBlock()
954 {
955   if( isDragging() && !myDragPosition.isNull() )
956     return BlockStatus( BS_Selection );
957
958   if( myAreSelectionPointsInitialized && ( myFirstSelectionPoint != myLastSelectionPoint ) )
959     return BlockStatus( BS_Selection );
960
961   if( isPulling() )
962     return BlockStatus( BS_Selection );
963
964   return BS_NoBlock;
965 }
966
967 //================================================================
968 // Function : highlight
969 // Purpose  : 
970 //================================================================
971 void GraphicsView_ViewPort::highlight( double theX, double theY )
972 {
973   myIsHighlighting = true;
974   myHighlightX = theX;
975   myHighlightY = theY;
976
977   bool anIsHighlighted = false;
978   bool anIsOnObject = false;
979
980   GraphicsView_Object* aPreviousHighlightedObject = myHighlightedObject;
981   GraphicsView_Object* aHighlightedObject = 0;
982
983   QCursor aCursor;
984
985   GraphicsView_ObjectList aList = getObjects( SortByZLevel );
986   GraphicsView_ObjectListIterator anIter( aList );
987   anIter.toBack(); // objects with higher priority have to be checked earlier
988   while( anIter.hasPrevious() )
989   {
990     if( GraphicsView_Object* anObject = anIter.previous() )
991     {
992       if( anObject->isVisible() && anObject->isSelectable() )
993       {
994         if( anObject->checkHighlight( theX, theY, aCursor ) )
995         {
996           anIsOnObject = true;
997           anIsHighlighted = anObject->highlight( theX, theY );
998         }
999
1000         if( anIsHighlighted )
1001         {
1002           aHighlightedObject = anObject;
1003           break;
1004         }
1005       }
1006     }
1007   }
1008
1009   setCursor( aCursor );
1010
1011   if( !anIsOnObject )
1012   {
1013     anIter = aList;
1014     while( anIter.hasNext() )
1015       if( GraphicsView_Object* anObject = anIter.next() )
1016         anObject->unhighlight();
1017
1018     myHighlightedObject = 0;
1019     return;
1020   }
1021   else if( !myHighlightedObject && anIsHighlighted )
1022   {
1023     myHighlightedObject = aHighlightedObject;
1024   }
1025   else if( myHighlightedObject && !anIsHighlighted )
1026   {
1027     myHighlightedObject->unhighlight();
1028     myHighlightedObject = 0;
1029   }
1030   else if( myHighlightedObject && anIsHighlighted )
1031   {
1032     myHighlightedObject->highlight( theX, theY );
1033     if( myHighlightedObject != aHighlightedObject )
1034     {
1035       myHighlightedObject->unhighlight();
1036       myHighlightedObject = aHighlightedObject;
1037     }
1038   }
1039 }
1040
1041 //================================================================
1042 // Function : clearHighlighted
1043 // Purpose  : 
1044 //================================================================
1045 void GraphicsView_ViewPort::clearHighlighted()
1046 {
1047   if( myHighlightedObject )
1048   {
1049     myHighlightedObject->unhighlight();
1050     myHighlightedObject = 0;
1051   }
1052 }
1053
1054 //================================================================
1055 // Function : select
1056 // Purpose  : 
1057 //================================================================
1058 int GraphicsView_ViewPort::select( const QRectF& theRect, bool theIsAppend )
1059 {
1060   if( !myIsHighlighting )
1061     return GVSS_NoChanged;
1062
1063   GV_SelectionStatus aStatus = GVSS_Invalid;
1064   if( theRect.isNull() ) // point selection
1065   {
1066     if( myHighlightedObject )
1067     {
1068       if( mySelectedObjects.count() == 1 &&
1069           mySelectedObjects.first() == myHighlightedObject )
1070         aStatus = GVSS_LocalChanged;
1071
1072       if( !theIsAppend )
1073       {
1074         GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1075         while( anIter.hasNext() )
1076           if( GraphicsView_Object* anObject = anIter.next() )
1077             if( myHighlightedObject != anObject )
1078               anObject->unselect();
1079
1080         if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1081           aStatus = GVSS_GlobalChanged;
1082         mySelectedObjects.clear();
1083       } 
1084       else if( myHighlightedObject->isSelected() && aStatus != GVSS_LocalChanged )
1085       {
1086         mySelectedObjects.removeAll( myHighlightedObject );
1087         myHighlightedObject->unselect();
1088
1089         if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1090           aStatus = GVSS_GlobalChanged;
1091
1092         return aStatus;
1093       }
1094
1095       if( myHighlightedObject->select( myHighlightX, myHighlightY, QRectF() ) &&
1096           mySelectedObjects.indexOf( myHighlightedObject ) == -1 )
1097       {
1098         mySelectedObjects.append( myHighlightedObject );
1099         if( aStatus == GVSS_Invalid )
1100           aStatus = GVSS_GlobalChanged;
1101       }
1102       else if( aStatus == GVSS_LocalChanged )
1103         aStatus = GVSS_GlobalChanged;
1104
1105       return aStatus;
1106     }
1107
1108     if( !myHighlightedObject )
1109     {
1110       if( !theIsAppend )
1111       {
1112         GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1113         while( anIter.hasNext() )
1114           if( GraphicsView_Object* anObject = anIter.next() )
1115             if( myHighlightedObject != anObject )
1116               anObject->unselect();
1117
1118         if( !mySelectedObjects.isEmpty() )
1119           aStatus = GVSS_GlobalChanged;
1120         mySelectedObjects.clear();
1121       }
1122       return aStatus;
1123     }
1124
1125     return GVSS_NoChanged;
1126   }
1127   else // rectangle selection
1128   {
1129     aStatus = GVSS_NoChanged;
1130
1131     bool updateAll = false;
1132     if( !theIsAppend )
1133     {
1134       if( !mySelectedObjects.isEmpty() )
1135         aStatus = GVSS_GlobalChanged;
1136
1137       GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1138       while( anIter.hasNext() )
1139         if( GraphicsView_Object* anObject = anIter.next() )
1140           if( myHighlightedObject != anObject )
1141             anObject->unselect();
1142       mySelectedObjects.clear();
1143     }
1144
1145     QListIterator<QGraphicsItem*> anIter( items() );
1146     while( anIter.hasNext() )
1147     {
1148       if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1149       {
1150         if( anObject->isVisible() && anObject->isSelectable() )
1151         {
1152           bool anIsSelected = false;
1153           QRectF aRect = anObject->getRect();
1154           if( theRect.contains( aRect ) && myIsHighlighting )
1155             anIsSelected = anObject->select( myHighlightX, myHighlightY, theRect );
1156
1157           if( anIsSelected && mySelectedObjects.indexOf( anObject ) == -1 )
1158           {
1159             mySelectedObjects.append( anObject );
1160             aStatus = GVSS_GlobalChanged;
1161           }
1162         }
1163       }
1164     }
1165   }
1166   return aStatus;
1167 }
1168
1169 //================================================================
1170 // Function : clearSelected
1171 // Purpose  : 
1172 //================================================================
1173 void GraphicsView_ViewPort::clearSelected()
1174 {
1175   GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1176   while( anIter.hasNext() )
1177     if( GraphicsView_Object* anObject = anIter.next() )
1178       anObject->unselect();
1179   mySelectedObjects.clear();
1180 }
1181
1182 //================================================================
1183 // Function : setSelected
1184 // Purpose  : 
1185 //================================================================
1186 void GraphicsView_ViewPort::setSelected( GraphicsView_Object* theObject )
1187 {
1188   if( theObject )
1189   {
1190     theObject->setSelected( true );
1191     mySelectedObjects.append( theObject );
1192   }
1193 }
1194
1195 //================================================================
1196 // Function : nbSelected
1197 // Purpose  : 
1198 //================================================================
1199 int GraphicsView_ViewPort::nbSelected() const
1200 {
1201   return mySelectedObjects.count();
1202 }
1203
1204 //================================================================
1205 // Function : initSelected
1206 // Purpose  : 
1207 //================================================================
1208 void GraphicsView_ViewPort::initSelected()
1209 {
1210   mySelectionIterator = 0;
1211 }
1212
1213 //================================================================
1214 // Function : moreSelected
1215 // Purpose  : 
1216 //================================================================
1217 bool GraphicsView_ViewPort::moreSelected()
1218 {
1219   return mySelectionIterator < nbSelected();
1220 }
1221
1222 //================================================================
1223 // Function : nextSelected
1224 // Purpose  : 
1225 //================================================================
1226 bool GraphicsView_ViewPort::nextSelected()
1227 {
1228   if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1229   {
1230     mySelectionIterator++;
1231     return true;
1232   }
1233   return false;
1234 }
1235
1236 //================================================================
1237 // Function : selectedObject
1238 // Purpose  : 
1239 //================================================================
1240 GraphicsView_Object* GraphicsView_ViewPort::selectedObject()
1241 {
1242   if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1243     return mySelectedObjects[ mySelectionIterator ];
1244   return 0;
1245 }
1246
1247 //================================================================
1248 // Function : startSelectByRect
1249 // Purpose  : 
1250 //================================================================
1251 void GraphicsView_ViewPort::startSelectByRect( int x, int y )
1252 {
1253   if( !myAreSelectionPointsInitialized )
1254   {
1255     myFirstSelectionPoint = QPoint( x, y );
1256     myLastSelectionPoint = QPoint( x, y );
1257     myAreSelectionPointsInitialized = true;
1258   }
1259
1260   if( !myRectBand )
1261   {
1262     myRectBand = new QRubberBand( QRubberBand::Rectangle, this );
1263     QPalette palette;
1264     palette.setColor( myRectBand->foregroundRole(), Qt::white );
1265     myRectBand->setPalette( palette );
1266   }
1267   myRectBand->hide();
1268 }
1269
1270 //================================================================
1271 // Function : drawSelectByRect
1272 // Purpose  : 
1273 //================================================================
1274 void GraphicsView_ViewPort::drawSelectByRect( int x, int y )
1275 {
1276   if( myAreSelectionPointsInitialized )
1277   {
1278     myRectBand->hide();
1279
1280     myLastSelectionPoint.setX( x );
1281     myLastSelectionPoint.setY( y );
1282
1283     QRect aRect = selectionRect();
1284     myRectBand->setGeometry( aRect );
1285     myRectBand->setVisible( aRect.isValid() );
1286   }
1287 }
1288
1289 //================================================================
1290 // Function : isSelectByRect
1291 // Purpose  : 
1292 //================================================================
1293 bool GraphicsView_ViewPort::isSelectByRect() const
1294 {
1295   return myAreSelectionPointsInitialized;
1296 }
1297
1298 //================================================================
1299 // Function : finishSelectByRect
1300 // Purpose  : 
1301 //================================================================
1302 void GraphicsView_ViewPort::finishSelectByRect()
1303 {
1304   if( myAreSelectionPointsInitialized )
1305   {
1306     if( myRectBand )
1307     {
1308       myRectBand->hide();
1309       delete myRectBand;
1310       myRectBand = 0;
1311     }
1312
1313     myAreSelectionPointsInitialized = false;
1314   }
1315 }
1316
1317 //================================================================
1318 // Function : selectionRect
1319 // Purpose  : 
1320 //================================================================
1321 QRect GraphicsView_ViewPort::selectionRect()
1322 {
1323   QRect aRect;
1324   if( myAreSelectionPointsInitialized )
1325   {
1326     aRect.setLeft( qMin( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1327     aRect.setTop( qMin( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1328     aRect.setRight( qMax( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1329     aRect.setBottom( qMax( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1330   }
1331   return aRect;
1332 }
1333
1334 //================================================================
1335 // Function : prepareToSketch
1336 // Purpose  : 
1337 //================================================================
1338 void GraphicsView_ViewPort::prepareToSketch( bool theStatus )
1339 {
1340   myIsPrepareToSketch = theStatus;
1341   if( theStatus )
1342     setCursor( *getSketchCursor() );
1343 }
1344
1345 //================================================================
1346 // Function : isPrepareToSketch
1347 // Purpose  : 
1348 //================================================================
1349 bool GraphicsView_ViewPort::isPrepareToSketch()
1350 {
1351   return myIsPrepareToSketch;
1352 }
1353
1354 //================================================================
1355 // Function : startSketching
1356 // Purpose  : 
1357 //================================================================
1358 void GraphicsView_ViewPort::startSketching( const QPointF& thePoint,
1359                                             bool theIsPath )
1360 {
1361   prepareToSketch( false );
1362
1363   if( !mySketchingItem )
1364   {
1365     mySketchingItem = new QGraphicsPathItem();
1366     mySketchingItem->setZValue( SKETCH_Z_VALUE );
1367
1368     QPen aPen = mySketchingItem->pen();
1369     aPen.setStyle( Qt::DotLine );
1370     mySketchingItem->setPen( aPen );
1371
1372     addItem( mySketchingItem );
1373   }
1374
1375   mySketchingPoint = thePoint;
1376
1377   QPainterPath aPath;
1378   aPath.moveTo( mySketchingPoint );
1379   mySketchingItem->setPath( aPath );
1380   mySketchingItem->setVisible( true );
1381
1382   myIsSketching = true;
1383   myIsSketchingByPath = theIsPath;
1384 }
1385
1386 //================================================================
1387 // Function : drawSketching
1388 // Purpose  : 
1389 //================================================================
1390 void GraphicsView_ViewPort::drawSketching( const QPointF& thePoint )
1391 {
1392   bool anIsPath = false;
1393   if( mySketchingItem && isSketching( &anIsPath ) )
1394   {
1395     QPainterPath aPath = mySketchingItem->path();
1396     if( anIsPath ) // arbitrary path
1397       aPath.lineTo( thePoint );
1398     else // rectangle
1399     {
1400       // make a valid rectangle
1401       double x1 = mySketchingPoint.x(), y1 = mySketchingPoint.y();
1402       double x2 = thePoint.x(), y2 = thePoint.y();
1403       QPointF aPoint1( qMin( x1, x2 ), qMin( y1, y2 ) );
1404       QPointF aPoint2( qMax( x1, x2 ), qMax( y1, y2 ) );
1405       QRectF aRect( aPoint1, aPoint2 );
1406
1407       aPath = QPainterPath();
1408       aPath.addRect( aRect );
1409     }
1410     mySketchingItem->setPath( aPath );
1411   }
1412 }
1413
1414 //================================================================
1415 // Function : finishSketching
1416 // Purpose  : 
1417 //================================================================
1418 void GraphicsView_ViewPort::finishSketching( bool theStatus )
1419 {
1420   prepareToSketch( false );
1421
1422   mySketchingItem->setVisible( false );
1423   myIsSketching = false;
1424
1425   setCursor( *getDefaultCursor() );
1426
1427   if( theStatus )
1428   {
1429     QPainterPath aPath = mySketchingItem->path();
1430     emit vpSketchingFinished( aPath );
1431   }
1432 }
1433
1434 //================================================================
1435 // Function : isSketching
1436 // Purpose  : 
1437 //================================================================
1438 bool GraphicsView_ViewPort::isSketching( bool* theIsPath ) const
1439 {
1440   if( theIsPath )
1441     *theIsPath = myIsSketchingByPath;
1442   return myIsSketching;
1443 }
1444
1445 //================================================================
1446 // Function : dragObjects
1447 // Purpose  : 
1448 //================================================================
1449 void GraphicsView_ViewPort::dragObjects( QGraphicsSceneMouseEvent* e )
1450 {
1451   GraphicsView_Object* anObject = getHighlightedObject();
1452
1453   if( myDragPosition.isNull() )
1454   {
1455     myDragPosition = e->scenePos();
1456     return;
1457   }
1458
1459   GraphicsView_ObjectList anObjectsToMove;
1460   if( anObject && anObject->isMovable() && ( e->buttons() & Qt::LeftButton ) )
1461   {
1462     if( anObject->isSelected() )
1463     {
1464       for( initSelected(); moreSelected(); nextSelected() )
1465         if( GraphicsView_Object* aMovingObject = selectedObject() )
1466           if( aMovingObject->isMovable() )
1467             anObjectsToMove.append( aMovingObject );
1468     }
1469     else
1470       anObjectsToMove.append( anObject );
1471   }
1472   else if( hasInteractionFlag( DraggingByMiddleButton ) &&
1473            nbSelected() && ( e->buttons() & Qt::MidButton ) )
1474   {
1475     for( initSelected(); moreSelected(); nextSelected() )
1476       if( GraphicsView_Object* aMovingObject = selectedObject() )
1477         if( aMovingObject->isMovable() )
1478           anObjectsToMove.append( aMovingObject );
1479   }
1480
1481   if( anObjectsToMove.isEmpty() )
1482     return;
1483
1484   double aDX = e->scenePos().x() - myDragPosition.x();
1485   double aDY = e->scenePos().y() - myDragPosition.y();
1486
1487   bool anIsMovingByXAllowed = true, anIsMovingByYAllowed = true;
1488   GraphicsView_ObjectListIterator anIter( anObjectsToMove );
1489   while( anIter.hasNext() )
1490     if( GraphicsView_Object* aMovingObject = anIter.next() )
1491     {
1492       if( !aMovingObject->isMovingByXAllowed( aDX ) )
1493         anIsMovingByXAllowed = false;
1494       if( !aMovingObject->isMovingByYAllowed( aDY ) )
1495         anIsMovingByYAllowed = false;
1496     }
1497
1498   if( !anIsMovingByXAllowed && !anIsMovingByYAllowed )
1499     return; // myDragPosition shouldn't be changed
1500
1501   if( !anIsMovingByXAllowed )
1502     aDX = 0;
1503
1504   if( !anIsMovingByYAllowed )
1505     aDY = 0;
1506
1507   anIter = anObjectsToMove;
1508   while( anIter.hasNext() )
1509     if( GraphicsView_Object* aMovingObject = anIter.next() )
1510       aMovingObject->move( aDX, aDY );
1511
1512   if( anIsMovingByXAllowed )
1513     myDragPosition.setX( e->scenePos().x() );
1514
1515   if( anIsMovingByYAllowed )
1516     myDragPosition.setY( e->scenePos().y() );
1517 }
1518
1519 //================================================================
1520 // Function : startPulling
1521 // Purpose  : 
1522 //================================================================
1523 bool GraphicsView_ViewPort::startPulling( const QPointF& thePoint )
1524 {
1525   QListIterator<QGraphicsItem*> anIter( items() );
1526   while( anIter.hasNext() )
1527   {
1528     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1529     {
1530       QRectF aRect = anObject->getPullingRect();
1531       if( aRect.contains( thePoint ) && anObject->startPulling( thePoint ) )
1532       {
1533         myIsPulling = true;
1534         myPullingObject = anObject;
1535         //setCursor( *getHandCursor() ); // testing ImageViewer
1536         return true;
1537       }
1538     }
1539   }
1540   return false;
1541 }
1542
1543 //================================================================
1544 // Function : drawPulling
1545 // Purpose  : 
1546 //================================================================
1547 void GraphicsView_ViewPort::drawPulling( const QPointF& thePoint )
1548 {
1549   GraphicsView_Object* aLockedObject = 0;
1550
1551   QListIterator<QGraphicsItem*> anIter( items() );
1552   while( anIter.hasNext() )
1553   {
1554     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1555     {
1556       if( !anObject->isVisible() )
1557         continue;
1558
1559       QRectF aRect = anObject->getPullingRect();
1560       if( aRect.contains( thePoint ) && anObject->portContains( thePoint ) )
1561       {
1562         aLockedObject = anObject;
1563         break;
1564       }
1565     }
1566   }
1567
1568   myPullingObject->pull( thePoint, aLockedObject, getSelectedObjects() );
1569 }
1570
1571 //================================================================
1572 // Function : finishPulling
1573 // Purpose  : 
1574 //================================================================
1575 void GraphicsView_ViewPort::finishPulling( bool theStatus )
1576 {
1577   myIsPulling = false;
1578   myPullingObject->finishPulling( theStatus, getSelectedObjects() );
1579   setCursor( *getDefaultCursor() );
1580 }
1581
1582 //================================================================
1583 // Function : cancelCurrentOperation
1584 // Purpose  : 
1585 //================================================================
1586 bool GraphicsView_ViewPort::cancelCurrentOperation()
1587 {
1588   myIsHighlighting = false;
1589
1590   if( isDragging() )
1591   {
1592     for( initSelected(); moreSelected(); nextSelected() )
1593       if( GraphicsView_Object* aMovingObject = selectedObject() )
1594         aMovingObject->finishMove( false );
1595
1596     if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1597       aMovingObject->finishMove( false );
1598
1599     myIsDragging = false;
1600     myDragPosition = QPointF();
1601     //setCursor( myStoredCursor );
1602     setCursor( *getDefaultCursor() );
1603
1604     return true;
1605   }
1606
1607   if( isPulling() )
1608   {
1609     finishPulling( false );
1610     return true;
1611   }
1612
1613   if( isSketching() || isPrepareToSketch() )
1614   {
1615     finishSketching( false );
1616     return true;
1617   }
1618
1619   return false;
1620 }
1621
1622 //================================================================
1623 // Function : onBoundingRectChanged
1624 // Purpose  : 
1625 //================================================================
1626 void GraphicsView_ViewPort::onBoundingRectChanged()
1627 {
1628   if( hasInteractionFlag( TraceBoundingRect ) )
1629   {
1630     QRectF aRect = objectsBoundingRect( true );
1631     myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
1632   }
1633 }
1634
1635 //================================================================
1636 // Function : onKeyEvent
1637 // Purpose  : 
1638 //================================================================
1639 void GraphicsView_ViewPort::onKeyEvent( QKeyEvent* e )
1640 {
1641   emit vpKeyEvent( e );
1642 }
1643
1644 //================================================================
1645 // Function : onMouseEvent
1646 // Purpose  : 
1647 //================================================================
1648 void GraphicsView_ViewPort::onMouseEvent( QGraphicsSceneMouseEvent* e )
1649 {
1650   emit vpMouseEvent( e );
1651
1652   bool anIsHandled = false;
1653   switch( e->type() )
1654   {
1655     case QEvent::GraphicsSceneMousePress:
1656     {
1657       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1658         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1659           if( GraphicsView_Object* anObject = selectedObject() )
1660             anIsHandled = anObject->handleMousePress( e );
1661
1662       if( !anIsHandled && hasInteractionFlag( Dragging ) )
1663       {
1664         bool anAccel = e->modifiers() & GraphicsView_ViewTransformer::accelKey();
1665         if( ( getHighlightedObject() &&
1666               getHighlightedObject()->isMovable() &&
1667               !( anAccel || e->button() != Qt::LeftButton ) ) ||
1668             ( hasInteractionFlag( DraggingByMiddleButton ) &&
1669               nbSelected() && !anAccel && e->button() == Qt::MidButton ) )
1670         {
1671           myIsDragging = true;
1672           myStoredCursor = cursor();
1673           setCursor( Qt::ClosedHandCursor );
1674         }
1675       }
1676       break;
1677     }
1678     case QEvent::GraphicsSceneMouseMove:
1679     {
1680       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1681         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1682           if( GraphicsView_Object* anObject = selectedObject() )
1683             anIsHandled = anObject->handleMouseMove( e );
1684
1685       if( !anIsHandled && !isPulling() && myIsDragging )
1686         dragObjects( e );
1687       break;
1688     }
1689     case QEvent::GraphicsSceneMouseRelease:
1690     {
1691       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1692         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1693           if( GraphicsView_Object* anObject = selectedObject() )
1694             anIsHandled = anObject->handleMouseRelease( e );
1695
1696       if( !anIsHandled && !isPulling() && myIsDragging )
1697       {
1698         emit vpObjectBeforeMoving();
1699
1700         bool anIsMoved = false;
1701         for( initSelected(); moreSelected(); nextSelected() )
1702           if( GraphicsView_Object* aMovingObject = selectedObject() )
1703             anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1704
1705         if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1706           anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1707
1708         myIsDragging = false;
1709         myDragPosition = QPointF();
1710         setCursor( myStoredCursor );
1711
1712         emit vpObjectAfterMoving( anIsMoved );
1713       }
1714       break;
1715     }
1716     case QEvent::GraphicsSceneMouseDoubleClick:
1717       break; // do nothing, just emit the signal
1718     default:
1719       break;
1720   }
1721
1722   if( myIsMousePositionEnabled )
1723   {
1724     int aMouseX = (int)e->scenePos().x();
1725     int aMouseY = (int)e->scenePos().y();
1726     setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
1727   }
1728 }
1729
1730 //================================================================
1731 // Function : onWheelEvent
1732 // Purpose  : 
1733 //================================================================
1734 void GraphicsView_ViewPort::onWheelEvent( QGraphicsSceneWheelEvent* e )
1735 {
1736   emit vpWheelEvent( e );
1737 }
1738
1739 //================================================================
1740 // Function : onContextMenuEvent
1741 // Purpose  : 
1742 //================================================================
1743 void GraphicsView_ViewPort::onContextMenuEvent( QGraphicsSceneContextMenuEvent* e )
1744 {
1745   emit vpContextMenuEvent( e );
1746 }
1747
1748 //================================================================
1749 // Function : scrollContentsBy
1750 // Purpose  : 
1751 //================================================================
1752 void GraphicsView_ViewPort::scrollContentsBy( int theDX, int theDY )
1753 {
1754   if( myViewLabel )
1755     myViewLabel->setAcceptMoveEvents( false );
1756
1757   QGraphicsView::scrollContentsBy( theDX, theDY );
1758
1759   if( myViewLabel )
1760     myViewLabel->setAcceptMoveEvents( true );
1761 }