xref: /core/sc/source/core/data/postit.cxx (revision 8bbba41d8730212931208434ee63efe913868a12)
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