1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: graphctl.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svtools/itempool.hxx>
34 #include <vcl/dialog.hxx>
35 #include <vcl/wrkwin.hxx>
36 #include <svtools/syslocale.hxx>
37 #include <rtl/math.hxx>
38 #include <unotools/localedatawrapper.hxx>
39 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
40 #include <comphelper/processfactory.hxx>
42 #include <vcl/svapp.hxx>
43 #include <osl/mutex.hxx>
45 #include <svx/graphctl.hxx>
46 #include "GraphCtlAccessibleContext.hxx"
47 #include "xoutbmp.hxx"
48 #include <svx/svxids.hrc>
49 #include <svx/svdpage.hxx>
52 #include "sdrpaintwindow.hxx"
54 /*************************************************************************
58 \************************************************************************/
60 void GraphCtrlUserCall::Changed( const SdrObject
& rObj
, SdrUserCallType eType
, const Rectangle
& /*rOldBoundRect*/ )
64 case( SDRUSERCALL_MOVEONLY
):
65 case( SDRUSERCALL_RESIZE
):
66 rWin
.SdrObjChanged( rObj
);
69 case( SDRUSERCALL_INSERTED
):
70 rWin
.SdrObjCreated( rObj
);
79 /*************************************************************************
83 \************************************************************************/
85 GraphCtrl::GraphCtrl( Window
* pParent
, const WinBits nWinBits
) :
86 Control ( pParent
, nWinBits
),
87 aMap100 ( MAP_100TH_MM
),
88 eObjKind ( OBJ_NONE
),
92 mpAccContext ( NULL
),
96 pUserCall
= new GraphCtrlUserCall( *this );
97 aUpdateTimer
.SetTimeout( 200 );
98 aUpdateTimer
.SetTimeoutHdl( LINK( this, GraphCtrl
, UpdateHdl
) );
101 SetWinStyle( nWinBits
);
107 /*************************************************************************
111 \************************************************************************/
113 GraphCtrl::GraphCtrl( Window
* pParent
, const ResId
& rResId
) :
114 Control ( pParent
, rResId
),
115 aMap100 ( MAP_100TH_MM
),
117 eObjKind ( OBJ_NONE
),
122 mpAccContext ( NULL
),
126 pUserCall
= new GraphCtrlUserCall( *this );
127 aUpdateTimer
.SetTimeout( 500 );
128 aUpdateTimer
.SetTimeoutHdl( LINK( this, GraphCtrl
, UpdateHdl
) );
129 aUpdateTimer
.Start();
134 /*************************************************************************
138 \************************************************************************/
140 GraphCtrl::~GraphCtrl()
144 mpAccContext
->disposing();
145 mpAccContext
->release();
153 /*************************************************************************
157 \************************************************************************/
159 void GraphCtrl::SetWinStyle( WinBits nWinBits
)
161 nWinStyle
= nWinBits
;
162 bAnim
= ( nWinStyle
& WB_ANIMATION
) == WB_ANIMATION
;
163 bSdrMode
= ( nWinStyle
& WB_SDRMODE
) == WB_SDRMODE
;
165 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
166 SetBackground( Wallpaper( rStyleSettings
.GetWindowColor() ) );
167 SetMapMode( aMap100
);
180 /*************************************************************************
184 \************************************************************************/
186 void GraphCtrl::InitSdrModel()
188 ::vos::OGuard
aGuard (Application::GetSolarMutex());
192 // alten Kram zerstoeren
197 pModel
= new SdrModel
;
198 pModel
->GetItemPool().FreezeIdRanges();
199 pModel
->SetScaleUnit( aMap100
.GetMapUnit() );
200 pModel
->SetScaleFraction( Fraction( 1, 1 ) );
201 pModel
->SetDefaultFontHeight( 500 );
203 pPage
= new SdrPage( *pModel
);
205 pPage
->SetSize( aGraphSize
);
206 pPage
->SetBorder( 0, 0, 0, 0 );
207 pModel
->InsertPage( pPage
);
208 pModel
->SetChanged( sal_False
);
211 pView
= new GraphCtrlView( pModel
, this );
212 pView
->SetWorkArea( Rectangle( Point(), aGraphSize
) );
213 pView
->EnableExtendedMouseEventDispatcher( TRUE
);
214 pView
->ShowSdrPage(pView
->GetModel()->GetPage(0));
215 // pView->ShowSdrPage(pView->GetModel()->GetPage(0));
216 pView
->SetFrameDragSingles( TRUE
);
217 pView
->SetMarkedPointsSmooth( SDRPATHSMOOTH_SYMMETRIC
);
218 pView
->SetEditMode( TRUE
);
220 // #i72889# set neeeded flags
221 pView
->SetPagePaintingAllowed(false);
222 pView
->SetBufferedOutputAllowed(true);
223 pView
->SetBufferedOverlayAllowed(true);
225 // Tell the accessibility object about the changes.
226 if (mpAccContext
!= NULL
)
227 mpAccContext
->setModelAndView (pModel
, pView
);
231 /*************************************************************************
235 \************************************************************************/
237 void GraphCtrl::SetGraphic( const Graphic
& rGraphic
, BOOL bNewModel
)
239 // Bitmaps dithern wir ggf. fuer die Anzeige
240 if ( !bAnim
&& ( rGraphic
.GetType() == GRAPHIC_BITMAP
) )
242 if ( rGraphic
.IsTransparent() )
244 Bitmap
aBmp( rGraphic
.GetBitmap() );
246 DitherBitmap( aBmp
);
247 aGraphic
= Graphic( BitmapEx( aBmp
, rGraphic
.GetBitmapEx().GetMask() ) );
251 Bitmap
aBmp( rGraphic
.GetBitmap() );
252 DitherBitmap( aBmp
);
259 if ( aGraphic
.GetPrefMapMode().GetMapUnit() == MAP_PIXEL
)
260 aGraphSize
= Application::GetDefaultDevice()->PixelToLogic( aGraphic
.GetPrefSize(), aMap100
);
262 aGraphSize
= OutputDevice::LogicToLogic( aGraphic
.GetPrefSize(), aGraphic
.GetPrefMapMode(), aMap100
);
264 if ( bSdrMode
&& bNewModel
)
267 if ( aGraphSizeLink
.IsSet() )
268 aGraphSizeLink
.Call( this );
275 /*************************************************************************
279 \************************************************************************/
281 void GraphCtrl::Resize()
285 if ( aGraphSize
.Width() && aGraphSize
.Height() )
287 MapMode
aDisplayMap( aMap100
);
290 const Size aWinSize
= PixelToLogic( GetOutputSizePixel(), aDisplayMap
);
291 const long nWidth
= aWinSize
.Width();
292 const long nHeight
= aWinSize
.Height();
293 double fGrfWH
= (double) aGraphSize
.Width() / aGraphSize
.Height();
294 double fWinWH
= (double) nWidth
/ nHeight
;
296 // Bitmap an Thumbgroesse anpassen
297 if ( fGrfWH
< fWinWH
)
299 aNewSize
.Width() = (long) ( (double) nHeight
* fGrfWH
);
300 aNewSize
.Height()= nHeight
;
304 aNewSize
.Width() = nWidth
;
305 aNewSize
.Height()= (long) ( (double) nWidth
/ fGrfWH
);
308 aNewPos
.X() = ( nWidth
- aNewSize
.Width() ) >> 1;
309 aNewPos
.Y() = ( nHeight
- aNewSize
.Height() ) >> 1;
311 // MapMode fuer Engine umsetzen
312 aDisplayMap
.SetScaleX( Fraction( aNewSize
.Width(), aGraphSize
.Width() ) );
313 aDisplayMap
.SetScaleY( Fraction( aNewSize
.Height(), aGraphSize
.Height() ) );
315 aDisplayMap
.SetOrigin( LogicToLogic( aNewPos
, aMap100
, aDisplayMap
) );
316 SetMapMode( aDisplayMap
);
323 /*************************************************************************
327 \************************************************************************/
329 void GraphCtrl::Paint( const Rectangle
& rRect
)
331 // #i72889# used splitted repaint to be able to paint an own background
332 // even to the buffered view
333 const bool bGraphicValid(GRAPHIC_NONE
!= aGraphic
.GetType());
337 SdrPaintWindow
* pPaintWindow
= pView
->BeginCompleteRedraw(this);
341 OutputDevice
& rTarget
= pPaintWindow
->GetTargetOutputDevice();
343 rTarget
.SetBackground(GetBackground());
346 aGraphic
.Draw(&rTarget
, Point(), aGraphSize
);
349 const Region
aRepaintRegion(rRect
);
350 pView
->DoCompleteRedraw(*pPaintWindow
, aRepaintRegion
);
351 pView
->EndCompleteRedraw(*pPaintWindow
, true);
355 // #i73381# in non-SdrMode, paint to local directly
358 aGraphic
.Draw(this, Point(), aGraphSize
);
364 /*************************************************************************
368 \************************************************************************/
370 void GraphCtrl::SdrObjChanged( const SdrObject
& )
375 /*************************************************************************
379 \************************************************************************/
381 void GraphCtrl::SdrObjCreated( const SdrObject
& )
386 /*************************************************************************
390 \************************************************************************/
392 void GraphCtrl::MarkListHasChanged()
394 if ( aMarkObjLink
.IsSet() )
395 aMarkObjLink
.Call( this );
399 /*************************************************************************
403 \************************************************************************/
405 void GraphCtrl::KeyInput( const KeyEvent
& rKEvt
)
407 KeyCode
aCode( rKEvt
.GetKeyCode() );
410 switch ( aCode
.GetCode() )
417 pView
->DeleteMarked();
419 if( !pView
->AreObjectsMarked() )
420 ((Dialog
*)GetParent())->GrabFocusToFirstControl();
429 if ( pView
->IsAction() )
433 else if ( pView
->AreObjectsMarked() )
435 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
436 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
440 ((SdrHdlList
&)rHdlList
).ResetFocusHdl();
444 ((Dialog
*)GetParent())->GrabFocusToFirstControl();
449 ((Dialog
*)GetParent())->GrabFocusToFirstControl();
461 if( !aCode
.IsMod1() && !aCode
.IsMod2() )
463 bool bForward
= !aCode
.IsShift();
464 // select next object
465 if ( ! pView
->MarkNextObj( bForward
))
467 // At first or last object. Cycle to the other end
469 pView
->UnmarkAllObj();
470 pView
->MarkNextObj (bForward
);
474 else if(aCode
.IsMod1())
476 // select next handle
477 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
478 sal_Bool
bForward(!aCode
.IsShift());
480 ((SdrHdlList
&)rHdlList
).TravelFocusHdl(bForward
);
491 if ( aCode
.IsMod1() )
493 // #97016# mark last object
494 pView
->UnmarkAllObj();
495 pView
->MarkNextObj(FALSE
);
504 if ( aCode
.IsMod1() )
506 pView
->UnmarkAllObj();
507 pView
->MarkNextObj(TRUE
);
522 if (aCode
.GetCode() == KEY_UP
)
528 else if (aCode
.GetCode() == KEY_DOWN
)
534 else if (aCode
.GetCode() == KEY_LEFT
)
540 else if (aCode
.GetCode() == KEY_RIGHT
)
542 // Scroll nach rechts
547 if (pView
->AreObjectsMarked() && !aCode
.IsMod1() )
551 // #97016# move in 1 pixel distance
552 Size aLogicSizeOnePixel
= PixelToLogic(Size(1,1));
553 nX
*= aLogicSizeOnePixel
.Width();
554 nY
*= aLogicSizeOnePixel
.Height();
558 // old, fixed move distance
564 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
565 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
569 // #90129# restrict movement to WorkArea
570 const Rectangle
& rWorkArea
= pView
->GetWorkArea();
572 if(!rWorkArea
.IsEmpty())
574 Rectangle
aMarkRect(pView
->GetMarkedObjRect());
575 aMarkRect
.Move(nX
, nY
);
577 if(!aMarkRect
.IsInside(rWorkArea
))
579 if(aMarkRect
.Left() < rWorkArea
.Left())
581 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
584 if(aMarkRect
.Right() > rWorkArea
.Right())
586 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
589 if(aMarkRect
.Top() < rWorkArea
.Top())
591 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
594 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
596 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
601 // no handle selected
602 if(0 != nX
|| 0 != nY
)
604 pView
->MoveAllMarked(Size(nX
, nY
));
609 // move handle with index nHandleIndex
610 if(pHdl
&& (nX
|| nY
))
612 // now move the Handle (nX, nY)
613 Point
aStartPoint(pHdl
->GetPos());
614 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
615 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
618 pView
->BegDragObj(aStartPoint
, 0, pHdl
, 0);
620 if(pView
->IsDragObj())
622 FASTBOOL bWasNoSnap
= rDragStat
.IsNoSnap();
623 BOOL bWasSnapEnabled
= pView
->IsSnapEnabled();
625 // switch snapping off
627 ((SdrDragStat
&)rDragStat
).SetNoSnap(TRUE
);
629 pView
->SetSnapEnabled(FALSE
);
631 pView
->MovAction(aEndPoint
);
636 ((SdrDragStat
&)rDragStat
).SetNoSnap(bWasNoSnap
);
638 pView
->SetSnapEnabled(bWasSnapEnabled
);
650 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
651 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
655 if(pHdl
->GetKind() == HDL_POLY
)
657 // rescue ID of point with focus
658 sal_uInt32
nPol(pHdl
->GetPolyNum());
659 sal_uInt32
nPnt(pHdl
->GetPointNum());
661 if(pView
->IsPointMarked(*pHdl
))
663 if(rKEvt
.GetKeyCode().IsShift())
665 pView
->UnmarkPoint(*pHdl
);
670 if(!rKEvt
.GetKeyCode().IsShift())
672 pView
->UnmarkAllPoints();
675 pView
->MarkPoint(*pHdl
);
678 if(0L == rHdlList
.GetFocusHdl())
680 // restore point with focus
681 SdrHdl
* pNewOne
= 0L;
683 for(sal_uInt32
a(0); !pNewOne
&& a
< rHdlList
.GetHdlCount(); a
++)
685 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
688 && pAct
->GetKind() == HDL_POLY
689 && pAct
->GetPolyNum() == nPol
690 && pAct
->GetPointNum() == nPnt
)
698 ((SdrHdlList
&)rHdlList
).SetFocusHdl(pNewOne
);
713 Control::KeyInput( rKEvt
);
719 /*************************************************************************
723 \************************************************************************/
725 void GraphCtrl::MouseButtonDown( const MouseEvent
& rMEvt
)
727 if ( bSdrMode
&& ( rMEvt
.GetClicks() < 2 ) )
729 const Point
aLogPt( PixelToLogic( rMEvt
.GetPosPixel() ) );
731 if ( !Rectangle( Point(), aGraphSize
).IsInside( aLogPt
) && !pView
->IsEditMode() )
732 Control::MouseButtonDown( rMEvt
);
735 // Focus anziehen fuer Key-Inputs
741 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SDRMOUSEBUTTONDOWN
, aVEvt
);
743 if ( nPolyEdit
== SID_BEZIER_INSERT
&& eHit
== SDRHIT_MARKEDOBJECT
)
744 pView
->BegInsObjPoint( aLogPt
, rMEvt
.IsMod1());
746 pView
->MouseButtonDown( rMEvt
, this );
749 pView
->MouseButtonDown( rMEvt
, this );
752 SdrObject
* pCreateObj
= pView
->GetCreateObj();
754 // Wir wollen das Inserten mitbekommen
755 if ( pCreateObj
&& !pCreateObj
->GetUserCall() )
756 pCreateObj
->SetUserCall( pUserCall
);
758 SetPointer( pView
->GetPreferedPointer( aLogPt
, this ) );
761 Control::MouseButtonDown( rMEvt
);
765 /*************************************************************************
769 \************************************************************************/
771 void GraphCtrl::MouseMove(const MouseEvent
& rMEvt
)
773 const Point
aLogPos( PixelToLogic( rMEvt
.GetPosPixel() ) );
777 pView
->MouseMove( rMEvt
, this );
779 if( ( SID_BEZIER_INSERT
== nPolyEdit
) &&
780 !pView
->PickHandle( aLogPos
) &&
781 !pView
->IsInsObjPoint() )
783 SetPointer( POINTER_CROSS
);
786 SetPointer( pView
->GetPreferedPointer( aLogPos
, this ) );
789 Control::MouseButtonUp( rMEvt
);
791 if ( aMousePosLink
.IsSet() )
793 if ( Rectangle( Point(), aGraphSize
).IsInside( aLogPos
) )
798 aMousePosLink
.Call( this );
803 /*************************************************************************
807 \************************************************************************/
809 void GraphCtrl::MouseButtonUp(const MouseEvent
& rMEvt
)
813 if ( pView
->IsInsObjPoint() )
814 pView
->EndInsObjPoint( SDRCREATE_FORCEEND
);
816 pView
->MouseButtonUp( rMEvt
, this );
819 SetPointer( pView
->GetPreferedPointer( PixelToLogic( rMEvt
.GetPosPixel() ), this ) );
822 Control::MouseButtonUp( rMEvt
);
826 /*************************************************************************
830 \************************************************************************/
832 SdrObject
* GraphCtrl::GetSelectedSdrObject() const
834 SdrObject
* pSdrObj
= NULL
;
838 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
840 if ( rMarkList
.GetMarkCount() == 1 )
841 pSdrObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
848 /*************************************************************************
852 \************************************************************************/
854 void GraphCtrl::SetEditMode( const BOOL _bEditMode
)
858 bEditMode
= _bEditMode
;
859 pView
->SetEditMode( bEditMode
);
861 pView
->SetCurrentObj( sal::static_int_cast
< UINT16
>( eObjKind
) );
868 /*************************************************************************
872 \************************************************************************/
874 void GraphCtrl::SetPolyEditMode( const USHORT _nPolyEdit
)
876 if ( bSdrMode
&& ( _nPolyEdit
!= nPolyEdit
) )
878 nPolyEdit
= _nPolyEdit
;
879 pView
->SetFrameDragSingles( nPolyEdit
== 0 );
886 /*************************************************************************
890 \************************************************************************/
892 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind
)
897 pView
->SetEditMode( bEditMode
);
898 eObjKind
= _eObjKind
;
899 pView
->SetCurrentObj( sal::static_int_cast
< UINT16
>( eObjKind
) );
906 /*************************************************************************
910 \************************************************************************/
912 String
GraphCtrl::GetStringFromDouble( const double& rDouble
)
915 SvtSysLocale().GetLocaleData().getNumDecimalSep().GetChar(0);
916 String
aStr( ::rtl::math::doubleToUString( rDouble
,
917 rtl_math_StringFormat_F
, 2, cSep
));
922 /*************************************************************************
926 \************************************************************************/
928 IMPL_LINK( GraphCtrl
, UpdateHdl
, Timer
*, pTimer
)
930 if ( aUpdateLink
.IsSet() )
931 aUpdateLink
.Call( this );
939 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> GraphCtrl::CreateAccessible()
941 if( mpAccContext
== NULL
)
943 Window
* pParent
= GetParent();
945 DBG_ASSERT( pParent
, "-GraphCtrl::CreateAccessible(): No Parent!" );
949 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> xAccParent( pParent
->GetAccessible() );
951 // #103856# Disable accessibility if no model/view data available
956 mpAccContext
= new SvxGraphCtrlAccessibleContext( xAccParent
, *this );
957 mpAccContext
->acquire();