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