diff options
Diffstat (limited to 'svx/source/svdraw/textchainflow.cxx')
-rw-r--r-- | svx/source/svdraw/textchainflow.cxx | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/svx/source/svdraw/textchainflow.cxx b/svx/source/svdraw/textchainflow.cxx new file mode 100644 index 0000000000..9763ea5015 --- /dev/null +++ b/svx/source/svdraw/textchainflow.cxx @@ -0,0 +1,314 @@ +/* -*- 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 <svx/svdotext.hxx> +#include <svx/svdoutl.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/editobj.hxx> +#include <editeng/overflowingtxt.hxx> +#include <textchainflow.hxx> +#include <sal/log.hxx> + +TextChainFlow::TextChainFlow(SdrTextObj *pChainTarget) + : mpTargetLink(pChainTarget) +{ + SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new TextChainFlow"); + + mpTextChain = mpTargetLink->GetTextChain(); + mpNextLink = mpTargetLink->GetNextLinkInChain(); + + bUnderflow = bOverflow = false; + + mbOFisUFinduced = false; + + mpOverflChText = nullptr; + mpUnderflChText = nullptr; + + mbPossiblyCursorOut = false; +} + + +TextChainFlow::~TextChainFlow() +{ + mpOverflChText.reset(); + mpUnderflChText.reset(); +} + +void TextChainFlow::impSetFlowOutlinerParams(SdrOutliner *, SdrOutliner *) +{ + // Nothing to do if not in editing mode +} + +/* + * Check for overflow in the state of pFlowOutl. + * If pParamOutl is not NULL sets some parameters from there. + * This is useful in case the outliner is not set for overflow + * (e.g. in editing mode we check for overflow in drawing outl but + * parameters come from editing outliner) +*/ +void TextChainFlow::impCheckForFlowEvents(SdrOutliner *pFlowOutl, SdrOutliner *pParamOutl) +{ + bool bOldUpdateMode = pFlowOutl->IsUpdateLayout(); + + // XXX: This could be reorganized moving most of this stuff inside EditingTextChainFlow + if (pParamOutl != nullptr) + { + // We need this since it's required to check overflow + pFlowOutl->SetUpdateLayout(true); + + // XXX: does this work if you do it before setting the text? Seems so. + impSetFlowOutlinerParams(pFlowOutl, pParamOutl); + } + + bool bIsPageOverflow = pFlowOutl->IsPageOverflow(); + + // NOTE: overflow and underflow cannot be both true + bOverflow = bIsPageOverflow && mpNextLink; + bUnderflow = !bIsPageOverflow && mpNextLink && mpNextLink->HasText(); + + // Get old state on whether to merge para-s or not + // NOTE: We handle UF/OF using the _old_ state. The new one is simply saved + bool bMustMergeParaAmongLinks = GetTextChain()->GetIsPartOfLastParaInNextLink(mpTargetLink); + + // Set (Non)OverflowingTxt here (if any) + + // If we had an underflow before we have to deep merge paras anyway + bool bMustMergeParaOF = bMustMergeParaAmongLinks || mbOFisUFinduced; + + mpOverflChText.reset( bOverflow ? + new OFlowChainedText(pFlowOutl, bMustMergeParaOF) : + nullptr ); + + // Set current underflowing text (if any) + mpUnderflChText.reset( bUnderflow ? + new UFlowChainedText(pFlowOutl, bMustMergeParaAmongLinks) : + nullptr ); + + // Reset update mode // Reset it here because we use WriteRTF (needing updatemode = true) in the two constructors above + if (!bOldUpdateMode) // Reset only if the old value was false + pFlowOutl->SetUpdateLayout(bOldUpdateMode); + + // NOTE: Must be called after mp*ChText abd b*flow have been set but before mbOFisUFinduced is reset + impUpdateCursorInfo(); + + // To check whether an overflow is underflow induced or not (useful in cursor checking) + mbOFisUFinduced = bUnderflow; +} + +void TextChainFlow::impUpdateCursorInfo() +{ + // XXX: Maybe we can get rid of mbOFisUFinduced by not allowing handling of more than one event by the same TextChainFlow + // if this is not an OF triggered during an UF + + mbPossiblyCursorOut = bOverflow; + + if(mbPossiblyCursorOut ) { + maOverflowPosSel = mpOverflChText->GetOverflowPointSel(); + ESelection aSelAtUFTime = GetTextChain()->GetPreChainingSel(GetLinkTarget()); + // Might be an invalid selection if the cursor at UF time was before + // the (possibly UF-induced) Overflowing point but we don't use it in that case + maPostChainingSel = ESelection(aSelAtUFTime.nStartPara-maOverflowPosSel.nStartPara, + aSelAtUFTime.nStartPos-maOverflowPosSel.nStartPos ); + } + + // XXX: It may not be necessary anymore to keep this method separated from EditingTextChainFlow::impBroadcastCursorInfo +} + +void TextChainFlow::CheckForFlowEvents(SdrOutliner *pFlowOutl) +{ + impCheckForFlowEvents(pFlowOutl, nullptr); +} + + +bool TextChainFlow::IsOverflow() const +{ + return bOverflow; +} + +bool TextChainFlow::IsUnderflow() const +{ + return bUnderflow; +} + + +// XXX: In editing mode you need to get "underflowing" text from editing outliner, so it's kinda separate from the drawing one! + +// XXX:Would it be possible to unify underflow and its possibly following overflow? +void TextChainFlow::ExecuteUnderflow(SdrOutliner *pOutl) +{ + //GetTextChain()->SetNilChainingEvent(mpTargetLink, true); + // making whole text + // merges underflowing text with the one in the next box + std::optional<OutlinerParaObject> pNewText = mpUnderflChText->CreateMergedUnderflowParaObject(pOutl, mpNextLink->GetOutlinerParaObject()); + + // Set the other box empty; it will be replaced by the rest of the text if overflow occurs + if (!mpTargetLink->GetPreventChainable()) + mpNextLink->NbcSetOutlinerParaObject(pOutl->GetEmptyParaObject()); + + // We store the size since NbcSetOutlinerParaObject can change it + //Size aOldSize = pOutl->GetMaxAutoPaperSize(); + + // This should not be done in editing mode!! //XXX + if (!mpTargetLink->IsInEditMode()) + { + mpTargetLink->NbcSetOutlinerParaObject(pNewText); + } + + // Restore size and set new text + //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX (it seems to be working anyway without this) + pOutl->SetText(*pNewText); + + //GetTextChain()->SetNilChainingEvent(mpTargetLink, false); + + // Check for new overflow + CheckForFlowEvents(pOutl); +} + +void TextChainFlow::ExecuteOverflow(SdrOutliner *pNonOverflOutl, SdrOutliner *pOverflOutl) +{ + //GetTextChain()->SetNilChainingEvent(mpTargetLink, true); + // Leave only non overflowing text + impLeaveOnlyNonOverflowingText(pNonOverflOutl); + + // Transfer of text to next link + if (!mpTargetLink->GetPreventChainable() ) // we don't transfer text while dragging because of resizing + { + impMoveChainedTextToNextLink(pOverflOutl); + } + + //GetTextChain()->SetNilChainingEvent(mpTargetLink, false); +} + +void TextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner *pNonOverflOutl) +{ + std::optional<OutlinerParaObject> pNewText = mpOverflChText->RemoveOverflowingText(pNonOverflOutl); + + SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] SOURCE box set to " + << pNewText->GetTextObject().GetParagraphCount() << " paras"); + + // adds it to current outliner anyway (useful in static decomposition) + pNonOverflOutl->SetText(*pNewText); + + mpTargetLink->NbcSetOutlinerParaObject(std::move(pNewText)); + // For some reason the paper size is lost after last instruction, so we set it. + pNonOverflOutl->SetPaperSize(Size(pNonOverflOutl->GetPaperSize().Width(), + pNonOverflOutl->GetTextHeight())); + +} + +void TextChainFlow::impMoveChainedTextToNextLink(SdrOutliner *pOverflOutl) +{ + // prevent copying text in same box + if ( mpNextLink == mpTargetLink ) { + SAL_INFO("svx.chaining", "[CHAINING] Trying to copy text for next link in same object"); + return; + } + + std::optional<OutlinerParaObject> pNewText = + mpOverflChText->InsertOverflowingText(pOverflOutl, + mpNextLink->GetOutlinerParaObject()); + SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] DEST box set to " + << pNewText->GetTextObject().GetParagraphCount() << " paras"); + + if (pNewText) + mpNextLink->NbcSetOutlinerParaObject(std::move(pNewText)); + + // Set Deep Merge status + SAL_INFO("svx.chaining", "[DEEPMERGE] Setting deepMerge to " + << mpOverflChText->IsLastParaInterrupted()); + GetTextChain()->SetIsPartOfLastParaInNextLink( + mpTargetLink, + mpOverflChText->IsLastParaInterrupted()); +} + +SdrTextObj *TextChainFlow::GetLinkTarget() const +{ + return mpTargetLink; +} + +TextChain *TextChainFlow::GetTextChain() const +{ + return mpTextChain; +} + +// EditingTextChainFlow + +EditingTextChainFlow::EditingTextChainFlow(SdrTextObj *pLinkTarget) : + TextChainFlow(pLinkTarget) +{ + SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new EditingTextChainFlow"); +} + +void EditingTextChainFlow::CheckForFlowEvents(SdrOutliner *pFlowOutl) +{ + // if this is editing outliner no need to set parameters + if (pFlowOutl == GetLinkTarget()->mpEditingOutliner) + impCheckForFlowEvents(pFlowOutl, nullptr); + else + impCheckForFlowEvents(pFlowOutl, GetLinkTarget()->mpEditingOutliner); + + // Broadcast events for cursor handling + impBroadcastCursorInfo(); +} + +void EditingTextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner *pNonOverflOutl) +{ + mpOverflChText->RemoveOverflowingText(pNonOverflOutl); + //impSetTextForEditingOutliner(pNewText); //XXX: Don't call it since we do everything with NonOverflowingText::ToParaObject // XXX: You may need this for Underflow + + // XXX: I'm not sure whether we need this (after all operations such as Paste don't change this - as far as I understand) + //GetLinkTarget()->NbcSetOutlinerParaObject(pNewText); +} + +void EditingTextChainFlow::impSetFlowOutlinerParams(SdrOutliner *pFlowOutl, SdrOutliner *pParamOutl) +{ + // Set right size for overflow + pFlowOutl->SetMaxAutoPaperSize(pParamOutl->GetMaxAutoPaperSize()); + pFlowOutl->SetMinAutoPaperSize(pParamOutl->GetMinAutoPaperSize()); + pFlowOutl->SetPaperSize(pParamOutl->GetPaperSize()); +} + +void EditingTextChainFlow::impBroadcastCursorInfo() const +{ + ESelection aPreChainingSel = GetTextChain()->GetPreChainingSel(GetLinkTarget()) ; + + // Test whether the cursor is out of the box. + bool bCursorOut = mbPossiblyCursorOut && maOverflowPosSel < aPreChainingSel; + + // NOTE: I handled already the stuff for the comments below. They will be kept temporarily till stuff settles down. + // Possibility: 1) why don't we stop passing the actual event to the TextChain and instead we pass + // the overflow pos and mbPossiblyCursorOut + // 2) We pass the current selection before anything happens and we make impBroadcastCursorInfo compute it. + + + if (bCursorOut) { + //maCursorEvent = CursorChainingEvent::TO_NEXT_LINK; + GetTextChain()->SetPostChainingSel(GetLinkTarget(), maPostChainingSel); + GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::TO_NEXT_LINK); + } else { + //maCursorEvent = CursorChainingEvent::UNCHANGED; + GetTextChain()->SetPostChainingSel(GetLinkTarget(), aPreChainingSel); + GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::UNCHANGED); + } + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |