Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/bigint.hxx>
21 : #include "pagefrm.hxx"
22 : #include "txtfrm.hxx"
23 : #include <doc.hxx>
24 : #include <IDocumentUndoRedo.hxx>
25 : #include <IDocumentSettingAccess.hxx>
26 : #include <IDocumentDrawModelAccess.hxx>
27 : #include "frmtool.hxx"
28 : #include "dflyobj.hxx"
29 : #include "hints.hxx"
30 : #include <fmtornt.hxx>
31 : #include <fmtfsize.hxx>
32 : #include <fmtsrnd.hxx>
33 : #include <txatbase.hxx>
34 :
35 : #include "tabfrm.hxx"
36 : #include "flyfrms.hxx"
37 : #include "crstate.hxx"
38 : #include "sectfrm.hxx"
39 :
40 : #include <tocntntanchoredobjectposition.hxx>
41 : #include <dcontact.hxx>
42 : #include <sortedobjs.hxx>
43 : #include <layouter.hxx>
44 : #include <objectformattertxtfrm.hxx>
45 : #include <HandleAnchorNodeChg.hxx>
46 :
47 : using namespace ::com::sun::star;
48 :
49 : namespace
50 : {
51 :
52 10 : static inline SwTwips lcl_GetTopForObjPos(const SwContentFrm* pCnt, const bool bVert, const bool bVertL2R)
53 : {
54 10 : if ( bVert )
55 : {
56 0 : SwTwips aResult = pCnt->Frm().Left();
57 0 : if ( bVertL2R )
58 0 : aResult += pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid();
59 : else
60 0 : aResult += pCnt->Frm().Width() - pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid();
61 0 : return aResult;
62 : }
63 : else
64 10 : return pCnt->Frm().Top() + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid();
65 : }
66 :
67 : }
68 :
69 1231 : SwFlyAtCntFrm::SwFlyAtCntFrm( SwFlyFrameFormat *pFormat, SwFrm* pSib, SwFrm *pAnch ) :
70 1231 : SwFlyFreeFrm( pFormat, pSib, pAnch )
71 : {
72 1231 : bAtCnt = true;
73 1231 : bAutoPosition = (FLY_AT_CHAR == pFormat->GetAnchor().GetAnchorId());
74 1231 : }
75 :
76 : // #i28701#
77 823762 : TYPEINIT1(SwFlyAtCntFrm,SwFlyFreeFrm);
78 :
79 62 : void SwFlyAtCntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
80 : {
81 62 : const sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
82 62 : const SwFormatAnchor *pAnch = 0;
83 :
84 92 : if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET ==
85 30 : static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false,
86 30 : reinterpret_cast<const SfxPoolItem**>(&pAnch) ))
87 : ; // The anchor pointer is set at GetItemState!
88 :
89 62 : else if( RES_ANCHOR == nWhich )
90 : {
91 : //Change anchor, I move myself to a new place.
92 : //The anchor type must not change, this is only possible using
93 : //SwFEShell.
94 0 : pAnch = static_cast<const SwFormatAnchor*>(pNew);
95 : }
96 :
97 62 : if( pAnch )
98 : {
99 : OSL_ENSURE( pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(),
100 : "Illegal change of anchor type. " );
101 :
102 : //Unregister, get hold of a new anchor and attach it
103 0 : SwRect aOld( GetObjRectWithSpaces() );
104 0 : SwPageFrm *pOldPage = FindPageFrm();
105 0 : const SwFrm *pOldAnchor = GetAnchorFrm();
106 0 : SwContentFrm *pContent = const_cast<SwContentFrm*>(static_cast<const SwContentFrm*>(GetAnchorFrm()));
107 0 : AnchorFrm()->RemoveFly( this );
108 :
109 0 : const bool bBodyFootnote = (pContent->IsInDocBody() || pContent->IsInFootnote());
110 :
111 : // Search the new anchor using the NodeIdx; the relation between old
112 : // and new NodeIdx determines the search direction
113 0 : const SwNodeIndex aNewIdx( pAnch->GetContentAnchor()->nNode );
114 0 : SwNodeIndex aOldIdx( *pContent->GetNode() );
115 :
116 : //fix: depending on which index was smaller, searching in the do-while
117 : //loop previously was done forward or backwards respectively. This however
118 : //could lead to an infinite loop. To at least avoid the loop, searching
119 : //is now done in only one direction. Getting hold of a frame from the node
120 : //is still possible if the new anchor could not be found. Chances are
121 : //good that this will be the correct one.
122 0 : const bool bNext = aOldIdx < aNewIdx;
123 : // consider the case that at found anchor frame candidate already a
124 : // fly frame of the given fly format is registered.
125 : // consider, that <pContent> is the already
126 : // the new anchor frame.
127 0 : bool bFound( aOldIdx == aNewIdx );
128 0 : while ( pContent && !bFound )
129 : {
130 0 : do
131 : {
132 0 : if ( bNext )
133 0 : pContent = pContent->GetNextContentFrm();
134 : else
135 0 : pContent = pContent->GetPrevContentFrm();
136 0 : } while ( pContent &&
137 0 : !( bBodyFootnote == ( pContent->IsInDocBody() ||
138 0 : pContent->IsInFootnote() ) ) );
139 0 : if ( pContent )
140 0 : aOldIdx = *pContent->GetNode();
141 :
142 : // check, if at found anchor frame candidate already a fly frame
143 : // of the given fly frame format is registered.
144 0 : bFound = aOldIdx == aNewIdx;
145 0 : if (bFound && pContent && pContent->GetDrawObjs())
146 : {
147 0 : SwFrameFormat* pMyFlyFrameFormat( &GetFrameFormat() );
148 0 : SwSortedObjs &rObjs = *pContent->GetDrawObjs();
149 0 : for( size_t i = 0; i < rObjs.size(); ++i)
150 : {
151 0 : SwFlyFrm* pFlyFrm = dynamic_cast<SwFlyFrm*>(rObjs[i]);
152 0 : if ( pFlyFrm &&
153 0 : &(pFlyFrm->GetFrameFormat()) == pMyFlyFrameFormat )
154 : {
155 0 : bFound = false;
156 0 : break;
157 : }
158 : }
159 : }
160 : }
161 0 : if ( !pContent )
162 : {
163 0 : SwContentNode *pNode = aNewIdx.GetNode().GetContentNode();
164 0 : pContent = pNode->getLayoutFrm( getRootFrm(), &pOldAnchor->Frm().Pos(), 0, false );
165 : OSL_ENSURE( pContent, "Neuen Anker nicht gefunden" );
166 : }
167 : //Flys are never attached to a follow, but always on the master which
168 : //we are going to search now.
169 0 : SwContentFrm* pFlow = pContent;
170 0 : while ( pFlow->IsFollow() )
171 0 : pFlow = pFlow->FindMaster();
172 0 : pContent = pFlow;
173 :
174 : //and *puff* it's attached...
175 0 : pContent->AppendFly( this );
176 0 : if ( pOldPage && pOldPage != FindPageFrm() )
177 0 : NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE );
178 :
179 : //Fix(3495)
180 0 : _InvalidatePos();
181 0 : InvalidatePage();
182 0 : SetNotifyBack();
183 : // #i28701# - reset member <maLastCharRect> and
184 : // <mnLastTopOfLine> for to-character anchored objects.
185 0 : ClearCharRectAndTopOfLine();
186 : }
187 : else
188 62 : SwFlyFrm::Modify( pOld, pNew );
189 62 : }
190 :
191 : //We need some helper classes to monitor the oscillation and a few functions
192 : //to not get lost.
193 :
194 : // #i3317# - re-factoring of the position stack
195 : class SwOszControl
196 : {
197 : static const SwFlyFrm *pStk1;
198 : static const SwFlyFrm *pStk2;
199 : static const SwFlyFrm *pStk3;
200 : static const SwFlyFrm *pStk4;
201 : static const SwFlyFrm *pStk5;
202 :
203 : const SwFlyFrm *pFly;
204 : // #i3317#
205 : sal_uInt8 mnPosStackSize;
206 : std::vector<Point*> maObjPositions;
207 :
208 : public:
209 : explicit SwOszControl( const SwFlyFrm *pFrm );
210 : ~SwOszControl();
211 : bool ChkOsz();
212 : static bool IsInProgress( const SwFlyFrm *pFly );
213 : };
214 :
215 : const SwFlyFrm *SwOszControl::pStk1 = 0;
216 : const SwFlyFrm *SwOszControl::pStk2 = 0;
217 : const SwFlyFrm *SwOszControl::pStk3 = 0;
218 : const SwFlyFrm *SwOszControl::pStk4 = 0;
219 : const SwFlyFrm *SwOszControl::pStk5 = 0;
220 :
221 2893 : SwOszControl::SwOszControl( const SwFlyFrm *pFrm )
222 : : pFly( pFrm ),
223 : // #i3317#
224 2893 : mnPosStackSize( 20 )
225 : {
226 2893 : if ( !SwOszControl::pStk1 )
227 2893 : SwOszControl::pStk1 = pFly;
228 0 : else if ( !SwOszControl::pStk2 )
229 0 : SwOszControl::pStk2 = pFly;
230 0 : else if ( !SwOszControl::pStk3 )
231 0 : SwOszControl::pStk3 = pFly;
232 0 : else if ( !SwOszControl::pStk4 )
233 0 : SwOszControl::pStk4 = pFly;
234 0 : else if ( !SwOszControl::pStk5 )
235 0 : SwOszControl::pStk5 = pFly;
236 2893 : }
237 :
238 5786 : SwOszControl::~SwOszControl()
239 : {
240 2893 : if ( SwOszControl::pStk1 == pFly )
241 2893 : SwOszControl::pStk1 = 0;
242 0 : else if ( SwOszControl::pStk2 == pFly )
243 0 : SwOszControl::pStk2 = 0;
244 0 : else if ( SwOszControl::pStk3 == pFly )
245 0 : SwOszControl::pStk3 = 0;
246 0 : else if ( SwOszControl::pStk4 == pFly )
247 0 : SwOszControl::pStk4 = 0;
248 0 : else if ( SwOszControl::pStk5 == pFly )
249 0 : SwOszControl::pStk5 = 0;
250 : // #i3317#
251 7269 : while ( !maObjPositions.empty() )
252 : {
253 1483 : Point* pPos = maObjPositions.back();
254 1483 : delete pPos;
255 :
256 1483 : maObjPositions.pop_back();
257 : }
258 2893 : }
259 :
260 11738 : bool SwOszControl::IsInProgress( const SwFlyFrm *pFly )
261 : {
262 11738 : if ( SwOszControl::pStk1 && !pFly->IsLowerOf( SwOszControl::pStk1 ) )
263 0 : return true;
264 11738 : if ( SwOszControl::pStk2 && !pFly->IsLowerOf( SwOszControl::pStk2 ) )
265 0 : return true;
266 11738 : if ( SwOszControl::pStk3 && !pFly->IsLowerOf( SwOszControl::pStk3 ) )
267 0 : return true;
268 11738 : if ( SwOszControl::pStk4 && !pFly->IsLowerOf( SwOszControl::pStk4 ) )
269 0 : return true;
270 11738 : if ( SwOszControl::pStk5 && !pFly->IsLowerOf( SwOszControl::pStk5 ) )
271 0 : return true;
272 11738 : return false;
273 : }
274 :
275 1483 : bool SwOszControl::ChkOsz()
276 : {
277 1483 : bool bOscillationDetected = false;
278 :
279 1483 : if ( maObjPositions.size() == mnPosStackSize )
280 : {
281 : // position stack is full -> oscillation
282 0 : bOscillationDetected = true;
283 : }
284 : else
285 : {
286 1483 : Point* pNewObjPos = new Point( pFly->GetObjRect().Pos() );
287 4449 : for ( std::vector<Point*>::iterator aObjPosIter = maObjPositions.begin();
288 2966 : aObjPosIter != maObjPositions.end();
289 : ++aObjPosIter )
290 : {
291 0 : if ( *(pNewObjPos) == *(*aObjPosIter) )
292 : {
293 : // position already occurred -> oscillation
294 0 : bOscillationDetected = true;
295 0 : delete pNewObjPos;
296 0 : break;
297 : }
298 : }
299 1483 : if ( !bOscillationDetected )
300 : {
301 1483 : maObjPositions.push_back( pNewObjPos );
302 : }
303 : }
304 :
305 1483 : return bOscillationDetected;
306 : }
307 :
308 : /**
309 : |* With a paragraph-anchored fly it's absolutely possible that
310 : |* the anchor reacts to changes of the fly. To this reaction the fly must
311 : |* certaily react too. Sadly this can lead to oscillations; for example the
312 : |* fly wants to go down therefore the content can go up - this leads to a
313 : |* smaller TextFrm thus the fly needs to go up again whereby the text will
314 : |* get pushed down...
315 : |* To avoid such oscillations, a small position stack is built. If the fly
316 : |* reaches a position which it already had once, the action is stopped.
317 : |* To not run into problems, the stack is designed to hold five positions.
318 : |* If the stack flows over, the action is stopped too.
319 : |* Cancellation leads to the situation that the fly has a bad position in
320 : |* the end. In case of cancellation, the frame is set to automatic top
321 : |* alignment to not trigger a 'big oscillation' when calling from outside
322 : |* again.
323 : |*/
324 2893 : void SwFlyAtCntFrm::MakeAll()
325 : {
326 2893 : if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
327 : {
328 2893 : return;
329 : }
330 :
331 2893 : if ( !SwOszControl::IsInProgress( this ) && !IsLocked() && !IsColLocked() )
332 : {
333 : // #i28701# - use new method <GetPageFrm()>
334 2893 : if( !GetPageFrm() && GetAnchorFrm() && GetAnchorFrm()->IsInFly() )
335 : {
336 0 : SwFlyFrm* pFly = AnchorFrm()->FindFlyFrm();
337 0 : SwPageFrm *pTmpPage = pFly ? pFly->FindPageFrm() : NULL;
338 0 : if( pTmpPage )
339 0 : pTmpPage->AppendFlyToPage( this );
340 : }
341 : // #i28701# - use new method <GetPageFrm()>
342 2893 : if( GetPageFrm() )
343 : {
344 2893 : bSetCompletePaintOnInvalidate = true;
345 : {
346 2893 : SwFlyFrameFormat *pFormat = GetFormat();
347 2893 : const SwFormatFrmSize &rFrmSz = GetFormat()->GetFrmSize();
348 5783 : if( rFrmSz.GetHeightPercent() != 0xFF &&
349 2890 : rFrmSz.GetHeightPercent() >= 100 )
350 : {
351 0 : pFormat->LockModify();
352 0 : SwFormatSurround aMain( pFormat->GetSurround() );
353 0 : if ( aMain.GetSurround() == SURROUND_NONE )
354 : {
355 0 : aMain.SetSurround( SURROUND_THROUGHT );
356 0 : pFormat->SetFormatAttr( aMain );
357 : }
358 0 : pFormat->UnlockModify();
359 : }
360 : }
361 :
362 2893 : SwOszControl aOszCntrl( this );
363 :
364 : // #i43255#
365 : // #i50356# - format the anchor frame, which
366 : // contains the anchor position. E.g., for at-character anchored
367 : // object this can be the follow frame of the anchor frame.
368 : const bool bFormatAnchor =
369 5786 : !static_cast<const SwTextFrm*>( GetAnchorFrmContainingAnchPos() )->IsAnyJoinLocked() &&
370 5126 : !ConsiderObjWrapInfluenceOnObjPos() &&
371 5126 : !ConsiderObjWrapInfluenceOfOtherObjs();
372 :
373 2893 : const SwFrm* pFooter = GetAnchorFrm()->FindFooterOrHeader();
374 2893 : if( pFooter && !pFooter->IsFooterFrm() )
375 694 : pFooter = NULL;
376 2893 : bool bOsz = false;
377 2893 : bool bExtra = Lower() && Lower()->IsColumnFrm();
378 : // #i3317# - boolean, to apply temporarly the
379 : // 'straightforward positioning process' for the frame due to its
380 : // overlapping with a previous column.
381 2893 : bool bConsiderWrapInfluenceDueToOverlapPrevCol( false );
382 : // #i35911# - boolean, to apply temporarly the
383 : // 'straightforward positioning process' for the frame due to fact
384 : // that it causes the complete content of its layout environment
385 : // to move forward.
386 : // #i40444# - extend usage of this boolean:
387 : // apply temporarly the 'straightforward positioning process' for
388 : // the frame due to the fact that the frame clears the area for
389 : // the anchor frame, thus it has to move forward.
390 2893 : bool bConsiderWrapInfluenceDueToMovedFwdAnchor( false );
391 8697 : do {
392 2902 : SWRECTFN( this )
393 2902 : Point aOldPos( (Frm().*fnRect->fnGetPos)() );
394 2902 : SwFlyFreeFrm::MakeAll();
395 : const bool bPosChgDueToOwnFormat =
396 2902 : aOldPos != (Frm().*fnRect->fnGetPos)();
397 : // #i3317#
398 5144 : if ( !ConsiderObjWrapInfluenceOnObjPos() &&
399 2242 : OverlapsPrevColumn() )
400 : {
401 0 : bConsiderWrapInfluenceDueToOverlapPrevCol = true;
402 : }
403 : // #i28701# - no format of anchor frame, if
404 : // wrapping style influence is considered on object positioning
405 2902 : if ( bFormatAnchor )
406 : {
407 : SwTextFrm& rAnchPosAnchorFrm =
408 1927 : dynamic_cast<SwTextFrm&>(*GetAnchorFrmContainingAnchPos());
409 : // #i58182# - For the usage of new method
410 : // <SwObjectFormatterTextFrm::CheckMovedFwdCondition(..)>
411 : // to check move forward of anchor frame due to the object
412 : // positioning it's needed to know, if the object is anchored
413 : // at the master frame before the anchor frame is formatted.
414 1927 : const bool bAnchoredAtMaster(!rAnchPosAnchorFrm.IsFollow());
415 :
416 : // #i56300#
417 : // perform complete format of anchor text frame and its
418 : // previous frames, which have become invalid due to the
419 : // fly frame format.
420 1927 : SwObjectFormatterTextFrm::FormatAnchorFrmAndItsPrevs( rAnchPosAnchorFrm );
421 : // #i35911#
422 : // #i40444#
423 : // #i58182# - usage of new method
424 : // <SwObjectFormatterTextFrm::CheckMovedFwdCondition(..)>
425 1927 : sal_uInt32 nToPageNum( 0L );
426 1927 : bool bDummy( false );
427 1927 : if ( SwObjectFormatterTextFrm::CheckMovedFwdCondition(
428 1927 : *this, GetPageFrm()->GetPhyPageNum(),
429 3854 : bAnchoredAtMaster, nToPageNum, bDummy ) )
430 : {
431 1 : bConsiderWrapInfluenceDueToMovedFwdAnchor = true;
432 : // mark anchor text frame
433 : // directly, that it is moved forward by object positioning.
434 1 : SwTextFrm* pAnchorTextFrm( static_cast<SwTextFrm*>(AnchorFrm()) );
435 1 : bool bInsert( true );
436 1 : sal_uInt32 nAnchorFrmToPageNum( 0L );
437 1 : const SwDoc& rDoc = *(GetFrameFormat().GetDoc());
438 1 : if ( SwLayouter::FrmMovedFwdByObjPos(
439 : rDoc, *pAnchorTextFrm, nAnchorFrmToPageNum ) )
440 : {
441 0 : if ( nAnchorFrmToPageNum < nToPageNum )
442 0 : SwLayouter::RemoveMovedFwdFrm( rDoc, *pAnchorTextFrm );
443 : else
444 0 : bInsert = false;
445 : }
446 1 : if ( bInsert )
447 : {
448 : SwLayouter::InsertMovedFwdFrm( rDoc, *pAnchorTextFrm,
449 1 : nToPageNum );
450 : }
451 : }
452 : }
453 :
454 5804 : if ( aOldPos != (Frm().*fnRect->fnGetPos)() ||
455 1420 : ( !GetValidPosFlag() &&
456 1 : ( pFooter || bPosChgDueToOwnFormat ) ) )
457 : {
458 1483 : bOsz = aOszCntrl.ChkOsz();
459 :
460 : // special loop prevention for dedicated document:
461 1483 : if ( bOsz &&
462 1483 : HasFixSize() && IsClipped() &&
463 0 : GetAnchorFrm()->GetUpper()->IsCellFrm() )
464 : {
465 0 : SwFrameFormat* pFormat = GetFormat();
466 0 : const SwFormatFrmSize& rFrmSz = pFormat->GetFrmSize();
467 0 : if ( rFrmSz.GetWidthPercent() &&
468 0 : rFrmSz.GetHeightPercent() == 0xFF )
469 : {
470 0 : SwFormatSurround aSurround( pFormat->GetSurround() );
471 0 : if ( aSurround.GetSurround() == SURROUND_NONE )
472 : {
473 0 : pFormat->LockModify();
474 0 : aSurround.SetSurround( SURROUND_THROUGHT );
475 0 : pFormat->SetFormatAttr( aSurround );
476 0 : pFormat->UnlockModify();
477 0 : bOsz = false;
478 : OSL_FAIL( "<SwFlyAtCntFrm::MakeAll()> - special loop prevention for dedicated document of b6403541 applied" );
479 0 : }
480 : }
481 : }
482 : }
483 :
484 2902 : if ( bExtra && Lower() && !Lower()->GetValidPosFlag() )
485 : {
486 : // If a multi column frame leaves invalid columns because of
487 : // a position change, we loop once more and format
488 : // our content using FormatWidthCols again.
489 0 : _InvalidateSize();
490 0 : bExtra = false; // Ensure only one additional loop run
491 : }
492 2922 : } while ( !IsValid() && !bOsz &&
493 : // #i3317#
494 20 : !bConsiderWrapInfluenceDueToOverlapPrevCol &&
495 : // #i40444#
496 5832 : !bConsiderWrapInfluenceDueToMovedFwdAnchor &&
497 2929 : GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) );
498 :
499 : // #i3317# - instead of attribute change apply
500 : // temporarly the 'straightforward positioning process'.
501 : // #i80924#
502 : // handle special case during splitting of table rows
503 2894 : if ( bConsiderWrapInfluenceDueToMovedFwdAnchor &&
504 2893 : GetAnchorFrm()->IsInTab() &&
505 0 : GetAnchorFrm()->IsInFollowFlowRow() )
506 : {
507 0 : const SwFrm* pCellFrm = GetAnchorFrm();
508 0 : while ( pCellFrm && !pCellFrm->IsCellFrm() )
509 : {
510 0 : pCellFrm = pCellFrm->GetUpper();
511 : }
512 0 : if ( pCellFrm )
513 : {
514 0 : SWRECTFN( pCellFrm )
515 0 : if ( (pCellFrm->Frm().*fnRect->fnGetTop)() == 0 &&
516 0 : (pCellFrm->Frm().*fnRect->fnGetHeight)() == 0 )
517 : {
518 0 : bConsiderWrapInfluenceDueToMovedFwdAnchor = false;
519 : }
520 : }
521 : }
522 2893 : if ( bOsz || bConsiderWrapInfluenceDueToOverlapPrevCol ||
523 : // #i40444#
524 : bConsiderWrapInfluenceDueToMovedFwdAnchor )
525 : {
526 1 : SetTmpConsiderWrapInfluence( true );
527 1 : SetRestartLayoutProcess( true );
528 1 : SetTmpConsiderWrapInfluenceOfOtherObjs( true );
529 : }
530 2893 : bSetCompletePaintOnInvalidate = false;
531 : }
532 : }
533 : }
534 :
535 : /** method to determine, if a <MakeAll()> on the Writer fly frame is possible
536 :
537 : #i28701#
538 : */
539 8845 : bool SwFlyAtCntFrm::IsFormatPossible() const
540 : {
541 17690 : return SwFlyFreeFrm::IsFormatPossible() &&
542 17690 : !SwOszControl::IsInProgress( this );
543 : }
544 :
545 : class SwDistance
546 : {
547 : public:
548 : SwTwips nMain, nSub;
549 6 : SwDistance() { nMain = nSub = 0; }
550 11 : SwDistance& operator=( const SwDistance &rTwo )
551 11 : { nMain = rTwo.nMain; nSub = rTwo.nSub; return *this; }
552 2 : bool operator<( const SwDistance& rTwo ) const
553 3 : { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && nSub &&
554 2 : rTwo.nSub && nSub < rTwo.nSub ); }
555 8 : bool operator<=( const SwDistance& rTwo ) const
556 15 : { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && ( !nSub ||
557 8 : !rTwo.nSub || nSub <= rTwo.nSub ) ); }
558 : };
559 :
560 10 : static const SwFrm * lcl_CalcDownDist( SwDistance &rRet,
561 : const Point &rPt,
562 : const SwContentFrm *pCnt )
563 : {
564 10 : rRet.nSub = 0;
565 : //If the point stays inside the Cnt everything is clear already; the Content
566 : //automatically has a distance of 0.
567 10 : if ( pCnt->Frm().IsInside( rPt ) )
568 : {
569 0 : rRet.nMain = 0;
570 0 : return pCnt;
571 : }
572 : else
573 : {
574 10 : const SwLayoutFrm *pUp = pCnt->IsInTab() ? pCnt->FindTabFrm()->GetUpper() : pCnt->GetUpper();
575 : // single column sections need to interconnect to their upper
576 20 : while( pUp->IsSctFrm() )
577 0 : pUp = pUp->GetUpper();
578 10 : const bool bVert = pUp->IsVertical();
579 :
580 10 : const bool bVertL2R = pUp->IsVertLR();
581 :
582 : //Follow the text flow.
583 : // #i70582#
584 : // --> OD 2009-03-05 - adopted for Support for Classical Mongolian Script
585 10 : const SwTwips nTopForObjPos = lcl_GetTopForObjPos(pCnt, bVert, bVertL2R);
586 10 : if ( pUp->Frm().IsInside( rPt ) )
587 : {
588 : // <rPt> point is inside environment of given content frame
589 : // #i70582#
590 10 : if( bVert )
591 : {
592 0 : if ( bVertL2R )
593 0 : rRet.nMain = rPt.X() - nTopForObjPos;
594 : else
595 0 : rRet.nMain = nTopForObjPos - rPt.X();
596 : }
597 : else
598 10 : rRet.nMain = rPt.Y() - nTopForObjPos;
599 10 : return pCnt;
600 : }
601 0 : else if ( rPt.Y() <= pUp->Frm().Top() )
602 : {
603 : // <rPt> point is above environment of given content frame
604 : // correct for vertical layout?
605 0 : rRet.nMain = LONG_MAX;
606 : }
607 0 : else if( rPt.X() < pUp->Frm().Left() &&
608 0 : rPt.Y() <= ( bVert ? pUp->Frm().Top() : pUp->Frm().Bottom() ) )
609 : {
610 : // <rPt> point is left of environment of given content frame
611 : // seems not to be correct for vertical layout!?
612 0 : const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, false, pCnt );
613 0 : if( !pLay ||
614 0 : (bVert && (pLay->Frm().Top() + pLay->Prt().Bottom()) <rPt.Y())||
615 0 : (!bVert && (pLay->Frm().Left() + pLay->Prt().Right())<rPt.X()) )
616 : {
617 : // <rPt> point is in left border of environment
618 : // #i70582#
619 0 : if( bVert )
620 : {
621 0 : if ( bVertL2R )
622 0 : rRet.nMain = rPt.X() - nTopForObjPos;
623 : else
624 0 : rRet.nMain = nTopForObjPos - rPt.X();
625 : }
626 : else
627 0 : rRet.nMain = rPt.Y() - nTopForObjPos;
628 0 : return pCnt;
629 : }
630 : else
631 0 : rRet.nMain = LONG_MAX;
632 : }
633 : else
634 : {
635 : rRet.nMain = bVert
636 : ? ( bVertL2R
637 0 : ? ( (pUp->Frm().Left() + pUp->Prt().Right()) - nTopForObjPos )
638 0 : : ( nTopForObjPos - (pUp->Frm().Left() + pUp->Prt().Left() ) ) )
639 0 : : ( (pUp->Frm().Top() + pUp->Prt().Bottom()) - nTopForObjPos );
640 :
641 0 : const SwFrm *pPre = pCnt;
642 0 : const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, true, pCnt );
643 0 : SwTwips nFrmTop = 0;
644 0 : SwTwips nPrtHeight = 0;
645 0 : bool bSct = false;
646 0 : const SwSectionFrm *pSect = pUp->FindSctFrm();
647 0 : if( pSect )
648 : {
649 0 : rRet.nSub = rRet.nMain;
650 0 : rRet.nMain = 0;
651 : }
652 0 : if( pSect && !pSect->IsAnLower( pLay ) )
653 : {
654 0 : bSct = false;
655 0 : const SwSectionFrm* pNxtSect = pLay ? pLay->FindSctFrm() : 0;
656 0 : if (pSect->IsAnFollow(pNxtSect) && pLay)
657 : {
658 0 : if( pLay->IsVertical() )
659 : {
660 0 : if ( pLay->IsVertLR() )
661 0 : nFrmTop = pLay->Frm().Left();
662 : else
663 0 : nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
664 0 : nPrtHeight = pLay->Prt().Width();
665 : }
666 : else
667 : {
668 0 : nFrmTop = pLay->Frm().Top();
669 0 : nPrtHeight = pLay->Prt().Height();
670 : }
671 0 : pSect = pNxtSect;
672 : }
673 : else
674 : {
675 0 : pLay = pSect->GetUpper();
676 0 : if( pLay->IsVertical() )
677 : {
678 0 : if ( pLay->IsVertLR() )
679 : {
680 0 : nFrmTop = pSect->Frm().Right();
681 0 : nPrtHeight = pLay->Frm().Left() + pLay->Prt().Left()
682 0 : + pLay->Prt().Width() - pSect->Frm().Left()
683 0 : - pSect->Frm().Width();
684 : }
685 : else
686 : {
687 0 : nFrmTop = pSect->Frm().Left();
688 0 : nPrtHeight = pSect->Frm().Left() - pLay->Frm().Left()
689 0 : - pLay->Prt().Left();
690 : }
691 : }
692 : else
693 : {
694 0 : nFrmTop = pSect->Frm().Bottom();
695 0 : nPrtHeight = pLay->Frm().Top() + pLay->Prt().Top()
696 0 : + pLay->Prt().Height() - pSect->Frm().Top()
697 0 : - pSect->Frm().Height();
698 : }
699 0 : pSect = 0;
700 : }
701 : }
702 0 : else if( pLay )
703 : {
704 0 : if( pLay->IsVertical() )
705 : {
706 0 : if ( pLay->IsVertLR() )
707 : {
708 0 : nFrmTop = pLay->Frm().Left();
709 0 : nPrtHeight = pLay->Prt().Width();
710 : }
711 : else
712 : {
713 0 : nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
714 0 : nPrtHeight = pLay->Prt().Width();
715 : }
716 : }
717 : else
718 : {
719 0 : nFrmTop = pLay->Frm().Top();
720 0 : nPrtHeight = pLay->Prt().Height();
721 : }
722 0 : bSct = 0 != pSect;
723 : }
724 0 : while ( pLay && !pLay->Frm().IsInside( rPt ) &&
725 0 : ( pLay->Frm().Top() <= rPt.Y() || pLay->IsInFly() ||
726 0 : ( pLay->IsInSct() &&
727 0 : pLay->FindSctFrm()->GetUpper()->Frm().Top() <= rPt.Y())) )
728 : {
729 0 : if ( pLay->IsFootnoteContFrm() )
730 : {
731 0 : if ( !static_cast<const SwLayoutFrm*>(pLay)->Lower() )
732 : {
733 0 : SwFrm *pDel = const_cast<SwFrm*>(pLay);
734 0 : pDel->Cut();
735 0 : SwFrm::DestroyFrm(pDel);
736 0 : return pPre;
737 : }
738 0 : return 0;
739 : }
740 : else
741 : {
742 0 : if( bSct || pSect )
743 0 : rRet.nSub += nPrtHeight;
744 : else
745 0 : rRet.nMain += nPrtHeight;
746 0 : pPre = pLay;
747 0 : pLay = pLay->GetLeaf( MAKEPAGE_NONE, true, pCnt );
748 0 : if( pSect && !pSect->IsAnLower( pLay ) )
749 : { // If we're leaving a SwSectionFrm, the next Leaf-Frm
750 : // is the part of the upper below the SectionFrm.
751 : const SwSectionFrm* pNxtSect = pLay ?
752 0 : pLay->FindSctFrm() : NULL;
753 0 : bSct = false;
754 0 : if (pLay && pSect->IsAnFollow(pNxtSect))
755 : {
756 0 : pSect = pNxtSect;
757 0 : if( pLay->IsVertical() )
758 : {
759 0 : if ( pLay->IsVertLR() )
760 : {
761 0 : nFrmTop = pLay->Frm().Left();
762 0 : nPrtHeight = pLay->Prt().Width();
763 : }
764 : else
765 : {
766 0 : nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
767 0 : nPrtHeight = pLay->Prt().Width();
768 : }
769 : }
770 : else
771 : {
772 0 : nFrmTop = pLay->Frm().Top();
773 0 : nPrtHeight = pLay->Prt().Height();
774 : }
775 : }
776 : else
777 : {
778 0 : pLay = pSect->GetUpper();
779 0 : if( pLay->IsVertical() )
780 : {
781 0 : if ( pLay->IsVertLR() )
782 : {
783 0 : nFrmTop = pSect->Frm().Right();
784 0 : nPrtHeight = pLay->Frm().Left()+pLay->Prt().Left()
785 0 : + pLay->Prt().Width() - pSect->Frm().Left()
786 0 : - pSect->Frm().Width();
787 : }
788 : else
789 : {
790 0 : nFrmTop = pSect->Frm().Left();
791 0 : nPrtHeight = pSect->Frm().Left() -
792 0 : pLay->Frm().Left() - pLay->Prt().Left();
793 : }
794 : }
795 : else
796 : {
797 0 : nFrmTop = pSect->Frm().Bottom();
798 0 : nPrtHeight = pLay->Frm().Top()+pLay->Prt().Top()
799 0 : + pLay->Prt().Height() - pSect->Frm().Top()
800 0 : - pSect->Frm().Height();
801 : }
802 0 : pSect = 0;
803 : }
804 : }
805 0 : else if( pLay )
806 : {
807 0 : if( pLay->IsVertical() )
808 : {
809 0 : if ( pLay->IsVertLR() )
810 : {
811 0 : nFrmTop = pLay->Frm().Left();
812 0 : nPrtHeight = pLay->Prt().Width();
813 : }
814 : else
815 : {
816 0 : nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
817 0 : nPrtHeight = pLay->Prt().Width();
818 : }
819 : }
820 : else
821 : {
822 0 : nFrmTop = pLay->Frm().Top();
823 0 : nPrtHeight = pLay->Prt().Height();
824 : }
825 0 : bSct = 0 != pSect;
826 : }
827 : }
828 : }
829 0 : if ( pLay )
830 : {
831 0 : if ( pLay->Frm().IsInside( rPt ) )
832 : {
833 0 : SwTwips nDiff = pLay->IsVertical() ? ( pLay->IsVertLR() ? ( rPt.X() - nFrmTop ) : ( nFrmTop - rPt.X() ) )
834 0 : : ( rPt.Y() - nFrmTop );
835 0 : if( bSct || pSect )
836 0 : rRet.nSub += nDiff;
837 : else
838 0 : rRet.nMain += nDiff;
839 : }
840 0 : if ( pLay->IsFootnoteContFrm() && !static_cast<const SwLayoutFrm*>(pLay)->Lower() )
841 : {
842 0 : SwFrm *pDel = const_cast<SwFrm*>(pLay);
843 0 : pDel->Cut();
844 0 : SwFrm::DestroyFrm(pDel);
845 0 : return 0;
846 : }
847 0 : return pLay;
848 : }
849 : else
850 0 : rRet.nMain = LONG_MAX;
851 : }
852 : }
853 0 : return 0;
854 : }
855 :
856 0 : static sal_uInt64 lcl_FindCntDiff( const Point &rPt, const SwLayoutFrm *pLay,
857 : const SwContentFrm *& rpCnt,
858 : const bool bBody, const bool bFootnote )
859 : {
860 : // Searches below pLay the nearest Cnt to the point. The reference point of
861 : //the Contents is always the left upper corner.
862 : //The Cnt should preferably be above the point.
863 :
864 0 : rpCnt = 0;
865 0 : sal_uInt64 nDistance = SAL_MAX_UINT64;
866 0 : sal_uInt64 nNearest = SAL_MAX_UINT64;
867 0 : const SwContentFrm *pCnt = pLay ? pLay->ContainsContent() : NULL;
868 :
869 0 : while ( pCnt && (bBody != pCnt->IsInDocBody() || bFootnote != pCnt->IsInFootnote()))
870 : {
871 0 : pCnt = pCnt->GetNextContentFrm();
872 0 : if ( !pLay->IsAnLower( pCnt ) )
873 0 : pCnt = 0;
874 : }
875 0 : const SwContentFrm *pNearest = pCnt;
876 0 : if ( pCnt )
877 : {
878 0 : do
879 : {
880 : //Calculate the distance between those two points.
881 : //'delta' X^2 + 'delta' Y^2 = 'distance'^2
882 0 : sal_uInt64 dX = std::max( pCnt->Frm().Left(), rPt.X() ) -
883 0 : std::min( pCnt->Frm().Left(), rPt.X() ),
884 0 : dY = std::max( pCnt->Frm().Top(), rPt.Y() ) -
885 0 : std::min( pCnt->Frm().Top(), rPt.Y() );
886 : // square of the difference will do fine here
887 0 : const sal_uInt64 nDiff = (dX * dX) + (dY * dY);
888 0 : if ( pCnt->Frm().Top() <= rPt.Y() )
889 : {
890 0 : if ( nDiff < nDistance )
891 : {
892 : //This one is the nearer one
893 0 : nDistance = nNearest = nDiff;
894 0 : rpCnt = pNearest = pCnt;
895 : }
896 : }
897 0 : else if ( nDiff < nNearest )
898 : {
899 0 : nNearest = nDiff;
900 0 : pNearest = pCnt;
901 : }
902 0 : pCnt = pCnt->GetNextContentFrm();
903 0 : while ( pCnt &&
904 0 : (bBody != pCnt->IsInDocBody() || bFootnote != pCnt->IsInFootnote()))
905 0 : pCnt = pCnt->GetNextContentFrm();
906 :
907 0 : } while ( pCnt && pLay->IsAnLower( pCnt ) );
908 : }
909 0 : if (nDistance == SAL_MAX_UINT64)
910 0 : { rpCnt = pNearest;
911 0 : return nNearest;
912 : }
913 0 : return nDistance;
914 : }
915 :
916 0 : static const SwContentFrm * lcl_FindCnt( const Point &rPt, const SwContentFrm *pCnt,
917 : const bool bBody, const bool bFootnote )
918 : {
919 : //Starting from pCnt searches the ContentFrm whose left upper corner is the
920 : //nearest to the point.
921 : //Always returns a ContentFrm.
922 :
923 : //First the nearest Content inside the page which contains the Content is
924 : //searched. Starting from this page the pages in both directions need to
925 : //be considered. If possible a Content is returned whose Y-position is
926 : //above the point.
927 : const SwContentFrm *pRet, *pNew;
928 0 : const SwLayoutFrm *pLay = pCnt->FindPageFrm();
929 : sal_uInt64 nDist; // not sure if a sal_Int32 would be enough?
930 :
931 0 : nDist = ::lcl_FindCntDiff( rPt, pLay, pNew, bBody, bFootnote );
932 0 : if ( pNew )
933 0 : pRet = pNew;
934 : else
935 0 : { pRet = pCnt;
936 0 : nDist = SAL_MAX_UINT64;
937 : }
938 0 : const SwContentFrm *pNearest = pRet;
939 0 : sal_uInt64 nNearest = nDist;
940 :
941 0 : if ( pLay )
942 : {
943 0 : const SwLayoutFrm *pPge = pLay;
944 0 : sal_uInt64 nOldNew = SAL_MAX_UINT64;
945 0 : for ( int i = 0; pPge->GetPrev() && (i < 3); ++i )
946 : {
947 0 : pPge = static_cast<const SwLayoutFrm*>(pPge->GetPrev());
948 0 : const sal_uInt64 nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFootnote );
949 0 : if ( nNew < nDist )
950 : {
951 0 : if ( pNew->Frm().Top() <= rPt.Y() )
952 : {
953 0 : pRet = pNearest = pNew;
954 0 : nDist = nNearest = nNew;
955 : }
956 0 : else if ( nNew < nNearest )
957 : {
958 0 : pNearest = pNew;
959 0 : nNearest = nNew;
960 : }
961 : }
962 0 : else if (nOldNew != SAL_MAX_UINT64 && nNew > nOldNew)
963 : break;
964 : else
965 0 : nOldNew = nNew;
966 :
967 : }
968 0 : pPge = pLay;
969 0 : nOldNew = SAL_MAX_UINT64;
970 0 : for ( int j = 0; pPge->GetNext() && (j < 3); ++j )
971 : {
972 0 : pPge = static_cast<const SwLayoutFrm*>(pPge->GetNext());
973 0 : const sal_uInt64 nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFootnote );
974 0 : if ( nNew < nDist )
975 : {
976 0 : if ( pNew->Frm().Top() <= rPt.Y() )
977 : {
978 0 : pRet = pNearest = pNew;
979 0 : nDist = nNearest = nNew;
980 : }
981 0 : else if ( nNew < nNearest )
982 : {
983 0 : pNearest = pNew;
984 0 : nNearest = nNew;
985 : }
986 : }
987 0 : else if (nOldNew != SAL_MAX_UINT64 && nNew > nOldNew)
988 : break;
989 : else
990 0 : nOldNew = nNew;
991 : }
992 : }
993 0 : if ( (pRet->Frm().Top() > rPt.Y()) )
994 0 : return pNearest;
995 : else
996 0 : return pRet;
997 : }
998 :
999 4 : static void lcl_PointToPrt( Point &rPoint, const SwFrm *pFrm )
1000 : {
1001 4 : SwRect aTmp( pFrm->Prt() );
1002 4 : aTmp += pFrm->Frm().Pos();
1003 4 : if ( rPoint.getX() < aTmp.Left() )
1004 0 : rPoint.setX(aTmp.Left());
1005 4 : else if ( rPoint.getX() > aTmp.Right() )
1006 2 : rPoint.setX(aTmp.Right());
1007 4 : if ( rPoint.getY() < aTmp.Top() )
1008 0 : rPoint.setY(aTmp.Top());
1009 4 : else if ( rPoint.getY() > aTmp.Bottom() )
1010 2 : rPoint.setY(aTmp.Bottom());
1011 :
1012 4 : }
1013 :
1014 : /** Searches an anchor for paragraph bound objects starting from pOldAnch.
1015 : *
1016 : * This is used to show anchors as well as changing anchors
1017 : * when dragging paragraph bound objects.
1018 : */
1019 2 : const SwContentFrm *FindAnchor( const SwFrm *pOldAnch, const Point &rNew,
1020 : const bool bBodyOnly )
1021 : {
1022 : //Search the nearest Cnt around the given document position in the text
1023 : //flow. The given anchor is the starting Frm.
1024 : const SwContentFrm* pCnt;
1025 2 : if ( pOldAnch->IsContentFrm() )
1026 : {
1027 2 : pCnt = static_cast<const SwContentFrm*>(pOldAnch);
1028 : }
1029 : else
1030 : {
1031 0 : Point aTmp( rNew );
1032 0 : const SwLayoutFrm *pTmpLay = static_cast<const SwLayoutFrm*>(pOldAnch);
1033 0 : if( pTmpLay->IsRootFrm() )
1034 : {
1035 0 : SwRect aTmpRect( aTmp, Size(0,0) );
1036 0 : pTmpLay = static_cast<const SwLayoutFrm*>(::FindPage( aTmpRect, pTmpLay->Lower() ));
1037 : }
1038 0 : pCnt = pTmpLay->GetContentPos( aTmp, false, bBodyOnly );
1039 : }
1040 :
1041 : //Take care to use meaningful ranges during search. This means to not enter
1042 : //or leave header/footer in this case.
1043 2 : const bool bBody = pCnt->IsInDocBody() || bBodyOnly;
1044 2 : const bool bFootnote = !bBodyOnly && pCnt->IsInFootnote();
1045 :
1046 2 : Point aNew( rNew );
1047 2 : if ( bBody )
1048 : {
1049 : //#38848 drag from page margin into the body.
1050 2 : const SwFrm *pPage = pCnt->FindPageFrm();
1051 2 : ::lcl_PointToPrt( aNew, pPage->GetUpper() );
1052 2 : SwRect aTmp( aNew, Size( 0, 0 ) );
1053 2 : pPage = ::FindPage( aTmp, pPage );
1054 2 : ::lcl_PointToPrt( aNew, pPage );
1055 : }
1056 :
1057 2 : if ( pCnt->IsInDocBody() == bBody && pCnt->Frm().IsInside( aNew ) )
1058 0 : return pCnt;
1059 2 : else if ( pOldAnch->IsInDocBody() || pOldAnch->IsPageFrm() )
1060 : {
1061 : // Maybe the selected anchor is on the same page as the current anchor.
1062 : // With this we won't run into problems with the columns.
1063 2 : Point aTmp( aNew );
1064 2 : const SwContentFrm *pTmp = pCnt->FindPageFrm()->
1065 2 : GetContentPos( aTmp, false, true, false );
1066 2 : if ( pTmp && pTmp->Frm().IsInside( aNew ) )
1067 0 : return pTmp;
1068 : }
1069 :
1070 : //Starting from the anchor we now search in both directions until we found
1071 : //the nearest one respectively.
1072 : //Not the direct distance is relevant but the distance which needs to be
1073 : //traveled through the text flow.
1074 : const SwContentFrm *pUpLst;
1075 2 : const SwContentFrm *pUpFrm = pCnt;
1076 2 : SwDistance nUp, nUpLst;
1077 2 : ::lcl_CalcDownDist( nUp, aNew, pUpFrm );
1078 2 : SwDistance nDown = nUp;
1079 2 : bool bNegAllowed = true;// Make it possible to leave the negative section once.
1080 8 : do
1081 : {
1082 8 : pUpLst = pUpFrm; nUpLst = nUp;
1083 8 : pUpFrm = pUpLst->GetPrevContentFrm();
1084 23 : while ( pUpFrm &&
1085 14 : (bBody != pUpFrm->IsInDocBody() || bFootnote != pUpFrm->IsInFootnote()))
1086 0 : pUpFrm = pUpFrm->GetPrevContentFrm();
1087 8 : if ( pUpFrm )
1088 : {
1089 7 : ::lcl_CalcDownDist( nUp, aNew, pUpFrm );
1090 : //It makes sense to search further, if the distance grows inside
1091 : //a table.
1092 7 : if ( pUpLst->IsInTab() && pUpFrm->IsInTab() )
1093 : {
1094 0 : while ( pUpFrm && ((nUpLst < nUp && pUpFrm->IsInTab()) ||
1095 0 : bBody != pUpFrm->IsInDocBody()) )
1096 : {
1097 0 : pUpFrm = pUpFrm->GetPrevContentFrm();
1098 0 : if ( pUpFrm )
1099 0 : ::lcl_CalcDownDist( nUp, aNew, pUpFrm );
1100 : }
1101 : }
1102 : }
1103 8 : if ( !pUpFrm )
1104 1 : nUp.nMain = LONG_MAX;
1105 8 : if ( nUp.nMain >= 0 && LONG_MAX != nUp.nMain )
1106 : {
1107 7 : bNegAllowed = false;
1108 7 : if ( nUpLst.nMain < 0 ) //don't take the wrong one, if the value
1109 : //just changed from negative to positive.
1110 0 : { pUpLst = pUpFrm;
1111 0 : nUpLst = nUp;
1112 : }
1113 : }
1114 8 : } while ( pUpFrm && ( ( bNegAllowed && nUp.nMain < 0 ) || ( nUp <= nUpLst ) ) );
1115 :
1116 : const SwContentFrm *pDownLst;
1117 2 : const SwContentFrm *pDownFrm = pCnt;
1118 2 : SwDistance nDownLst;
1119 2 : if ( nDown.nMain < 0 )
1120 0 : nDown.nMain = LONG_MAX;
1121 3 : do
1122 : {
1123 3 : pDownLst = pDownFrm; nDownLst = nDown;
1124 3 : pDownFrm = pDownLst->GetNextContentFrm();
1125 7 : while ( pDownFrm &&
1126 2 : (bBody != pDownFrm->IsInDocBody() || bFootnote != pDownFrm->IsInFootnote()))
1127 0 : pDownFrm = pDownFrm->GetNextContentFrm();
1128 3 : if ( pDownFrm )
1129 : {
1130 1 : ::lcl_CalcDownDist( nDown, aNew, pDownFrm );
1131 1 : if ( nDown.nMain < 0 )
1132 0 : nDown.nMain = LONG_MAX;
1133 : //It makes sense to search further, if the distance grows inside
1134 : //a table.
1135 1 : if ( pDownLst->IsInTab() && pDownFrm->IsInTab() )
1136 : {
1137 0 : while ( pDownFrm && ( ( nDown.nMain != LONG_MAX && pDownFrm->IsInTab()) || bBody != pDownFrm->IsInDocBody() ) )
1138 : {
1139 0 : pDownFrm = pDownFrm->GetNextContentFrm();
1140 0 : if ( pDownFrm )
1141 0 : ::lcl_CalcDownDist( nDown, aNew, pDownFrm );
1142 0 : if ( nDown.nMain < 0 )
1143 0 : nDown.nMain = LONG_MAX;
1144 : }
1145 : }
1146 : }
1147 3 : if ( !pDownFrm )
1148 2 : nDown.nMain = LONG_MAX;
1149 :
1150 2 : } while ( pDownFrm && nDown <= nDownLst &&
1151 5 : nDown.nMain != LONG_MAX && nDownLst.nMain != LONG_MAX );
1152 :
1153 : //If we couldn't find one in both directions, we'll search the Content whose
1154 : //left upper corner is the nearest to the point. Such a situation may
1155 : //happen, if the point doesn't lay in the text flow but in any margin.
1156 2 : if ( nDownLst.nMain == LONG_MAX && nUpLst.nMain == LONG_MAX )
1157 : {
1158 : // If an OLE objects, which is contained in a fly frame
1159 : // is resized in inplace mode and the new Position is outside the
1160 : // fly frame, we do not want to leave our fly frame.
1161 0 : if ( pCnt->IsInFly() )
1162 0 : return pCnt;
1163 :
1164 0 : return ::lcl_FindCnt( aNew, pCnt, bBody, bFootnote );
1165 : }
1166 : else
1167 2 : return nDownLst < nUpLst ? pDownLst : pUpLst;
1168 : }
1169 :
1170 0 : void SwFlyAtCntFrm::SetAbsPos( const Point &rNew )
1171 : {
1172 0 : SwPageFrm *pOldPage = FindPageFrm();
1173 0 : const SwRect aOld( GetObjRectWithSpaces() );
1174 0 : Point aNew( rNew );
1175 :
1176 0 : if( ( GetAnchorFrm()->IsVertical() && !GetAnchorFrm()->IsVertLR() ) || GetAnchorFrm()->IsRightToLeft() )
1177 0 : aNew.setX(aNew.getX() + Frm().Width());
1178 0 : SwContentFrm *pCnt = const_cast<SwContentFrm*>(::FindAnchor( GetAnchorFrm(), aNew ));
1179 0 : if( pCnt->IsProtected() )
1180 0 : pCnt = const_cast<SwContentFrm*>(static_cast<const SwContentFrm*>(GetAnchorFrm()));
1181 :
1182 0 : SwPageFrm *pTmpPage = 0;
1183 0 : const bool bVert = pCnt->IsVertical();
1184 :
1185 0 : const bool bVertL2R = pCnt->IsVertLR();
1186 0 : const bool bRTL = pCnt->IsRightToLeft();
1187 :
1188 0 : if( ( !bVert != !GetAnchorFrm()->IsVertical() ) ||
1189 0 : ( !bRTL != !GetAnchorFrm()->IsRightToLeft() ) )
1190 : {
1191 0 : if( bVert || bRTL )
1192 0 : aNew.setX(aNew.getX() + Frm().Width());
1193 : else
1194 0 : aNew.setX(aNew.getX() - Frm().Width());
1195 : }
1196 :
1197 0 : if ( pCnt->IsInDocBody() )
1198 : {
1199 : //#38848 drag from page margin into the body.
1200 0 : pTmpPage = pCnt->FindPageFrm();
1201 0 : ::lcl_PointToPrt( aNew, pTmpPage->GetUpper() );
1202 0 : SwRect aTmp( aNew, Size( 0, 0 ) );
1203 0 : pTmpPage = const_cast<SwPageFrm*>(static_cast<const SwPageFrm*>(::FindPage( aTmp, pTmpPage )));
1204 0 : ::lcl_PointToPrt( aNew, pTmpPage );
1205 : }
1206 :
1207 : //Setup RelPos, only invalidate if requested.
1208 : //rNew is an absolute position. We need to calculate the distance from rNew
1209 : //to the anchor inside the text flow to correctly set RelPos.
1210 : //!!!!!We can optimize here: FindAnchor could also return RelPos!
1211 0 : const SwFrm *pFrm = 0;
1212 : SwTwips nY;
1213 0 : if ( pCnt->Frm().IsInside( aNew ) )
1214 : {
1215 : // #i70582#
1216 0 : if ( bVert )
1217 : {
1218 0 : nY = pCnt->Frm().Left() - rNew.X();
1219 0 : if ( bVertL2R )
1220 0 : nY = -nY;
1221 0 : nY -= pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid();
1222 : }
1223 : else
1224 0 : nY = rNew.Y() - pCnt->Frm().Top() + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid();
1225 : }
1226 : else
1227 : {
1228 0 : SwDistance aDist;
1229 0 : pFrm = ::lcl_CalcDownDist( aDist, aNew, pCnt );
1230 0 : nY = aDist.nMain + aDist.nSub;
1231 : }
1232 :
1233 0 : SwTwips nX = 0;
1234 :
1235 0 : if ( pCnt->IsFollow() )
1236 : {
1237 : // Flys are never attached to the follow but always to the master,
1238 : // which we're going to search now.
1239 0 : const SwContentFrm *pOriginal = pCnt;
1240 0 : const SwContentFrm *pFollow = pCnt;
1241 0 : while ( pCnt->IsFollow() )
1242 : {
1243 0 : do
1244 : {
1245 0 : SwContentFrm* pPrev = pCnt->GetPrevContentFrm();
1246 0 : if (!pPrev)
1247 : {
1248 : SAL_WARN("sw.core", "very unexpected missing PrevContentFrm");
1249 0 : break;
1250 : }
1251 0 : pCnt = pPrev;
1252 : }
1253 0 : while ( pCnt->GetFollow() != pFollow );
1254 0 : pFollow = pCnt;
1255 : }
1256 0 : SwTwips nDiff = 0;
1257 0 : do
1258 0 : { const SwFrm *pUp = pFollow->GetUpper();
1259 0 : if( pUp->IsVertical() )
1260 : {
1261 0 : if ( pUp->IsVertLR() )
1262 0 : nDiff += pUp->Prt().Width() - pFollow->GetRelPos().getX();
1263 : else
1264 0 : nDiff += pFollow->Frm().Left() + pFollow->Frm().Width()
1265 0 : - pUp->Frm().Left() - pUp->Prt().Left();
1266 : }
1267 : else
1268 0 : nDiff += pUp->Prt().Height() - pFollow->GetRelPos().Y();
1269 0 : pFollow = pFollow->GetFollow();
1270 : } while ( pFollow != pOriginal );
1271 0 : nY += nDiff;
1272 0 : if( bVert )
1273 0 : nX = pCnt->Frm().Top() - pOriginal->Frm().Top();
1274 : else
1275 0 : nX = pCnt->Frm().Left() - pOriginal->Frm().Left();
1276 : }
1277 :
1278 0 : if ( nY == LONG_MAX )
1279 : {
1280 : // #i70582#
1281 0 : const SwTwips nTopForObjPos = lcl_GetTopForObjPos(pCnt, bVert, bVertL2R);
1282 0 : if( bVert )
1283 : {
1284 0 : if ( bVertL2R )
1285 0 : nY = rNew.X() - nTopForObjPos;
1286 : else
1287 0 : nY = nTopForObjPos - rNew.X();
1288 : }
1289 : else
1290 : {
1291 0 : nY = rNew.Y() - nTopForObjPos;
1292 : }
1293 : }
1294 :
1295 0 : SwFlyFrameFormat *pFormat = GetFormat();
1296 :
1297 0 : if( bVert )
1298 : {
1299 0 : if( !pFrm )
1300 0 : nX += rNew.Y() - pCnt->Frm().Top();
1301 : else
1302 0 : nX = rNew.Y() - pFrm->Frm().Top();
1303 : }
1304 : else
1305 : {
1306 0 : if( !pFrm )
1307 : {
1308 0 : if ( pCnt->IsRightToLeft() )
1309 0 : nX += pCnt->Frm().Right() - rNew.X() - Frm().Width();
1310 : else
1311 0 : nX += rNew.X() - pCnt->Frm().Left();
1312 : }
1313 : else
1314 : {
1315 0 : if ( pFrm->IsRightToLeft() )
1316 0 : nX += pFrm->Frm().Right() - rNew.X() - Frm().Width();
1317 : else
1318 0 : nX = rNew.X() - pFrm->Frm().Left();
1319 : }
1320 : }
1321 0 : GetFormat()->GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
1322 :
1323 0 : if( pCnt != GetAnchorFrm() || ( IsAutoPos() && pCnt->IsTextFrm() &&
1324 0 : GetFormat()->getIDocumentSettingAccess()->get(DocumentSettingId::HTML_MODE)) )
1325 : {
1326 : //Set the anchor attribute according to the new Cnt.
1327 0 : SwFormatAnchor aAnch( pFormat->GetAnchor() );
1328 0 : SwPosition pos = *aAnch.GetContentAnchor();
1329 0 : if( IsAutoPos() && pCnt->IsTextFrm() )
1330 : {
1331 0 : SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
1332 0 : Point aPt( rNew );
1333 0 : if( pCnt->GetCrsrOfst( &pos, aPt, &eTmpState )
1334 0 : && pos.nNode == *pCnt->GetNode() )
1335 : {
1336 0 : if ( pCnt->GetNode()->GetTextNode() != NULL )
1337 : {
1338 : const SwTextAttr* pTextInputField =
1339 0 : pCnt->GetNode()->GetTextNode()->GetTextAttrAt( pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT );
1340 0 : if ( pTextInputField != NULL )
1341 : {
1342 0 : pos.nContent = pTextInputField->GetStart();
1343 : }
1344 : }
1345 0 : ResetLastCharRectHeight();
1346 0 : if( text::RelOrientation::CHAR == pFormat->GetVertOrient().GetRelationOrient() )
1347 0 : nY = LONG_MAX;
1348 0 : if( text::RelOrientation::CHAR == pFormat->GetHoriOrient().GetRelationOrient() )
1349 0 : nX = LONG_MAX;
1350 : }
1351 : else
1352 : {
1353 0 : pos.nNode = *pCnt->GetNode();
1354 0 : pos.nContent.Assign( pCnt->GetNode(), 0 );
1355 : }
1356 : }
1357 : else
1358 : {
1359 0 : pos.nNode = *pCnt->GetNode();
1360 0 : pos.nContent.Assign( pCnt->GetNode(), 0 );
1361 : }
1362 0 : aAnch.SetAnchor( &pos );
1363 :
1364 : // handle change of anchor node:
1365 : // if count of the anchor frame also change, the fly frames have to be
1366 : // re-created. Thus, delete all fly frames except the <this> before the
1367 : // anchor attribute is change and re-create them afterwards.
1368 : {
1369 0 : SwHandleAnchorNodeChg aHandleAnchorNodeChg( *pFormat, aAnch, this );
1370 0 : pFormat->GetDoc()->SetAttr( aAnch, *pFormat );
1371 0 : }
1372 : }
1373 0 : else if ( pTmpPage && pTmpPage != GetPageFrm() )
1374 0 : GetPageFrm()->MoveFly( this, pTmpPage );
1375 :
1376 0 : const Point aRelPos = bVert ? Point( -nY, nX ) : Point( nX, nY );
1377 :
1378 0 : ChgRelPos( aRelPos );
1379 :
1380 0 : GetFormat()->GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
1381 :
1382 0 : if ( pOldPage != FindPageFrm() )
1383 0 : ::Notify_Background( GetVirtDrawObj(), pOldPage, aOld, PREP_FLY_LEAVE, false );
1384 0 : }
1385 :
1386 : /** method to assure that anchored object is registered at the correct
1387 : page frame
1388 :
1389 : #i28701#
1390 : takes over functionality of deleted method <SwFlyAtCntFrm::AssertPage()>
1391 : */
1392 2458 : void SwFlyAtCntFrm::RegisterAtCorrectPage()
1393 : {
1394 2458 : SwPageFrm* pPageFrm( 0L );
1395 2458 : if ( GetVertPosOrientFrm() )
1396 : {
1397 2458 : pPageFrm = const_cast<SwPageFrm*>(GetVertPosOrientFrm()->FindPageFrm());
1398 : }
1399 2458 : if ( pPageFrm && GetPageFrm() != pPageFrm )
1400 : {
1401 16 : if ( GetPageFrm() )
1402 16 : GetPageFrm()->MoveFly( this, pPageFrm );
1403 : else
1404 0 : pPageFrm->AppendFlyToPage( this );
1405 : }
1406 2458 : }
1407 :
1408 : // #i26791#
1409 2460 : void SwFlyAtCntFrm::MakeObjPos()
1410 : {
1411 : // if fly frame position is valid, nothing is to do. Thus, return
1412 2460 : if ( mbValidPos )
1413 : {
1414 2 : return;
1415 : }
1416 :
1417 : // #i26791# - validate position flag here.
1418 2460 : mbValidPos = true;
1419 :
1420 : // #i35911# - no calculation of new position, if
1421 : // anchored object is marked that it clears its environment and its
1422 : // environment is already cleared.
1423 : // before checking for cleared environment
1424 : // check, if member <mpVertPosOrientFrm> is set.
1425 6173 : if ( GetVertPosOrientFrm() &&
1426 2464 : ClearedEnvironment() && HasClearedEnvironment() )
1427 : {
1428 2 : return;
1429 : }
1430 :
1431 : // use new class to position object
1432 : objectpositioning::SwToContentAnchoredObjectPosition
1433 2458 : aObjPositioning( *GetVirtDrawObj() );
1434 2458 : aObjPositioning.CalcPosition();
1435 :
1436 2458 : SetVertPosOrientFrm ( aObjPositioning.GetVertPosOrientFrm() );
1437 : }
1438 :
1439 : // #i28701#
1440 3052 : bool SwFlyAtCntFrm::_InvalidationAllowed( const InvalidationType _nInvalid ) const
1441 : {
1442 3052 : bool bAllowed( SwFlyFreeFrm::_InvalidationAllowed( _nInvalid ) );
1443 :
1444 : // forbiddance of base instance can't be over ruled.
1445 3052 : if ( bAllowed )
1446 : {
1447 3052 : if ( _nInvalid == INVALID_POS ||
1448 : _nInvalid == INVALID_ALL )
1449 : {
1450 2022 : bAllowed = InvalidationOfPosAllowed();
1451 : }
1452 : }
1453 :
1454 3052 : return bAllowed;
1455 177 : }
1456 :
1457 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|