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 && pDrawLayer->IsRecording() ) 351 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoGeoObject( *mpCaption ) ); 352 // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly) 353 Rectangle aCaptRect = mpCaption->GetLogicRect(); 354 long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right()); 355 if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth(); 356 long nDiffY = aCaptRect.Top() - rOldTailPos.Y(); 357 aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) ); 358 // set new tail position and caption rectangle 359 mpCaption->SetTailPos( aTailPos ); 360 mpCaption->SetLogicRect( aCaptRect ); 361 // fit caption into draw page 362 FitCaptionToRect( pVisRect ); 363 } 364 365 // update cell position in caption user data 366 ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mpCaption, maPos.Tab() ); 367 if( pCaptData && (maPos != pCaptData->maStart) ) 368 { 369 // create drawing undo action 370 if( pDrawLayer && pDrawLayer->IsRecording() ) 371 pDrawLayer->AddCalcUndo( new ScUndoObjData( mpCaption, pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) ); 372 // set new position 373 pCaptData->maStart = maPos; 374 } 375 } 376 377 Point ScCaptionCreator::CalcTailPos( bool bTailFront ) 378 { 379 // tail position 380 bool bTailLeft = bTailFront != mbNegPage; 381 Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight(); 382 // move caption point 1/10 mm inside cell 383 if( bTailLeft ) aTailPos.X() += 10; else aTailPos.X() -= 10; 384 aTailPos.Y() += 10; 385 return aTailPos; 386 } 387 388 void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront ) 389 { 390 // create the caption drawing object 391 Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) ); 392 Point aTailPos = CalcTailPos( bTailFront ); 393 mpCaption = new SdrCaptionObj( aTextRect, aTailPos ); 394 // basic caption settings 395 ScCaptionUtil::SetBasicCaptionSettings( *mpCaption, bShown ); 396 } 397 398 void ScCaptionCreator::Initialize() 399 { 400 maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true ); 401 mbNegPage = mrDoc.IsNegativePage( maPos.Tab() ); 402 if( SdrPage* pDrawPage = GetDrawPage() ) 403 { 404 maPageRect = Rectangle( Point( 0, 0 ), pDrawPage->GetSize() ); 405 /* #i98141# SdrPage::GetSize() returns negative width in RTL mode. 406 The call to Rectangle::Adjust() orders left/right coordinate 407 accordingly. */ 408 maPageRect.Justify(); 409 } 410 } 411 412 // ============================================================================ 413 414 /** Helper for creation of permanent caption drawing objects for cell notes. */ 415 class ScNoteCaptionCreator : public ScCaptionCreator 416 { 417 public: 418 /** Create a new caption object and inserts it into the document. */ 419 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ); 420 /** Manipulate an existing caption. */ 421 explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ); 422 }; 423 424 // ---------------------------------------------------------------------------- 425 426 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) : 427 ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet 428 { 429 SdrPage* pDrawPage = GetDrawPage(); 430 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" ); 431 if( pDrawPage ) 432 { 433 // create the caption drawing object 434 CreateCaption( rNoteData.mbShown, false ); 435 rNoteData.mpCaption = GetCaption(); 436 OSL_ENSURE( rNoteData.mpCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" ); 437 if( rNoteData.mpCaption ) 438 { 439 // store note position in user data of caption object 440 ScCaptionUtil::SetCaptionUserData( *rNoteData.mpCaption, rPos ); 441 // insert object into draw page 442 pDrawPage->InsertObject( rNoteData.mpCaption ); 443 } 444 } 445 } 446 447 ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ) : 448 ScCaptionCreator( rDoc, rPos, rCaption ) 449 { 450 SdrPage* pDrawPage = GetDrawPage(); 451 OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" ); 452 OSL_ENSURE( rCaption.GetPage() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" ); 453 if( pDrawPage && (rCaption.GetPage() == pDrawPage) ) 454 { 455 // store note position in user data of caption object 456 ScCaptionUtil::SetCaptionUserData( rCaption, rPos ); 457 // basic caption settings 458 ScCaptionUtil::SetBasicCaptionSettings( rCaption, bShown ); 459 // set correct tail position 460 rCaption.SetTailPos( CalcTailPos( false ) ); 461 } 462 } 463 464 } // namespace 465 466 // ============================================================================ 467 468 struct ScCaptionInitData 469 { 470 typedef ::std::auto_ptr< SfxItemSet > SfxItemSetPtr; 471 typedef ::std::auto_ptr< OutlinerParaObject > OutlinerParaObjPtr; 472 473 SfxItemSetPtr mxItemSet; /// Caption object formatting. 474 OutlinerParaObjPtr mxOutlinerObj; /// Text object with all text portion formatting. 475 ::rtl::OUString maSimpleText; /// Simple text without formatting. 476 Point maCaptionOffset; /// Caption position relative to cell corner. 477 Size maCaptionSize; /// Size of the caption object. 478 bool mbDefaultPosSize; /// True = use default position and size for caption. 479 480 explicit ScCaptionInitData(); 481 }; 482 483 // ---------------------------------------------------------------------------- 484 485 ScCaptionInitData::ScCaptionInitData() : 486 mbDefaultPosSize( true ) 487 { 488 } 489 490 // ============================================================================ 491 492 ScNoteData::ScNoteData( bool bShown ) : 493 mpCaption( 0 ), 494 mbShown( bShown ) 495 { 496 } 497 498 ScNoteData::~ScNoteData() 499 { 500 } 501 502 // ============================================================================ 503 504 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, bool bShown ) : 505 mrDoc( rDoc ), 506 maNoteData( bShown ) 507 { 508 AutoStamp(); 509 CreateCaption( rPos ); 510 } 511 512 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote ) : 513 mrDoc( rDoc ), 514 maNoteData( rNote.maNoteData ) 515 { 516 maNoteData.mpCaption = 0; 517 CreateCaption( rPos, rNote.maNoteData.mpCaption ); 518 } 519 520 ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption ) : 521 mrDoc( rDoc ), 522 maNoteData( rNoteData ) 523 { 524 if( bAlwaysCreateCaption || maNoteData.mbShown ) 525 CreateCaptionFromInitData( rPos ); 526 } 527 528 ScPostIt::~ScPostIt() 529 { 530 RemoveCaption(); 531 } 532 533 ScPostIt* ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const 534 { 535 CreateCaptionFromInitData( rOwnPos ); 536 return bCloneCaption ? new ScPostIt( rDestDoc, rDestPos, *this ) : new ScPostIt( rDestDoc, rDestPos, maNoteData, false ); 537 } 538 539 void ScPostIt::AutoStamp() 540 { 541 maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() ); 542 maNoteData.maAuthor = SvtUserOptions().GetID(); 543 } 544 545 const OutlinerParaObject* ScPostIt::GetOutlinerObject() const 546 { 547 if( maNoteData.mpCaption ) 548 return maNoteData.mpCaption->GetOutlinerParaObject(); 549 if( maNoteData.mxInitData.get() ) 550 return maNoteData.mxInitData->mxOutlinerObj.get(); 551 return 0; 552 } 553 554 const EditTextObject* ScPostIt::GetEditTextObject() const 555 { 556 const OutlinerParaObject* pOPO = GetOutlinerObject(); 557 return pOPO ? &pOPO->GetTextObject() : 0; 558 } 559 560 OUString ScPostIt::GetText() const 561 { 562 if( const EditTextObject* pEditObj = GetEditTextObject() ) 563 { 564 OUStringBuffer aBuffer; 565 for( sal_uInt16 nPara = 0, nParaCount = pEditObj->GetParagraphCount(); nPara < nParaCount; ++nPara ) 566 { 567 if( nPara > 0 ) 568 aBuffer.append( sal_Unicode( '\n' ) ); 569 aBuffer.append( pEditObj->GetText( nPara ) ); 570 } 571 return aBuffer.makeStringAndClear(); 572 } 573 if( maNoteData.mxInitData.get() ) 574 return maNoteData.mxInitData->maSimpleText; 575 return OUString(); 576 } 577 578 bool ScPostIt::HasMultiLineText() const 579 { 580 if( const EditTextObject* pEditObj = GetEditTextObject() ) 581 return pEditObj->GetParagraphCount() > 1; 582 if( maNoteData.mxInitData.get() ) 583 return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0; 584 return false; 585 } 586 587 void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText ) 588 { 589 CreateCaptionFromInitData( rPos ); 590 if( maNoteData.mpCaption ) 591 maNoteData.mpCaption->SetText( rText ); 592 } 593 594 SdrCaptionObj* ScPostIt::GetOrCreateCaption( const ScAddress& rPos ) const 595 { 596 CreateCaptionFromInitData( rPos ); 597 return maNoteData.mpCaption; 598 } 599 600 void ScPostIt::ForgetCaption() 601 { 602 /* This function is used in undo actions to give up the responsibility for 603 the caption object which is handled by separate drawing undo actions. */ 604 maNoteData.mpCaption = 0; 605 maNoteData.mxInitData.reset(); 606 } 607 608 void ScPostIt::ShowCaption( const ScAddress& rPos, bool bShow ) 609 { 610 CreateCaptionFromInitData( rPos ); 611 // no separate drawing undo needed, handled completely inside ScUndoShowHideNote 612 maNoteData.mbShown = bShow; 613 if( maNoteData.mpCaption ) 614 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, bShow ); 615 } 616 617 void ScPostIt::ShowCaptionTemp( const ScAddress& rPos, bool bShow ) 618 { 619 CreateCaptionFromInitData( rPos ); 620 if( maNoteData.mpCaption ) 621 ScCaptionUtil::SetCaptionLayer( *maNoteData.mpCaption, maNoteData.mbShown || bShow ); 622 } 623 624 void ScPostIt::UpdateCaptionPos( const ScAddress& rPos ) 625 { 626 CreateCaptionFromInitData( rPos ); 627 if( maNoteData.mpCaption ) 628 { 629 ScCaptionCreator aCreator( mrDoc, rPos, *maNoteData.mpCaption ); 630 aCreator.UpdateCaptionPos(); 631 } 632 } 633 634 // private -------------------------------------------------------------------- 635 636 void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const 637 { 638 OSL_ENSURE( maNoteData.mpCaption || maNoteData.mxInitData.get(), "ScPostIt::CreateCaptionFromInitData - need caption object or initial caption data" ); 639 if( maNoteData.mxInitData.get() ) 640 { 641 /* This function is called from ScPostIt::Clone() when copying cells 642 to the clipboard/undo document, and when copying cells from the 643 clipboard/undo document. The former should always be called first, 644 so if called in an clipboard/undo document, the caption should have 645 been created already. */ 646 OSL_ENSURE( !mrDoc.IsUndo() && !mrDoc.IsClipboard(), "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" ); 647 648 /* #i104915# Never try to create notes in Undo document, leads to 649 crash due to missing document members (e.g. row height array). */ 650 if( !maNoteData.mpCaption && !mrDoc.IsUndo() ) 651 { 652 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData 653 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); 654 if( maNoteData.mpCaption ) 655 { 656 ScCaptionInitData& rInitData = *maNoteData.mxInitData; 657 658 // transfer ownership of outliner object to caption, or set simple text 659 OSL_ENSURE( rInitData.mxOutlinerObj.get() || (rInitData.maSimpleText.getLength() > 0), 660 "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" ); 661 if( rInitData.mxOutlinerObj.get() ) 662 maNoteData.mpCaption->SetOutlinerParaObject( rInitData.mxOutlinerObj.release() ); 663 else 664 maNoteData.mpCaption->SetText( rInitData.maSimpleText ); 665 666 // copy all items or set default items; reset shadow items 667 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc ); 668 if( rInitData.mxItemSet.get() ) 669 ScCaptionUtil::SetCaptionItems( *maNoteData.mpCaption, *rInitData.mxItemSet ); 670 671 // set position and size of the caption object 672 if( rInitData.mbDefaultPosSize ) 673 { 674 // set other items and fit caption size to text 675 maNoteData.mpCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) ); 676 maNoteData.mpCaption->SetMergedItem( SdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) ); 677 maNoteData.mpCaption->AdjustTextFrameWidthAndHeight(); 678 aCreator.AutoPlaceCaption(); 679 } 680 else 681 { 682 Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true ); 683 bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() ); 684 long nPosX = bNegPage ? (aCellRect.Left() - rInitData.maCaptionOffset.X()) : (aCellRect.Right() + rInitData.maCaptionOffset.X()); 685 long nPosY = aCellRect.Top() + rInitData.maCaptionOffset.Y(); 686 Rectangle aCaptRect( Point( nPosX, nPosY ), rInitData.maCaptionSize ); 687 maNoteData.mpCaption->SetLogicRect( aCaptRect ); 688 aCreator.FitCaptionToRect(); 689 } 690 } 691 } 692 // forget the initial caption data struct 693 maNoteData.mxInitData.reset(); 694 } 695 } 696 697 void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption ) 698 { 699 OSL_ENSURE( !maNoteData.mpCaption, "ScPostIt::CreateCaption - unexpected caption object found" ); 700 maNoteData.mpCaption = 0; 701 702 /* #i104915# Never try to create notes in Undo document, leads to 703 crash due to missing document members (e.g. row height array). */ 704 OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" ); 705 if( mrDoc.IsUndo() ) 706 return; 707 708 // drawing layer may be missing, if a note is copied into a clipboard document 709 if( mrDoc.IsClipboard() ) 710 mrDoc.InitDrawLayer(); 711 712 // ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData 713 ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); 714 if( maNoteData.mpCaption ) 715 { 716 // clone settings of passed caption 717 if( pCaption ) 718 { 719 // copy edit text object (object must be inserted into page already) 720 if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() ) 721 maNoteData.mpCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) ); 722 // copy formatting items (after text has been copied to apply font formatting) 723 maNoteData.mpCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() ); 724 // move textbox position relative to new cell, copy textbox size 725 Rectangle aCaptRect = pCaption->GetLogicRect(); 726 Point aDist = maNoteData.mpCaption->GetTailPos() - pCaption->GetTailPos(); 727 aCaptRect.Move( aDist.X(), aDist.Y() ); 728 maNoteData.mpCaption->SetLogicRect( aCaptRect ); 729 aCreator.FitCaptionToRect(); 730 } 731 else 732 { 733 // set default formatting and default position 734 ScCaptionUtil::SetDefaultItems( *maNoteData.mpCaption, mrDoc ); 735 aCreator.AutoPlaceCaption(); 736 } 737 738 // create undo action 739 if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() ) 740 if( pDrawLayer->IsRecording() ) 741 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoNewObject( *maNoteData.mpCaption ) ); 742 } 743 } 744 745 void ScPostIt::RemoveCaption() 746 { 747 748 /* Remove caption object only, if this note is its owner (e.g. notes in 749 undo documents refer to captions in original document, do not remove 750 them from drawing layer here). */ 751 ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer(); 752 if( maNoteData.mpCaption && (pDrawLayer == maNoteData.mpCaption->GetModel()) ) 753 { 754 OSL_ENSURE( pDrawLayer, "ScPostIt::RemoveCaption - object without drawing layer" ); 755 SdrPage* pDrawPage = maNoteData.mpCaption->GetPage(); 756 OSL_ENSURE( pDrawPage, "ScPostIt::RemoveCaption - object without drawing page" ); 757 if( pDrawPage ) 758 { 759 pDrawPage->RecalcObjOrdNums(); 760 // create drawing undo action (before removing the object to have valid draw page in undo action) 761 bool bRecording = ( pDrawLayer && pDrawLayer->IsRecording() ); 762 if( bRecording ) 763 pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoDeleteObject( *maNoteData.mpCaption ) ); 764 // remove the object from the drawing page, delete if undo is disabled 765 SdrObject* pObj = pDrawPage->RemoveObject( maNoteData.mpCaption->GetOrdNum() ); 766 if( !bRecording ) 767 SdrObject::Free( pObj ); 768 } 769 } 770 maNoteData.mpCaption = 0; 771 } 772 773 // ============================================================================ 774 775 void ScNoteUtil::UpdateCaptionPositions( ScDocument& rDoc, const ScRange& rRange ) 776 { 777 // do not use ScCellIterator, it skips filtered and subtotal cells 778 for( ScAddress aPos( rRange.aStart ); aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab() ) 779 for( aPos.SetCol( rRange.aStart.Col() ); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol() ) 780 for( aPos.SetRow( rRange.aStart.Row() ); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow() ) 781 if( ScPostIt* pNote = rDoc.GetNote( aPos ) ) 782 pNote->UpdateCaptionPos( aPos ); 783 } 784 785 SdrCaptionObj* ScNoteUtil::CreateTempCaption( 786 ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage, 787 const OUString& rUserText, const Rectangle& rVisRect, bool bTailFront ) 788 { 789 OUStringBuffer aBuffer( rUserText ); 790 // add plain text of invisible (!) cell note (no formatting etc.) 791 SdrCaptionObj* pNoteCaption = 0; 792 const ScPostIt* pNote = rDoc.GetNote( rPos ); 793 if( pNote && !pNote->IsCaptionShown() ) 794 { 795 if( aBuffer.getLength() > 0 ) 796 aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\n--------\n" ) ).append( pNote->GetText() ); 797 pNoteCaption = pNote->GetOrCreateCaption( rPos ); 798 } 799 800 // create a caption if any text exists 801 if( !pNoteCaption && (aBuffer.getLength() == 0) ) 802 return 0; 803 804 // prepare visible rectangle (add default distance to all borders) 805 Rectangle aVisRect( 806 rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP, 807 rVisRect.Top() + SC_NOTECAPTION_BORDERDIST_TEMP, 808 rVisRect.Right() - SC_NOTECAPTION_BORDERDIST_TEMP, 809 rVisRect.Bottom() - SC_NOTECAPTION_BORDERDIST_TEMP ); 810 811 // create the caption object 812 ScCaptionCreator aCreator( rDoc, rPos, true, bTailFront ); 813 SdrCaptionObj* pCaption = aCreator.GetCaption(); 814 815 // insert caption into page (needed to set caption text) 816 rDrawPage.InsertObject( pCaption ); 817 818 // clone the edit text object, unless user text is present, then set this text 819 if( pNoteCaption && (rUserText.getLength() == 0) ) 820 { 821 if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() ) 822 pCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) ); 823 // set formatting (must be done after setting text) and resize the box to fit the text 824 pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() ); 825 Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() ); 826 pCaption->SetLogicRect( aCaptRect ); 827 } 828 else 829 { 830 // if pNoteCaption is null, then aBuffer contains some text 831 pCaption->SetText( aBuffer.makeStringAndClear() ); 832 ScCaptionUtil::SetDefaultItems( *pCaption, rDoc ); 833 // adjust caption size to text size 834 long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP ); 835 pCaption->SetMergedItem( SdrTextAutoGrowWidthItem( sal_True ) ); 836 pCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) ); 837 pCaption->SetMergedItem( SdrTextMaxFrameWidthItem( nMaxWidth ) ); 838 pCaption->SetMergedItem( SdrTextAutoGrowHeightItem( sal_True ) ); 839 pCaption->AdjustTextFrameWidthAndHeight(); 840 } 841 842 // move caption into visible area 843 aCreator.AutoPlaceCaption( &aVisRect ); 844 return pCaption; 845 } 846 847 ScPostIt* ScNoteUtil::CreateNoteFromCaption( 848 ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption, bool bShown ) 849 { 850 ScNoteData aNoteData( bShown ); 851 aNoteData.mpCaption = &rCaption; 852 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false ); 853 pNote->AutoStamp(); 854 rDoc.TakeNote( rPos, pNote ); 855 // if pNote still points to the note after TakeNote(), insertion was successful 856 if( pNote ) 857 { 858 // ScNoteCaptionCreator c'tor updates the caption object to be part of a note 859 ScNoteCaptionCreator aCreator( rDoc, rPos, rCaption, bShown ); 860 } 861 return pNote; 862 } 863 864 ScPostIt* ScNoteUtil::CreateNoteFromObjectData( 865 ScDocument& rDoc, const ScAddress& rPos, SfxItemSet* pItemSet, 866 OutlinerParaObject* pOutlinerObj, const Rectangle& rCaptionRect, 867 bool bShown, bool bAlwaysCreateCaption ) 868 { 869 OSL_ENSURE( pItemSet && pOutlinerObj, "ScNoteUtil::CreateNoteFromObjectData - item set and outliner object expected" ); 870 ScNoteData aNoteData( bShown ); 871 aNoteData.mxInitData.reset( new ScCaptionInitData ); 872 ScCaptionInitData& rInitData = *aNoteData.mxInitData; 873 rInitData.mxItemSet.reset( pItemSet ); 874 rInitData.mxOutlinerObj.reset( pOutlinerObj ); 875 876 // convert absolute caption position to relative position 877 rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty(); 878 if( !rInitData.mbDefaultPosSize ) 879 { 880 Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, rPos, true ); 881 bool bNegPage = rDoc.IsNegativePage( rPos.Tab() ); 882 rInitData.maCaptionOffset.X() = bNegPage ? (aCellRect.Left() - rCaptionRect.Right()) : (rCaptionRect.Left() - aCellRect.Right()); 883 rInitData.maCaptionOffset.Y() = rCaptionRect.Top() - aCellRect.Top(); 884 rInitData.maCaptionSize = rCaptionRect.GetSize(); 885 } 886 887 /* Create the note and insert it into the document. If the note is 888 visible, the caption object will be created automatically. */ 889 ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption ); 890 pNote->AutoStamp(); 891 rDoc.TakeNote( rPos, pNote ); 892 // if pNote still points to the note after TakeNote(), insertion was successful 893 return pNote; 894 } 895 896 ScPostIt* ScNoteUtil::CreateNoteFromString( 897 ScDocument& rDoc, const ScAddress& rPos, const OUString& rNoteText, 898 bool bShown, bool bAlwaysCreateCaption ) 899 { 900 ScPostIt* pNote = 0; 901 if( rNoteText.getLength() > 0 ) 902 { 903 ScNoteData aNoteData( bShown ); 904 aNoteData.mxInitData.reset( new ScCaptionInitData ); 905 ScCaptionInitData& rInitData = *aNoteData.mxInitData; 906 rInitData.maSimpleText = rNoteText; 907 rInitData.mbDefaultPosSize = true; 908 909 /* Create the note and insert it into the document. If the note is 910 visible, the caption object will be created automatically. */ 911 pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption ); 912 pNote->AutoStamp(); 913 rDoc.TakeNote( rPos, pNote ); 914 // if pNote still points to the note after TakeNote(), insertion was successful 915 } 916 return pNote; 917 } 918 919 // ============================================================================ 920