diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/svdraw/textchaincursor.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/svdraw/textchaincursor.cxx')
-rw-r--r-- | svx/source/svdraw/textchaincursor.cxx | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/svx/source/svdraw/textchaincursor.cxx b/svx/source/svdraw/textchaincursor.cxx new file mode 100644 index 000000000..51c4d1d8e --- /dev/null +++ b/svx/source/svdraw/textchaincursor.cxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <textchain.hxx> +#include <textchaincursor.hxx> +#include <svx/svdedxv.hxx> +#include <svx/svdoutl.hxx> +#include <vcl/event.hxx> + +// XXX: Possible duplication of code in behavior with stuff in ImpEditView (or ImpEditEngine) and OutlinerView + +// XXX: We violate Demeter's Law several times here, I'm afraid + +TextChainCursorManager::TextChainCursorManager(SdrObjEditView *pEditView, const SdrTextObj *pTextObj) : + mpEditView(pEditView), + mpTextObj(pTextObj), + mbHandlingDel(false) +{ + assert(mpEditView); + assert(mpTextObj); + +} + +bool TextChainCursorManager::HandleKeyEvent( const KeyEvent& rKEvt ) +{ + ESelection aNewSel; + CursorChainingEvent aCursorEvent; + + // check what the cursor/event situation looks like + bool bCompletelyHandled = false; + impDetectEvent(rKEvt, aCursorEvent, aNewSel, bCompletelyHandled); + + if (aCursorEvent == CursorChainingEvent::NULL_EVENT) + return false; + else { + HandleCursorEvent(aCursorEvent, aNewSel); + // return value depends on the situation we are in + return bCompletelyHandled; + } +} + +void TextChainCursorManager::impDetectEvent(const KeyEvent& rKEvt, + CursorChainingEvent& rOutCursorEvt, + ESelection& rOutSel, + bool& rOutHandled) +{ + SdrOutliner *pOutl = mpEditView->GetTextEditOutliner(); + OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView(); + + SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain(); + SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain(); + + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + + // We need to have this KeyFuncType + if (eFunc != KeyFuncType::DONTKNOW && eFunc != KeyFuncType::DELETE) + { + rOutCursorEvt = CursorChainingEvent::NULL_EVENT; + return; + } + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + ESelection aCurSel = pOLV->GetSelection(); + + ESelection aEndSelPrevBox(100000, 100000); + + sal_Int32 nLastPara = pOutl->GetParagraphCount()-1; + OUString aLastParaText = pOutl->GetText(pOutl->GetParagraph(nLastPara)); + sal_Int32 nLastParaLen = aLastParaText.getLength(); + + ESelection aEndSel(nLastPara, nLastParaLen); + bool bAtEndOfTextContent = aCurSel == aEndSel; + + // Possibility: Are we "pushing" at the end of the object? + if (nCode == KEY_RIGHT && bAtEndOfTextContent && pNextLink) + { + rOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK; + // Selection unchanged: we are at the beginning of the box + rOutHandled = true; // Nothing more to do than move cursor + return; + } + + // Possibility: Are we "pushing" at the end of the object? + if (eFunc == KeyFuncType::DELETE && bAtEndOfTextContent && pNextLink) + { + rOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK; + // Selection unchanged: we are at the beginning of the box + rOutHandled = false; // We still need to delete the characters + mbHandlingDel = true; + return; + } + + ESelection aStartSel(0, 0); + bool bAtStartOfTextContent = aCurSel == aStartSel; + + // Possibility: Are we "pushing" at the start of the object? + if (nCode == KEY_LEFT && bAtStartOfTextContent && pPrevLink) + { + rOutCursorEvt = CursorChainingEvent::TO_PREV_LINK; + rOutSel = aEndSelPrevBox; // Set at end of selection + rOutHandled = true; // Nothing more to do than move cursor + return; + } + + // Possibility: Are we "pushing" at the start of the object and deleting left? + if (nCode == KEY_BACKSPACE && bAtStartOfTextContent && pPrevLink) + { + rOutCursorEvt = CursorChainingEvent::TO_PREV_LINK; + rOutSel = aEndSelPrevBox; // Set at end of selection + rOutHandled = false; // We need to delete characters after moving cursor + return; + } + + // If arrived here there is no event detected + rOutCursorEvt = CursorChainingEvent::NULL_EVENT; + +} + +void TextChainCursorManager::HandleCursorEventAfterChaining( + const CursorChainingEvent aCurEvt, + const ESelection& aNewSel) + +{ + // Special case for DELETE handling: we need to get back at the end of the prev box + if (mbHandlingDel) { + // reset flag + mbHandlingDel = false; + + // Move to end of prev box + SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain(); + ESelection aEndSel(100000, 100000); + impChangeEditingTextObj(pPrevLink, aEndSel); + return; + } + + // Standard handling + HandleCursorEvent(aCurEvt, aNewSel); +} + + +void TextChainCursorManager::HandleCursorEvent( + const CursorChainingEvent aCurEvt, + const ESelection& aNewSel) + +{ + + OutlinerView* pOLV = mpEditView->GetTextEditOutlinerView(); + SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain(); + SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain(); + + + switch ( aCurEvt ) { + case CursorChainingEvent::UNCHANGED: + // Set same selection as before the chaining (which is saved as PostChainingSel) + // We need an explicit set because the Outliner is messed up + // after text transfer and otherwise it brings us at arbitrary positions. + pOLV->SetSelection(aNewSel); + break; + case CursorChainingEvent::TO_NEXT_LINK: + mpTextObj->GetTextChain()->SetSwitchingToNextBox(mpTextObj, true); + impChangeEditingTextObj(pNextLink, aNewSel); + break; + case CursorChainingEvent::TO_PREV_LINK: + impChangeEditingTextObj(pPrevLink, aNewSel); + break; + case CursorChainingEvent::NULL_EVENT: + // Do nothing here + break; + } + +} + +void TextChainCursorManager::impChangeEditingTextObj(SdrTextObj *pTargetTextObj, ESelection aNewSel) +{ + assert(pTargetTextObj); + + mpEditView->SdrEndTextEdit(); + mpEditView->SdrBeginTextEdit(pTargetTextObj); + // OutlinerView has changed, so we update the pointer + OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView(); + pOLV->SetSelection(aNewSel); + + // Update reference text obj + mpTextObj = pTargetTextObj; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |