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 <dcontact.hxx>
21 : #include <rootfrm.hxx>
22 : #include <pagefrm.hxx>
23 : #include <tocntntanchoredobjectposition.hxx>
24 : #include <tolayoutanchoredobjectposition.hxx>
25 : #include <frmtool.hxx>
26 : #include <fmtornt.hxx>
27 : // --> #i32795#
28 : #include <txtfrm.hxx>
29 : // --> #i32795#
30 : // template class <std::vector>
31 : #include <vector>
32 :
33 : using namespace ::com::sun::star;
34 :
35 : // ============================================================================
36 : // helper class for correct notification due to the positioning of
37 : // the anchored drawing object
38 : // ============================================================================
39 : class SwPosNotify
40 : {
41 : private:
42 : SwAnchoredDrawObject* mpAnchoredDrawObj;
43 : SwRect maOldObjRect;
44 : SwPageFrm* mpOldPageFrm;
45 :
46 : public:
47 : SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj );
48 : ~SwPosNotify();
49 : // #i32795#
50 : Point LastObjPos() const;
51 : };
52 :
53 63 : SwPosNotify::SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj ) :
54 63 : mpAnchoredDrawObj( _pAnchoredDrawObj )
55 : {
56 63 : maOldObjRect = mpAnchoredDrawObj->GetObjRect();
57 : // --> #i35640# - determine correct page frame
58 63 : mpOldPageFrm = mpAnchoredDrawObj->GetPageFrm();
59 63 : }
60 :
61 63 : SwPosNotify::~SwPosNotify()
62 : {
63 63 : if ( maOldObjRect != mpAnchoredDrawObj->GetObjRect() )
64 : {
65 54 : if( maOldObjRect.HasArea() && mpOldPageFrm )
66 : {
67 : mpAnchoredDrawObj->NotifyBackground( mpOldPageFrm, maOldObjRect,
68 52 : PREP_FLY_LEAVE );
69 : }
70 54 : SwRect aNewObjRect( mpAnchoredDrawObj->GetObjRect() );
71 54 : if( aNewObjRect.HasArea() )
72 : {
73 : // --> #i35640# - determine correct page frame
74 52 : SwPageFrm* pNewPageFrm = mpAnchoredDrawObj->GetPageFrm();
75 52 : if( pNewPageFrm )
76 : mpAnchoredDrawObj->NotifyBackground( pNewPageFrm, aNewObjRect,
77 52 : PREP_FLY_ARRIVE );
78 : }
79 :
80 54 : ::ClrContourCache( mpAnchoredDrawObj->GetDrawObj() );
81 :
82 : // --> #i35640# - additional notify anchor text frame
83 : // Needed for negative positioned drawing objects
84 : // --> #i43255# - refine condition to avoid unneeded
85 : // invalidations: anchored object had to be on the page of its anchor
86 : // text frame.
87 101 : if ( mpAnchoredDrawObj->GetAnchorFrm()->IsTxtFrm() &&
88 47 : mpOldPageFrm == mpAnchoredDrawObj->GetAnchorFrm()->FindPageFrm() )
89 : {
90 47 : mpAnchoredDrawObj->AnchorFrm()->Prepare( PREP_FLY_LEAVE );
91 : }
92 :
93 : // indicate a restart of the layout process
94 54 : mpAnchoredDrawObj->SetRestartLayoutProcess( true );
95 : }
96 : else
97 : {
98 : // lock position
99 9 : mpAnchoredDrawObj->LockPosition();
100 :
101 9 : if ( !mpAnchoredDrawObj->ConsiderForTextWrap() )
102 : {
103 : // indicate that object has to be considered for text wrap
104 3 : mpAnchoredDrawObj->SetConsiderForTextWrap( true );
105 : // invalidate 'background' in order to allow its 'background'
106 : // to wrap around it.
107 : mpAnchoredDrawObj->NotifyBackground( mpAnchoredDrawObj->GetPageFrm(),
108 3 : mpAnchoredDrawObj->GetObjRectWithSpaces(),
109 6 : PREP_FLY_ARRIVE );
110 : // invalidate position of anchor frame in order to force
111 : // a re-format of the anchor frame, which also causes a
112 : // re-format of the invalid previous frames of the anchor frame.
113 3 : mpAnchoredDrawObj->AnchorFrm()->InvalidatePos();
114 : }
115 : }
116 63 : }
117 :
118 : // --> #i32795#
119 56 : Point SwPosNotify::LastObjPos() const
120 : {
121 56 : return maOldObjRect.Pos();
122 : }
123 :
124 : // ============================================================================
125 : // #i32795#
126 : // helper class for oscillation control on object positioning
127 : // ============================================================================
128 : class SwObjPosOscillationControl
129 : {
130 : private:
131 : sal_uInt8 mnPosStackSize;
132 :
133 : const SwAnchoredDrawObject* mpAnchoredDrawObj;
134 :
135 : std::vector<Point*> maObjPositions;
136 :
137 : public:
138 : SwObjPosOscillationControl( const SwAnchoredDrawObject& _rAnchoredDrawObj );
139 : ~SwObjPosOscillationControl();
140 :
141 : bool OscillationDetected();
142 : };
143 :
144 56 : SwObjPosOscillationControl::SwObjPosOscillationControl(
145 : const SwAnchoredDrawObject& _rAnchoredDrawObj )
146 : : mnPosStackSize( 20 ),
147 56 : mpAnchoredDrawObj( &_rAnchoredDrawObj )
148 : {
149 56 : }
150 :
151 112 : SwObjPosOscillationControl::~SwObjPosOscillationControl()
152 : {
153 159 : while ( !maObjPositions.empty() )
154 : {
155 47 : Point* pPos = maObjPositions.back();
156 47 : delete pPos;
157 :
158 47 : maObjPositions.pop_back();
159 : }
160 56 : }
161 :
162 47 : bool SwObjPosOscillationControl::OscillationDetected()
163 : {
164 47 : bool bOscillationDetected = false;
165 :
166 47 : if ( maObjPositions.size() == mnPosStackSize )
167 : {
168 : // position stack is full -> oscillation
169 0 : bOscillationDetected = true;
170 : }
171 : else
172 : {
173 47 : Point* pNewObjPos = new Point( mpAnchoredDrawObj->GetObjRect().Pos() );
174 141 : for ( std::vector<Point*>::iterator aObjPosIter = maObjPositions.begin();
175 94 : aObjPosIter != maObjPositions.end();
176 : ++aObjPosIter )
177 : {
178 0 : if ( *(pNewObjPos) == *(*aObjPosIter) )
179 : {
180 : // position already occurred -> oscillation
181 0 : bOscillationDetected = true;
182 0 : delete pNewObjPos;
183 0 : break;
184 : }
185 : }
186 47 : if ( !bOscillationDetected )
187 : {
188 47 : maObjPositions.push_back( pNewObjPos );
189 : }
190 : }
191 :
192 47 : return bOscillationDetected;
193 : }
194 :
195 : // ============================================================================
196 : // implementation of class <SwAnchoredDrawObject>
197 : // ============================================================================
198 29951 : TYPEINIT1(SwAnchoredDrawObject,SwAnchoredObject);
199 :
200 399 : SwAnchoredDrawObject::SwAnchoredDrawObject() :
201 : SwAnchoredObject(),
202 : mbValidPos( false ),
203 : // --> #i34748#
204 : mpLastObjRect( 0L ),
205 : mbNotYetAttachedToAnchorFrame( true ),
206 : // --> #i28749#
207 : mbNotYetPositioned( true ),
208 : // --> #i62875#
209 399 : mbCaptureAfterLayoutDirChange( false )
210 : {
211 399 : }
212 :
213 796 : SwAnchoredDrawObject::~SwAnchoredDrawObject()
214 : {
215 : // #i34748#
216 398 : delete mpLastObjRect;
217 398 : }
218 :
219 : // --> #i62875#
220 305 : void SwAnchoredDrawObject::UpdateLayoutDir()
221 : {
222 305 : SwFrmFmt::tLayoutDir nOldLayoutDir( GetFrmFmt().GetLayoutDir() );
223 :
224 305 : SwAnchoredObject::UpdateLayoutDir();
225 :
226 621 : if ( !NotYetPositioned() &&
227 11 : GetFrmFmt().GetLayoutDir() != nOldLayoutDir &&
228 305 : GetFrmFmt().GetDoc()->get(IDocumentSettingAccess::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE) &&
229 0 : !IsOutsidePage() )
230 : {
231 0 : mbCaptureAfterLayoutDirChange = true;
232 : }
233 305 : }
234 :
235 : // --> #i62875#
236 0 : bool SwAnchoredDrawObject::IsOutsidePage() const
237 : {
238 0 : bool bOutsidePage( false );
239 :
240 0 : if ( !NotYetPositioned() && GetPageFrm() )
241 : {
242 0 : SwRect aTmpRect( GetObjRect() );
243 : bOutsidePage =
244 0 : ( aTmpRect.Intersection( GetPageFrm()->Frm() ) != GetObjRect() );
245 : }
246 :
247 0 : return bOutsidePage;
248 : }
249 :
250 : // =============================================================================
251 : // #i26791# - implementation of pure virtual method declared in
252 : // base class <SwAnchoredObject>
253 : // =============================================================================
254 1572 : void SwAnchoredDrawObject::MakeObjPos()
255 : {
256 1572 : if ( IsPositioningInProgress() )
257 : {
258 : // nothind to do - positioning already in progress
259 0 : return;
260 : }
261 :
262 1572 : if ( mbValidPos )
263 : {
264 : // nothing to do - position is valid
265 1260 : return;
266 : }
267 :
268 : // --> #i28749# - anchored drawing object has to be attached
269 : // to anchor frame
270 312 : if ( mbNotYetAttachedToAnchorFrame )
271 : {
272 : OSL_FAIL( "<SwAnchoredDrawObject::MakeObjPos() - drawing object not yet attached to anchor frame -> no positioning" );
273 0 : return;
274 : }
275 :
276 : SwDrawContact* pDrawContact =
277 312 : static_cast<SwDrawContact*>(::GetUserCall( GetDrawObj() ));
278 :
279 : // --> #i28749# - if anchored drawing object hasn't been yet
280 : // positioned, convert its positioning attributes, if its positioning
281 : // attributes are given in horizontal left-to-right layout.
282 : // --> #i36010# - Note: horizontal left-to-right layout is made
283 : // the default layout direction for <SwDrawFrmFmt> instances. Thus, it has
284 : // to be adjusted manually, if no adjustment of the positioning attributes
285 : // have to be performed here.
286 : // --> #i35635# - additionally move drawing object to the visible layer.
287 312 : if ( mbNotYetPositioned )
288 : {
289 : // --> #i35635#
290 294 : pDrawContact->MoveObjToVisibleLayer( DrawObj() );
291 : // --> perform conversion of positioning
292 : // attributes only for 'master' drawing objects
293 : // #i44334#, #i44681# - check, if positioning
294 : // attributes already have been set.
295 588 : if ( !GetDrawObj()->ISA(SwDrawVirtObj) &&
296 294 : !static_cast<SwDrawFrmFmt&>(GetFrmFmt()).IsPosAttrSet() )
297 : {
298 280 : _SetPositioningAttr();
299 : }
300 : // -->
301 : // - reset internal flag after all needed actions are performed to
302 : // avoid callbacks from drawing layer
303 294 : mbNotYetPositioned = false;
304 : }
305 :
306 : // indicate that positioning is in progress
307 : {
308 312 : SwObjPositioningInProgress aObjPosInProgress( *this );
309 :
310 : // determine relative position of drawing object and set it
311 312 : switch ( pDrawContact->GetAnchorId() )
312 : {
313 : case FLY_AS_CHAR:
314 : {
315 : // indicate that position will be valid after positioning is performed
316 249 : mbValidPos = true;
317 : // nothing to do, because as-character anchored objects are positioned
318 : // during the format of its anchor frame - see <SwFlyCntPortion::SetBase(..)>
319 : }
320 249 : break;
321 : case FLY_AT_PARA:
322 : case FLY_AT_CHAR:
323 : {
324 : // --> #i32795# - move intrinsic positioning to
325 : // helper method <_MakeObjPosAnchoredAtPara()>
326 56 : _MakeObjPosAnchoredAtPara();
327 : }
328 56 : break;
329 : case FLY_AT_PAGE:
330 : case FLY_AT_FLY:
331 : {
332 : // --> #i32795# - move intrinsic positioning to
333 : // helper method <_MakeObjPosAnchoredAtLayout()>
334 7 : _MakeObjPosAnchoredAtLayout();
335 : }
336 7 : break;
337 : default:
338 : {
339 : OSL_FAIL( "<SwAnchoredDrawObject::MakeObjPos()> - unknown anchor type - please inform OD." );
340 : }
341 : }
342 :
343 : // keep, current object rectangle
344 : // --> #i34748# - use new method <SetLastObjRect(..)>
345 312 : SetLastObjRect( GetObjRect().SVRect() );
346 :
347 : // Assure for 'master' drawing object, that it's registered at the correct page.
348 : // Perform check not for as-character anchored drawing objects and only if
349 : // the anchor frame is valid.
350 936 : if ( !GetDrawObj()->ISA(SwDrawVirtObj) &&
351 375 : !pDrawContact->ObjAnchoredAsChar() &&
352 63 : GetAnchorFrm()->IsValid() )
353 : {
354 57 : pDrawContact->ChkPage();
355 312 : }
356 : }
357 :
358 : // --> #i62875#
359 312 : if ( mbCaptureAfterLayoutDirChange &&
360 0 : GetPageFrm() )
361 : {
362 0 : SwRect aPageRect( GetPageFrm()->Frm() );
363 0 : SwRect aObjRect( GetObjRect() );
364 0 : if ( aObjRect.Right() >= aPageRect.Right() + 10 )
365 : {
366 0 : Size aSize( aPageRect.Right() - aObjRect.Right(), 0 );
367 0 : DrawObj()->Move( aSize );
368 0 : aObjRect = GetObjRect();
369 : }
370 :
371 0 : if ( aObjRect.Left() + 10 <= aPageRect.Left() )
372 : {
373 0 : Size aSize( aPageRect.Left() - aObjRect.Left(), 0 );
374 0 : DrawObj()->Move( aSize );
375 : }
376 :
377 0 : mbCaptureAfterLayoutDirChange = false;
378 : }
379 : }
380 :
381 : /** method for the intrinsic positioning of a at-paragraph|at-character
382 : anchored drawing object
383 :
384 : #i32795# - helper method for method <MakeObjPos>
385 :
386 : @author OD
387 : */
388 56 : void SwAnchoredDrawObject::_MakeObjPosAnchoredAtPara()
389 : {
390 : // --> #i32795# - adopt positioning algorithm from Writer
391 : // fly frames, which are anchored at paragraph|at character
392 :
393 : // Determine, if anchor frame can/has to be formatted.
394 : // If yes, after each object positioning the anchor frame is formatted.
395 : // If after the anchor frame format the object position isn't valid, the
396 : // object is positioned again.
397 : // --> #i43255# - refine condition: anchor frame format not
398 : // allowed, if another anchored object, has to be consider its wrap influence
399 : // --> #i50356# - format anchor frame containing the anchor
400 : // position. E.g., for at-character anchored object this can be the follow
401 : // frame of the anchor frame, which contains the anchor character.
402 : const bool bFormatAnchor =
403 112 : !static_cast<const SwTxtFrm*>( GetAnchorFrmContainingAnchPos() )->IsAnyJoinLocked() &&
404 106 : !ConsiderObjWrapInfluenceOnObjPos() &&
405 106 : !ConsiderObjWrapInfluenceOfOtherObjs();
406 :
407 56 : if ( bFormatAnchor )
408 : {
409 : // --> #i50356#
410 50 : GetAnchorFrmContainingAnchPos()->Calc();
411 : }
412 :
413 56 : bool bOscillationDetected = false;
414 56 : SwObjPosOscillationControl aObjPosOscCtrl( *this );
415 : // --> #i3317# - boolean, to apply temporarly the
416 : // 'straightforward positioning process' for the frame due to its
417 : // overlapping with a previous column.
418 56 : bool bConsiderWrapInfluenceDueToOverlapPrevCol( false );
419 56 : do {
420 : // indicate that position will be valid after positioning is performed
421 56 : mbValidPos = true;
422 :
423 : // --> #i35640# - correct scope for <SwPosNotify> instance
424 : {
425 : // create instance of <SwPosNotify> for correct notification
426 56 : SwPosNotify aPosNotify( this );
427 :
428 : // determine and set position
429 : objectpositioning::SwToCntntAnchoredObjectPosition
430 112 : aObjPositioning( *DrawObj() );
431 56 : aObjPositioning.CalcPosition();
432 :
433 : // get further needed results of the positioning algorithm
434 56 : SetVertPosOrientFrm ( aObjPositioning.GetVertPosOrientFrm() );
435 56 : _SetDrawObjAnchor();
436 :
437 : // check for object position oscillation, if position has changed.
438 56 : if ( GetObjRect().Pos() != aPosNotify.LastObjPos() )
439 : {
440 47 : bOscillationDetected = aObjPosOscCtrl.OscillationDetected();
441 56 : }
442 : }
443 : // format anchor frame, if requested.
444 : // Note: the format of the anchor frame can cause the object position
445 : // to be invalid.
446 56 : if ( bFormatAnchor )
447 : {
448 : // --> #i50356#
449 50 : GetAnchorFrmContainingAnchPos()->Calc();
450 : }
451 :
452 : // --> #i3317#
453 106 : if ( !ConsiderObjWrapInfluenceOnObjPos() &&
454 50 : OverlapsPrevColumn() )
455 : {
456 0 : bConsiderWrapInfluenceDueToOverlapPrevCol = true;
457 : }
458 56 : } while ( !mbValidPos && !bOscillationDetected &&
459 0 : !bConsiderWrapInfluenceDueToOverlapPrevCol );
460 :
461 : // --> #i3317# - consider a detected oscillation and overlapping
462 : // with previous column.
463 : // temporarly consider the anchored objects wrapping style influence
464 56 : if ( bOscillationDetected || bConsiderWrapInfluenceDueToOverlapPrevCol )
465 : {
466 0 : SetTmpConsiderWrapInfluence( true );
467 0 : SetRestartLayoutProcess( true );
468 56 : }
469 56 : }
470 :
471 : /** method for the intrinsic positioning of a at-page|at-frame anchored
472 : drawing object
473 :
474 : #i32795# - helper method for method <MakeObjPos>
475 :
476 : @author OD
477 : */
478 7 : void SwAnchoredDrawObject::_MakeObjPosAnchoredAtLayout()
479 : {
480 : // indicate that position will be valid after positioning is performed
481 7 : mbValidPos = true;
482 :
483 : // create instance of <SwPosNotify> for correct notification
484 7 : SwPosNotify aPosNotify( this );
485 :
486 : // determine position
487 : objectpositioning::SwToLayoutAnchoredObjectPosition
488 14 : aObjPositioning( *DrawObj() );
489 7 : aObjPositioning.CalcPosition();
490 :
491 : // set position
492 :
493 : // --> #i31698#
494 : // --> #i34995# - setting anchor position needed for filters,
495 : // especially for the xml-filter to the OpenOffice.org file format
496 : {
497 : const Point aNewAnchorPos =
498 7 : GetAnchorFrm()->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) );
499 7 : DrawObj()->SetAnchorPos( aNewAnchorPos );
500 : // --> #i70122# - missing invalidation
501 7 : InvalidateObjRectWithSpaces();
502 : }
503 7 : SetCurrRelPos( aObjPositioning.GetRelPos() );
504 7 : const SwFrm* pAnchorFrm = GetAnchorFrm();
505 7 : SWRECTFN( pAnchorFrm );
506 7 : const Point aAnchPos( (pAnchorFrm->Frm().*fnRect->fnGetPos)() );
507 7 : SetObjLeft( aAnchPos.X() + GetCurrRelPos().X() );
508 14 : SetObjTop( aAnchPos.Y() + GetCurrRelPos().Y() );
509 7 : }
510 :
511 56 : void SwAnchoredDrawObject::_SetDrawObjAnchor()
512 : {
513 : // new anchor position
514 : // --> #i31698# -
515 : Point aNewAnchorPos =
516 56 : GetAnchorFrm()->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) );
517 56 : Point aCurrAnchorPos = GetDrawObj()->GetAnchorPos();
518 56 : if ( aNewAnchorPos != aCurrAnchorPos )
519 : {
520 : // determine movement to be applied after setting the new anchor position
521 45 : Size aMove( aCurrAnchorPos.getX() - aNewAnchorPos.getX(),
522 90 : aCurrAnchorPos.getY() - aNewAnchorPos.getY() );
523 : // set new anchor position
524 45 : DrawObj()->SetAnchorPos( aNewAnchorPos );
525 : // correct object position, caused by setting new anchor position
526 45 : DrawObj()->Move( aMove );
527 : // --> #i70122# - missing invalidation
528 45 : InvalidateObjRectWithSpaces();
529 : }
530 56 : }
531 :
532 : /** method to invalidate the given page frame
533 :
534 : #i28701#
535 :
536 : @author OD
537 : */
538 20 : void SwAnchoredDrawObject::_InvalidatePage( SwPageFrm* _pPageFrm )
539 : {
540 20 : if ( _pPageFrm && !_pPageFrm->GetFmt()->GetDoc()->IsInDtor() )
541 : {
542 20 : if ( _pPageFrm->GetUpper() )
543 : {
544 : // --> #i35007# - correct invalidation for as-character
545 : // anchored objects.
546 20 : if ( GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR )
547 : {
548 9 : _pPageFrm->InvalidateFlyInCnt();
549 : }
550 : else
551 : {
552 11 : _pPageFrm->InvalidateFlyLayout();
553 : }
554 :
555 20 : SwRootFrm* pRootFrm = static_cast<SwRootFrm*>(_pPageFrm->GetUpper());
556 20 : pRootFrm->DisallowTurbo();
557 20 : if ( pRootFrm->GetTurbo() )
558 : {
559 0 : const SwCntntFrm* pTmpFrm = pRootFrm->GetTurbo();
560 0 : pRootFrm->ResetTurbo();
561 0 : pTmpFrm->InvalidatePage();
562 : }
563 20 : pRootFrm->SetIdleFlags();
564 : }
565 : }
566 20 : }
567 :
568 1064 : void SwAnchoredDrawObject::InvalidateObjPos()
569 : {
570 : // --> #i28701# - check, if invalidation is allowed
571 1082 : if ( mbValidPos &&
572 18 : InvalidationOfPosAllowed() )
573 : {
574 18 : mbValidPos = false;
575 : // --> #i68520#
576 18 : InvalidateObjRectWithSpaces();
577 :
578 : // --> #i44339# - check, if anchor frame exists.
579 18 : if ( GetAnchorFrm() )
580 : {
581 : // --> #118547# - notify anchor frame of as-character
582 : // anchored object, because its positioned by the format of its anchor frame.
583 : // --> #i44559# - assure, that text hint is already
584 : // existing in the text frame
585 36 : if ( GetAnchorFrm()->ISA(SwTxtFrm) &&
586 18 : (GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) )
587 : {
588 7 : SwTxtFrm* pAnchorTxtFrm( static_cast<SwTxtFrm*>(AnchorFrm()) );
589 14 : if ( pAnchorTxtFrm->GetTxtNode()->GetpSwpHints() &&
590 7 : pAnchorTxtFrm->CalcFlyPos( &GetFrmFmt() ) != STRING_LEN )
591 : {
592 7 : AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, &GetFrmFmt() );
593 : }
594 : }
595 :
596 18 : SwPageFrm* pPageFrm = AnchorFrm()->FindPageFrm();
597 18 : _InvalidatePage( pPageFrm );
598 :
599 : // --> #i32270# - also invalidate page frame, at which the
600 : // drawing object is registered at.
601 18 : SwPageFrm* pPageFrmRegisteredAt = GetPageFrm();
602 18 : if ( pPageFrmRegisteredAt &&
603 : pPageFrmRegisteredAt != pPageFrm )
604 : {
605 0 : _InvalidatePage( pPageFrmRegisteredAt );
606 : }
607 : // #i33751#, #i34060# - method <GetPageFrmOfAnchor()>
608 : // is replaced by method <FindPageFrmOfAnchor()>. It's return value
609 : // have to be checked.
610 18 : SwPageFrm* pPageFrmOfAnchor = FindPageFrmOfAnchor();
611 18 : if ( pPageFrmOfAnchor &&
612 2 : pPageFrmOfAnchor != pPageFrm &&
613 : pPageFrmOfAnchor != pPageFrmRegisteredAt )
614 : {
615 2 : _InvalidatePage( pPageFrmOfAnchor );
616 : }
617 : }
618 : }
619 1064 : }
620 :
621 8102 : SwFrmFmt& SwAnchoredDrawObject::GetFrmFmt()
622 : {
623 : OSL_ENSURE( static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt(),
624 : "<SwAnchoredDrawObject::GetFrmFmt()> - missing frame format -> crash." );
625 8102 : return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt());
626 : }
627 5088 : const SwFrmFmt& SwAnchoredDrawObject::GetFrmFmt() const
628 : {
629 : OSL_ENSURE( static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt(),
630 : "<SwAnchoredDrawObject::GetFrmFmt()> - missing frame format -> crash." );
631 5088 : return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt());
632 : }
633 :
634 8650 : const SwRect SwAnchoredDrawObject::GetObjRect() const
635 : {
636 : // use geometry of drawing object
637 : //return GetDrawObj()->GetCurrentBoundRect();
638 8650 : return GetDrawObj()->GetSnapRect();
639 : }
640 :
641 : // --> #i70122#
642 356 : const SwRect SwAnchoredDrawObject::GetObjBoundRect() const
643 : {
644 : // Resize objects with relative width or height
645 356 : if ( GetDrawObj( )->GetRelativeWidth( ) || GetDrawObj()->GetRelativeHeight( ) )
646 : {
647 2 : Rectangle aPageRect = GetPageFrm( )->GetBoundRect( ).SVRect();
648 2 : Rectangle aCurrObjRect = GetDrawObj()->GetCurrentBoundRect();
649 :
650 2 : long nTargetWidth = aCurrObjRect.GetWidth( );
651 2 : if ( GetDrawObj( )->GetRelativeWidth( ) )
652 2 : nTargetWidth = aPageRect.GetWidth( ) * GetDrawObj( )->GetRelativeWidth( ).get( );
653 :
654 2 : long nTargetHeight = aCurrObjRect.GetHeight( );
655 2 : if ( GetDrawObj( )->GetRelativeHeight( ) )
656 2 : nTargetHeight = aPageRect.GetHeight( ) * GetDrawObj( )->GetRelativeHeight( ).get( );
657 :
658 2 : if ( nTargetWidth != aCurrObjRect.GetWidth( ) || nTargetHeight != aCurrObjRect.GetHeight( ) )
659 : {
660 2 : const_cast< SdrObject* >( GetDrawObj() )->Resize( aCurrObjRect.TopLeft(),
661 : Fraction( nTargetWidth, aCurrObjRect.GetWidth() ),
662 2 : Fraction( nTargetHeight, aCurrObjRect.GetHeight() ), false );
663 : }
664 : }
665 356 : return GetDrawObj()->GetCurrentBoundRect();
666 : }
667 :
668 : // --> #i68520#
669 175 : bool SwAnchoredDrawObject::_SetObjTop( const SwTwips _nTop )
670 : {
671 175 : SwTwips nDiff = _nTop - GetObjRect().Top();
672 175 : DrawObj()->Move( Size( 0, nDiff ) );
673 :
674 175 : return nDiff != 0;
675 : }
676 63 : bool SwAnchoredDrawObject::_SetObjLeft( const SwTwips _nLeft )
677 : {
678 63 : SwTwips nDiff = _nLeft - GetObjRect().Left();
679 63 : DrawObj()->Move( Size( nDiff, 0 ) );
680 :
681 63 : return nDiff != 0;
682 : }
683 :
684 : /** adjust positioning and alignment attributes for new anchor frame
685 :
686 : #i33313# - add second optional parameter <_pNewObjRect>
687 :
688 : @author OD
689 : */
690 0 : void SwAnchoredDrawObject::AdjustPositioningAttr( const SwFrm* _pNewAnchorFrm,
691 : const SwRect* _pNewObjRect )
692 : {
693 0 : SwTwips nHoriRelPos = 0;
694 0 : SwTwips nVertRelPos = 0;
695 0 : const Point aAnchorPos = _pNewAnchorFrm->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) );
696 : // --> #i33313#
697 0 : const SwRect aObjRect( _pNewObjRect ? *_pNewObjRect : GetObjRect() );
698 0 : const bool bVert = _pNewAnchorFrm->IsVertical();
699 0 : const bool bR2L = _pNewAnchorFrm->IsRightToLeft();
700 0 : if ( bVert )
701 : {
702 0 : nHoriRelPos = aObjRect.Top() - aAnchorPos.Y();
703 0 : nVertRelPos = aAnchorPos.X() - aObjRect.Right();
704 : }
705 0 : else if ( bR2L )
706 : {
707 0 : nHoriRelPos = aAnchorPos.X() - aObjRect.Right();
708 0 : nVertRelPos = aObjRect.Top() - aAnchorPos.Y();
709 : }
710 : else
711 : {
712 0 : nHoriRelPos = aObjRect.Left() - aAnchorPos.X();
713 0 : nVertRelPos = aObjRect.Top() - aAnchorPos.Y();
714 : }
715 :
716 0 : GetFrmFmt().SetFmtAttr( SwFmtHoriOrient( nHoriRelPos, text::HoriOrientation::NONE, text::RelOrientation::FRAME ) );
717 0 : GetFrmFmt().SetFmtAttr( SwFmtVertOrient( nVertRelPos, text::VertOrientation::NONE, text::RelOrientation::FRAME ) );
718 0 : }
719 :
720 : // --> #i34748# - change return type
721 0 : const Rectangle* SwAnchoredDrawObject::GetLastObjRect() const
722 : {
723 0 : return mpLastObjRect;
724 : }
725 :
726 : // --> #i34748# - change return type.
727 : // If member <mpLastObjRect> is NULL, create one.
728 1402 : void SwAnchoredDrawObject::SetLastObjRect( const Rectangle& _rNewLastRect )
729 : {
730 1402 : if ( !mpLastObjRect )
731 : {
732 294 : mpLastObjRect = new Rectangle;
733 : }
734 1402 : *(mpLastObjRect) = _rNewLastRect;
735 1402 : }
736 :
737 305 : void SwAnchoredDrawObject::ObjectAttachedToAnchorFrame()
738 : {
739 : // --> #i31698#
740 305 : SwAnchoredObject::ObjectAttachedToAnchorFrame();
741 :
742 305 : if ( mbNotYetAttachedToAnchorFrame )
743 : {
744 294 : mbNotYetAttachedToAnchorFrame = false;
745 : }
746 305 : }
747 :
748 : /** method to set positioning attributes
749 :
750 : #i35798#
751 : During load the positioning attributes aren't set.
752 : Thus, the positioning attributes are set by the current object geometry.
753 : This method is also used for the conversion for drawing objects
754 : (not anchored as-character) imported from OpenOffice.org file format
755 : once and directly before the first positioning.
756 :
757 : @author OD
758 : */
759 280 : void SwAnchoredDrawObject::_SetPositioningAttr()
760 : {
761 : SwDrawContact* pDrawContact =
762 280 : static_cast<SwDrawContact*>(GetUserCall( GetDrawObj() ));
763 :
764 280 : if ( !pDrawContact->ObjAnchoredAsChar() )
765 : {
766 39 : SwRect aObjRect( GetObjRect() );
767 :
768 39 : SwTwips nHoriPos = aObjRect.Left();
769 39 : SwTwips nVertPos = aObjRect.Top();
770 : // #i44334#, #i44681#
771 : // perform conversion only if position is in horizontal-left-to-right-layout.
772 39 : if ( GetFrmFmt().GetPositionLayoutDir() ==
773 : text::PositionLayoutDir::PositionInHoriL2R )
774 : {
775 3 : SwFrmFmt::tLayoutDir eLayoutDir = GetFrmFmt().GetLayoutDir();
776 3 : switch ( eLayoutDir )
777 : {
778 : case SwFrmFmt::HORI_L2R:
779 : {
780 : // nothing to do
781 : }
782 3 : break;
783 : case SwFrmFmt::HORI_R2L:
784 : {
785 0 : nHoriPos = -aObjRect.Left() - aObjRect.Width();
786 : }
787 0 : break;
788 : case SwFrmFmt::VERT_R2L:
789 : {
790 0 : nHoriPos = aObjRect.Top();
791 0 : nVertPos = -aObjRect.Left() - aObjRect.Width();
792 : }
793 0 : break;
794 : default:
795 : {
796 : OSL_FAIL( "<SwAnchoredDrawObject::_SetPositioningAttr()> - unsupported layout direction" );
797 : }
798 : }
799 : }
800 :
801 : // --> #i71182#
802 : // only change position - do not lose other attributes
803 39 : SwFmtHoriOrient aHori( GetFrmFmt().GetHoriOrient() );
804 39 : aHori.SetPos( nHoriPos );
805 39 : GetFrmFmt().SetFmtAttr( aHori );
806 :
807 78 : SwFmtVertOrient aVert( GetFrmFmt().GetVertOrient() );
808 :
809 39 : aVert.SetPos( nVertPos );
810 39 : GetFrmFmt().SetFmtAttr( aVert );
811 :
812 : // --> #i36010# - set layout direction of the position
813 39 : GetFrmFmt().SetPositionLayoutDir(
814 78 : text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
815 : }
816 : // --> #i65798# - also for as-character anchored objects
817 : // --> #i45952# - indicate that position
818 : // attributes are set now.
819 280 : static_cast<SwDrawFrmFmt&>(GetFrmFmt()).PosAttrSet();
820 280 : }
821 :
822 110 : void SwAnchoredDrawObject::NotifyBackground( SwPageFrm* _pPageFrm,
823 : const SwRect& _rRect,
824 : PrepareHint _eHint )
825 : {
826 110 : ::Notify_Background( GetDrawObj(), _pPageFrm, _rRect, _eHint, sal_True );
827 110 : }
828 :
829 : /** method to assure that anchored object is registered at the correct
830 : page frame
831 :
832 : #i28701#
833 :
834 : @author OD
835 : */
836 56 : void SwAnchoredDrawObject::RegisterAtCorrectPage()
837 : {
838 56 : SwPageFrm* pPageFrm( 0L );
839 56 : if ( GetVertPosOrientFrm() )
840 : {
841 56 : pPageFrm = const_cast<SwPageFrm*>(GetVertPosOrientFrm()->FindPageFrm());
842 : }
843 56 : if ( pPageFrm && GetPageFrm() != pPageFrm )
844 : {
845 0 : if ( GetPageFrm() )
846 0 : GetPageFrm()->RemoveDrawObjFromPage( *this );
847 0 : pPageFrm->AppendDrawObjToPage( *this );
848 : }
849 155 : }
850 :
851 : // =============================================================================
852 :
853 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|