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