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 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 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 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 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 item's 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 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 obejct. */ 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. */ 203 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 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 225 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ) : 226 mrDoc( rDoc ), 227 maPos( rPos ), 228 mpCaption( &rCaption ) 229 { 230 Initialize(); 231 } 232 233 ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos ) : 234 mrDoc( rDoc ), 235 maPos( rPos ), 236 mpCaption( 0 ) 237 { 238 Initialize(); 239 } 240 241 SdrPage* ScCaptionCreator::GetDrawPage() 242 { 243 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer(); 244 return pDrawLayer ? pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) : 0; 245 } 246 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 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 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 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 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 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 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 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 488 ScCaptionInitData::ScCaptionInitData() : 489 mbDefaultPosSize( true ) 490 { 491 } 492 493 // ============================================================================ 494 495 ScNoteData::ScNoteData( bool bShown ) : 496 mpCaption( 0 ), 497 mbShown( bShown ) 498 { 499 } 500 501 ScNoteData::~ScNoteData() 502 { 503 } 504 505 // ============================================================================ 506 507 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, bool bShown ) : 508 mrDoc( rDoc ), 509 maNoteData( bShown ) 510 { 511 AutoStamp(); 512 CreateCaption( rPos ); 513 } 514 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 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 531 ScPostIt::~ScPostIt() 532 { 533 RemoveCaption(); 534 } 535 536 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 542 void ScPostIt::AutoStamp() 543 { 544 maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() ); 545 maNoteData.maAuthor = SvtUserOptions().GetID(); 546 } 547 548 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 557 const EditTextObject* ScPostIt::GetEditTextObject() const 558 { 559 const OutlinerParaObject* pOPO = GetOutlinerObject(); 560 return pOPO ? &pOPO->GetTextObject() : 0; 561 } 562 563 OUString ScPostIt::GetText() const 564 { 565 if( const EditTextObject* pEditObj = GetEditTextObject() ) 566 { 567 OUStringBuffer aBuffer; 568 for( sal_uInt16 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 581 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 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 597 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const 598 { 599 CreateCaptionFromInitData( rPos ); 600 return maNoteData.mpCaption; 601 } 602 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 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 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 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 639 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 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 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 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