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 <memory>
21 #include <postit.hxx>
22
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
25 #include <unotools/useroptions.hxx>
26 #include <unotools/datetime.hxx>
27 #include <svx/svdocapt.hxx>
28 #include <svx/svdpage.hxx>
29 #include <editeng/outlobj.hxx>
30 #include <editeng/editobj.hxx>
31 #include <osl/diagnose.h>
32 #include <comphelper/lok.hxx>
33
34 #include <svx/sdsxyitm.hxx>
35 #include <svx/sdtagitm.hxx>
36 #include <svx/sdtmfitm.hxx>
37 #include <tools/gen.hxx>
38
39 #include <document.hxx>
40 #include <stlpool.hxx>
41 #include <stylehelper.hxx>
42 #include <drwlayer.hxx>
43 #include <userdat.hxx>
44 #include <editutil.hxx>
45 #include <globstr.hrc>
46 #include <scresid.hxx>
47 #include <utility>
48 #include <strings.hrc>
49 #include <officecfg/Office/Calc.hxx>
50
51 #include <com/sun/star/text/XText.hpp>
52 #include <com/sun/star/text/XTextAppend.hpp>
53 #include <com/sun/star/awt/FontWeight.hpp>
54 #include <comphelper/propertyvalue.hxx>
55
56 using namespace com::sun::star;
57
58 namespace {
59
60 const tools::Long SC_NOTECAPTION_WIDTH = 2900; /// Default width of note caption textbox.
61 const tools::Long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; /// Maximum width of temporary note caption textbox.
62 const tools::Long SC_NOTECAPTION_HEIGHT = 1800; /// Default height of note caption textbox.
63 const tools::Long SC_NOTECAPTION_CELLDIST = 600; /// Default distance of note captions to border of anchor cell.
64 const tools::Long SC_NOTECAPTION_OFFSET_Y = -1500; /// Default Y offset of note captions to top border of anchor cell.
65 const tools::Long SC_NOTECAPTION_OFFSET_X = 1500; /// Default X offset of note captions to left border of anchor cell.
66 const tools::Long SC_NOTECAPTION_BORDERDIST_TEMP = 100; /// Distance of temporary note captions to visible sheet area.
67
68 /** Static helper functions for caption objects. */
69 class ScCaptionUtil
70 {
71 public:
72 /** Moves the caption object to the correct layer according to passed visibility. */
73 static void SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown );
74 /** Sets basic caption settings required for note caption objects. */
75 static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown );
76 /** Stores the cell position of the note in the user data area of the caption. */
77 static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos );
78 /** Sets all hard formatting attributes to the caption object. */
79 static void SetExtraItems( SdrCaptionObj& rCaption, const SfxItemSet& rExtraItemSet );
80 };
81
SetCaptionLayer(SdrCaptionObj & rCaption,bool bShown)82 void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
83 {
84 SdrLayerID nLayer = bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN;
85 if( nLayer != rCaption.GetLayer() )
86 rCaption.SetLayer( nLayer );
87 }
88
SetBasicCaptionSettings(SdrCaptionObj & rCaption,bool bShown)89 void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown )
90 {
91 rCaption.SetFixedTail();
92 rCaption.SetSpecialTextBoxShadow();
93 SetCaptionLayer( rCaption, bShown );
94 }
95
SetCaptionUserData(SdrCaptionObj & rCaption,const ScAddress & rPos)96 void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos )
97 {
98 // pass true to ScDrawLayer::GetObjData() to create the object data entry
99 ScDrawObjData* pObjData = ScDrawLayer::GetObjData( &rCaption, true );
100 assert(pObjData && "ScCaptionUtil::SetCaptionUserData - missing drawing object user data");
101 pObjData->maStart = rPos;
102 pObjData->meType = ScDrawObjData::CellNote;
103 }
104
SetExtraItems(SdrCaptionObj & rCaption,const SfxItemSet & rExtraItemSet)105 void ScCaptionUtil::SetExtraItems( SdrCaptionObj& rCaption, const SfxItemSet& rExtraItemSet )
106 {
107 SfxItemSet aItemSet = rCaption.GetMergedItemSet();
108
109 aItemSet.Put(rExtraItemSet);
110 // reset shadow visibility (see also ScNoteUtil::CreateNoteFromCaption)
111 aItemSet.ClearItem(SDRATTR_SHADOW);
112 // ... but not distance, as that will fallback to wrong values
113 // if the comment is shown and then opened in older versions:
114 aItemSet.Put( makeSdrShadowXDistItem( 100 ) );
115 aItemSet.Put( makeSdrShadowYDistItem( 100 ) );
116
117 rCaption.SetMergedItemSet( aItemSet, /*bClearAllItems*/false, /*bAdjustTextFrameWidthAndHeight*/false );
118 }
119
120 /** Helper for creation and manipulation of caption drawing objects independent
121 from cell annotations. */
122 class ScCaptionCreator
123 {
124 public:
125 /** Create a new caption. The caption will not be inserted into the document. */
126 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront );
127 /** Manipulate an existing caption. */
128 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption );
129
130 /** Returns the drawing layer page of the sheet contained in maPos. */
131 SdrPage* GetDrawPage();
132 /** Returns the caption drawing object. */
GetCaption()133 rtl::Reference<SdrCaptionObj> & GetCaption() { return mxCaption; }
134
135 /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
136 void FitCaptionToRect( const tools::Rectangle* pVisRect = nullptr );
137 /** Places the caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */
138 void AutoPlaceCaption( const tools::Rectangle* pVisRect = nullptr );
139 /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */
140 void UpdateCaptionPos();
141
142 protected:
143 /** Helper constructor for derived classes. */
144 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos );
145
146 /** Calculates the caption tail position according to current cell position. */
147 Point CalcTailPos( bool bTailFront );
148 /** Implements creation of the caption object. The caption will not be inserted into the document. */
149 void CreateCaption( bool bShown, bool bTailFront );
150
151 private:
152 /** Initializes all members. */
153 void Initialize();
154 /** Returns the passed rectangle if existing, page rectangle otherwise. */
GetVisRect(const tools::Rectangle * pVisRect) const155 const tools::Rectangle& GetVisRect( const tools::Rectangle* pVisRect ) const { return pVisRect ? *pVisRect : maPageRect; }
156
157 private:
158 ScDocument& mrDoc;
159 ScAddress maPos;
160 rtl::Reference<SdrCaptionObj> mxCaption;
161 tools::Rectangle maPageRect;
162 tools::Rectangle maCellRect;
163 bool mbNegPage;
164 };
165
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,bool bTailFront)166 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront ) :
167 mrDoc( rDoc ),
168 maPos( rPos )
169 {
170 Initialize();
171 CreateCaption( true/*bShown*/, bTailFront );
172 }
173
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,const rtl::Reference<SdrCaptionObj> & xCaption)174 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption ) :
175 mrDoc( rDoc ),
176 maPos( rPos ),
177 mxCaption( xCaption )
178 {
179 Initialize();
180 }
181
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos)182 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) :
183 mrDoc( rDoc ),
184 maPos( rPos )
185 {
186 Initialize();
187 }
188
GetDrawPage()189 SdrPage* ScCaptionCreator::GetDrawPage()
190 {
191 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
192 return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : nullptr;
193 }
194
FitCaptionToRect(const tools::Rectangle * pVisRect)195 void ScCaptionCreator::FitCaptionToRect( const tools::Rectangle* pVisRect )
196 {
197 const tools::Rectangle& rVisRect = GetVisRect( pVisRect );
198
199 // tail position
200 Point aTailPos = mxCaption->GetTailPos();
201 aTailPos.setX( ::std::clamp( aTailPos.X(), rVisRect.Left(), rVisRect.Right() ) );
202 aTailPos.setY( ::std::clamp( aTailPos.Y(), rVisRect.Top(), rVisRect.Bottom() ) );
203 mxCaption->SetTailPos( aTailPos );
204
205 // caption rectangle
206 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
207 Point aCaptPos = aCaptRect.TopLeft();
208 // move textbox inside right border of visible area
209 aCaptPos.setX( ::std::min< tools::Long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() ) );
210 // move textbox inside left border of visible area (this may move it outside on right side again)
211 aCaptPos.setX( ::std::max< tools::Long >( aCaptPos.X(), rVisRect.Left() ) );
212 // move textbox inside bottom border of visible area
213 aCaptPos.setY( ::std::min< tools::Long >( aCaptPos.Y(), rVisRect.Bottom() - aCaptRect.GetHeight() ) );
214 // move textbox inside top border of visible area (this may move it outside on bottom side again)
215 aCaptPos.setY( ::std::max< tools::Long >( aCaptPos.Y(), rVisRect.Top() ) );
216 // update caption
217 aCaptRect.SetPos( aCaptPos );
218 mxCaption->NbcSetLogicRect( aCaptRect, /*bAdaptTextMinSize*/false );
219 }
220
AutoPlaceCaption(const tools::Rectangle * pVisRect)221 void ScCaptionCreator::AutoPlaceCaption( const tools::Rectangle* pVisRect )
222 {
223 const tools::Rectangle& rVisRect = GetVisRect( pVisRect );
224
225 // caption rectangle
226 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
227 tools::Long nWidth = aCaptRect.GetWidth();
228 tools::Long nHeight = aCaptRect.GetHeight();
229
230 // n***Space contains available space between border of visible area and cell
231 tools::Long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1;
232 tools::Long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1;
233 tools::Long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1;
234 tools::Long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1;
235
236 // nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area
237 tools::Long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST;
238 tools::Long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST;
239
240 // bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area
241 bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell
242 bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell
243 bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area
244
245 // bFitsHeight*** == true means height of textbox fits into vertical free space of visible area
246 bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell
247 bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell
248 bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area
249
250 // bFits*** == true means the textbox fits completely into free space of visible area
251 bool bFitsLeft = bFitsWidthLeft && bFitsHeight;
252 bool bFitsRight = bFitsWidthRight && bFitsHeight;
253 bool bFitsTop = bFitsWidth && bFitsHeightTop;
254 bool bFitsBottom = bFitsWidth && bFitsHeightBottom;
255
256 Point aCaptPos;
257 // use left/right placement if possible, or if top/bottom placement not possible
258 if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) )
259 {
260 // prefer left in RTL sheet and right in LTR sheets
261 bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight);
262 bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft);
263 // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left
264 if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) )
265 aCaptPos.setX( maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth );
266 else // to right
267 aCaptPos.setX( maCellRect.Right() + SC_NOTECAPTION_CELLDIST );
268 // Y position according to top cell border
269 aCaptPos.setY( maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y );
270 }
271 else // top or bottom placement
272 {
273 // X position
274 aCaptPos.setX( maCellRect.Left() + SC_NOTECAPTION_OFFSET_X );
275 // top placement, if possible
276 if( bFitsTop )
277 aCaptPos.setY( maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight );
278 else // bottom placement
279 aCaptPos.setY( maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST );
280 }
281
282 // update textbox position in note caption object
283 aCaptRect.SetPos( aCaptPos );
284 mxCaption->SetLogicRect( aCaptRect );
285 FitCaptionToRect( pVisRect );
286 }
287
UpdateCaptionPos()288 void ScCaptionCreator::UpdateCaptionPos()
289 {
290 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
291
292 // update caption position
293 const Point& rOldTailPos = mxCaption->GetTailPos();
294 Point aTailPos = CalcTailPos( false );
295 if( rOldTailPos != aTailPos )
296 {
297 // create drawing undo action
298 if( pDrawLayer && pDrawLayer->IsRecording() )
299 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *mxCaption ) );
300 // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly)
301 tools::Rectangle aCaptRect = mxCaption->GetLogicRect();
302 tools::Long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right());
303 if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth();
304 tools::Long nDiffY = aCaptRect.Top() - rOldTailPos.Y();
305 aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) );
306 // set new tail position and caption rectangle
307 mxCaption->SetTailPos( aTailPos );
308 mxCaption->SetLogicRect( aCaptRect );
309 // fit caption into draw page
310 FitCaptionToRect();
311 }
312
313 // update cell position in caption user data
314 ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mxCaption.get(), maPos.Tab() );
315 if( pCaptData && (maPos != pCaptData->maStart) )
316 {
317 // create drawing undo action
318 if( pDrawLayer && pDrawLayer->IsRecording() )
319 pDrawLayer->AddCalcUndo( std::make_unique<ScUndoObjData>( mxCaption.get(), pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) );
320 // set new position
321 pCaptData->maStart = maPos;
322 }
323 }
324
CalcTailPos(bool bTailFront)325 Point ScCaptionCreator::CalcTailPos( bool bTailFront )
326 {
327 // tail position
328 bool bTailLeft = bTailFront != mbNegPage;
329 Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight();
330 // move caption point 1/10 mm inside cell
331 if( bTailLeft ) aTailPos.AdjustX(10 ); else aTailPos.AdjustX( -10 );
332 aTailPos.AdjustY(10);
333 return aTailPos;
334 }
335
CreateCaption(bool bShown,bool bTailFront)336 void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
337 {
338 // create the caption drawing object
339 tools::Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
340 Point aTailPos = CalcTailPos( bTailFront );
341 mxCaption =
342 new SdrCaptionObj(
343 *mrDoc.GetDrawLayer(), // TTTT should ret a ref?
344 aTextRect,
345 aTailPos);
346 // basic caption settings
347 ScCaptionUtil::SetBasicCaptionSettings( *mxCaption, bShown );
348 }
349
Initialize()350 void ScCaptionCreator::Initialize()
351 {
352 maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true );
353 mbNegPage = mrDoc.IsNegativePage( maPos.Tab() );
354 if( SdrPage* pDrawPage = GetDrawPage() )
355 {
356 maPageRect = tools::Rectangle( Point( 0, 0 ), pDrawPage->GetSize() );
357 /* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
358 The call to Rectangle::Adjust() orders left/right coordinate
359 accordingly. */
360 maPageRect.Normalize();
361 }
362 }
363
364 /** Helper for creation of permanent caption drawing objects for cell notes. */
365 class ScNoteCaptionCreator : public ScCaptionCreator
366 {
367 public:
368 /** Create a new caption object and inserts it into the document. */
369 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
370 /** Manipulate an existing caption. */
371 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption, bool bShown );
372 };
373
ScNoteCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,ScNoteData & rNoteData)374 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
375 ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet
376 {
377 SdrPage* pDrawPage = GetDrawPage();
378 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
379 if( !pDrawPage )
380 return;
381
382 // create the caption drawing object
383 CreateCaption( rNoteData.mbShown, false );
384 rNoteData.mxCaption = GetCaption();
385 OSL_ENSURE( rNoteData.mxCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
386 if( rNoteData.mxCaption )
387 {
388 // store note position in user data of caption object
389 ScCaptionUtil::SetCaptionUserData( *rNoteData.mxCaption, rPos );
390 // insert object into draw page
391 pDrawPage->InsertObject( rNoteData.mxCaption.get() );
392 }
393 }
394
ScNoteCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,const rtl::Reference<SdrCaptionObj> & xCaption,bool bShown)395 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption, bool bShown ) :
396 ScCaptionCreator( rDoc, rPos, xCaption )
397 {
398 SdrPage* pDrawPage = GetDrawPage();
399 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
400 OSL_ENSURE( xCaption->getSdrPageFromSdrObject() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
401 if( pDrawPage && (xCaption->getSdrPageFromSdrObject() == pDrawPage) )
402 {
403 // store note position in user data of caption object
404 ScCaptionUtil::SetCaptionUserData( *xCaption, rPos );
405 // basic caption settings
406 ScCaptionUtil::SetBasicCaptionSettings( *xCaption, bShown );
407 // set correct tail position
408 xCaption->SetTailPos( CalcTailPos( false ) );
409 }
410 }
411
412 } // namespace
413
414 struct ScCaptionInitData
415 {
416 std::optional< SfxItemSet > moItemSet; /// Caption object formatting.
417 std::optional< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting.
418 std::unique_ptr< GenerateNoteCaption > mxGenerator; /// Operator to generate Caption Object from import data
419 OUString maStyleName; /// Drawing style associated with the caption object.
420 OUString maSimpleText; /// Simple text without formatting.
421 Point maCaptionOffset; /// Caption position relative to cell corner.
422 Size maCaptionSize; /// Size of the caption object.
423 bool mbDefaultPosSize; /// True = use default position and size for caption.
424
425 explicit ScCaptionInitData();
426 };
427
ScCaptionInitData()428 ScCaptionInitData::ScCaptionInitData() :
429 mbDefaultPosSize( true )
430 {
431 }
432
ScNoteData(bool bShown)433 ScNoteData::ScNoteData( bool bShown ) :
434 mbShown( bShown )
435 {
436 }
437
438 sal_uInt32 ScPostIt::mnLastPostItId = 1;
439
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,sal_uInt32 nPostItId)440 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, sal_uInt32 nPostItId ) :
441 mrDoc( rDoc ),
442 maNoteData( false )
443 {
444 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
445 AutoStamp();
446 CreateCaption( rPos );
447 }
448
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,const ScPostIt & rNote,sal_uInt32 nPostItId)449 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote, sal_uInt32 nPostItId ) :
450 mrDoc( rDoc ),
451 maNoteData( rNote.maNoteData )
452 {
453 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
454 maNoteData.mxCaption.clear();
455 CreateCaption( rPos, rNote.maNoteData.mxCaption.get() );
456 }
457
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,ScNoteData aNoteData,bool bAlwaysCreateCaption,sal_uInt32 nPostItId)458 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, ScNoteData aNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId ) :
459 mrDoc( rDoc ),
460 maNoteData(std::move( aNoteData ))
461 {
462 mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
463 if( bAlwaysCreateCaption || maNoteData.mbShown )
464 CreateCaptionFromInitData( rPos );
465 }
466
~ScPostIt()467 ScPostIt::~ScPostIt()
468 {
469 RemoveCaption();
470 }
471
Clone(const ScAddress & rOwnPos,ScDocument & rDestDoc,const ScAddress & rDestPos,bool bCloneCaption) const472 std::unique_ptr<ScPostIt> ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const
473 {
474 // tdf#117307: Don't clone comment, if it is in the same position in the same document
475 const bool bIsSameDoc = mrDoc.GetPool() == rDestDoc.GetPool();
476 if (bIsSameDoc && !mrDoc.IsClipboard() && rOwnPos == rDestPos)
477 bCloneCaption = false;
478 CreateCaptionFromInitData( rOwnPos );
479 sal_uInt32 nPostItId = comphelper::LibreOfficeKit::isActive() ? 0 : mnPostItId;
480 return bCloneCaption ? std::make_unique<ScPostIt>( rDestDoc, rDestPos, *this, nPostItId ) : std::make_unique<ScPostIt>( rDestDoc, rDestPos, maNoteData, false, mnPostItId );
481 }
482
SetDate(const OUString & rDate)483 void ScPostIt::SetDate( const OUString& rDate )
484 {
485 maNoteData.maDate = rDate;
486 }
487
SetAuthor(const OUString & rAuthor)488 void ScPostIt::SetAuthor( const OUString& rAuthor )
489 {
490 maNoteData.maAuthor = rAuthor;
491 }
492
AutoStamp(bool bCreate)493 void ScPostIt::AutoStamp(bool bCreate)
494 {
495 if (bCreate)
496 {
497 DateTime aNow(DateTime::SYSTEM);
498 maNoteData.maDate = utl::toISO8601(aNow.GetUNODateTime());
499 }
500 if (!maNoteData.maAuthor.isEmpty())
501 return;
502 const OUString aAuthor = SvtUserOptions().GetFullName();
503 maNoteData.maAuthor = !aAuthor.isEmpty() ? aAuthor : ScResId(STR_CHG_UNKNOWN_AUTHOR);
504 }
505
GetOutlinerObject() const506 const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
507 {
508 if( maNoteData.mxCaption )
509 return maNoteData.mxCaption->GetOutlinerParaObject();
510 if( maNoteData.mxInitData && maNoteData.mxInitData->mxOutlinerObj )
511 return &*maNoteData.mxInitData->mxOutlinerObj;
512 return nullptr;
513 }
514
GetEditTextObject() const515 const EditTextObject* ScPostIt::GetEditTextObject() const
516 {
517 const OutlinerParaObject* pOPO = GetOutlinerObject();
518 return pOPO ? &pOPO->GetTextObject() : nullptr;
519 }
520
GetText() const521 OUString ScPostIt::GetText() const
522 {
523 if( const EditTextObject* pEditObj = GetEditTextObject() )
524 {
525 OUStringBuffer aBuffer;
526 ScNoteEditEngine& rEngine = mrDoc.GetNoteEngine();
527 rEngine.SetTextCurrentDefaults(*pEditObj);
528 sal_Int32 nParaCount = rEngine.GetParagraphCount();
529 for( sal_Int32 nPara = 0; nPara < nParaCount; ++nPara )
530 {
531 if( nPara > 0 )
532 aBuffer.append( '\n' );
533 aBuffer.append(rEngine.GetText(nPara));
534 }
535 return aBuffer.makeStringAndClear();
536 }
537 if( maNoteData.mxInitData )
538 return maNoteData.mxInitData->maSimpleText;
539 return OUString();
540 }
541
SetText(const ScAddress & rPos,const OUString & rText)542 void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
543 {
544 CreateCaptionFromInitData( rPos );
545 if( maNoteData.mxCaption )
546 maNoteData.mxCaption->SetText( rText );
547 }
548
GetOrCreateCaption(const ScAddress & rPos) const549 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
550 {
551 CreateCaptionFromInitData( rPos );
552 return maNoteData.mxCaption.get();
553 }
554
ForgetCaption(bool bPreserveData)555 void ScPostIt::ForgetCaption( bool bPreserveData )
556 {
557 if (bPreserveData)
558 {
559 // Used in clipboard when the originating document is destructed to be
560 // able to paste into another document. Caption size and relative
561 // position are not preserved but default created when pasted. Also the
562 // MergedItemSet can not be carried over or it had to be adapted to
563 // defaults and pool. At least preserve the text and outline object if
564 // possible.
565 ScCaptionInitData* pInitData = new ScCaptionInitData;
566 const OutlinerParaObject* pOPO = GetOutlinerObject();
567 if (pOPO)
568 pInitData->mxOutlinerObj = *pOPO;
569 pInitData->maSimpleText = GetText();
570
571 maNoteData.mxInitData.reset(pInitData);
572 maNoteData.mxCaption.clear();
573 }
574 else
575 {
576 /* This function is used in undo actions to give up the responsibility for
577 the caption object which is handled by separate drawing undo actions. */
578 maNoteData.mxCaption.clear();
579 maNoteData.mxInitData.reset();
580 }
581 }
582
ShowCaption(const ScAddress & rPos,bool bShow)583 void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow )
584 {
585 CreateCaptionFromInitData( rPos );
586 // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
587 maNoteData.mbShown = bShow;
588 if( maNoteData.mxCaption )
589 ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, bShow );
590 }
591
ShowCaptionTemp(const ScAddress & rPos,bool bShow)592 void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow )
593 {
594 CreateCaptionFromInitData( rPos );
595 if( maNoteData.mxCaption )
596 ScCaptionUtil::SetCaptionLayer( *maNoteData.mxCaption, maNoteData.mbShown || bShow );
597 }
598
UpdateCaptionPos(const ScAddress & rPos)599 void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
600 {
601 CreateCaptionFromInitData( rPos );
602 if( maNoteData.mxCaption )
603 {
604 ScCaptionCreator aCreator( mrDoc, rPos, maNoteData.mxCaption );
605 aCreator.UpdateCaptionPos();
606 }
607 }
608
609 // private --------------------------------------------------------------------
610
CreateCaptionFromInitData(const ScAddress & rPos) const611 void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
612 {
613 // Captions are not created in Undo documents and only rarely in Clipboard,
614 // but otherwise we need caption or initial data.
615 assert((maNoteData.mxCaption || maNoteData.mxInitData) || mrDoc.IsUndo() || mrDoc.IsClipboard());
616 if( !maNoteData.mxInitData )
617 return;
618
619
620 /* This function is called from ScPostIt::Clone() when copying cells
621 to the clipboard/undo document, and when copying cells from the
622 clipboard/undo document. The former should always be called first,
623 so if called in a clipboard/undo document, the caption should have
624 been created already. However, for clipboard in case the
625 originating document was destructed a new caption has to be
626 created. */
627 OSL_ENSURE( !mrDoc.IsUndo() && (!mrDoc.IsClipboard() || !maNoteData.mxCaption),
628 "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );
629
630 // going to forget the initial caption data struct when this method returns
631 auto xInitData = std::move(maNoteData.mxInitData);
632
633 /* #i104915# Never try to create notes in Undo document, leads to
634 crash due to missing document members (e.g. row height array). */
635 if( maNoteData.mxCaption || mrDoc.IsUndo() )
636 return;
637
638 if (mrDoc.IsClipboard())
639 mrDoc.InitDrawLayer(); // ensure there is a drawing layer
640
641 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
642 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
643 if( !maNoteData.mxCaption )
644 return;
645
646 // Prevent triple change broadcasts of the same object.
647 bool bWasLocked = maNoteData.mxCaption->getSdrModelFromSdrObject().isLocked();
648 maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(true);
649
650 if (xInitData->mxGenerator)
651 xInitData->mxGenerator->Generate(*maNoteData.mxCaption);
652 else
653 {
654 // transfer ownership of outliner object to caption, or set simple text
655 OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(),
656 "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
657 if (xInitData->mxOutlinerObj)
658 maNoteData.mxCaption->NbcSetOutlinerParaObjectForText(
659 std::move(xInitData->mxOutlinerObj),
660 maNoteData.mxCaption->getActiveText(),
661 /*bAdjustTextFrameWidthAndHeight*/false );
662 else
663 maNoteData.mxCaption->SetText( xInitData->maSimpleText );
664 }
665
666 if (!xInitData->maStyleName.isEmpty())
667 {
668 if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(xInitData->maStyleName, SfxStyleFamily::Frame))
669 maNoteData.mxCaption->NbcSetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true, /*bAdjustTextFrameWidthAndHeight*/false);
670
671 if (xInitData->moItemSet)
672 maNoteData.mxCaption->SetMergedItemSet(*xInitData->moItemSet,
673 /*bClearAllItems*/false, /*bAdjustTextFrameWidthAndHeight*/false);
674 }
675 else
676 {
677 if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
678 maNoteData.mxCaption->NbcSetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true, /*bAdjustTextFrameWidthAndHeight*/false);
679
680 // copy all items and reset shadow items
681 if (xInitData->moItemSet)
682 ScCaptionUtil::SetExtraItems(*maNoteData.mxCaption, *xInitData->moItemSet);
683 }
684
685 // set position and size of the caption object
686 if( xInitData->mbDefaultPosSize )
687 {
688 // set other items and fit caption size to text
689 maNoteData.mxCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
690 maNoteData.mxCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
691 maNoteData.mxCaption->AdjustTextFrameWidthAndHeight();
692 aCreator.AutoPlaceCaption();
693 }
694 else
695 {
696 tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true );
697 bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() );
698 tools::Long nPosX = bNegPage ? (aCellRect.Left() - xInitData->maCaptionOffset.X()) : (aCellRect.Right() + xInitData->maCaptionOffset.X());
699 tools::Long nPosY = aCellRect.Top() + xInitData->maCaptionOffset.Y();
700 tools::Rectangle aCaptRect( Point( nPosX, nPosY ), xInitData->maCaptionSize );
701 maNoteData.mxCaption->NbcSetLogicRect( aCaptRect, /*bAdaptTextMinSize*/false );
702 aCreator.FitCaptionToRect();
703 }
704
705 // End prevent triple change broadcasts of the same object.
706 maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(bWasLocked);
707 maNoteData.mxCaption->BroadcastObjectChange();
708 }
709
CreateCaption(const ScAddress & rPos,const SdrCaptionObj * pCaption)710 void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
711 {
712 OSL_ENSURE( !maNoteData.mxCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
713 maNoteData.mxCaption.clear();
714
715 /* #i104915# Never try to create notes in Undo document, leads to
716 crash due to missing document members (e.g. row height array). */
717 OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" );
718 if( mrDoc.IsUndo() )
719 return;
720
721 // drawing layer may be missing, if a note is copied into a clipboard document
722 if( mrDoc.IsClipboard() )
723 mrDoc.InitDrawLayer();
724
725 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
726 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
727 if( !maNoteData.mxCaption )
728 return;
729
730 // clone settings of passed caption
731 if( pCaption )
732 {
733 // copy edit text object (object must be inserted into page already)
734 if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
735 maNoteData.mxCaption->SetOutlinerParaObject( *pOPO );
736 // copy formatting items (after text has been copied to apply font formatting)
737 if (auto pStyleSheet = pCaption->GetStyleSheet())
738 {
739 auto pPool = mrDoc.GetStyleSheetPool();
740 pPool->CopyStyleFrom(pStyleSheet->GetPool(), pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);
741
742 if (auto pDestStyleSheet = pPool->Find(pStyleSheet->GetName(), pStyleSheet->GetFamily()))
743 maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pDestStyleSheet), true);
744 }
745 maNoteData.mxCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
746 // move textbox position relative to new cell, copy textbox size
747 tools::Rectangle aCaptRect = pCaption->GetLogicRect();
748 Point aDist = maNoteData.mxCaption->GetTailPos() - pCaption->GetTailPos();
749 aCaptRect.Move( aDist.X(), aDist.Y() );
750 maNoteData.mxCaption->SetLogicRect( aCaptRect );
751 aCreator.FitCaptionToRect();
752 }
753 else
754 {
755 if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
756 maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
757 // set default size, undoing sdr::TextProperties::SetStyleSheet's
758 // adjustment that use a wrong min height.
759 tools::Rectangle aCaptRect = maNoteData.mxCaption->GetLogicRect();
760 aCaptRect.SetSize({ SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT });
761 maNoteData.mxCaption->SetLogicRect(aCaptRect);
762 // set default position
763 aCreator.AutoPlaceCaption();
764 }
765
766 // create undo action
767 if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
768 if( pDrawLayer->IsRecording() )
769 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoNewObj>( *maNoteData.mxCaption ) );
770 }
771
RemoveCaption()772 void ScPostIt::RemoveCaption()
773 {
774 if (!maNoteData.mxCaption)
775 return;
776
777 /* Remove caption object only, if this note is its owner (e.g. notes in
778 undo documents refer to captions in original document, do not remove
779 them from drawing layer here). */
780 // TTTT maybe no longer needed - can that still happen?
781 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
782 if (pDrawLayer == &maNoteData.mxCaption->getSdrModelFromSdrObject())
783 {
784 SdrPage* pDrawPage(maNoteData.mxCaption->getSdrPageFromSdrObject());
785 SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page");
786 if (pDrawPage)
787 {
788 pDrawPage->RecalcObjOrdNums();
789 // create drawing undo action (before removing the object to have valid draw page in undo action)
790 if (pDrawLayer->IsRecording())
791 pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoDelObj>( *maNoteData.mxCaption ));
792 // remove the object from the drawing page
793 rtl::Reference<SdrObject> pRemovedObj = pDrawPage->RemoveObject( maNoteData.mxCaption->GetOrdNum() );
794 assert(pRemovedObj.get() == maNoteData.mxCaption.get()); (void)pRemovedObj;
795 }
796 }
797
798 SAL_INFO("sc.core","ScPostIt::RemoveCaption -"
799 " IsUndo: " << mrDoc.IsUndo() << " IsClip: " << mrDoc.IsClipboard() <<
800 " Dtor: " << mrDoc.IsInDtorClear());
801
802 // Forget the caption object if removeFromDrawPageAndFree() did not free it.
803 if (maNoteData.mxCaption)
804 {
805 SAL_INFO("sc.core","ScPostIt::RemoveCaption - forgetting one ref");
806 maNoteData.mxCaption.clear();
807 }
808 }
809
lcl_FormatAndInsertAuthorAndDatepara(SdrCaptionObj * pCaption,OUStringBuffer & aUserData,bool bUserWithTrackText)810 static void lcl_FormatAndInsertAuthorAndDatepara(SdrCaptionObj* pCaption, OUStringBuffer& aUserData, bool bUserWithTrackText)
811 {
812 uno::Reference<drawing::XShape> xShape = pCaption->getUnoShape();
813 uno::Reference<text::XText> xText(xShape, uno::UNO_QUERY);
814 uno::Reference<text::XTextAppend> xBodyTextAppend(xText, uno::UNO_QUERY);
815
816 if (xBodyTextAppend.is())
817 {
818 uno::Sequence< beans::PropertyValue > aArgs;
819 if (bUserWithTrackText)
820 {
821 xBodyTextAppend->insertTextPortion(aUserData.makeStringAndClear(), aArgs, xText->getStart());
822 }
823 else
824 {
825 xBodyTextAppend->insertTextPortion(u"\n--------\n"_ustr, aArgs, xText->getStart());
826 aArgs = {
827 comphelper::makePropertyValue(u"CharWeight"_ustr, uno::Any(awt::FontWeight::BOLD)),
828 };
829 xBodyTextAppend->insertTextPortion(aUserData.makeStringAndClear(), aArgs, xText->getStart());
830 }
831 }
832 }
833
CreateTempCaption(ScDocument & rDoc,const ScAddress & rPos,SdrPage & rDrawPage,std::u16string_view rUserText,const tools::Rectangle & rVisRect,bool bTailFront)834 rtl::Reference<SdrCaptionObj> ScNoteUtil::CreateTempCaption(
835 ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage,
836 std::u16string_view rUserText, const tools::Rectangle& rVisRect, bool bTailFront )
837 {
838 bool bUserWithTrackText = false;
839 OUStringBuffer aBuffer( rUserText );
840 // add plain text of invisible (!) cell note (no formatting etc.)
841 SdrCaptionObj* pNoteCaption = nullptr;
842 const ScPostIt* pNote = rDoc.GetNote( rPos );
843 if( pNote && !pNote->IsCaptionShown() )
844 {
845 if (!aBuffer.isEmpty())
846 {
847 bUserWithTrackText = true;
848 aBuffer.append("\n--------\n");
849 }
850 else
851 {
852 aBuffer.append(pNote->GetAuthor()
853 + (!pNote->GetDate().isEmpty() ? ", " + pNote->GetDate() : OUString()));
854 }
855 pNoteCaption = pNote->GetOrCreateCaption( rPos );
856 }
857
858 // prepare visible rectangle (add default distance to all borders)
859 tools::Rectangle aVisRect(
860 rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP,
861 rVisRect.Top() + SC_NOTECAPTION_BORDERDIST_TEMP,
862 rVisRect.Right() - SC_NOTECAPTION_BORDERDIST_TEMP,
863 rVisRect.Bottom() - SC_NOTECAPTION_BORDERDIST_TEMP );
864
865 // create the caption object
866 ScCaptionCreator aCreator( rDoc, rPos, bTailFront );
867
868 // insert caption into page (needed to set caption text)
869 rtl::Reference<SdrCaptionObj> pCaption = aCreator.GetCaption(); // just for ease of use
870 rDrawPage.InsertObject( pCaption.get() );
871
872 // clone the edit text object, then seta and format the Author and date text
873 if (pNoteCaption)
874 {
875 if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
876 pCaption->SetOutlinerParaObject( *pOPO );
877 // Setting and formatting rUserText: Author name and date time
878 if (officecfg::Office::Calc::Content::Display::NoteAuthor::get())
879 lcl_FormatAndInsertAuthorAndDatepara(pCaption.get(), aBuffer, bUserWithTrackText);
880 // set formatting (must be done after setting text) and resize the box to fit the text
881 if (auto pStyleSheet = pNoteCaption->GetStyleSheet())
882 pCaption->SetStyleSheet(pStyleSheet, true);
883 pCaption->SetMergedItemSetAndBroadcast(pNoteCaption->GetMergedItemSet());
884 }
885 else
886 {
887 pCaption->SetText(aBuffer.makeStringAndClear());
888 if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
889 pCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
890 }
891
892 // adjust caption size to text size
893 tools::Long nMaxWidth = ::std::min< tools::Long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
894 pCaption->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
895 pCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
896 pCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( nMaxWidth ) );
897 pCaption->SetMergedItem( makeSdrTextAutoGrowHeightItem( true ) );
898 pCaption->AdjustTextFrameWidthAndHeight();
899
900 // move caption into visible area
901 aCreator.AutoPlaceCaption( &aVisRect );
902
903 // XXX Note it is already inserted to the draw page.
904 return aCreator.GetCaption();
905 }
906
CreateNoteFromCaption(ScDocument & rDoc,const ScAddress & rPos,SdrCaptionObj * pCaption,bool bHasStyle)907 ScPostIt* ScNoteUtil::CreateNoteFromCaption(
908 ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj* pCaption, bool bHasStyle )
909 {
910 ScNoteData aNoteData( true/*bShown*/ );
911 aNoteData.mxCaption = pCaption;
912 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
913 pNote->AutoStamp();
914
915 rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
916
917 // ScNoteCaptionCreator c'tor updates the caption object to be part of a note
918 ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.mxCaption, true/*bShown*/ );
919
920 if (!bHasStyle)
921 {
922 if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
923 aNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
924
925 /* We used to show a shadow despite of the shadow item being set to false.
926 Clear the existing item, so it inherits the true setting from the style.
927 Setting explicitly to true would corrupt the shadow when opened in older versions. */
928 aNoteData.mxCaption->ClearMergedItem(SDRATTR_SHADOW);
929 }
930
931 return pNote;
932 }
933
CreateNoteData(const ScDocument & rDoc,const ScAddress & rPos,const tools::Rectangle & rCaptionRect,bool bShown)934 ScNoteData ScNoteUtil::CreateNoteData(const ScDocument& rDoc, const ScAddress& rPos,
935 const tools::Rectangle& rCaptionRect, bool bShown)
936 {
937 ScNoteData aNoteData( bShown );
938 aNoteData.mxInitData = std::make_shared<ScCaptionInitData>();
939 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
940
941 // convert absolute caption position to relative position
942 rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty();
943 if( !rInitData.mbDefaultPosSize )
944 {
945 tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, rPos, true );
946 bool bNegPage = rDoc.IsNegativePage( rPos.Tab() );
947 rInitData.maCaptionOffset.setX( bNegPage ? (aCellRect.Left() - rCaptionRect.Right()) : (rCaptionRect.Left() - aCellRect.Right()) );
948 rInitData.maCaptionOffset.setY( rCaptionRect.Top() - aCellRect.Top() );
949 rInitData.maCaptionSize = rCaptionRect.GetSize();
950 }
951
952 return aNoteData;
953 }
954
CreateNoteFromObjectData(ScDocument & rDoc,const ScAddress & rPos,const SfxItemSet & rItemSet,const OUString & rStyleName,const OutlinerParaObject & rOutlinerObj,const tools::Rectangle & rCaptionRect,bool bShown)955 ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
956 ScDocument& rDoc, const ScAddress& rPos, const SfxItemSet& rItemSet, const OUString& rStyleName,
957 const OutlinerParaObject& rOutlinerObj, const tools::Rectangle& rCaptionRect,
958 bool bShown )
959 {
960 ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown));
961 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
962 rInitData.mxOutlinerObj = rOutlinerObj;
963 rInitData.moItemSet.emplace(rItemSet);
964 rInitData.maStyleName = ScStyleNameConversion::ProgrammaticToDisplayName(rStyleName, SfxStyleFamily::Frame);
965
966 return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/false, 0/*nPostItId*/);
967 }
968
CreateNoteFromGenerator(ScDocument & rDoc,const ScAddress & rPos,std::unique_ptr<GenerateNoteCaption> xGenerator,const tools::Rectangle & rCaptionRect,bool bShown)969 ScPostIt* ScNoteUtil::CreateNoteFromGenerator(
970 ScDocument& rDoc, const ScAddress& rPos,
971 std::unique_ptr<GenerateNoteCaption> xGenerator,
972 const tools::Rectangle& rCaptionRect,
973 bool bShown )
974 {
975 ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown));
976 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
977 rInitData.mxGenerator = std::move(xGenerator);
978 // because the Caption is generated on demand, we will need to create the
979 // simple text now to supply any queries for that which don't require
980 // creation of a full Caption
981 rInitData.maSimpleText = rInitData.mxGenerator->GetSimpleText();
982 aNoteData.maAuthor = rInitData.mxGenerator->GetAuthorName();
983 return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/ false,
984 0 /*nPostItId*/, false /*bShouldAutoStamp*/);
985 }
986
InsertNote(ScDocument & rDoc,const ScAddress & rPos,ScNoteData && rNoteData,bool bAlwaysCreateCaption,sal_uInt32 nPostItId,bool bShouldAutoStamp)987 ScPostIt* ScNoteUtil::InsertNote(ScDocument& rDoc, const ScAddress& rPos, ScNoteData&& rNoteData,
988 bool bAlwaysCreateCaption, sal_uInt32 nPostItId,
989 bool bShouldAutoStamp)
990 {
991 /* Create the note and insert it into the document. If the note is
992 visible, the caption object will be created automatically. */
993 ScPostIt* pNote = new ScPostIt( rDoc, rPos, std::move(rNoteData), bAlwaysCreateCaption, nPostItId );
994 pNote->AutoStamp(bShouldAutoStamp);
995 //insert takes ownership
996 rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
997 return pNote;
998 }
999
CreateNoteFromString(ScDocument & rDoc,const ScAddress & rPos,const OUString & rNoteText,bool bShown,bool bAlwaysCreateCaption,sal_uInt32 nPostItId)1000 ScPostIt* ScNoteUtil::CreateNoteFromString(
1001 ScDocument& rDoc, const ScAddress& rPos, const OUString& rNoteText,
1002 bool bShown, bool bAlwaysCreateCaption, sal_uInt32 nPostItId )
1003 {
1004 ScPostIt* pNote = nullptr;
1005 if( !rNoteText.isEmpty() )
1006 {
1007 ScNoteData aNoteData( bShown );
1008 aNoteData.mxInitData = std::make_shared<ScCaptionInitData>();
1009 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
1010 rInitData.maSimpleText = rNoteText;
1011 rInitData.maStyleName = ScResId(STR_STYLENAME_NOTE);
1012 rInitData.mbDefaultPosSize = true;
1013
1014 pNote = InsertNote(rDoc, rPos, std::move(aNoteData), bAlwaysCreateCaption, nPostItId);
1015 }
1016 return pNote;
1017 }
1018
1019 namespace sc {
1020
NoteEntry(const ScAddress & rPos,const ScPostIt * pNote)1021 NoteEntry::NoteEntry( const ScAddress& rPos, const ScPostIt* pNote ) :
1022 maPos(rPos), mpNote(pNote) {}
1023
1024 }
1025
1026 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1027