1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/itempool.hxx>
21 #include <vcl/dialog.hxx>
22 #include <vcl/wrkwin.hxx>
23 #include <unotools/syslocale.hxx>
24 #include <rtl/math.hxx>
25 #include <unotools/localedatawrapper.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <vcl/svapp.hxx>
28 #include <osl/mutex.hxx>
30 #include <svx/graphctl.hxx>
31 #include "GraphCtlAccessibleContext.hxx"
32 #include "svx/xoutbmp.hxx"
33 #include <svx/svxids.hrc>
34 #include <svx/svdpage.hxx>
37 #include "svx/sdrpaintwindow.hxx"
39 void GraphCtrlUserCall::Changed( const SdrObject
& rObj
, SdrUserCallType eType
, const Rectangle
& /*rOldBoundRect*/ )
43 case( SDRUSERCALL_MOVEONLY
):
44 case( SDRUSERCALL_RESIZE
):
45 rWin
.SdrObjChanged( rObj
);
48 case( SDRUSERCALL_INSERTED
):
49 rWin
.SdrObjCreated( rObj
);
57 GraphCtrl::GraphCtrl( Window
* pParent
, const ResId
& rResId
) :
58 Control ( pParent
, rResId
),
59 aMap100 ( MAP_100TH_MM
),
61 eObjKind ( OBJ_NONE
),
63 bEditMode ( sal_False
),
64 bSdrMode ( sal_False
),
66 mpAccContext ( NULL
),
70 pUserCall
= new GraphCtrlUserCall( *this );
71 aUpdateTimer
.SetTimeout( 500 );
72 aUpdateTimer
.SetTimeoutHdl( LINK( this, GraphCtrl
, UpdateHdl
) );
74 EnableRTL( sal_False
);
77 GraphCtrl::~GraphCtrl()
81 mpAccContext
->disposing();
82 mpAccContext
->release();
89 void GraphCtrl::SetWinStyle( WinBits nWinBits
)
92 bAnim
= ( nWinStyle
& WB_ANIMATION
) == WB_ANIMATION
;
93 bSdrMode
= ( nWinStyle
& WB_SDRMODE
) == WB_SDRMODE
;
95 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
96 SetBackground( Wallpaper( rStyleSettings
.GetWindowColor() ) );
97 SetMapMode( aMap100
);
109 void GraphCtrl::InitSdrModel()
111 SolarMutexGuard aGuard
;
120 pModel
= new SdrModel
;
121 pModel
->GetItemPool().FreezeIdRanges();
122 pModel
->SetScaleUnit( aMap100
.GetMapUnit() );
123 pModel
->SetScaleFraction( Fraction( 1, 1 ) );
124 pModel
->SetDefaultFontHeight( 500 );
126 pPage
= new SdrPage( *pModel
);
128 pPage
->SetSize( aGraphSize
);
129 pPage
->SetBorder( 0, 0, 0, 0 );
130 pModel
->InsertPage( pPage
);
131 pModel
->SetChanged( sal_False
);
134 pView
= new GraphCtrlView( pModel
, this );
135 pView
->SetWorkArea( Rectangle( Point(), aGraphSize
) );
136 pView
->EnableExtendedMouseEventDispatcher( sal_True
);
137 pView
->ShowSdrPage(pView
->GetModel()->GetPage(0));
138 pView
->SetFrameDragSingles( sal_True
);
139 pView
->SetMarkedPointsSmooth( SDRPATHSMOOTH_SYMMETRIC
);
140 pView
->SetEditMode( sal_True
);
142 // #i72889# set neeeded flags
143 pView
->SetPagePaintingAllowed(false);
144 pView
->SetBufferedOutputAllowed(true);
145 pView
->SetBufferedOverlayAllowed(true);
147 // Tell the accessibility object about the changes.
148 if (mpAccContext
!= NULL
)
149 mpAccContext
->setModelAndView (pModel
, pView
);
152 void GraphCtrl::SetGraphic( const Graphic
& rGraphic
, sal_Bool bNewModel
)
154 // If possible we dither bitmaps for the display
155 if ( !bAnim
&& ( rGraphic
.GetType() == GRAPHIC_BITMAP
) )
157 if ( rGraphic
.IsTransparent() )
159 Bitmap
aBmp( rGraphic
.GetBitmap() );
161 DitherBitmap( aBmp
);
162 aGraphic
= Graphic( BitmapEx( aBmp
, rGraphic
.GetBitmapEx().GetMask() ) );
166 Bitmap
aBmp( rGraphic
.GetBitmap() );
167 DitherBitmap( aBmp
);
174 if ( aGraphic
.GetPrefMapMode().GetMapUnit() == MAP_PIXEL
)
175 aGraphSize
= Application::GetDefaultDevice()->PixelToLogic( aGraphic
.GetPrefSize(), aMap100
);
177 aGraphSize
= OutputDevice::LogicToLogic( aGraphic
.GetPrefSize(), aGraphic
.GetPrefMapMode(), aMap100
);
179 if ( bSdrMode
&& bNewModel
)
182 if ( aGraphSizeLink
.IsSet() )
183 aGraphSizeLink
.Call( this );
189 void GraphCtrl::Resize()
193 if ( aGraphSize
.Width() && aGraphSize
.Height() )
195 MapMode
aDisplayMap( aMap100
);
198 const Size aWinSize
= PixelToLogic( GetOutputSizePixel(), aDisplayMap
);
199 const long nWidth
= aWinSize
.Width();
200 const long nHeight
= aWinSize
.Height();
201 double fGrfWH
= (double) aGraphSize
.Width() / aGraphSize
.Height();
202 double fWinWH
= (double) nWidth
/ nHeight
;
204 // Adapt Bitmap to Thumb size
205 if ( fGrfWH
< fWinWH
)
207 aNewSize
.Width() = (long) ( (double) nHeight
* fGrfWH
);
208 aNewSize
.Height()= nHeight
;
212 aNewSize
.Width() = nWidth
;
213 aNewSize
.Height()= (long) ( (double) nWidth
/ fGrfWH
);
216 aNewPos
.X() = ( nWidth
- aNewSize
.Width() ) >> 1;
217 aNewPos
.Y() = ( nHeight
- aNewSize
.Height() ) >> 1;
219 // Implementing MapMode for Engine
220 aDisplayMap
.SetScaleX( Fraction( aNewSize
.Width(), aGraphSize
.Width() ) );
221 aDisplayMap
.SetScaleY( Fraction( aNewSize
.Height(), aGraphSize
.Height() ) );
223 aDisplayMap
.SetOrigin( LogicToLogic( aNewPos
, aMap100
, aDisplayMap
) );
224 SetMapMode( aDisplayMap
);
230 void GraphCtrl::Paint( const Rectangle
& rRect
)
232 // #i72889# used splitted repaint to be able to paint an own background
233 // even to the buffered view
234 const bool bGraphicValid(GRAPHIC_NONE
!= aGraphic
.GetType());
238 SdrPaintWindow
* pPaintWindow
= pView
->BeginCompleteRedraw(this);
242 OutputDevice
& rTarget
= pPaintWindow
->GetTargetOutputDevice();
244 rTarget
.SetBackground(GetBackground());
247 aGraphic
.Draw(&rTarget
, Point(), aGraphSize
);
250 const Region
aRepaintRegion(rRect
);
251 pView
->DoCompleteRedraw(*pPaintWindow
, aRepaintRegion
);
252 pView
->EndCompleteRedraw(*pPaintWindow
, true);
256 // #i73381# in non-SdrMode, paint to local directly
259 aGraphic
.Draw(this, Point(), aGraphSize
);
264 void GraphCtrl::SdrObjChanged( const SdrObject
& )
268 void GraphCtrl::SdrObjCreated( const SdrObject
& )
272 void GraphCtrl::MarkListHasChanged()
274 if ( aMarkObjLink
.IsSet() )
275 aMarkObjLink
.Call( this );
278 void GraphCtrl::KeyInput( const KeyEvent
& rKEvt
)
280 KeyCode
aCode( rKEvt
.GetKeyCode() );
283 switch ( aCode
.GetCode() )
290 pView
->DeleteMarked();
292 if( !pView
->AreObjectsMarked() )
293 GetParentDialog()->GrabFocusToFirstControl();
302 if ( pView
->IsAction() )
306 else if ( pView
->AreObjectsMarked() )
308 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
309 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
313 ((SdrHdlList
&)rHdlList
).ResetFocusHdl();
317 GetParentDialog()->GrabFocusToFirstControl();
322 GetParentDialog()->GrabFocusToFirstControl();
334 if( !aCode
.IsMod1() && !aCode
.IsMod2() )
336 bool bForward
= !aCode
.IsShift();
337 // select next object
338 if ( ! pView
->MarkNextObj( bForward
))
340 // At first or last object. Cycle to the other end
342 pView
->UnmarkAllObj();
343 pView
->MarkNextObj (bForward
);
347 else if(aCode
.IsMod1())
349 // select next handle
350 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
351 sal_Bool
bForward(!aCode
.IsShift());
353 ((SdrHdlList
&)rHdlList
).TravelFocusHdl(bForward
);
364 if ( aCode
.IsMod1() )
367 pView
->UnmarkAllObj();
368 pView
->MarkNextObj(sal_False
);
377 if ( aCode
.IsMod1() )
379 pView
->UnmarkAllObj();
380 pView
->MarkNextObj(sal_True
);
395 if (aCode
.GetCode() == KEY_UP
)
401 else if (aCode
.GetCode() == KEY_DOWN
)
407 else if (aCode
.GetCode() == KEY_LEFT
)
413 else if (aCode
.GetCode() == KEY_RIGHT
)
420 if (pView
->AreObjectsMarked() && !aCode
.IsMod1() )
424 // move in 1 pixel distance
425 Size aLogicSizeOnePixel
= PixelToLogic(Size(1,1));
426 nX
*= aLogicSizeOnePixel
.Width();
427 nY
*= aLogicSizeOnePixel
.Height();
431 // old, fixed move distance
437 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
438 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
442 // restrict movement to WorkArea
443 const Rectangle
& rWorkArea
= pView
->GetWorkArea();
445 if(!rWorkArea
.IsEmpty())
447 Rectangle
aMarkRect(pView
->GetMarkedObjRect());
448 aMarkRect
.Move(nX
, nY
);
450 if(!aMarkRect
.IsInside(rWorkArea
))
452 if(aMarkRect
.Left() < rWorkArea
.Left())
454 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
457 if(aMarkRect
.Right() > rWorkArea
.Right())
459 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
462 if(aMarkRect
.Top() < rWorkArea
.Top())
464 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
467 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
469 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
474 // no handle selected
475 if(0 != nX
|| 0 != nY
)
477 pView
->MoveAllMarked(Size(nX
, nY
));
482 // move handle with index nHandleIndex
483 if(pHdl
&& (nX
|| nY
))
485 // now move the Handle (nX, nY)
486 Point
aStartPoint(pHdl
->GetPos());
487 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
488 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
491 pView
->BegDragObj(aStartPoint
, 0, pHdl
, 0);
493 if(pView
->IsDragObj())
495 bool bWasNoSnap
= rDragStat
.IsNoSnap();
496 sal_Bool bWasSnapEnabled
= pView
->IsSnapEnabled();
498 // switch snapping off
500 ((SdrDragStat
&)rDragStat
).SetNoSnap(sal_True
);
502 pView
->SetSnapEnabled(sal_False
);
504 pView
->MovAction(aEndPoint
);
509 ((SdrDragStat
&)rDragStat
).SetNoSnap(bWasNoSnap
);
511 pView
->SetSnapEnabled(bWasSnapEnabled
);
523 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
524 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
528 if(pHdl
->GetKind() == HDL_POLY
)
530 // rescue ID of point with focus
531 sal_uInt32
nPol(pHdl
->GetPolyNum());
532 sal_uInt32
nPnt(pHdl
->GetPointNum());
534 if(pView
->IsPointMarked(*pHdl
))
536 if(rKEvt
.GetKeyCode().IsShift())
538 pView
->UnmarkPoint(*pHdl
);
543 if(!rKEvt
.GetKeyCode().IsShift())
545 pView
->UnmarkAllPoints();
548 pView
->MarkPoint(*pHdl
);
551 if(0L == rHdlList
.GetFocusHdl())
553 // restore point with focus
554 SdrHdl
* pNewOne
= 0L;
556 for(sal_uInt32
a(0); !pNewOne
&& a
< rHdlList
.GetHdlCount(); a
++)
558 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
561 && pAct
->GetKind() == HDL_POLY
562 && pAct
->GetPolyNum() == nPol
563 && pAct
->GetPointNum() == nPnt
)
571 ((SdrHdlList
&)rHdlList
).SetFocusHdl(pNewOne
);
586 Control::KeyInput( rKEvt
);
591 void GraphCtrl::MouseButtonDown( const MouseEvent
& rMEvt
)
593 if ( bSdrMode
&& ( rMEvt
.GetClicks() < 2 ) )
595 const Point
aLogPt( PixelToLogic( rMEvt
.GetPosPixel() ) );
597 if ( !Rectangle( Point(), aGraphSize
).IsInside( aLogPt
) && !pView
->IsEditMode() )
598 Control::MouseButtonDown( rMEvt
);
601 // Get Focus for key inputs
607 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SDRMOUSEBUTTONDOWN
, aVEvt
);
609 if ( nPolyEdit
== SID_BEZIER_INSERT
&& eHit
== SDRHIT_MARKEDOBJECT
)
610 pView
->BegInsObjPoint( aLogPt
, rMEvt
.IsMod1());
612 pView
->MouseButtonDown( rMEvt
, this );
615 pView
->MouseButtonDown( rMEvt
, this );
618 SdrObject
* pCreateObj
= pView
->GetCreateObj();
620 // We want to realize the insert
621 if ( pCreateObj
&& !pCreateObj
->GetUserCall() )
622 pCreateObj
->SetUserCall( pUserCall
);
624 SetPointer( pView
->GetPreferedPointer( aLogPt
, this ) );
627 Control::MouseButtonDown( rMEvt
);
630 void GraphCtrl::MouseMove(const MouseEvent
& rMEvt
)
632 const Point
aLogPos( PixelToLogic( rMEvt
.GetPosPixel() ) );
636 pView
->MouseMove( rMEvt
, this );
638 if( ( SID_BEZIER_INSERT
== nPolyEdit
) &&
639 !pView
->PickHandle( aLogPos
) &&
640 !pView
->IsInsObjPoint() )
642 SetPointer( POINTER_CROSS
);
645 SetPointer( pView
->GetPreferedPointer( aLogPos
, this ) );
648 Control::MouseButtonUp( rMEvt
);
650 if ( aMousePosLink
.IsSet() )
652 if ( Rectangle( Point(), aGraphSize
).IsInside( aLogPos
) )
657 aMousePosLink
.Call( this );
661 void GraphCtrl::MouseButtonUp(const MouseEvent
& rMEvt
)
665 if ( pView
->IsInsObjPoint() )
666 pView
->EndInsObjPoint( SDRCREATE_FORCEEND
);
668 pView
->MouseButtonUp( rMEvt
, this );
671 SetPointer( pView
->GetPreferedPointer( PixelToLogic( rMEvt
.GetPosPixel() ), this ) );
674 Control::MouseButtonUp( rMEvt
);
677 SdrObject
* GraphCtrl::GetSelectedSdrObject() const
679 SdrObject
* pSdrObj
= NULL
;
683 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
685 if ( rMarkList
.GetMarkCount() == 1 )
686 pSdrObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
692 void GraphCtrl::SetEditMode( const sal_Bool _bEditMode
)
696 bEditMode
= _bEditMode
;
697 pView
->SetEditMode( bEditMode
);
699 pView
->SetCurrentObj( sal::static_int_cast
< sal_uInt16
>( eObjKind
) );
702 bEditMode
= sal_False
;
705 void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit
)
707 if ( bSdrMode
&& ( _nPolyEdit
!= nPolyEdit
) )
709 nPolyEdit
= _nPolyEdit
;
710 pView
->SetFrameDragSingles( nPolyEdit
== 0 );
716 void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind
)
720 bEditMode
= sal_False
;
721 pView
->SetEditMode( bEditMode
);
722 eObjKind
= _eObjKind
;
723 pView
->SetCurrentObj( sal::static_int_cast
< sal_uInt16
>( eObjKind
) );
729 IMPL_LINK( GraphCtrl
, UpdateHdl
, Timer
*, pTimer
)
731 if ( aUpdateLink
.IsSet() )
732 aUpdateLink
.Call( this );
740 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> GraphCtrl::CreateAccessible()
742 if( mpAccContext
== NULL
)
744 Window
* pParent
= GetParent();
746 DBG_ASSERT( pParent
, "-GraphCtrl::CreateAccessible(): No Parent!" );
750 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> xAccParent( pParent
->GetAccessible() );
752 // Disable accessibility if no model/view data available
757 mpAccContext
= new SvxGraphCtrlAccessibleContext( xAccParent
, *this );
758 mpAccContext
->acquire();
766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */