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