/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" //------------------------------------------------------------------------ #include // EditEngine::IsSimpleCharInput #include #include #include #include #include #include #include #include #include #include #include "sc.hrc" #include "fudraw.hxx" #include "futext.hxx" #include "tabvwsh.hxx" #include "drwlayer.hxx" #include "scresid.hxx" #include "userdat.hxx" #include "docsh.hxx" #include "postit.hxx" #include "globstr.hrc" #include "drawview.hxx" /************************************************************************* |* |* Basisklasse fuer alle Drawmodul-spezifischen Funktionen |* \************************************************************************/ FuDraw::FuDraw(ScTabViewShell* pViewSh, Window* pWin, ScDrawView* pViewP, SdrModel* pDoc, SfxRequest& rReq) : FuPoor (pViewSh, pWin, pViewP, pDoc, rReq), aNewPointer ( POINTER_ARROW ), aOldPointer ( POINTER_ARROW ) { } /************************************************************************* |* |* Destruktor |* \************************************************************************/ FuDraw::~FuDraw() { } /************************************************************************* |* |* Modifier-Tasten auswerten |* \************************************************************************/ void FuDraw::DoModifiers(const MouseEvent& rMEvt) { // Shift = Ortho und AngleSnap // Control = Snap (Toggle) // Alt = zentrisch sal_Bool bShift = rMEvt.IsShift(); // sal_Bool bCtrl = rMEvt.IsMod1(); sal_Bool bAlt = rMEvt.IsMod2(); // ScViewData* pViewData = pViewShell->GetViewData(); // const ScViewOptions& rOpt = pViewData->GetOptions(); // const ScGridOptions& rGrid = rOpt.GetGridOptions(); // sal_Bool bGridOpt = rGrid.GetUseGridSnap(); sal_Bool bOrtho = bShift; sal_Bool bAngleSnap = bShift; // sal_Bool bGridSnap = ( bGridOpt != bCtrl ); // andere Snap's nicht unterstuetzt sal_Bool bCenter = bAlt; // #i33136# if(doConstructOrthogonal()) { bOrtho = !bShift; } if (pView->IsOrtho() != bOrtho) pView->SetOrtho(bOrtho); if (pView->IsAngleSnapEnabled() != bAngleSnap) pView->SetAngleSnapEnabled(bAngleSnap); /* Control fuer Snap beisst sich beim Verschieben mit "kopieren" !!! if (pView->IsGridSnap() != bGridSnap) pView->SetGridSnap(bGridSnap); if (pView->IsSnapEnabled() != bGridSnap) pView->SetSnapEnabled(bGridSnap); */ if (pView->IsCreate1stPointAsCenter() != bCenter) pView->SetCreate1stPointAsCenter(bCenter); if (pView->IsResizeAtCenter() != bCenter) pView->SetResizeAtCenter(bCenter); } void FuDraw::ResetModifiers() { ScViewData* pViewData = pViewShell->GetViewData(); const ScViewOptions& rOpt = pViewData->GetOptions(); const ScGridOptions& rGrid = rOpt.GetGridOptions(); sal_Bool bGridOpt = rGrid.GetUseGridSnap(); if (pView->IsOrtho()) pView->SetOrtho(sal_False); if (pView->IsAngleSnapEnabled()) pView->SetAngleSnapEnabled(sal_False); if (pView->IsGridSnap() != bGridOpt) pView->SetGridSnap(bGridOpt); if (pView->IsSnapEnabled() != bGridOpt) pView->SetSnapEnabled(bGridOpt); if (pView->IsCreate1stPointAsCenter()) pView->SetCreate1stPointAsCenter(sal_False); if (pView->IsResizeAtCenter()) pView->SetResizeAtCenter(sal_False); } /************************************************************************* |* |* MouseButtonDown-event |* \************************************************************************/ sal_Bool __EXPORT FuDraw::MouseButtonDown(const MouseEvent& rMEvt) { // #95491# remember button state for creation of own MouseEvents SetMouseButtonCode(rMEvt.GetButtons()); DoModifiers( rMEvt ); return sal_False; } /************************************************************************* |* |* MouseMove-event |* \************************************************************************/ sal_Bool __EXPORT FuDraw::MouseMove(const MouseEvent& rMEvt) { // #106438# evaluate modifiers only if in a drawing layer action // (don't interfere with keyboard shortcut handling) if (pView->IsAction()) DoModifiers( rMEvt ); return sal_False; } /************************************************************************* |* |* MouseButtonUp-event |* \************************************************************************/ sal_Bool __EXPORT FuDraw::MouseButtonUp(const MouseEvent& rMEvt) { // #95491# remember button state for creation of own MouseEvents SetMouseButtonCode(rMEvt.GetButtons()); ResetModifiers(); return sal_False; } /************************************************************************* |* |* Tastaturereignisse bearbeiten |* |* Wird ein KeyEvent bearbeitet, so ist der Return-Wert sal_True, andernfalls |* FALSE. |* \************************************************************************/ sal_Bool lcl_KeyEditMode( SdrObject* pObj, ScTabViewShell* pViewShell, const KeyEvent* pInitialKey ) { sal_Bool bReturn = sal_False; if ( pObj && pObj->ISA(SdrTextObj) && !pObj->ISA(SdrUnoObj) ) { // start text edit - like FuSelection::MouseButtonUp, // but with bCursorToEnd instead of mouse position OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject(); sal_Bool bVertical = ( pOPO && pOPO->IsVertical() ); sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT; // don't switch shells if text shell is already active FuPoor* pPoor = pViewShell->GetViewData()->GetView()->GetDrawFuncPtr(); if ( !pPoor || pPoor->GetSlotID() != nTextSlotId ) { pViewShell->GetViewData()->GetDispatcher(). Execute(nTextSlotId, SFX_CALLMODE_SYNCHRON | SFX_CALLMODE_RECORD); } // get the resulting FuText and set in edit mode pPoor = pViewShell->GetViewData()->GetView()->GetDrawFuncPtr(); if ( pPoor && pPoor->GetSlotID() == nTextSlotId ) // no RTTI { FuText* pText = (FuText*)pPoor; pText->SetInEditMode( pObj, NULL, sal_True, pInitialKey ); //! set cursor to end of text } bReturn = sal_True; } return bReturn; } sal_Bool __EXPORT FuDraw::KeyInput(const KeyEvent& rKEvt) { sal_Bool bReturn = sal_False; ScViewData& rViewData = *pViewShell->GetViewData(); switch ( rKEvt.GetKeyCode().GetCode() ) { case KEY_ESCAPE: /* 18.12.95: TextShell beibehalten nicht mehr gewuenscht... * * if ( pView->IsAction() ) * { * pView->BrkAction(); * pWindow->ReleaseMouse(); * bReturn = sal_True; * } * else if ( pView->IsTextEdit() ) * { * pView->EndTextEdit(); * pView->SetCreateMode(); * pViewShell->GetScDrawView()->InvalidateDrawTextAttrs(); * bReturn = sal_True; * } * else */ if ( pViewShell->IsDrawTextShell() || aSfxRequest.GetSlot() == SID_DRAW_NOTEEDIT ) { // in normale Draw-Shell, wenn Objekt selektiert, sonst Zeichnen aus rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD); bReturn = sal_True; } else if ( pViewShell->IsDrawSelMode() ) { pView->UnmarkAll(); rViewData.GetDispatcher().Execute(SID_OBJECT_SELECT, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD); bReturn = sal_True; } else if ( pView->AreObjectsMarked() ) { // #97016# III SdrHdlList& rHdlList = const_cast< SdrHdlList& >( pView->GetHdlList() ); if( rHdlList.GetFocusHdl() ) rHdlList.ResetFocusHdl(); else pView->UnmarkAll(); // Beim Bezier-Editieren ist jetzt wieder das Objekt selektiert if (!pView->AreObjectsMarked()) pViewShell->SetDrawShell( sal_False ); bReturn = sal_True; } break; case KEY_DELETE: //! ueber Accelerator pView->DeleteMarked(); bReturn = sal_True; break; case KEY_RETURN: { if( rKEvt.GetKeyCode().GetModifier() == 0 ) { // #98256# activate OLE object on RETURN for selected object // #98198# put selected text object in edit mode const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() ) { sal_Bool bOle = pViewShell->GetViewFrame()->GetFrame().IsInPlace(); SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); if( pObj && pObj->ISA( SdrOle2Obj ) && !bOle ) { //HMHpView->HideMarkHdl(); pViewShell->ActivateObject( static_cast< SdrOle2Obj* >( pObj ), 0 ); // consumed bReturn = sal_True; } else if ( lcl_KeyEditMode( pObj, pViewShell, NULL ) ) // start text edit for suitable object bReturn = sal_True; } } } break; case KEY_F2: { if( rKEvt.GetKeyCode().GetModifier() == 0 ) { // #98198# put selected text object in edit mode // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer) const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() ) { SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); if ( lcl_KeyEditMode( pObj, pViewShell, NULL ) ) // start text edit for suitable object bReturn = sal_True; } } } break; // #97016# case KEY_TAB: { // in calc do NOT start draw object selection using TAB/SHIFT-TAB when // there is not yet a object selected if(pView->AreObjectsMarked()) { KeyCode aCode = rKEvt.GetKeyCode(); if ( !aCode.IsMod1() && !aCode.IsMod2() ) { // changeover to the next object if(!pView->MarkNextObj( !aCode.IsShift() )) { //If there is only one object, don't do the UnmarkAlllObj() & MarkNextObj(). if ( pView->GetMarkableObjCount() > 1 && pView->HasMarkableObj() ) { // #97016# No next object: go over open end and // get first from the other side pView->UnmarkAllObj(); pView->MarkNextObj(!aCode.IsShift()); } } // #97016# II if(pView->AreObjectsMarked()) pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); bReturn = sal_True; } // #98994# handle Mod1 and Mod2 to get travelling running on different systems if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2()) { // #97016# II do something with a selected handle? const SdrHdlList& rHdlList = pView->GetHdlList(); sal_Bool bForward(!rKEvt.GetKeyCode().IsShift()); ((SdrHdlList&)rHdlList).TravelFocusHdl(bForward); // guarantee visibility of focused handle SdrHdl* pHdl = rHdlList.GetFocusHdl(); if(pHdl) { Point aHdlPosition(pHdl->GetPos()); Rectangle aVisRect(aHdlPosition - Point(100, 100), Size(200, 200)); pView->MakeVisible(aVisRect, *pWindow); } // consumed bReturn = sal_True; } } } break; // #97016# case KEY_END: { // in calc do NOT select the last draw object when // there is not yet a object selected if(pView->AreObjectsMarked()) { KeyCode aCode = rKEvt.GetKeyCode(); if ( aCode.IsMod1() ) { // #97016# mark last object pView->UnmarkAllObj(); pView->MarkNextObj(sal_False); // #97016# II if(pView->AreObjectsMarked()) pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); bReturn = sal_True; } } } break; // #97016# case KEY_HOME: { // in calc do NOT select the first draw object when // there is not yet a object selected if(pView->AreObjectsMarked()) { KeyCode aCode = rKEvt.GetKeyCode(); if ( aCode.IsMod1() ) { // #97016# mark first object pView->UnmarkAllObj(); pView->MarkNextObj(sal_True); // #97016# II if(pView->AreObjectsMarked()) pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); bReturn = sal_True; } } } break; // #97016# case KEY_UP: case KEY_DOWN: case KEY_LEFT: case KEY_RIGHT: { // in calc do cursor travelling of draw objects only when // there is a object selected yet if(pView->AreObjectsMarked()) { const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); if(rMarkList.GetMarkCount() == 1) { // disable cursor travelling on note objects as the tail connector position // must not move. SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); if( ScDrawLayer::IsNoteCaption( pObj ) ) break; } long nX = 0; long nY = 0; sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); if (nCode == KEY_UP) { // Scroll nach oben nX = 0; nY =-1; } else if (nCode == KEY_DOWN) { // Scroll nach unten nX = 0; nY = 1; } else if (nCode == KEY_LEFT) { // Scroll nach links nX =-1; nY = 0; } else if (nCode == KEY_RIGHT) { // Scroll nach rechts nX = 1; nY = 0; } sal_Bool bReadOnly = rViewData.GetDocShell()->IsReadOnly(); if(!rKEvt.GetKeyCode().IsMod1() && !bReadOnly) { if(rKEvt.GetKeyCode().IsMod2()) { // #97016# move in 1 pixel distance Size aLogicSizeOnePixel = (pWindow) ? pWindow->PixelToLogic(Size(1,1)) : Size(100, 100); nX *= aLogicSizeOnePixel.Width(); nY *= aLogicSizeOnePixel.Height(); } else if(rKEvt.GetKeyCode().IsShift()) // #121236# Support for shift key in calc { nX *= 1000; nY *= 1000; } else { // old, fixed move distance nX *= 100; nY *= 100; } // is there a movement to do? if(0 != nX || 0 != nY) { // #97016# II const SdrHdlList& rHdlList = pView->GetHdlList(); SdrHdl* pHdl = rHdlList.GetFocusHdl(); if(0L == pHdl) { // #107086# only take action when move is allowed if(pView->IsMoveAllowed()) { // #90129# restrict movement to WorkArea const Rectangle& rWorkArea = pView->GetWorkArea(); if(!rWorkArea.IsEmpty()) { Rectangle aMarkRect(pView->GetMarkedObjRect()); aMarkRect.Move(nX, nY); if(!aMarkRect.IsInside(rWorkArea)) { if(aMarkRect.Left() < rWorkArea.Left()) { nX += rWorkArea.Left() - aMarkRect.Left(); } if(aMarkRect.Right() > rWorkArea.Right()) { nX -= aMarkRect.Right() - rWorkArea.Right(); } if(aMarkRect.Top() < rWorkArea.Top()) { nY += rWorkArea.Top() - aMarkRect.Top(); } if(aMarkRect.Bottom() > rWorkArea.Bottom()) { nY -= aMarkRect.Bottom() - rWorkArea.Bottom(); } } } // now move the selected draw objects pView->MoveAllMarked(Size(nX, nY)); // #97016# II pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow); bReturn = sal_True; } } else { // move handle with index nHandleIndex if(pHdl && (nX || nY)) { // now move the Handle (nX, nY) Point aStartPoint(pHdl->GetPos()); Point aEndPoint(pHdl->GetPos() + Point(nX, nY)); const SdrDragStat& rDragStat = pView->GetDragStat(); // start dragging pView->BegDragObj(aStartPoint, 0, pHdl, 0); if(pView->IsDragObj()) { FASTBOOL bWasNoSnap = rDragStat.IsNoSnap(); sal_Bool bWasSnapEnabled = pView->IsSnapEnabled(); // switch snapping off if(!bWasNoSnap) ((SdrDragStat&)rDragStat).SetNoSnap(sal_True); if(bWasSnapEnabled) pView->SetSnapEnabled(sal_False); pView->MovAction(aEndPoint); pView->EndDragObj(); // restore snap if(!bWasNoSnap) ((SdrDragStat&)rDragStat).SetNoSnap(bWasNoSnap); if(bWasSnapEnabled) pView->SetSnapEnabled(bWasSnapEnabled); } // make moved handle visible Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200)); pView->MakeVisible(aVisRect, *pWindow); bReturn = sal_True; } } } } } } break; // #97016# case KEY_SPACE: { // in calc do only something when draw objects are selected if(pView->AreObjectsMarked()) { const SdrHdlList& rHdlList = pView->GetHdlList(); SdrHdl* pHdl = rHdlList.GetFocusHdl(); if(pHdl) { if(pHdl->GetKind() == HDL_POLY) { // rescue ID of point with focus sal_uInt32 nPol(pHdl->GetPolyNum()); sal_uInt32 nPnt(pHdl->GetPointNum()); if(pView->IsPointMarked(pHdl)) { if(rKEvt.GetKeyCode().IsShift()) { pView->UnmarkPoint(*pHdl); } } else { if(!rKEvt.GetKeyCode().IsShift()) { pView->UnmarkAllPoints(); } pView->MarkPoint(*pHdl); } if(0L == rHdlList.GetFocusHdl()) { // restore point with focus SdrHdl* pNewOne = 0L; for(sal_uInt32 a(0); !pNewOne && a < rHdlList.GetHdlCount(); a++) { SdrHdl* pAct = rHdlList.GetHdl(a); if(pAct && pAct->GetKind() == HDL_POLY && pAct->GetPolyNum() == nPol && pAct->GetPointNum() == nPnt) { pNewOne = pAct; } } if(pNewOne) { ((SdrHdlList&)rHdlList).SetFocusHdl(pNewOne); } } bReturn = sal_True; } } } } break; } if (!bReturn) { bReturn = FuPoor::KeyInput(rKEvt); } if (!bReturn) { // #98198# allow direct typing into a selected text object const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt) ) { SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); // start text edit for suitable object, pass key event to OutlinerView if ( lcl_KeyEditMode( pObj, pViewShell, &rKEvt ) ) bReturn = sal_True; } } return (bReturn); } // #97016# II void FuDraw::SelectionHasChanged() { const SdrHdlList& rHdlList = pView->GetHdlList(); ((SdrHdlList&)rHdlList).ResetFocusHdl(); } /************************************************************************* |* |* Vor dem Scrollen Selektionsdarstellung ausblenden |* \************************************************************************/ void FuDraw::ScrollStart() { // HideShownXor in Gridwin } /************************************************************************* |* |* Nach dem Scrollen Selektionsdarstellung wieder anzeigen |* \************************************************************************/ void FuDraw::ScrollEnd() { // ShowShownXor in Gridwin } /************************************************************************* |* |* Function aktivieren |* \************************************************************************/ void FuDraw::Activate() { FuPoor::Activate(); } /************************************************************************* |* |* Function deaktivieren |* \************************************************************************/ void FuDraw::Deactivate() { FuPoor::Deactivate(); } /************************************************************************* |* |* Maus-Pointer umschalten |* \************************************************************************/ sal_Bool lcl_UrlHit( SdrView* pView, const Point& rPosPixel, Window* pWindow ) { SdrViewEvent aVEvt; MouseEvent aMEvt( rPosPixel, 1, 0, MOUSE_LEFT ); SdrHitKind eHit = pView->PickAnything( aMEvt, SDRMOUSEBUTTONDOWN, aVEvt ); if ( eHit != SDRHIT_NONE && aVEvt.pObj != NULL ) { if ( ScDrawLayer::GetIMapInfo( aVEvt.pObj ) && ScDrawLayer::GetHitIMapObject( aVEvt.pObj, pWindow->PixelToLogic(rPosPixel), *pWindow ) ) return sal_True; if ( aVEvt.eEvent == SDREVENT_EXECUTEURL ) return sal_True; } return sal_False; } void FuDraw::ForcePointer(const MouseEvent* pMEvt) { if ( !pView->IsAction() ) { Point aPosPixel = pWindow->GetPointerPosPixel(); sal_Bool bAlt = pMEvt && pMEvt->IsMod2(); Point aPnt = pWindow->PixelToLogic( aPosPixel ); SdrHdl* pHdl = pView->PickHandle(aPnt); SdrObject* pObj; SdrPageView* pPV; ScMacroInfo* pInfo = 0; if ( pView->PickObj(aPnt, pView->getHitTolLog(), pObj, pPV, SDRSEARCH_ALSOONMASTER) ) { if ( pObj->IsGroupObject() ) { SdrObject* pHit = 0; if ( pView->PickObj(aMDPos, pView->getHitTolLog(), pHit, pPV, SDRSEARCH_DEEP ) ) pObj = pHit; } pInfo = ScDrawLayer::GetMacroInfo( pObj ); } if ( pView->IsTextEdit() ) { pViewShell->SetActivePointer(Pointer(POINTER_TEXT)); // kann nicht sein ? } else if ( pHdl ) { pViewShell->SetActivePointer( pView->GetPreferedPointer( aPnt, pWindow ) ); } else if ( pView->IsMarkedHit(aPnt) ) { pViewShell->SetActivePointer( Pointer(POINTER_MOVE) ); } else if ( !bAlt && ( !pMEvt || !pMEvt->GetButtons() ) && lcl_UrlHit( pView, aPosPixel, pWindow ) ) { // kann mit ALT unterdrueckt werden pWindow->SetPointer( Pointer( POINTER_REFHAND ) ); // Text-URL / ImageMap } else if ( !bAlt && pView->PickObj(aPnt, pView->getHitTolLog(), pObj, pPV, SDRSEARCH_PICKMACRO) ) { // kann mit ALT unterdrueckt werden SdrObjMacroHitRec aHitRec; //! muss da noch irgendwas gesetzt werden ???? pViewShell->SetActivePointer( pObj->GetMacroPointer(aHitRec) ); } #ifdef ISSUE66550_HLINK_FOR_SHAPES else if ( !bAlt && pInfo && ((pInfo->GetMacro().getLength() > 0) || (pInfo->GetHlink().getLength() > 0)) ) #else else if ( !bAlt && pInfo && (pInfo->GetMacro().getLength() > 0) ) #endif pWindow->SetPointer( Pointer( POINTER_REFHAND ) ); else if ( IsDetectiveHit( aPnt ) ) pViewShell->SetActivePointer( Pointer( POINTER_DETECTIVE ) ); else pViewShell->SetActivePointer( aNewPointer ); //! in Gridwin? } } sal_Bool FuDraw::IsSizingOrMovingNote( const MouseEvent& rMEvt ) const { sal_Bool bIsSizingOrMoving = sal_False; if ( rMEvt.IsLeft() ) { const SdrMarkList& rNoteMarkList = pView->GetMarkedObjectList(); if(rNoteMarkList.GetMarkCount() == 1) { SdrObject* pObj = rNoteMarkList.GetMark( 0 )->GetMarkedSdrObj(); if ( ScDrawLayer::IsNoteCaption( pObj ) ) { Point aMPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() ); bIsSizingOrMoving = pView->PickHandle( aMPos ) || // handles to resize the note pView->IsTextEditFrameHit( aMPos ); // frame for moving the note } } } return bIsSizingOrMoving; }