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 <com/sun/star/embed/EmbedStates.hpp>
22 #include <editeng/eeitem.hxx>
23 #include <editeng/flditem.hxx>
24 #include <svx/svdoole2.hxx>
25 #include <svx/svdotext.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <svtools/imapobj.hxx>
28 #include <svx/svdouno.hxx>
29 #include <svx/svdomedia.hxx>
30 #include <svx/svdpagv.hxx>
31 #include <editeng/outlobj.hxx>
32 #include <svx/svdocapt.hxx>
33 #include <sfx2/app.hxx>
39 #include "drawview.hxx"
40 #include "tabvwsh.hxx"
41 #include "drawpage.hxx"
42 #include "globstr.hrc"
43 #include "drwlayer.hxx"
44 #include "userdat.hxx"
47 #include "charthelper.hxx"
51 // -----------------------------------------------------------------------
53 // Maximal erlaubte Mausbewegung um noch Drag&Drop zu starten
54 //! fusel,fuconstr,futext - zusammenfassen!
55 #define SC_MAXDRAGMOVE 3
56 // Min necessary mouse motion for normal dragging
57 #define SC_MINDRAGMOVE 2
59 // -----------------------------------------------------------------------
61 using namespace com::sun::star
;
63 /*************************************************************************
67 \************************************************************************/
69 FuSelection::FuSelection(ScTabViewShell
* pViewSh
, Window
* pWin
, ScDrawView
* pViewP
,
70 SdrModel
* pDoc
, SfxRequest
& rReq
) :
71 FuDraw(pViewSh
, pWin
, pViewP
, pDoc
, rReq
),
76 /*************************************************************************
80 \************************************************************************/
82 FuSelection::~FuSelection()
86 sal_uInt8
FuSelection::Command(const CommandEvent
& rCEvt
)
88 return FuDraw::Command( rCEvt
);
91 /*************************************************************************
93 |* MouseButtonDown-event
95 \************************************************************************/
97 sal_Bool
FuSelection::MouseButtonDown(const MouseEvent
& rMEvt
)
99 // remember button state for creation of own MouseEvents
100 SetMouseButtonCode(rMEvt
.GetButtons());
101 const bool bSelectionOnly
= rMEvt
.IsRight();
102 if ( pView
->IsAction() )
104 if ( bSelectionOnly
)
110 bIsInDragMode
= false; // irgendwo muss es ja zurueckgesetzt werden (#50033#)
112 sal_Bool bReturn
= FuDraw::MouseButtonDown(rMEvt
);
114 aMDPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
116 if ( rMEvt
.IsLeft() )
118 SdrHdl
* pHdl
= pView
->PickHandle(aMDPos
);
120 if ( pHdl
!=NULL
|| pView
->IsMarkedHit(aMDPos
) )
122 // Determine if this is the tail of a SdrCaptionObj i.e.
123 // we need to disable the drag option on the tail of a note
124 // object. Also, disable the ability to use the circular
125 // drag of a note object.
127 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
128 if( rMarkList
.GetMarkCount() == 1 )
130 SdrObject
* pMarkedObj
= rMarkList
.GetMark( 0 )->GetMarkedSdrObj();
131 if( ScDrawLayer::IsNoteCaption( pMarkedObj
) )
133 // move using the valid caption handles for note text box.
134 if(pHdl
&& (pHdl
->GetKind() != HDL_POLY
&& pHdl
->GetKind() != HDL_CIRC
))
136 // move the complete note box.
141 bDrag
= true; // different object
144 bDrag
= true; // several objects
149 pView
->BegDragObj(aMDPos
, (OutputDevice
*) NULL
, pHdl
);
157 sal_Bool bAlt
= rMEvt
.IsMod2();
158 if ( !bAlt
&& pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pObj
, pPV
, SDRSEARCH_PICKMACRO
) )
160 pView
->BegMacroObj(aMDPos
, pObj
, pPV
, pWindow
);
165 OUString sURL
, sTarget
;
166 if ( !bAlt
&& pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pObj
, pPV
, SDRSEARCH_ALSOONMASTER
))
168 // Support for imported Excel docs
169 // Excel is of course not consistent and allows
170 // a hyperlink to be assigned for an object group
171 // and even though the hyperlink is exported in the Escher layer
172 // its never used, when dealing with a group object the link
173 // associated with the clicked object is used only
175 // additionally you can also select a macro in Excel for a grouped
176 // objects and this *usually* results in the macro being set
177 // for the elements in the group and no macro is exported
178 // for the group itself ( this however is not always true )
179 // if a macro and hlink are defined favour the hlink
180 // If a group object has no hyperlink use the hyperlink of the
183 if ( pObj
->IsGroupObject() )
185 ScMacroInfo
* pTmpInfo
= ScDrawLayer::GetMacroInfo( pObj
);
186 if ( !pTmpInfo
|| pTmpInfo
->GetMacro().isEmpty() )
188 SdrObject
* pHit
= NULL
;
189 if ( pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pHit
, pPV
, SDRSEARCH_DEEP
) )
194 ScMacroInfo
* pInfo
= ScDrawLayer::GetMacroInfo( pObj
, true );
195 // For interoperability favour links over macros if both are defined
196 if ( !pInfo
->GetHlink().isEmpty() )
198 OSL_TRACE("** Got URL");
199 sURL
= pInfo
->GetHlink();
201 else if ( !pInfo
->GetMacro().isEmpty() )
203 SfxObjectShell
* pObjSh
= SfxObjectShell::Current();
204 if ( pObjSh
&& SfxApplication::IsXScriptURL( pInfo
->GetMacro() ) )
206 uno::Reference
< beans::XPropertySet
> xProps( pObj
->getUnoShape(), uno::UNO_QUERY
);
212 aCaller
= xProps
->getPropertyValue("Name");
214 catch( uno::Exception
& ) {}
217 uno::Sequence
< sal_Int16
> aOutArgsIndex
;
218 uno::Sequence
< uno::Any
> aOutArgs
;
219 uno::Sequence
< uno::Any
>* pInArgs
=
220 new uno::Sequence
< uno::Any
>(0);
221 pObjSh
->CallXScript( pInfo
->GetMacro(),
222 *pInArgs
, aRet
, aOutArgsIndex
, aOutArgs
, true, &aCaller
);
223 pViewShell
->FakeButtonUp( pViewShell
->GetViewData()->GetActivePart() );
224 return sal_True
; // kein CaptureMouse etc.
233 pView
->PickAnything( rMEvt
, SDRMOUSEBUTTONDOWN
, aVEvt
) != SDRHIT_NONE
&&
236 if ( ScDrawLayer::GetIMapInfo( aVEvt
.pObj
) ) // ImageMap
238 const IMapObject
* pIMapObj
=
239 ScDrawLayer::GetHitIMapObject( aVEvt
.pObj
, aMDPos
, *pWindow
);
240 if ( pIMapObj
&& !pIMapObj
->GetURL().isEmpty() )
242 sURL
= pIMapObj
->GetURL();
243 sTarget
= pIMapObj
->GetTarget();
246 if ( aVEvt
.eEvent
== SDREVENT_EXECUTEURL
&& aVEvt
.pURLField
) // URL
248 sURL
= aVEvt
.pURLField
->GetURL();
249 sTarget
= aVEvt
.pURLField
->GetTargetFrame();
253 // open hyperlink, if found at object or in object's text
254 if ( !sURL
.isEmpty() )
256 ScGlobal::OpenURL( sURL
, sTarget
);
257 pViewShell
->FakeButtonUp( pViewShell
->GetViewData()->GetActivePart() );
258 return sal_True
; // kein CaptureMouse etc.
261 // Is another object being edited in this view?
262 // (Editing is ended in MarkListHasChanged - test before UnmarkAll)
263 SfxInPlaceClient
* pClient
= pViewShell
->GetIPClient();
264 sal_Bool bWasOleActive
= ( pClient
&& pClient
->IsObjectInPlaceActive() );
268 // do not allow multiselection with note caption
269 bool bCaptionClicked
= IsNoteCaptionClicked( aMDPos
);
270 if ( !rMEvt
.IsShift() || bCaptionClicked
|| IsNoteCaptionMarked() )
273 /* Unlock internal layer, if a note caption is clicked. The
274 layer will be relocked in ScDrawView::MarkListHasChanged(). */
275 if( bCaptionClicked
)
276 pView
->UnlockInternalLayer();
278 // try to select the clicked object
279 if ( pView
->MarkObj( aMDPos
, -2, false, rMEvt
.IsMod1() ) )
281 //*********************************************************
283 //********************************************************
284 if (pView
->IsMarkedHit(aMDPos
))
286 // Don't start drag timer if inplace editing of an OLE object
287 // was just ended with this mouse click - the view will be moved
288 // (different tool bars) and the object that was clicked on would
289 // be moved unintentionally.
290 if ( !bWasOleActive
)
293 pHdl
=pView
->PickHandle(aMDPos
);
294 pView
->BegDragObj(aMDPos
, (OutputDevice
*) NULL
, pHdl
);
297 else // Objekt am Rand getroffen
298 if (pViewShell
->IsDrawSelMode())
305 if (pViewShell
->IsDrawSelMode())
307 //*********************************************************
309 //********************************************************
310 pView
->BegMarkObj(aMDPos
);
321 if (!bVCAction
) // VC rufen selber CaptureMouse
322 pWindow
->CaptureMouse();
323 ForcePointer(&rMEvt
);
329 /*************************************************************************
333 \************************************************************************/
335 sal_Bool
FuSelection::MouseMove(const MouseEvent
& rMEvt
)
337 sal_Bool bReturn
= FuDraw::MouseMove(rMEvt
);
339 if (aDragTimer
.IsActive() )
341 Point aOldPixel
= pWindow
->LogicToPixel( aMDPos
);
342 Point aNewPixel
= rMEvt
.GetPosPixel();
343 if ( std::abs( aOldPixel
.X() - aNewPixel
.X() ) > SC_MAXDRAGMOVE
||
344 std::abs( aOldPixel
.Y() - aNewPixel
.Y() ) > SC_MAXDRAGMOVE
)
348 if ( pView
->IsAction() )
350 Point
aPix(rMEvt
.GetPosPixel());
351 Point
aPnt(pWindow
->PixelToLogic(aPix
));
354 pView
->MovAction(aPnt
);
358 // Ein VCControl ist aktiv
359 // Event an den Manager weiterleiten
365 ForcePointer(&rMEvt
);
370 /*************************************************************************
372 |* MouseButtonUp-event
374 \************************************************************************/
376 sal_Bool
FuSelection::MouseButtonUp(const MouseEvent
& rMEvt
)
378 // remember button state for creation of own MouseEvents
379 SetMouseButtonCode(rMEvt
.GetButtons());
381 sal_Bool bReturn
= FuDraw::MouseButtonUp(rMEvt
);
382 sal_Bool bOle
= pViewShell
->GetViewFrame()->GetFrame().IsInPlace();
384 SdrObject
* pObj
= NULL
;
385 SdrPageView
* pPV
= NULL
;
386 if (aDragTimer
.IsActive() )
391 sal_uInt16 nDrgLog
= sal_uInt16 ( pWindow
->PixelToLogic(Size(SC_MINDRAGMOVE
,0)).Width() );
392 Point
aPnt( pWindow
->PixelToLogic( rMEvt
.GetPosPixel() ) );
395 ScViewData
* pViewData
= ( pViewShell
? pViewShell
->GetViewData() : NULL
);
396 ScDocument
* pDocument
= ( pViewData
? pViewData
->GetDocument() : NULL
);
397 SdrPageView
* pPageView
= ( pView
? pView
->GetSdrPageView() : NULL
);
398 SdrPage
* pPage
= ( pPageView
? pPageView
->GetPage() : NULL
);
399 ::std::vector
< OUString
> aExcludedChartNames
;
400 ScRangeListVector aProtectedChartRangesVector
;
402 if ( rMEvt
.IsLeft() )
404 if ( pView
->IsDragObj() )
406 /******************************************************************
407 * Objekt wurde verschoben
408 ******************************************************************/
409 if ( rMEvt
.IsMod1() )
413 ScChartHelper::GetChartNames( aExcludedChartNames
, pPage
);
415 if ( pView
&& pDocument
)
417 const SdrMarkList
& rSdrMarkList
= pView
->GetMarkedObjectList();
418 sal_uLong nMarkCount
= rSdrMarkList
.GetMarkCount();
419 for ( sal_uLong i
= 0; i
< nMarkCount
; ++i
)
421 SdrMark
* pMark
= rSdrMarkList
.GetMark( i
);
422 pObj
= ( pMark
? pMark
->GetMarkedSdrObj() : NULL
);
425 ScChartHelper::AddRangesIfProtectedChart( aProtectedChartRangesVector
, pDocument
, pObj
);
432 if (!rMEvt
.IsShift() && !rMEvt
.IsMod1() && !rMEvt
.IsMod2() &&
433 std::abs(aPnt
.X() - aMDPos
.X()) < nDrgLog
&&
434 std::abs(aPnt
.Y() - aMDPos
.Y()) < nDrgLog
)
436 /*************************************************************
437 * If a user wants to click on an object in front of a marked
438 * one, he releases the mouse button immediately
439 **************************************************************/
440 if (pView
->PickObj(aMDPos
, pView
->getHitTolLog(), pObj
, pPV
, SDRSEARCH_ALSOONMASTER
| SDRSEARCH_BEFOREMARK
))
442 pView
->UnmarkAllObj();
443 pView
->MarkObj(pObj
,pPV
,false,false);
447 pView
->EndDragObj( rMEvt
.IsMod1() );
448 pView
->ForceMarkedToAnotherPage();
450 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
451 if (rMarkList
.GetMarkCount() == 1)
453 SdrMark
* pMark
= rMarkList
.GetMark(0);
454 pObj
= pMark
->GetMarkedSdrObj();
455 FuPoor
* pPoor
= pViewShell
->GetViewData()->GetView()->GetDrawFuncPtr();
456 FuText
* pText
= static_cast<FuText
*>(pPoor
);
457 pText
->StopDragMode(pObj
);
461 else if (pView
->IsAction() )
463 // unlock internal layer to include note captions
464 pView
->UnlockInternalLayer();
466 if ( pView
->AreObjectsMarked() )
470 /* if multi-selection contains a note caption object, remove
471 all other objects from selection. */
472 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
473 sal_uLong nCount
= rMarkList
.GetMarkCount();
477 for( sal_uLong nIdx
= 0; !bFound
&& (nIdx
< nCount
); ++nIdx
)
479 pObj
= rMarkList
.GetMark( nIdx
)->GetMarkedSdrObj();
480 bFound
= ScDrawLayer::IsNoteCaption( pObj
);
484 pView
->MarkObj( pObj
, pView
->GetSdrPageView() );
492 /**************************************************************************
493 * Ggf. OLE-Objekt beruecksichtigen
494 **************************************************************************/
495 SfxInPlaceClient
* pIPClient
= pViewShell
->GetIPClient();
499 ScModule
* pScMod
= SC_MOD();
500 bool bUnoRefDialog
= pScMod
->IsRefDialogOpen() && pScMod
->GetCurRefDlgId() == WID_SIMPLE_REF
;
502 if ( pIPClient
->IsObjectInPlaceActive() && !bUnoRefDialog
)
503 pIPClient
->DeactivateObject();
506 sal_uInt16 nClicks
= rMEvt
.GetClicks();
507 if ( nClicks
== 2 && rMEvt
.IsLeft() )
509 if ( pView
->AreObjectsMarked() )
511 const SdrMarkList
& rMarkList
= pView
->GetMarkedObjectList();
512 if (rMarkList
.GetMarkCount() == 1)
514 SdrMark
* pMark
= rMarkList
.GetMark(0);
515 pObj
= pMark
->GetMarkedSdrObj();
517 // aktivieren nur, wenn die Maus auch (noch) ueber dem
518 // selektierten Objekt steht
521 SdrHitKind eHit
= pView
->PickAnything( rMEvt
, SDRMOUSEBUTTONDOWN
, aVEvt
);
522 if ( eHit
!= SDRHIT_NONE
&& aVEvt
.pObj
== pObj
)
524 sal_uInt16 nSdrObjKind
= pObj
->GetObjIdentifier();
530 if (nSdrObjKind
== OBJ_OLE2
)
534 if (((SdrOle2Obj
*) pObj
)->GetObjRef().is())
536 pViewShell
->ActivateObject( (SdrOle2Obj
*) pObj
, 0 );
543 // not in UNO controls
544 // #i32352# not in media objects
546 else if ( pObj
->ISA(SdrTextObj
) && !pObj
->ISA(SdrUnoObj
) && !pObj
->ISA(SdrMediaObj
) )
548 OutlinerParaObject
* pOPO
= pObj
->GetOutlinerParaObject();
549 sal_Bool bVertical
= ( pOPO
&& pOPO
->IsVertical() );
550 sal_uInt16 nTextSlotId
= bVertical
? SID_DRAW_TEXT_VERTICAL
: SID_DRAW_TEXT
;
552 pViewShell
->GetViewData()->GetDispatcher().
553 Execute(nTextSlotId
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
555 // jetzt den erzeugten FuText holen und in den EditModus setzen
556 FuPoor
* pPoor
= pViewShell
->GetViewData()->GetView()->GetDrawFuncPtr();
557 if ( pPoor
&& pPoor
->GetSlotID() == nTextSlotId
) // hat keine RTTI
559 FuText
* pText
= (FuText
*)pPoor
;
560 Point aMousePixel
= rMEvt
.GetPosPixel();
561 pText
->SetInEditMode( pObj
, &aMousePixel
);
568 else if ( TestDetective( pView
->GetSdrPageView(), aPnt
) )
572 // Ein VCControl ist aktiv
573 // Event an den Manager weiterleiten
580 ForcePointer(&rMEvt
);
582 pWindow
->ReleaseMouse();
584 // Command-Handler fuer Kontext-Menue kommt erst nach MouseButtonUp,
585 // darum hier die harte IsLeft-Abfrage
586 if ( !bReturn
&& rMEvt
.IsLeft() )
587 if (pViewShell
->IsDrawSelMode())
588 pViewShell
->GetViewData()->GetDispatcher().
589 Execute(SID_OBJECT_SELECT
, SFX_CALLMODE_SLOT
| SFX_CALLMODE_RECORD
);
591 if ( bCopy
&& pViewData
&& pDocument
&& pPage
)
593 ScDocShell
* pDocShell
= pViewData
->GetDocShell();
594 ScModelObj
* pModelObj
= ( pDocShell
? ScModelObj::getImplementation( pDocShell
->GetModel() ) : NULL
);
597 SCTAB nTab
= pViewData
->GetTabNo();
598 ScChartHelper::CreateProtectedChartListenersAndNotify( pDocument
, pPage
, pModelObj
, nTab
,
599 aProtectedChartRangesVector
, aExcludedChartNames
);
606 /*************************************************************************
608 |* Tastaturereignisse bearbeiten
610 |* Wird ein KeyEvent bearbeitet, so ist der Return-Wert sal_True, andernfalls
613 \************************************************************************/
615 sal_Bool
FuSelection::KeyInput(const KeyEvent
& rKEvt
)
617 sal_Bool bReturn
= false;
621 bReturn
= FuDraw::KeyInput(rKEvt
);
628 /*************************************************************************
630 |* Function aktivieren
632 \************************************************************************/
634 void FuSelection::Activate()
639 /*************************************************************************
641 |* Function deaktivieren
643 \************************************************************************/
645 void FuSelection::Deactivate()
647 /**************************************************************************
649 **************************************************************************/
650 FuDraw::Deactivate();
653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */