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