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