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