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