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 <editeng/editeng.hxx>
21 #include <editeng/outlobj.hxx>
22 #include <svx/svdobj.hxx>
23 #include <svx/svdoole2.hxx>
24 #include <svx/svdouno.hxx>
25 #include <svx/svdocapt.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svditer.hxx>
28 #include <svx/svdundo.hxx>
29 #include <sfx2/dispatch.hxx>
30 #include <sfx2/viewfrm.hxx>
35 #include "tabvwsh.hxx"
36 #include "drwlayer.hxx"
37 #include "scresid.hxx"
38 #include "userdat.hxx"
41 #include "globstr.hrc"
42 #include "drawview.hxx"
44 /*************************************************************************
46 |* base class for draw module specific functions
48 \************************************************************************/
50 FuDraw::FuDraw(ScTabViewShell
* pViewSh
, vcl::Window
* pWin
, ScDrawView
* pViewP
,
51 SdrModel
* pDoc
, SfxRequest
& rReq
) :
52 FuPoor (pViewSh
, pWin
, pViewP
, pDoc
, rReq
),
53 aNewPointer ( PointerStyle::Arrow
),
54 aOldPointer ( PointerStyle::Arrow
)
58 /*************************************************************************
62 \************************************************************************/
68 /*************************************************************************
70 |* evaluate modifier keys
72 \************************************************************************/
74 void FuDraw::DoModifiers(const MouseEvent
& rMEvt
)
76 // Shift = Ortho and AngleSnap
77 // Control = Snap (Toggle)
80 bool bShift
= rMEvt
.IsShift();
81 bool bAlt
= rMEvt
.IsMod2();
84 bool bAngleSnap
= bShift
;
88 if(doConstructOrthogonal())
93 if (pView
->IsOrtho() != bOrtho
)
94 pView
->SetOrtho(bOrtho
);
95 if (pView
->IsAngleSnapEnabled() != bAngleSnap
)
96 pView
->SetAngleSnapEnabled(bAngleSnap
);
98 if (pView
->IsCreate1stPointAsCenter() != bCenter
)
99 pView
->SetCreate1stPointAsCenter(bCenter
);
100 if (pView
->IsResizeAtCenter() != bCenter
)
101 pView
->SetResizeAtCenter(bCenter
);
105 void FuDraw::ResetModifiers()
110 ScViewData
& rViewData
= pViewShell
->GetViewData();
111 const ScViewOptions
& rOpt
= rViewData
.GetOptions();
112 const ScGridOptions
& rGrid
= rOpt
.GetGridOptions();
113 bool bGridOpt
= rGrid
.GetUseGridSnap();
115 if (pView
->IsOrtho())
116 pView
->SetOrtho(false);
117 if (pView
->IsAngleSnapEnabled())
118 pView
->SetAngleSnapEnabled(false);
120 if (pView
->IsGridSnap() != bGridOpt
)
121 pView
->SetGridSnap(bGridOpt
);
122 if (pView
->IsSnapEnabled() != bGridOpt
)
123 pView
->SetSnapEnabled(bGridOpt
);
125 if (pView
->IsCreate1stPointAsCenter())
126 pView
->SetCreate1stPointAsCenter(false);
127 if (pView
->IsResizeAtCenter())
128 pView
->SetResizeAtCenter(false);
131 /*************************************************************************
133 |* MouseButtonDown-event
135 \************************************************************************/
137 bool FuDraw::MouseButtonDown(const MouseEvent
& rMEvt
)
139 // remember button state for creation of own MouseEvents
140 SetMouseButtonCode(rMEvt
.GetButtons());
142 DoModifiers( rMEvt
);
146 /*************************************************************************
150 \************************************************************************/
152 bool FuDraw::MouseMove(const MouseEvent
& rMEvt
)
154 // evaluate modifiers only if in a drawing layer action
155 // (don't interfere with keyboard shortcut handling)
156 if (pView
->IsAction())
157 DoModifiers( rMEvt
);
162 /*************************************************************************
164 |* MouseButtonUp-event
166 \************************************************************************/
168 bool FuDraw::MouseButtonUp(const MouseEvent
& rMEvt
)
170 // remember button state for creation of own MouseEvents
171 SetMouseButtonCode(rMEvt
.GetButtons());
177 /*************************************************************************
179 |* process keyboard events
181 |* if a keyevent is processed -> returns sal_True
184 \************************************************************************/
186 static bool lcl_KeyEditMode( SdrObject
* pObj
, ScTabViewShell
* pViewShell
, const KeyEvent
* pInitialKey
)
188 bool bReturn
= false;
189 if ( pObj
&& pObj
->ISA(SdrTextObj
) && !pObj
->ISA(SdrUnoObj
) )
191 // start text edit - like FuSelection::MouseButtonUp,
192 // but with bCursorToEnd instead of mouse position
194 OutlinerParaObject
* pOPO
= pObj
->GetOutlinerParaObject();
195 bool bVertical
= ( pOPO
&& pOPO
->IsVertical() );
196 sal_uInt16 nTextSlotId
= bVertical
? SID_DRAW_TEXT_VERTICAL
: SID_DRAW_TEXT
;
198 // don't switch shells if text shell is already active
199 FuPoor
* pPoor
= pViewShell
->GetViewData().GetView()->GetDrawFuncPtr();
200 if ( !pPoor
|| pPoor
->GetSlotID() != nTextSlotId
)
202 pViewShell
->GetViewData().GetDispatcher().
203 Execute(nTextSlotId
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
206 // get the resulting FuText and set in edit mode
207 pPoor
= pViewShell
->GetViewData().GetView()->GetDrawFuncPtr();
208 if ( pPoor
&& pPoor
->GetSlotID() == nTextSlotId
) // no RTTI
210 FuText
* pText
= static_cast<FuText
*>(pPoor
);
211 pText
->SetInEditMode( pObj
, NULL
, true, pInitialKey
);
212 //! set cursor to end of text
219 bool FuDraw::KeyInput(const KeyEvent
& rKEvt
)
221 bool bReturn
= false;
222 ScViewData
& rViewData
= pViewShell
->GetViewData();
224 switch ( rKEvt
.GetKeyCode().GetCode() )
227 if ( pViewShell
->IsDrawTextShell() || aSfxRequest
.GetSlot() == SID_DRAW_NOTEEDIT
)
229 // if object selected -> normal draw-shell, else turn off drawing
230 rViewData
.GetDispatcher().Execute(aSfxRequest
.GetSlot(), SfxCallMode::SLOT
| SfxCallMode::RECORD
);
233 else if ( pViewShell
->IsDrawSelMode() )
236 rViewData
.GetDispatcher().Execute(SID_OBJECT_SELECT
, SfxCallMode::SLOT
| SfxCallMode::RECORD
);
239 else if ( pView
->AreObjectsMarked() )
242 SdrHdlList
& rHdlList
= const_cast< SdrHdlList
& >( pView
->GetHdlList() );
243 if( rHdlList
.GetFocusHdl() )
244 rHdlList
.ResetFocusHdl();
248 // while bezier editing, object is selected
249 if (!pView
->AreObjectsMarked())
250 pViewShell
->SetDrawShell( false );
256 case KEY_DELETE
: //! via accelerator
257 pView
->DeleteMarked();
263 if( rKEvt
.GetKeyCode().GetModifier() == 0 )
265 // activate OLE object on RETURN for selected object
266 // put selected text object in edit mode
267 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
268 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() )
270 bool bOle
= pViewShell
->GetViewFrame()->GetFrame().IsInPlace();
271 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
272 if( pObj
&& pObj
->ISA( SdrOle2Obj
) && !bOle
)
274 pViewShell
->ActivateObject( static_cast< SdrOle2Obj
* >( pObj
), 0 );
279 else if ( lcl_KeyEditMode( pObj
, pViewShell
, NULL
) ) // start text edit for suitable object
288 if( rKEvt
.GetKeyCode().GetModifier() == 0 )
290 // put selected text object in edit mode
291 // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer)
292 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
293 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() )
295 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
296 if ( lcl_KeyEditMode( pObj
, pViewShell
, NULL
) ) // start text edit for suitable object
306 // in calc do NOT start draw object selection using TAB/SHIFT-TAB when
307 // there is not yet a object selected
308 if(pView
->AreObjectsMarked())
310 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
312 if ( !aCode
.IsMod1() && !aCode
.IsMod2() )
314 // changeover to the next object
315 if(!pView
->MarkNextObj( !aCode
.IsShift() ))
317 //If there is only one object, don't do the UnmarkAlllObj() & MarkNextObj().
318 if ( pView
->GetMarkableObjCount() > 1 && pView
->HasMarkableObj() )
320 // No next object: go over open end and
321 // get first from the other side
322 pView
->UnmarkAllObj();
323 pView
->MarkNextObj(!aCode
.IsShift());
328 if(pView
->AreObjectsMarked())
329 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
334 // handle Mod1 and Mod2 to get travelling running on different systems
335 if(rKEvt
.GetKeyCode().IsMod1() || rKEvt
.GetKeyCode().IsMod2())
337 // II do something with a selected handle?
338 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
339 bool bForward(!rKEvt
.GetKeyCode().IsShift());
341 ((SdrHdlList
&)rHdlList
).TravelFocusHdl(bForward
);
343 // guarantee visibility of focused handle
344 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
348 Point
aHdlPosition(pHdl
->GetPos());
349 Rectangle
aVisRect(aHdlPosition
- Point(100, 100), Size(200, 200));
350 pView
->MakeVisible(aVisRect
, *pWindow
);
363 // in calc do NOT select the last draw object when
364 // there is not yet a object selected
365 if(pView
->AreObjectsMarked())
367 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
369 if ( aCode
.IsMod1() )
372 pView
->UnmarkAllObj();
373 pView
->MarkNextObj(false);
376 if(pView
->AreObjectsMarked())
377 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
388 // in calc do NOT select the first draw object when
389 // there is not yet a object selected
390 if(pView
->AreObjectsMarked())
392 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
394 if ( aCode
.IsMod1() )
397 pView
->UnmarkAllObj();
398 pView
->MarkNextObj(true);
401 if(pView
->AreObjectsMarked())
402 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
416 // in calc do cursor travelling of draw objects only when
417 // there is a object selected yet
418 if(pView
->AreObjectsMarked())
421 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
422 if(rMarkList
.GetMarkCount() == 1)
424 // disable cursor travelling on note objects as the tail connector position
426 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
427 if( ScDrawLayer::IsNoteCaption( pObj
) )
433 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
441 else if (nCode
== KEY_DOWN
)
447 else if (nCode
== KEY_LEFT
)
453 else if (nCode
== KEY_RIGHT
)
460 bool bReadOnly
= rViewData
.GetDocShell()->IsReadOnly();
462 if(!rKEvt
.GetKeyCode().IsMod1() && !bReadOnly
)
464 if(rKEvt
.GetKeyCode().IsMod2())
466 // move in 1 pixel distance
467 Size aLogicSizeOnePixel
= (pWindow
) ? pWindow
->PixelToLogic(Size(1,1)) : Size(100, 100);
468 nX
*= aLogicSizeOnePixel
.Width();
469 nY
*= aLogicSizeOnePixel
.Height();
471 else if(rKEvt
.GetKeyCode().IsShift()) // #i121236# Support for shift key in calc
478 // old, fixed move distance
483 // is there a movement to do?
484 if(0 != nX
|| 0 != nY
)
487 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
488 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
492 // only take action when move is allowed
493 if(pView
->IsMoveAllowed())
495 // restrict movement to WorkArea
496 const Rectangle
& rWorkArea
= pView
->GetWorkArea();
498 if(!rWorkArea
.IsEmpty())
500 Rectangle
aMarkRect(pView
->GetMarkedObjRect());
501 aMarkRect
.Move(nX
, nY
);
503 if(!aMarkRect
.IsInside(rWorkArea
))
505 if(aMarkRect
.Left() < rWorkArea
.Left())
507 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
510 if(aMarkRect
.Right() > rWorkArea
.Right())
512 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
515 if(aMarkRect
.Top() < rWorkArea
.Top())
517 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
520 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
522 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
527 // now move the selected draw objects
528 pView
->MoveAllMarked(Size(nX
, nY
));
531 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
538 // move handle with index nHandleIndex
539 if(pHdl
&& (nX
|| nY
))
541 // now move the Handle (nX, nY)
542 Point
aStartPoint(pHdl
->GetPos());
543 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
544 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
547 pView
->BegDragObj(aStartPoint
, 0, pHdl
, 0);
549 if(pView
->IsDragObj())
551 bool bWasNoSnap
= rDragStat
.IsNoSnap();
552 bool bWasSnapEnabled
= pView
->IsSnapEnabled();
554 // switch snapping off
556 ((SdrDragStat
&)rDragStat
).SetNoSnap(true);
558 pView
->SetSnapEnabled(false);
560 pView
->MovAction(aEndPoint
);
565 ((SdrDragStat
&)rDragStat
).SetNoSnap(bWasNoSnap
);
567 pView
->SetSnapEnabled(bWasSnapEnabled
);
570 // make moved handle visible
571 Rectangle
aVisRect(aEndPoint
- Point(100, 100), Size(200, 200));
572 pView
->MakeVisible(aVisRect
, *pWindow
);
586 // in calc do only something when draw objects are selected
587 if(pView
->AreObjectsMarked())
589 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
590 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
594 if(pHdl
->GetKind() == HDL_POLY
)
596 // rescue ID of point with focus
597 sal_uInt32
nPol(pHdl
->GetPolyNum());
598 sal_uInt32
nPnt(pHdl
->GetPointNum());
600 if(pView
->IsPointMarked(*pHdl
))
602 if(rKEvt
.GetKeyCode().IsShift())
604 pView
->UnmarkPoint(*pHdl
);
609 if(!rKEvt
.GetKeyCode().IsShift())
611 pView
->UnmarkAllPoints();
614 pView
->MarkPoint(*pHdl
);
617 if(0L == rHdlList
.GetFocusHdl())
619 // restore point with focus
620 SdrHdl
* pNewOne
= 0L;
622 for(size_t a
= 0; !pNewOne
&& a
< rHdlList
.GetHdlCount(); ++a
)
624 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
627 && pAct
->GetKind() == HDL_POLY
628 && pAct
->GetPolyNum() == nPol
629 && pAct
->GetPointNum() == nPnt
)
637 ((SdrHdlList
&)rHdlList
).SetFocusHdl(pNewOne
);
651 bReturn
= FuPoor::KeyInput(rKEvt
);
656 // allow direct typing into a selected text object
658 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
659 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt
) )
661 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
663 // start text edit for suitable object, pass key event to OutlinerView
664 if ( lcl_KeyEditMode( pObj
, pViewShell
, &rKEvt
) )
673 void FuDraw::SelectionHasChanged()
675 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
676 ((SdrHdlList
&)rHdlList
).ResetFocusHdl();
679 /*************************************************************************
683 \************************************************************************/
685 void FuDraw::Activate()
690 /*************************************************************************
694 \************************************************************************/
696 void FuDraw::Deactivate()
698 FuPoor::Deactivate();
701 /*************************************************************************
703 |* toggle mouse-pointer
705 \************************************************************************/
707 static bool lcl_UrlHit( SdrView
* pView
, const Point
& rPosPixel
, vcl::Window
* pWindow
)
710 MouseEvent
aMEvt( rPosPixel
, 1, MouseEventModifiers::NONE
, MOUSE_LEFT
);
711 SdrHitKind eHit
= pView
->PickAnything( aMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
713 if ( eHit
!= SDRHIT_NONE
&& aVEvt
.pObj
!= NULL
)
715 if ( ScDrawLayer::GetIMapInfo( aVEvt
.pObj
) && ScDrawLayer::GetHitIMapObject(
716 aVEvt
.pObj
, pWindow
->PixelToLogic(rPosPixel
), *pWindow
) )
719 if ( aVEvt
.eEvent
== SDREVENT_EXECUTEURL
)
726 void FuDraw::ForcePointer(const MouseEvent
* pMEvt
)
728 if ( !pView
->IsAction() )
730 Point aPosPixel
= pWindow
->GetPointerPosPixel();
731 bool bAlt
= pMEvt
&& pMEvt
->IsMod2();
732 Point aPnt
= pWindow
->PixelToLogic( aPosPixel
);
733 SdrHdl
* pHdl
= pView
->PickHandle(aPnt
);
737 ScMacroInfo
* pInfo
= 0;
738 if ( pView
->PickObj(aPnt
, pView
->getHitTolLog(), pObj
, pPV
, SdrSearchOptions::ALSOONMASTER
) )
740 if ( pObj
->IsGroupObject() )
743 if ( pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pHit
, pPV
, SdrSearchOptions::DEEP
) )
746 pInfo
= ScDrawLayer::GetMacroInfo( pObj
);
749 if ( pView
->IsTextEdit() )
751 pViewShell
->SetActivePointer(Pointer(PointerStyle::Text
)); // can't be ?
755 pViewShell
->SetActivePointer(
756 pView
->GetPreferredPointer( aPnt
, pWindow
) );
758 else if ( pView
->IsMarkedHit(aPnt
) )
760 pViewShell
->SetActivePointer( Pointer(PointerStyle::Move
) );
762 else if ( !bAlt
&& ( !pMEvt
|| !pMEvt
->GetButtons() )
763 && lcl_UrlHit( pView
, aPosPixel
, pWindow
) )
765 // could be suppressed with ALT
766 pWindow
->SetPointer( Pointer( PointerStyle::RefHand
) ); // Text-URL / ImageMap
768 else if ( !bAlt
&& pView
->PickObj(aPnt
, pView
->getHitTolLog(), pObj
, pPV
, SdrSearchOptions::PICKMACRO
) )
770 // could be suppressed with ALT
771 SdrObjMacroHitRec aHitRec
; //! something missing ????
772 pViewShell
->SetActivePointer( pObj
->GetMacroPointer(aHitRec
) );
774 else if ( !bAlt
&& pInfo
&& (!pInfo
->GetMacro().isEmpty() || !pInfo
->GetHlink().isEmpty()) )
775 pWindow
->SetPointer( Pointer( PointerStyle::RefHand
) );
776 else if ( IsDetectiveHit( aPnt
) )
777 pViewShell
->SetActivePointer( Pointer( PointerStyle::Detective
) );
779 pViewShell
->SetActivePointer( aNewPointer
); //! in Gridwin?
783 bool FuDraw::IsEditingANote() const
785 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
786 const size_t backval
=rMarkList
.GetMarkCount();
787 for (size_t nlv1
=0; nlv1
<backval
; ++nlv1
)
789 SdrObject
* pObj
= rMarkList
.GetMark( nlv1
)->GetMarkedSdrObj();
790 if ( ScDrawLayer::IsNoteCaption( pObj
) )
798 bool FuDraw::IsSizingOrMovingNote( const MouseEvent
& rMEvt
) const
800 bool bIsSizingOrMoving
= false;
801 if ( rMEvt
.IsLeft() )
803 const SdrMarkList
& rNoteMarkList
= pView
->GetMarkedObjectList();
804 if(rNoteMarkList
.GetMarkCount() == 1)
806 SdrObject
* pObj
= rNoteMarkList
.GetMark( 0 )->GetMarkedSdrObj();
807 if ( ScDrawLayer::IsNoteCaption( pObj
) )
809 Point aMPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
811 pView
->PickHandle( aMPos
) || // handles to resize the note
812 pView
->IsTextEditFrameHit( aMPos
); // frame for moving the note
816 return bIsSizingOrMoving
;
819 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */