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