1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "postit.hxx"
28
29 #include <rtl/ustrbuf.hxx>
30 #include <unotools/useroptions.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/svdocapt.hxx>
33 #include <editeng/outlobj.hxx>
34 #include <editeng/editobj.hxx>
35 #include <basegfx/polygon/b2dpolygon.hxx>
36
37 #include "scitems.hxx"
38 #include <svx/xlnstit.hxx>
39 #include <svx/xlnstwit.hxx>
40 #include <svx/xlnstcit.hxx>
41 #include <svx/sxcecitm.hxx>
42 #include <svx/xflclit.hxx>
43 #include <svx/sdshitm.hxx>
44 #include <svx/sdsxyitm.hxx>
45
46 #include "document.hxx"
47 #include "docpool.hxx"
48 #include "patattr.hxx"
49 #include "cell.hxx"
50 #include "drwlayer.hxx"
51 #include "userdat.hxx"
52 #include "detfunc.hxx"
53
54 using ::rtl::OUString;
55 using ::rtl::OUStringBuffer;
56
57 // ============================================================================
58
59 namespace {
60
61 const long SC_NOTECAPTION_WIDTH = 2900; // Default width of note caption textbox.
62 const long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; // Maximum width of temporary note caption textbox.
63 const long SC_NOTECAPTION_HEIGHT = 1800; // Default height of note caption textbox.
64 const long SC_NOTECAPTION_CELLDIST = 600; // Default distance of note captions to border of anchor cell.
65 const long SC_NOTECAPTION_OFFSET_Y = -1500; // Default Y offset of note captions to top border of anchor cell.
66 const long SC_NOTECAPTION_OFFSET_X = 1500; // Default X offset of note captions to left border of anchor cell.
67 const long SC_NOTECAPTION_BORDERDIST_TEMP = 100; // Distance of temporary note captions to visible sheet area.
68
69 // ============================================================================
70
71 /** Static helper functions for caption objects. */
72 class ScCaptionUtil
73 {
74 public:
75 /** Moves the caption object to the correct layer according to passed visibility. */
76 static void SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown );
77 /** Sets basic caption settings required for note caption objects. */
78 static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown );
79 /** Stores the cell position of the note in the user data area of the caption. */
80 static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos );
81 /** Sets all default formatting attributes to the caption object. */
82 static void SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc );
83 /** Updates caption item set according to the passed item set while removing shadow items. */
84 static void SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet );
85 };
86
87 // ----------------------------------------------------------------------------
88
SetCaptionLayer(SdrCaptionObj & rCaption,bool bShown)89 void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
90 {
91 SdrLayerID nLayer = bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN;
92 if( nLayer != rCaption.GetLayer() )
93 rCaption.SetLayer( nLayer );
94 }
95
SetBasicCaptionSettings(SdrCaptionObj & rCaption,bool bShown)96 void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown )
97 {
98 ScDrawLayer::SetAnchor( &rCaption, SCA_PAGE );
99 SetCaptionLayer( rCaption, bShown );
100 rCaption.SetFixedTail();
101 rCaption.SetSpecialTextBoxShadow();
102 }
103
SetCaptionUserData(SdrCaptionObj & rCaption,const ScAddress & rPos)104 void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos )
105 {
106 // pass true to ScDrawLayer::GetObjData() to create the object data entry
107 ScDrawObjData* pObjData = ScDrawLayer::GetObjData( &rCaption, true );
108 OSL_ENSURE( pObjData, "ScCaptionUtil::SetCaptionUserData - missing drawing object user data" );
109 pObjData->maStart = rPos;
110 pObjData->mbNote = true;
111 }
112
SetDefaultItems(SdrCaptionObj & rCaption,ScDocument & rDoc)113 void ScCaptionUtil::SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc )
114 {
115 SfxItemSet aItemSet = rCaption.GetMergedItemSet();
116
117 // caption tail arrow
118 ::basegfx::B2DPolygon aTriangle;
119 aTriangle.append( ::basegfx::B2DPoint( 10.0, 0.0 ) );
120 aTriangle.append( ::basegfx::B2DPoint( 0.0, 30.0 ) );
121 aTriangle.append( ::basegfx::B2DPoint( 20.0, 30.0 ) );
122 aTriangle.setClosed( true );
123 /* #99319# Line ends are now created with an empty name. The
124 checkForUniqueItem() method then finds a unique name for the items
125 value. */
126 aItemSet.Put( XLineStartItem( String::EmptyString(), ::basegfx::B2DPolyPolygon( aTriangle ) ) );
127 aItemSet.Put( XLineStartWidthItem( 200 ) );
128 aItemSet.Put( XLineStartCenterItem( sal_False ) );
129 aItemSet.Put( XFillStyleItem( XFILL_SOLID ) );
130 aItemSet.Put( XFillColorItem( String::EmptyString(), ScDetectiveFunc::GetCommentColor() ) );
131 aItemSet.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT ) );
132
133 // shadow
134 /* SdrShadowItem has sal_False, instead the shadow is set for the
135 rectangle only with SetSpecialTextBoxShadow() when the object is
136 created (item must be set to adjust objects from older files). */
137 aItemSet.Put( SdrShadowItem( sal_False ) );
138 aItemSet.Put( SdrShadowXDistItem( 100 ) );
139 aItemSet.Put( SdrShadowYDistItem( 100 ) );
140
141 // text attributes
142 aItemSet.Put( SdrTextLeftDistItem( 100 ) );
143 aItemSet.Put( SdrTextRightDistItem( 100 ) );
144 aItemSet.Put( SdrTextUpperDistItem( 100 ) );
145 aItemSet.Put( SdrTextLowerDistItem( 100 ) );
146 aItemSet.Put( SdrTextAutoGrowWidthItem( sal_False ) );
147 aItemSet.Put( SdrTextAutoGrowHeightItem( sal_True ) );
148 // #78943# use the default cell style to be able to modify the caption font
149 const ScPatternAttr& rDefPattern = static_cast< const ScPatternAttr& >( rDoc.GetPool()->GetDefaultItem( ATTR_PATTERN ) );
150 rDefPattern.FillEditItemSet( &aItemSet );
151
152 rCaption.SetMergedItemSet( aItemSet );
153 }
154
SetCaptionItems(SdrCaptionObj & rCaption,const SfxItemSet & rItemSet)155 void ScCaptionUtil::SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet )
156 {
157 // copy all items
158 rCaption.SetMergedItemSet( rItemSet );
159 // reset shadow items
160 rCaption.SetMergedItem( SdrShadowItem( sal_False ) );
161 rCaption.SetMergedItem( SdrShadowXDistItem( 100 ) );
162 rCaption.SetMergedItem( SdrShadowYDistItem( 100 ) );
163 rCaption.SetSpecialTextBoxShadow();
164 }
165
166 // ============================================================================
167
168 /** Helper for creation and manipulation of caption drawing objects independent
169 from cell annotations. */
170 class ScCaptionCreator
171 {
172 public:
173 /** Create a new caption. The caption will not be inserted into the document. */
174 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront );
175 /** Manipulate an existing caption. */
176 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption );
177
178 /** Returns the drawing layer page of the sheet contained in maPos. */
179 SdrPage* GetDrawPage();
180 /** Returns the caption drawing object. */
GetCaption()181 inline SdrCaptionObj* GetCaption() { return mpCaption; }
182
183 /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
184 void FitCaptionToRect( const Rectangle* pVisRect = 0 );
185 /** Places the caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */
186 void AutoPlaceCaption( const Rectangle* pVisRect = 0 );
187 /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */
188 void UpdateCaptionPos( const Rectangle* pVisRect = 0 );
189
190 protected:
191 /** Helper constructor for derived classes. */
192 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos );
193
194 /** Calculates the caption tail position according to current cell position. */
195 Point CalcTailPos( bool bTailFront );
196 /** Implements creation of the caption object. The caption will not be inserted into the document. */
197 void CreateCaption( bool bShown, bool bTailFront );
198
199 private:
200 /** Initializes all members. */
201 void Initialize();
202 /** Returns the passed rectangle if existing, page rectangle otherwise. */
GetVisRect(const Rectangle * pVisRect) const203 inline const Rectangle& GetVisRect( const Rectangle* pVisRect ) const { return pVisRect ? *pVisRect : maPageRect; }
204
205 private:
206 ScDocument& mrDoc;
207 ScAddress maPos;
208 SdrCaptionObj* mpCaption;
209 Rectangle maPageRect;
210 Rectangle maCellRect;
211 bool mbNegPage;
212 };
213
214 // ----------------------------------------------------------------------------
215
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,bool bShown,bool bTailFront)216 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront ) :
217 mrDoc( rDoc ),
218 maPos( rPos ),
219 mpCaption( 0 )
220 {
221 Initialize();
222 CreateCaption( bShown, bTailFront );
223 }
224
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,SdrCaptionObj & rCaption)225 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ) :
226 mrDoc( rDoc ),
227 maPos( rPos ),
228 mpCaption( &rCaption )
229 {
230 Initialize();
231 }
232
ScCaptionCreator(ScDocument & rDoc,const ScAddress & rPos)233 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) :
234 mrDoc( rDoc ),
235 maPos( rPos ),
236 mpCaption( 0 )
237 {
238 Initialize();
239 }
240
GetDrawPage()241 SdrPage* ScCaptionCreator::GetDrawPage()
242 {
243 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
244 return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : 0;
245 }
246
FitCaptionToRect(const Rectangle * pVisRect)247 void ScCaptionCreator::FitCaptionToRect( const Rectangle* pVisRect )
248 {
249 const Rectangle& rVisRect = GetVisRect( pVisRect );
250
251 // tail position
252 Point aTailPos = mpCaption->GetTailPos();
253 aTailPos.X() = ::std::max( ::std::min( aTailPos.X(), rVisRect.Right() ), rVisRect.Left() );
254 aTailPos.Y() = ::std::max( ::std::min( aTailPos.Y(), rVisRect.Bottom() ), rVisRect.Top() );
255 mpCaption->SetTailPos( aTailPos );
256
257 // caption rectangle
258 Rectangle aCaptRect = mpCaption->GetLogicRect();
259 Point aCaptPos = aCaptRect.TopLeft();
260 // move textbox inside right border of visible area
261 aCaptPos.X() = ::std::min< long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() );
262 // move textbox inside left border of visible area (this may move it outside on right side again)
263 aCaptPos.X() = ::std::max< long >( aCaptPos.X(), rVisRect.Left() );
264 // move textbox inside bottom border of visible area
265 aCaptPos.Y() = ::std::min< long >( aCaptPos.Y(), rVisRect.Bottom() - aCaptRect.GetHeight() );
266 // move textbox inside top border of visible area (this may move it outside on bottom side again)
267 aCaptPos.Y() = ::std::max< long >( aCaptPos.Y(), rVisRect.Top() );
268 // update caption
269 aCaptRect.SetPos( aCaptPos );
270 mpCaption->SetLogicRect( aCaptRect );
271 }
272
AutoPlaceCaption(const Rectangle * pVisRect)273 void ScCaptionCreator::AutoPlaceCaption( const Rectangle* pVisRect )
274 {
275 const Rectangle& rVisRect = GetVisRect( pVisRect );
276
277 // caption rectangle
278 Rectangle aCaptRect = mpCaption->GetLogicRect();
279 long nWidth = aCaptRect.GetWidth();
280 long nHeight = aCaptRect.GetHeight();
281
282 // n***Space contains available space between border of visible area and cell
283 long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1;
284 long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1;
285 long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1;
286 long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1;
287
288 // nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area
289 long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST;
290 long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST;
291
292 // bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area
293 bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell
294 bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell
295 bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area
296
297 // bFitsHeight*** == true means height of textbox fits into vertical free space of visible area
298 bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell
299 bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell
300 bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area
301
302 // bFits*** == true means the textbox fits completely into free space of visible area
303 bool bFitsLeft = bFitsWidthLeft && bFitsHeight;
304 bool bFitsRight = bFitsWidthRight && bFitsHeight;
305 bool bFitsTop = bFitsWidth && bFitsHeightTop;
306 bool bFitsBottom = bFitsWidth && bFitsHeightBottom;
307
308 Point aCaptPos;
309 // use left/right placement if possible, or if top/bottom placement not possible
310 if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) )
311 {
312 // prefer left in RTL sheet and right in LTR sheets
313 bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight);
314 bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft);
315 // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left
316 if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) )
317 aCaptPos.X() = maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth;
318 else // to right
319 aCaptPos.X() = maCellRect.Right() + SC_NOTECAPTION_CELLDIST;
320 // Y position according to top cell border
321 aCaptPos.Y() = maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y;
322 }
323 else // top or bottom placement
324 {
325 // X position
326 aCaptPos.X() = maCellRect.Left() + SC_NOTECAPTION_OFFSET_X;
327 // top placement, if possible
328 if( bFitsTop )
329 aCaptPos.Y() = maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight;
330 else // bottom placement
331 aCaptPos.Y() = maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST;
332 }
333
334 // update textbox position in note caption object
335 aCaptRect.SetPos( aCaptPos );
336 mpCaption->SetLogicRect( aCaptRect );
337 FitCaptionToRect( pVisRect );
338 }
339
UpdateCaptionPos(const Rectangle * pVisRect)340 void ScCaptionCreator::UpdateCaptionPos( const Rectangle* pVisRect )
341 {
342 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
343
344 // update caption position
345 const Point& rOldTailPos = mpCaption->GetTailPos();
346 Point aTailPos = CalcTailPos( false );
347 if( rOldTailPos != aTailPos )
348 {
349 // create drawing undo action
350 if( pDrawLayer )
351 if( pDrawLayer->IsUndoAllowed() )
352 if( pDrawLayer->IsRecording() )
353 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoGeoObject( *mpCaption ) );
354
355 // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly)
356 Rectangle aCaptRect = mpCaption->GetLogicRect();
357 long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right());
358 if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth();
359 long nDiffY = aCaptRect.Top() - rOldTailPos.Y();
360 aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) );
361 // set new tail position and caption rectangle
362 mpCaption->SetTailPos( aTailPos );
363 mpCaption->SetLogicRect( aCaptRect );
364 // fit caption into draw page
365 FitCaptionToRect( pVisRect );
366 }
367
368 // update cell position in caption user data
369 ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mpCaption, maPos.Tab() );
370 if( pCaptData && (maPos != pCaptData->maStart) )
371 {
372 // create drawing undo action
373 if( pDrawLayer && pDrawLayer->IsRecording() )
374 pDrawLayer->AddCalcUndo< ScUndoObjData >(mpCaption, pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd );
375 // set new position
376 pCaptData->maStart = maPos;
377 }
378 }
379
CalcTailPos(bool bTailFront)380 Point ScCaptionCreator::CalcTailPos( bool bTailFront )
381 {
382 // tail position
383 bool bTailLeft = bTailFront != mbNegPage;
384 Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight();
385 // move caption point 1/10 mm inside cell
386 if( bTailLeft ) aTailPos.X() += 10; else aTailPos.X() -= 10;
387 aTailPos.Y() += 10;
388 return aTailPos;
389 }
390
CreateCaption(bool bShown,bool bTailFront)391 void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
392 {
393 // create the caption drawing object
394 Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
395 Point aTailPos = CalcTailPos( bTailFront );
396 mpCaption = new SdrCaptionObj( aTextRect, aTailPos );
397 // basic caption settings
398 ScCaptionUtil::SetBasicCaptionSettings( *mpCaption, bShown );
399 }
400
Initialize()401 void ScCaptionCreator::Initialize()
402 {
403 maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true );
404 mbNegPage = mrDoc.IsNegativePage( maPos.Tab() );
405 if( SdrPage* pDrawPage = GetDrawPage() )
406 {
407 maPageRect = Rectangle( Point( 0, 0 ), pDrawPage->GetSize() );
408 /* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
409 The call to Rectangle::Adjust() orders left/right coordinate
410 accordingly. */
411 maPageRect.Justify();
412 }
413 }
414
415 // ============================================================================
416
417 /** Helper for creation of permanent caption drawing objects for cell notes. */
418 class ScNoteCaptionCreator : public ScCaptionCreator
419 {
420 public:
421 /** Create a new caption object and inserts it into the document. */
422 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
423 /** Manipulate an existing caption. */
424 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown );
425 };
426
427 // ----------------------------------------------------------------------------
428
ScNoteCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,ScNoteData & rNoteData)429 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
430 ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet
431 {
432 SdrPage* pDrawPage = GetDrawPage();
433 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
434 if( pDrawPage )
435 {
436 // create the caption drawing object
437 CreateCaption( rNoteData.mbShown, false );
438 rNoteData.mpCaption = GetCaption();
439 OSL_ENSURE( rNoteData.mpCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" );
440 if( rNoteData.mpCaption )
441 {
442 // store note position in user data of caption object
443 ScCaptionUtil::SetCaptionUserData( *rNoteData.mpCaption, rPos );
444 // insert object into draw page
445 pDrawPage->InsertObject( rNoteData.mpCaption );
446 }
447 }
448 }
449
ScNoteCaptionCreator(ScDocument & rDoc,const ScAddress & rPos,SdrCaptionObj & rCaption,bool bShown)450 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ) :
451 ScCaptionCreator( rDoc, rPos, rCaption )
452 {
453 SdrPage* pDrawPage = GetDrawPage();
454 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
455 OSL_ENSURE( rCaption.GetPage() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" );
456 if( pDrawPage && (rCaption.GetPage() == pDrawPage) )
457 {
458 // store note position in user data of caption object
459 ScCaptionUtil::SetCaptionUserData( rCaption, rPos );
460 // basic caption settings
461 ScCaptionUtil::SetBasicCaptionSettings( rCaption, bShown );
462 // set correct tail position
463 rCaption.SetTailPos( CalcTailPos( false ) );
464 }
465 }
466
467 } // namespace
468
469 // ============================================================================
470
471 struct ScCaptionInitData
472 {
473 typedef ::std::auto_ptr< SfxItemSet > SfxItemSetPtr;
474 typedef ::std::auto_ptr< OutlinerParaObject > OutlinerParaObjPtr;
475
476 SfxItemSetPtr mxItemSet; // Caption object formatting.
477 OutlinerParaObjPtr mxOutlinerObj; // Text object with all text portion formatting.
478 ::rtl::OUString maSimpleText; // Simple text without formatting.
479 Point maCaptionOffset; // Caption position relative to cell corner.
480 Size maCaptionSize; // Size of the caption object.
481 bool mbDefaultPosSize; // True = use default position and size for caption.
482
483 explicit ScCaptionInitData();
484 };
485
486 // ----------------------------------------------------------------------------
487
ScCaptionInitData()488 ScCaptionInitData::ScCaptionInitData() :
489 mbDefaultPosSize( true )
490 {
491 }
492
493 // ============================================================================
494
ScNoteData(bool bShown)495 ScNoteData::ScNoteData( bool bShown ) :
496 mpCaption( 0 ),
497 mbShown( bShown )
498 {
499 }
500
~ScNoteData()501 ScNoteData::~ScNoteData()
502 {
503 }
504
505 // ============================================================================
506
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,bool bShown)507 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, bool bShown ) :
508 mrDoc( rDoc ),
509 maNoteData( bShown )
510 {
511 AutoStamp();
512 CreateCaption( rPos );
513 }
514
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,const ScPostIt & rNote)515 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote ) :
516 mrDoc( rDoc ),
517 maNoteData( rNote.maNoteData )
518 {
519 maNoteData.mpCaption = 0;
520 CreateCaption( rPos, rNote.maNoteData.mpCaption );
521 }
522
ScPostIt(ScDocument & rDoc,const ScAddress & rPos,const ScNoteData & rNoteData,bool bAlwaysCreateCaption)523 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption ) :
524 mrDoc( rDoc ),
525 maNoteData( rNoteData )
526 {
527 if( bAlwaysCreateCaption || maNoteData.mbShown )
528 CreateCaptionFromInitData( rPos );
529 }
530
~ScPostIt()531 ScPostIt::~ScPostIt()
532 {
533 RemoveCaption();
534 }
535
Clone(const ScAddress & rOwnPos,ScDocument & rDestDoc,const ScAddress & rDestPos,bool bCloneCaption) const536 ScPostIt* ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const
537 {
538 CreateCaptionFromInitData( rOwnPos );
539 return bCloneCaption ? new ScPostIt( rDestDoc, rDestPos, *this ) : new ScPostIt( rDestDoc, rDestPos, maNoteData, false );
540 }
541
AutoStamp()542 void ScPostIt::AutoStamp()
543 {
544 maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() );
545 maNoteData.maAuthor = SvtUserOptions().GetID();
546 }
547
GetOutlinerObject() const548 const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
549 {
550 if( maNoteData.mpCaption )
551 return maNoteData.mpCaption->GetOutlinerParaObject();
552 if( maNoteData.mxInitData.get() )
553 return maNoteData.mxInitData->mxOutlinerObj.get();
554 return 0;
555 }
556
GetEditTextObject() const557 const EditTextObject* ScPostIt::GetEditTextObject() const
558 {
559 const OutlinerParaObject* pOPO = GetOutlinerObject();
560 return pOPO ? &pOPO->GetTextObject() : 0;
561 }
562
GetText() const563 OUString ScPostIt::GetText() const
564 {
565 if( const EditTextObject* pEditObj = GetEditTextObject() )
566 {
567 OUStringBuffer aBuffer;
568 for( sal_uInt32 nPara = 0, nParaCount = pEditObj->GetParagraphCount(); nPara < nParaCount; ++nPara )
569 {
570 if( nPara > 0 )
571 aBuffer.append( sal_Unicode( '\n' ) );
572 aBuffer.append( pEditObj->GetText( nPara ) );
573 }
574 return aBuffer.makeStringAndClear();
575 }
576 if( maNoteData.mxInitData.get() )
577 return maNoteData.mxInitData->maSimpleText;
578 return OUString();
579 }
580
HasMultiLineText() const581 bool ScPostIt::HasMultiLineText() const
582 {
583 if( const EditTextObject* pEditObj = GetEditTextObject() )
584 return pEditObj->GetParagraphCount() > 1;
585 if( maNoteData.mxInitData.get() )
586 return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0;
587 return false;
588 }
589
SetText(const ScAddress & rPos,const OUString & rText)590 void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
591 {
592 CreateCaptionFromInitData( rPos );
593 if( maNoteData.mpCaption )
594 maNoteData.mpCaption->SetText( rText );
595 }
596
GetOrCreateCaption(const ScAddress & rPos) const597 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const
598 {
599 CreateCaptionFromInitData( rPos );
600 return maNoteData.mpCaption;
601 }
602
ForgetCaption()603 void ScPostIt::ForgetCaption()
604 {
605 /* This function is used in undo actions to give up the responsibility for
606 the caption object which is handled by separate drawing undo actions. */
607 maNoteData.mpCaption = 0;
608 maNoteData.mxInitData.reset();
609 }
610
ShowCaption(const ScAddress & rPos,bool bShow)611 void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow )
612 {
613 CreateCaptionFromInitData( rPos );
614 // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
615 maNoteData.mbShown = bShow;
616 if( maNoteData.mpCaption )
617 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, bShow );
618 }
619
ShowCaptionTemp(const ScAddress & rPos,bool bShow)620 void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow )
621 {
622 CreateCaptionFromInitData( rPos );
623 if( maNoteData.mpCaption )
624 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, maNoteData.mbShown || bShow );
625 }
626
UpdateCaptionPos(const ScAddress & rPos)627 void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
628 {
629 CreateCaptionFromInitData( rPos );
630 if( maNoteData.mpCaption )
631 {
632 ScCaptionCreator aCreator( mrDoc, rPos, *maNoteData.mpCaption );
633 aCreator.UpdateCaptionPos();
634 }
635 }
636
637 // private --------------------------------------------------------------------
638
CreateCaptionFromInitData(const ScAddress & rPos) const639 void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
640 {
641 OSL_ENSURE( maNoteData.mpCaption || maNoteData.mxInitData.get(), "ScPostIt::CreateCaptionFromInitData - need caption object or initial caption data" );
642 if( maNoteData.mxInitData.get() )
643 {
644 /* This function is called from ScPostIt::Clone() when copying cells
645 to the clipboard/undo document, and when copying cells from the
646 clipboard/undo document. The former should always be called first,
647 so if called in an clipboard/undo document, the caption should have
648 been created already. */
649 OSL_ENSURE( !mrDoc.IsUndo() && !mrDoc.IsClipboard(), "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );
650
651 /* #i104915# Never try to create notes in Undo document, leads to
652 crash due to missing document members (e.g. row height array). */
653 if( !maNoteData.mpCaption && !mrDoc.IsUndo() )
654 {
655 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
656 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
657 if( maNoteData.mpCaption )
658 {
659 ScCaptionInitData& rInitData = *maNoteData.mxInitData;
660
661 // transfer ownership of outliner object to caption, or set simple text
662 OSL_ENSURE( rInitData.mxOutlinerObj.get() || (rInitData.maSimpleText.getLength() > 0),
663 "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
664 if( rInitData.mxOutlinerObj.get() )
665 maNoteData.mpCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() );
666 else
667 maNoteData.mpCaption->SetText( rInitData.maSimpleText );
668
669 // copy all items or set default items; reset shadow items
670 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc );
671 if( rInitData.mxItemSet.get() )
672 ScCaptionUtil::SetCaptionItems( *maNoteData.mpCaption, *rInitData.mxItemSet );
673
674 // set position and size of the caption object
675 if( rInitData.mbDefaultPosSize )
676 {
677 // set other items and fit caption size to text
678 maNoteData.mpCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
679 maNoteData.mpCaption->SetMergedItem( SdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
680 maNoteData.mpCaption->AdjustTextFrameWidthAndHeight();
681 aCreator.AutoPlaceCaption();
682 }
683 else
684 {
685 Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true );
686 bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() );
687 long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X());
688 long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y();
689 Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize );
690 maNoteData.mpCaption->SetLogicRect( aCaptRect );
691 aCreator.FitCaptionToRect();
692 }
693 }
694 }
695 // forget the initial caption data struct
696 maNoteData.mxInitData.reset();
697 }
698 }
699
CreateCaption(const ScAddress & rPos,const SdrCaptionObj * pCaption)700 void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
701 {
702 OSL_ENSURE( !maNoteData.mpCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
703 maNoteData.mpCaption = 0;
704
705 /* #i104915# Never try to create notes in Undo document, leads to
706 crash due to missing document members (e.g. row height array). */
707 OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" );
708 if( mrDoc.IsUndo() )
709 return;
710
711 // drawing layer may be missing, if a note is copied into a clipboard document
712 if( mrDoc.IsClipboard() )
713 mrDoc.InitDrawLayer();
714
715 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
716 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData );
717 if( maNoteData.mpCaption )
718 {
719 // clone settings of passed caption
720 if( pCaption )
721 {
722 // copy edit text object (object must be inserted into page already)
723 if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
724 maNoteData.mpCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
725 // copy formatting items (after text has been copied to apply font formatting)
726 maNoteData.mpCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
727 // move textbox position relative to new cell, copy textbox size
728 Rectangle aCaptRect = pCaption->GetLogicRect();
729 Point aDist = maNoteData.mpCaption->GetTailPos() - pCaption->GetTailPos();
730 aCaptRect.Move( aDist.X(), aDist.Y() );
731 maNoteData.mpCaption->SetLogicRect( aCaptRect );
732 aCreator.FitCaptionToRect();
733 }
734 else
735 {
736 // set default formatting and default position
737 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc );
738 aCreator.AutoPlaceCaption();
739 }
740
741 // create undo action
742 if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
743 if( pDrawLayer->IsUndoAllowed() )
744 if( pDrawLayer->IsRecording() )
745 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoNewObject( *maNoteData.mpCaption ) );
746 }
747 }
748
RemoveCaption()749 void ScPostIt::RemoveCaption()
750 {
751
752 /* Remove caption object only, if this note is its owner (e.g. notes in
753 undo documents refer to captions in original document, do not remove
754 them from drawing layer here). */
755 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
756 if( maNoteData.mpCaption && (pDrawLayer == maNoteData.mpCaption->GetModel()) )
757 {
758 OSL_ENSURE( pDrawLayer, "ScPostIt::RemoveCaption - object without drawing layer" );
759 SdrPage* pDrawPage = maNoteData.mpCaption->GetPage();
760 OSL_ENSURE( pDrawPage, "ScPostIt::RemoveCaption - object without drawing page" );
761 if( pDrawPage )
762 {
763 pDrawPage->RecalcObjOrdNums();
764 // create drawing undo action (before removing the object to have valid draw page in undo action)
765 bool bRecording = ( pDrawLayer && pDrawLayer->IsUndoAllowed() && pDrawLayer->IsRecording() );
766 if( bRecording )
767 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoDeleteObject( *maNoteData.mpCaption ) );
768 // remove the object from the drawing page, delete if undo is disabled
769 SdrObject* pObj = pDrawPage->RemoveObject( maNoteData.mpCaption->GetOrdNum() );
770 if( !bRecording )
771 SdrObject::Free( pObj );
772 }
773 }
774 maNoteData.mpCaption = 0;
775 }
776
777 // ============================================================================
778
UpdateCaptionPositions(ScDocument & rDoc,const ScRange & rRange)779 void ScNoteUtil::UpdateCaptionPositions( ScDocument& rDoc, const ScRange& rRange )
780 {
781 // do not use ScCellIterator, it skips filtered and subtotal cells
782 for( ScAddress aPos( rRange.aStart ); aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab() )
783 for( aPos.SetCol( rRange.aStart.Col() ); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol() )
784 for( aPos.SetRow( rRange.aStart.Row() ); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow() )
785 if( ScPostIt* pNote = rDoc.GetNote( aPos ) )
786 pNote->UpdateCaptionPos( aPos );
787 }
788
CreateTempCaption(ScDocument & rDoc,const ScAddress & rPos,SdrPage & rDrawPage,const OUString & rUserText,const Rectangle & rVisRect,bool bTailFront)789 SdrCaptionObj* ScNoteUtil::CreateTempCaption(
790 ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage,
791 const OUString& rUserText, const Rectangle& rVisRect, bool bTailFront )
792 {
793 OUStringBuffer aBuffer( rUserText );
794 // add plain text of invisible (!) cell note (no formatting etc.)
795 SdrCaptionObj* pNoteCaption = 0;
796 const ScPostIt* pNote = rDoc.GetNote( rPos );
797 if( pNote && !pNote->IsCaptionShown() )
798 {
799 if( aBuffer.getLength() > 0 )
800 aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\n________\n" ) ).append( pNote->GetText() );
801 pNoteCaption = pNote->GetOrCreateCaption( rPos );
802 }
803
804 // create a caption if any text exists
805 if( !pNoteCaption && (aBuffer.getLength() == 0) )
806 return 0;
807
808 // prepare visible rectangle (add default distance to all borders)
809 Rectangle aVisRect(
810 rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP,
811 rVisRect.Top() + SC_NOTECAPTION_BORDERDIST_TEMP,
812 rVisRect.Right() - SC_NOTECAPTION_BORDERDIST_TEMP,
813 rVisRect.Bottom() - SC_NOTECAPTION_BORDERDIST_TEMP );
814
815 // create the caption object
816 ScCaptionCreator aCreator( rDoc, rPos, true, bTailFront );
817 SdrCaptionObj* pCaption = aCreator.GetCaption();
818
819 // insert caption into page (needed to set caption text)
820 rDrawPage.InsertObject( pCaption );
821
822 // clone the edit text object, unless user text is present, then set this text
823 if( pNoteCaption && (rUserText.getLength() == 0) )
824 {
825 if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
826 pCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
827 // set formatting (must be done after setting text) and resize the box to fit the text
828 pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() );
829 Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() );
830 pCaption->SetLogicRect( aCaptRect );
831 }
832 else
833 {
834 // if pNoteCaption is null, then aBuffer contains some text
835 pCaption->SetText( aBuffer.makeStringAndClear() );
836 ScCaptionUtil::SetDefaultItems( *pCaption, rDoc );
837 // adjust caption size to text size
838 long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
839 pCaption->SetMergedItem( SdrTextAutoGrowWidthItem( sal_True ) );
840 pCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
841 pCaption->SetMergedItem( SdrTextMaxFrameWidthItem( nMaxWidth ) );
842 pCaption->SetMergedItem( SdrTextAutoGrowHeightItem( sal_True ) );
843 pCaption->AdjustTextFrameWidthAndHeight();
844 }
845
846 // move caption into visible area
847 aCreator.AutoPlaceCaption( &aVisRect );
848 return pCaption;
849 }
850
CreateNoteFromCaption(ScDocument & rDoc,const ScAddress & rPos,SdrCaptionObj & rCaption,bool bShown)851 ScPostIt* ScNoteUtil::CreateNoteFromCaption(
852 ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown )
853 {
854 ScNoteData aNoteData( bShown );
855 aNoteData.mpCaption = &rCaption;
856 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
857 pNote->AutoStamp();
858 rDoc.TakeNote( rPos, pNote );
859 // if pNote still points to the note after TakeNote(), insertion was successful
860 if( pNote )
861 {
862 // ScNoteCaptionCreator c'tor updates the caption object to be part of a note
863 ScNoteCaptionCreator aCreator( rDoc, rPos, rCaption, bShown );
864 }
865 return pNote;
866 }
867
CreateNoteFromObjectData(ScDocument & rDoc,const ScAddress & rPos,SfxItemSet * pItemSet,OutlinerParaObject * pOutlinerObj,const Rectangle & rCaptionRect,bool bShown,bool bAlwaysCreateCaption)868 ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
869 ScDocument& rDoc, const ScAddress& rPos, SfxItemSet* pItemSet,
870 OutlinerParaObject* pOutlinerObj, const Rectangle& rCaptionRect,
871 bool bShown, bool bAlwaysCreateCaption )
872 {
873 OSL_ENSURE( pItemSet && pOutlinerObj, "ScNoteUtil::CreateNoteFromObjectData - item set and outliner object expected" );
874 ScNoteData aNoteData( bShown );
875 aNoteData.mxInitData.reset( new ScCaptionInitData );
876 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
877 rInitData.mxItemSet.reset( pItemSet );
878 rInitData.mxOutlinerObj.reset( pOutlinerObj );
879
880 // convert absolute caption position to relative position
881 rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty();
882 if( !rInitData.mbDefaultPosSize )
883 {
884 Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, rPos, true );
885 bool bNegPage = rDoc.IsNegativePage( rPos.Tab() );
886 rInitData.maCaptionOffset.X() = bNegPage ? (aCellRect.Left() - rCaptionRect.Right()) : (rCaptionRect.Left() - aCellRect.Right());
887 rInitData.maCaptionOffset.Y() = rCaptionRect.Top() - aCellRect.Top();
888 rInitData.maCaptionSize = rCaptionRect.GetSize();
889 }
890
891 /* Create the note and insert it into the document. If the note is
892 visible, the caption object will be created automatically. */
893 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption );
894 pNote->AutoStamp();
895 rDoc.TakeNote( rPos, pNote );
896 // if pNote still points to the note after TakeNote(), insertion was successful
897 return pNote;
898 }
899
CreateNoteFromString(ScDocument & rDoc,const ScAddress & rPos,const OUString & rNoteText,bool bShown,bool bAlwaysCreateCaption)900 ScPostIt* ScNoteUtil::CreateNoteFromString(
901 ScDocument& rDoc, const ScAddress& rPos, const OUString& rNoteText,
902 bool bShown, bool bAlwaysCreateCaption )
903 {
904 ScPostIt* pNote = 0;
905 if( rNoteText.getLength() > 0 )
906 {
907 ScNoteData aNoteData( bShown );
908 aNoteData.mxInitData.reset( new ScCaptionInitData );
909 ScCaptionInitData& rInitData = *aNoteData.mxInitData;
910 rInitData.maSimpleText = rNoteText;
911 rInitData.mbDefaultPosSize = true;
912
913 /* Create the note and insert it into the document. If the note is
914 visible, the caption object will be created automatically. */
915 pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption );
916 pNote->AutoStamp();
917 rDoc.TakeNote( rPos, pNote );
918 // if pNote still points to the note after TakeNote(), insertion was successful
919 }
920 return pNote;
921 }
922
923 // ============================================================================
924