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_uInt16 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_uInt16 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_uInt16 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_uInt16 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 substract 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_uInt16 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_uInt16 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 substract 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_uInt16 nParaStart, 375 const sal_uInt16 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_uInt16 nBulletsCount = 0; 385 sal_uInt16 nNumberingCount = 0; 386 for (sal_uInt16 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_uInt16 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_uInt16 nStartPara, sal_uInt16 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 beeing 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 substract 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 substract 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_uInt16 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_uInt16 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_uInt16 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_uInt16 nPara ) 796 { 797 Paragraph* pPara = pParaList->GetParagraph( nPara ); 798 if (pPara) 799 pPara->aBulSize.Width() = -1; 800 } 801 802 void Outliner::ImplSetLevelDependendStyleSheet( sal_uInt16 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_uInt16 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_uInt16 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_uInt16 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_uInt16 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_uInt16 nPara ) const 1520 { 1521 return GetNumberFormat(nPara) != 0; 1522 } 1523 1524 const SvxNumberFormat* Outliner::GetNumberFormat( sal_uInt16 nPara ) const 1525 { 1526 const SvxNumberFormat* pFmt = NULL; 1527 1528 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1529 if (pPara == NULL) 1530 return NULL; 1531 1532 sal_Int16 nDepth = pPara? pPara->GetDepth() : -1; 1533 1534 if( nDepth >= 0 ) 1535 { 1536 const SvxNumBulletItem& rNumBullet = (const SvxNumBulletItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_NUMBULLET ); 1537 if ( rNumBullet.GetNumRule()->GetLevelCount() > nDepth ) 1538 pFmt = rNumBullet.GetNumRule()->Get( nDepth ); 1539 } 1540 1541 return pFmt; 1542 } 1543 1544 Size Outliner::ImplGetBulletSize( sal_uInt16 nPara ) 1545 { 1546 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1547 if (!pPara) 1548 return Size(); 1549 1550 if( pPara->aBulSize.Width() == -1 ) 1551 { 1552 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1553 DBG_ASSERT( pFmt, "ImplGetBulletSize - no Bullet!" ); 1554 1555 if ( pFmt->GetNumberingType() == SVX_NUM_NUMBER_NONE ) 1556 { 1557 pPara->aBulSize = Size( 0, 0 ); 1558 } 1559 else if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) 1560 { 1561 String aBulletText = ImplGetBulletText( nPara ); 1562 OutputDevice* pRefDev = pEditEngine->GetRefDevice(); 1563 Font aBulletFont( ImpCalcBulletFont( nPara ) ); 1564 Font aRefFont( pRefDev->GetFont()); 1565 pRefDev->SetFont( aBulletFont ); 1566 pPara->aBulSize.Width() = pRefDev->GetTextWidth( aBulletText ); 1567 pPara->aBulSize.Height() = pRefDev->GetTextHeight(); 1568 pRefDev->SetFont( aRefFont ); 1569 } 1570 else 1571 { 1572 pPara->aBulSize = OutputDevice::LogicToLogic( pFmt->GetGraphicSize(), MAP_100TH_MM, pEditEngine->GetRefDevice()->GetMapMode() ); 1573 } 1574 } 1575 1576 return pPara->aBulSize; 1577 } 1578 1579 void Outliner::ImplCheckParagraphs( sal_uInt16 nStart, sal_uInt16 nEnd ) 1580 { 1581 DBG_CHKTHIS( Outliner, 0 ); 1582 1583 // --> OD 2009-03-10 #i100014# 1584 // assure that the following for-loop does not loop forever 1585 for ( sal_uInt16 n = nStart; n < nEnd; n++ ) 1586 // <-- 1587 { 1588 Paragraph* pPara = pParaList->GetParagraph( n ); 1589 if (pPara) 1590 { 1591 pPara->Invalidate(); 1592 ImplCalcBulletText( n, sal_False, sal_False ); 1593 } 1594 } 1595 } 1596 1597 void Outliner::SetRefDevice( OutputDevice* pRefDev ) 1598 { 1599 DBG_CHKTHIS(Outliner,0); 1600 pEditEngine->SetRefDevice( pRefDev ); 1601 for ( sal_uInt16 n = (sal_uInt16) pParaList->GetParagraphCount(); n; ) 1602 { 1603 Paragraph* pPara = pParaList->GetParagraph( --n ); 1604 pPara->Invalidate(); 1605 } 1606 } 1607 1608 void Outliner::ParaAttribsChanged( sal_uInt16 nPara ) 1609 { 1610 DBG_CHKTHIS(Outliner,0); 1611 1612 // Der Outliner hat kein eigenes Undo, wenn Absaetz getrennt/verschmolzen werden. 1613 // Beim ParagraphInserted ist das Attribut EE_PARA_OUTLLEVEL 1614 // ggf. noch nicht eingestellt, dies wird aber benoetigt um die Tiefe 1615 // des Absatzes zu bestimmen. 1616 1617 if( pEditEngine->IsInUndo() ) 1618 { 1619 if ( pParaList->GetParagraphCount() == pEditEngine->GetParagraphCount() ) 1620 { 1621 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1622 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); 1623 if ( pPara && pPara->GetDepth() != rLevel.GetValue() ) 1624 { 1625 pPara->SetDepth( rLevel.GetValue() ); 1626 ImplCalcBulletText( nPara, sal_True, sal_True ); 1627 } 1628 } 1629 } 1630 } 1631 1632 void Outliner::StyleSheetChanged( SfxStyleSheet* pStyle ) 1633 { 1634 DBG_CHKTHIS(Outliner,0); 1635 1636 // Die EditEngine ruft StyleSheetChanged auch fuer abgeleitete Styles. 1637 // MT: Hier wurde frueher alle Absaetze durch ein ImpRecalcParaAttribs 1638 // gejagt, die die besagte Vorlage haben, warum? 1639 // => Eigentlich kann sich nur die Bullet-Repraesentation aendern... 1640 1641 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount(); 1642 for( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) 1643 { 1644 if ( pEditEngine->GetStyleSheet( nPara ) == pStyle ) 1645 { 1646 ImplCheckNumBulletItem( nPara ); 1647 ImplCalcBulletText( nPara, sal_False, sal_False ); 1648 // #97333# EditEngine formats changed paragraphs before calling this method, 1649 // so they are not reformatted now and use wrong bullet indent 1650 pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) ); 1651 } 1652 } 1653 } 1654 1655 Rectangle Outliner::ImpCalcBulletArea( sal_uInt16 nPara, sal_Bool bAdjust, sal_Bool bReturnPaperPos ) 1656 { 1657 // Bullet-Bereich innerhalb des Absatzes... 1658 Rectangle aBulletArea; 1659 1660 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1661 if ( pFmt ) 1662 { 1663 Point aTopLeft; 1664 Size aBulletSize( ImplGetBulletSize( nPara ) ); 1665 1666 sal_Bool bOutlineMode = ( pEditEngine->GetControlWord() & EE_CNTRL_OUTLINER ) != 0; 1667 1668 // the ODF attribut text:space-before which holds the spacing to add to the left of the label 1669 const short nSpaceBefore = pFmt->GetAbsLSpace() + pFmt->GetFirstLineOffset(); 1670 1671 const SvxLRSpaceItem& rLR = (const SvxLRSpaceItem&) pEditEngine->GetParaAttrib( nPara, bOutlineMode ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE ); 1672 aTopLeft.X() = rLR.GetTxtLeft() + rLR.GetTxtFirstLineOfst() + nSpaceBefore; 1673 1674 long nBulletWidth = Max( (long) -rLR.GetTxtFirstLineOfst(), (long) ((-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance()) ); 1675 if ( nBulletWidth < aBulletSize.Width() ) // Bullet macht sich Platz 1676 nBulletWidth = aBulletSize.Width(); 1677 1678 if ( bAdjust && !bOutlineMode ) 1679 { 1680 // Bei zentriert/rechtsbuendig anpassen 1681 const SvxAdjustItem& rItem = (const SvxAdjustItem&)pEditEngine->GetParaAttrib( nPara, EE_PARA_JUST ); 1682 if ( ( !pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_LEFT ) ) || 1683 ( pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_RIGHT ) ) ) 1684 { 1685 aTopLeft.X() = pEditEngine->GetFirstLineStartX( nPara ) - nBulletWidth; 1686 } 1687 } 1688 1689 // Vertikal: 1690 ParagraphInfos aInfos = pEditEngine->GetParagraphInfos( nPara ); 1691 if ( aInfos.bValid ) 1692 { 1693 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ // #91076# nFirstLineOffset is already added to the StartPos (PaintBullet) from the EditEngine 1694 aInfos.nFirstLineHeight - aInfos.nFirstLineTextHeight 1695 + aInfos.nFirstLineTextHeight / 2 1696 - aBulletSize.Height() / 2; 1697 // ggf. lieber auf der Baseline ausgeben... 1698 if( ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) ) 1699 { 1700 Font aBulletFont( ImpCalcBulletFont( nPara ) ); 1701 if ( aBulletFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) 1702 { 1703 OutputDevice* pRefDev = pEditEngine->GetRefDevice(); 1704 Font aOldFont = pRefDev->GetFont(); 1705 pRefDev->SetFont( aBulletFont ); 1706 FontMetric aMetric( pRefDev->GetFontMetric() ); 1707 // Leading der ersten Zeile... 1708 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ aInfos.nFirstLineMaxAscent; 1709 aTopLeft.Y() -= aMetric.GetAscent(); 1710 pRefDev->SetFont( aOldFont ); 1711 } 1712 } 1713 } 1714 1715 // Horizontal: 1716 if( pFmt->GetNumAdjust() == SVX_ADJUST_RIGHT ) 1717 { 1718 aTopLeft.X() += nBulletWidth - aBulletSize.Width(); 1719 } 1720 else if( pFmt->GetNumAdjust() == SVX_ADJUST_CENTER ) 1721 { 1722 aTopLeft.X() += ( nBulletWidth - aBulletSize.Width() ) / 2; 1723 } 1724 1725 if ( aTopLeft.X() < 0 ) // dann draengeln 1726 aTopLeft.X() = 0; 1727 1728 aBulletArea = Rectangle( aTopLeft, aBulletSize ); 1729 } 1730 if ( bReturnPaperPos ) 1731 { 1732 Size aBulletSize( aBulletArea.GetSize() ); 1733 Point aBulletDocPos( aBulletArea.TopLeft() ); 1734 aBulletDocPos.Y() += pEditEngine->GetDocPosTopLeft( nPara ).Y(); 1735 Point aBulletPos( aBulletDocPos ); 1736 1737 if ( IsVertical() ) 1738 { 1739 aBulletPos.Y() = aBulletDocPos.X(); 1740 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.Y(); 1741 // Rotate: 1742 aBulletPos.X() -= aBulletSize.Height(); 1743 Size aSz( aBulletSize ); 1744 aBulletSize.Width() = aSz.Height(); 1745 aBulletSize.Height() = aSz.Width(); 1746 } 1747 else if ( pEditEngine->IsRightToLeft( nPara ) ) 1748 { 1749 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.X() - aBulletSize.Width(); 1750 } 1751 1752 aBulletArea = Rectangle( aBulletPos, aBulletSize ); 1753 } 1754 return aBulletArea; 1755 } 1756 1757 void Outliner::ExpandHdl() 1758 { 1759 DBG_CHKTHIS(Outliner,0); 1760 aExpandHdl.Call( this ); 1761 } 1762 1763 EBulletInfo Outliner::GetBulletInfo( sal_uInt16 nPara ) 1764 { 1765 EBulletInfo aInfo; 1766 1767 aInfo.nParagraph = nPara; 1768 aInfo.bVisible = ImplHasNumberFormat( nPara ) ? sal_True : sal_False; 1769 1770 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1771 aInfo.nType = pFmt ? pFmt->GetNumberingType() : 0; 1772 1773 if( pFmt ) 1774 { 1775 if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) 1776 { 1777 aInfo.aText = ImplGetBulletText( nPara ); 1778 1779 if( pFmt->GetBulletFont() ) 1780 aInfo.aFont = *pFmt->GetBulletFont(); 1781 } 1782 else if ( pFmt->GetBrush()->GetGraphicObject() ) 1783 { 1784 aInfo.aGraphic = pFmt->GetBrush()->GetGraphicObject()->GetGraphic(); 1785 } 1786 } 1787 1788 if ( aInfo.bVisible ) 1789 { 1790 aInfo.aBounds = ImpCalcBulletArea( nPara, sal_True, sal_True ); 1791 } 1792 1793 return aInfo; 1794 } 1795 1796 XubString Outliner::GetText( Paragraph* pParagraph, sal_uLong nCount ) const 1797 { 1798 DBG_CHKTHIS(Outliner,0); 1799 1800 XubString aText; 1801 sal_uInt16 nStartPara = (sal_uInt16) pParaList->GetAbsPos( pParagraph ); 1802 for ( sal_uInt16 n = 0; n < nCount; n++ ) 1803 { 1804 aText += pEditEngine->GetText( nStartPara + n ); 1805 if ( (n+1) < (sal_uInt16)nCount ) 1806 aText += '\n'; 1807 } 1808 return aText; 1809 } 1810 1811 void Outliner::Remove( Paragraph* pPara, sal_uLong nParaCount ) 1812 { 1813 DBG_CHKTHIS(Outliner,0); 1814 1815 sal_uLong nPos = pParaList->GetAbsPos( pPara ); 1816 if( !nPos && ( nParaCount >= pParaList->GetParagraphCount() ) ) 1817 { 1818 Clear(); 1819 } 1820 else 1821 { 1822 for( sal_uInt16 n = 0; n < (sal_uInt16)nParaCount; n++ ) 1823 pEditEngine->RemoveParagraph( (sal_uInt16) nPos ); 1824 } 1825 } 1826 1827 void Outliner::StripPortions() 1828 { 1829 DBG_CHKTHIS(Outliner,0); 1830 bStrippingPortions = sal_True; 1831 pEditEngine->StripPortions(); 1832 bStrippingPortions = sal_False; 1833 } 1834 1835 // #101498# 1836 void Outliner::DrawingText( const Point& rStartPos, const XubString& rText, sal_uInt16 nTextStart, sal_uInt16 nTextLen, const sal_Int32* pDXArray,const SvxFont& rFont, 1837 sal_uInt16 nPara, sal_uInt16 nIndex, sal_uInt8 nRightToLeft, 1838 const EEngineData::WrongSpellVector* pWrongSpellVector, 1839 const SvxFieldData* pFieldData, 1840 bool bEndOfLine, 1841 bool bEndOfParagraph, 1842 bool bEndOfBullet, 1843 const ::com::sun::star::lang::Locale* pLocale, 1844 const Color& rOverlineColor, 1845 const Color& rTextLineColor) 1846 { 1847 DBG_CHKTHIS(Outliner,0); 1848 1849 if(aDrawPortionHdl.IsSet()) 1850 { 1851 // #101498# 1852 DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, nIndex, pDXArray, pWrongSpellVector, 1853 pFieldData, pLocale, rOverlineColor, rTextLineColor, nRightToLeft, bEndOfLine, bEndOfParagraph, bEndOfBullet); 1854 1855 aDrawPortionHdl.Call( &aInfo ); 1856 } 1857 } 1858 1859 long Outliner::RemovingPagesHdl( OutlinerView* pView ) 1860 { 1861 DBG_CHKTHIS(Outliner,0); 1862 return aRemovingPagesHdl.IsSet() ? aRemovingPagesHdl.Call( pView ) : sal_True; 1863 } 1864 1865 sal_Bool Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView, sal_uInt16 _nFirstPage, sal_uInt16 nPages ) 1866 { 1867 DBG_CHKTHIS(Outliner,0); 1868 1869 nDepthChangedHdlPrevDepth = nPages; 1870 mnFirstSelPage = _nFirstPage; 1871 pHdlParagraph = 0; 1872 return (sal_Bool)RemovingPagesHdl( pCurView ); 1873 } 1874 1875 SfxItemSet Outliner::GetParaAttribs( sal_uInt16 nPara ) 1876 { 1877 DBG_CHKTHIS(Outliner,0); 1878 return pEditEngine->GetParaAttribs( nPara ); 1879 } 1880 1881 IMPL_LINK( Outliner, ParaVisibleStateChangedHdl, Paragraph*, pPara ) 1882 { 1883 DBG_CHKTHIS(Outliner,0); 1884 1885 sal_uLong nPara = pParaList->GetAbsPos( pPara ); 1886 pEditEngine->ShowParagraph( (sal_uInt16)nPara, pPara->IsVisible() ); 1887 1888 return 0; 1889 } 1890 1891 IMPL_LINK( Outliner, BeginMovingParagraphsHdl, MoveParagraphsInfo*, EMPTYARG ) 1892 { 1893 DBG_CHKTHIS(Outliner,0); 1894 1895 if( !IsInUndo() ) 1896 GetBeginMovingHdl().Call( this ); 1897 1898 return 0; 1899 } 1900 1901 IMPL_LINK( Outliner, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfos ) 1902 { 1903 UndoActionStart( EDITUNDO_DRAGANDDROP ); 1904 maBeginPasteOrDropHdl.Call(pInfos); 1905 return 0; 1906 } 1907 1908 IMPL_LINK( Outliner, EndPasteOrDropHdl, PasteOrDropInfos*, pInfos ) 1909 { 1910 bPasting = sal_False; 1911 ImpTextPasted( pInfos->nStartPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); 1912 maEndPasteOrDropHdl.Call( pInfos ); 1913 UndoActionEnd( EDITUNDO_DRAGANDDROP ); 1914 return 0; 1915 } 1916 1917 IMPL_LINK( Outliner, EndMovingParagraphsHdl, MoveParagraphsInfo*, pInfos ) 1918 { 1919 DBG_CHKTHIS(Outliner,0); 1920 1921 pParaList->MoveParagraphs( pInfos->nStartPara, pInfos->nDestPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); 1922 sal_uInt16 nChangesStart = Min( pInfos->nStartPara, pInfos->nDestPara ); 1923 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount(); 1924 for ( sal_uInt16 n = nChangesStart; n < nParas; n++ ) 1925 ImplCalcBulletText( n, sal_False, sal_False ); 1926 1927 if( !IsInUndo() ) 1928 aEndMovingHdl.Call( this ); 1929 1930 return 0; 1931 } 1932 1933 static bool isSameNumbering( const SvxNumberFormat& rN1, const SvxNumberFormat& rN2 ) 1934 { 1935 if( rN1.GetNumberingType() != rN2.GetNumberingType() ) 1936 return false; 1937 1938 if( rN1.GetNumStr(1) != rN2.GetNumStr(1) ) 1939 return false; 1940 1941 if( (rN1.GetPrefix() != rN2.GetPrefix()) || (rN1.GetSuffix() != rN2.GetSuffix()) ) 1942 return false; 1943 1944 return true; 1945 } 1946 1947 sal_uInt16 Outliner::ImplGetNumbering( sal_uInt16 nPara, const SvxNumberFormat* pParaFmt ) 1948 { 1949 sal_uInt16 nNumber = pParaFmt->GetStart() - 1; 1950 1951 Paragraph* pPara = pParaList->GetParagraph( nPara ); 1952 const sal_Int16 nParaDepth = pPara->GetDepth(); 1953 1954 do 1955 { 1956 pPara = pParaList->GetParagraph( nPara ); 1957 const sal_Int16 nDepth = pPara->GetDepth(); 1958 1959 // ignore paragraphs that are below our paragraph or have no numbering 1960 if( (nDepth > nParaDepth) || (nDepth == -1) ) 1961 continue; 1962 1963 // stop on paragraphs that are above our paragraph 1964 if( nDepth < nParaDepth ) 1965 break; 1966 1967 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 1968 1969 if( pFmt == 0 ) 1970 continue; // ignore paragraphs without bullets 1971 1972 // check if numbering less than or equal to pParaFmt 1973 if( !isSameNumbering( *pFmt, *pParaFmt ) || ( pFmt->GetStart() < pParaFmt->GetStart() ) ) 1974 break; 1975 1976 if ( pFmt->GetStart() > pParaFmt->GetStart() ) 1977 { 1978 nNumber += pFmt->GetStart() - pParaFmt->GetStart(); 1979 pParaFmt = pFmt; 1980 } 1981 1982 const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ); 1983 1984 if( rBulletState.GetValue() ) 1985 nNumber += 1; 1986 1987 // same depth, same number format, check for restart 1988 const sal_Int16 nNumberingStartValue = pPara->GetNumberingStartValue(); 1989 if( (nNumberingStartValue != -1) || pPara->IsParaIsNumberingRestart() ) 1990 { 1991 if( nNumberingStartValue != -1 ) 1992 nNumber += nNumberingStartValue - 1; 1993 break; 1994 } 1995 } 1996 while( nPara-- ); 1997 1998 return nNumber; 1999 } 2000 2001 void Outliner::ImplCalcBulletText( sal_uInt16 nPara, sal_Bool bRecalcLevel, sal_Bool bRecalcChilds ) 2002 { 2003 DBG_CHKTHIS(Outliner,0); 2004 2005 Paragraph* pPara = pParaList->GetParagraph( nPara ); 2006 sal_uInt16 nRelPos = 0xFFFF; 2007 2008 while ( pPara ) 2009 { 2010 XubString aBulletText; 2011 const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); 2012 if( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) ) 2013 { 2014 aBulletText += pFmt->GetPrefix(); 2015 if( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL ) 2016 { 2017 aBulletText += pFmt->GetBulletChar(); 2018 } 2019 else if( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) 2020 { 2021 aBulletText += pFmt->GetNumStr( ImplGetNumbering( nPara, pFmt ) ); 2022 } 2023 aBulletText += pFmt->GetSuffix(); 2024 } 2025 2026 if( aBulletText != pPara->GetText() ) 2027 pPara->SetText( aBulletText ); 2028 2029 pPara->nFlags &= (~PARAFLAG_SETBULLETTEXT); 2030 2031 if ( bRecalcLevel ) 2032 { 2033 if ( nRelPos != 0xFFFF ) 2034 nRelPos++; 2035 2036 sal_Int16 nDepth = pPara->GetDepth(); 2037 pPara = pParaList->GetParagraph( ++nPara ); 2038 if ( !bRecalcChilds ) 2039 { 2040 while ( pPara && ( pPara->GetDepth() > nDepth ) ) 2041 pPara = pParaList->GetParagraph( ++nPara ); 2042 } 2043 2044 if ( pPara && ( pPara->GetDepth() < nDepth ) ) 2045 pPara = NULL; 2046 } 2047 else 2048 { 2049 pPara = NULL; 2050 } 2051 } 2052 } 2053 2054 void Outliner::Clear() 2055 { 2056 DBG_CHKTHIS(Outliner,0); 2057 2058 if( !bFirstParaIsEmpty ) 2059 { 2060 ImplBlockInsertionCallbacks( sal_True ); 2061 pEditEngine->Clear(); 2062 pParaList->Clear( sal_True ); 2063 pParaList->Insert( new Paragraph( nMinDepth ), LIST_APPEND ); 2064 bFirstParaIsEmpty = sal_True; 2065 ImplBlockInsertionCallbacks( sal_False ); 2066 } 2067 else 2068 { 2069 Paragraph* pPara = pParaList->GetParagraph( 0 ); 2070 if(pPara) 2071 pPara->SetDepth( nMinDepth ); 2072 } 2073 } 2074 2075 void Outliner::SetFlatMode( sal_Bool bFlat ) 2076 { 2077 DBG_CHKTHIS(Outliner,0); 2078 2079 if( bFlat != pEditEngine->IsFlatMode() ) 2080 { 2081 for ( sal_uInt16 nPara = (sal_uInt16)pParaList->GetParagraphCount(); nPara; ) 2082 pParaList->GetParagraph( --nPara )->aBulSize.Width() = -1; 2083 2084 pEditEngine->SetFlatMode( bFlat ); 2085 } 2086 } 2087 2088 String Outliner::ImplGetBulletText( sal_uInt16 nPara ) 2089 { 2090 String aRes; 2091 Paragraph* pPara = pParaList->GetParagraph( nPara ); 2092 if (pPara) 2093 { 2094 // MT: Optimierung mal wieder aktivieren... 2095 // if( pPara->nFlags & PARAFLAG_SETBULLETTEXT ) 2096 ImplCalcBulletText( nPara, sal_False, sal_False ); 2097 aRes = pPara->GetText(); 2098 } 2099 return aRes; 2100 } 2101 2102 // this is needed for StarOffice Api 2103 void Outliner::SetLevelDependendStyleSheet( sal_uInt16 nPara ) 2104 { 2105 SfxItemSet aOldAttrs( pEditEngine->GetParaAttribs( nPara ) ); 2106 ImplSetLevelDependendStyleSheet( nPara ); 2107 pEditEngine->SetParaAttribs( nPara, aOldAttrs ); 2108 } 2109 2110 SV_IMPL_PTRARR( NotifyList, EENotifyPtr ); 2111 2112 void Outliner::ImplBlockInsertionCallbacks( sal_Bool b ) 2113 { 2114 if ( b ) 2115 { 2116 bBlockInsCallback++; 2117 } 2118 else 2119 { 2120 DBG_ASSERT( bBlockInsCallback, "ImplBlockInsertionCallbacks ?!" ); 2121 bBlockInsCallback--; 2122 if ( !bBlockInsCallback ) 2123 { 2124 // Call blocked notify events... 2125 while ( pEditEngine->aNotifyCache.Count() ) 2126 { 2127 EENotify* pNotify = pEditEngine->aNotifyCache[0]; 2128 // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler... 2129 pEditEngine->aNotifyCache.Remove( 0 ); 2130 pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); 2131 delete pNotify; 2132 } 2133 } 2134 } 2135 } 2136 2137 IMPL_LINK( Outliner, EditEngineNotifyHdl, EENotify*, pNotify ) 2138 { 2139 if ( !bBlockInsCallback ) 2140 { 2141 pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); 2142 } 2143 else 2144 { 2145 EENotify* pNewNotify = new EENotify( *pNotify ); 2146 pEditEngine->aNotifyCache.Insert( pNewNotify, pEditEngine->aNotifyCache.Count() ); 2147 } 2148 2149 return 0; 2150 } 2151 2152 /** sets a link that is called at the beginning of a drag operation at an edit view */ 2153 void Outliner::SetBeginDropHdl( const Link& rLink ) 2154 { 2155 pEditEngine->SetBeginDropHdl( rLink ); 2156 } 2157 2158 Link Outliner::GetBeginDropHdl() const 2159 { 2160 return pEditEngine->GetBeginDropHdl(); 2161 } 2162 2163 /** sets a link that is called at the end of a drag operation at an edit view */ 2164 void Outliner::SetEndDropHdl( const Link& rLink ) 2165 { 2166 pEditEngine->SetEndDropHdl( rLink ); 2167 } 2168 2169 Link Outliner::GetEndDropHdl() const 2170 { 2171 return pEditEngine->GetEndDropHdl(); 2172 } 2173 2174 /** sets a link that is called before a drop or paste operation. */ 2175 void Outliner::SetBeginPasteOrDropHdl( const Link& rLink ) 2176 { 2177 maBeginPasteOrDropHdl = rLink; 2178 } 2179 2180 /** sets a link that is called after a drop or paste operation. */ 2181 void Outliner::SetEndPasteOrDropHdl( const Link& rLink ) 2182 { 2183 maEndPasteOrDropHdl = rLink; 2184 } 2185 2186 void Outliner::SetParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) 2187 { 2188 if( pPara && !pPara->HasFlag( nFlag ) ) 2189 { 2190 if( IsUndoEnabled() && !IsInUndo() ) 2191 InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags|nFlag ) ); 2192 2193 pPara->SetFlag( nFlag ); 2194 } 2195 } 2196 2197 void Outliner::RemoveParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) 2198 { 2199 if( pPara && pPara->HasFlag( nFlag ) ) 2200 { 2201 if( IsUndoEnabled() && !IsInUndo() ) 2202 InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags & ~nFlag ) ); 2203 2204 pPara->RemoveFlag( nFlag ); 2205 } 2206 } 2207 2208 bool Outliner::HasParaFlag( const Paragraph* pPara, sal_uInt16 nFlag ) const 2209 { 2210 return pPara && pPara->HasFlag( nFlag ); 2211 } 2212 2213 2214 sal_Bool DrawPortionInfo::IsRTL() const 2215 { 2216 if(0xFF == mnBiDiLevel) 2217 { 2218 // Use Bidi functions from icu 2.0 to calculate if this portion 2219 // is RTL or not. 2220 UErrorCode nError(U_ZERO_ERROR); 2221 UBiDi* pBidi = ubidi_openSized(mrText.Len(), 0, &nError); 2222 nError = U_ZERO_ERROR; 2223 2224 // I do not have this info here. Is it necessary? I'll have to ask MT. 2225 const sal_uInt8 nDefaultDir = UBIDI_LTR; //IsRightToLeft( nPara ) ? UBIDI_RTL : UBIDI_LTR; 2226 2227 ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(mrText.GetBuffer()), mrText.Len(), nDefaultDir, NULL, &nError); // UChar != sal_Unicode in MinGW 2228 nError = U_ZERO_ERROR; 2229 2230 // sal_Int32 nCount(ubidi_countRuns(pBidi, &nError)); 2231 2232 int32_t nStart(0); 2233 int32_t nEnd; 2234 UBiDiLevel nCurrDir; 2235 2236 ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir); 2237 2238 ubidi_close(pBidi); 2239 2240 // remember on-demand calculated state 2241 ((DrawPortionInfo*)this)->mnBiDiLevel = nCurrDir; 2242 } 2243 2244 return (1 == (mnBiDiLevel % 2)); 2245 } 2246 2247 // eof 2248