Bump for 3.6-28
[LibreOffice.git] / editeng / source / outliner / outliner.cxx
blobffefcfb790043649c56c42792a30b45936d020d1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <comphelper/string.hxx>
31 #include <svl/intitem.hxx>
32 #include <editeng/editeng.hxx>
33 #include <editeng/editview.hxx>
34 #include <editeng/editdata.hxx>
35 #include <editeng/eerdll.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <editeng/fhgtitem.hxx>
39 #include <math.h>
40 #include <svl/style.hxx>
41 #include <vcl/wrkwin.hxx>
42 #define _OUTLINER_CXX
43 #include <editeng/outliner.hxx>
44 #include <paralist.hxx>
45 #include <editeng/outlobj.hxx>
46 #include <outleeng.hxx>
47 #include <outlundo.hxx>
48 #include <editeng/eeitem.hxx>
49 #include <editeng/editstat.hxx>
50 #include <editeng/scripttypeitem.hxx>
51 #include <editeng/editobj.hxx>
52 #include <svl/itemset.hxx>
53 #include <svl/whiter.hxx>
54 #include <vcl/metric.hxx>
55 #include <editeng/numitem.hxx>
56 #include <editeng/adjitem.hxx>
57 #include <vcl/graph.hxx>
58 #include <vcl/gdimtf.hxx>
59 #include <vcl/metaact.hxx>
60 #include <svtools/grfmgr.hxx>
61 #include <editeng/svxfont.hxx>
62 #include <editeng/brshitem.hxx>
63 #include <svl/itempool.hxx>
65 // calculate if it's RTL or not
66 #include <unicode/ubidi.h>
67 #include <cassert>
68 using ::std::advance;
70 #define DEFAULT_SCALE 75
72 static const sal_uInt16 nDefStyles = 3; // Special treatment for the first 3 levels
73 static const sal_uInt16 nDefBulletIndent = 800;
74 static const sal_uInt16 nDefBulletWidth = 700;
75 static const sal_uInt16 pDefBulletIndents[nDefStyles]= { 1400, 800, 800 };
76 static const sal_uInt16 pDefBulletWidths[nDefStyles] = { 1000, 850, 700 };
78 // ----------------------------------------------------------------------
79 // Outliner
80 // ----------------------------------------------------------------------
81 DBG_NAME(Outliner);
83 void Outliner::ImplCheckDepth( sal_Int16& rnDepth ) const
85 if( rnDepth < nMinDepth )
86 rnDepth = nMinDepth;
87 else if( rnDepth > nMaxDepth )
88 rnDepth = nMaxDepth;
91 Paragraph* Outliner::Insert(const XubString& rText, sal_uLong nAbsPos, sal_Int16 nDepth)
93 DBG_CHKTHIS(Outliner,0);
94 DBG_ASSERT(pParaList->GetParagraphCount(),"Insert:No Paras");
96 Paragraph* pPara;
98 ImplCheckDepth( nDepth );
100 sal_uLong nParagraphCount = pParaList->GetParagraphCount();
101 if( nAbsPos > nParagraphCount )
102 nAbsPos = nParagraphCount;
104 if( bFirstParaIsEmpty )
106 pPara = pParaList->GetParagraph( 0 );
107 if( pPara->GetDepth() != nDepth )
109 nDepthChangedHdlPrevDepth = pPara->GetDepth();
110 mnDepthChangeHdlPrevFlags = pPara->nFlags;
111 pPara->SetDepth( nDepth );
112 pHdlParagraph = pPara;
113 DepthChangedHdl();
115 pPara->nFlags |= PARAFLAG_HOLDDEPTH;
116 SetText( rText, pPara );
118 else
120 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
121 pEditEngine->SetUpdateMode( sal_False );
122 ImplBlockInsertionCallbacks( sal_True );
123 pPara = new Paragraph( nDepth );
124 pParaList->Insert( pPara, nAbsPos );
125 pEditEngine->InsertParagraph( (sal_uInt16)nAbsPos, String() );
126 DBG_ASSERT(pPara==pParaList->GetParagraph(nAbsPos),"Insert:Failed");
127 ImplInitDepth( (sal_uInt16)nAbsPos, nDepth, sal_False );
128 pHdlParagraph = pPara;
129 ParagraphInsertedHdl();
130 pPara->nFlags |= PARAFLAG_HOLDDEPTH;
131 SetText( rText, pPara );
132 ImplBlockInsertionCallbacks( sal_False );
133 pEditEngine->SetUpdateMode( bUpdate );
135 bFirstParaIsEmpty = sal_False;
136 DBG_ASSERT(pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(),"SetText failed");
137 return pPara;
141 void Outliner::ParagraphInserted( sal_uInt16 nPara )
143 DBG_CHKTHIS(Outliner,0);
145 if ( bBlockInsCallback )
146 return;
148 if( bPasting || pEditEngine->IsInUndo() )
150 Paragraph* pPara = new Paragraph( -1 );
151 pParaList->Insert( pPara, nPara );
152 if( pEditEngine->IsInUndo() )
154 pPara->nFlags = PARAFLAG_SETBULLETTEXT;
155 pPara->bVisible = sal_True;
156 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL );
157 pPara->SetDepth( rLevel.GetValue() );
160 else
162 sal_Int16 nDepth = -1;
163 Paragraph* pParaBefore = pParaList->GetParagraph( nPara-1 );
164 if ( pParaBefore )
165 nDepth = pParaBefore->GetDepth();
167 Paragraph* pPara = new Paragraph( nDepth );
168 pParaList->Insert( pPara, nPara );
170 if( !pEditEngine->IsInUndo() )
172 ImplCalcBulletText( nPara, sal_True, sal_False );
173 pHdlParagraph = pPara;
174 ParagraphInsertedHdl();
179 void Outliner::ParagraphDeleted( sal_uInt16 nPara )
181 DBG_CHKTHIS(Outliner,0);
183 if ( bBlockInsCallback || ( nPara == EE_PARA_ALL ) )
184 return;
186 Paragraph* pPara = pParaList->GetParagraph( nPara );
187 if (!pPara)
188 return;
190 sal_Int16 nDepth = pPara->GetDepth();
192 if( !pEditEngine->IsInUndo() )
194 pHdlParagraph = pPara;
195 ParagraphRemovingHdl();
198 pParaList->Remove( nPara );
199 delete pPara;
201 if( !pEditEngine->IsInUndo() && !bPasting )
203 pPara = pParaList->GetParagraph( nPara );
204 if ( pPara && ( pPara->GetDepth() > nDepth ) )
206 ImplCalcBulletText( nPara, sal_True, sal_False );
207 // Search for next on the this level ...
208 while ( pPara && pPara->GetDepth() > nDepth )
209 pPara = pParaList->GetParagraph( ++nPara );
212 if ( pPara && ( pPara->GetDepth() == nDepth ) )
213 ImplCalcBulletText( nPara, sal_True, sal_False );
217 void Outliner::Init( sal_uInt16 nMode )
219 nOutlinerMode = nMode;
221 Clear();
223 sal_uLong nCtrl = pEditEngine->GetControlWord();
224 nCtrl &= ~(EE_CNTRL_OUTLINER|EE_CNTRL_OUTLINER2);
226 SetMaxDepth( 9 );
228 switch ( ImplGetOutlinerMode() )
230 case OUTLINERMODE_TEXTOBJECT:
231 case OUTLINERMODE_TITLEOBJECT:
232 break;
234 case OUTLINERMODE_OUTLINEOBJECT:
235 nCtrl |= EE_CNTRL_OUTLINER2;
236 break;
237 case OUTLINERMODE_OUTLINEVIEW:
238 nCtrl |= EE_CNTRL_OUTLINER;
239 break;
241 default: OSL_FAIL( "Outliner::Init - Invalid Mode!" );
244 pEditEngine->SetControlWord( nCtrl );
246 ImplInitDepth( 0, GetMinDepth(), sal_False );
248 GetUndoManager().Clear();
251 void Outliner::SetMaxDepth( sal_Int16 nDepth, sal_Bool bCheckParagraphs )
253 if( nMaxDepth != nDepth )
255 nMaxDepth = Min( nDepth, (sal_Int16)(SVX_MAX_NUM-1) );
257 if( bCheckParagraphs )
259 sal_uInt16 nParagraphs = (sal_uInt16)pParaList->GetParagraphCount();
260 for ( sal_uInt16 nPara = 0; nPara < nParagraphs; nPara++ )
262 Paragraph* pPara = pParaList->GetParagraph( nPara );
263 if( pPara && pPara->GetDepth() > nMaxDepth )
265 SetDepth( pPara, nMaxDepth );
272 sal_Int16 Outliner::GetDepth( sal_uLong nPara ) const
274 Paragraph* pPara = pParaList->GetParagraph( nPara );
275 DBG_ASSERT( pPara, "Outliner::GetDepth - Paragraph not found!" );
276 return pPara ? pPara->GetDepth() : -1;
279 void Outliner::SetDepth( Paragraph* pPara, sal_Int16 nNewDepth )
281 DBG_CHKTHIS(Outliner,0);
283 ImplCheckDepth( nNewDepth );
285 if ( nNewDepth != pPara->GetDepth() )
287 nDepthChangedHdlPrevDepth = pPara->GetDepth();
288 mnDepthChangeHdlPrevFlags = pPara->nFlags;
289 pHdlParagraph = pPara;
291 sal_uInt16 nPara = (sal_uInt16)GetAbsPos( pPara );
292 ImplInitDepth( nPara, nNewDepth, sal_True );
293 ImplCalcBulletText( nPara, sal_False, sal_False );
295 if ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT )
296 ImplSetLevelDependendStyleSheet( nPara );
298 DepthChangedHdl();
302 sal_Int16 Outliner::GetNumberingStartValue( sal_uInt16 nPara )
304 Paragraph* pPara = pParaList->GetParagraph( nPara );
305 DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" );
306 return pPara ? pPara->GetNumberingStartValue() : -1;
309 void Outliner::SetNumberingStartValue( sal_uInt16 nPara, sal_Int16 nNumberingStartValue )
311 Paragraph* pPara = pParaList->GetParagraph( nPara );
312 DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" );
313 if( pPara && pPara->GetNumberingStartValue() != nNumberingStartValue )
315 if( IsUndoEnabled() && !IsInUndo() )
316 InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara,
317 pPara->GetNumberingStartValue(), nNumberingStartValue,
318 pPara->IsParaIsNumberingRestart(), pPara->IsParaIsNumberingRestart() ) );
320 pPara->SetNumberingStartValue( nNumberingStartValue );
321 // #i100014#
322 // It is not a good idea to substract 1 from a count and cast the result
323 // to USHORT without check, if the count is 0.
324 ImplCheckParagraphs( nPara, (sal_uInt16) (pParaList->GetParagraphCount()) );
325 pEditEngine->SetModified();
329 sal_Bool Outliner::IsParaIsNumberingRestart( sal_uInt16 nPara )
331 Paragraph* pPara = pParaList->GetParagraph( nPara );
332 DBG_ASSERT( pPara, "Outliner::IsParaIsNumberingRestart - Paragraph not found!" );
333 return pPara ? pPara->IsParaIsNumberingRestart() : sal_False;
336 void Outliner::SetParaIsNumberingRestart( sal_uInt16 nPara, sal_Bool bParaIsNumberingRestart )
338 Paragraph* pPara = pParaList->GetParagraph( nPara );
339 DBG_ASSERT( pPara, "Outliner::SetParaIsNumberingRestart - Paragraph not found!" );
340 if( pPara && (pPara->IsParaIsNumberingRestart() != bParaIsNumberingRestart) )
342 if( IsUndoEnabled() && !IsInUndo() )
343 InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara,
344 pPara->GetNumberingStartValue(), pPara->GetNumberingStartValue(),
345 pPara->IsParaIsNumberingRestart(), bParaIsNumberingRestart ) );
347 pPara->SetParaIsNumberingRestart( bParaIsNumberingRestart );
348 // #i100014#
349 // It is not a good idea to substract 1 from a count and cast the result
350 // to USHORT without check, if the count is 0.
351 ImplCheckParagraphs( nPara, (sal_uInt16) (pParaList->GetParagraphCount()) );
352 pEditEngine->SetModified();
356 OutlinerParaObject* Outliner::CreateParaObject( sal_uInt16 nStartPara, sal_uInt16 nCount ) const
358 DBG_CHKTHIS(Outliner,0);
360 if ( sal::static_int_cast< sal_uLong >( nStartPara + nCount ) >
361 pParaList->GetParagraphCount() )
362 nCount = sal::static_int_cast< sal_uInt16 >(
363 pParaList->GetParagraphCount() - nStartPara );
365 // When a new OutlinerParaObject is created because a paragraph is just beeing deleted,
366 // it can happen that the ParaList is not updated yet...
367 if ( ( nStartPara + nCount ) > pEditEngine->GetParagraphCount() )
368 nCount = pEditEngine->GetParagraphCount() - nStartPara;
370 if( !nCount )
371 return NULL;
373 EditTextObject* pText = pEditEngine->CreateTextObject( nStartPara, nCount );
374 const bool bIsEditDoc(OUTLINERMODE_TEXTOBJECT == ImplGetOutlinerMode());
375 ParagraphDataVector aParagraphDataVector(nCount);
376 const sal_uInt16 nLastPara(nStartPara + nCount - 1);
378 for(sal_uInt16 nPara(nStartPara); nPara <= nLastPara; nPara++)
380 aParagraphDataVector[nPara-nStartPara] = *GetParagraph(nPara);
383 OutlinerParaObject* pPObj = new OutlinerParaObject(*pText, aParagraphDataVector, bIsEditDoc);
384 pPObj->SetOutlinerMode(GetMode());
385 delete pText;
387 return pPObj;
390 void Outliner::SetText( const XubString& rText, Paragraph* pPara )
392 DBG_CHKTHIS(Outliner,0);
393 DBG_ASSERT(pPara,"SetText:No Para");
395 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
396 pEditEngine->SetUpdateMode( sal_False );
397 ImplBlockInsertionCallbacks( sal_True );
399 sal_uInt16 nPara = (sal_uInt16)pParaList->GetAbsPos( pPara );
401 if( !rText.Len() )
403 pEditEngine->SetText( nPara, rText );
404 ImplInitDepth( nPara, pPara->GetDepth(), sal_False );
406 else
408 XubString aText(convertLineEnd(rText, LINEEND_LF));
410 if( aText.GetChar( aText.Len()-1 ) == '\x0A' )
411 aText.Erase( aText.Len()-1, 1 ); // Delete the last break
413 sal_uInt16 nCount = comphelper::string::getTokenCount(aText, '\x0A');
414 sal_uInt16 nPos = 0;
415 sal_uInt16 nInsPos = nPara+1;
416 while( nCount > nPos )
418 XubString aStr = aText.GetToken( nPos, '\x0A' );
420 sal_Int16 nCurDepth;
421 if( nPos )
423 pPara = new Paragraph( -1 );
424 nCurDepth = -1;
426 else
427 nCurDepth = pPara->GetDepth();
429 // In the outliner mode, filter the tabs and set the indentation
430 // about a LRSpaceItem. In EditEngine mode intend over old tabs
431 if( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) ||
432 ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ) )
434 // Extract Tabs
435 sal_uInt16 nTabs = 0;
436 while ( ( nTabs < aStr.Len() ) && ( aStr.GetChar( nTabs ) == '\t' ) )
437 nTabs++;
438 if ( nTabs )
439 aStr.Erase( 0, nTabs );
441 // Keep depth? (see Outliner::Insert)
442 if( !(pPara->nFlags & PARAFLAG_HOLDDEPTH) )
444 nCurDepth = nTabs-1;
445 ImplCheckDepth( nCurDepth );
446 pPara->SetDepth( nCurDepth );
447 pPara->nFlags &= (~PARAFLAG_HOLDDEPTH);
450 if( nPos ) // not with the first paragraph
452 pParaList->Insert( pPara, nInsPos );
453 pEditEngine->InsertParagraph( nInsPos, aStr );
454 pHdlParagraph = pPara;
455 ParagraphInsertedHdl();
457 else
459 nInsPos--;
460 pEditEngine->SetText( nInsPos, aStr );
462 ImplInitDepth( nInsPos, nCurDepth, sal_False );
463 nInsPos++;
464 nPos++;
468 DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"SetText failed!");
469 bFirstParaIsEmpty = sal_False;
470 ImplBlockInsertionCallbacks( sal_False );
471 pEditEngine->SetUpdateMode( bUpdate );
474 // pView == 0 -> Ignore tabs
476 bool Outliner::ImpConvertEdtToOut( sal_uInt32 nPara,EditView* pView)
478 DBG_CHKTHIS(Outliner,0);
480 bool bConverted = false;
481 sal_uInt16 nTabs = 0;
482 ESelection aDelSel;
484 // const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (sal_uInt16)nPara );
485 // bool bAlreadyOutliner = rAttrs.GetItemState( EE_PARA_OUTLLRSPACE ) == SFX_ITEM_ON ? true : false;
487 XubString aName;
488 XubString aHeading_US( RTL_CONSTASCII_USTRINGPARAM( "heading" ) );
489 XubString aNumber_US( RTL_CONSTASCII_USTRINGPARAM( "Numbering" ) );
491 XubString aStr( pEditEngine->GetText( (sal_uInt16)nPara ) );
492 xub_Unicode* pPtr = (xub_Unicode*)aStr.GetBuffer();
494 sal_uInt16 nHeadingNumberStart = 0;
495 sal_uInt16 nNumberingNumberStart = 0;
496 SfxStyleSheet* pStyle= pEditEngine->GetStyleSheet( (sal_uInt16)nPara );
497 if( pStyle )
499 aName = pStyle->GetName();
500 sal_uInt16 nSearch;
501 if ( ( nSearch = aName.Search( aHeading_US ) ) != STRING_NOTFOUND )
502 nHeadingNumberStart = nSearch + aHeading_US.Len();
503 else if ( ( nSearch = aName.Search( aNumber_US ) ) != STRING_NOTFOUND )
504 nNumberingNumberStart = nSearch + aNumber_US.Len();
507 if ( nHeadingNumberStart || nNumberingNumberStart )
509 // PowerPoint import ?
510 if( nHeadingNumberStart && ( aStr.Len() >= 2 ) &&
511 ( pPtr[0] != '\t' ) && ( pPtr[1] == '\t' ) )
513 // Extract Bullet and Tab
514 aDelSel = ESelection( (sal_uInt16)nPara, 0, (sal_uInt16)nPara, 2 );
517 sal_uInt16 nPos = nHeadingNumberStart ? nHeadingNumberStart : nNumberingNumberStart;
518 String aLevel = aName.Copy( nPos );
519 aLevel.EraseLeadingChars( ' ' );
520 nTabs = sal::static_int_cast< sal_uInt16 >(aLevel.ToInt32());
521 if( nTabs )
522 nTabs--; // Level 0 = "heading 1"
523 bConverted = sal_True;
525 else
527 // filter leading tabs
528 while( *pPtr == '\t' )
530 pPtr++;
531 nTabs++;
533 // Remove tabs from the text
534 if( nTabs )
535 aDelSel = ESelection( (sal_uInt16)nPara, 0, (sal_uInt16)nPara, nTabs );
538 if ( aDelSel.HasRange() )
540 if ( pView )
542 pView->SetSelection( aDelSel );
543 pView->DeleteSelected();
545 else
546 pEditEngine->QuickDelete( aDelSel );
549 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( sal::static_int_cast< sal_uInt16 >(nPara), EE_PARA_OUTLLEVEL );
550 sal_Int16 nOutlLevel = rLevel.GetValue();
552 ImplCheckDepth( nOutlLevel );
553 ImplInitDepth( sal::static_int_cast< sal_uInt16 >(nPara), nOutlLevel, sal_False );
555 return bConverted;
558 void Outliner::SetText( const OutlinerParaObject& rPObj )
560 DBG_CHKTHIS(Outliner,0);
562 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
563 pEditEngine->SetUpdateMode( sal_False );
565 sal_Bool bUndo = pEditEngine->IsUndoEnabled();
566 EnableUndo( sal_False );
568 Init( rPObj.GetOutlinerMode() );
570 ImplBlockInsertionCallbacks( sal_True );
571 pEditEngine->SetText(rPObj.GetTextObject());
572 if( rPObj.Count() != pEditEngine->GetParagraphCount() )
574 int nop=0;nop++;
577 bFirstParaIsEmpty = sal_False;
579 pParaList->Clear( sal_True );
580 for( sal_uInt16 nCurPara = 0; nCurPara < rPObj.Count(); nCurPara++ )
582 Paragraph* pPara = new Paragraph( rPObj.GetParagraphData(nCurPara));
583 ImplCheckDepth( pPara->nDepth );
585 pParaList->Append(pPara);
586 ImplCheckNumBulletItem( nCurPara );
589 // #i100014#
590 // It is not a good idea to substract 1 from a count and cast the result
591 // to USHORT without check, if the count is 0.
592 ImplCheckParagraphs( 0, (sal_uInt16) (pParaList->GetParagraphCount()) );
594 EnableUndo( bUndo );
595 ImplBlockInsertionCallbacks( sal_False );
596 pEditEngine->SetUpdateMode( bUpdate );
598 DBG_ASSERT( pParaList->GetParagraphCount()==rPObj.Count(),"SetText failed");
599 DBG_ASSERT( pEditEngine->GetParagraphCount()==rPObj.Count(),"SetText failed");
602 void Outliner::AddText( const OutlinerParaObject& rPObj )
604 DBG_CHKTHIS(Outliner,0);
605 Paragraph* pPara;
607 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
608 pEditEngine->SetUpdateMode( sal_False );
610 ImplBlockInsertionCallbacks( sal_True );
611 sal_uLong nPara;
612 if( bFirstParaIsEmpty )
614 pParaList->Clear( sal_True );
615 pEditEngine->SetText(rPObj.GetTextObject());
616 nPara = 0;
618 else
620 nPara = pParaList->GetParagraphCount();
621 pEditEngine->InsertParagraph( EE_PARA_APPEND, rPObj.GetTextObject() );
623 bFirstParaIsEmpty = sal_False;
625 for( sal_uInt16 n = 0; n < rPObj.Count(); n++ )
627 pPara = new Paragraph( rPObj.GetParagraphData(n) );
628 pParaList->Append(pPara);
629 sal_uInt16 nP = sal::static_int_cast< sal_uInt16 >(nPara+n);
630 DBG_ASSERT(pParaList->GetAbsPos(pPara)==nP,"AddText:Out of sync");
631 ImplInitDepth( nP, pPara->GetDepth(), sal_False );
633 DBG_ASSERT( pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(), "SetText: OutOfSync" );
635 // #i100014#
636 // It is not a good idea to substract 1 from a count and cast the result
637 // to USHORT without check, if the count is 0.
638 ImplCheckParagraphs( (sal_uInt16)nPara, (sal_uInt16) (pParaList->GetParagraphCount()) );
640 ImplBlockInsertionCallbacks( sal_False );
641 pEditEngine->SetUpdateMode( bUpdate );
644 void Outliner::FieldClicked( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos )
646 DBG_CHKTHIS(Outliner,0);
648 if ( aFieldClickedHdl.IsSet() )
650 EditFieldInfo aFldInfo( this, rField, nPara, nPos );
651 aFldInfo.SetSimpleClick( sal_True );
652 aFieldClickedHdl.Call( &aFldInfo );
657 void Outliner::FieldSelected( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos )
659 DBG_CHKTHIS(Outliner,0);
660 if ( !aFieldClickedHdl.IsSet() )
661 return;
663 EditFieldInfo aFldInfo( this, rField, nPara, nPos );
664 aFldInfo.SetSimpleClick( sal_False );
665 aFieldClickedHdl.Call( &aFldInfo );
669 XubString Outliner::CalcFieldValue( const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos, Color*& rpTxtColor, Color*& rpFldColor )
671 DBG_CHKTHIS(Outliner,0);
672 if ( !aCalcFieldValueHdl.IsSet() )
673 return String( ' ' );
675 EditFieldInfo aFldInfo( this, rField, nPara, nPos );
676 // The FldColor is preset with COL_LIGHTGRAY.
677 if ( rpFldColor )
678 aFldInfo.SetFldColor( *rpFldColor );
680 aCalcFieldValueHdl.Call( &aFldInfo );
681 if ( aFldInfo.GetTxtColor() )
683 delete rpTxtColor;
684 rpTxtColor = new Color( *aFldInfo.GetTxtColor() );
687 delete rpFldColor;
688 rpFldColor = aFldInfo.GetFldColor() ? new Color( *aFldInfo.GetFldColor() ) : 0;
690 return aFldInfo.GetRepresentation();
693 void Outliner::SetStyleSheet( sal_uLong nPara, SfxStyleSheet* pStyle )
695 DBG_CHKTHIS(Outliner,0);
696 Paragraph* pPara = pParaList->GetParagraph( nPara );
697 if (pPara)
699 pEditEngine->SetStyleSheet( (sal_uInt16)nPara, pStyle );
700 pPara->nFlags |= PARAFLAG_SETBULLETTEXT;
701 ImplCheckNumBulletItem( (sal_uInt16) nPara );
705 void Outliner::ImplCheckNumBulletItem( sal_uInt16 nPara )
707 Paragraph* pPara = pParaList->GetParagraph( nPara );
708 if (pPara)
709 pPara->aBulSize.Width() = -1;
712 void Outliner::ImplSetLevelDependendStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pLevelStyle )
714 DBG_CHKTHIS(Outliner,0);
716 DBG_ASSERT( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) || ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ), "SetLevelDependendStyleSheet: Wrong Mode!" );
718 SfxStyleSheet* pStyle = pLevelStyle;
719 if ( !pStyle )
720 pStyle = GetStyleSheet( nPara );
722 if ( pStyle )
724 sal_Int16 nDepth = GetDepth( nPara );
725 if( nDepth < 0 )
726 nDepth = 0;
728 String aNewStyleSheetName( pStyle->GetName() );
729 aNewStyleSheetName.Erase( aNewStyleSheetName.Len()-1, 1 );
730 aNewStyleSheetName += String::CreateFromInt32( nDepth+1 );
731 SfxStyleSheet* pNewStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( aNewStyleSheetName, pStyle->GetFamily() );
732 DBG_ASSERT( pNewStyle, "AutoStyleSheetName - Style not found!" );
733 if ( pNewStyle && ( pNewStyle != GetStyleSheet( nPara ) ) )
735 SfxItemSet aOldAttrs( GetParaAttribs( nPara ) );
736 SetStyleSheet( nPara, pNewStyle );
737 if ( aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SFX_ITEM_ON )
739 SfxItemSet aAttrs( GetParaAttribs( nPara ) );
740 aAttrs.Put( aOldAttrs.Get( EE_PARA_NUMBULLET ) );
741 SetParaAttribs( nPara, aAttrs );
747 void Outliner::ImplInitDepth( sal_uInt16 nPara, sal_Int16 nDepth, sal_Bool bCreateUndo, sal_Bool bUndoAction )
749 DBG_CHKTHIS(Outliner,0);
751 DBG_ASSERT( ( nDepth >= nMinDepth ) && ( nDepth <= nMaxDepth ), "ImplInitDepth - Depth is invalid!" );
753 Paragraph* pPara = pParaList->GetParagraph( nPara );
754 if (!pPara)
755 return;
756 sal_Int16 nOldDepth = pPara->GetDepth();
757 pPara->SetDepth( nDepth );
759 // For IsInUndo attributes and style do not have to be set, there
760 // the old values are restored by the EditEngine.
761 if( !IsInUndo() )
763 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
764 pEditEngine->SetUpdateMode( sal_False );
766 sal_Bool bUndo = bCreateUndo && IsUndoEnabled();
767 if ( bUndo && bUndoAction )
768 UndoActionStart( OLUNDO_DEPTH );
770 SfxItemSet aAttrs( pEditEngine->GetParaAttribs( nPara ) );
771 aAttrs.Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nDepth ) );
772 pEditEngine->SetParaAttribs( nPara, aAttrs );
773 ImplCheckNumBulletItem( nPara );
774 ImplCalcBulletText( nPara, sal_False, sal_False );
776 if ( bUndo )
778 InsertUndo( new OutlinerUndoChangeDepth( this, nPara, nOldDepth, nDepth ) );
779 if ( bUndoAction )
780 UndoActionEnd( OLUNDO_DEPTH );
783 pEditEngine->SetUpdateMode( bUpdate );
787 void Outliner::SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet )
789 DBG_CHKTHIS(Outliner,0);
791 pEditEngine->SetParaAttribs( nPara, rSet );
794 sal_Bool Outliner::Expand( Paragraph* pPara )
796 DBG_CHKTHIS(Outliner,0);
798 if ( pParaList->HasHiddenChildren( pPara ) )
800 OLUndoExpand* pUndo = 0;
801 sal_Bool bUndo = IsUndoEnabled() && !IsInUndo();
802 if( bUndo )
804 UndoActionStart( OLUNDO_EXPAND );
805 pUndo = new OLUndoExpand( this, OLUNDO_EXPAND );
806 pUndo->pParas = 0;
807 pUndo->nCount = (sal_uInt16)pParaList->GetAbsPos( pPara );
809 pHdlParagraph = pPara;
810 bIsExpanding = sal_True;
811 pParaList->Expand( pPara );
812 ExpandHdl();
813 InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) );
814 if( bUndo )
816 InsertUndo( pUndo );
817 UndoActionEnd( OLUNDO_EXPAND );
819 return sal_True;
821 return sal_False;
825 sal_Bool Outliner::Collapse( Paragraph* pPara )
827 DBG_CHKTHIS(Outliner,0);
828 if ( pParaList->HasVisibleChildren( pPara ) ) // expanded
830 OLUndoExpand* pUndo = 0;
831 sal_Bool bUndo = sal_False;
833 if( !IsInUndo() && IsUndoEnabled() )
834 bUndo = sal_True;
835 if( bUndo )
837 UndoActionStart( OLUNDO_COLLAPSE );
838 pUndo = new OLUndoExpand( this, OLUNDO_COLLAPSE );
839 pUndo->pParas = 0;
840 pUndo->nCount = (sal_uInt16)pParaList->GetAbsPos( pPara );
843 pHdlParagraph = pPara;
844 bIsExpanding = sal_False;
845 pParaList->Collapse( pPara );
846 ExpandHdl();
847 InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) );
848 if( bUndo )
850 InsertUndo( pUndo );
851 UndoActionEnd( OLUNDO_COLLAPSE );
853 return sal_True;
855 return sal_False;
859 Font Outliner::ImpCalcBulletFont( sal_uInt16 nPara ) const
861 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
862 DBG_ASSERT( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ), "ImpCalcBulletFont: Missing or BitmapBullet!" );
864 Font aStdFont;
865 if ( !pEditEngine->IsFlatMode() )
867 ESelection aSel( nPara, 0, nPara, 0 );
868 aStdFont = EditEngine::CreateFontFromItemSet( pEditEngine->GetAttribs( aSel ), GetScriptType( aSel ) );
870 else
872 aStdFont = pEditEngine->GetStandardFont( nPara );
875 Font aBulletFont;
876 if ( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL )
878 aBulletFont = *pFmt->GetBulletFont();
880 else
882 aBulletFont = aStdFont;
883 aBulletFont.SetUnderline( UNDERLINE_NONE );
884 aBulletFont.SetOverline( UNDERLINE_NONE );
885 aBulletFont.SetStrikeout( STRIKEOUT_NONE );
886 aBulletFont.SetEmphasisMark( EMPHASISMARK_NONE );
887 aBulletFont.SetRelief( RELIEF_NONE );
890 // Use original scale...
891 sal_uInt16 nStretchX, nStretchY;
892 const_cast<Outliner*>(this)->GetGlobalCharStretching(nStretchX, nStretchY);
894 sal_uInt16 nScale = pFmt->GetBulletRelSize() * nStretchY / 100;
895 sal_uLong nScaledLineHeight = aStdFont.GetSize().Height();
896 nScaledLineHeight *= nScale*10;
897 nScaledLineHeight /= 1000;
899 aBulletFont.SetAlign( ALIGN_BOTTOM );
900 aBulletFont.SetSize( Size( 0, nScaledLineHeight ) );
901 sal_Bool bVertical = IsVertical();
902 aBulletFont.SetVertical( bVertical );
903 aBulletFont.SetOrientation( bVertical ? 2700 : 0 );
905 Color aColor( COL_AUTO );
906 if( !pEditEngine->IsFlatMode() && !( pEditEngine->GetControlWord() & EE_CNTRL_NOCOLORS ) )
908 aColor = pFmt->GetBulletColor();
911 if ( ( aColor == COL_AUTO ) || ( IsForceAutoColor() ) )
912 aColor = pEditEngine->GetAutoColor();
914 aBulletFont.SetColor( aColor );
915 return aBulletFont;
918 void Outliner::PaintBullet( sal_uInt16 nPara, const Point& rStartPos,
919 const Point& rOrigin, short nOrientation, OutputDevice* pOutDev )
921 DBG_CHKTHIS(Outliner,0);
923 bool bDrawBullet = false;
924 if (pEditEngine)
926 const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE );
927 bDrawBullet = rBulletState.GetValue() ? true : false;
930 if ( ImplHasBullet( nPara ) && bDrawBullet)
932 sal_Bool bVertical = IsVertical();
934 sal_Bool bRightToLeftPara = pEditEngine->IsRightToLeft( nPara );
936 Rectangle aBulletArea( ImpCalcBulletArea( nPara, sal_True, sal_False ) );
937 sal_uInt16 nStretchX, nStretchY;
938 GetGlobalCharStretching(nStretchX, nStretchY);
939 aBulletArea = Rectangle( Point(aBulletArea.Left()*nStretchX/100,
940 aBulletArea.Top()),
941 Size(aBulletArea.GetWidth()*nStretchX/100,
942 aBulletArea.GetHeight()) );
944 Paragraph* pPara = pParaList->GetParagraph( nPara );
945 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
946 if ( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) )
948 if( pFmt->GetNumberingType() != SVX_NUM_BITMAP )
950 Font aBulletFont( ImpCalcBulletFont( nPara ) );
951 // Use baseline
952 sal_Bool bSymbol = pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL;
953 aBulletFont.SetAlign( bSymbol ? ALIGN_BOTTOM : ALIGN_BASELINE );
954 Font aOldFont = pOutDev->GetFont();
955 pOutDev->SetFont( aBulletFont );
957 ParagraphInfos aParaInfos = pEditEngine->GetParagraphInfos( nPara );
958 Point aTextPos;
959 if ( !bVertical )
961 // aTextPos.Y() = rStartPos.Y() + aBulletArea.Bottom();
962 aTextPos.Y() = rStartPos.Y() + ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent );
963 if ( !bRightToLeftPara )
964 aTextPos.X() = rStartPos.X() + aBulletArea.Left();
965 else
966 aTextPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left();
968 else
970 // aTextPos.X() = rStartPos.X() - aBulletArea.Bottom();
971 aTextPos.X() = rStartPos.X() - ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent );
972 aTextPos.Y() = rStartPos.Y() + aBulletArea.Left();
975 if ( nOrientation )
977 // Both TopLeft and bottom left is not quite correct,
978 // since in EditEngine baseline ...
979 double nRealOrientation = nOrientation*F_PI1800;
980 double nCos = cos( nRealOrientation );
981 double nSin = sin( nRealOrientation );
982 Point aRotatedPos;
983 // Translation...
984 aTextPos -= rOrigin;
985 // Rotation...
986 aRotatedPos.X()=(long) (nCos*aTextPos.X() + nSin*aTextPos.Y());
987 aRotatedPos.Y()=(long) - (nSin*aTextPos.X() - nCos*aTextPos.Y());
988 aTextPos = aRotatedPos;
989 // Translation...
990 aTextPos += rOrigin;
991 Font aRotatedFont( aBulletFont );
992 aRotatedFont.SetOrientation( nOrientation );
993 pOutDev->SetFont( aRotatedFont );
996 // VCL will take care of brackets and so on...
997 sal_uLong nLayoutMode = pOutDev->GetLayoutMode();
998 nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG);
999 if ( bRightToLeftPara )
1000 nLayoutMode |= TEXT_LAYOUT_BIDI_RTL;
1001 pOutDev->SetLayoutMode( nLayoutMode );
1003 if(bStrippingPortions)
1005 const Font aSvxFont(pOutDev->GetFont());
1006 sal_Int32* pBuf = new sal_Int32[ pPara->GetText().Len() ];
1007 pOutDev->GetTextArray( pPara->GetText(), pBuf );
1009 if(bSymbol)
1011 // aTextPos is Bottom, go to Baseline
1012 FontMetric aMetric(pOutDev->GetFontMetric());
1013 aTextPos.Y() -= aMetric.GetDescent();
1016 DrawingText(aTextPos, pPara->GetText(), 0, pPara->GetText().Len(), pBuf,
1017 aSvxFont, nPara, 0xFFFF, 0xFF, 0, 0, false, false, true, 0, Color(), Color());
1019 delete[] pBuf;
1021 else
1023 pOutDev->DrawText( aTextPos, pPara->GetText() );
1026 pOutDev->SetFont( aOldFont );
1028 else
1030 if ( pFmt->GetBrush()->GetGraphicObject() )
1032 Point aBulletPos;
1033 if ( !bVertical )
1035 aBulletPos.Y() = rStartPos.Y() + aBulletArea.Top();
1036 if ( !bRightToLeftPara )
1037 aBulletPos.X() = rStartPos.X() + aBulletArea.Left();
1038 else
1039 aBulletPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Right();
1041 else
1043 aBulletPos.X() = rStartPos.X() - aBulletArea.Bottom();
1044 aBulletPos.Y() = rStartPos.Y() + aBulletArea.Left();
1047 if(bStrippingPortions)
1049 if(aDrawBulletHdl.IsSet())
1051 // call something analog to aDrawPortionHdl (if set) and feed it something
1052 // analog to DrawPortionInfo...
1053 // created aDrawBulletHdl, Set/GetDrawBulletHdl.
1054 // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx
1055 DrawBulletInfo aDrawBulletInfo(
1056 *pFmt->GetBrush()->GetGraphicObject(),
1057 aBulletPos,
1058 pPara->aBulSize);
1060 aDrawBulletHdl.Call(&aDrawBulletInfo);
1063 else
1065 // Remove CAST when KA made the Draw-Method const
1066 ((GraphicObject*)pFmt->GetBrush()->GetGraphicObject())->Draw( pOutDev, aBulletPos, pPara->aBulSize );
1072 // In case of collapsed subparagraphs paint a line before the text.
1073 if( pParaList->HasChildren(pPara) && !pParaList->HasVisibleChildren(pPara) &&
1074 !bStrippingPortions && !nOrientation )
1076 long nWidth = pOutDev->PixelToLogic( Size( 10, 0 ) ).Width();
1078 Point aStartPos, aEndPos;
1079 if ( !bVertical )
1081 aStartPos.Y() = rStartPos.Y() + aBulletArea.Bottom();
1082 if ( !bRightToLeftPara )
1083 aStartPos.X() = rStartPos.X() + aBulletArea.Right();
1084 else
1085 aStartPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left();
1086 aEndPos = aStartPos;
1087 aEndPos.X() += nWidth;
1089 else
1091 aStartPos.X() = rStartPos.X() - aBulletArea.Bottom();
1092 aStartPos.Y() = rStartPos.Y() + aBulletArea.Right();
1093 aEndPos = aStartPos;
1094 aEndPos.Y() += nWidth;
1097 const Color& rOldLineColor = pOutDev->GetLineColor();
1098 pOutDev->SetLineColor( Color( COL_BLACK ) );
1099 pOutDev->DrawLine( aStartPos, aEndPos );
1100 pOutDev->SetLineColor( rOldLineColor );
1105 void Outliner::InvalidateBullet( Paragraph* /*pPara*/, sal_uLong nPara )
1107 DBG_CHKTHIS(Outliner,0);
1109 long nLineHeight = (long)pEditEngine->GetLineHeight((sal_uInt16)nPara );
1110 for ( size_t i = 0, n = aViewList.size(); i < n; ++i )
1112 OutlinerView* pView = aViewList[ i ];
1113 Point aPos( pView->pEditView->GetWindowPosTopLeft((sal_uInt16)nPara ) );
1114 Rectangle aRect( pView->GetOutputArea() );
1115 aRect.Right() = aPos.X();
1116 aRect.Top() = aPos.Y();
1117 aRect.Bottom() = aPos.Y();
1118 aRect.Bottom() += nLineHeight;
1120 pView->GetWindow()->Invalidate( aRect );
1124 sal_uLong Outliner::Read( SvStream& rInput, const String& rBaseURL, sal_uInt16 eFormat, SvKeyValueIterator* pHTTPHeaderAttrs )
1126 DBG_CHKTHIS(Outliner,0);
1128 sal_Bool bOldUndo = pEditEngine->IsUndoEnabled();
1129 EnableUndo( sal_False );
1131 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
1132 pEditEngine->SetUpdateMode( sal_False );
1134 Clear();
1136 ImplBlockInsertionCallbacks( sal_True );
1137 sal_uLong nRet = pEditEngine->Read( rInput, rBaseURL, (EETextFormat)eFormat, pHTTPHeaderAttrs );
1139 bFirstParaIsEmpty = sal_False;
1141 sal_uInt16 nParas = pEditEngine->GetParagraphCount();
1142 pParaList->Clear( sal_True );
1143 sal_uInt16 n;
1144 for ( n = 0; n < nParas; n++ )
1146 Paragraph* pPara = new Paragraph( 0 );
1147 pParaList->Append(pPara);
1149 if ( eFormat == EE_FORMAT_BIN )
1151 const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( n );
1152 const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL );
1153 sal_Int16 nDepth = rLevel.GetValue();
1154 ImplInitDepth( n, nDepth, sal_False );
1158 if ( eFormat != EE_FORMAT_BIN )
1160 ImpFilterIndents( 0, nParas-1 );
1163 ImplBlockInsertionCallbacks( sal_False );
1164 pEditEngine->SetUpdateMode( bUpdate );
1165 EnableUndo( bOldUndo );
1167 return nRet;
1171 void Outliner::ImpFilterIndents( sal_uLong nFirstPara, sal_uLong nLastPara )
1173 DBG_CHKTHIS(Outliner,0);
1175 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
1176 pEditEngine->SetUpdateMode( sal_False );
1178 Paragraph* pLastConverted = NULL;
1179 for( sal_uLong nPara = nFirstPara; nPara <= nLastPara; nPara++ )
1181 Paragraph* pPara = pParaList->GetParagraph( nPara );
1182 if (pPara)
1184 if( ImpConvertEdtToOut( nPara ) )
1186 pLastConverted = pPara;
1188 else if ( pLastConverted )
1190 // Arrange normal paragraphs below the heading ...
1191 pPara->SetDepth( pLastConverted->GetDepth() );
1194 ImplInitDepth( (sal_uInt16)nPara, pPara->GetDepth(), sal_False );
1198 pEditEngine->SetUpdateMode( bUpdate );
1201 ::svl::IUndoManager& Outliner::GetUndoManager()
1203 DBG_CHKTHIS(Outliner,0);
1204 return pEditEngine->GetUndoManager();
1207 void Outliner::ImpTextPasted( sal_uLong nStartPara, sal_uInt16 nCount )
1209 DBG_CHKTHIS(Outliner,0);
1211 sal_Bool bUpdate = pEditEngine->GetUpdateMode();
1212 pEditEngine->SetUpdateMode( sal_False );
1214 const sal_uLong nStart = nStartPara;
1216 Paragraph* pPara = pParaList->GetParagraph( nStartPara );
1218 while( nCount && pPara )
1220 if( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT )
1222 nDepthChangedHdlPrevDepth = pPara->GetDepth();
1223 mnDepthChangeHdlPrevFlags = pPara->nFlags;
1225 ImpConvertEdtToOut( nStartPara );
1227 pHdlParagraph = pPara;
1229 if( nStartPara == nStart )
1231 // the existing paragraph has changed depth or flags
1232 if( (pPara->GetDepth() != nDepthChangedHdlPrevDepth) || (pPara->nFlags != mnDepthChangeHdlPrevFlags) )
1233 DepthChangedHdl();
1236 else // EditEngine mode
1238 sal_Int16 nDepth = -1;
1239 const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (sal_uInt16)nStartPara );
1240 if ( rAttrs.GetItemState( EE_PARA_OUTLLEVEL ) == SFX_ITEM_ON )
1242 const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL );
1243 nDepth = rLevel.GetValue();
1245 if ( nDepth != GetDepth( nStartPara ) )
1246 ImplInitDepth( (sal_uInt16)nStartPara, nDepth, sal_False );
1249 nCount--;
1250 nStartPara++;
1251 pPara = pParaList->GetParagraph( nStartPara );
1254 pEditEngine->SetUpdateMode( bUpdate );
1256 DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"ImpTextPasted failed");
1259 long Outliner::IndentingPagesHdl( OutlinerView* pView )
1261 DBG_CHKTHIS(Outliner,0);
1262 if( !aIndentingPagesHdl.IsSet() )
1263 return 1;
1264 return aIndentingPagesHdl.Call( pView );
1267 sal_Bool Outliner::ImpCanIndentSelectedPages( OutlinerView* pCurView )
1269 DBG_CHKTHIS(Outliner,0);
1270 // The selected pages must already be set in advance through
1271 // ImpCalcSelectedPages
1273 // If the first paragraph is on level 0 it can not indented in any case,
1274 // possible there might be indentations in the following on the 0 level.
1275 if ( ( mnFirstSelPage == 0 ) && ( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) )
1277 if ( nDepthChangedHdlPrevDepth == 1 ) // is the only page
1278 return sal_False;
1279 else
1280 pCurView->ImpCalcSelectedPages( sal_False ); // without the first
1282 return (sal_Bool)IndentingPagesHdl( pCurView );
1286 sal_Bool Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView )
1288 DBG_CHKTHIS(Outliner,0);
1289 // The selected pages must already be set in advance through
1290 // ImpCalcSelectedPages
1291 return (sal_Bool)RemovingPagesHdl( pCurView );
1294 Outliner::Outliner( SfxItemPool* pPool, sal_uInt16 nMode )
1295 : nMinDepth( -1 )
1297 DBG_CTOR( Outliner, 0 );
1299 bStrippingPortions = sal_False;
1300 bPasting = sal_False;
1302 nFirstPage = 1;
1303 bBlockInsCallback = sal_False;
1305 nMaxDepth = 9;
1307 pParaList = new ParagraphList;
1308 pParaList->SetVisibleStateChangedHdl( LINK( this, Outliner, ParaVisibleStateChangedHdl ) );
1309 Paragraph* pPara = new Paragraph( 0 );
1310 pParaList->Append(pPara);
1311 bFirstParaIsEmpty = sal_True;
1313 pEditEngine = new OutlinerEditEng( this, pPool );
1314 pEditEngine->SetBeginMovingParagraphsHdl( LINK( this, Outliner, BeginMovingParagraphsHdl ) );
1315 pEditEngine->SetEndMovingParagraphsHdl( LINK( this, Outliner, EndMovingParagraphsHdl ) );
1316 pEditEngine->SetBeginPasteOrDropHdl( LINK( this, Outliner, BeginPasteOrDropHdl ) );
1317 pEditEngine->SetEndPasteOrDropHdl( LINK( this, Outliner, EndPasteOrDropHdl ) );
1319 Init( nMode );
1322 Outliner::~Outliner()
1324 DBG_DTOR(Outliner,0);
1326 pParaList->Clear( sal_True );
1327 delete pParaList;
1328 delete pEditEngine;
1331 size_t Outliner::InsertView( OutlinerView* pView, size_t nIndex )
1333 DBG_CHKTHIS(Outliner,0);
1334 size_t ActualIndex;
1336 if ( nIndex >= aViewList.size() )
1338 aViewList.push_back( pView );
1339 ActualIndex = aViewList.size() - 1;
1341 else
1343 ViewList::iterator it = aViewList.begin();
1344 advance( it, nIndex );
1345 ActualIndex = nIndex;
1347 pEditEngine->InsertView( pView->pEditView, (sal_uInt16)nIndex );
1348 return ActualIndex;
1351 OutlinerView* Outliner::RemoveView( OutlinerView* pView )
1353 DBG_CHKTHIS(Outliner,0);
1355 for ( ViewList::iterator it = aViewList.begin(); it != aViewList.end(); ++it )
1357 if ( *it == pView )
1359 pView->pEditView->HideCursor(); // HACK
1360 pEditEngine->RemoveView( pView->pEditView );
1361 aViewList.erase( it );
1362 break;
1365 return NULL; // return superfluous
1368 OutlinerView* Outliner::RemoveView( size_t nIndex )
1370 DBG_CHKTHIS(Outliner,0);
1372 EditView* pEditView = pEditEngine->GetView( (sal_uInt16)nIndex );
1373 pEditView->HideCursor(); // HACK
1375 pEditEngine->RemoveView( (sal_uInt16)nIndex );
1378 ViewList::iterator it = aViewList.begin();
1379 advance( it, nIndex );
1380 aViewList.erase( it );
1383 return NULL; // return superfluous
1387 OutlinerView* Outliner::GetView( size_t nIndex ) const
1389 DBG_CHKTHIS(Outliner,0);
1390 return ( nIndex >= aViewList.size() ) ? NULL : aViewList[ nIndex ];
1393 size_t Outliner::GetViewCount() const
1395 DBG_CHKTHIS(Outliner,0);
1396 return aViewList.size();
1399 void Outliner::ParagraphInsertedHdl()
1401 DBG_CHKTHIS(Outliner,0);
1402 if( !IsInUndo() )
1403 aParaInsertedHdl.Call( this );
1407 void Outliner::ParagraphRemovingHdl()
1409 DBG_CHKTHIS(Outliner,0);
1410 if( !IsInUndo() )
1411 aParaRemovingHdl.Call( this );
1415 void Outliner::DepthChangedHdl()
1417 DBG_CHKTHIS(Outliner,0);
1418 if( !IsInUndo() )
1419 aDepthChangedHdl.Call( this );
1423 sal_uLong Outliner::GetAbsPos( Paragraph* pPara )
1425 DBG_CHKTHIS(Outliner,0);
1426 DBG_ASSERT(pPara,"GetAbsPos:No Para");
1427 return pParaList->GetAbsPos( pPara );
1430 sal_uLong Outliner::GetParagraphCount() const
1432 DBG_CHKTHIS(Outliner,0);
1433 return pParaList->GetParagraphCount();
1436 Paragraph* Outliner::GetParagraph( sal_uLong nAbsPos ) const
1438 DBG_CHKTHIS(Outliner,0);
1439 return pParaList->GetParagraph( nAbsPos );
1442 sal_Bool Outliner::HasChildren( Paragraph* pParagraph ) const
1444 DBG_CHKTHIS(Outliner,0);
1445 return pParaList->HasChildren( pParagraph );
1448 sal_Bool Outliner::ImplHasBullet( sal_uInt16 nPara ) const
1450 return GetNumberFormat(nPara) != 0;
1453 const SvxNumberFormat* Outliner::GetNumberFormat( sal_uInt16 nPara ) const
1455 const SvxNumberFormat* pFmt = NULL;
1457 Paragraph* pPara = pParaList->GetParagraph( nPara );
1458 if (pPara == NULL)
1459 return NULL;
1461 sal_Int16 nDepth = pPara? pPara->GetDepth() : -1;
1463 if( nDepth >= 0 )
1465 const SvxNumBulletItem& rNumBullet = (const SvxNumBulletItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_NUMBULLET );
1466 if ( rNumBullet.GetNumRule()->GetLevelCount() > nDepth )
1467 pFmt = rNumBullet.GetNumRule()->Get( nDepth );
1470 return pFmt;
1473 Size Outliner::ImplGetBulletSize( sal_uInt16 nPara )
1475 Paragraph* pPara = pParaList->GetParagraph( nPara );
1476 if (!pPara)
1477 return Size();
1479 if( pPara->aBulSize.Width() == -1 )
1481 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
1482 DBG_ASSERT( pFmt, "ImplGetBulletSize - no Bullet!" );
1484 if ( pFmt->GetNumberingType() == SVX_NUM_NUMBER_NONE )
1486 pPara->aBulSize = Size( 0, 0 );
1488 else if( pFmt->GetNumberingType() != SVX_NUM_BITMAP )
1490 String aBulletText = ImplGetBulletText( nPara );
1491 OutputDevice* pRefDev = pEditEngine->GetRefDevice();
1492 Font aBulletFont( ImpCalcBulletFont( nPara ) );
1493 Font aRefFont( pRefDev->GetFont());
1494 pRefDev->SetFont( aBulletFont );
1495 pPara->aBulSize.Width() = pRefDev->GetTextWidth( aBulletText );
1496 pPara->aBulSize.Height() = pRefDev->GetTextHeight();
1497 pRefDev->SetFont( aRefFont );
1499 else
1501 pPara->aBulSize = OutputDevice::LogicToLogic( pFmt->GetGraphicSize(), MAP_100TH_MM, pEditEngine->GetRefDevice()->GetMapMode() );
1505 return pPara->aBulSize;
1508 void Outliner::ImplCheckParagraphs( sal_uInt16 nStart, sal_uInt16 nEnd )
1510 DBG_CHKTHIS( Outliner, 0 );
1512 // i100014#
1513 // assure that the following for-loop does not loop forever
1514 for ( sal_uInt16 n = nStart; n < nEnd; n++ )
1516 Paragraph* pPara = pParaList->GetParagraph( n );
1517 if (pPara)
1519 pPara->Invalidate();
1520 ImplCalcBulletText( n, sal_False, sal_False );
1525 void Outliner::SetRefDevice( OutputDevice* pRefDev )
1527 DBG_CHKTHIS(Outliner,0);
1528 pEditEngine->SetRefDevice( pRefDev );
1529 for ( sal_uInt16 n = (sal_uInt16) pParaList->GetParagraphCount(); n; )
1531 Paragraph* pPara = pParaList->GetParagraph( --n );
1532 pPara->Invalidate();
1536 void Outliner::ParaAttribsChanged( sal_uInt16 nPara )
1538 DBG_CHKTHIS(Outliner,0);
1540 // The Outliner does not have an undo of its own, when paragraphs are
1541 // separated/merged. When ParagraphInserted the attribute EE_PARA_OUTLLEVEL
1542 // may not be set, this is however needed when the depth of the paragraph
1543 // is to be determined.
1544 if( pEditEngine->IsInUndo() )
1546 if ( pParaList->GetParagraphCount() == pEditEngine->GetParagraphCount() )
1548 Paragraph* pPara = pParaList->GetParagraph( nPara );
1549 const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL );
1550 if ( pPara && pPara->GetDepth() != rLevel.GetValue() )
1552 pPara->SetDepth( rLevel.GetValue() );
1553 ImplCalcBulletText( nPara, sal_True, sal_True );
1559 void Outliner::StyleSheetChanged( SfxStyleSheet* pStyle )
1561 DBG_CHKTHIS(Outliner,0);
1563 // The EditEngine calls StyleSheetChanged also for derived styles.
1564 // Here all the paragraphs, which had the said template, used to be
1565 // hunted by a ImpRecalcParaAttribs, why?
1566 // => only the Bullet-representation can really change...
1567 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount();
1568 for( sal_uInt16 nPara = 0; nPara < nParas; nPara++ )
1570 if ( pEditEngine->GetStyleSheet( nPara ) == pStyle )
1572 ImplCheckNumBulletItem( nPara );
1573 ImplCalcBulletText( nPara, sal_False, sal_False );
1574 // EditEngine formats changed paragraphs before calling this method,
1575 // so they are not reformatted now and use wrong bullet indent
1576 pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) );
1581 Rectangle Outliner::ImpCalcBulletArea( sal_uInt16 nPara, sal_Bool bAdjust, sal_Bool bReturnPaperPos )
1583 // Bullet area within the paragraph ...
1584 Rectangle aBulletArea;
1586 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
1587 if ( pFmt )
1589 Point aTopLeft;
1590 Size aBulletSize( ImplGetBulletSize( nPara ) );
1592 sal_Bool bOutlineMode = ( pEditEngine->GetControlWord() & EE_CNTRL_OUTLINER ) != 0;
1594 // the ODF attribut text:space-before which holds the spacing to add to the left of the label
1595 const short nSpaceBefore = pFmt->GetAbsLSpace() + pFmt->GetFirstLineOffset();
1597 const SvxLRSpaceItem& rLR = (const SvxLRSpaceItem&) pEditEngine->GetParaAttrib( nPara, bOutlineMode ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
1598 aTopLeft.X() = rLR.GetTxtLeft() + rLR.GetTxtFirstLineOfst() + nSpaceBefore;
1600 long nBulletWidth = Max( (long) -rLR.GetTxtFirstLineOfst(), (long) ((-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance()) );
1601 if ( nBulletWidth < aBulletSize.Width() ) // The Bullet creates its space
1602 nBulletWidth = aBulletSize.Width();
1604 if ( bAdjust && !bOutlineMode )
1606 // Adjust when centered or align right
1607 const SvxAdjustItem& rItem = (const SvxAdjustItem&)pEditEngine->GetParaAttrib( nPara, EE_PARA_JUST );
1608 if ( ( !pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_LEFT ) ) ||
1609 ( pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_RIGHT ) ) )
1611 aTopLeft.X() = pEditEngine->GetFirstLineStartX( nPara ) - nBulletWidth;
1615 // Vertical:
1616 ParagraphInfos aInfos = pEditEngine->GetParagraphInfos( nPara );
1617 if ( aInfos.bValid )
1619 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ // nFirstLineOffset is already added to the StartPos (PaintBullet) from the EditEngine
1620 aInfos.nFirstLineHeight - aInfos.nFirstLineTextHeight
1621 + aInfos.nFirstLineTextHeight / 2
1622 - aBulletSize.Height() / 2;
1623 // may prefer to print out on the baseline ...
1624 if( ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) )
1626 Font aBulletFont( ImpCalcBulletFont( nPara ) );
1627 if ( aBulletFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL )
1629 OutputDevice* pRefDev = pEditEngine->GetRefDevice();
1630 Font aOldFont = pRefDev->GetFont();
1631 pRefDev->SetFont( aBulletFont );
1632 FontMetric aMetric( pRefDev->GetFontMetric() );
1633 // Leading on the first line ...
1634 aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ aInfos.nFirstLineMaxAscent;
1635 aTopLeft.Y() -= aMetric.GetAscent();
1636 pRefDev->SetFont( aOldFont );
1641 // Horizontal:
1642 if( pFmt->GetNumAdjust() == SVX_ADJUST_RIGHT )
1644 aTopLeft.X() += nBulletWidth - aBulletSize.Width();
1646 else if( pFmt->GetNumAdjust() == SVX_ADJUST_CENTER )
1648 aTopLeft.X() += ( nBulletWidth - aBulletSize.Width() ) / 2;
1651 if ( aTopLeft.X() < 0 ) // then push
1652 aTopLeft.X() = 0;
1654 aBulletArea = Rectangle( aTopLeft, aBulletSize );
1656 if ( bReturnPaperPos )
1658 Size aBulletSize( aBulletArea.GetSize() );
1659 Point aBulletDocPos( aBulletArea.TopLeft() );
1660 aBulletDocPos.Y() += pEditEngine->GetDocPosTopLeft( nPara ).Y();
1661 Point aBulletPos( aBulletDocPos );
1663 if ( IsVertical() )
1665 aBulletPos.Y() = aBulletDocPos.X();
1666 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.Y();
1667 // Rotate:
1668 aBulletPos.X() -= aBulletSize.Height();
1669 Size aSz( aBulletSize );
1670 aBulletSize.Width() = aSz.Height();
1671 aBulletSize.Height() = aSz.Width();
1673 else if ( pEditEngine->IsRightToLeft( nPara ) )
1675 aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.X() - aBulletSize.Width();
1678 aBulletArea = Rectangle( aBulletPos, aBulletSize );
1680 return aBulletArea;
1683 void Outliner::ExpandHdl()
1685 DBG_CHKTHIS(Outliner,0);
1686 aExpandHdl.Call( this );
1689 EBulletInfo Outliner::GetBulletInfo( sal_uInt16 nPara )
1691 EBulletInfo aInfo;
1693 aInfo.nParagraph = nPara;
1694 aInfo.bVisible = ImplHasBullet( nPara );
1696 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
1697 aInfo.nType = pFmt ? pFmt->GetNumberingType() : 0;
1699 if( pFmt )
1701 if( pFmt->GetNumberingType() != SVX_NUM_BITMAP )
1703 aInfo.aText = ImplGetBulletText( nPara );
1705 if( pFmt->GetBulletFont() )
1706 aInfo.aFont = *pFmt->GetBulletFont();
1708 else if ( pFmt->GetBrush()->GetGraphicObject() )
1710 aInfo.aGraphic = pFmt->GetBrush()->GetGraphicObject()->GetGraphic();
1714 if ( aInfo.bVisible )
1716 aInfo.aBounds = ImpCalcBulletArea( nPara, sal_True, sal_True );
1719 return aInfo;
1722 XubString Outliner::GetText( Paragraph* pParagraph, sal_uLong nCount ) const
1724 DBG_CHKTHIS(Outliner,0);
1726 XubString aText;
1727 sal_uInt16 nStartPara = (sal_uInt16) pParaList->GetAbsPos( pParagraph );
1728 for ( sal_uInt16 n = 0; n < nCount; n++ )
1730 aText += pEditEngine->GetText( nStartPara + n );
1731 if ( (n+1) < (sal_uInt16)nCount )
1732 aText += '\n';
1734 return aText;
1737 void Outliner::Remove( Paragraph* pPara, sal_uLong nParaCount )
1739 DBG_CHKTHIS(Outliner,0);
1741 sal_uLong nPos = pParaList->GetAbsPos( pPara );
1742 if( !nPos && ( nParaCount >= pParaList->GetParagraphCount() ) )
1744 Clear();
1746 else
1748 for( sal_uInt16 n = 0; n < (sal_uInt16)nParaCount; n++ )
1749 pEditEngine->RemoveParagraph( (sal_uInt16) nPos );
1753 void Outliner::StripPortions()
1755 DBG_CHKTHIS(Outliner,0);
1756 bStrippingPortions = sal_True;
1757 pEditEngine->StripPortions();
1758 bStrippingPortions = sal_False;
1761 void Outliner::DrawingText( const Point& rStartPos, const XubString& rText, sal_uInt16 nTextStart, sal_uInt16 nTextLen, const sal_Int32* pDXArray,const SvxFont& rFont,
1762 sal_uInt16 nPara, sal_uInt16 nIndex, sal_uInt8 nRightToLeft,
1763 const EEngineData::WrongSpellVector* pWrongSpellVector,
1764 const SvxFieldData* pFieldData,
1765 bool bEndOfLine,
1766 bool bEndOfParagraph,
1767 bool bEndOfBullet,
1768 const ::com::sun::star::lang::Locale* pLocale,
1769 const Color& rOverlineColor,
1770 const Color& rTextLineColor)
1772 DBG_CHKTHIS(Outliner,0);
1774 if(aDrawPortionHdl.IsSet())
1776 DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, nIndex, pDXArray, pWrongSpellVector,
1777 pFieldData, pLocale, rOverlineColor, rTextLineColor, nRightToLeft, false, 0, bEndOfLine, bEndOfParagraph, bEndOfBullet);
1779 aDrawPortionHdl.Call( &aInfo );
1783 void Outliner::DrawingTab( const Point& rStartPos, long nWidth, const String& rChar, const SvxFont& rFont,
1784 sal_uInt16 nPara, xub_StrLen nIndex, sal_uInt8 nRightToLeft, bool bEndOfLine, bool bEndOfParagraph,
1785 const Color& rOverlineColor, const Color& rTextLineColor)
1787 if(aDrawPortionHdl.IsSet())
1789 DrawPortionInfo aInfo( rStartPos, rChar, 0, rChar.Len(), rFont, nPara, nIndex, NULL, NULL,
1790 NULL, NULL, rOverlineColor, rTextLineColor, nRightToLeft, true, nWidth, bEndOfLine, bEndOfParagraph, false);
1792 aDrawPortionHdl.Call( &aInfo );
1796 long Outliner::RemovingPagesHdl( OutlinerView* pView )
1798 DBG_CHKTHIS(Outliner,0);
1799 return aRemovingPagesHdl.IsSet() ? aRemovingPagesHdl.Call( pView ) : sal_True;
1802 sal_Bool Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView, sal_uInt16 _nFirstPage, sal_uInt16 nPages )
1804 DBG_CHKTHIS(Outliner,0);
1806 nDepthChangedHdlPrevDepth = nPages;
1807 mnFirstSelPage = _nFirstPage;
1808 pHdlParagraph = 0;
1809 return (sal_Bool)RemovingPagesHdl( pCurView );
1812 SfxItemSet Outliner::GetParaAttribs( sal_uInt16 nPara )
1814 DBG_CHKTHIS(Outliner,0);
1815 return pEditEngine->GetParaAttribs( nPara );
1818 IMPL_LINK( Outliner, ParaVisibleStateChangedHdl, Paragraph*, pPara )
1820 DBG_CHKTHIS(Outliner,0);
1822 sal_uLong nPara = pParaList->GetAbsPos( pPara );
1823 pEditEngine->ShowParagraph( (sal_uInt16)nPara, pPara->IsVisible() );
1825 return 0;
1828 IMPL_LINK_NOARG(Outliner, BeginMovingParagraphsHdl)
1830 DBG_CHKTHIS(Outliner,0);
1832 if( !IsInUndo() )
1833 GetBeginMovingHdl().Call( this );
1835 return 0;
1838 IMPL_LINK( Outliner, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfos )
1840 UndoActionStart( EDITUNDO_DRAGANDDROP );
1841 maBeginPasteOrDropHdl.Call(pInfos);
1842 return 0;
1845 IMPL_LINK( Outliner, EndPasteOrDropHdl, PasteOrDropInfos*, pInfos )
1847 bPasting = sal_False;
1848 ImpTextPasted( pInfos->nStartPara, pInfos->nEndPara - pInfos->nStartPara + 1 );
1849 maEndPasteOrDropHdl.Call( pInfos );
1850 UndoActionEnd( EDITUNDO_DRAGANDDROP );
1851 return 0;
1854 IMPL_LINK( Outliner, EndMovingParagraphsHdl, MoveParagraphsInfo*, pInfos )
1856 DBG_CHKTHIS(Outliner,0);
1858 pParaList->MoveParagraphs( pInfos->nStartPara, pInfos->nDestPara, pInfos->nEndPara - pInfos->nStartPara + 1 );
1859 sal_uInt16 nChangesStart = Min( pInfos->nStartPara, pInfos->nDestPara );
1860 sal_uInt16 nParas = (sal_uInt16)pParaList->GetParagraphCount();
1861 for ( sal_uInt16 n = nChangesStart; n < nParas; n++ )
1862 ImplCalcBulletText( n, sal_False, sal_False );
1864 if( !IsInUndo() )
1865 aEndMovingHdl.Call( this );
1867 return 0;
1870 static bool isSameNumbering( const SvxNumberFormat& rN1, const SvxNumberFormat& rN2 )
1872 if( rN1.GetNumberingType() != rN2.GetNumberingType() )
1873 return false;
1875 if( rN1.GetNumStr(1) != rN2.GetNumStr(1) )
1876 return false;
1878 if( (rN1.GetPrefix() != rN2.GetPrefix()) || (rN1.GetSuffix() != rN2.GetSuffix()) )
1879 return false;
1881 return true;
1884 sal_uInt16 Outliner::ImplGetNumbering( sal_uInt16 nPara, const SvxNumberFormat* pParaFmt )
1886 sal_uInt16 nNumber = pParaFmt->GetStart() - 1;
1888 Paragraph* pPara = pParaList->GetParagraph( nPara );
1889 const sal_Int16 nParaDepth = pPara->GetDepth();
1893 pPara = pParaList->GetParagraph( nPara );
1894 const sal_Int16 nDepth = pPara->GetDepth();
1896 // ignore paragraphs that are below our paragraph or have no numbering
1897 if( (nDepth > nParaDepth) || (nDepth == -1) )
1898 continue;
1900 // stop on paragraphs that are above our paragraph
1901 if( nDepth < nParaDepth )
1902 break;
1904 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
1906 if( pFmt == 0 )
1907 continue; // ignore paragraphs without bullets
1909 // check if numbering is the same
1910 if( !isSameNumbering( *pFmt, *pParaFmt ) )
1911 break;
1913 const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE );
1915 if( rBulletState.GetValue() )
1916 nNumber += 1;
1918 // same depth, same number format, check for restart
1919 const sal_Int16 nNumberingStartValue = pPara->GetNumberingStartValue();
1920 if( (nNumberingStartValue != -1) || pPara->IsParaIsNumberingRestart() )
1922 if( nNumberingStartValue != -1 )
1923 nNumber += nNumberingStartValue - 1;
1924 break;
1927 while( nPara-- );
1929 return nNumber;
1932 void Outliner::ImplCalcBulletText( sal_uInt16 nPara, sal_Bool bRecalcLevel, sal_Bool bRecalcChildren )
1934 DBG_CHKTHIS(Outliner,0);
1936 Paragraph* pPara = pParaList->GetParagraph( nPara );
1937 sal_uInt16 nRelPos = 0xFFFF;
1939 while ( pPara )
1941 XubString aBulletText;
1942 const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
1943 if( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) )
1945 aBulletText += pFmt->GetPrefix();
1946 if( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL )
1948 aBulletText += pFmt->GetBulletChar();
1950 else if( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE )
1952 aBulletText += pFmt->GetNumStr( ImplGetNumbering( nPara, pFmt ) );
1954 aBulletText += pFmt->GetSuffix();
1957 if( aBulletText != pPara->GetText() )
1958 pPara->SetText( aBulletText );
1960 pPara->nFlags &= (~PARAFLAG_SETBULLETTEXT);
1962 if ( bRecalcLevel )
1964 if ( nRelPos != 0xFFFF )
1965 nRelPos++;
1967 sal_Int16 nDepth = pPara->GetDepth();
1968 pPara = pParaList->GetParagraph( ++nPara );
1969 if ( !bRecalcChildren )
1971 while ( pPara && ( pPara->GetDepth() > nDepth ) )
1972 pPara = pParaList->GetParagraph( ++nPara );
1975 if ( pPara && ( pPara->GetDepth() < nDepth ) )
1976 pPara = NULL;
1978 else
1980 pPara = NULL;
1985 void Outliner::Clear()
1987 DBG_CHKTHIS(Outliner,0);
1989 if( !bFirstParaIsEmpty )
1991 ImplBlockInsertionCallbacks( sal_True );
1992 pEditEngine->Clear();
1993 pParaList->Clear( sal_True );
1994 pParaList->Append( new Paragraph( nMinDepth ));
1995 bFirstParaIsEmpty = sal_True;
1996 ImplBlockInsertionCallbacks( sal_False );
1998 else
2000 Paragraph* pPara = pParaList->GetParagraph( 0 );
2001 if(pPara)
2002 pPara->SetDepth( nMinDepth );
2006 void Outliner::SetFlatMode( sal_Bool bFlat )
2008 DBG_CHKTHIS(Outliner,0);
2010 if( bFlat != pEditEngine->IsFlatMode() )
2012 for ( sal_uInt16 nPara = (sal_uInt16)pParaList->GetParagraphCount(); nPara; )
2013 pParaList->GetParagraph( --nPara )->aBulSize.Width() = -1;
2015 pEditEngine->SetFlatMode( bFlat );
2019 String Outliner::ImplGetBulletText( sal_uInt16 nPara )
2021 String aRes;
2022 Paragraph* pPara = pParaList->GetParagraph( nPara );
2023 if (pPara)
2025 // Enable optimization again ...
2026 // if( pPara->nFlags & PARAFLAG_SETBULLETTEXT )
2027 ImplCalcBulletText( nPara, sal_False, sal_False );
2028 aRes = pPara->GetText();
2030 return aRes;
2033 // this is needed for StarOffice Api
2034 void Outliner::SetLevelDependendStyleSheet( sal_uInt16 nPara )
2036 SfxItemSet aOldAttrs( pEditEngine->GetParaAttribs( nPara ) );
2037 ImplSetLevelDependendStyleSheet( nPara );
2038 pEditEngine->SetParaAttribs( nPara, aOldAttrs );
2041 void Outliner::ImplBlockInsertionCallbacks( sal_Bool b )
2043 if ( b )
2045 bBlockInsCallback++;
2047 else
2049 DBG_ASSERT( bBlockInsCallback, "ImplBlockInsertionCallbacks ?!" );
2050 bBlockInsCallback--;
2051 if ( !bBlockInsCallback )
2053 // Call blocked notify events...
2054 while(!pEditEngine->aNotifyCache.empty())
2056 EENotify aNotify(pEditEngine->aNotifyCache.front());
2057 // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler...
2058 pEditEngine->aNotifyCache.erase(pEditEngine->aNotifyCache.begin());
2059 pEditEngine->aOutlinerNotifyHdl.Call( &aNotify );
2065 IMPL_LINK( Outliner, EditEngineNotifyHdl, EENotify*, pNotify )
2067 if ( !bBlockInsCallback )
2068 pEditEngine->aOutlinerNotifyHdl.Call( pNotify );
2069 else
2070 pEditEngine->aNotifyCache.push_back(*pNotify);
2072 return 0;
2075 /** sets a link that is called at the beginning of a drag operation at an edit view */
2076 void Outliner::SetBeginDropHdl( const Link& rLink )
2078 pEditEngine->SetBeginDropHdl( rLink );
2081 /** sets a link that is called at the end of a drag operation at an edit view */
2082 void Outliner::SetEndDropHdl( const Link& rLink )
2084 pEditEngine->SetEndDropHdl( rLink );
2087 /** sets a link that is called before a drop or paste operation. */
2088 void Outliner::SetBeginPasteOrDropHdl( const Link& rLink )
2090 maBeginPasteOrDropHdl = rLink;
2093 /** sets a link that is called after a drop or paste operation. */
2094 void Outliner::SetEndPasteOrDropHdl( const Link& rLink )
2096 maEndPasteOrDropHdl = rLink;
2099 void Outliner::SetParaFlag( Paragraph* pPara, sal_uInt16 nFlag )
2101 if( pPara && !pPara->HasFlag( nFlag ) )
2103 if( IsUndoEnabled() && !IsInUndo() )
2104 InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags|nFlag ) );
2106 pPara->SetFlag( nFlag );
2110 bool Outliner::HasParaFlag( const Paragraph* pPara, sal_uInt16 nFlag ) const
2112 return pPara && pPara->HasFlag( nFlag );
2116 sal_Bool DrawPortionInfo::IsRTL() const
2118 if(0xFF == mnBiDiLevel)
2120 // Use Bidi functions from icu 2.0 to calculate if this portion
2121 // is RTL or not.
2122 UErrorCode nError(U_ZERO_ERROR);
2123 UBiDi* pBidi = ubidi_openSized(mrText.Len(), 0, &nError);
2124 nError = U_ZERO_ERROR;
2126 // I do not have this info here. Is it necessary? I'll have to ask MT.
2127 const sal_uInt8 nDefaultDir = UBIDI_LTR; //IsRightToLeft( nPara ) ? UBIDI_RTL : UBIDI_LTR;
2129 ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(mrText.GetBuffer()), mrText.Len(), nDefaultDir, NULL, &nError); // UChar != sal_Unicode in MinGW
2130 nError = U_ZERO_ERROR;
2132 int32_t nStart(0);
2133 int32_t nEnd;
2134 UBiDiLevel nCurrDir;
2136 ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir);
2138 ubidi_close(pBidi);
2140 // remember on-demand calculated state
2141 ((DrawPortionInfo*)this)->mnBiDiLevel = nCurrDir;
2144 return (1 == (mnBiDiLevel % 2));
2147 // eof
2149 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */