c1c679deca
... because "update" is such a generic term I keep forgetting what we are turning on and off Also return the previous value from SetUpdateLayout to make the save/restore code more compact. Change-Id: Iae1764c837a92e58c9b17521f130e8fc80311d22 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121479 Tested-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
314 lines
12 KiB
C++
314 lines
12 KiB
C++
/* -*- 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: */
|