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_editeng.hxx" 30 31 #include <svl/intitem.hxx> 32 #include <editeng/editeng.hxx> 33 #include <editeng/editview.hxx> 34 #include <editeng/editdata.hxx> 35 #include <editeng/eerdll.hxx> 36 #include <editeng/lrspitem.hxx> 37 #include <editeng/fhgtitem.hxx> 38 39 #include <math.h> 40 #include <svl/style.hxx> 41 #include <vcl/wrkwin.hxx> 42 #define _OUTLINER_CXX 43 #include <editeng/outliner.hxx> 44 #include <paralist.hxx> 45 #include <editeng/outlobj.hxx> 46 #include <outleeng.hxx> 47 #include <outlundo.hxx> 48 #include <editeng/eeitem.hxx> 49 #include <editeng/editstat.hxx> 50 #include <editeng/scripttypeitem.hxx> 51 #include <editeng/editobj.hxx> 52 #include <svl/itemset.hxx> 53 #include <svl/whiter.hxx> 54 #include <vcl/metric.hxx> 55 #include <editeng/numitem.hxx> 56 #include <editeng/adjitem.hxx> 57 #include <vcl/graph.hxx> 58 #include <vcl/gdimtf.hxx> 59 #include <vcl/metaact.hxx> 60 #include <svtools/grfmgr.hxx> 61 #include <editeng/svxfont.hxx> 62 #include <editeng/brshitem.hxx> 63 #include <svl/itempool.hxx> 64 65 // #101498# calculate if it's RTL or not 66 #include <unicode/ubidi.h> 67 68 #define DEFAULT_SCALE 75 69 70 static const sal_uInt16 nDefStyles = 3; // Sonderbehandlung fuer die ersten 3 Ebenen 71 static const sal_uInt16 nDefBulletIndent = 800; 72 static const sal_uInt16 nDefBulletWidth = 700; 73 static const sal_uInt16 pDefBulletIndents[nDefStyles]= { 1400, 800, 800 }; 74 static const sal_uInt16 pDefBulletWidths[nDefStyles] = { 1000, 850, 700 }; 75 76 sal_uInt16 lcl_ImplGetDefBulletWidth( sal_Int16 nDepth ) 77 { 78 return ( nDepth < nDefStyles ) ? pDefBulletWidths[nDepth] : nDefBulletWidth; 79 } 80 81 sal_uInt16 lcl_ImplGetDefBulletIndent( sal_Int16 nDepth ) 82 { 83 sal_uInt16 nI = 0; 84 85 if( nDepth >= 0 ) 86 { 87 for ( sal_Int16 n = 0; n <= nDepth; n++ ) 88 nI = nI + 89 ( ( n < nDefStyles ) ? pDefBulletIndents[n] : nDefBulletIndent ); 90 } 91 return nI; 92 } 93 94 95 // ---------------------------------------------------------------------- 96 // Outliner 97 // ---------------------------------------------------------------------- 98 DBG_NAME(Outliner); 99 100 void Outliner::ImplCheckDepth( sal_Int16& rnDepth ) const 101 { 102 if( rnDepth < nMinDepth ) 103 rnDepth = nMinDepth; 104 else if( rnDepth > nMaxDepth ) 105 rnDepth = nMaxDepth; 106 } 107 108 Paragraph* Outliner::Insert(const XubString& rText, sal_uLong nAbsPos, sal_Int16 nDepth) 109 { 110 DBG_CHKTHIS(Outliner,0); 111 DBG_ASSERT(pParaList->GetParagraphCount(),"Insert:No Paras"); 112 113 Paragraph* pPara; 114 115 ImplCheckDepth( nDepth ); 116 117 sal_uLong nParagraphCount = pParaList->GetParagraphCount(); 118 if( nAbsPos > nParagraphCount ) 119 nAbsPos = nParagraphCount; 120 121 if( bFirstParaIsEmpty ) 122 { 123 pPara = pParaList->GetParagraph( 0 ); 124 if( pPara->GetDepth() != nDepth ) 125 { 126 nDepthChangedHdlPrevDepth = pPara->GetDepth(); 127 mnDepthChangeHdlPrevFlags = pPara->nFlags; 128 pPara->SetDepth( nDepth ); 129 pHdlParagraph = pPara; 130 DepthChangedHdl(); 131 } 132 pPara->nFlags |= PARAFLAG_HOLDDEPTH; 133 SetText( rText, pPara ); 134 } 135 else 136 { 137 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 138 pEditEngine->SetUpdateMode( sal_False ); 139 ImplBlockInsertionCallbacks( sal_True ); 140 pPara = new Paragraph( nDepth ); 141 pParaList->Insert( pPara, nAbsPos ); 142 pEditEngine->InsertParagraph( (sal_uInt16)nAbsPos, String() ); 143 DBG_ASSERT(pPara==pParaList->GetParagraph(nAbsPos),"Insert:Failed"); 144 ImplInitDepth( (sal_uInt16)nAbsPos, nDepth, sal_False ); 145 pHdlParagraph = pPara; 146 ParagraphInsertedHdl(); 147 pPara->nFlags |= PARAFLAG_HOLDDEPTH; 148 SetText( rText, pPara ); 149 ImplBlockInsertionCallbacks( sal_False ); 150 pEditEngine->SetUpdateMode( bUpdate ); 151 } 152 bFirstParaIsEmpty = sal_False; 153 DBG_ASSERT(pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(),"SetText failed"); 154 return pPara; 155 } 156 157 158 void Outliner::ParagraphInserted( sal_uInt16 nPara ) 159 { 160 DBG_CHKTHIS(Outliner,0); 161 162 if ( bBlockInsCallback ) 163 return; 164 165 if( bPasting || pEditEngine->IsInUndo() ) 166 { 167 Paragraph* pPara = new Paragraph( -1 ); 168 pParaList->Insert( pPara, nPara ); 169 if( pEditEngine->IsInUndo() ) 170 { 171 pPara->nFlags = PARAFLAG_SETBULLETTEXT; 172 pPara->bVisible = sal_True; 173 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); 174 pPara->SetDepth( rLevel.GetValue() ); 175 } 176 } 177 else 178 { 179 sal_Int16 nDepth = -1; 180 Paragraph* pParaBefore = pParaList->GetParagraph( nPara-1 ); 181 if ( pParaBefore ) 182 nDepth = pParaBefore->GetDepth(); 183 184 Paragraph* pPara = new Paragraph( nDepth ); 185 pParaList->Insert( pPara, nPara ); 186 187 if( !pEditEngine->IsInUndo() ) 188 { 189 ImplCalcBulletText( nPara, sal_True, sal_False ); 190 pHdlParagraph = pPara; 191 ParagraphInsertedHdl(); 192 } 193 } 194 } 195 196 void Outliner::ParagraphDeleted( sal_uInt16 nPara ) 197 { 198 DBG_CHKTHIS(Outliner,0); 199 200 if ( bBlockInsCallback || ( nPara == EE_PARA_ALL ) ) 201 return; 202 203 Paragraph* pPara = pParaList->GetParagraph( nPara ); 204 if (!pPara) 205 return; 206 207 sal_Int16 nDepth = pPara->GetDepth(); 208 209 if( !pEditEngine->IsInUndo() ) 210 { 211 pHdlParagraph = pPara; 212 ParagraphRemovingHdl(); 213 } 214 215 pParaList->Remove( nPara ); 216 delete pPara; 217 218 if( !pEditEngine->IsInUndo() && !bPasting ) 219 { 220 pPara = pParaList->GetParagraph( nPara ); 221 if ( pPara && ( pPara->GetDepth() > nDepth ) ) 222 { 223 ImplCalcBulletText( nPara, sal_True, sal_False ); 224 // naechsten auf gleicher Ebene suchen... 225 while ( pPara && pPara->GetDepth() > nDepth ) 226 pPara = pParaList->GetParagraph( ++nPara ); 227 } 228 229 if ( pPara && ( pPara->GetDepth() == nDepth ) ) 230 ImplCalcBulletText( nPara, sal_True, sal_False ); 231 } 232 } 233 234 void Outliner::Init( sal_uInt16 nMode ) 235 { 236 nOutlinerMode = nMode; 237 238 Clear(); 239 240 sal_uLong nCtrl = pEditEngine->GetControlWord(); 241 nCtrl &= ~(EE_CNTRL_OUTLINER|EE_CNTRL_OUTLINER2); 242 243 SetMaxDepth( 9 ); 244 245 switch ( ImplGetOutlinerMode() ) 246 { 247 case OUTLINERMODE_TEXTOBJECT: 248 case OUTLINERMODE_TITLEOBJECT: 249 break; 250 251 case OUTLINERMODE_OUTLINEOBJECT: 252 nCtrl |= EE_CNTRL_OUTLINER2; 253 break; 254 case OUTLINERMODE_OUTLINEVIEW: 255 nCtrl |= EE_CNTRL_OUTLINER; 256 break; 257 258 default: DBG_ERROR( "Outliner::Init - Invalid Mode!" ); 259 } 260 261 pEditEngine->SetControlWord( nCtrl ); 262 263 ImplInitDepth( 0, GetMinDepth(), sal_False ); 264 265 GetUndoManager().Clear(); 266 } 267 268 void Outliner::SetMaxDepth( sal_Int16 nDepth, sal_Bool bCheckParagraphs ) 269 { 270 if( nMaxDepth != nDepth ) 271 { 272 nMaxDepth = Min( nDepth, (sal_Int16)(SVX_MAX_NUM-1) ); 273 274 if( bCheckParagraphs ) 275 { 276 sal_uInt16 nParagraphs = (sal_uInt16)pParaList->GetParagraphCount(); 277 for ( sal_uInt16 nPara = 0; nPara < nParagraphs; nPara++ ) 278 { 279 Paragraph* pPara = pParaList->GetParagraph( nPara ); 280 if( pPara && pPara->GetDepth() > nMaxDepth ) 281 { 282 SetDepth( pPara, nMaxDepth ); 283 } 284 } 285 } 286 } 287 } 288 289 sal_Int16 Outliner::GetDepth( sal_uLong nPara ) const 290 { 291 Paragraph* pPara = pParaList->GetParagraph( nPara ); 292 DBG_ASSERT( pPara, "Outliner::GetDepth - Paragraph not found!" ); 293 return pPara ? pPara->GetDepth() : -1; 294 } 295 296 void Outliner::SetDepth( Paragraph* pPara, sal_Int16 nNewDepth ) 297 { 298 DBG_CHKTHIS(Outliner,0); 299 300 ImplCheckDepth( nNewDepth ); 301 302 if ( nNewDepth != pPara->GetDepth() ) 303 { 304 nDepthChangedHdlPrevDepth = pPara->GetDepth(); 305 mnDepthChangeHdlPrevFlags = pPara->nFlags; 306 pHdlParagraph = pPara; 307 308 sal_uInt16 nPara = (sal_uInt16)GetAbsPos( pPara ); 309 ImplInitDepth( nPara, nNewDepth, sal_True ); 310 ImplCalcBulletText( nPara, sal_False, sal_False ); 311 312 if ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) 313 ImplSetLevelDependendStyleSheet( nPara ); 314 315 DepthChangedHdl(); 316 } 317 } 318 319 sal_Int16 Outliner::GetNumberingStartValue( sal_uInt16 nPara ) 320 { 321 Paragraph* pPara = pParaList->GetParagraph( nPara ); 322 DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" ); 323 return pPara ? pPara->GetNumberingStartValue() : -1; 324 } 325 326 void Outliner::SetNumberingStartValue( sal_uInt16 nPara, sal_Int16 nNumberingStartValue ) 327 { 328 Paragraph* pPara = pParaList->GetParagraph( nPara ); 329 DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" ); 330 if( pPara && pPara->GetNumberingStartValue() != nNumberingStartValue ) 331 { 332 if( IsUndoEnabled() && !IsInUndo() ) 333 InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara, 334 pPara->GetNumberingStartValue(), nNumberingStartValue, 335 pPara->IsParaIsNumberingRestart(), pPara->IsParaIsNumberingRestart() ) ); 336 337 pPara->SetNumberingStartValue( nNumberingStartValue ); 338 // --> OD 2009-03-10 #i100014# 339 // It is not a good idea to substract 1 from a count and cast the result 340 // to sal_uInt16 without check, if the count is 0. 341 ImplCheckParagraphs( nPara, (sal_uInt16) (pParaList->GetParagraphCount()) ); 342 // <-- 343 pEditEngine->SetModified(); 344 } 345 } 346 347 sal_Bool Outliner::IsParaIsNumberingRestart( sal_uInt16 nPara ) 348 { 349 Paragraph* pPara = pParaList->GetParagraph( nPara ); 350 DBG_ASSERT( pPara, "Outliner::IsParaIsNumberingRestart - Paragraph not found!" ); 351 return pPara ? pPara->IsParaIsNumberingRestart() : sal_False; 352 } 353 354 void Outliner::SetParaIsNumberingRestart( sal_uInt16 nPara, sal_Bool bParaIsNumberingRestart ) 355 { 356 Paragraph* pPara = pParaList->GetParagraph( nPara ); 357 DBG_ASSERT( pPara, "Outliner::SetParaIsNumberingRestart - Paragraph not found!" ); 358 if( pPara && (pPara->IsParaIsNumberingRestart() != bParaIsNumberingRestart) ) 359 { 360 if( IsUndoEnabled() && !IsInUndo() ) 361 InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara, 362 pPara->GetNumberingStartValue(), pPara->GetNumberingStartValue(), 363 pPara->IsParaIsNumberingRestart(), bParaIsNumberingRestart ) ); 364 365 pPara->SetParaIsNumberingRestart( bParaIsNumberingRestart ); 366 // --> OD 2009-03-10 #i100014# 367 // It is not a good idea to substract 1 from a count and cast the result 368 // to sal_uInt16 without check, if the count is 0. 369 ImplCheckParagraphs( nPara, (sal_uInt16) (pParaList->GetParagraphCount()) ); 370 // <-- 371 pEditEngine->SetModified(); 372 } 373 } 374 375 OutlinerParaObject* Outliner::CreateParaObject( sal_uInt16 nStartPara, sal_uInt16 nCount ) const 376 { 377 DBG_CHKTHIS(Outliner,0); 378 379 if ( sal::static_int_cast< sal_uLong >( nStartPara + nCount ) > 380 pParaList->GetParagraphCount() ) 381 nCount = sal::static_int_cast< sal_uInt16 >( 382 pParaList->GetParagraphCount() - nStartPara ); 383 384 // When a new OutlinerParaObject is created because a paragraph is just beeing deleted, 385 // it can happen that the ParaList is not updated yet... 386 if ( ( nStartPara + nCount ) > pEditEngine->GetParagraphCount() ) 387 nCount = pEditEngine->GetParagraphCount() - nStartPara; 388 389 if( !nCount ) 390 return NULL; 391 392 EditTextObject* pText = pEditEngine->CreateTextObject( nStartPara, nCount ); 393 const bool bIsEditDoc(OUTLINERMODE_TEXTOBJECT == ImplGetOutlinerMode()); 394 ParagraphDataVector aParagraphDataVector(nCount); 395 const sal_uInt16 nLastPara(nStartPara + nCount - 1); 396 397 for(sal_uInt16 nPara(nStartPara); nPara <= nLastPara; nPara++) 398 { 399 aParagraphDataVector[nPara-nStartPara] = *GetParagraph(nPara); 400 } 401 402 OutlinerParaObject* pPObj = new OutlinerParaObject(*pText, aParagraphDataVector, bIsEditDoc); 403 pPObj->SetOutlinerMode(GetMode()); 404 delete pText; 405 406 return pPObj; 407 } 408 409 void Outliner::SetText( const XubString& rText, Paragraph* pPara ) 410 { 411 DBG_CHKTHIS(Outliner,0); 412 DBG_ASSERT(pPara,"SetText:No Para"); 413 414 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 415 pEditEngine->SetUpdateMode( sal_False ); 416 ImplBlockInsertionCallbacks( sal_True ); 417 418 sal_uInt16 nPara = (sal_uInt16)pParaList->GetAbsPos( pPara ); 419 420 if( !rText.Len() ) 421 { 422 pEditEngine->SetText( nPara, rText ); 423 ImplInitDepth( nPara, pPara->GetDepth(), sal_False ); 424 } 425 else 426 { 427 XubString aText( rText ); 428 aText.ConvertLineEnd( LINEEND_LF ); 429 430 if( aText.GetChar( aText.Len()-1 ) == '\x0A' ) 431 aText.Erase( aText.Len()-1, 1 ); // letzten Umbruch loeschen 432 433 sal_uInt16 nCount = aText.GetTokenCount( '\x0A' ); 434 sal_uInt16 nPos = 0; 435 sal_uInt16 nInsPos = nPara+1; 436 while( nCount > nPos ) 437 { 438 XubString aStr = aText.GetToken( nPos, '\x0A' ); 439 440 sal_Int16 nCurDepth; 441 if( nPos ) 442 { 443 pPara = new Paragraph( -1 ); 444 nCurDepth = -1; 445 } 446 else 447 nCurDepth = pPara->GetDepth(); 448 449 // Im Outliner-Modus die Tabulatoren filtern und die 450 // Einrueckung ueber ein LRSpaceItem einstellen 451 // Im EditEngine-Modus ueber Maltes Tabulatoren einruecken 452 if( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) || 453 ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ) ) 454 { 455 // Tabs raus 456 sal_uInt16 nTabs = 0; 457 while ( ( nTabs < aStr.Len() ) && ( aStr.GetChar( nTabs ) == '\t' ) ) 458 nTabs++; 459 if ( nTabs ) 460 aStr.Erase( 0, nTabs ); 461 462 // Tiefe beibehalten ? (siehe Outliner::Insert) 463 if( !(pPara->nFlags & PARAFLAG_HOLDDEPTH) ) 464 { 465 nCurDepth = nTabs-1; 466 ImplCheckDepth( nCurDepth ); 467 pPara->SetDepth( nCurDepth ); 468 pPara->nFlags &= (~PARAFLAG_HOLDDEPTH); 469 } 470 } 471 if( nPos ) // nicht mit dem ersten Absatz 472 { 473 pParaList->Insert( pPara, nInsPos ); 474 pEditEngine->InsertParagraph( nInsPos, aStr ); 475 pHdlParagraph = pPara; 476 ParagraphInsertedHdl(); 477 } 478 else 479 { 480 nInsPos--; 481 pEditEngine->SetText( nInsPos, aStr ); 482 } 483 ImplInitDepth( nInsPos, nCurDepth, sal_False ); 484 nInsPos++; 485 nPos++; 486 } 487 } 488 489 DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"SetText failed!"); 490 bFirstParaIsEmpty = sal_False; 491 ImplBlockInsertionCallbacks( sal_False ); 492 pEditEngine->SetUpdateMode( bUpdate ); 493 } 494 495 // pView == 0 -> Tabulatoren nicht beachten 496 497 bool Outliner::ImpConvertEdtToOut( sal_uInt32 nPara,EditView* pView) 498 { 499 DBG_CHKTHIS(Outliner,0); 500 501 bool bConverted = false; 502 sal_uInt16 nTabs = 0; 503 ESelection aDelSel; 504 505 // const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (sal_uInt16)nPara ); 506 // bool bAlreadyOutliner = rAttrs.GetItemState( EE_PARA_OUTLLRSPACE ) == SFX_ITEM_ON ? true : false; 507 508 XubString aName; 509 XubString aHeading_US( RTL_CONSTASCII_USTRINGPARAM( "heading" ) ); 510 XubString aNumber_US( RTL_CONSTASCII_USTRINGPARAM( "Numbering" ) ); 511 512 XubString aStr( pEditEngine->GetText( (sal_uInt16)nPara ) ); 513 xub_Unicode* pPtr = (xub_Unicode*)aStr.GetBuffer(); 514 515 sal_uInt16 nHeadingNumberStart = 0; 516 sal_uInt16 nNumberingNumberStart = 0; 517 SfxStyleSheet* pStyle= pEditEngine->GetStyleSheet( (sal_uInt16)nPara ); 518 if( pStyle ) 519 { 520 aName = pStyle->GetName(); 521 sal_uInt16 nSearch; 522 if ( ( nSearch = aName.Search( aHeading_US ) ) != STRING_NOTFOUND ) 523 nHeadingNumberStart = nSearch + aHeading_US.Len(); 524 else if ( ( nSearch = aName.Search( aNumber_US ) ) != STRING_NOTFOUND ) 525 nNumberingNumberStart = nSearch + aNumber_US.Len(); 526 } 527 528 if ( nHeadingNumberStart || nNumberingNumberStart ) 529 { 530 // PowerPoint-Import ? 531 if( nHeadingNumberStart && ( aStr.Len() >= 2 ) && 532 ( pPtr[0] != '\t' ) && ( pPtr[1] == '\t' ) ) 533 { 534 // Bullet & Tab raus 535 aDelSel = ESelection( (sal_uInt16)nPara, 0, (sal_uInt16)nPara, 2 ); 536 } 537 538 sal_uInt16 nPos = nHeadingNumberStart ? nHeadingNumberStart : nNumberingNumberStart; 539 String aLevel = aName.Copy( nPos ); 540 aLevel.EraseLeadingChars( ' ' ); 541 nTabs = sal::static_int_cast< sal_uInt16 >(aLevel.ToInt32()); 542 if( nTabs ) 543 nTabs--; // ebene 0 = "heading 1" 544 bConverted = sal_True; 545 } 546 else 547 { 548 // Fuehrende Tabulatoren filtern 549 while( *pPtr == '\t' ) 550 { 551 pPtr++; 552 nTabs++; 553 } 554 // Tabulatoren aus dem Text entfernen 555 if( nTabs ) 556 aDelSel = ESelection( (sal_uInt16)nPara, 0, (sal_uInt16)nPara, nTabs ); 557 } 558 559 if ( aDelSel.HasRange() ) 560 { 561 if ( pView ) 562 { 563 pView->SetSelection( aDelSel ); 564 pView->DeleteSelected(); 565 } 566 else 567 pEditEngine->QuickDelete( aDelSel ); 568 } 569 570 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( sal::static_int_cast< sal_uInt16 >(nPara), EE_PARA_OUTLLEVEL ); 571 sal_Int16 nOutlLevel = rLevel.GetValue(); 572 573 ImplCheckDepth( nOutlLevel ); 574 ImplInitDepth( sal::static_int_cast< sal_uInt16 >(nPara), nOutlLevel, sal_False ); 575 576 return bConverted; 577 } 578 579 void Outliner::SetText( const OutlinerParaObject& rPObj ) 580 { 581 DBG_CHKTHIS(Outliner,0); 582 583 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 584 pEditEngine->SetUpdateMode( sal_False ); 585 586 sal_Bool bUndo = pEditEngine->IsUndoEnabled(); 587 EnableUndo( sal_False ); 588 589 Init( rPObj.GetOutlinerMode() ); 590 591 ImplBlockInsertionCallbacks( sal_True ); 592 pEditEngine->SetText(rPObj.GetTextObject()); 593 if( rPObj.Count() != pEditEngine->GetParagraphCount() ) 594 { 595 int nop=0;nop++; 596 } 597 598 bFirstParaIsEmpty = sal_False; 599 600 pParaList->Clear( sal_True ); 601 for( sal_uInt16 nCurPara = 0; nCurPara < rPObj.Count(); nCurPara++ ) 602 { 603 Paragraph* pPara = new Paragraph( rPObj.GetParagraphData(nCurPara)); 604 ImplCheckDepth( pPara->nDepth ); 605 606 pParaList->Insert( pPara, LIST_APPEND ); 607 ImplCheckNumBulletItem( nCurPara ); 608 } 609 610 // --> OD 2009-03-10 #i100014# 611 // It is not a good idea to substract 1 from a count and cast the result 612 // to sal_uInt16 without check, if the count is 0. 613 ImplCheckParagraphs( 0, (sal_uInt16) (pParaList->GetParagraphCount()) ); 614 // <-- 615 616 EnableUndo( bUndo ); 617 ImplBlockInsertionCallbacks( sal_False ); 618 pEditEngine->SetUpdateMode( bUpdate ); 619 620 DBG_ASSERT( pParaList->GetParagraphCount()==rPObj.Count(),"SetText failed"); 621 DBG_ASSERT( pEditEngine->GetParagraphCount()==rPObj.Count(),"SetText failed"); 622 } 623 624 void Outliner::AddText( const OutlinerParaObject& rPObj ) 625 { 626 DBG_CHKTHIS(Outliner,0); 627 Paragraph* pPara; 628 629 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 630 pEditEngine->SetUpdateMode( sal_False ); 631 632 ImplBlockInsertionCallbacks( sal_True ); 633 sal_uLong nPara; 634 if( bFirstParaIsEmpty ) 635 { 636 pParaList->Clear( sal_True ); 637 pEditEngine->SetText(rPObj.GetTextObject()); 638 nPara = 0; 639 } 640 else 641 { 642 nPara = pParaList->GetParagraphCount(); 643 pEditEngine->InsertParagraph( EE_PARA_APPEND, rPObj.GetTextObject() ); 644 } 645 bFirstParaIsEmpty = sal_False; 646 647 for( sal_uInt16 n = 0; n < rPObj.Count(); n++ ) 648 { 649 pPara = new Paragraph( rPObj.GetParagraphData(n) ); 650 pParaList->Insert( pPara, LIST_APPEND ); 651 sal_uInt16 nP = sal::static_int_cast< sal_uInt16 >(nPara+n); 652 DBG_ASSERT(pParaList->GetAbsPos(pPara)==nP,"AddText:Out of sync"); 653 ImplInitDepth( nP, pPara->GetDepth(), sal_False ); 654 } 655 DBG_ASSERT( pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(), "SetText: OutOfSync" ); 656 657 // --> OD 2009-03-10 #i100014# 658 // It is not a good idea to substract 1 from a count and cast the result 659 // to sal_uInt16 without check, if the count is 0. 660 ImplCheckParagraphs( (sal_uInt16)nPara, (sal_uInt16) (pParaList->GetParagraphCount()) ); 661 // <-- 662 663 ImplBlockInsertionCallbacks( sal_False ); 664 pEditEngine->SetUpdateMode( bUpdate ); 665 } 666 667 void __EXPORT Outliner::FieldClicked( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos ) 668 { 669 DBG_CHKTHIS(Outliner,0); 670 671 if ( aFieldClickedHdl.IsSet() ) 672 { 673 EditFieldInfo aFldInfo( this, rField, nPara, nPos ); 674 aFldInfo.SetSimpleClick( sal_True ); 675 aFieldClickedHdl.Call( &aFldInfo ); 676 } 677 } 678 679 680 void __EXPORT Outliner::FieldSelected( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos ) 681 { 682 DBG_CHKTHIS(Outliner,0); 683 if ( !aFieldClickedHdl.IsSet() ) 684 return; 685 686 EditFieldInfo aFldInfo( this, rField, nPara, nPos ); 687 aFldInfo.SetSimpleClick( sal_False ); 688 aFieldClickedHdl.Call( &aFldInfo ); 689 } 690 691 692 XubString __EXPORT Outliner::CalcFieldValue( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos, Color*& rpTxtColor, Color*& rpFldColor ) 693 { 694 DBG_CHKTHIS(Outliner,0); 695 if ( !aCalcFieldValueHdl.IsSet() ) 696 return String( ' ' ); 697 698 EditFieldInfo aFldInfo( this, rField, nPara, nPos ); 699 // Die FldColor ist mit COL_LIGHTGRAY voreingestellt. 700 if ( rpFldColor ) 701 aFldInfo.SetFldColor( *rpFldColor ); 702 703 aCalcFieldValueHdl.Call( &aFldInfo ); 704 if ( aFldInfo.GetTxtColor() ) 705 { 706 delete rpTxtColor; 707 rpTxtColor = new Color( *aFldInfo.GetTxtColor() ); 708 } 709 710 delete rpFldColor; 711 rpFldColor = aFldInfo.GetFldColor() ? new Color( *aFldInfo.GetFldColor() ) : 0; 712 713 return aFldInfo.GetRepresentation(); 714 } 715 716 void Outliner::SetStyleSheet( sal_uLong nPara, SfxStyleSheet* pStyle ) 717 { 718 DBG_CHKTHIS(Outliner,0); 719 Paragraph* pPara = pParaList->GetParagraph( nPara ); 720 if (pPara) 721 { 722 pEditEngine->SetStyleSheet( (sal_uInt16)nPara, pStyle ); 723 pPara->nFlags |= PARAFLAG_SETBULLETTEXT; 724 ImplCheckNumBulletItem( (sal_uInt16) nPara ); 725 } 726 } 727 728 void Outliner::SetVisible( Paragraph* pPara, sal_Bool bVisible ) 729 { 730 DBG_CHKTHIS(Outliner,0); 731 DBG_ASSERT( pPara, "SetVisible: pPara = NULL" ); 732 733 if (pPara) 734 { 735 pPara->bVisible = bVisible; 736 sal_uLong nPara = pParaList->GetAbsPos( pPara ); 737 pEditEngine->ShowParagraph( (sal_uInt16)nPara, bVisible ); 738 } 739 } 740 741 void Outliner::ImplCheckNumBulletItem( sal_uInt16 nPara ) 742 { 743 Paragraph* pPara = pParaList->GetParagraph( nPara ); 744 if (pPara) 745 pPara->aBulSize.Width() = -1; 746 } 747 748 void Outliner::ImplSetLevelDependendStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pLevelStyle ) 749 { 750 DBG_CHKTHIS(Outliner,0); 751 752 DBG_ASSERT( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) || ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ), "SetLevelDependendStyleSheet: Wrong Mode!" ); 753 754 SfxStyleSheet* pStyle = pLevelStyle; 755 if ( !pStyle ) 756 pStyle = GetStyleSheet( nPara ); 757 758 if ( pStyle ) 759 { 760 sal_Int16 nDepth = GetDepth( nPara ); 761 if( nDepth < 0 ) 762 nDepth = 0; 763 764 String aNewStyleSheetName( pStyle->GetName() ); 765 aNewStyleSheetName.Erase( aNewStyleSheetName.Len()-1, 1 ); 766 aNewStyleSheetName += String::CreateFromInt32( nDepth+1 ); 767 SfxStyleSheet* pNewStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( aNewStyleSheetName, pStyle->GetFamily() ); 768 DBG_ASSERT( pNewStyle, "AutoStyleSheetName - Style not found!" ); 769 if ( pNewStyle && ( pNewStyle != GetStyleSheet( nPara ) ) ) 770 { 771 SfxItemSet aOldAttrs( GetParaAttribs( nPara ) ); 772 SetStyleSheet( nPara, pNewStyle ); 773 if ( aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SFX_ITEM_ON ) 774 { 775 SfxItemSet aAttrs( GetParaAttribs( nPara ) ); 776 aAttrs.Put( aOldAttrs.Get( EE_PARA_NUMBULLET ) ); 777 SetParaAttribs( nPara, aAttrs ); 778 } 779 } 780 } 781 } 782 783 void Outliner::ImplInitDepth( sal_uInt16 nPara, sal_Int16 nDepth, sal_Bool bCreateUndo, sal_Bool bUndoAction ) 784 { 785 DBG_CHKTHIS(Outliner,0); 786 787 DBG_ASSERT( ( nDepth >= nMinDepth ) && ( nDepth <= nMaxDepth ), "ImplInitDepth - Depth is invalid!" ); 788 789 Paragraph* pPara = pParaList->GetParagraph( nPara ); 790 if (!pPara) 791 return; 792 sal_Int16 nOldDepth = pPara->GetDepth(); 793 pPara->SetDepth( nDepth ); 794 795 // Bei IsInUndo brauchen Attribute und Style nicht eingestellt werden, 796 // dort werden die alten Werte durch die EditEngine restauriert. 797 798 if( !IsInUndo() ) 799 { 800 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 801 pEditEngine->SetUpdateMode( sal_False ); 802 803 sal_Bool bUndo = bCreateUndo && IsUndoEnabled(); 804 if ( bUndo && bUndoAction ) 805 UndoActionStart( OLUNDO_DEPTH ); 806 807 SfxItemSet aAttrs( pEditEngine->GetParaAttribs( nPara ) ); 808 aAttrs.Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nDepth ) ); 809 pEditEngine->SetParaAttribs( nPara, aAttrs ); 810 ImplCheckNumBulletItem( nPara ); 811 ImplCalcBulletText( nPara, sal_False, sal_False ); 812 813 if ( bUndo ) 814 { 815 InsertUndo( new OutlinerUndoChangeDepth( this, nPara, nOldDepth, nDepth ) ); 816 if ( bUndoAction ) 817 UndoActionEnd( OLUNDO_DEPTH ); 818 } 819 820 pEditEngine->SetUpdateMode( bUpdate ); 821 } 822 } 823 824 void Outliner::SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet ) 825 { 826 DBG_CHKTHIS(Outliner,0); 827 828 pEditEngine->SetParaAttribs( nPara, rSet ); 829 } 830 831 sal_Bool Outliner::Expand( Paragraph* pPara ) 832 { 833 DBG_CHKTHIS(Outliner,0); 834 835 if ( pParaList->HasHiddenChilds( pPara ) ) 836 { 837 OLUndoExpand* pUndo = 0; 838 sal_Bool bUndo = IsUndoEnabled() && !IsInUndo(); 839 if( bUndo ) 840 { 841 UndoActionStart( OLUNDO_EXPAND ); 842 pUndo = new OLUndoExpand( this, OLUNDO_EXPAND ); 843 pUndo->pParas = 0; 844 pUndo->nCount = (sal_uInt16)pParaList->GetAbsPos( pPara ); 845 } 846 pHdlParagraph = pPara; 847 bIsExpanding = sal_True; 848 pParaList->Expand( pPara ); 849 ExpandHdl(); 850 InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) ); 851 if( bUndo ) 852 { 853 InsertUndo( pUndo ); 854 UndoActionEnd( OLUNDO_EXPAND ); 855 } 856 return sal_True; 857 } 858 return sal_False; 859 } 860 861 862 sal_Bool Outliner::Collapse( Paragraph* pPara ) 863 { 864 DBG_CHKTHIS(Outliner,0); 865 if ( pParaList->HasVisibleChilds( pPara ) ) // expandiert 866 { 867 OLUndoExpand* pUndo = 0; 868 sal_Bool bUndo = sal_False; 869 870 if( !IsInUndo() && IsUndoEnabled() ) 871 bUndo = sal_True; 872 if( bUndo ) 873 { 874 UndoActionStart( OLUNDO_COLLAPSE ); 875 pUndo = new OLUndoExpand( this, OLUNDO_COLLAPSE ); 876 pUndo->pParas = 0; 877 pUndo->nCount = (sal_uInt16)pParaList->GetAbsPos( pPara ); 878 } 879 880 pHdlParagraph = pPara; 881 bIsExpanding = sal_False; 882 pParaList->Collapse( pPara ); 883 ExpandHdl(); 884 InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) ); 885 if( bUndo ) 886 { 887 InsertUndo( pUndo ); 888 UndoActionEnd( OLUNDO_COLLAPSE ); 889 } 890 return sal_True; 891 } 892 return sal_False; 893 } 894 895 896 Font Outliner::ImpCalcBulletFont( sal_uInt16 nPara ) const 897 { 898 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 899 DBG_ASSERT( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ), "ImpCalcBulletFont: Missing or BitmapBullet!" ); 900 901 Font aStdFont; //#107508# 902 if ( !pEditEngine->IsFlatMode() ) 903 { 904 ESelection aSel( nPara, 0, nPara, 0 ); 905 aStdFont = EditEngine::CreateFontFromItemSet( pEditEngine->GetAttribs( aSel ), GetScriptType( aSel ) ); 906 } 907 else 908 { 909 aStdFont = pEditEngine->GetStandardFont( nPara ); 910 } 911 912 Font aBulletFont; 913 if ( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL ) 914 { 915 aBulletFont = *pFmt->GetBulletFont(); 916 } 917 else 918 { 919 aBulletFont = aStdFont; 920 aBulletFont.SetUnderline( UNDERLINE_NONE ); 921 aBulletFont.SetOverline( UNDERLINE_NONE ); 922 aBulletFont.SetStrikeout( STRIKEOUT_NONE ); 923 aBulletFont.SetEmphasisMark( EMPHASISMARK_NONE ); 924 aBulletFont.SetRelief( RELIEF_NONE ); 925 } 926 927 // #107508# Use original scale... 928 sal_uInt16 nScale = /* pEditEngine->IsFlatMode() ? DEFAULT_SCALE : */ pFmt->GetBulletRelSize(); 929 sal_uLong nScaledLineHeight = aStdFont.GetSize().Height(); 930 nScaledLineHeight *= nScale*10; 931 nScaledLineHeight /= 1000; 932 933 aBulletFont.SetAlign( ALIGN_BOTTOM ); 934 aBulletFont.SetSize( Size( 0, nScaledLineHeight ) ); 935 sal_Bool bVertical = IsVertical(); 936 aBulletFont.SetVertical( bVertical ); 937 aBulletFont.SetOrientation( bVertical ? 2700 : 0 ); 938 939 Color aColor( COL_AUTO ); 940 if( !pEditEngine->IsFlatMode() && !( pEditEngine->GetControlWord() & EE_CNTRL_NOCOLORS ) ) 941 { 942 aColor = pFmt->GetBulletColor(); 943 } 944 945 if ( ( aColor == COL_AUTO ) || ( IsForceAutoColor() ) ) 946 aColor = pEditEngine->GetAutoColor(); 947 948 aBulletFont.SetColor( aColor ); 949 return aBulletFont; 950 } 951 952 void Outliner::PaintBullet( sal_uInt16 nPara, const Point& rStartPos, 953 const Point& rOrigin, short nOrientation, OutputDevice* pOutDev ) 954 { 955 DBG_CHKTHIS(Outliner,0); 956 957 bool bDrawBullet = false; 958 if (pEditEngine) 959 { 960 const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ); 961 bDrawBullet = rBulletState.GetValue() ? true : false; 962 } 963 964 if ( ImplHasBullet( nPara ) && bDrawBullet) 965 { 966 sal_Bool bVertical = IsVertical(); 967 968 sal_Bool bRightToLeftPara = pEditEngine->IsRightToLeft( nPara ); 969 970 Rectangle aBulletArea( ImpCalcBulletArea( nPara, sal_True, sal_False ) ); 971 972 Paragraph* pPara = pParaList->GetParagraph( nPara ); 973 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 974 if ( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) 975 { 976 if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) 977 { 978 Font aBulletFont( ImpCalcBulletFont( nPara ) ); 979 // #2338# Use base line 980 sal_Bool bSymbol = pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL; 981 aBulletFont.SetAlign( bSymbol ? ALIGN_BOTTOM : ALIGN_BASELINE ); 982 Font aOldFont = pOutDev->GetFont(); 983 pOutDev->SetFont( aBulletFont ); 984 985 ParagraphInfos aParaInfos = pEditEngine->GetParagraphInfos( nPara ); 986 Point aTextPos; 987 if ( !bVertical ) 988 { 989 // aTextPos.Y() = rStartPos.Y() + aBulletArea.Bottom(); 990 aTextPos.Y() = rStartPos.Y() + ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent ); 991 if ( !bRightToLeftPara ) 992 aTextPos.X() = rStartPos.X() + aBulletArea.Left(); 993 else 994 aTextPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left(); 995 } 996 else 997 { 998 // aTextPos.X() = rStartPos.X() - aBulletArea.Bottom(); 999 aTextPos.X() = rStartPos.X() - ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent ); 1000 aTextPos.Y() = rStartPos.Y() + aBulletArea.Left(); 1001 } 1002 1003 if ( nOrientation ) 1004 { 1005 // Sowohl TopLeft als auch BottomLeft nicht ganz richtig, da 1006 // in EditEngine BaseLine... 1007 double nRealOrientation = nOrientation*F_PI1800; 1008 double nCos = cos( nRealOrientation ); 1009 double nSin = sin( nRealOrientation ); 1010 Point aRotatedPos; 1011 // Translation... 1012 aTextPos -= rOrigin; 1013 // Rotation... 1014 aRotatedPos.X()=(long) (nCos*aTextPos.X() + nSin*aTextPos.Y()); 1015 aRotatedPos.Y()=(long) - (nSin*aTextPos.X() - nCos*aTextPos.Y()); 1016 aTextPos = aRotatedPos; 1017 // Translation... 1018 aTextPos += rOrigin; 1019 Font aRotatedFont( aBulletFont ); 1020 aRotatedFont.SetOrientation( nOrientation ); 1021 pOutDev->SetFont( aRotatedFont ); 1022 } 1023 1024 // #105803# VCL will care for brackets and so on... 1025 sal_uLong nLayoutMode = pOutDev->GetLayoutMode(); 1026 nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG); 1027 if ( bRightToLeftPara ) 1028 nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; 1029 pOutDev->SetLayoutMode( nLayoutMode ); 1030 1031 if(bStrippingPortions) 1032 { 1033 const Font aSvxFont(pOutDev->GetFont()); 1034 sal_Int32* pBuf = new sal_Int32[ pPara->GetText().Len() ]; 1035 pOutDev->GetTextArray( pPara->GetText(), pBuf ); 1036 1037 if(bSymbol) 1038 { 1039 // aTextPos is Bottom, go to Baseline 1040 FontMetric aMetric(pOutDev->GetFontMetric()); 1041 aTextPos.Y() -= aMetric.GetDescent(); 1042 } 1043 1044 DrawingText(aTextPos, pPara->GetText(), 0, pPara->GetText().Len(), pBuf, 1045 aSvxFont, nPara, 0xFFFF, 0xFF, 0, 0, false, false, true, 0, Color(), Color()); 1046 1047 delete[] pBuf; 1048 } 1049 else 1050 { 1051 pOutDev->DrawText( aTextPos, pPara->GetText() ); 1052 } 1053 1054 pOutDev->SetFont( aOldFont ); 1055 } 1056 else 1057 { 1058 if ( pFmt->GetBrush()->GetGraphicObject() ) 1059 { 1060 Point aBulletPos; 1061 if ( !bVertical ) 1062 { 1063 aBulletPos.Y() = rStartPos.Y() + aBulletArea.Top(); 1064 if ( !bRightToLeftPara ) 1065 aBulletPos.X() = rStartPos.X() + aBulletArea.Left(); 1066 else 1067 aBulletPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Right(); 1068 } 1069 else 1070 { 1071 aBulletPos.X() = rStartPos.X() - aBulletArea.Bottom(); 1072 aBulletPos.Y() = rStartPos.Y() + aBulletArea.Left(); 1073 } 1074 1075 if(bStrippingPortions) 1076 { 1077 if(aDrawBulletHdl.IsSet()) 1078 { 1079 // call something analog to aDrawPortionHdl (if set) and feed it something 1080 // analog to DrawPortionInfo... 1081 // created aDrawBulletHdl, Set/GetDrawBulletHdl. 1082 // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx 1083 DrawBulletInfo aDrawBulletInfo( 1084 *pFmt->GetBrush()->GetGraphicObject(), 1085 aBulletPos, 1086 pPara->aBulSize); 1087 1088 aDrawBulletHdl.Call(&aDrawBulletInfo); 1089 } 1090 } 1091 else 1092 { 1093 // MT: Remove CAST when KA made the Draw-Method const 1094 ((GraphicObject*)pFmt->GetBrush()->GetGraphicObject())->Draw( pOutDev, aBulletPos, pPara->aBulSize ); 1095 } 1096 } 1097 } 1098 } 1099 1100 // Bei zusammengeklappten Absaetzen einen Strich vor den Text malen. 1101 if( pParaList->HasChilds(pPara) && !pParaList->HasVisibleChilds(pPara) && 1102 !bStrippingPortions && !nOrientation ) 1103 { 1104 long nWidth = pOutDev->PixelToLogic( Size( 10, 0 ) ).Width(); 1105 1106 Point aStartPos, aEndPos; 1107 if ( !bVertical ) 1108 { 1109 aStartPos.Y() = rStartPos.Y() + aBulletArea.Bottom(); 1110 if ( !bRightToLeftPara ) 1111 aStartPos.X() = rStartPos.X() + aBulletArea.Right(); 1112 else 1113 aStartPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left(); 1114 aEndPos = aStartPos; 1115 aEndPos.X() += nWidth; 1116 } 1117 else 1118 { 1119 aStartPos.X() = rStartPos.X() - aBulletArea.Bottom(); 1120 aStartPos.Y() = rStartPos.Y() + aBulletArea.Right(); 1121 aEndPos = aStartPos; 1122 aEndPos.Y() += nWidth; 1123 } 1124 1125 const Color& rOldLineColor = pOutDev->GetLineColor(); 1126 pOutDev->SetLineColor( Color( COL_BLACK ) ); 1127 pOutDev->DrawLine( aStartPos, aEndPos ); 1128 pOutDev->SetLineColor( rOldLineColor ); 1129 } 1130 } 1131 } 1132 1133 void Outliner::InvalidateBullet( Paragraph* /*pPara*/, sal_uLong nPara ) 1134 { 1135 DBG_CHKTHIS(Outliner,0); 1136 1137 long nLineHeight = (long)pEditEngine->GetLineHeight((sal_uInt16)nPara ); 1138 OutlinerView* pView = aViewList.First(); 1139 while( pView ) 1140 { 1141 Point aPos( pView->pEditView->GetWindowPosTopLeft((sal_uInt16)nPara ) ); 1142 Rectangle aRect( pView->GetOutputArea() ); 1143 aRect.Right() = aPos.X(); 1144 aRect.Top() = aPos.Y(); 1145 aRect.Bottom() = aPos.Y(); 1146 aRect.Bottom() += nLineHeight; 1147 1148 pView->GetWindow()->Invalidate( aRect ); 1149 pView = aViewList.Next(); 1150 } 1151 } 1152 1153 sal_uLong Outliner::Read( SvStream& rInput, const String& rBaseURL, sal_uInt16 eFormat, SvKeyValueIterator* pHTTPHeaderAttrs ) 1154 { 1155 DBG_CHKTHIS(Outliner,0); 1156 1157 sal_Bool bOldUndo = pEditEngine->IsUndoEnabled(); 1158 EnableUndo( sal_False ); 1159 1160 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 1161 pEditEngine->SetUpdateMode( sal_False ); 1162 1163 Clear(); 1164 1165 ImplBlockInsertionCallbacks( sal_True ); 1166 sal_uLong nRet = pEditEngine->Read( rInput, rBaseURL, (EETextFormat)eFormat, pHTTPHeaderAttrs ); 1167 1168 bFirstParaIsEmpty = sal_False; 1169 1170 sal_uInt16 nParas = pEditEngine->GetParagraphCount(); 1171 pParaList->Clear( sal_True ); 1172 sal_uInt16 n; 1173 for ( n = 0; n < nParas; n++ ) 1174 { 1175 Paragraph* pPara = new Paragraph( 0 ); 1176 pParaList->Insert( pPara, LIST_APPEND ); 1177 1178 if ( eFormat == EE_FORMAT_BIN ) 1179 { 1180 const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( n ); 1181 const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL ); 1182 sal_Int16 nDepth = rLevel.GetValue(); 1183 ImplInitDepth( n, nDepth, sal_False ); 1184 } 1185 } 1186 1187 if ( eFormat != EE_FORMAT_BIN ) 1188 { 1189 ImpFilterIndents( 0, nParas-1 ); 1190 } 1191 1192 ImplBlockInsertionCallbacks( sal_False ); 1193 pEditEngine->SetUpdateMode( bUpdate ); 1194 EnableUndo( bOldUndo ); 1195 1196 return nRet; 1197 } 1198 1199 1200 void Outliner::ImpFilterIndents( sal_uLong nFirstPara, sal_uLong nLastPara ) 1201 { 1202 DBG_CHKTHIS(Outliner,0); 1203 1204 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 1205 pEditEngine->SetUpdateMode( sal_False ); 1206 1207 Paragraph* pLastConverted = NULL; 1208 for( sal_uLong nPara = nFirstPara; nPara <= nLastPara; nPara++ ) 1209 { 1210 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1211 if (pPara) 1212 { 1213 if( ImpConvertEdtToOut( nPara ) ) 1214 { 1215 pLastConverted = pPara; 1216 } 1217 else if ( pLastConverted ) 1218 { 1219 // Normale Absaetze unter der Ueberschrift anordnen... 1220 pPara->SetDepth( pLastConverted->GetDepth() ); 1221 } 1222 1223 ImplInitDepth( (sal_uInt16)nPara, pPara->GetDepth(), sal_False ); 1224 } 1225 } 1226 1227 pEditEngine->SetUpdateMode( bUpdate ); 1228 } 1229 1230 ::svl::IUndoManager& Outliner::GetUndoManager() 1231 { 1232 DBG_CHKTHIS(Outliner,0); 1233 return pEditEngine->GetUndoManager(); 1234 } 1235 1236 void Outliner::ImpTextPasted( sal_uLong nStartPara, sal_uInt16 nCount ) 1237 { 1238 DBG_CHKTHIS(Outliner,0); 1239 1240 sal_Bool bUpdate = pEditEngine->GetUpdateMode(); 1241 pEditEngine->SetUpdateMode( sal_False ); 1242 1243 const sal_uLong nStart = nStartPara; 1244 1245 Paragraph* pPara = pParaList->GetParagraph( nStartPara ); 1246 // Paragraph* pLastConverted = NULL; 1247 // bool bFirst = true; 1248 1249 while( nCount && pPara ) 1250 { 1251 if( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) 1252 { 1253 nDepthChangedHdlPrevDepth = pPara->GetDepth(); 1254 mnDepthChangeHdlPrevFlags = pPara->nFlags; 1255 1256 ImpConvertEdtToOut( nStartPara ); 1257 1258 pHdlParagraph = pPara; 1259 1260 if( nStartPara == nStart ) 1261 { 1262 // the existing paragraph has changed depth or flags 1263 if( (pPara->GetDepth() != nDepthChangedHdlPrevDepth) || (pPara->nFlags != mnDepthChangeHdlPrevFlags) ) 1264 DepthChangedHdl(); 1265 } 1266 } 1267 else // EditEngine-Modus 1268 { 1269 sal_Int16 nDepth = -1; 1270 const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (sal_uInt16)nStartPara ); 1271 if ( rAttrs.GetItemState( EE_PARA_OUTLLEVEL ) == SFX_ITEM_ON ) 1272 { 1273 const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL ); 1274 nDepth = rLevel.GetValue(); 1275 } 1276 if ( nDepth != GetDepth( nStartPara ) ) 1277 ImplInitDepth( (sal_uInt16)nStartPara, nDepth, sal_False ); 1278 } 1279 1280 nCount--; 1281 nStartPara++; 1282 pPara = pParaList->GetParagraph( nStartPara ); 1283 } 1284 1285 pEditEngine->SetUpdateMode( bUpdate ); 1286 1287 DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"ImpTextPasted failed"); 1288 } 1289 1290 long Outliner::IndentingPagesHdl( OutlinerView* pView ) 1291 { 1292 DBG_CHKTHIS(Outliner,0); 1293 if( !aIndentingPagesHdl.IsSet() ) 1294 return 1; 1295 return aIndentingPagesHdl.Call( pView ); 1296 } 1297 1298 sal_Bool Outliner::ImpCanIndentSelectedPages( OutlinerView* pCurView ) 1299 { 1300 DBG_CHKTHIS(Outliner,0); 1301 // Die selektierten Seiten muessen vorher durch ImpCalcSelectedPages 1302 // schon eingestellt sein 1303 1304 // Wenn der erste Absatz auf Ebene 0 liegt darf er auf keinen Fall 1305 // eingerueckt werden, evtl folgen aber weitere auf Ebene 0. 1306 if ( ( mnFirstSelPage == 0 ) && ( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) ) 1307 { 1308 if ( nDepthChangedHdlPrevDepth == 1 ) // ist die einzige Seite 1309 return sal_False; 1310 else 1311 pCurView->ImpCalcSelectedPages( sal_False ); // ohne die erste 1312 } 1313 return (sal_Bool)IndentingPagesHdl( pCurView ); 1314 } 1315 1316 1317 sal_Bool Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView ) 1318 { 1319 DBG_CHKTHIS(Outliner,0); 1320 // Die selektierten Seiten muessen vorher durch ImpCalcSelectedPages 1321 // schon eingestellt sein 1322 return (sal_Bool)RemovingPagesHdl( pCurView ); 1323 } 1324 1325 Outliner::Outliner( SfxItemPool* pPool, sal_uInt16 nMode ) 1326 : nMinDepth( -1 ) 1327 { 1328 DBG_CTOR( Outliner, 0 ); 1329 1330 bStrippingPortions = sal_False; 1331 bPasting = sal_False; 1332 1333 nFirstPage = 1; 1334 bBlockInsCallback = sal_False; 1335 1336 nMaxDepth = 9; 1337 1338 pParaList = new ParagraphList; 1339 pParaList->SetVisibleStateChangedHdl( LINK( this, Outliner, ParaVisibleStateChangedHdl ) ); 1340 Paragraph* pPara = new Paragraph( 0 ); 1341 pParaList->Insert( pPara, LIST_APPEND ); 1342 bFirstParaIsEmpty = sal_True; 1343 1344 pEditEngine = new OutlinerEditEng( this, pPool ); 1345 pEditEngine->SetBeginMovingParagraphsHdl( LINK( this, Outliner, BeginMovingParagraphsHdl ) ); 1346 pEditEngine->SetEndMovingParagraphsHdl( LINK( this, Outliner, EndMovingParagraphsHdl ) ); 1347 pEditEngine->SetBeginPasteOrDropHdl( LINK( this, Outliner, BeginPasteOrDropHdl ) ); 1348 pEditEngine->SetEndPasteOrDropHdl( LINK( this, Outliner, EndPasteOrDropHdl ) ); 1349 1350 Init( nMode ); 1351 } 1352 1353 Outliner::~Outliner() 1354 { 1355 DBG_DTOR(Outliner,0); 1356 1357 pParaList->Clear( sal_True ); 1358 delete pParaList; 1359 delete pEditEngine; 1360 } 1361 1362 sal_uLong Outliner::InsertView( OutlinerView* pView, sal_uLong nIndex ) 1363 { 1364 DBG_CHKTHIS(Outliner,0); 1365 1366 aViewList.Insert( pView, nIndex ); 1367 pEditEngine->InsertView( pView->pEditView, (sal_uInt16)nIndex ); 1368 return aViewList.GetPos( pView ); 1369 } 1370 1371 OutlinerView* Outliner::RemoveView( OutlinerView* pView ) 1372 { 1373 DBG_CHKTHIS(Outliner,0); 1374 1375 sal_uLong nPos = aViewList.GetPos( pView ); 1376 if ( nPos != LIST_ENTRY_NOTFOUND ) 1377 { 1378 pView->pEditView->HideCursor(); // HACK wg. BugId 10006 1379 pEditEngine->RemoveView( pView->pEditView ); 1380 aViewList.Remove( nPos ); 1381 } 1382 return NULL; // MT: return ueberfluessig 1383 } 1384 1385 OutlinerView* Outliner::RemoveView( sal_uLong nIndex ) 1386 { 1387 DBG_CHKTHIS(Outliner,0); 1388 1389 EditView* pEditView = pEditEngine->GetView( (sal_uInt16)nIndex ); 1390 pEditView->HideCursor(); // HACK wg. BugId 10006 1391 1392 pEditEngine->RemoveView( (sal_uInt16)nIndex ); 1393 aViewList.Remove( nIndex ); 1394 return NULL; // MT: return ueberfluessig 1395 } 1396 1397 1398 OutlinerView* Outliner::GetView( sal_uLong nIndex ) const 1399 { 1400 DBG_CHKTHIS(Outliner,0); 1401 return aViewList.GetObject( nIndex ); 1402 } 1403 1404 sal_uLong Outliner::GetViewCount() const 1405 { 1406 DBG_CHKTHIS(Outliner,0); 1407 return aViewList.Count(); 1408 } 1409 1410 void Outliner::ParagraphInsertedHdl() 1411 { 1412 DBG_CHKTHIS(Outliner,0); 1413 if( !IsInUndo() ) 1414 aParaInsertedHdl.Call( this ); 1415 } 1416 1417 1418 void Outliner::ParagraphRemovingHdl() 1419 { 1420 DBG_CHKTHIS(Outliner,0); 1421 if( !IsInUndo() ) 1422 aParaRemovingHdl.Call( this ); 1423 } 1424 1425 1426 void Outliner::DepthChangedHdl() 1427 { 1428 DBG_CHKTHIS(Outliner,0); 1429 if( !IsInUndo() ) 1430 aDepthChangedHdl.Call( this ); 1431 } 1432 1433 1434 sal_uLong Outliner::GetAbsPos( Paragraph* pPara ) 1435 { 1436 DBG_CHKTHIS(Outliner,0); 1437 DBG_ASSERT(pPara,"GetAbsPos:No Para"); 1438 return pParaList->GetAbsPos( pPara ); 1439 } 1440 1441 sal_uLong Outliner::GetParagraphCount() const 1442 { 1443 DBG_CHKTHIS(Outliner,0); 1444 return pParaList->GetParagraphCount(); 1445 } 1446 1447 Paragraph* Outliner::GetParagraph( sal_uLong nAbsPos ) const 1448 { 1449 DBG_CHKTHIS(Outliner,0); 1450 return pParaList->GetParagraph( nAbsPos ); 1451 } 1452 1453 sal_Bool Outliner::HasChilds( Paragraph* pParagraph ) const 1454 { 1455 DBG_CHKTHIS(Outliner,0); 1456 return pParaList->HasChilds( pParagraph ); 1457 } 1458 1459 sal_Bool Outliner::ImplHasBullet( sal_uInt16 nPara ) const 1460 { 1461 return GetNumberFormat(nPara) != 0; 1462 } 1463 1464 const SvxNumberFormat* Outliner::GetNumberFormat( sal_uInt16 nPara ) const 1465 { 1466 const SvxNumberFormat* pFmt = NULL; 1467 1468 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1469 if (pPara == NULL) 1470 return NULL; 1471 1472 sal_Int16 nDepth = pPara? pPara->GetDepth() : -1; 1473 1474 if( nDepth >= 0 ) 1475 { 1476 const SvxNumBulletItem& rNumBullet = (const SvxNumBulletItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_NUMBULLET ); 1477 if ( rNumBullet.GetNumRule()->GetLevelCount() > nDepth ) 1478 pFmt = rNumBullet.GetNumRule()->Get( nDepth ); 1479 } 1480 1481 return pFmt; 1482 } 1483 1484 Size Outliner::ImplGetBulletSize( sal_uInt16 nPara ) 1485 { 1486 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1487 if (!pPara) 1488 return Size(); 1489 1490 if( pPara->aBulSize.Width() == -1 ) 1491 { 1492 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1493 DBG_ASSERT( pFmt, "ImplGetBulletSize - no Bullet!" ); 1494 1495 if ( pFmt->GetNumberingType() == SVX_NUM_NUMBER_NONE ) 1496 { 1497 pPara->aBulSize = Size( 0, 0 ); 1498 } 1499 else if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) 1500 { 1501 String aBulletText = ImplGetBulletText( nPara ); 1502 OutputDevice* pRefDev = pEditEngine->GetRefDevice(); 1503 Font aBulletFont( ImpCalcBulletFont( nPara ) ); 1504 Font aRefFont( pRefDev->GetFont()); 1505 pRefDev->SetFont( aBulletFont ); 1506 pPara->aBulSize.Width() = pRefDev->GetTextWidth( aBulletText ); 1507 pPara->aBulSize.Height() = pRefDev->GetTextHeight(); 1508 pRefDev->SetFont( aRefFont ); 1509 } 1510 else 1511 { 1512 pPara->aBulSize = OutputDevice::LogicToLogic( pFmt->GetGraphicSize(), MAP_100TH_MM, pEditEngine->GetRefDevice()->GetMapMode() ); 1513 } 1514 } 1515 1516 return pPara->aBulSize; 1517 } 1518 1519 void Outliner::ImplCheckParagraphs( sal_uInt16 nStart, sal_uInt16 nEnd ) 1520 { 1521 DBG_CHKTHIS( Outliner, 0 ); 1522 1523 // --> OD 2009-03-10 #i100014# 1524 // assure that the following for-loop does not loop forever 1525 for ( sal_uInt16 n = nStart; n < nEnd; n++ ) 1526 // <-- 1527 { 1528 Paragraph* pPara = pParaList->GetParagraph( n ); 1529 if (pPara) 1530 { 1531 pPara->Invalidate(); 1532 ImplCalcBulletText( n, sal_False, sal_False ); 1533 } 1534 } 1535 } 1536 1537 void Outliner::SetRefDevice( OutputDevice* pRefDev ) 1538 { 1539 DBG_CHKTHIS(Outliner,0); 1540 pEditEngine->SetRefDevice( pRefDev ); 1541 for ( sal_uInt16 n = (sal_uInt16) pParaList->GetParagraphCount(); n; ) 1542 { 1543 Paragraph* pPara = pParaList->GetParagraph( --n ); 1544 pPara->Invalidate(); 1545 } 1546 } 1547 1548 void Outliner::ParaAttribsChanged( sal_uInt16 nPara ) 1549 { 1550 DBG_CHKTHIS(Outliner,0); 1551 1552 // Der Outliner hat kein eigenes Undo, wenn Absaetz getrennt/verschmolzen werden. 1553 // Beim ParagraphInserted ist das Attribut EE_PARA_OUTLLEVEL 1554 // ggf. noch nicht eingestellt, dies wird aber benoetigt um die Tiefe 1555 // des Absatzes zu bestimmen. 1556 1557 if( pEditEngine->IsInUndo() ) 1558 { 1559 if ( pParaList->GetParagraphCount() == pEditEngine->GetParagraphCount() ) 1560 { 1561 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1562 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); 1563 if ( pPara && pPara->GetDepth() != rLevel.GetValue() ) 1564 { 1565 pPara->SetDepth( rLevel.GetValue() ); 1566 ImplCalcBulletText( nPara, sal_True, sal_True ); 1567 } 1568 } 1569 } 1570 } 1571 1572 void Outliner::StyleSheetChanged( SfxStyleSheet* pStyle ) 1573 { 1574 DBG_CHKTHIS(Outliner,0); 1575 1576 // Die EditEngine ruft StyleSheetChanged auch fuer abgeleitete Styles. 1577 // MT: Hier wurde frueher alle Absaetze durch ein ImpRecalcParaAttribs 1578 // gejagt, die die besagte Vorlage haben, warum? 1579 // => Eigentlich kann sich nur die Bullet-Repraesentation aendern... 1580 1581 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount(); 1582 for( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) 1583 { 1584 if ( pEditEngine->GetStyleSheet( nPara ) == pStyle ) 1585 { 1586 ImplCheckNumBulletItem( nPara ); 1587 ImplCalcBulletText( nPara, sal_False, sal_False ); 1588 // #97333# EditEngine formats changed paragraphs before calling this method, 1589 // so they are not reformatted now and use wrong bullet indent 1590 pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) ); 1591 } 1592 } 1593 } 1594 1595 Rectangle Outliner::ImpCalcBulletArea( sal_uInt16 nPara, sal_Bool bAdjust, sal_Bool bReturnPaperPos ) 1596 { 1597 // Bullet-Bereich innerhalb des Absatzes... 1598 Rectangle aBulletArea; 1599 1600 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1601 if ( pFmt ) 1602 { 1603 Point aTopLeft; 1604 Size aBulletSize( ImplGetBulletSize( nPara ) ); 1605 1606 sal_Bool bOutlineMode = ( pEditEngine->GetControlWord() & EE_CNTRL_OUTLINER ) != 0; 1607 1608 // the ODF attribut text:space-before which holds the spacing to add to the left of the label 1609 const short nSpaceBefore = pFmt->GetAbsLSpace() + pFmt->GetFirstLineOffset(); 1610 1611 const SvxLRSpaceItem& rLR = (const SvxLRSpaceItem&) pEditEngine->GetParaAttrib( nPara, bOutlineMode ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE ); 1612 aTopLeft.X() = rLR.GetTxtLeft() + rLR.GetTxtFirstLineOfst() + nSpaceBefore; 1613 1614 long nBulletWidth = Max( (long) -rLR.GetTxtFirstLineOfst(), (long) ((-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance()) ); 1615 if ( nBulletWidth < aBulletSize.Width() ) // Bullet macht sich Platz 1616 nBulletWidth = aBulletSize.Width(); 1617 1618 if ( bAdjust && !bOutlineMode ) 1619 { 1620 // Bei zentriert/rechtsbuendig anpassen 1621 const SvxAdjustItem& rItem = (const SvxAdjustItem&)pEditEngine->GetParaAttrib( nPara, EE_PARA_JUST ); 1622 if ( ( !pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_LEFT ) ) || 1623 ( pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_RIGHT ) ) ) 1624 { 1625 aTopLeft.X() = pEditEngine->GetFirstLineStartX( nPara ) - nBulletWidth; 1626 } 1627 } 1628 1629 // Vertikal: 1630 ParagraphInfos aInfos = pEditEngine->GetParagraphInfos( nPara ); 1631 if ( aInfos.bValid ) 1632 { 1633 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ // #91076# nFirstLineOffset is already added to the StartPos (PaintBullet) from the EditEngine 1634 aInfos.nFirstLineHeight - aInfos.nFirstLineTextHeight 1635 + aInfos.nFirstLineTextHeight / 2 1636 - aBulletSize.Height() / 2; 1637 // ggf. lieber auf der Baseline ausgeben... 1638 if( ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) ) 1639 { 1640 Font aBulletFont( ImpCalcBulletFont( nPara ) ); 1641 if ( aBulletFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) 1642 { 1643 OutputDevice* pRefDev = pEditEngine->GetRefDevice(); 1644 Font aOldFont = pRefDev->GetFont(); 1645 pRefDev->SetFont( aBulletFont ); 1646 FontMetric aMetric( pRefDev->GetFontMetric() ); 1647 // Leading der ersten Zeile... 1648 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ aInfos.nFirstLineMaxAscent; 1649 aTopLeft.Y() -= aMetric.GetAscent(); 1650 pRefDev->SetFont( aOldFont ); 1651 } 1652 } 1653 } 1654 1655 // Horizontal: 1656 if( pFmt->GetNumAdjust() == SVX_ADJUST_RIGHT ) 1657 { 1658 aTopLeft.X() += nBulletWidth - aBulletSize.Width(); 1659 } 1660 else if( pFmt->GetNumAdjust() == SVX_ADJUST_CENTER ) 1661 { 1662 aTopLeft.X() += ( nBulletWidth - aBulletSize.Width() ) / 2; 1663 } 1664 1665 if ( aTopLeft.X() < 0 ) // dann draengeln 1666 aTopLeft.X() = 0; 1667 1668 aBulletArea = Rectangle( aTopLeft, aBulletSize ); 1669 } 1670 if ( bReturnPaperPos ) 1671 { 1672 Size aBulletSize( aBulletArea.GetSize() ); 1673 Point aBulletDocPos( aBulletArea.TopLeft() ); 1674 aBulletDocPos.Y() += pEditEngine->GetDocPosTopLeft( nPara ).Y(); 1675 Point aBulletPos( aBulletDocPos ); 1676 1677 if ( IsVertical() ) 1678 { 1679 aBulletPos.Y() = aBulletDocPos.X(); 1680 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.Y(); 1681 // Rotate: 1682 aBulletPos.X() -= aBulletSize.Height(); 1683 Size aSz( aBulletSize ); 1684 aBulletSize.Width() = aSz.Height(); 1685 aBulletSize.Height() = aSz.Width(); 1686 } 1687 else if ( pEditEngine->IsRightToLeft( nPara ) ) 1688 { 1689 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.X() - aBulletSize.Width(); 1690 } 1691 1692 aBulletArea = Rectangle( aBulletPos, aBulletSize ); 1693 } 1694 return aBulletArea; 1695 } 1696 1697 void Outliner::ExpandHdl() 1698 { 1699 DBG_CHKTHIS(Outliner,0); 1700 aExpandHdl.Call( this ); 1701 } 1702 1703 EBulletInfo Outliner::GetBulletInfo( sal_uInt16 nPara ) 1704 { 1705 EBulletInfo aInfo; 1706 1707 aInfo.nParagraph = nPara; 1708 aInfo.bVisible = ImplHasBullet( nPara ); 1709 1710 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1711 aInfo.nType = pFmt ? pFmt->GetNumberingType() : 0; 1712 1713 if( pFmt ) 1714 { 1715 if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) 1716 { 1717 aInfo.aText = ImplGetBulletText( nPara ); 1718 1719 if( pFmt->GetBulletFont() ) 1720 aInfo.aFont = *pFmt->GetBulletFont(); 1721 } 1722 else if ( pFmt->GetBrush()->GetGraphicObject() ) 1723 { 1724 aInfo.aGraphic = pFmt->GetBrush()->GetGraphicObject()->GetGraphic(); 1725 } 1726 } 1727 1728 if ( aInfo.bVisible ) 1729 { 1730 aInfo.aBounds = ImpCalcBulletArea( nPara, sal_True, sal_True ); 1731 } 1732 1733 return aInfo; 1734 } 1735 1736 XubString Outliner::GetText( Paragraph* pParagraph, sal_uLong nCount ) const 1737 { 1738 DBG_CHKTHIS(Outliner,0); 1739 1740 XubString aText; 1741 sal_uInt16 nStartPara = (sal_uInt16) pParaList->GetAbsPos( pParagraph ); 1742 for ( sal_uInt16 n = 0; n < nCount; n++ ) 1743 { 1744 aText += pEditEngine->GetText( nStartPara + n ); 1745 if ( (n+1) < (sal_uInt16)nCount ) 1746 aText += '\n'; 1747 } 1748 return aText; 1749 } 1750 1751 void Outliner::Remove( Paragraph* pPara, sal_uLong nParaCount ) 1752 { 1753 DBG_CHKTHIS(Outliner,0); 1754 1755 sal_uLong nPos = pParaList->GetAbsPos( pPara ); 1756 if( !nPos && ( nParaCount >= pParaList->GetParagraphCount() ) ) 1757 { 1758 Clear(); 1759 } 1760 else 1761 { 1762 for( sal_uInt16 n = 0; n < (sal_uInt16)nParaCount; n++ ) 1763 pEditEngine->RemoveParagraph( (sal_uInt16) nPos ); 1764 } 1765 } 1766 1767 void Outliner::StripPortions() 1768 { 1769 DBG_CHKTHIS(Outliner,0); 1770 bStrippingPortions = sal_True; 1771 pEditEngine->StripPortions(); 1772 bStrippingPortions = sal_False; 1773 } 1774 1775 // #101498# 1776 void Outliner::DrawingText( const Point& rStartPos, const XubString& rText, sal_uInt16 nTextStart, sal_uInt16 nTextLen, const sal_Int32* pDXArray,const SvxFont& rFont, 1777 sal_uInt16 nPara, sal_uInt16 nIndex, sal_uInt8 nRightToLeft, 1778 const EEngineData::WrongSpellVector* pWrongSpellVector, 1779 const SvxFieldData* pFieldData, 1780 bool bEndOfLine, 1781 bool bEndOfParagraph, 1782 bool bEndOfBullet, 1783 const ::com::sun::star::lang::Locale* pLocale, 1784 const Color& rOverlineColor, 1785 const Color& rTextLineColor) 1786 { 1787 DBG_CHKTHIS(Outliner,0); 1788 1789 if(aDrawPortionHdl.IsSet()) 1790 { 1791 // #101498# 1792 DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, nIndex, pDXArray, pWrongSpellVector, 1793 pFieldData, pLocale, rOverlineColor, rTextLineColor, nRightToLeft, bEndOfLine, bEndOfParagraph, bEndOfBullet); 1794 1795 aDrawPortionHdl.Call( &aInfo ); 1796 } 1797 } 1798 1799 long Outliner::RemovingPagesHdl( OutlinerView* pView ) 1800 { 1801 DBG_CHKTHIS(Outliner,0); 1802 return aRemovingPagesHdl.IsSet() ? aRemovingPagesHdl.Call( pView ) : sal_True; 1803 } 1804 1805 sal_Bool Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView, sal_uInt16 _nFirstPage, sal_uInt16 nPages ) 1806 { 1807 DBG_CHKTHIS(Outliner,0); 1808 1809 nDepthChangedHdlPrevDepth = nPages; 1810 mnFirstSelPage = _nFirstPage; 1811 pHdlParagraph = 0; 1812 return (sal_Bool)RemovingPagesHdl( pCurView ); 1813 } 1814 1815 SfxItemSet Outliner::GetParaAttribs( sal_uInt16 nPara ) 1816 { 1817 DBG_CHKTHIS(Outliner,0); 1818 return pEditEngine->GetParaAttribs( nPara ); 1819 } 1820 1821 IMPL_LINK( Outliner, ParaVisibleStateChangedHdl, Paragraph*, pPara ) 1822 { 1823 DBG_CHKTHIS(Outliner,0); 1824 1825 sal_uLong nPara = pParaList->GetAbsPos( pPara ); 1826 pEditEngine->ShowParagraph( (sal_uInt16)nPara, pPara->IsVisible() ); 1827 1828 return 0; 1829 } 1830 1831 IMPL_LINK( Outliner, BeginMovingParagraphsHdl, MoveParagraphsInfo*, EMPTYARG ) 1832 { 1833 DBG_CHKTHIS(Outliner,0); 1834 1835 if( !IsInUndo() ) 1836 GetBeginMovingHdl().Call( this ); 1837 1838 return 0; 1839 } 1840 1841 IMPL_LINK( Outliner, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfos ) 1842 { 1843 UndoActionStart( EDITUNDO_DRAGANDDROP ); 1844 maBeginPasteOrDropHdl.Call(pInfos); 1845 return 0; 1846 } 1847 1848 IMPL_LINK( Outliner, EndPasteOrDropHdl, PasteOrDropInfos*, pInfos ) 1849 { 1850 bPasting = sal_False; 1851 ImpTextPasted( pInfos->nStartPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); 1852 maEndPasteOrDropHdl.Call( pInfos ); 1853 UndoActionEnd( EDITUNDO_DRAGANDDROP ); 1854 return 0; 1855 } 1856 1857 IMPL_LINK( Outliner, EndMovingParagraphsHdl, MoveParagraphsInfo*, pInfos ) 1858 { 1859 DBG_CHKTHIS(Outliner,0); 1860 1861 pParaList->MoveParagraphs( pInfos->nStartPara, pInfos->nDestPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); 1862 sal_uInt16 nChangesStart = Min( pInfos->nStartPara, pInfos->nDestPara ); 1863 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount(); 1864 for ( sal_uInt16 n = nChangesStart; n < nParas; n++ ) 1865 ImplCalcBulletText( n, sal_False, sal_False ); 1866 1867 if( !IsInUndo() ) 1868 aEndMovingHdl.Call( this ); 1869 1870 return 0; 1871 } 1872 1873 static bool isSameNumbering( const SvxNumberFormat& rN1, const SvxNumberFormat& rN2 ) 1874 { 1875 if( rN1.GetNumberingType() != rN2.GetNumberingType() ) 1876 return false; 1877 1878 if( rN1.GetNumStr(1) != rN2.GetNumStr(1) ) 1879 return false; 1880 1881 if( (rN1.GetPrefix() != rN2.GetPrefix()) || (rN1.GetSuffix() != rN2.GetSuffix()) ) 1882 return false; 1883 1884 return true; 1885 } 1886 1887 sal_uInt16 Outliner::ImplGetNumbering( sal_uInt16 nPara, const SvxNumberFormat* pParaFmt ) 1888 { 1889 sal_uInt16 nNumber = pParaFmt->GetStart() - 1; 1890 1891 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1892 const sal_Int16 nParaDepth = pPara->GetDepth(); 1893 1894 do 1895 { 1896 pPara = pParaList->GetParagraph( nPara ); 1897 const sal_Int16 nDepth = pPara->GetDepth(); 1898 1899 // ignore paragraphs that are below our paragraph or have no numbering 1900 if( (nDepth > nParaDepth) || (nDepth == -1) ) 1901 continue; 1902 1903 // stop on paragraphs that are above our paragraph 1904 if( nDepth < nParaDepth ) 1905 break; 1906 1907 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1908 1909 if( pFmt == 0 ) 1910 continue; // ignore paragraphs without bullets 1911 1912 // check if numbering is the same 1913 if( !isSameNumbering( *pFmt, *pParaFmt ) ) 1914 break; 1915 1916 const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ); 1917 1918 if( rBulletState.GetValue() ) 1919 nNumber += 1; 1920 1921 // same depth, same number format, check for restart 1922 const sal_Int16 nNumberingStartValue = pPara->GetNumberingStartValue(); 1923 if( (nNumberingStartValue != -1) || pPara->IsParaIsNumberingRestart() ) 1924 { 1925 if( nNumberingStartValue != -1 ) 1926 nNumber += nNumberingStartValue - 1; 1927 break; 1928 } 1929 } 1930 while( nPara-- ); 1931 1932 return nNumber; 1933 } 1934 1935 void Outliner::ImplCalcBulletText( sal_uInt16 nPara, sal_Bool bRecalcLevel, sal_Bool bRecalcChilds ) 1936 { 1937 DBG_CHKTHIS(Outliner,0); 1938 1939 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1940 sal_uInt16 nRelPos = 0xFFFF; 1941 1942 while ( pPara ) 1943 { 1944 XubString aBulletText; 1945 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1946 if( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) ) 1947 { 1948 aBulletText += pFmt->GetPrefix(); 1949 if( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL ) 1950 { 1951 aBulletText += pFmt->GetBulletChar(); 1952 } 1953 else if( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) 1954 { 1955 aBulletText += pFmt->GetNumStr( ImplGetNumbering( nPara, pFmt ) ); 1956 } 1957 aBulletText += pFmt->GetSuffix(); 1958 } 1959 1960 if( aBulletText != pPara->GetText() ) 1961 pPara->SetText( aBulletText ); 1962 1963 pPara->nFlags &= (~PARAFLAG_SETBULLETTEXT); 1964 1965 if ( bRecalcLevel ) 1966 { 1967 if ( nRelPos != 0xFFFF ) 1968 nRelPos++; 1969 1970 sal_Int16 nDepth = pPara->GetDepth(); 1971 pPara = pParaList->GetParagraph( ++nPara ); 1972 if ( !bRecalcChilds ) 1973 { 1974 while ( pPara && ( pPara->GetDepth() > nDepth ) ) 1975 pPara = pParaList->GetParagraph( ++nPara ); 1976 } 1977 1978 if ( pPara && ( pPara->GetDepth() < nDepth ) ) 1979 pPara = NULL; 1980 } 1981 else 1982 { 1983 pPara = NULL; 1984 } 1985 } 1986 } 1987 1988 void Outliner::Clear() 1989 { 1990 DBG_CHKTHIS(Outliner,0); 1991 1992 if( !bFirstParaIsEmpty ) 1993 { 1994 ImplBlockInsertionCallbacks( sal_True ); 1995 pEditEngine->Clear(); 1996 pParaList->Clear( sal_True ); 1997 pParaList->Insert( new Paragraph( nMinDepth ), LIST_APPEND ); 1998 bFirstParaIsEmpty = sal_True; 1999 ImplBlockInsertionCallbacks( sal_False ); 2000 } 2001 else 2002 { 2003 Paragraph* pPara = pParaList->GetParagraph( 0 ); 2004 if(pPara) 2005 pPara->SetDepth( nMinDepth ); 2006 } 2007 } 2008 2009 void Outliner::SetFlatMode( sal_Bool bFlat ) 2010 { 2011 DBG_CHKTHIS(Outliner,0); 2012 2013 if( bFlat != pEditEngine->IsFlatMode() ) 2014 { 2015 for ( sal_uInt16 nPara = (sal_uInt16)pParaList->GetParagraphCount(); nPara; ) 2016 pParaList->GetParagraph( --nPara )->aBulSize.Width() = -1; 2017 2018 pEditEngine->SetFlatMode( bFlat ); 2019 } 2020 } 2021 2022 String Outliner::ImplGetBulletText( sal_uInt16 nPara ) 2023 { 2024 String aRes; 2025 Paragraph* pPara = pParaList->GetParagraph( nPara ); 2026 if (pPara) 2027 { 2028 // MT: Optimierung mal wieder aktivieren... 2029 // if( pPara->nFlags & PARAFLAG_SETBULLETTEXT ) 2030 ImplCalcBulletText( nPara, sal_False, sal_False ); 2031 aRes = pPara->GetText(); 2032 } 2033 return aRes; 2034 } 2035 2036 // this is needed for StarOffice Api 2037 void Outliner::SetLevelDependendStyleSheet( sal_uInt16 nPara ) 2038 { 2039 SfxItemSet aOldAttrs( pEditEngine->GetParaAttribs( nPara ) ); 2040 ImplSetLevelDependendStyleSheet( nPara ); 2041 pEditEngine->SetParaAttribs( nPara, aOldAttrs ); 2042 } 2043 2044 SV_IMPL_PTRARR( NotifyList, EENotifyPtr ); 2045 2046 void Outliner::ImplBlockInsertionCallbacks( sal_Bool b ) 2047 { 2048 if ( b ) 2049 { 2050 bBlockInsCallback++; 2051 } 2052 else 2053 { 2054 DBG_ASSERT( bBlockInsCallback, "ImplBlockInsertionCallbacks ?!" ); 2055 bBlockInsCallback--; 2056 if ( !bBlockInsCallback ) 2057 { 2058 // Call blocked notify events... 2059 while ( pEditEngine->aNotifyCache.Count() ) 2060 { 2061 EENotify* pNotify = pEditEngine->aNotifyCache[0]; 2062 // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler... 2063 pEditEngine->aNotifyCache.Remove( 0 ); 2064 pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); 2065 delete pNotify; 2066 } 2067 } 2068 } 2069 } 2070 2071 IMPL_LINK( Outliner, EditEngineNotifyHdl, EENotify*, pNotify ) 2072 { 2073 if ( !bBlockInsCallback ) 2074 { 2075 pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); 2076 } 2077 else 2078 { 2079 EENotify* pNewNotify = new EENotify( *pNotify ); 2080 pEditEngine->aNotifyCache.Insert( pNewNotify, pEditEngine->aNotifyCache.Count() ); 2081 } 2082 2083 return 0; 2084 } 2085 2086 /** sets a link that is called at the beginning of a drag operation at an edit view */ 2087 void Outliner::SetBeginDropHdl( const Link& rLink ) 2088 { 2089 pEditEngine->SetBeginDropHdl( rLink ); 2090 } 2091 2092 Link Outliner::GetBeginDropHdl() const 2093 { 2094 return pEditEngine->GetBeginDropHdl(); 2095 } 2096 2097 /** sets a link that is called at the end of a drag operation at an edit view */ 2098 void Outliner::SetEndDropHdl( const Link& rLink ) 2099 { 2100 pEditEngine->SetEndDropHdl( rLink ); 2101 } 2102 2103 Link Outliner::GetEndDropHdl() const 2104 { 2105 return pEditEngine->GetEndDropHdl(); 2106 } 2107 2108 /** sets a link that is called before a drop or paste operation. */ 2109 void Outliner::SetBeginPasteOrDropHdl( const Link& rLink ) 2110 { 2111 maBeginPasteOrDropHdl = rLink; 2112 } 2113 2114 /** sets a link that is called after a drop or paste operation. */ 2115 void Outliner::SetEndPasteOrDropHdl( const Link& rLink ) 2116 { 2117 maEndPasteOrDropHdl = rLink; 2118 } 2119 2120 void Outliner::SetParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) 2121 { 2122 if( pPara && !pPara->HasFlag( nFlag ) ) 2123 { 2124 if( IsUndoEnabled() && !IsInUndo() ) 2125 InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags|nFlag ) ); 2126 2127 pPara->SetFlag( nFlag ); 2128 } 2129 } 2130 2131 void Outliner::RemoveParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) 2132 { 2133 if( pPara && pPara->HasFlag( nFlag ) ) 2134 { 2135 if( IsUndoEnabled() && !IsInUndo() ) 2136 InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags & ~nFlag ) ); 2137 2138 pPara->RemoveFlag( nFlag ); 2139 } 2140 } 2141 2142 bool Outliner::HasParaFlag( const Paragraph* pPara, sal_uInt16 nFlag ) const 2143 { 2144 return pPara && pPara->HasFlag( nFlag ); 2145 } 2146 2147 2148 sal_Bool DrawPortionInfo::IsRTL() const 2149 { 2150 if(0xFF == mnBiDiLevel) 2151 { 2152 // Use Bidi functions from icu 2.0 to calculate if this portion 2153 // is RTL or not. 2154 UErrorCode nError(U_ZERO_ERROR); 2155 UBiDi* pBidi = ubidi_openSized(mrText.Len(), 0, &nError); 2156 nError = U_ZERO_ERROR; 2157 2158 // I do not have this info here. Is it necessary? I'll have to ask MT. 2159 const sal_uInt8 nDefaultDir = UBIDI_LTR; //IsRightToLeft( nPara ) ? UBIDI_RTL : UBIDI_LTR; 2160 2161 ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(mrText.GetBuffer()), mrText.Len(), nDefaultDir, NULL, &nError); // UChar != sal_Unicode in MinGW 2162 nError = U_ZERO_ERROR; 2163 2164 // sal_Int32 nCount(ubidi_countRuns(pBidi, &nError)); 2165 2166 int32_t nStart(0); 2167 int32_t nEnd; 2168 UBiDiLevel nCurrDir; 2169 2170 ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir); 2171 2172 ubidi_close(pBidi); 2173 2174 // remember on-demand calculated state 2175 ((DrawPortionInfo*)this)->mnBiDiLevel = nCurrDir; 2176 } 2177 2178 return (1 == (mnBiDiLevel % 2)); 2179 } 2180 2181 // eof 2182