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 |* Basisklasse fuer alle Drawmodul-spezifischen Funktionen
48 \************************************************************************/
50 FuDraw::FuDraw(ScTabViewShell
* pViewSh
, Window
* pWin
, ScDrawView
* pViewP
,
51 SdrModel
* pDoc
, SfxRequest
& rReq
) :
52 FuPoor (pViewSh
, pWin
, pViewP
, pDoc
, rReq
),
53 aNewPointer ( POINTER_ARROW
),
54 aOldPointer ( POINTER_ARROW
)
58 /*************************************************************************
62 \************************************************************************/
68 /*************************************************************************
70 |* Modifier-Tasten auswerten
72 \************************************************************************/
74 void FuDraw::DoModifiers(const MouseEvent
& rMEvt
)
76 // Shift = Ortho und AngleSnap
77 // Control = Snap (Toggle)
80 sal_Bool bShift
= rMEvt
.IsShift();
81 sal_Bool bAlt
= rMEvt
.IsMod2();
84 sal_Bool bAngleSnap
= bShift
;
85 sal_Bool bCenter
= bAlt
;
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()
107 ScViewData
* pViewData
= pViewShell
->GetViewData();
108 const ScViewOptions
& rOpt
= pViewData
->GetOptions();
109 const ScGridOptions
& rGrid
= rOpt
.GetGridOptions();
110 sal_Bool bGridOpt
= rGrid
.GetUseGridSnap();
112 if (pView
->IsOrtho())
113 pView
->SetOrtho(false);
114 if (pView
->IsAngleSnapEnabled())
115 pView
->SetAngleSnapEnabled(false);
117 if (pView
->IsGridSnap() != bGridOpt
)
118 pView
->SetGridSnap(bGridOpt
);
119 if (pView
->IsSnapEnabled() != bGridOpt
)
120 pView
->SetSnapEnabled(bGridOpt
);
122 if (pView
->IsCreate1stPointAsCenter())
123 pView
->SetCreate1stPointAsCenter(false);
124 if (pView
->IsResizeAtCenter())
125 pView
->SetResizeAtCenter(false);
128 /*************************************************************************
130 |* MouseButtonDown-event
132 \************************************************************************/
134 sal_Bool
FuDraw::MouseButtonDown(const MouseEvent
& rMEvt
)
136 // remember button state for creation of own MouseEvents
137 SetMouseButtonCode(rMEvt
.GetButtons());
139 DoModifiers( rMEvt
);
143 /*************************************************************************
147 \************************************************************************/
149 sal_Bool
FuDraw::MouseMove(const MouseEvent
& rMEvt
)
151 // evaluate modifiers only if in a drawing layer action
152 // (don't interfere with keyboard shortcut handling)
153 if (pView
->IsAction())
154 DoModifiers( rMEvt
);
159 /*************************************************************************
161 |* MouseButtonUp-event
163 \************************************************************************/
165 sal_Bool
FuDraw::MouseButtonUp(const MouseEvent
& rMEvt
)
167 // remember button state for creation of own MouseEvents
168 SetMouseButtonCode(rMEvt
.GetButtons());
174 /*************************************************************************
176 |* Tastaturereignisse bearbeiten
178 |* Wird ein KeyEvent bearbeitet, so ist der Return-Wert sal_True, andernfalls
181 \************************************************************************/
183 static sal_Bool
lcl_KeyEditMode( SdrObject
* pObj
, ScTabViewShell
* pViewShell
, const KeyEvent
* pInitialKey
)
185 sal_Bool bReturn
= false;
186 if ( pObj
&& pObj
->ISA(SdrTextObj
) && !pObj
->ISA(SdrUnoObj
) )
188 // start text edit - like FuSelection::MouseButtonUp,
189 // but with bCursorToEnd instead of mouse position
191 OutlinerParaObject
* pOPO
= pObj
->GetOutlinerParaObject();
192 sal_Bool bVertical
= ( pOPO
&& pOPO
->IsVertical() );
193 sal_uInt16 nTextSlotId
= bVertical
? SID_DRAW_TEXT_VERTICAL
: SID_DRAW_TEXT
;
195 // don't switch shells if text shell is already active
196 FuPoor
* pPoor
= pViewShell
->GetViewData()->GetView()->GetDrawFuncPtr();
197 if ( !pPoor
|| pPoor
->GetSlotID() != nTextSlotId
)
199 pViewShell
->GetViewData()->GetDispatcher().
200 Execute(nTextSlotId
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
203 // get the resulting FuText and set in edit mode
204 pPoor
= pViewShell
->GetViewData()->GetView()->GetDrawFuncPtr();
205 if ( pPoor
&& pPoor
->GetSlotID() == nTextSlotId
) // no RTTI
207 FuText
* pText
= (FuText
*)pPoor
;
208 pText
->SetInEditMode( pObj
, NULL
, sal_True
, pInitialKey
);
209 //! set cursor to end of text
216 sal_Bool
FuDraw::KeyInput(const KeyEvent
& rKEvt
)
218 sal_Bool bReturn
= false;
219 ScViewData
& rViewData
= *pViewShell
->GetViewData();
221 switch ( rKEvt
.GetKeyCode().GetCode() )
224 if ( pViewShell
->IsDrawTextShell() || aSfxRequest
.GetSlot() == SID_DRAW_NOTEEDIT
)
226 // in normale Draw-Shell, wenn Objekt selektiert, sonst Zeichnen aus
227 rViewData
.GetDispatcher().Execute(aSfxRequest
.GetSlot(), SFX_CALLMODE_SLOT
| SFX_CALLMODE_RECORD
);
230 else if ( pViewShell
->IsDrawSelMode() )
233 rViewData
.GetDispatcher().Execute(SID_OBJECT_SELECT
, SFX_CALLMODE_SLOT
| SFX_CALLMODE_RECORD
);
236 else if ( pView
->AreObjectsMarked() )
239 SdrHdlList
& rHdlList
= const_cast< SdrHdlList
& >( pView
->GetHdlList() );
240 if( rHdlList
.GetFocusHdl() )
241 rHdlList
.ResetFocusHdl();
245 // Beim Bezier-Editieren ist jetzt wieder das Objekt selektiert
246 if (!pView
->AreObjectsMarked())
247 pViewShell
->SetDrawShell( false );
253 case KEY_DELETE
: //! ueber Accelerator
254 pView
->DeleteMarked();
260 if( rKEvt
.GetKeyCode().GetModifier() == 0 )
262 // activate OLE object on RETURN for selected object
263 // put selected text object in edit mode
264 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
265 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() )
267 sal_Bool bOle
= pViewShell
->GetViewFrame()->GetFrame().IsInPlace();
268 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
269 if( pObj
&& pObj
->ISA( SdrOle2Obj
) && !bOle
)
271 pViewShell
->ActivateObject( static_cast< SdrOle2Obj
* >( pObj
), 0 );
276 else if ( lcl_KeyEditMode( pObj
, pViewShell
, NULL
) ) // start text edit for suitable object
285 if( rKEvt
.GetKeyCode().GetModifier() == 0 )
287 // put selected text object in edit mode
288 // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer)
289 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
290 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() )
292 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
293 if ( lcl_KeyEditMode( pObj
, pViewShell
, NULL
) ) // start text edit for suitable object
303 // in calc do NOT start draw object selection using TAB/SHIFT-TAB when
304 // there is not yet a object selected
305 if(pView
->AreObjectsMarked())
307 KeyCode aCode
= rKEvt
.GetKeyCode();
309 if ( !aCode
.IsMod1() && !aCode
.IsMod2() )
311 // changeover to the next object
312 if(!pView
->MarkNextObj( !aCode
.IsShift() ))
314 // No next object: go over open end and
315 // get first from the other side
316 pView
->UnmarkAllObj();
317 pView
->MarkNextObj(!aCode
.IsShift());
321 if(pView
->AreObjectsMarked())
322 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
327 // handle Mod1 and Mod2 to get travelling running on different systems
328 if(rKEvt
.GetKeyCode().IsMod1() || rKEvt
.GetKeyCode().IsMod2())
330 // II do something with a selected handle?
331 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
332 sal_Bool
bForward(!rKEvt
.GetKeyCode().IsShift());
334 ((SdrHdlList
&)rHdlList
).TravelFocusHdl(bForward
);
336 // guarantee visibility of focused handle
337 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
341 Point
aHdlPosition(pHdl
->GetPos());
342 Rectangle
aVisRect(aHdlPosition
- Point(100, 100), Size(200, 200));
343 pView
->MakeVisible(aVisRect
, *pWindow
);
356 // in calc do NOT select the last draw object when
357 // there is not yet a object selected
358 if(pView
->AreObjectsMarked())
360 KeyCode aCode
= rKEvt
.GetKeyCode();
362 if ( aCode
.IsMod1() )
365 pView
->UnmarkAllObj();
366 pView
->MarkNextObj(false);
369 if(pView
->AreObjectsMarked())
370 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
381 // in calc do NOT select the first draw object when
382 // there is not yet a object selected
383 if(pView
->AreObjectsMarked())
385 KeyCode aCode
= rKEvt
.GetKeyCode();
387 if ( aCode
.IsMod1() )
390 pView
->UnmarkAllObj();
391 pView
->MarkNextObj(sal_True
);
394 if(pView
->AreObjectsMarked())
395 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
409 // in calc do cursor travelling of draw objects only when
410 // there is a object selected yet
411 if(pView
->AreObjectsMarked())
414 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
415 if(rMarkList
.GetMarkCount() == 1)
417 // disable cursor travelling on note objects as the tail connector position
419 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
420 if( ScDrawLayer::IsNoteCaption( pObj
) )
426 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
434 else if (nCode
== KEY_DOWN
)
440 else if (nCode
== KEY_LEFT
)
446 else if (nCode
== KEY_RIGHT
)
448 // Scroll nach rechts
453 sal_Bool bReadOnly
= rViewData
.GetDocShell()->IsReadOnly();
455 if(!rKEvt
.GetKeyCode().IsMod1() && !bReadOnly
)
457 if(rKEvt
.GetKeyCode().IsMod2())
459 // move in 1 pixel distance
460 Size aLogicSizeOnePixel
= (pWindow
) ? pWindow
->PixelToLogic(Size(1,1)) : Size(100, 100);
461 nX
*= aLogicSizeOnePixel
.Width();
462 nY
*= aLogicSizeOnePixel
.Height();
464 else if(rKEvt
.GetKeyCode().IsShift()) // #i121236# Support for shift key in calc
471 // old, fixed move distance
476 // is there a movement to do?
477 if(0 != nX
|| 0 != nY
)
480 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
481 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
485 // only take action when move is allowed
486 if(pView
->IsMoveAllowed())
488 // restrict movement to WorkArea
489 const Rectangle
& rWorkArea
= pView
->GetWorkArea();
491 if(!rWorkArea
.IsEmpty())
493 Rectangle
aMarkRect(pView
->GetMarkedObjRect());
494 aMarkRect
.Move(nX
, nY
);
496 if(!aMarkRect
.IsInside(rWorkArea
))
498 if(aMarkRect
.Left() < rWorkArea
.Left())
500 nX
+= rWorkArea
.Left() - aMarkRect
.Left();
503 if(aMarkRect
.Right() > rWorkArea
.Right())
505 nX
-= aMarkRect
.Right() - rWorkArea
.Right();
508 if(aMarkRect
.Top() < rWorkArea
.Top())
510 nY
+= rWorkArea
.Top() - aMarkRect
.Top();
513 if(aMarkRect
.Bottom() > rWorkArea
.Bottom())
515 nY
-= aMarkRect
.Bottom() - rWorkArea
.Bottom();
520 // now move the selected draw objects
521 pView
->MoveAllMarked(Size(nX
, nY
));
524 pView
->MakeVisible(pView
->GetAllMarkedRect(), *pWindow
);
531 // move handle with index nHandleIndex
532 if(pHdl
&& (nX
|| nY
))
534 // now move the Handle (nX, nY)
535 Point
aStartPoint(pHdl
->GetPos());
536 Point
aEndPoint(pHdl
->GetPos() + Point(nX
, nY
));
537 const SdrDragStat
& rDragStat
= pView
->GetDragStat();
540 pView
->BegDragObj(aStartPoint
, 0, pHdl
, 0);
542 if(pView
->IsDragObj())
544 bool bWasNoSnap
= rDragStat
.IsNoSnap();
545 sal_Bool bWasSnapEnabled
= pView
->IsSnapEnabled();
547 // switch snapping off
549 ((SdrDragStat
&)rDragStat
).SetNoSnap(sal_True
);
551 pView
->SetSnapEnabled(false);
553 pView
->MovAction(aEndPoint
);
558 ((SdrDragStat
&)rDragStat
).SetNoSnap(bWasNoSnap
);
560 pView
->SetSnapEnabled(bWasSnapEnabled
);
563 // make moved handle visible
564 Rectangle
aVisRect(aEndPoint
- Point(100, 100), Size(200, 200));
565 pView
->MakeVisible(aVisRect
, *pWindow
);
579 // in calc do only something when draw objects are selected
580 if(pView
->AreObjectsMarked())
582 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
583 SdrHdl
* pHdl
= rHdlList
.GetFocusHdl();
587 if(pHdl
->GetKind() == HDL_POLY
)
589 // rescue ID of point with focus
590 sal_uInt32
nPol(pHdl
->GetPolyNum());
591 sal_uInt32
nPnt(pHdl
->GetPointNum());
593 if(pView
->IsPointMarked(*pHdl
))
595 if(rKEvt
.GetKeyCode().IsShift())
597 pView
->UnmarkPoint(*pHdl
);
602 if(!rKEvt
.GetKeyCode().IsShift())
604 pView
->UnmarkAllPoints();
607 pView
->MarkPoint(*pHdl
);
610 if(0L == rHdlList
.GetFocusHdl())
612 // restore point with focus
613 SdrHdl
* pNewOne
= 0L;
615 for(sal_uInt32
a(0); !pNewOne
&& a
< rHdlList
.GetHdlCount(); a
++)
617 SdrHdl
* pAct
= rHdlList
.GetHdl(a
);
620 && pAct
->GetKind() == HDL_POLY
621 && pAct
->GetPolyNum() == nPol
622 && pAct
->GetPointNum() == nPnt
)
630 ((SdrHdlList
&)rHdlList
).SetFocusHdl(pNewOne
);
644 bReturn
= FuPoor::KeyInput(rKEvt
);
649 // allow direct typing into a selected text object
651 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
652 if( !pView
->IsTextEdit() && 1 == rMarkList
.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt
) )
654 SdrObject
* pObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
656 // start text edit for suitable object, pass key event to OutlinerView
657 if ( lcl_KeyEditMode( pObj
, pViewShell
, &rKEvt
) )
666 void FuDraw::SelectionHasChanged()
668 const SdrHdlList
& rHdlList
= pView
->GetHdlList();
669 ((SdrHdlList
&)rHdlList
).ResetFocusHdl();
672 /*************************************************************************
674 |* Function aktivieren
676 \************************************************************************/
678 void FuDraw::Activate()
683 /*************************************************************************
685 |* Function deaktivieren
687 \************************************************************************/
689 void FuDraw::Deactivate()
691 FuPoor::Deactivate();
694 /*************************************************************************
696 |* Maus-Pointer umschalten
698 \************************************************************************/
700 static sal_Bool
lcl_UrlHit( SdrView
* pView
, const Point
& rPosPixel
, Window
* pWindow
)
703 MouseEvent
aMEvt( rPosPixel
, 1, 0, MOUSE_LEFT
);
704 SdrHitKind eHit
= pView
->PickAnything( aMEvt
, SDRMOUSEBUTTONDOWN
, aVEvt
);
706 if ( eHit
!= SDRHIT_NONE
&& aVEvt
.pObj
!= NULL
)
708 if ( ScDrawLayer::GetIMapInfo( aVEvt
.pObj
) && ScDrawLayer::GetHitIMapObject(
709 aVEvt
.pObj
, pWindow
->PixelToLogic(rPosPixel
), *pWindow
) )
712 if ( aVEvt
.eEvent
== SDREVENT_EXECUTEURL
)
719 void FuDraw::ForcePointer(const MouseEvent
* pMEvt
)
721 if ( !pView
->IsAction() )
723 Point aPosPixel
= pWindow
->GetPointerPosPixel();
724 sal_Bool bAlt
= pMEvt
&& pMEvt
->IsMod2();
725 Point aPnt
= pWindow
->PixelToLogic( aPosPixel
);
726 SdrHdl
* pHdl
= pView
->PickHandle(aPnt
);
730 ScMacroInfo
* pInfo
= 0;
731 if ( pView
->PickObj(aPnt
, pView
->getHitTolLog(), pObj
, pPV
, SDRSEARCH_ALSOONMASTER
) )
733 if ( pObj
->IsGroupObject() )
736 if ( pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pHit
, pPV
, SDRSEARCH_DEEP
) )
739 pInfo
= ScDrawLayer::GetMacroInfo( pObj
);
742 if ( pView
->IsTextEdit() )
744 pViewShell
->SetActivePointer(Pointer(POINTER_TEXT
)); // kann nicht sein ?
748 pViewShell
->SetActivePointer(
749 pView
->GetPreferedPointer( aPnt
, pWindow
) );
751 else if ( pView
->IsMarkedHit(aPnt
) )
753 pViewShell
->SetActivePointer( Pointer(POINTER_MOVE
) );
755 else if ( !bAlt
&& ( !pMEvt
|| !pMEvt
->GetButtons() )
756 && lcl_UrlHit( pView
, aPosPixel
, pWindow
) )
758 // kann mit ALT unterdrueckt werden
759 pWindow
->SetPointer( Pointer( POINTER_REFHAND
) ); // Text-URL / ImageMap
761 else if ( !bAlt
&& pView
->PickObj(aPnt
, pView
->getHitTolLog(), pObj
, pPV
, SDRSEARCH_PICKMACRO
) )
763 // kann mit ALT unterdrueckt werden
764 SdrObjMacroHitRec aHitRec
; //! muss da noch irgendwas gesetzt werden ????
765 pViewShell
->SetActivePointer( pObj
->GetMacroPointer(aHitRec
) );
767 else if ( !bAlt
&& pInfo
&& (!pInfo
->GetMacro().isEmpty() || !pInfo
->GetHlink().isEmpty()) )
768 pWindow
->SetPointer( Pointer( POINTER_REFHAND
) );
769 else if ( IsDetectiveHit( aPnt
) )
770 pViewShell
->SetActivePointer( Pointer( POINTER_DETECTIVE
) );
772 pViewShell
->SetActivePointer( aNewPointer
); //! in Gridwin?
776 sal_Bool
FuDraw::IsEditingANote() const
778 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
779 sal_Int32 backval
=rMarkList
.GetMarkCount();
780 for (sal_Int32 nlv1
=0;nlv1
<backval
;nlv1
++)
782 SdrObject
* pObj
= rMarkList
.GetMark( nlv1
)->GetMarkedSdrObj();
783 if ( ScDrawLayer::IsNoteCaption( pObj
) )
791 sal_Bool
FuDraw::IsSizingOrMovingNote( const MouseEvent
& rMEvt
) const
793 sal_Bool bIsSizingOrMoving
= false;
794 if ( rMEvt
.IsLeft() )
796 const SdrMarkList
& rNoteMarkList
= pView
->GetMarkedObjectList();
797 if(rNoteMarkList
.GetMarkCount() == 1)
799 SdrObject
* pObj
= rNoteMarkList
.GetMark( 0 )->GetMarkedSdrObj();
800 if ( ScDrawLayer::IsNoteCaption( pObj
) )
802 Point aMPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
804 pView
->PickHandle( aMPos
) || // handles to resize the note
805 pView
->IsTextEditFrameHit( aMPos
); // frame for moving the note
809 return bIsSizingOrMoving
;
812 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */