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 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdoutl.hxx>
23 #include <editeng/outlobj.hxx>
24 #include <editeng/editobj.hxx>
25 #include <editeng/overflowingtxt.hxx>
26 #include <textchainflow.hxx>
27 #include <sal/log.hxx>
29 TextChainFlow::TextChainFlow(SdrTextObj
*pChainTarget
)
30 : mpTargetLink(pChainTarget
)
32 SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new TextChainFlow");
34 mpTextChain
= mpTargetLink
->GetTextChain();
35 mpNextLink
= mpTargetLink
->GetNextLinkInChain();
37 bUnderflow
= bOverflow
= false;
39 mbOFisUFinduced
= false;
41 mpOverflChText
= nullptr;
42 mpUnderflChText
= nullptr;
44 mbPossiblyCursorOut
= false;
48 TextChainFlow::~TextChainFlow()
50 mpOverflChText
.reset();
51 mpUnderflChText
.reset();
54 void TextChainFlow::impSetFlowOutlinerParams(SdrOutliner
*, SdrOutliner
*)
56 // Nothing to do if not in editing mode
60 * Check for overflow in the state of pFlowOutl.
61 * If pParamOutl is not NULL sets some parameters from there.
62 * This is useful in case the outliner is not set for overflow
63 * (e.g. in editing mode we check for overflow in drawing outl but
64 * parameters come from editing outliner)
66 void TextChainFlow::impCheckForFlowEvents(SdrOutliner
*pFlowOutl
, SdrOutliner
*pParamOutl
)
68 bool bOldUpdateMode
= pFlowOutl
->GetUpdateMode();
70 // XXX: This could be reorganized moving most of this stuff inside EditingTextChainFlow
71 if (pParamOutl
!= nullptr)
73 // We need this since it's required to check overflow
74 pFlowOutl
->SetUpdateMode(true);
76 // XXX: does this work if you do it before setting the text? Seems so.
77 impSetFlowOutlinerParams(pFlowOutl
, pParamOutl
);
80 bool bIsPageOverflow
= pFlowOutl
->IsPageOverflow();
82 // NOTE: overflow and underflow cannot be both true
83 bOverflow
= bIsPageOverflow
&& mpNextLink
;
84 bUnderflow
= !bIsPageOverflow
&& mpNextLink
&& mpNextLink
->HasText();
86 // Get old state on whether to merge para-s or not
87 // NOTE: We handle UF/OF using the _old_ state. The new one is simply saved
88 bool bMustMergeParaAmongLinks
= GetTextChain()->GetIsPartOfLastParaInNextLink(mpTargetLink
);
90 // Set (Non)OverflowingTxt here (if any)
92 // If we had an underflow before we have to deep merge paras anyway
93 bool bMustMergeParaOF
= bMustMergeParaAmongLinks
|| mbOFisUFinduced
;
95 mpOverflChText
.reset( bOverflow
?
96 new OFlowChainedText(pFlowOutl
, bMustMergeParaOF
) :
99 // Set current underflowing text (if any)
100 mpUnderflChText
.reset( bUnderflow
?
101 new UFlowChainedText(pFlowOutl
, bMustMergeParaAmongLinks
) :
104 // Reset update mode // Reset it here because we use WriteRTF (needing updatemode = true) in the two constructors above
105 if (!bOldUpdateMode
) // Reset only if the old value was false
106 pFlowOutl
->SetUpdateMode(bOldUpdateMode
);
108 // NOTE: Must be called after mp*ChText abd b*flow have been set but before mbOFisUFinduced is reset
109 impUpdateCursorInfo();
111 // To check whether an overflow is underflow induced or not (useful in cursor checking)
112 mbOFisUFinduced
= bUnderflow
;
115 void TextChainFlow::impUpdateCursorInfo()
117 // XXX: Maybe we can get rid of mbOFisUFinduced by not allowing handling of more than one event by the same TextChainFlow
118 // if this is not an OF triggered during an UF
120 mbPossiblyCursorOut
= bOverflow
;
122 if(mbPossiblyCursorOut
) {
123 maOverflowPosSel
= mpOverflChText
->GetOverflowPointSel();
124 ESelection aSelAtUFTime
= GetTextChain()->GetPreChainingSel(GetLinkTarget());
125 // Might be an invalid selection if the cursor at UF time was before
126 // the (possibly UF-induced) Overflowing point but we don't use it in that case
127 maPostChainingSel
= ESelection(aSelAtUFTime
.nStartPara
-maOverflowPosSel
.nStartPara
,
128 aSelAtUFTime
.nStartPos
-maOverflowPosSel
.nStartPos
);
131 // XXX: It may not be necessary anymore to keep this method separated from EditingTextChainFlow::impBroadcastCursorInfo
134 void TextChainFlow::CheckForFlowEvents(SdrOutliner
*pFlowOutl
)
136 impCheckForFlowEvents(pFlowOutl
, nullptr);
140 bool TextChainFlow::IsOverflow() const
145 bool TextChainFlow::IsUnderflow() const
151 // XXX: In editing mode you need to get "underflowing" text from editing outliner, so it's kinda separate from the drawing one!
153 // XXX:Would it be possible to unify underflow and its possibly following overflow?
154 void TextChainFlow::ExecuteUnderflow(SdrOutliner
*pOutl
)
156 //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
158 // merges underflowing text with the one in the next box
159 std::unique_ptr
<OutlinerParaObject
> pNewText
= mpUnderflChText
->CreateMergedUnderflowParaObject(pOutl
, mpNextLink
->GetOutlinerParaObject());
161 // Set the other box empty; it will be replaced by the rest of the text if overflow occurs
162 if (!mpTargetLink
->GetPreventChainable())
163 mpNextLink
->NbcSetOutlinerParaObject(pOutl
->GetEmptyParaObject());
165 // We store the size since NbcSetOutlinerParaObject can change it
166 //Size aOldSize = pOutl->GetMaxAutoPaperSize();
168 auto pNewTextTemp
= pNewText
.get(); // because we need to access it after a std::move
169 // This should not be done in editing mode!! //XXX
170 if (!mpTargetLink
->IsInEditMode())
172 mpTargetLink
->NbcSetOutlinerParaObject(std::move(pNewText
));
175 // Restore size and set new text
176 //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX (it seems to be working anyway without this)
177 pOutl
->SetText(*pNewTextTemp
);
179 //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
181 // Check for new overflow
182 CheckForFlowEvents(pOutl
);
185 void TextChainFlow::ExecuteOverflow(SdrOutliner
*pNonOverflOutl
, SdrOutliner
*pOverflOutl
)
187 //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
188 // Leave only non overflowing text
189 impLeaveOnlyNonOverflowingText(pNonOverflOutl
);
191 // Transfer of text to next link
192 if (!mpTargetLink
->GetPreventChainable() ) // we don't transfer text while dragging because of resizing
194 impMoveChainedTextToNextLink(pOverflOutl
);
197 //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
200 void TextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner
*pNonOverflOutl
)
202 std::unique_ptr
<OutlinerParaObject
> pNewText
= mpOverflChText
->RemoveOverflowingText(pNonOverflOutl
);
204 SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] SOURCE box set to "
205 << pNewText
->GetTextObject().GetParagraphCount() << " paras");
207 // adds it to current outliner anyway (useful in static decomposition)
208 pNonOverflOutl
->SetText(*pNewText
);
210 mpTargetLink
->NbcSetOutlinerParaObject(std::move(pNewText
));
211 // For some reason the paper size is lost after last instruction, so we set it.
212 pNonOverflOutl
->SetPaperSize(Size(pNonOverflOutl
->GetPaperSize().Width(),
213 pNonOverflOutl
->GetTextHeight()));
217 void TextChainFlow::impMoveChainedTextToNextLink(SdrOutliner
*pOverflOutl
)
219 // prevent copying text in same box
220 if ( mpNextLink
== mpTargetLink
) {
221 SAL_INFO("svx.chaining", "[CHAINING] Trying to copy text for next link in same object");
225 std::unique_ptr
<OutlinerParaObject
> pNewText
=
226 mpOverflChText
->InsertOverflowingText(pOverflOutl
,
227 mpNextLink
->GetOutlinerParaObject());
228 SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] DEST box set to "
229 << pNewText
->GetTextObject().GetParagraphCount() << " paras");
232 mpNextLink
->NbcSetOutlinerParaObject(std::move(pNewText
));
234 // Set Deep Merge status
235 SAL_INFO("svx.chaining", "[DEEPMERGE] Setting deepMerge to "
236 << mpOverflChText
->IsLastParaInterrupted());
237 GetTextChain()->SetIsPartOfLastParaInNextLink(
239 mpOverflChText
->IsLastParaInterrupted());
242 SdrTextObj
*TextChainFlow::GetLinkTarget() const
247 TextChain
*TextChainFlow::GetTextChain() const
252 // EditingTextChainFlow
254 EditingTextChainFlow::EditingTextChainFlow(SdrTextObj
*pLinkTarget
) :
255 TextChainFlow(pLinkTarget
)
257 SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new EditingTextChainFlow");
260 void EditingTextChainFlow::CheckForFlowEvents(SdrOutliner
*pFlowOutl
)
262 // if this is editing outliner no need to set parameters
263 if (pFlowOutl
== GetLinkTarget()->pEdtOutl
)
264 impCheckForFlowEvents(pFlowOutl
, nullptr);
266 impCheckForFlowEvents(pFlowOutl
, GetLinkTarget()->pEdtOutl
);
268 // Broadcast events for cursor handling
269 impBroadcastCursorInfo();
272 void EditingTextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner
*pNonOverflOutl
)
274 mpOverflChText
->RemoveOverflowingText(pNonOverflOutl
);
275 //impSetTextForEditingOutliner(pNewText); //XXX: Don't call it since we do everything with NonOverflowingText::ToParaObject // XXX: You may need this for Underflow
277 // XXX: I'm not sure whether we need this (after all operations such as Paste don't change this - as far as I understand)
278 //GetLinkTarget()->NbcSetOutlinerParaObject(pNewText);
281 void EditingTextChainFlow::impSetFlowOutlinerParams(SdrOutliner
*pFlowOutl
, SdrOutliner
*pParamOutl
)
283 // Set right size for overflow
284 pFlowOutl
->SetMaxAutoPaperSize(pParamOutl
->GetMaxAutoPaperSize());
285 pFlowOutl
->SetMinAutoPaperSize(pParamOutl
->GetMinAutoPaperSize());
286 pFlowOutl
->SetPaperSize(pParamOutl
->GetPaperSize());
289 void EditingTextChainFlow::impBroadcastCursorInfo() const
291 ESelection aPreChainingSel
= GetTextChain()->GetPreChainingSel(GetLinkTarget()) ;
293 // Test whether the cursor is out of the box.
294 bool bCursorOut
= mbPossiblyCursorOut
&& maOverflowPosSel
< aPreChainingSel
;
296 // NOTE: I handled already the stuff for the comments below. They will be kept temporarily till stuff settles down.
297 // Possibility: 1) why don't we stop passing the actual event to the TextChain and instead we pass
298 // the overflow pos and mbPossiblyCursorOut
299 // 2) We pass the current selection before anything happens and we make impBroadcastCursorInfo compute it.
303 //maCursorEvent = CursorChainingEvent::TO_NEXT_LINK;
304 GetTextChain()->SetPostChainingSel(GetLinkTarget(), maPostChainingSel
);
305 GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::TO_NEXT_LINK
);
307 //maCursorEvent = CursorChainingEvent::UNCHANGED;
308 GetTextChain()->SetPostChainingSel(GetLinkTarget(), aPreChainingSel
);
309 GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::UNCHANGED
);
315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */