1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 #include "postit.hxx" 32 33 #include <rtl/ustrbuf.hxx> 34 #include <unotools/useroptions.hxx> 35 #include <svx/svdpage.hxx> 36 #include <svx/svdocapt.hxx> 37 #include <editeng/outlobj.hxx> 38 #include <editeng/editobj.hxx> 39 #include <basegfx/polygon/b2dpolygon.hxx> 40 41 #include "scitems.hxx" 42 #include <svx/xlnstit.hxx> 43 #include <svx/xlnstwit.hxx> 44 #include <svx/xlnstcit.hxx> 45 #include <svx/sxcecitm.hxx> 46 #include <svx/xflclit.hxx> 47 #include <svx/sdshitm.hxx> 48 #include <svx/sdsxyitm.hxx> 49 50 #include "document.hxx" 51 #include "docpool.hxx" 52 #include "patattr.hxx" 53 #include "cell.hxx" 54 #include "drwlayer.hxx" 55 #include "userdat.hxx" 56 #include "detfunc.hxx" 57 58 using ::rtl::OUString; 59 using ::rtl::OUStringBuffer; 60 61 // ============================================================================ 62 63 namespace { 64 65 const long SC_NOTECAPTION_WIDTH = 2900; /// Default width of note caption textbox. 66 const long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; /// Maximum width of temporary note caption textbox. 67 const long SC_NOTECAPTION_HEIGHT = 1800; /// Default height of note caption textbox. 68 const long SC_NOTECAPTION_CELLDIST = 600; /// Default distance of note captions to border of anchor cell. 69 const long SC_NOTECAPTION_OFFSET_Y = -1500; /// Default Y offset of note captions to top border of anchor cell. 70 const long SC_NOTECAPTION_OFFSET_X = 1500; /// Default X offset of note captions to left border of anchor cell. 71 const long SC_NOTECAPTION_BORDERDIST_TEMP = 100; /// Distance of temporary note captions to visible sheet area. 72 73 // ============================================================================ 74 75 /** Static helper functions for caption objects. */ 76 class ScCaptionUtil 77 { 78 public: 79 /** Moves the caption object to the correct layer according to passed visibility. */ 80 static void SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown ); 81 /** Sets basic caption settings required for note caption objects. */ 82 static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown ); 83 /** Stores the cell position of the note in the user data area of the caption. */ 84 static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos ); 85 /** Sets all default formatting attributes to the caption object. */ 86 static void SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc ); 87 /** Updates caption item set according to the passed item set while removing shadow items. */ 88 static void SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet ); 89 }; 90 91 // ---------------------------------------------------------------------------- 92 93 void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown ) 94 { 95 SdrLayerID nLayer = bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN; 96 if( nLayer != rCaption.GetLayer() ) 97 rCaption.SetLayer( nLayer ); 98 } 99 100 void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown ) 101 { 102 ScDrawLayer::SetAnchor( &rCaption, SCA_PAGE ); 103 SetCaptionLayer( rCaption, bShown ); 104 rCaption.SetFixedTail(); 105 rCaption.SetSpecialTextBoxShadow(); 106 } 107 108 void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos ) 109 { 110 // pass true to ScDrawLayer::GetObjData() to create the object data entry 111 ScDrawObjData* pObjData = ScDrawLayer::GetObjData( &rCaption, true ); 112 OSL_ENSURE( pObjData, "ScCaptionUtil::SetCaptionUserData - missing drawing object user data" ); 113 pObjData->maStart = rPos; 114 pObjData->mbNote = true; 115 } 116 117 void ScCaptionUtil::SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc ) 118 { 119 SfxItemSet aItemSet = rCaption.GetMergedItemSet(); 120 121 // caption tail arrow 122 ::basegfx::B2DPolygon aTriangle; 123 aTriangle.append( ::basegfx::B2DPoint( 10.0, 0.0 ) ); 124 aTriangle.append( ::basegfx::B2DPoint( 0.0, 30.0 ) ); 125 aTriangle.append( ::basegfx::B2DPoint( 20.0, 30.0 ) ); 126 aTriangle.setClosed( true ); 127 /* #99319# Line ends are now created with an empty name. The 128 checkForUniqueItem() method then finds a unique name for the item's 129 value. */ 130 aItemSet.Put( XLineStartItem( String::EmptyString(), ::basegfx::B2DPolyPolygon( aTriangle ) ) ); 131 aItemSet.Put( XLineStartWidthItem( 200 ) ); 132 aItemSet.Put( XLineStartCenterItem( sal_False ) ); 133 aItemSet.Put( XFillStyleItem( XFILL_SOLID ) ); 134 aItemSet.Put( XFillColorItem( String::EmptyString(), ScDetectiveFunc::GetCommentColor() ) ); 135 aItemSet.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT ) ); 136 137 // shadow 138 /* SdrShadowItem has sal_False, instead the shadow is set for the 139 rectangle only with SetSpecialTextBoxShadow() when the object is 140 created (item must be set to adjust objects from older files). */ 141 aItemSet.Put( SdrShadowItem( sal_False ) ); 142 aItemSet.Put( SdrShadowXDistItem( 100 ) ); 143 aItemSet.Put( SdrShadowYDistItem( 100 ) ); 144 145 // text attributes 146 aItemSet.Put( SdrTextLeftDistItem( 100 ) ); 147 aItemSet.Put( SdrTextRightDistItem( 100 ) ); 148 aItemSet.Put( SdrTextUpperDistItem( 100 ) ); 149 aItemSet.Put( SdrTextLowerDistItem( 100 ) ); 150 aItemSet.Put( SdrTextAutoGrowWidthItem( sal_False ) ); 151 aItemSet.Put( SdrTextAutoGrowHeightItem( sal_True ) ); 152 // #78943# use the default cell style to be able to modify the caption font 153 const ScPatternAttr& rDefPattern = static_cast< const ScPatternAttr& >( rDoc.GetPool()->GetDefaultItem( ATTR_PATTERN ) ); 154 rDefPattern.FillEditItemSet( &aItemSet ); 155 156 rCaption.SetMergedItemSet( aItemSet ); 157 } 158 159 void ScCaptionUtil::SetCaptionItems( SdrCaptionObj& rCaption, const SfxItemSet& rItemSet ) 160 { 161 // copy all items 162 rCaption.SetMergedItemSet( rItemSet ); 163 // reset shadow items 164 rCaption.SetMergedItem( SdrShadowItem( sal_False ) ); 165 rCaption.SetMergedItem( SdrShadowXDistItem( 100 ) ); 166 rCaption.SetMergedItem( SdrShadowYDistItem( 100 ) ); 167 rCaption.SetSpecialTextBoxShadow(); 168 } 169 170 // ============================================================================ 171 172 /** Helper for creation and manipulation of caption drawing objects independent 173 from cell annotations. */ 174 class ScCaptionCreator 175 { 176 public: 177 /** Create a new caption. The caption will not be inserted into the document. */ 178 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront ); 179 /** Manipulate an existing caption. */ 180 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ); 181 182 /** Returns the drawing layer page of the sheet contained in maPos. */ 183 SdrPage* GetDrawPage(); 184 /** Returns the caption drawing obejct. */ 185 inline SdrCaptionObj* GetCaption() { return mpCaption; } 186 187 /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */ 188 void FitCaptionToRect( const Rectangle* pVisRect = 0 ); 189 /** Places the caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */ 190 void AutoPlaceCaption( const Rectangle* pVisRect = 0 ); 191 /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */ 192 void UpdateCaptionPos( const Rectangle* pVisRect = 0 ); 193 194 protected: 195 /** Helper constructor for derived classes. */ 196 explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ); 197 198 /** Calculates the caption tail position according to current cell position. */ 199 Point CalcTailPos( bool bTailFront ); 200 /** Implements creation of the caption object. The caption will not be inserted into the document. */ 201 void CreateCaption( bool bShown, bool bTailFront ); 202 203 private: 204 /** Initializes all members. */ 205 void Initialize(); 206 /** Returns the passed rectangle if existing, page rectangle otherwise. */ 207 inline const Rectangle& GetVisRect( const Rectangle* pVisRect ) const { return pVisRect ? *pVisRect : maPageRect; } 208 209 private: 210 ScDocument& mrDoc; 211 ScAddress maPos; 212 SdrCaptionObj* mpCaption; 213 Rectangle maPageRect; 214 Rectangle maCellRect; 215 bool mbNegPage; 216 }; 217 218 // ---------------------------------------------------------------------------- 219 220 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront ) : 221 mrDoc( rDoc ), 222 maPos( rPos ), 223 mpCaption( 0 ) 224 { 225 Initialize(); 226 CreateCaption( bShown, bTailFront ); 227 } 228 229 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ) : 230 mrDoc( rDoc ), 231 maPos( rPos ), 232 mpCaption( &rCaption ) 233 { 234 Initialize(); 235 } 236 237 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) : 238 mrDoc( rDoc ), 239 maPos( rPos ), 240 mpCaption( 0 ) 241 { 242 Initialize(); 243 } 244 245 SdrPage* ScCaptionCreator::GetDrawPage() 246 { 247 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer(); 248 return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : 0; 249 } 250 251 void ScCaptionCreator::FitCaptionToRect( const Rectangle* pVisRect ) 252 { 253 const Rectangle& rVisRect = GetVisRect( pVisRect ); 254 255 // tail position 256 Point aTailPos = mpCaption->GetTailPos(); 257 aTailPos.X() = ::std::max( ::std::min( aTailPos.X(), rVisRect.Right() ), rVisRect.Left() ); 258 aTailPos.Y() = ::std::max( ::std::min( aTailPos.Y(), rVisRect.Bottom() ), rVisRect.Top() ); 259 mpCaption->SetTailPos( aTailPos ); 260 261 // caption rectangle 262 Rectangle aCaptRect = mpCaption->GetLogicRect(); 263 Point aCaptPos = aCaptRect.TopLeft(); 264 // move textbox inside right border of visible area 265 aCaptPos.X() = ::std::min< long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() ); 266 // move textbox inside left border of visible area (this may move it outside on right side again) 267 aCaptPos.X() = ::std::max< long >( aCaptPos.X(), rVisRect.Left() ); 268 // move textbox inside bottom border of visible area 269 aCaptPos.Y() = ::std::min< long >( aCaptPos.Y(), rVisRect.Bottom() - aCaptRect.GetHeight() ); 270 // move textbox inside top border of visible area (this may move it outside on bottom side again) 271 aCaptPos.Y() = ::std::max< long >( aCaptPos.Y(), rVisRect.Top() ); 272 // update caption 273 aCaptRect.SetPos( aCaptPos ); 274 mpCaption->SetLogicRect( aCaptRect ); 275 } 276 277 void ScCaptionCreator::AutoPlaceCaption( const Rectangle* pVisRect ) 278 { 279 const Rectangle& rVisRect = GetVisRect( pVisRect ); 280 281 // caption rectangle 282 Rectangle aCaptRect = mpCaption->GetLogicRect(); 283 long nWidth = aCaptRect.GetWidth(); 284 long nHeight = aCaptRect.GetHeight(); 285 286 // n***Space contains available space between border of visible area and cell 287 long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1; 288 long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1; 289 long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1; 290 long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1; 291 292 // nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area 293 long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST; 294 long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST; 295 296 // bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area 297 bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell 298 bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell 299 bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area 300 301 // bFitsHeight*** == true means height of textbox fits into vertical free space of visible area 302 bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell 303 bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell 304 bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area 305 306 // bFits*** == true means the textbox fits completely into free space of visible area 307 bool bFitsLeft = bFitsWidthLeft && bFitsHeight; 308 bool bFitsRight = bFitsWidthRight && bFitsHeight; 309 bool bFitsTop = bFitsWidth && bFitsHeightTop; 310 bool bFitsBottom = bFitsWidth && bFitsHeightBottom; 311 312 Point aCaptPos; 313 // use left/right placement if possible, or if top/bottom placement not possible 314 if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) ) 315 { 316 // prefer left in RTL sheet and right in LTR sheets 317 bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight); 318 bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft); 319 // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left 320 if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) ) 321 aCaptPos.X() = maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth; 322 else // to right 323 aCaptPos.X() = maCellRect.Right() + SC_NOTECAPTION_CELLDIST; 324 // Y position according to top cell border 325 aCaptPos.Y() = maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y; 326 } 327 else // top or bottom placement 328 { 329 // X position 330 aCaptPos.X() = maCellRect.Left() + SC_NOTECAPTION_OFFSET_X; 331 // top placement, if possible 332 if( bFitsTop ) 333 aCaptPos.Y() = maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight; 334 else // bottom placement 335 aCaptPos.Y() = maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST; 336 } 337 338 // update textbox position in note caption object 339 aCaptRect.SetPos( aCaptPos ); 340 mpCaption->SetLogicRect( aCaptRect ); 341 FitCaptionToRect( pVisRect ); 342 } 343 344 void ScCaptionCreator::UpdateCaptionPos( const Rectangle* pVisRect ) 345 { 346 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer(); 347 348 // update caption position 349 const Point& rOldTailPos = mpCaption->GetTailPos(); 350 Point aTailPos = CalcTailPos( false ); 351 if( rOldTailPos != aTailPos ) 352 { 353 // create drawing undo action 354 if( pDrawLayer && pDrawLayer->IsRecording() ) 355 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoGeoObject( *mpCaption ) ); 356 // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly) 357 Rectangle aCaptRect = mpCaption->GetLogicRect(); 358 long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right()); 359 if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth(); 360 long nDiffY = aCaptRect.Top() - rOldTailPos.Y(); 361 aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) ); 362 // set new tail position and caption rectangle 363 mpCaption->SetTailPos( aTailPos ); 364 mpCaption->SetLogicRect( aCaptRect ); 365 // fit caption into draw page 366 FitCaptionToRect( pVisRect ); 367 } 368 369 // update cell position in caption user data 370 ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mpCaption, maPos.Tab() ); 371 if( pCaptData && (maPos != pCaptData->maStart) ) 372 { 373 // create drawing undo action 374 if( pDrawLayer && pDrawLayer->IsRecording() ) 375 pDrawLayer->AddCalcUndo( new ScUndoObjData( mpCaption, pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) ); 376 // set new position 377 pCaptData->maStart = maPos; 378 } 379 } 380 381 Point ScCaptionCreator::CalcTailPos( bool bTailFront ) 382 { 383 // tail position 384 bool bTailLeft = bTailFront != mbNegPage; 385 Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight(); 386 // move caption point 1/10 mm inside cell 387 if( bTailLeft ) aTailPos.X() += 10; else aTailPos.X() -= 10; 388 aTailPos.Y() += 10; 389 return aTailPos; 390 } 391 392 void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront ) 393 { 394 // create the caption drawing object 395 Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) ); 396 Point aTailPos = CalcTailPos( bTailFront ); 397 mpCaption = new SdrCaptionObj( aTextRect, aTailPos ); 398 // basic caption settings 399 ScCaptionUtil::SetBasicCaptionSettings( *mpCaption, bShown ); 400 } 401 402 void ScCaptionCreator::Initialize() 403 { 404 maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true ); 405 mbNegPage = mrDoc.IsNegativePage( maPos.Tab() ); 406 if( SdrPage* pDrawPage = GetDrawPage() ) 407 { 408 maPageRect = Rectangle( Point( 0, 0 ), pDrawPage->GetSize() ); 409 /* #i98141# SdrPage::GetSize() returns negative width in RTL mode. 410 The call to Rectangle::Adjust() orders left/right coordinate 411 accordingly. */ 412 maPageRect.Justify(); 413 } 414 } 415 416 // ============================================================================ 417 418 /** Helper for creation of permanent caption drawing objects for cell notes. */ 419 class ScNoteCaptionCreator : public ScCaptionCreator 420 { 421 public: 422 /** Create a new caption object and inserts it into the document. */ 423 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ); 424 /** Manipulate an existing caption. */ 425 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ); 426 }; 427 428 // ---------------------------------------------------------------------------- 429 430 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) : 431 ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet 432 { 433 SdrPage* pDrawPage = GetDrawPage(); 434 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" ); 435 if( pDrawPage ) 436 { 437 // create the caption drawing object 438 CreateCaption( rNoteData.mbShown, false ); 439 rNoteData.mpCaption = GetCaption(); 440 OSL_ENSURE( rNoteData.mpCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" ); 441 if( rNoteData.mpCaption ) 442 { 443 // store note position in user data of caption object 444 ScCaptionUtil::SetCaptionUserData( *rNoteData.mpCaption, rPos ); 445 // insert object into draw page 446 pDrawPage->InsertObject( rNoteData.mpCaption ); 447 } 448 } 449 } 450 451 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ) : 452 ScCaptionCreator( rDoc, rPos, rCaption ) 453 { 454 SdrPage* pDrawPage = GetDrawPage(); 455 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" ); 456 OSL_ENSURE( rCaption.GetPage() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" ); 457 if( pDrawPage && (rCaption.GetPage() == pDrawPage) ) 458 { 459 // store note position in user data of caption object 460 ScCaptionUtil::SetCaptionUserData( rCaption, rPos ); 461 // basic caption settings 462 ScCaptionUtil::SetBasicCaptionSettings( rCaption, bShown ); 463 // set correct tail position 464 rCaption.SetTailPos( CalcTailPos( false ) ); 465 } 466 } 467 468 } // namespace 469 470 // ============================================================================ 471 472 struct ScCaptionInitData 473 { 474 typedef ::std::auto_ptr< SfxItemSet > SfxItemSetPtr; 475 typedef ::std::auto_ptr< OutlinerParaObject > OutlinerParaObjPtr; 476 477 SfxItemSetPtr mxItemSet; /// Caption object formatting. 478 OutlinerParaObjPtr mxOutlinerObj; /// Text object with all text portion formatting. 479 ::rtl::OUString maSimpleText; /// Simple text without formatting. 480 Point maCaptionOffset; /// Caption position relative to cell corner. 481 Size maCaptionSize; /// Size of the caption object. 482 bool mbDefaultPosSize; /// True = use default position and size for caption. 483 484 explicit ScCaptionInitData(); 485 }; 486 487 // ---------------------------------------------------------------------------- 488 489 ScCaptionInitData::ScCaptionInitData() : 490 mbDefaultPosSize( true ) 491 { 492 } 493 494 // ============================================================================ 495 496 ScNoteData::ScNoteData( bool bShown ) : 497 mpCaption( 0 ), 498 mbShown( bShown ) 499 { 500 } 501 502 ScNoteData::~ScNoteData() 503 { 504 } 505 506 // ============================================================================ 507 508 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, bool bShown ) : 509 mrDoc( rDoc ), 510 maNoteData( bShown ) 511 { 512 AutoStamp(); 513 CreateCaption( rPos ); 514 } 515 516 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote ) : 517 mrDoc( rDoc ), 518 maNoteData( rNote.maNoteData ) 519 { 520 maNoteData.mpCaption = 0; 521 CreateCaption( rPos, rNote.maNoteData.mpCaption ); 522 } 523 524 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption ) : 525 mrDoc( rDoc ), 526 maNoteData( rNoteData ) 527 { 528 if( bAlwaysCreateCaption || maNoteData.mbShown ) 529 CreateCaptionFromInitData( rPos ); 530 } 531 532 ScPostIt::~ScPostIt() 533 { 534 RemoveCaption(); 535 } 536 537 ScPostIt* ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const 538 { 539 CreateCaptionFromInitData( rOwnPos ); 540 return bCloneCaption ? new ScPostIt( rDestDoc, rDestPos, *this ) : new ScPostIt( rDestDoc, rDestPos, maNoteData, false ); 541 } 542 543 void ScPostIt::AutoStamp() 544 { 545 maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() ); 546 maNoteData.maAuthor = SvtUserOptions().GetID(); 547 } 548 549 const OutlinerParaObject* ScPostIt::GetOutlinerObject() const 550 { 551 if( maNoteData.mpCaption ) 552 return maNoteData.mpCaption->GetOutlinerParaObject(); 553 if( maNoteData.mxInitData.get() ) 554 return maNoteData.mxInitData->mxOutlinerObj.get(); 555 return 0; 556 } 557 558 const EditTextObject* ScPostIt::GetEditTextObject() const 559 { 560 const OutlinerParaObject* pOPO = GetOutlinerObject(); 561 return pOPO ? &pOPO->GetTextObject() : 0; 562 } 563 564 OUString ScPostIt::GetText() const 565 { 566 if( const EditTextObject* pEditObj = GetEditTextObject() ) 567 { 568 OUStringBuffer aBuffer; 569 for( sal_uInt16 nPara = 0, nParaCount = pEditObj->GetParagraphCount(); nPara < nParaCount; ++nPara ) 570 { 571 if( nPara > 0 ) 572 aBuffer.append( sal_Unicode( '\n' ) ); 573 aBuffer.append( pEditObj->GetText( nPara ) ); 574 } 575 return aBuffer.makeStringAndClear(); 576 } 577 if( maNoteData.mxInitData.get() ) 578 return maNoteData.mxInitData->maSimpleText; 579 return OUString(); 580 } 581 582 bool ScPostIt::HasMultiLineText() const 583 { 584 if( const EditTextObject* pEditObj = GetEditTextObject() ) 585 return pEditObj->GetParagraphCount() > 1; 586 if( maNoteData.mxInitData.get() ) 587 return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0; 588 return false; 589 } 590 591 void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText ) 592 { 593 CreateCaptionFromInitData( rPos ); 594 if( maNoteData.mpCaption ) 595 maNoteData.mpCaption->SetText( rText ); 596 } 597 598 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const 599 { 600 CreateCaptionFromInitData( rPos ); 601 return maNoteData.mpCaption; 602 } 603 604 void ScPostIt::ForgetCaption() 605 { 606 /* This function is used in undo actions to give up the responsibility for 607 the caption object which is handled by separate drawing undo actions. */ 608 maNoteData.mpCaption = 0; 609 maNoteData.mxInitData.reset(); 610 } 611 612 void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow ) 613 { 614 CreateCaptionFromInitData( rPos ); 615 // no separate drawing undo needed, handled completely inside ScUndoShowHideNote 616 maNoteData.mbShown = bShow; 617 if( maNoteData.mpCaption ) 618 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, bShow ); 619 } 620 621 void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow ) 622 { 623 CreateCaptionFromInitData( rPos ); 624 if( maNoteData.mpCaption ) 625 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, maNoteData.mbShown || bShow ); 626 } 627 628 void ScPostIt::UpdateCaptionPos( const ScAddress& rPos ) 629 { 630 CreateCaptionFromInitData( rPos ); 631 if( maNoteData.mpCaption ) 632 { 633 ScCaptionCreator aCreator( mrDoc, rPos, *maNoteData.mpCaption ); 634 aCreator.UpdateCaptionPos(); 635 } 636 } 637 638 // private -------------------------------------------------------------------- 639 640 void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const 641 { 642 OSL_ENSURE( maNoteData.mpCaption || maNoteData.mxInitData.get(), "ScPostIt::CreateCaptionFromInitData - need caption object or initial caption data" ); 643 if( maNoteData.mxInitData.get() ) 644 { 645 /* This function is called from ScPostIt::Clone() when copying cells 646 to the clipboard/undo document, and when copying cells from the 647 clipboard/undo document. The former should always be called first, 648 so if called in an clipboard/undo document, the caption should have 649 been created already. */ 650 OSL_ENSURE( !mrDoc.IsUndo() && !mrDoc.IsClipboard(), "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" ); 651 652 /* #i104915# Never try to create notes in Undo document, leads to 653 crash due to missing document members (e.g. row height array). */ 654 if( !maNoteData.mpCaption && !mrDoc.IsUndo() ) 655 { 656 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData 657 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); 658 if( maNoteData.mpCaption ) 659 { 660 ScCaptionInitData& rInitData = *maNoteData.mxInitData; 661 662 // transfer ownership of outliner object to caption, or set simple text 663 OSL_ENSURE( rInitData.mxOutlinerObj.get() || (rInitData.maSimpleText.getLength() > 0), 664 "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" ); 665 if( rInitData.mxOutlinerObj.get() ) 666 maNoteData.mpCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() ); 667 else 668 maNoteData.mpCaption->SetText( rInitData.maSimpleText ); 669 670 // copy all items or set default items; reset shadow items 671 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc ); 672 if( rInitData.mxItemSet.get() ) 673 ScCaptionUtil::SetCaptionItems( *maNoteData.mpCaption, *rInitData.mxItemSet ); 674 675 // set position and size of the caption object 676 if( rInitData.mbDefaultPosSize ) 677 { 678 // set other items and fit caption size to text 679 maNoteData.mpCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) ); 680 maNoteData.mpCaption->SetMergedItem( SdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) ); 681 maNoteData.mpCaption->AdjustTextFrameWidthAndHeight(); 682 aCreator.AutoPlaceCaption(); 683 } 684 else 685 { 686 Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true ); 687 bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() ); 688 long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X()); 689 long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y(); 690 Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize ); 691 maNoteData.mpCaption->SetLogicRect( aCaptRect ); 692 aCreator.FitCaptionToRect(); 693 } 694 } 695 } 696 // forget the initial caption data struct 697 maNoteData.mxInitData.reset(); 698 } 699 } 700 701 void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption ) 702 { 703 OSL_ENSURE( !maNoteData.mpCaption, "ScPostIt::CreateCaption - unexpected caption object found" ); 704 maNoteData.mpCaption = 0; 705 706 /* #i104915# Never try to create notes in Undo document, leads to 707 crash due to missing document members (e.g. row height array). */ 708 OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" ); 709 if( mrDoc.IsUndo() ) 710 return; 711 712 // drawing layer may be missing, if a note is copied into a clipboard document 713 if( mrDoc.IsClipboard() ) 714 mrDoc.InitDrawLayer(); 715 716 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData 717 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); 718 if( maNoteData.mpCaption ) 719 { 720 // clone settings of passed caption 721 if( pCaption ) 722 { 723 // copy edit text object (object must be inserted into page already) 724 if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() ) 725 maNoteData.mpCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) ); 726 // copy formatting items (after text has been copied to apply font formatting) 727 maNoteData.mpCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() ); 728 // move textbox position relative to new cell, copy textbox size 729 Rectangle aCaptRect = pCaption->GetLogicRect(); 730 Point aDist = maNoteData.mpCaption->GetTailPos() - pCaption->GetTailPos(); 731 aCaptRect.Move( aDist.X(), aDist.Y() ); 732 maNoteData.mpCaption->SetLogicRect( aCaptRect ); 733 aCreator.FitCaptionToRect(); 734 } 735 else 736 { 737 // set default formatting and default position 738 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc ); 739 aCreator.AutoPlaceCaption(); 740 } 741 742 // create undo action 743 if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() ) 744 if( pDrawLayer->IsRecording() ) 745 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoNewObject( *maNoteData.mpCaption ) ); 746 } 747 } 748 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->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 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 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 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 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 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