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