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