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