reintroduce ScCaptionPtr
[LibreOffice.git] / sc / source / core / data / postit.cxx
blob69c2d4887dcc38f4280e5c054d666e8557ef7ac6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <postit.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
25 #include <unotools/useroptions.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svdocapt.hxx>
28 #include <editeng/outlobj.hxx>
29 #include <editeng/editobj.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <scitems.hxx>
33 #include <svx/xlnstit.hxx>
34 #include <svx/xlnstwit.hxx>
35 #include <svx/xlnstcit.hxx>
36 #include <svx/sxcecitm.hxx>
37 #include <svx/xflclit.hxx>
38 #include <svx/sdshitm.hxx>
39 #include <svx/sdsxyitm.hxx>
40 #include <tools/gen.hxx>
42 #include <document.hxx>
43 #include <docpool.hxx>
44 #include <patattr.hxx>
45 #include <drwlayer.hxx>
46 #include <userdat.hxx>
47 #include <detfunc.hxx>
48 #include <editutil.hxx>
50 using namespace com::sun::star;
52 namespace {
54 const long SC_NOTECAPTION_WIDTH = 2900; /// Default width of note caption textbox.
55 const long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; /// Maximum width of temporary note caption textbox.
56 const long SC_NOTECAPTION_HEIGHT = 1800; /// Default height of note caption textbox.
57 const long SC_NOTECAPTION_CELLDIST = 600; /// Default distance of note captions to border of anchor cell.
58 const long SC_NOTECAPTION_OFFSET_Y = -1500; /// Default Y offset of note captions to top border of anchor cell.
59 const long SC_NOTECAPTION_OFFSET_X = 1500; /// Default X offset of note captions to left border of anchor cell.
60 const long SC_NOTECAPTION_BORDERDIST_TEMP = 100; /// Distance of temporary note captions to visible sheet area.
62 /** Static helper functions for caption objects. */
63 class ScCaptionUtil
65 public:
66 /** Moves the caption object to the correct layer according to passed visibility. */
67 static void SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown );
68 /** Sets basic caption settings required for note caption objects. */
69 static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown );
70 /** Stores the cell position of the note in the user data area of the caption. */
71 static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos );
72 /** Sets all default formatting attributes to the caption object. */
73 static void SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc );
74 /** Updates caption item set according to the passed item set while removing shadow items. */
75 static void SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet );
78 void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
80 SdrLayerID nLayer = bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN;
81 if( nLayer != rCaption.GetLayer() )
82 rCaption.SetLayer( nLayer );
85 void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown )
87 SetCaptionLayer( rCaption, bShown );
88 rCaption.SetFixedTail();
89 rCaption.SetSpecialTextBoxShadow();
92 void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos )
94 // pass true to ScDrawLayer::GetObjData() to create the object data entry
95 ScDrawObjData* pObjData = ScDrawLayer::GetObjData( &rCaption, true );
96 OSL_ENSURE( pObjData, "ScCaptionUtil::SetCaptionUserData - missing drawing object user data" );
97 pObjData->maStart = rPos;
98 pObjData->meType = ScDrawObjData::CellNote;
101 void ScCaptionUtil::SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc )
103 SfxItemSet aItemSet = rCaption.GetMergedItemSet();
105 // caption tail arrow
106 ::basegfx::B2DPolygon aTriangle;
107 aTriangle.append( ::basegfx::B2DPoint( 10.0, 0.0 ) );
108 aTriangle.append( ::basegfx::B2DPoint( 0.0, 30.0 ) );
109 aTriangle.append( ::basegfx::B2DPoint( 20.0, 30.0 ) );
110 aTriangle.setClosed( true );
111 /* Line ends are now created with an empty name. The
112 checkForUniqueItem() method then finds a unique name for the item's
113 value. */
114 aItemSet.Put( XLineStartItem( OUString(), ::basegfx::B2DPolyPolygon( aTriangle ) ) );
115 aItemSet.Put( XLineStartWidthItem( 200 ) );
116 aItemSet.Put( XLineStartCenterItem( false ) );
117 aItemSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
118 aItemSet.Put( XFillColorItem( OUString(), ScDetectiveFunc::GetCommentColor() ) );
119 aItemSet.Put( SdrCaptionEscDirItem( SdrCaptionEscDir::BestFit ) );
121 // shadow
122 /* SdrShadowItem has sal_False, instead the shadow is set for the
123 rectangle only with SetSpecialTextBoxShadow() when the object is
124 created (item must be set to adjust objects from older files). */
125 aItemSet.Put( makeSdrShadowItem( false ) );
126 aItemSet.Put( makeSdrShadowXDistItem( 100 ) );
127 aItemSet.Put( makeSdrShadowYDistItem( 100 ) );
129 // text attributes
130 aItemSet.Put( makeSdrTextLeftDistItem( 100 ) );
131 aItemSet.Put( makeSdrTextRightDistItem( 100 ) );
132 aItemSet.Put( makeSdrTextUpperDistItem( 100 ) );
133 aItemSet.Put( makeSdrTextLowerDistItem( 100 ) );
134 aItemSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
135 aItemSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
136 // use the default cell style to be able to modify the caption font
137 const ScPatternAttr& rDefPattern = rDoc.GetPool()->GetDefaultItem( ATTR_PATTERN );
138 rDefPattern.FillEditItemSet( &aItemSet );
140 rCaption.SetMergedItemSet( aItemSet );
143 void ScCaptionUtil::SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet )
145 // copy all items
146 rCaption.SetMergedItemSet( rItemSet );
147 // reset shadow items
148 rCaption.SetMergedItem( makeSdrShadowItem( false ) );
149 rCaption.SetMergedItem( makeSdrShadowXDistItem( 100 ) );
150 rCaption.SetMergedItem( makeSdrShadowYDistItem( 100 ) );
151 rCaption.SetSpecialTextBoxShadow();
154 /** Helper for creation and manipulation of caption drawing objects independent
155 from cell annotations. */
156 class ScCaptionCreator
158 public:
159 /** Create a new caption. The caption will not be inserted into the document. */
160 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront );
161 /** Manipulate an existing caption. */
162 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption );
164 /** Returns the drawing layer page of the sheet contained in maPos. */
165 SdrPage* GetDrawPage();
166 /** Returns the caption drawing object. */
167 ScCaptionPtr & GetCaption() { return mxCaption; }
169 /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
170 void FitCaptionToRect( const tools::Rectangle* pVisRect = nullptr );
171 /** Places the caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */
172 void AutoPlaceCaption( const tools::Rectangle* pVisRect = nullptr );
173 /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */
174 void UpdateCaptionPos();
176 protected:
177 /** Helper constructor for derived classes. */
178 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos );
180 /** Calculates the caption tail position according to current cell position. */
181 Point CalcTailPos( bool bTailFront );
182 /** Implements creation of the caption object. The caption will not be inserted into the document. */
183 void CreateCaption( bool bShown, bool bTailFront );
185 private:
186 /** Initializes all members. */
187 void Initialize();
188 /** Returns the passed rectangle if existing, page rectangle otherwise. */
189 const tools::Rectangle& GetVisRect( const tools::Rectangle* pVisRect ) const { return pVisRect ? *pVisRect : maPageRect; }
191 private:
192 ScDocument& mrDoc;
193 ScAddress maPos;
194 ScCaptionPtr mxCaption;
195 tools::Rectangle maPageRect;
196 tools::Rectangle maCellRect;
197 bool mbNegPage;
200 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront ) :
201 mrDoc( rDoc ),
202 maPos( rPos )
204 Initialize();
205 CreateCaption( true/*bShown*/, bTailFront );
208 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption ) :
209 mrDoc( rDoc ),
210 maPos( rPos ),
211 mxCaption( xCaption )
213 Initialize();
216 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) :
217 mrDoc( rDoc ),
218 maPos( rPos )
220 Initialize();
223 SdrPage* ScCaptionCreator::GetDrawPage()
225 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
226 return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : nullptr;
229 void ScCaptionCreator::FitCaptionToRect( const tools::Rectangle* pVisRect )
231 const tools::Rectangle& rVisRect = GetVisRect( pVisRect );
233 // tail position
234 Point aTailPos = mxCaption->GetTailPos();
235 aTailPos.setX( ::std::max( ::std::min( aTailPos.X(), rVisRect.Right() ), rVisRect.Left() ) );
236 aTailPos.setY( ::std::max( ::std::min( aTailPos.Y(), rVisRect.Bottom() ), rVisRect.Top() ) );
237 mxCaption->SetTailPos( aTailPos );
239 // caption rectangle
240 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
241 Point aCaptPos = aCaptRect.TopLeft();
242 // move textbox inside right border of visible area
243 aCaptPos.setX( ::std::min< long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() ) );
244 // move textbox inside left border of visible area (this may move it outside on right side again)
245 aCaptPos.setX( ::std::max< long >( aCaptPos.X(), rVisRect.Left() ) );
246 // move textbox inside bottom border of visible area
247 aCaptPos.setY( ::std::min< long >( aCaptPos.Y(), rVisRect.Bottom() - aCaptRect.GetHeight() ) );
248 // move textbox inside top border of visible area (this may move it outside on bottom side again)
249 aCaptPos.setY( ::std::max< long >( aCaptPos.Y(), rVisRect.Top() ) );
250 // update caption
251 aCaptRect.SetPos( aCaptPos );
252 mxCaption->SetLogicRect( aCaptRect );
255 void ScCaptionCreator::AutoPlaceCaption( const tools::Rectangle* pVisRect )
257 const tools::Rectangle& rVisRect = GetVisRect( pVisRect );
259 // caption rectangle
260 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
261 long nWidth = aCaptRect.GetWidth();
262 long nHeight = aCaptRect.GetHeight();
264 // n***Space contains available space between border of visible area and cell
265 long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1;
266 long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1;
267 long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1;
268 long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1;
270 // nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area
271 long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST;
272 long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST;
274 // bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area
275 bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell
276 bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell
277 bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area
279 // bFitsHeight*** == true means height of textbox fits into vertical free space of visible area
280 bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell
281 bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell
282 bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area
284 // bFits*** == true means the textbox fits completely into free space of visible area
285 bool bFitsLeft = bFitsWidthLeft && bFitsHeight;
286 bool bFitsRight = bFitsWidthRight && bFitsHeight;
287 bool bFitsTop = bFitsWidth && bFitsHeightTop;
288 bool bFitsBottom = bFitsWidth && bFitsHeightBottom;
290 Point aCaptPos;
291 // use left/right placement if possible, or if top/bottom placement not possible
292 if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) )
294 // prefer left in RTL sheet and right in LTR sheets
295 bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight);
296 bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft);
297 // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left
298 if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) )
299 aCaptPos.setX( maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth );
300 else // to right
301 aCaptPos.setX( maCellRect.Right() + SC_NOTECAPTION_CELLDIST );
302 // Y position according to top cell border
303 aCaptPos.setY( maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y );
305 else // top or bottom placement
307 // X position
308 aCaptPos.setX( maCellRect.Left() + SC_NOTECAPTION_OFFSET_X );
309 // top placement, if possible
310 if( bFitsTop )
311 aCaptPos.setY( maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight );
312 else // bottom placement
313 aCaptPos.setY( maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST );
316 // update textbox position in note caption object
317 aCaptRect.SetPos( aCaptPos );
318 mxCaption->SetLogicRect( aCaptRect );
319 FitCaptionToRect( pVisRect );
322 void ScCaptionCreator::UpdateCaptionPos()
324 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
326 // update caption position
327 const Point& rOldTailPos = mxCaption->GetTailPos();
328 Point aTailPos = CalcTailPos( false );
329 if( rOldTailPos != aTailPos )
331 // create drawing undo action
332 if( pDrawLayer && pDrawLayer->IsRecording() )
333 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *mxCaption ) );
334 // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly)
335 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
336 long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right());
337 if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth();
338 long nDiffY = aCaptRect.Top() - rOldTailPos.Y();
339 aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) );
340 // set new tail position and caption rectangle
341 mxCaption->SetTailPos( aTailPos );
342 mxCaption->SetLogicRect( aCaptRect );
343 // fit caption into draw page
344 FitCaptionToRect();
347 // update cell position in caption user data
348 ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mxCaption.get(), maPos.Tab() );
349 if( pCaptData && (maPos != pCaptData->maStart) )
351 // create drawing undo action
352 if( pDrawLayer && pDrawLayer->IsRecording() )
353 pDrawLayer->AddCalcUndo( std::make_unique<ScUndoObjData>( mxCaption.get(), pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) );
354 // set new position
355 pCaptData->maStart = maPos;
359 Point ScCaptionCreator::CalcTailPos( bool bTailFront )
361 // tail position
362 bool bTailLeft = bTailFront != mbNegPage;
363 Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight();
364 // move caption point 1/10 mm inside cell
365 if( bTailLeft ) aTailPos.AdjustX(10 ); else aTailPos.AdjustX( -10 );
366 aTailPos.AdjustY(10);
367 return aTailPos;
370 void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
372 // create the caption drawing object
373 tools::Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
374 Point aTailPos = CalcTailPos( bTailFront );
375 mxCaption.reset(
376 new SdrCaptionObj(
377 *mrDoc.GetDrawLayer(), // TTTT should ret a ref?
378 aTextRect,
379 aTailPos));
380 // basic caption settings
381 ScCaptionUtil::SetBasicCaptionSettings( *mxCaption, bShown );
384 void ScCaptionCreator::Initialize()
386 maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true );
387 mbNegPage = mrDoc.IsNegativePage( maPos.Tab() );
388 if( SdrPage* pDrawPage = GetDrawPage() )
390 maPageRect = tools::Rectangle( Point( 0, 0 ), pDrawPage->GetSize() );
391 /* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
392 The call to Rectangle::Adjust() orders left/right coordinate
393 accordingly. */
394 maPageRect.Justify();
398 /** Helper for creation of permanent caption drawing objects for cell notes. */
399 class ScNoteCaptionCreator : public ScCaptionCreator
401 public:
402 /** Create a new caption object and inserts it into the document. */
403 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
404 /** Manipulate an existing caption. */
405 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown );
408 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
409 ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet
411 SdrPage* pDrawPage = GetDrawPage();
412 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
413 if( pDrawPage )
415 // create the caption drawing object
416 CreateCaption( rNoteData.mbShown, false );
417 rNoteData.mxCaption = GetCaption();
418 OSL_ENSURE( rNoteData.mxCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
419 if( rNoteData.mxCaption )
421 // store note position in user data of caption object
422 ScCaptionUtil::SetCaptionUserData( *rNoteData.mxCaption, rPos );
423 // insert object into draw page
424 pDrawPage->InsertObject( rNoteData.mxCaption.get() );
429 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown ) :
430 ScCaptionCreator( rDoc, rPos, xCaption )
432 SdrPage* pDrawPage = GetDrawPage();
433 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
434 OSL_ENSURE( xCaption->getSdrPageFromSdrObject() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
435 if( pDrawPage && (xCaption->getSdrPageFromSdrObject() == pDrawPage) )
437 // store note position in user data of caption object
438 ScCaptionUtil::SetCaptionUserData( *xCaption, rPos );
439 // basic caption settings
440 ScCaptionUtil::SetBasicCaptionSettings( *xCaption, bShown );
441 // set correct tail position
442 xCaption->SetTailPos( CalcTailPos( false ) );
446 } // namespace
448 ScCaptionPtr::ScCaptionPtr() :
449 mpHead(nullptr), mpNext(nullptr), mpCaption(nullptr), mbNotOwner(false)
453 ScCaptionPtr::ScCaptionPtr( SdrCaptionObj* p ) :
454 mpHead(nullptr), mpNext(nullptr), mpCaption(p), mbNotOwner(false)
456 if (p)
458 newHead();
462 ScCaptionPtr::ScCaptionPtr( const ScCaptionPtr& r ) :
463 mpHead(r.mpHead), mpCaption(r.mpCaption), mbNotOwner(false)
465 if (r.mpCaption)
467 assert(r.mpHead);
468 r.incRef();
469 // Insert into list.
470 mpNext = r.mpNext;
471 r.mpNext = this;
473 else
475 assert(!r.mpHead);
476 mpNext = nullptr;
480 ScCaptionPtr::ScCaptionPtr( ScCaptionPtr&& r ) :
481 mpHead(r.mpHead), mpNext(r.mpNext), mpCaption(r.mpCaption), mbNotOwner(false)
483 r.replaceInList( this );
484 r.mpCaption = nullptr;
485 r.mbNotOwner = false;
488 ScCaptionPtr& ScCaptionPtr::operator=( ScCaptionPtr&& r )
490 assert(this != &r);
492 mpHead = r.mpHead;
493 mpNext = r.mpNext;
494 mpCaption = r.mpCaption;
495 mbNotOwner = r.mbNotOwner;
497 r.replaceInList( this );
498 r.mpCaption = nullptr;
499 r.mbNotOwner = false;
501 return *this;
504 ScCaptionPtr& ScCaptionPtr::operator=( const ScCaptionPtr& r )
506 if (this == &r)
507 return *this;
509 if (mpCaption == r.mpCaption)
511 // Two lists for the same caption is bad.
512 assert(!mpCaption || mpHead == r.mpHead);
513 assert(!mpCaption); // assigning same caption pointer within same list is weird
514 // Nullptr captions are not inserted to the list, so nothing to do here
515 // if both are.
516 return *this;
519 // Let's find some weird usage.
520 // Assigning without head doesn't make sense unless it is a nullptr caption.
521 assert(r.mpHead || !r.mpCaption);
522 // A nullptr caption must not be in a list and thus not have a head.
523 assert(!r.mpHead || r.mpCaption);
524 // Same captions were caught above, so here different heads must be present.
525 assert(r.mpHead != mpHead);
527 r.incRef();
528 decRefAndDestroy();
529 removeFromList();
531 mpCaption = r.mpCaption;
532 mbNotOwner = r.mbNotOwner;
533 // That head is this' master.
534 mpHead = r.mpHead;
535 // Insert into list.
536 mpNext = r.mpNext;
537 r.mpNext = this;
539 return *this;
542 void ScCaptionPtr::setNotOwner()
544 mbNotOwner = true;
547 ScCaptionPtr::Head::Head( ScCaptionPtr* p ) :
548 mpFirst(p), mnRefs(1)
552 void ScCaptionPtr::newHead()
554 assert(!mpHead);
555 mpHead = new Head(this);
558 void ScCaptionPtr::replaceInList( ScCaptionPtr* pNew )
560 if (!mpHead && !mpNext)
561 return;
563 assert(mpHead);
564 assert(mpCaption == pNew->mpCaption);
566 ScCaptionPtr* pThat = mpHead->mpFirst;
567 while (pThat && pThat != this && pThat->mpNext != this)
569 pThat = pThat->mpNext;
571 if (pThat && pThat != this)
573 assert(pThat->mpNext == this);
574 pThat->mpNext = pNew;
576 pNew->mpNext = mpNext;
577 if (mpHead->mpFirst == this)
578 mpHead->mpFirst = pNew;
580 mpHead = nullptr;
581 mpNext = nullptr;
584 void ScCaptionPtr::removeFromList()
586 if (!mpHead && !mpNext && !mpCaption)
587 return;
589 #if OSL_DEBUG_LEVEL > 0
590 oslInterlockedCount nCount = 0;
591 #endif
592 ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
593 while (pThat && pThat != this && pThat->mpNext != this)
595 // Use the walk to check consistency on the fly.
596 assert(pThat->mpHead == mpHead); // all belong to the same
597 assert(pThat->mpHead || !pThat->mpNext); // next without head is bad
598 assert(pThat->mpCaption == mpCaption);
599 pThat = pThat->mpNext;
600 #if OSL_DEBUG_LEVEL > 0
601 ++nCount;
602 #endif
604 assert(pThat || !mpHead); // not found only if this was standalone
605 if (pThat)
607 if (pThat != this)
609 #if OSL_DEBUG_LEVEL > 0
610 // The while loop above was not executed, and for this
611 // (pThat->mpNext) the loop below won't either.
612 ++nCount;
613 #endif
614 pThat->mpNext = mpNext;
616 #if OSL_DEBUG_LEVEL > 0
619 assert(pThat->mpHead == mpHead); // all belong to the same
620 assert(pThat->mpHead || !pThat->mpNext); // next without head is bad
621 assert(pThat->mpCaption == mpCaption);
622 ++nCount;
624 while ((pThat = pThat->mpNext) != nullptr);
625 #endif
627 #if OSL_DEBUG_LEVEL > 0
628 // If part of a list then refs were already decremented.
629 assert(nCount == (mpHead ? mpHead->mnRefs + 1 : 0));
630 #endif
631 if (mpHead && mpHead->mpFirst == this)
633 if (mpNext)
634 mpHead->mpFirst = mpNext;
635 else
637 // The only one destroys also head.
638 assert(mpHead->mnRefs == 0); // cough
639 delete mpHead; // DEAD now
642 mpHead = nullptr;
643 mpNext = nullptr;
646 void ScCaptionPtr::reset( SdrCaptionObj* p )
648 assert(!p || p != mpCaption);
649 #if OSL_DEBUG_LEVEL > 0
650 if (p)
652 // Check if we end up with a duplicated management in this list.
653 ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
654 while (pThat)
656 assert(pThat->mpCaption != p);
657 pThat = pThat->mpNext;
660 #endif
661 decRefAndDestroy();
662 removeFromList();
663 mpCaption = p;
664 mbNotOwner = false;
665 if (p)
667 newHead();
671 ScCaptionPtr::~ScCaptionPtr()
673 decRefAndDestroy();
674 removeFromList();
677 oslInterlockedCount ScCaptionPtr::getRefs() const
679 return mpHead ? mpHead->mnRefs : 0;
682 void ScCaptionPtr::incRef() const
684 if (mpHead)
685 osl_atomic_increment(&mpHead->mnRefs);
688 bool ScCaptionPtr::decRef() const
690 return mpHead && mpHead->mnRefs > 0 && !osl_atomic_decrement(&mpHead->mnRefs);
693 void ScCaptionPtr::decRefAndDestroy()
695 if (decRef())
697 assert(mpHead->mpFirst == this); // this must be one and only one
698 assert(!mpNext); // this must be one and only one
699 assert(mpCaption);
701 #if 0
702 // Quick workaround for when there are still cases where the caption
703 // pointer is dangling
704 mpCaption = nullptr;
705 mbNotOwner = false;
706 #else
707 // Destroying Draw Undo and some other delete the SdrObject, don't
708 // attempt that twice.
709 if (mbNotOwner)
711 mpCaption = nullptr;
712 mbNotOwner = false;
714 else
716 removeFromDrawPageAndFree( true ); // ignoring Undo
717 if (mpCaption)
719 // There's no draw page associated so removeFromDrawPageAndFree()
720 // didn't do anything, but still we want to delete the caption
721 // object. release()/dissolve() also resets mpCaption.
722 SdrObject* pObj = release();
723 SdrObject::Free( pObj );
726 #endif
727 delete mpHead;
728 mpHead = nullptr;
732 void ScCaptionPtr::insertToDrawPage( SdrPage& rDrawPage )
734 assert(mpHead && mpCaption);
736 rDrawPage.InsertObject( mpCaption );
739 void ScCaptionPtr::removeFromDrawPage( SdrPage& rDrawPage )
741 assert(mpHead && mpCaption);
742 SdrObject* pObj = rDrawPage.RemoveObject( mpCaption->GetOrdNum() );
743 assert(pObj == mpCaption); (void)pObj;
746 void ScCaptionPtr::removeFromDrawPageAndFree( bool bIgnoreUndo )
748 assert(mpHead && mpCaption);
749 SdrPage* pDrawPage(mpCaption->getSdrPageFromSdrObject());
750 SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page");
751 if (pDrawPage)
753 pDrawPage->RecalcObjOrdNums();
754 bool bRecording = false;
755 if(!bIgnoreUndo)
757 ScDrawLayer* pDrawLayer(dynamic_cast< ScDrawLayer* >(&mpCaption->getSdrModelFromSdrObject()));
758 SAL_WARN_IF( !pDrawLayer, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing layer");
759 // create drawing undo action (before removing the object to have valid draw page in undo action)
760 bRecording = (pDrawLayer && pDrawLayer->IsRecording());
761 if (bRecording)
762 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoDelObj>( *mpCaption ));
764 // remove the object from the drawing page, delete if undo is disabled
765 removeFromDrawPage( *pDrawPage );
766 // If called from outside mnRefs must be 1 to delete. If called from
767 // decRefAndDestroy() mnRefs is already 0.
768 if (!bRecording && getRefs() <= 1)
770 SdrObject* pObj = release();
771 SdrObject::Free( pObj );
776 SdrCaptionObj* ScCaptionPtr::release()
778 SdrCaptionObj* pTmp = mpCaption;
779 dissolve();
780 return pTmp;
783 void ScCaptionPtr::forget()
785 decRef();
786 removeFromList();
787 mpCaption = nullptr;
788 mbNotOwner = false;
791 void ScCaptionPtr::dissolve()
793 ScCaptionPtr::Head* pHead = mpHead;
794 ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : this);
795 while (pThat)
797 assert(!pThat->mpNext || pThat->mpHead); // next without head is bad
798 assert(pThat->mpHead == pHead); // same head required within one list
799 ScCaptionPtr* p = pThat->mpNext;
800 pThat->clear();
801 pThat = p;
803 assert(!mpHead && !mpNext && !mpCaption); // should had been cleared during list walk
804 delete pHead;
807 void ScCaptionPtr::clear()
809 mpHead = nullptr;
810 mpNext = nullptr;
811 mpCaption = nullptr;
812 mbNotOwner = false;
815 struct ScCaptionInitData
817 std::unique_ptr< SfxItemSet > mxItemSet; /// Caption object formatting.
818 std::unique_ptr< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting.
819 OUString maSimpleText; /// Simple text without formatting.
820 Point maCaptionOffset; /// Caption position relative to cell corner.
821 Size maCaptionSize; /// Size of the caption object.
822 bool mbDefaultPosSize; /// True = use default position and size for caption.
824 explicit ScCaptionInitData();
827 ScCaptionInitData::ScCaptionInitData() :
828 mbDefaultPosSize( true )
832 ScNoteData::ScNoteData( bool bShown ) :
833 mbShown( bShown )
837 sal_uInt32 ScPostIt::mnLastPostItId = 1;
839 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, sal_uInt32 nPostItId ) :
840 mrDoc( rDoc ),
841 maNoteData( false )
843 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
844 AutoStamp();
845 CreateCaption( rPos );
848 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote, sal_uInt32 nPostItId ) :
849 mrDoc( rDoc ),
850 maNoteData( rNote.maNoteData )
852 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
853 maNoteData.mxCaption.reset(nullptr);
854 CreateCaption( rPos, rNote.maNoteData.mxCaption.get() );
857 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId ) :
858 mrDoc( rDoc ),
859 maNoteData( rNoteData )
861 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
862 if( bAlwaysCreateCaption || maNoteData.mbShown )
863 CreateCaptionFromInitData( rPos );
866 ScPostIt::~ScPostIt()
868 RemoveCaption();
871 std::unique_ptr<ScPostIt> ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const
873 CreateCaptionFromInitData( rOwnPos );
874 return bCloneCaption ? std::make_unique<ScPostIt>( rDestDoc, rDestPos, *this, mnPostItId ) : std::make_unique<ScPostIt>( rDestDoc, rDestPos, maNoteData, false, mnPostItId );
877 void ScPostIt::SetDate( const OUString& rDate )
879 maNoteData.maDate = rDate;
882 void ScPostIt::SetAuthor( const OUString& rAuthor )
884 maNoteData.maAuthor = rAuthor;
887 void ScPostIt::AutoStamp()
889 maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date( Date::SYSTEM ) );
890 maNoteData.maAuthor = SvtUserOptions().GetID();
893 const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
895 if( maNoteData.mxCaption )
896 return maNoteData.mxCaption->GetOutlinerParaObject();
897 if( maNoteData.mxInitData.get() )
898 return maNoteData.mxInitData->mxOutlinerObj.get();
899 return nullptr;
902 const EditTextObject* ScPostIt::GetEditTextObject() const
904 const OutlinerParaObject* pOPO = GetOutlinerObject();
905 return pOPO ? &pOPO->GetTextObject() : nullptr;
908 OUString ScPostIt::GetText() const
910 if( const EditTextObject* pEditObj = GetEditTextObject() )
912 OUStringBuffer aBuffer;
913 ScNoteEditEngine& rEngine = mrDoc.GetNoteEngine();
914 rEngine.SetText(*pEditObj);
915 sal_Int32 nParaCount = rEngine.GetParagraphCount();
916 for( sal_Int32 nPara = 0; nPara < nParaCount; ++nPara )
918 if( nPara > 0 )
919 aBuffer.append( '\n' );
920 aBuffer.append(rEngine.GetText(nPara));
922 return aBuffer.makeStringAndClear();
924 if( maNoteData.mxInitData.get() )
925 return maNoteData.mxInitData->maSimpleText;
926 return OUString();
929 bool ScPostIt::HasMultiLineText() const
931 if( const EditTextObject* pEditObj = GetEditTextObject() )
932 return pEditObj->GetParagraphCount() > 1;
933 if( maNoteData.mxInitData.get() )
934 return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0;
935 return false;
938 void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
940 CreateCaptionFromInitData( rPos );
941 if( maNoteData.mxCaption )
942 maNoteData.mxCaption->SetText( rText );
945 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
947 CreateCaptionFromInitData( rPos );
948 return maNoteData.mxCaption.get();
951 void ScPostIt::ForgetCaption( bool bPreserveData )
953 if (bPreserveData)
955 // Used in clipboard when the originating document is destructed to be
956 // able to paste into another document. Caption size and relative
957 // position are not preserved but default created when pasted. Also the
958 // MergedItemSet can not be carried over or it had to be adapted to
959 // defaults and pool. At least preserve the text and outline object if
960 // possible.
961 ScCaptionInitData* pInitData = new ScCaptionInitData;
962 const OutlinerParaObject* pOPO = GetOutlinerObject();
963 if (pOPO)
964 pInitData->mxOutlinerObj.reset( new OutlinerParaObject(*pOPO));
965 pInitData->maSimpleText = GetText();
967 maNoteData.mxInitData.reset(pInitData);
968 maNoteData.mxCaption.forget();
970 else
972 /* This function is used in undo actions to give up the responsibility for
973 the caption object which is handled by separate drawing undo actions. */
974 maNoteData.mxCaption.forget();
975 maNoteData.mxInitData.reset();
979 void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow )
981 CreateCaptionFromInitData( rPos );
982 // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
983 maNoteData.mbShown = bShow;
984 if( maNoteData.mxCaption )
985 ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, bShow );
988 void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow )
990 CreateCaptionFromInitData( rPos );
991 if( maNoteData.mxCaption )
992 ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, maNoteData.mbShown || bShow );
995 void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
997 CreateCaptionFromInitData( rPos );
998 if( maNoteData.mxCaption )
1000 ScCaptionCreator aCreator( mrDoc, rPos, maNoteData.mxCaption );
1001 aCreator.UpdateCaptionPos();
1005 // private --------------------------------------------------------------------
1007 void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
1009 // Captions are not created in Undo documents and only rarely in Clipboard,
1010 // but otherwise we need caption or initial data.
1011 assert((maNoteData.mxCaption || maNoteData.mxInitData.get()) || mrDoc.IsUndo() || mrDoc.IsClipboard());
1012 if( maNoteData.mxInitData.get() )
1014 /* This function is called from ScPostIt::Clone() when copying cells
1015 to the clipboard/undo document, and when copying cells from the
1016 clipboard/undo document. The former should always be called first,
1017 so if called in an clipboard/undo document, the caption should have
1018 been created already. However, for clipboard in case the
1019 originating document was destructed a new caption has to be
1020 created. */
1021 OSL_ENSURE( !mrDoc.IsUndo() && (!mrDoc.IsClipboard() || !maNoteData.mxCaption),
1022 "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );
1024 /* #i104915# Never try to create notes in Undo document, leads to
1025 crash due to missing document members (e.g. row height array). */
1026 if( !maNoteData.mxCaption && !mrDoc.IsUndo() )
1028 if (mrDoc.IsClipboard())
1029 mrDoc.InitDrawLayer(); // ensure there is a drawing layer
1031 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
1032 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
1033 if( maNoteData.mxCaption )
1035 // Prevent triple change broadcasts of the same object.
1036 maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(true);
1037 ScCaptionInitData& rInitData = *maNoteData.mxInitData;
1039 // transfer ownership of outliner object to caption, or set simple text
1040 OSL_ENSURE( rInitData.mxOutlinerObj.get() || !rInitData.maSimpleText.isEmpty(),
1041 "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
1042 if (rInitData.mxOutlinerObj)
1043 maNoteData.mxCaption->SetOutlinerParaObject( std::move(rInitData.mxOutlinerObj) );
1044 else
1045 maNoteData.mxCaption->SetText( rInitData.maSimpleText );
1047 // copy all items or set default items; reset shadow items
1048 ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc );
1049 if (rInitData.mxItemSet)
1050 ScCaptionUtil::SetCaptionItems( *maNoteData.mxCaption, *rInitData.mxItemSet );
1052 // set position and size of the caption object
1053 if( rInitData.mbDefaultPosSize )
1055 // set other items and fit caption size to text
1056 maNoteData.mxCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
1057 maNoteData.mxCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
1058 maNoteData.mxCaption->AdjustTextFrameWidthAndHeight();
1059 aCreator.AutoPlaceCaption();
1061 else
1063 tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true );
1064 bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() );
1065 long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X());
1066 long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y();
1067 tools::Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize );
1068 maNoteData.mxCaption->SetLogicRect( aCaptRect );
1069 aCreator.FitCaptionToRect();
1072 // End prevent triple change broadcasts of the same object.
1073 maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(false);
1074 maNoteData.mxCaption->BroadcastObjectChange();
1077 // forget the initial caption data struct
1078 maNoteData.mxInitData.reset();
1082 void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
1084 OSL_ENSURE( !maNoteData.mxCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
1085 maNoteData.mxCaption.reset(nullptr);
1087 /* #i104915# Never try to create notes in Undo document, leads to
1088 crash due to missing document members (e.g. row height array). */
1089 OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" );
1090 if( mrDoc.IsUndo() )
1091 return;
1093 // drawing layer may be missing, if a note is copied into a clipboard document
1094 if( mrDoc.IsClipboard() )
1095 mrDoc.InitDrawLayer();
1097 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
1098 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
1099 if( maNoteData.mxCaption )
1101 // clone settings of passed caption
1102 if( pCaption )
1104 // copy edit text object (object must be inserted into page already)
1105 if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
1106 maNoteData.mxCaption->SetOutlinerParaObject( std::make_unique<OutlinerParaObject>( *pOPO ) );
1107 // copy formatting items (after text has been copied to apply font formatting)
1108 maNoteData.mxCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
1109 // move textbox position relative to new cell, copy textbox size
1110 tools::Rectangle aCaptRect = pCaption->GetLogicRect();
1111 Point aDist = maNoteData.mxCaption->GetTailPos() - pCaption->GetTailPos();
1112 aCaptRect.Move( aDist.X(), aDist.Y() );
1113 maNoteData.mxCaption->SetLogicRect( aCaptRect );
1114 aCreator.FitCaptionToRect();
1116 else
1118 // set default formatting and default position
1119 ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc );
1120 aCreator.AutoPlaceCaption();
1123 // create undo action
1124 if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
1125 if( pDrawLayer->IsRecording() )
1126 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoNewObj>( *maNoteData.mxCaption ) );
1130 void ScPostIt::RemoveCaption()
1132 if (!maNoteData.mxCaption)
1133 return;
1135 /* Remove caption object only, if this note is its owner (e.g. notes in
1136 undo documents refer to captions in original document, do not remove
1137 them from drawing layer here). */
1138 // TTTT maybe no longer needed - can that still happen?
1139 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
1140 if (pDrawLayer == &maNoteData.mxCaption->getSdrModelFromSdrObject())
1141 maNoteData.mxCaption.removeFromDrawPageAndFree();
1143 SAL_INFO("sc.core","ScPostIt::RemoveCaption - refs: " << maNoteData.mxCaption.getRefs() <<
1144 " IsUndo: " << mrDoc.IsUndo() << " IsClip: " << mrDoc.IsClipboard() <<
1145 " Dtor: " << mrDoc.IsInDtorClear());
1147 // Forget the caption object if removeFromDrawPageAndFree() did not free it.
1148 if (maNoteData.mxCaption)
1150 SAL_INFO("sc.core","ScPostIt::RemoveCaption - forgetting one ref");
1151 maNoteData.mxCaption.forget();
1155 ScCaptionPtr ScNoteUtil::CreateTempCaption(
1156 ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage,
1157 const OUString& rUserText, const tools::Rectangle& rVisRect, bool bTailFront )
1159 OUStringBuffer aBuffer( rUserText );
1160 // add plain text of invisible (!) cell note (no formatting etc.)
1161 SdrCaptionObj* pNoteCaption = nullptr;
1162 const ScPostIt* pNote = rDoc.GetNote( rPos );
1163 if( pNote && !pNote->IsCaptionShown() )
1165 if( !aBuffer.isEmpty() )
1166 aBuffer.append( "\n--------\n" ).append( pNote->GetText() );
1167 pNoteCaption = pNote->GetOrCreateCaption( rPos );
1170 // create a caption if any text exists
1171 if( !pNoteCaption && aBuffer.isEmpty() )
1172 return ScCaptionPtr();
1174 // prepare visible rectangle (add default distance to all borders)
1175 tools::Rectangle aVisRect(
1176 rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP,
1177 rVisRect.Top() + SC_NOTECAPTION_BORDERDIST_TEMP,
1178 rVisRect.Right() - SC_NOTECAPTION_BORDERDIST_TEMP,
1179 rVisRect.Bottom() - SC_NOTECAPTION_BORDERDIST_TEMP );
1181 // create the caption object
1182 ScCaptionCreator aCreator( rDoc, rPos, bTailFront );
1184 // insert caption into page (needed to set caption text)
1185 aCreator.GetCaption().insertToDrawPage( rDrawPage );
1187 SdrCaptionObj* pCaption = aCreator.GetCaption().get(); // just for ease of use
1189 // clone the edit text object, unless user text is present, then set this text
1190 if( pNoteCaption && rUserText.isEmpty() )
1192 if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
1193 pCaption->SetOutlinerParaObject( std::make_unique<OutlinerParaObject>( *pOPO ) );
1194 // set formatting (must be done after setting text) and resize the box to fit the text
1195 pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() );
1196 tools::Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() );
1197 pCaption->SetLogicRect( aCaptRect );
1199 else
1201 // if pNoteCaption is null, then aBuffer contains some text
1202 pCaption->SetText( aBuffer.makeStringAndClear() );
1203 ScCaptionUtil::SetDefaultItems( *pCaption, rDoc );
1204 // adjust caption size to text size
1205 long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
1206 pCaption->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
1207 pCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
1208 pCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( nMaxWidth ) );
1209 pCaption->SetMergedItem( makeSdrTextAutoGrowHeightItem( true ) );
1210 pCaption->AdjustTextFrameWidthAndHeight();
1213 // move caption into visible area
1214 aCreator.AutoPlaceCaption( &aVisRect );
1216 // XXX Note it is already inserted to the draw page.
1217 return aCreator.GetCaption();
1220 ScPostIt* ScNoteUtil::CreateNoteFromCaption(
1221 ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj* pCaption )
1223 ScNoteData aNoteData( true/*bShown*/ );
1224 aNoteData.mxCaption.reset( pCaption );
1225 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
1226 pNote->AutoStamp();
1228 rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
1230 // ScNoteCaptionCreator c'tor updates the caption object to be part of a note
1231 ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.mxCaption, true/*bShown*/ );
1233 return pNote;
1236 ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
1237 ScDocument& rDoc, const ScAddress& rPos, std::unique_ptr<SfxItemSet> pItemSet,
1238 OutlinerParaObject* pOutlinerObj, const tools::Rectangle& rCaptionRect,
1239 bool bShown )
1241 OSL_ENSURE( pItemSet && pOutlinerObj, "ScNoteUtil::CreateNoteFromObjectData - item set and outliner object expected" );
1242 ScNoteData aNoteData( bShown );
1243 aNoteData.mxInitData.reset( new ScCaptionInitData );
1244 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
1245 rInitData.mxItemSet = std::move(pItemSet);
1246 rInitData.mxOutlinerObj.reset( pOutlinerObj );
1248 // convert absolute caption position to relative position
1249 rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty();
1250 if( !rInitData.mbDefaultPosSize )
1252 tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, rPos, true );
1253 bool bNegPage = rDoc.IsNegativePage( rPos.Tab() );
1254 rInitData.maCaptionOffset.setX( bNegPage ? (aCellRect.Left() - rCaptionRect.Right()) : (rCaptionRect.Left() - aCellRect.Right()) );
1255 rInitData.maCaptionOffset.setY( rCaptionRect.Top() - aCellRect.Top() );
1256 rInitData.maCaptionSize = rCaptionRect.GetSize();
1259 /* Create the note and insert it into the document. If the note is
1260 visible, the caption object will be created automatically. */
1261 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, /*bAlwaysCreateCaption*/false, 0/*nPostItId*/ );
1262 pNote->AutoStamp();
1264 rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
1266 return pNote;
1269 ScPostIt* ScNoteUtil::CreateNoteFromString(
1270 ScDocument& rDoc, const ScAddress& rPos, const OUString& rNoteText,
1271 bool bShown, bool bAlwaysCreateCaption, sal_uInt32 nPostItId )
1273 ScPostIt* pNote = nullptr;
1274 if( !rNoteText.isEmpty() )
1276 ScNoteData aNoteData( bShown );
1277 aNoteData.mxInitData.reset( new ScCaptionInitData );
1278 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
1279 rInitData.maSimpleText = rNoteText;
1280 rInitData.mbDefaultPosSize = true;
1282 /* Create the note and insert it into the document. If the note is
1283 visible, the caption object will be created automatically. */
1284 pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption, nPostItId );
1285 pNote->AutoStamp();
1286 //insert takes ownership
1287 rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
1289 return pNote;
1292 namespace sc {
1294 NoteEntry::NoteEntry( const ScAddress& rPos, const ScPostIt* pNote ) :
1295 maPos(rPos), mpNote(pNote) {}
1299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */