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