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