/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "OutlineView.hxx"
#include <memory>
#include <editeng/forbiddencharacterstable.hxx>
#include <sfx2/progress.hxx>
#include <vcl/wrkwin.hxx>
#include <svx/svxids.hrc>
#include "eetext.hxx"
#include <editeng/eeitem.hxx>
#include <editeng/editstat.hxx>
#include <editeng/lrspitem.hxx>
#include <svx/svdotext.hxx>
#include <sfx2/printer.hxx>
#include <sfx2/imagemgr.hxx>
#include <sfx2/app.hxx>
#include <sfx2/bindings.hxx>
#include <svl/itempool.hxx>
#include <svl/style.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdundo.hxx>
#include <svl/brdcst.hxx>
#include <vcl/msgbox.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/tstpitem.hxx>
#include <editeng/lspcitem.hxx>
#include <editeng/numitem.hxx>
#include <editeng/outlobj.hxx>
#include <editeng/numitem.hxx>
#include <editeng/editeng.hxx>

// #97766#
#include <editeng/editobj.hxx>
#include <editeng/editund2.hxx>

#include <editeng/editview.hxx>
#include <editeng/svxfont.hxx>
#include <editeng/fhgtitem.hxx>

#include "DrawDocShell.hxx"
#include "drawdoc.hxx"
#include "Window.hxx"
#include "sdpage.hxx"
#include "pres.hxx"
#include "OutlineViewShell.hxx"
#include "app.hrc"
#include "glob.hrc"
#include "sdresid.hxx"
#include "Outliner.hxx"
#include "strings.hrc"
#include "EventMultiplexer.hxx"
#include "ViewShellBase.hxx"
#include "undo/undoobjects.hxx"
#include "undo/undomanager.hxx"
#include "stlsheet.hxx"

using ::rtl::OUString;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::frame;

namespace sd {

// Breite: DIN A 4,  zwei Raender zu je 1 cm
#define OUTLINE_PAPERWIDTH 19000

// beim Seitenmanipulation Fortschrittsanzeige, wenn mehr Seiten betroffen
// sind als:
#define PROCESS_WITH_PROGRESS_THRESHOLD  5

struct SdParaAndPos
{
	Paragraph* pPara;
	sal_uInt16	   nPos;
};

TYPEINIT1( OutlineView, ::sd::View );

/*************************************************************************
|*
|* Konstruktor
|*
\************************************************************************/

OutlineView::OutlineView( DrawDocShell* pDocSh, ::Window* pWindow, OutlineViewShell* pOutlineViewSh)
: ::sd::View(pDocSh->GetDoc(), pWindow, pOutlineViewSh)
, mpOutlineViewShell(pOutlineViewSh)
, mpOutliner( mpDoc->GetOutliner(sal_True) )
, mpOldParaOrder(NULL)
, mpSelectedParas(NULL)
, mnPagesToProcess(0)
, mnPagesProcessed(0)
, mbFirstPaint(sal_True)
, mpProgress(NULL)
, mbHighContrastMode( false )
, maDocColor( COL_WHITE )
, mnPageNumberWidthPixel( 0 )
, maLRSpaceItem( 0, 0, 2000, 0, EE_PARA_OUTLLRSPACE )
{
	sal_Bool bInitOutliner = sal_False;

	if (mpOutliner->GetViewCount() == 0)
	{
		// Outliner initialisieren: Referenz-Device setzen
		bInitOutliner = sal_True;
		mpOutliner->Init( OUTLINERMODE_OUTLINEVIEW );
/*
		SfxStyleSheet* pTitleSheet = mpDoc->GetSdPage( 0, PK_STANDARD )->GetStyleSheetForPresObj( PRESOBJ_TITLE );

		if ( pTitleSheet )
		{
			// set title symbol (level 0)
			SvxNumBulletItem aNumBulletItem( (const SvxNumBulletItem&) pTitleSheet->GetItemSet().Get(EE_PARA_NUMBULLET) );
			SvxNumRule aNumRule(* aNumBulletItem.GetNumRule());
			SvxNumberFormat aFormat( aNumRule.GetLevel(0));
            Font    aBulletFont;
            const Font* pFont = aFormat.GetBulletFont();
            if ( pFont )                                        // if available take font size and color from style
                aBulletFont = *pFont;
            else
            {
                aBulletFont.SetColor( COL_AUTO );
                aBulletFont.SetHeight( 1552 );
            }
            aBulletFont.SetCharSet(RTL_TEXTENCODING_MS_1252);   // and replacing other values by standard
            aBulletFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "StarSymbol" )) );
	        aBulletFont.SetWeight(WEIGHT_NORMAL);
	        aBulletFont.SetUnderline(UNDERLINE_NONE);
	        aBulletFont.SetStrikeout(STRIKEOUT_NONE);
	        aBulletFont.SetItalic(ITALIC_NONE);
	        aBulletFont.SetOutline(sal_False);
	        aBulletFont.SetShadow(sal_False);
            aFormat.SetBulletFont( &aBulletFont );
			aFormat.SetBulletChar( 0xE011 );  // StarBats: 0xF000 + 114
			mpOutliner->OverwriteLevel0Bullet( aFormat );
		}
*/
		mpOutliner->SetRefDevice( SD_MOD()->GetRefDevice( *pDocSh ) );
		sal_uLong nWidth = OUTLINE_PAPERWIDTH;
		mpOutliner->SetPaperSize(Size(nWidth, 400000000));
	}

	// View in Outliner einfuegen
	for (sal_uInt16 nView = 0; nView < MAX_OUTLINERVIEWS; nView++)
	{
		mpOutlinerView[nView] = NULL;
	}

	mpOutlinerView[0] = new OutlinerView(mpOutliner, pWindow);
	Rectangle aNullRect;
	mpOutlinerView[0]->SetOutputArea(aNullRect);
	mpOutliner->SetUpdateMode(sal_False);
	mpOutliner->InsertView(mpOutlinerView[0], LIST_APPEND);

	onUpdateStyleSettings( true );

	if (bInitOutliner)
	{
		// Outliner mit Inhalt fuellen
		FillOutliner();
	}

	Link aLink( LINK(this,OutlineView,EventMultiplexerListener) );
    mpOutlineViewShell->GetViewShellBase().GetEventMultiplexer()->AddEventListener(
        aLink,
        tools::EventMultiplexerEvent::EID_CURRENT_PAGE
        | tools::EventMultiplexerEvent::EID_PAGE_ORDER);

	LanguageType eLang = mpOutliner->GetDefaultLanguage();
	maPageNumberFont = OutputDevice::GetDefaultFont( DEFAULTFONT_SANS_UNICODE, eLang, 0 );
	maPageNumberFont.SetHeight( 500 );

	maBulletFont.SetColor( COL_AUTO );
	maBulletFont.SetHeight( 1000 );
	maBulletFont.SetCharSet(RTL_TEXTENCODING_MS_1252);   // and replacing other values by standard
    maBulletFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "StarSymbol" )) );
    maBulletFont.SetWeight(WEIGHT_NORMAL);
    maBulletFont.SetUnderline(UNDERLINE_NONE);
    maBulletFont.SetStrikeout(STRIKEOUT_NONE);
    maBulletFont.SetItalic(ITALIC_NONE);
    maBulletFont.SetOutline(sal_False);
    maBulletFont.SetShadow(sal_False);


	Reference<XFrame> xFrame (mpOutlineViewShell->GetViewShellBase().GetFrame()->GetTopFrame().GetFrameInterface(), UNO_QUERY);

    const OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( ".uno:ShowSlide" ));
    maSlideImage = GetImage( xFrame, aSlotURL, true, false /* todo, hc mode */ );

    // Tell undo manager of the document about the undo manager of the
    // outliner, so that the former can synchronize with the later.
    sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager());
    if (pDocUndoMgr != NULL)
        pDocUndoMgr->SetLinkedUndoManager(&mpOutliner->GetUndoManager());
}

/*************************************************************************
|*
|* Destruktor, Links restaurieren, Outliner leeren
|*
\************************************************************************/

OutlineView::~OutlineView()
{
	DBG_ASSERT(maDragAndDropModelGuard.get() == 0, "sd::OutlineView::~OutlineView(), prior drag operation not finished correctly!" );

	Link aLink( LINK(this,OutlineView,EventMultiplexerListener) );
    mpOutlineViewShell->GetViewShellBase().GetEventMultiplexer()->RemoveEventListener( aLink );
	DisconnectFromApplication();

	if( mpProgress )
		delete mpProgress;

	// OutlinerViews abmelden und zerstoeren
	for (sal_uInt16 nView = 0; nView < MAX_OUTLINERVIEWS; nView++)
	{
		if (mpOutlinerView[nView] != NULL)
		{
			mpOutliner->RemoveView( mpOutlinerView[nView] );
			delete mpOutlinerView[nView];
			mpOutlinerView[nView] = NULL;
		}
	}

	if (mpOutliner->GetViewCount() == 0)
	{
		// Outliner deinitialisieren: Farbdarstellung einschalten
		ResetLinks();
		sal_uLong nCntrl = mpOutliner->GetControlWord();
		mpOutliner->SetUpdateMode(sal_False); // sonst wird bei SetControlWord gezeichnet
		mpOutliner->SetControlWord(nCntrl & ~EE_CNTRL_NOCOLORS);
		SvtAccessibilityOptions aOptions;
		mpOutliner->ForceAutoColor( aOptions.GetIsAutomaticFontColor() );
		mpOutliner->Clear();
	}

	DBG_ASSERT(!mpSelectedParas, "Absatzliste nicht geloescht");
	DBG_ASSERT(!mpOldParaOrder, "Absatzliste nicht geloescht");
}




void OutlineView::ConnectToApplication (void)
{
	mpOutlineViewShell->GetActiveWindow()->GrabFocus();
	Application::AddEventListener(LINK(this, OutlineView, AppEventListenerHdl));
}




void OutlineView::DisconnectFromApplication (void)
{
	Application::RemoveEventListener(LINK(this, OutlineView, AppEventListenerHdl));
}




/*************************************************************************
|*
|* Paint-Methode
|*
\************************************************************************/

void OutlineView::Paint(const Rectangle& rRect, ::sd::Window* pWin)
{
	OutlinerView* pOlView = GetViewByWindow(pWin);

	if (pOlView)
	{
		pOlView->HideCursor();
		pOlView->Paint(rRect);

		pOlView->ShowCursor(mbFirstPaint);

/*
		if( mnPageNumberWidthPixel == 0 )
			GetPageNumberWidthPixel();

		const sal_uLong nParaCount = pOlView->GetOutliner()->GetParagraphCount();
		EditView& rEditView = pOlView->GetEditView();

		Font aOldFont( pWin->GetFont() );

		const String aBulletStr( sal_Unicode( 0xE011 ) );
		pWin->SetFont( maBulletFont);
		sal_Int32 nBulletWidth = pWin->GetTextWidth(aBulletStr);

		sal_Int32 nPage = 1;
		for( sal_uLong nPara = 0; nPara < nParaCount; nPara++ )
		{
			Paragraph* pPara = pOlView->GetOutliner()->GetParagraph( nPara );
			if( pPara->HasFlag( PARAFLAG_ISPAGE ) )
			{
				pWin->SetFont( maPageNumberFont );
				const String aStr( String::CreateFromInt32( nPage++ ) );
				Point aPos( rEditView.GetWindowPosTopLeft( (sal_uInt16)nPara ) );

				sal_Int32 nNumberOffset = pWin->PixelToLogic( Point(mnPageNumberWidthPixel, 0) ).X() - nBulletWidth;
				sal_Int32 nLineHeight = pOlView->GetOutliner()->GetLineHeight( nPara, 0 );

				aPos.X() = nNumberOffset;
				
				Point aPoint( aPos.X() - pWin->GetTextWidth( aStr ), aPos.Y() + ( nLineHeight - maPageNumberFont.GetHeight()) / 2 );
				pWin->DrawText( aPoint, aStr );

				aPoint.X() = aPos.X();
				aPoint.Y() = aPos.Y() +( nLineHeight - maBulletFont.GetHeight()) / 2;
				pWin->SetFont( maBulletFont );
				pWin->DrawText( aPoint, aBulletStr );
			}
		}

		pWin->SetFont( aOldFont );
*/		
		mbFirstPaint = sal_False;
	}
}

void OutlineView::InvalidateSlideNumberArea()
{   
/*
	for( sal_Int16 nView = 0; nView < MAX_OUTLINERVIEWS; ++nView )
	{
		if (mpOutlinerView[nView] != NULL)
		{
            ::Window* pWindow = mpOutlinerView[nView]->GetWindow();
            if( pWindow )
            {
                Rectangle aRect( Point(0,0), pWindow->GetOutputSize() );
                aRect.nRight = aRect.nLeft + pWindow->PixelToLogic( Point( mnPageNumberWidthPixel, 0 ) ).X() * 2;

                pWindow->Invalidate(aRect);
            }
        }
    }
*/
}

/*************************************************************************
|*
|* Fenster-Groesse hat sich geaendert
|*
\************************************************************************/

void OutlineView::AdjustPosSizePixel(const Point &,const Size &,::sd::Window*)
{
}

/*************************************************************************
|*
|* ein Fenster hinzufuegen
|*
\************************************************************************/

void OutlineView::AddWindowToPaintView(OutputDevice* pWin)
{
	sal_Bool bAdded = sal_False;
	sal_Bool bValidArea = sal_False;
	Rectangle aOutputArea;
	const Color aWhiteColor( COL_WHITE );
	sal_uInt16 nView = 0;

	while (nView < MAX_OUTLINERVIEWS && !bAdded)
	{
		if (mpOutlinerView[nView] == NULL)
		{
			mpOutlinerView[nView] = new OutlinerView(mpOutliner, dynamic_cast< ::sd::Window* >(pWin));
			mpOutlinerView[nView]->SetBackgroundColor( aWhiteColor );
			mpOutliner->InsertView(mpOutlinerView[nView], LIST_APPEND);
			bAdded = sal_True;

			if (bValidArea)
			{
				mpOutlinerView[nView]->SetOutputArea(aOutputArea);
			}
		}
		else if (!bValidArea)
		{
			aOutputArea = mpOutlinerView[nView]->GetOutputArea();
			bValidArea = sal_True;
		}

		nView++;
	}

	// weisser Hintergrund im Outliner
	pWin->SetBackground( Wallpaper( aWhiteColor ) );

	::sd::View::AddWindowToPaintView(pWin);
}

/*************************************************************************
|*
|* ein Fenster entfernen
|*
\************************************************************************/

void OutlineView::DeleteWindowFromPaintView(OutputDevice* pWin)
{
	sal_Bool bRemoved = sal_False;
	sal_uInt16 nView = 0;
	::Window* pWindow;

	while (nView < MAX_OUTLINERVIEWS && !bRemoved)
	{
		if (mpOutlinerView[nView] != NULL)
		{
			pWindow = mpOutlinerView[nView]->GetWindow();

			if (pWindow == pWin)
			{
				mpOutliner->RemoveView( mpOutlinerView[nView] );
				delete mpOutlinerView[nView];
				mpOutlinerView[nView] = NULL;
				bRemoved = sal_True;
			}
		}

		nView++;
	}

	::sd::View::DeleteWindowFromPaintView(pWin);
}

/*************************************************************************
|*
|* Zeiger der dem Fenster entsprechenden OutlinerView zurueckgeben.
|*
\************************************************************************/

OutlinerView* OutlineView::GetViewByWindow (::Window* pWin) const
{
	OutlinerView* pOlView = NULL;
	for (sal_uInt16 nView = 0; nView < MAX_OUTLINERVIEWS; nView++)
	{
		if (mpOutlinerView[nView] != NULL)
		{
			if ( pWin == mpOutlinerView[nView]->GetWindow() )
			{
				pOlView = mpOutlinerView[nView];
			}
		}
	}
	return (pOlView);
}


/*************************************************************************
|*
|* Ermittelt den Titel vor einem beliebigen Absatz.
|*
\************************************************************************/

Paragraph* OutlineView::GetPrevTitle(const Paragraph* pPara)
{
	sal_Int32 nPos = mpOutliner->GetAbsPos(const_cast<Paragraph*>(pPara));

	if (nPos > 0)
	{
		while(nPos)
		{
			pPara = mpOutliner->GetParagraph(--nPos);
			if( mpOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )
			{
				return const_cast< Paragraph* >( pPara );
			}
		}

	}
	return NULL;
}

/*************************************************************************
|*
|* Ermittelt den Titel nach einem beliebigen Absatz.
|*
\************************************************************************/

Paragraph* OutlineView::GetNextTitle(const Paragraph* pPara)
{
	Paragraph* pResult = const_cast< Paragraph* >( pPara );

	sal_Int32 nPos = mpOutliner->GetAbsPos(pResult);

	do
	{
		pResult = mpOutliner->GetParagraph(++nPos);
		if( pResult && mpOutliner->HasParaFlag(pResult, PARAFLAG_ISPAGE) )
			return pResult;
	}
	while( pResult );

	return NULL;
}

/*************************************************************************
|*
|* Handler fuer das Einfuegen von Seiten (Absaetzen)
|*
\************************************************************************/

IMPL_LINK( OutlineView, ParagraphInsertedHdl, ::Outliner *, pOutliner )
{
//	DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::ParagraphInsertedHdl(), model change without undo?!" );

	// we get calls to this handler during binary insert of drag and drop contents but
	// we ignore it here and handle it later in OnEndPasteOrDrop()
	if( maDragAndDropModelGuard.get() == 0 )
	{
		OutlineViewPageChangesGuard aGuard(this);

		Paragraph* pPara = pOutliner->GetHdlParagraph();

		sal_uInt16 nAbsPos = (sal_uInt16)mpOutliner->GetAbsPos( pPara );

		UpdateParagraph( nAbsPos );

		if( (nAbsPos == 0) || mpOutliner->HasParaFlag(pPara,PARAFLAG_ISPAGE) || mpOutliner->HasParaFlag(mpOutliner->GetParagraph( nAbsPos-1 ), PARAFLAG_ISPAGE) )
		{
			InsertSlideForParagraph( pPara );
			InvalidateSlideNumberArea();
		}
	}

	return 0;
}

/** creates and inserts an empty slide for the given paragraph */
SdPage* OutlineView::InsertSlideForParagraph( Paragraph* pPara )
{
	DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::InsertSlideForParagraph(), model change without undo?!" );

	OutlineViewPageChangesGuard aGuard(this);

	mpOutliner->SetParaFlag( pPara, PARAFLAG_ISPAGE );
	// wieviele Titel sind vor dem neuen Titelabsatz?
	sal_uLong nExample = 0L;			// Position der "Vorbild"seite
	sal_uLong nTarget  = 0L;			// Einfuegeposition
	while(pPara)
	{
		pPara = GetPrevTitle(pPara);
		if (pPara)
			nTarget++;
	}


	// was der Outliner nicht kann, muss hier wieder wettgemacht werden:
	// wenn VOR dem ersten Absatz ein neuer Absatz mit RETURN erzeugt wird,
	// meldet der Outliner den bereits bestehenden (jetzt nach unten
	// gerutschten) Absatz als neuen Absatz; nicht darauf reinfallen!
	if (nTarget == 1)
	{
		String aTest(mpOutliner->GetText( mpOutliner->GetParagraph( 0 ) ));
		if (aTest.Len() == 0)
		{
			nTarget = 0;
		}
	}


	// "Vorbild"seite ist - wenn vorhanden - die Vorgaengerseite
	if (nTarget > 0)
	{
		nExample = nTarget - 1;

		sal_uInt16 nPageCount = mpDoc->GetSdPageCount( PK_STANDARD );
		if( nExample >= nPageCount )
			nExample = nPageCount - 1;
	}

	/**********************************************************************
	* Es wird stets zuerst eine Standardseite und dann eine
	* Notizseite erzeugt. Es ist sichergestellt, dass auf eine
	* Standardseite stets die zugehoerige Notizseite folgt.
	* Vorangestellt ist genau eine Handzettelseite
	**********************************************************************/

	// diese Seite hat Vorbildfunktion
	SdPage* pExample = (SdPage*)mpDoc->GetSdPage((sal_uInt16)nExample, PK_STANDARD);
	SdPage* pPage = (SdPage*)mpDoc->AllocPage(sal_False);

	pPage->SetLayoutName(pExample->GetLayoutName());

	// einfuegen (Seite)
	mpDoc->InsertPage(pPage, (sal_uInt16)(nTarget) * 2 + 1);
	if( isRecordingUndo() )
		AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pPage));

	// der Standardseite eine Masterpage zuweisen
	pPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage());

	// Seitengroesse setzen
	pPage->SetSize(pExample->GetSize());
	pPage->SetBorder( pExample->GetLftBorder(),
					  pExample->GetUppBorder(),
					  pExample->GetRgtBorder(),
					  pExample->GetLwrBorder() );

	// neue Praesentationsobjekte anlegen (auf <Titel> oder
	// <Titel mit Untertitel> folgt <Titel mit Gliederung>, ansonsten
	// wird das Layout von der Vorgaengerseite uebernommen)
	AutoLayout eAutoLayout = pExample->GetAutoLayout();
	if (eAutoLayout == AUTOLAYOUT_TITLE ||
		eAutoLayout == AUTOLAYOUT_ONLY_TITLE)
	{
		pPage->SetAutoLayout(AUTOLAYOUT_ENUM, sal_True);
	}
	else
	{
		pPage->SetAutoLayout(pExample->GetAutoLayout(), sal_True);
	}

	/**********************************************************************
	|* jetzt die Notizseite
	\*********************************************************************/
	pExample = (SdPage*)mpDoc->GetSdPage((sal_uInt16)nExample, PK_NOTES);
	SdPage* pNotesPage = (SdPage*)mpDoc->AllocPage(sal_False);

	pNotesPage->SetLayoutName(pExample->GetLayoutName());

	pNotesPage->SetPageKind(PK_NOTES);

	// einfuegen (Notizseite)
	mpDoc->InsertPage(pNotesPage, (sal_uInt16)(nTarget) * 2 + 2);
	if( isRecordingUndo() )
		AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoNewPage(*pNotesPage));

	// der Notizseite eine Masterpage zuweisen
	pNotesPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage());

	// Seitengroesse setzen, es muss bereits eine Seite vorhanden sein
	pNotesPage->SetSize(pExample->GetSize());
	pNotesPage->SetBorder( pExample->GetLftBorder(),
						   pExample->GetUppBorder(),
						   pExample->GetRgtBorder(),
						   pExample->GetLwrBorder() );

	// neue Praesentationsobjekte anlegen
	pNotesPage->SetAutoLayout(pExample->GetAutoLayout(), sal_True);

	mpOutliner->UpdateFields();

	return pPage;
}

/*************************************************************************
|*
|* Handler fuer das Loeschen von Seiten (Absaetzen)
|*
\************************************************************************/

IMPL_LINK( OutlineView, ParagraphRemovingHdl, ::Outliner *, pOutliner )
{
	DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::ParagraphRemovingHdl(), model change without undo?!" );

	OutlineViewPageChangesGuard aGuard(this);

	Paragraph* pPara = pOutliner->GetHdlParagraph();
	if( pOutliner->HasParaFlag( pPara, PARAFLAG_ISPAGE ) )
	{
		// wieviele Titel sind vor dem fraglichen Titelabsatz?
		sal_uLong nPos = 0L;
		while(pPara)
		{
			pPara = GetPrevTitle(pPara);
			if (pPara) nPos++;
		}

		// Seite und Notizseite loeschen
		sal_uInt16 nAbsPos = (sal_uInt16)nPos * 2 + 1;
		SdrPage* pPage = mpDoc->GetPage(nAbsPos);
		if( isRecordingUndo() )
			AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
		mpDoc->RemovePage(nAbsPos);

		nAbsPos = (sal_uInt16)nPos * 2 + 1;
		pPage = mpDoc->GetPage(nAbsPos);
		if( isRecordingUndo() )
			AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
		mpDoc->RemovePage(nAbsPos);

		// ggfs. Fortschrittsanzeige
		if (mnPagesToProcess)
		{
			mnPagesProcessed++;

			if(mpProgress)
				mpProgress->SetState(mnPagesProcessed);

			if (mnPagesProcessed == mnPagesToProcess)
			{
				if(mpProgress)
				{
					delete mpProgress;
					mpProgress = NULL;
				}
				mnPagesToProcess = 0;
				mnPagesProcessed = 0;
			}
		}
		pOutliner->UpdateFields();
	}

    InvalidateSlideNumberArea();

	return 0;
}

/*************************************************************************
|*
|* Handler fuer das Aendern der Einruecktiefe von Absaetzen (macht ggfs.
|* das Einfuegen oder Loeschen von Seiten notwendig)
|*
\************************************************************************/

IMPL_LINK( OutlineView, DepthChangedHdl, ::Outliner *, pOutliner )
{
	DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::DepthChangedHdl(), no undo for model change?!" );

	OutlineViewPageChangesGuard aGuard(this);

	Paragraph* pPara = pOutliner->GetHdlParagraph();
	if( pOutliner->HasParaFlag( pPara, PARAFLAG_ISPAGE ) && ((pOutliner->GetPrevFlags() & PARAFLAG_ISPAGE) == 0) )
	{
		// the current paragraph is transformed into a slide

		mpOutliner->SetDepth( pPara, -1 );

		// werden da etwa mehrere Level-1-Absaetze auf Level 0 gebracht und
		// wir sollten eine Fortschrittsanzeige oder Eieruhr aufsetzen und
		// haben es noch nicht getan?
		if (mnPagesToProcess == 0)
		{
			Window* 	  pActWin = mpOutlineViewShell->GetActiveWindow();
			OutlinerView* pOlView = GetViewByWindow(pActWin);
			List*		  pList   = pOlView->CreateSelectionList();

			Paragraph*	  pParagraph   = (Paragraph*)pList->First();
			while (pParagraph)
			{
				if( !pOutliner->HasParaFlag( pParagraph, PARAFLAG_ISPAGE ) && (pOutliner->GetDepth( (sal_uInt16) pOutliner->GetAbsPos( pParagraph ) ) <= 0) )
					mnPagesToProcess++;
				pParagraph = (Paragraph*)pList->Next();
			}

			mnPagesToProcess++;	// der Absatz, der jetzt schon auf Level 0
								// steht, gehoert auch dazu
			mnPagesProcessed = 0;

			if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD)
			{
				if( mpProgress )
					delete mpProgress;

				const String aStr(SdResId(STR_CREATE_PAGES));
				mpProgress = new SfxProgress( GetDocSh(), aStr, mnPagesToProcess );
			}
			else
			{
				mpDocSh->SetWaitCursor( sal_True );
			}
			delete pList;
		}

		ParagraphInsertedHdl(pOutliner);

		mnPagesProcessed++;

		// muss eine Fortschrittsanzeige gepflegt werden?
		if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD)
		{
			if (mpProgress)
				mpProgress->SetState(mnPagesProcessed);
		}

		// war das die letzte Seite?
		if (mnPagesProcessed == mnPagesToProcess)
		{
			if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD && mpProgress)
			{
				delete mpProgress;
				mpProgress = NULL;
			}
			else
				mpDocSh->SetWaitCursor( sal_False );

			mnPagesToProcess = 0;
			mnPagesProcessed = 0;
		}
		pOutliner->UpdateFields();
	}
	else if( !pOutliner->HasParaFlag( pPara, PARAFLAG_ISPAGE ) && ((pOutliner->GetPrevFlags() & PARAFLAG_ISPAGE) != 0) )
	{
		// the paragraph was a page but now becomes a normal paragraph

		// how many titles are before the title paragraph in question?
		sal_uLong nPos = 0L;
		Paragraph* pParagraph = pPara;
		while(pParagraph)
		{
			pParagraph = GetPrevTitle(pParagraph);
			if (pParagraph)
				nPos++;
		}
		// Seite und Notizseite loeschen

		sal_uInt16 nAbsPos = (sal_uInt16)nPos * 2 + 1;
		SdrPage* pPage = mpDoc->GetPage(nAbsPos);
		if( isRecordingUndo() )
			AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
		mpDoc->RemovePage(nAbsPos);

		nAbsPos = (sal_uInt16)nPos * 2 + 1;
		pPage = mpDoc->GetPage(nAbsPos);
		if( isRecordingUndo() )
			AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
		mpDoc->RemovePage(nAbsPos);

		pPage = GetPageForParagraph( pPara );

		mpOutliner->SetDepth( pPara, (pPage && (static_cast<SdPage*>(pPage)->GetAutoLayout() == AUTOLAYOUT_TITLE)) ?  -1 : 0 );

		// ggfs. Fortschrittsanzeige
		if (mnPagesToProcess)
		{
			mnPagesProcessed++;
			if (mpProgress)
				mpProgress->SetState(mnPagesProcessed);

			if (mnPagesProcessed == mnPagesToProcess)
			{
				if(mpProgress)
				{
					delete mpProgress;
					mpProgress = NULL;
				}
				mnPagesToProcess = 0;
				mnPagesProcessed = 0;
			}
		}
		pOutliner->UpdateFields();
	}
	else if ( (pOutliner->GetPrevDepth() == 1) && ( pOutliner->GetDepth( (sal_uInt16) pOutliner->GetAbsPos( pPara ) ) == 2 ) )
	{
		// wieviele Titel sind vor dem fraglichen Titelabsatz?
		sal_Int32 nPos = -1L;

		Paragraph* pParagraph = pPara;
		while(pParagraph)
		{
			pParagraph = GetPrevTitle(pParagraph);
			if (pParagraph)
				nPos++;
		}

		if(nPos >= 0)
		{
			SdPage*pPage = (SdPage*)mpDoc->GetSdPage( (sal_uInt16) nPos, PK_STANDARD);

			if(pPage && pPage->GetPresObj(PRESOBJ_TEXT))
				pOutliner->SetDepth( pPara, 0 );
		}

	}
	// wieviele Titel sind vor dem fraglichen Titelabsatz?
	sal_Int32 nPos = -1L;

	Paragraph* pTempPara = pPara;
	while(pTempPara)
	{
		pTempPara = GetPrevTitle(pTempPara);
		if (pTempPara)
			nPos++;
	}

	if( nPos >= 0 )
	{
		SdPage* pPage = (SdPage*) mpDoc->GetSdPage( (sal_uInt16) nPos, PK_STANDARD );

		if( pPage )
		{
			SfxStyleSheet* pStyleSheet = NULL;
			sal_uLong nPara = pOutliner->GetAbsPos( pPara );
			sal_Int16 nDepth = pOutliner->GetDepth( (sal_uInt16) nPara );
			bool bSubTitle = pPage->GetPresObj(PRESOBJ_TEXT) != NULL;

			if( pOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )
			{
				pStyleSheet = pPage->GetStyleSheetForPresObj( PRESOBJ_TITLE );
			}
			else if( bSubTitle )
			{
				pStyleSheet = pPage->GetStyleSheetForPresObj( PRESOBJ_TEXT );
			}
			else
			{
				pStyleSheet = pPage->GetStyleSheetForPresObj( PRESOBJ_OUTLINE );

				if( nDepth > 0 )
				{
					String aNewStyleSheetName( pStyleSheet->GetName() );
					aNewStyleSheetName.Erase( aNewStyleSheetName.Len()-1, 1 );
					aNewStyleSheetName += String::CreateFromInt32( nDepth+1 );
					SfxStyleSheetBasePool* pStylePool = mpDoc->GetStyleSheetPool();
					pStyleSheet = (SfxStyleSheet*) pStylePool->Find( aNewStyleSheetName, pStyleSheet->GetFamily() );
				}
			}

			// before we set the style sheet we need to preserve the bullet item
			// since all items will be deleted while setting a new style sheet
 			SfxItemSet aOldAttrs( pOutliner->GetParaAttribs( (sal_uInt16)nPara ) );

			pOutliner->SetStyleSheet( nPara, pStyleSheet );

			// restore the old bullet item but not if the style changed
			if ( pOutliner->GetPrevDepth() != -1 && nDepth != -1 &&
				 aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SFX_ITEM_ON )
			{
				SfxItemSet aAttrs( pOutliner->GetParaAttribs( (sal_uInt16)nPara ) );
				aAttrs.Put( *aOldAttrs.GetItem( EE_PARA_NUMBULLET ) );
				pOutliner->SetParaAttribs( (sal_uInt16)nPara, aAttrs );
			}
		}
	}

    InvalidateSlideNumberArea();

	return 0;
}

/*************************************************************************
|*
|* Handler fuer StatusEvents
|*
\************************************************************************/

IMPL_LINK( OutlineView, StatusEventHdl, EditStatus *, EMPTYARG )
{
    ::sd::Window*   pWin = mpOutlineViewShell->GetActiveWindow();
	OutlinerView*	pOutlinerView = GetViewByWindow(pWin);
	Rectangle	  aVis			= pOutlinerView->GetVisArea();

//	  sal_uLong nWidth = ((SdPage*)mpDoc->GetSdPage(0, PK_STANDARD))->GetSize().Width();
	sal_uLong nWidth = OUTLINE_PAPERWIDTH;
	Rectangle aText = Rectangle(Point(0,0),
								   Size(nWidth,
										mpOutliner->GetTextHeight()));
	Rectangle aWin(Point(0,0), pWin->GetOutputSizePixel());
	aWin = pWin->PixelToLogic(aWin);

	if (!aVis.IsEmpty())		// nicht beim Oeffnen
	{
		aText.Bottom() += aWin.GetHeight();

		mpOutlineViewShell->InitWindows(Point(0,0), aText.GetSize(),
									   Point(aVis.TopLeft()));
		mpOutlineViewShell->UpdateScrollBars();
	}

    InvalidateSlideNumberArea();
	return 0;
}

IMPL_LINK( OutlineView, BeginDropHdl, void *, EMPTYARG )
{
	DBG_ASSERT(maDragAndDropModelGuard.get() == 0, "sd::OutlineView::BeginDropHdl(), prior drag operation not finished correctly!" );

	maDragAndDropModelGuard.reset( new OutlineViewModelChangeGuard( *this ) );
	return 0;
}

IMPL_LINK( OutlineView, EndDropHdl, void *, EMPTYARG )
{
	maDragAndDropModelGuard.reset(0);
    InvalidateSlideNumberArea();
	return 0;
}

/*************************************************************************
|*
|* Handler fuer den Beginn einer Absatzverschiebung
|*
\************************************************************************/

IMPL_LINK( OutlineView, BeginMovingHdl, ::Outliner *, pOutliner )
{
	DBG_ASSERT(!mpSelectedParas, "Absatzliste nicht geloescht");
	DBG_ASSERT(!mpOldParaOrder, "Absatzliste nicht geloescht");

	OutlineViewPageChangesGuard aGuard(this);

	mpOldParaOrder = new List;

	// Liste der selektierten Titelabsaetze
	mpSelectedParas = mpOutlinerView[0]->CreateSelectionList();
	Paragraph* pPara = static_cast<Paragraph*>(mpSelectedParas->First());
	while (pPara)
	{
		if( !pOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )
		{
			mpSelectedParas->Remove();
			pPara = static_cast<Paragraph*>(mpSelectedParas->GetCurObject());
		}
		else
		{
			pPara = static_cast<Paragraph*>(mpSelectedParas->Next());
		}
	}

	// Die zu den selektierten Absaetzen auf Ebene 0 gehoerenden Seiten
	// selektieren
	sal_uInt16 nPos = 0;
	sal_uLong nParaPos = 0;
	pPara = pOutliner->GetParagraph( 0 );

	while(pPara)
	{
		if( pOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )                     // eine Seite?
		{
			mpOldParaOrder->Insert(pPara, LIST_APPEND);
			SdPage* pPage = mpDoc->GetSdPage(nPos, PK_STANDARD);
			pPage->SetSelected(sal_False);
			if (mpSelectedParas->Seek(pPara))            // selektiert?
			{
				pPage->SetSelected(sal_True);
			}
			nPos++;
		}
		pPara = pOutliner->GetParagraph( ++nParaPos );
	}

	return 0;
}

/*************************************************************************
|*
|* Handler fuer das Ende einer Absatzverschiebung
|*
\************************************************************************/

IMPL_LINK( OutlineView, EndMovingHdl, ::Outliner *, pOutliner )
{
	OutlineViewPageChangesGuard aGuard(this);

	DBG_ASSERT(mpSelectedParas, "keine Absatzliste");
	DBG_ASSERT(mpOldParaOrder, "keine Absatzliste");
	DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::EndMovingHdl(), model change without undo?!" );

	// Einfuegeposition anhand des ersten Absatzes suchen
	Paragraph* pSearchIt = (Paragraph*)mpSelectedParas->First();

	// den ersten der selektierten Paragraphen in der neuen Ordnung suchen
	sal_uInt16 nPosNewOrder = 0;
	sal_uLong nParaPos = 0;
	Paragraph*	pPara = pOutliner->GetParagraph( 0 );
	Paragraph*	pPrev = NULL;
	while (pPara && pPara != pSearchIt)
	{
		if( pOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )
		{
			nPosNewOrder++;
			pPrev = pPara;
		}
		pPara = pOutliner->GetParagraph( ++nParaPos );
	}

	sal_uInt16 nPos = nPosNewOrder; 	// nPosNewOrder nicht veraendern
	if (nPos == 0)
	{
		nPos = (sal_uInt16)-1;			// vor der ersten Seite einfuegen
	}
	else
	{
		// den Vorgaenger in der alten Ordnung suchen
		nPos = (sal_uInt16)mpOldParaOrder->GetPos(pPrev);
		DBG_ASSERT(nPos != 0xffff, "Absatz nicht gefunden");
	}

	mpDoc->MovePages(nPos);

	// die Seiten wieder deselektieren
	sal_uInt16 nPageCount = (sal_uInt16)mpSelectedParas->Count();
	while (nPageCount)
	{
		SdPage* pPage = mpDoc->GetSdPage(nPosNewOrder, PK_STANDARD);
		pPage->SetSelected(sal_False);
		nPosNewOrder++;
		nPageCount--;
	}

	pOutliner->UpdateFields();

	delete mpSelectedParas;
	mpSelectedParas = NULL;
	delete mpOldParaOrder;
	mpOldParaOrder = NULL;

    InvalidateSlideNumberArea();

	return 0;
}

/*************************************************************************
|*
|* Eine Seite des Models nach dem Titeltextobjekt durchsuchen
|*
\************************************************************************/

SdrTextObj* OutlineView::GetTitleTextObject(SdrPage* pPage)
{
	sal_uLong			nObjectCount = pPage->GetObjCount();
	SdrObject*		pObject 	 = NULL;
	SdrTextObj* 	pResult 	 = NULL;

	for (sal_uLong nObject = 0; nObject < nObjectCount; nObject++)
	{
		pObject = pPage->GetObj(nObject);
		if (pObject->GetObjInventor() == SdrInventor &&
			pObject->GetObjIdentifier() == OBJ_TITLETEXT)
		{
			pResult = (SdrTextObj*)pObject;
			break;
		}
	}
	return pResult;
}


/*************************************************************************
|*
|* Eine Seite des Models nach dem Gliederungstextobjekt durchsuchen
|*
\************************************************************************/

SdrTextObj* OutlineView::GetOutlineTextObject(SdrPage* pPage)
{
	sal_uLong			nObjectCount = pPage->GetObjCount();
	SdrObject*		pObject 	 = NULL;
	SdrTextObj* 	pResult 	 = NULL;

	for (sal_uLong nObject = 0; nObject < nObjectCount; nObject++)
	{
		pObject = pPage->GetObj(nObject);
		if (pObject->GetObjInventor() == SdrInventor &&
			pObject->GetObjIdentifier() == OBJ_OUTLINETEXT)
		{
			pResult = (SdrTextObj*)pObject;
			break;
		}
	}
	return pResult;
}

SdrTextObj* OutlineView::CreateTitleTextObject(SdPage* pPage)
{
	DBG_ASSERT( GetTitleTextObject(pPage) == 0, "sd::OutlineView::CreateTitleTextObject(), there is already a title text object!" );

	if( pPage->GetAutoLayout() == AUTOLAYOUT_NONE )
	{
		// simple case
		pPage->SetAutoLayout( AUTOLAYOUT_ONLY_TITLE, true );
	}
	else
	{
		// we already have a layout with a title but the title
		// object was deleted, create a new one
		pPage->InsertAutoLayoutShape( 0, PRESOBJ_TITLE, false, pPage->GetTitleRect(), true );
	}

	return GetTitleTextObject(pPage);
}

SdrTextObj* OutlineView::CreateOutlineTextObject(SdPage* pPage)
{
	DBG_ASSERT( GetOutlineTextObject(pPage) == 0, "sd::OutlineView::CreateOutlineTextObject(), there is already a layout text object!" );

	AutoLayout eNewLayout = pPage->GetAutoLayout();
	switch( eNewLayout )
	{
	case AUTOLAYOUT_NONE:
	case AUTOLAYOUT_ONLY_TITLE:
	case AUTOLAYOUT_TITLE:	eNewLayout = AUTOLAYOUT_ENUM; break;

	case AUTOLAYOUT_CHART:	eNewLayout = AUTOLAYOUT_CHARTTEXT; break;

	case AUTOLAYOUT_ORG:
	case AUTOLAYOUT_TAB:
	case AUTOLAYOUT_OBJ:	eNewLayout = AUTOLAYOUT_OBJTEXT; break;
	default:
		break;
	}

	if( eNewLayout != pPage->GetAutoLayout() )
	{
		pPage->SetAutoLayout( eNewLayout, true );
	}
	else
	{
		// we already have a layout with a text but the text
		// object was deleted, create a new one
		pPage->InsertAutoLayoutShape( 0,
									  (eNewLayout == AUTOLAYOUT_TITLE) ? PRESOBJ_TEXT : PRESOBJ_OUTLINE,
									  false, pPage->GetLayoutRect(), true );
	}

	return GetOutlineTextObject(pPage);
}

/** updates draw model with all changes from outliner model */
sal_Bool OutlineView::PrepareClose(sal_Bool)
{
    ::sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager());
    if (pDocUndoMgr != NULL)
        pDocUndoMgr->SetLinkedUndoManager(NULL);

	mpOutliner->GetUndoManager().Clear();

	const String aUndoStr(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT));
	BegUndo(aUndoStr);
	UpdateDocument();
	EndUndo();
	mpDoc->SetSelected(GetActualPage(), sal_True);
	return sal_True;
}


/*************************************************************************
|*
|* Attribute des selektierten Textes setzen
|*
\************************************************************************/

sal_Bool OutlineView::SetAttributes(const SfxItemSet& rSet, sal_Bool )
{
	sal_Bool bOk = sal_False;

	OutlinerView* pOlView = GetViewByWindow(mpOutlineViewShell->GetActiveWindow());

	if (pOlView)
	{
		pOlView->SetAttribs(rSet);
		bOk = sal_True;
	}

    mpOutlineViewShell->Invalidate (SID_PREVIEW_STATE);

	return (bOk);
}

/*************************************************************************
|*
|* Attribute des selektierten Textes erfragen
|*
\************************************************************************/

sal_Bool OutlineView::GetAttributes( SfxItemSet& rTargetSet, sal_Bool ) const
{
	OutlinerView* pOlView = GetViewByWindow(
								mpOutlineViewShell->GetActiveWindow());
	DBG_ASSERT(pOlView, "keine OutlinerView gefunden");

	rTargetSet.Put( pOlView->GetAttribs(), sal_False );
	return sal_True;
}

/** creates outliner model from draw model */
void OutlineView::FillOutliner()
{
	mpOutliner->GetUndoManager().Clear();
	mpOutliner->EnableUndo(sal_False);
	ResetLinks();
    mpOutliner->SetUpdateMode(false);

	Paragraph* pTitleToSelect = NULL;
	sal_uLong nPageCount = mpDoc->GetSdPageCount(PK_STANDARD);

	// fill outliner with paragraphs from slides title & (outlines|subtitles)
	for (sal_uInt16 nPage = 0; nPage < nPageCount; nPage++)
	{
		SdPage* 	pPage = (SdPage*)mpDoc->GetSdPage(nPage, PK_STANDARD);
		Paragraph * pPara = NULL;

        // take text from title shape
		SdrTextObj* pTO = GetTitleTextObject(pPage);
		if(pTO && !(pTO->IsEmptyPresObj()))
		{
			OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
			if (pOPO)
			{
				sal_Bool bVertical = pOPO->IsVertical();
				pOPO->SetVertical( sal_False );
				mpOutliner->AddText(*pOPO);
				pOPO->SetVertical( bVertical );
				pPara = mpOutliner->GetParagraph( mpOutliner->GetParagraphCount()-1 );
			}
		}

		if( pPara == 0 ) // no title, insert an empty paragraph
		{
			pPara = mpOutliner->Insert(String());
			mpOutliner->SetDepth(pPara, -1);

			// Keine harten Attribute vom vorherigen Absatz uebernehmen
			mpOutliner->SetParaAttribs( (sal_uInt16)mpOutliner->GetAbsPos(pPara),
									   mpOutliner->GetEmptyItemSet() );

			mpOutliner->SetStyleSheet( mpOutliner->GetAbsPos( pPara ), pPage->GetStyleSheetForPresObj( PRESOBJ_TITLE ) );
		}

		mpOutliner->SetParaFlag( pPara, PARAFLAG_ISPAGE );

		sal_uLong nPara = mpOutliner->GetAbsPos( pPara );

		UpdateParagraph( (sal_uInt16)nPara );

		// remember paragraph of currently selected page
		if (pPage->IsSelected())
			pTitleToSelect = pPara;

		// take text from subtitle or outline
		pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PRESOBJ_TEXT));
		const bool bSubTitle = pTO != 0;

		if (!pTO) // if no subtile found, try outline
			pTO = GetOutlineTextObject(pPage);
		
		if(pTO && !(pTO->IsEmptyPresObj())) // found some text
		{
			OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
			if (pOPO)
			{
				sal_uInt16 nParaCount1 = (sal_uInt16)mpOutliner->GetParagraphCount();
				sal_Bool bVertical = pOPO->IsVertical();
				pOPO->SetVertical( sal_False );
				mpOutliner->AddText(*pOPO);
				pOPO->SetVertical( bVertical );

                sal_uInt16 nParaCount2 = (sal_uInt16)mpOutliner->GetParagraphCount();
				for (sal_uInt16 n = nParaCount1; n < nParaCount2; n++)
				{
                    if( bSubTitle )
                    {
					    Paragraph* p = mpOutliner->GetParagraph(n);
					    if(p && mpOutliner->GetDepth( n ) > 0 )
						    mpOutliner->SetDepth(p, 0);
                    }

					UpdateParagraph( n );
				}
			}
		}
	}

	// place cursor at the start
	Paragraph* pFirstPara = mpOutliner->GetParagraph( 0 );
	mpOutlinerView[0]->Select( pFirstPara, sal_True, sal_False );
	mpOutlinerView[0]->Select( pFirstPara, sal_False, sal_False );

	// select title of slide that was selected
	if (pTitleToSelect)
		mpOutlinerView[0]->Select(pTitleToSelect, sal_True, sal_False);

	SetLinks();

	mpOutliner->EnableUndo(sal_True);

    mpOutliner->SetUpdateMode(true);
}

/*************************************************************************
|*
|* Handler fuer das Loeschen von Level-0-Absaetzen (Seiten): Warnung
|*
\************************************************************************/

IMPL_LINK( OutlineView, RemovingPagesHdl, OutlinerView *, EMPTYARG )
{
	sal_uInt16 nNumOfPages = mpOutliner->GetSelPageCount();

	if (nNumOfPages > PROCESS_WITH_PROGRESS_THRESHOLD)
	{
		mnPagesToProcess = nNumOfPages;
		mnPagesProcessed  = 0;
	}

	if (mnPagesToProcess)
	{
		if( mpProgress )
			delete mpProgress;

		String aStr(SdResId(STR_DELETE_PAGES));
		mpProgress = new SfxProgress( GetDocSh(), aStr, mnPagesToProcess );
	}
	mpOutliner->UpdateFields();

    InvalidateSlideNumberArea();

	return 1;
}

/*************************************************************************
|*
|* Handler fuer das Einruecken von Level-0-Absaetzen (Seiten): Warnung
|*
\************************************************************************/

IMPL_LINK_INLINE_START( OutlineView, IndentingPagesHdl, OutlinerView *, pOutlinerView )
{
	return RemovingPagesHdl(pOutlinerView);
}
IMPL_LINK_INLINE_END( OutlineView, IndentingPagesHdl, OutlinerView *, pOutlinerView )


/** returns the first slide that is selected in the outliner or where
	the cursor is located */
SdPage* OutlineView::GetActualPage()
{
    ::sd::Window* pWin = mpOutlineViewShell->GetActiveWindow();
	OutlinerView* pActiveView = GetViewByWindow(pWin);
	std::auto_ptr<List> pSelList( static_cast< List* >(pActiveView->CreateSelectionList()) );

	SdPage* pCurrent = GetPageForParagraph(static_cast<Paragraph*>(pSelList->First()) );
	DBG_ASSERT( pCurrent ||
				(mpDocSh->GetUndoManager() && static_cast< sd::UndoManager *>(mpDocSh->GetUndoManager())->IsDoing()) ||
				maDragAndDropModelGuard.get(),
				"sd::OutlineView::GetActualPage(), no current page?" );
	if( pCurrent )
		return pCurrent;
	else
		return mpDoc->GetSdPage( 0, PK_STANDARD );
}

SdPage* OutlineView::GetPageForParagraph( Paragraph* pPara )
{
	if( !mpOutliner->HasParaFlag(pPara,PARAFLAG_ISPAGE) )
		pPara = GetPrevTitle(pPara);

	sal_uInt32 nPageToSelect = 0;
	while(pPara)
	{
		pPara = GetPrevTitle(pPara);
		if(pPara)
			nPageToSelect++;
	}

	if( nPageToSelect < (sal_uInt32)mpDoc->GetSdPageCount( PK_STANDARD ) )
		return static_cast< SdPage* >( mpDoc->GetSdPage( (sal_uInt16)nPageToSelect, PK_STANDARD) );
	else
		return 0;
}

Paragraph* OutlineView::GetParagraphForPage( ::Outliner* pOutl, SdPage* pPage )
{
	// get the number of paragraphs with ident 0 we need to skip before
	// we finde the actual page
	sal_uInt32 nPagesToSkip = (pPage->GetPageNum() - 1) >> 1;

	sal_uInt32 nParaPos = 0;
	Paragraph* pPara = pOutl->GetParagraph( 0 );
	while( pPara )
	{
		// if this paragraph is a page ...
		if( mpOutliner->HasParaFlag(pPara,PARAFLAG_ISPAGE) )
		{
			// see if we already skiped enough pages
			if( 0 == nPagesToSkip )
				break;	// and if so, end the loop

			// we skiped another page
			nPagesToSkip--;
		}

		// get next paragraph
		pPara = mpOutliner->GetParagraph( ++nParaPos );
	}

	return pPara;
}

/** selects the paragraph for the given page at the outliner view*/
void OutlineView::SetActualPage( SdPage* pActual )
{
	if( pActual && mpOutliner && dynamic_cast<Outliner*> ( mpOutliner )->GetIgnoreCurrentPageChangesLevel()==0 && !mbFirstPaint)
	{
		// if we found a paragraph, select its text at the outliner view
		Paragraph* pPara = GetParagraphForPage( mpOutliner, pActual );
		if( pPara )
			mpOutlinerView[0]->Select( pPara, sal_True, sal_False );
	}
}

/*************************************************************************
|*
|* StyleSheet aus der Selektion besorgen
|*
\************************************************************************/

SfxStyleSheet* OutlineView::GetStyleSheet() const
{
 	::sd::Window* pActWin = mpOutlineViewShell->GetActiveWindow();
	OutlinerView* pOlView = GetViewByWindow(pActWin);
	SfxStyleSheet* pResult = pOlView->GetStyleSheet();
	return pResult;
}



/*************************************************************************
|*
|* Seiten als selektiert / nicht selektiert setzen
|*
\************************************************************************/

void OutlineView::SetSelectedPages()
{
	// Liste der selektierten Titelabsaetze
	List* pSelParas = mpOutlinerView[0]->CreateSelectionList();
	Paragraph* pPara = (Paragraph*) pSelParas->First();

	while(pPara)
	{
		if( !mpOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )
		{
			pSelParas->Remove();
			pPara = (Paragraph*) pSelParas->GetCurObject();
		}
		else
		{
			pPara = (Paragraph*) pSelParas->Next();
		}
	}

	// Die zu den selektierten Absaetzen auf Ebene 0 gehoerenden Seiten
	// selektieren
	sal_uInt16 nPos = 0;
	sal_uLong nParaPos = 0;
	pPara = mpOutliner->GetParagraph( 0 );

	while(pPara)
	{
		if( mpOutliner->HasParaFlag(pPara, PARAFLAG_ISPAGE) )                     // eine Seite?
		{
			SdPage* pPage = mpDoc->GetSdPage(nPos, PK_STANDARD);
            DBG_ASSERT(pPage!=NULL,
                "Trying to select non-existing page OutlineView::SetSelectedPages()");
            if (pPage != NULL)
            {
                pPage->SetSelected(sal_False);

                if (pSelParas->Seek(pPara))            // selektiert?
                    pPage->SetSelected(sal_True);
			}

			nPos++;
		}

		pPara = mpOutliner->GetParagraph( ++nParaPos );
	}
}


/*************************************************************************
|*
|* Neue Links setzen
|*
\************************************************************************/

void OutlineView::SetLinks()
{
	// Benachrichtigungs-Links setzen
	mpOutliner->SetParaInsertedHdl(LINK(this, OutlineView, ParagraphInsertedHdl));
	mpOutliner->SetParaRemovingHdl(LINK(this, OutlineView, ParagraphRemovingHdl));
	mpOutliner->SetDepthChangedHdl(LINK(this, OutlineView, DepthChangedHdl));
	mpOutliner->SetBeginMovingHdl(LINK(this, OutlineView, BeginMovingHdl));
	mpOutliner->SetEndMovingHdl(LINK(this, OutlineView, EndMovingHdl));
	mpOutliner->SetRemovingPagesHdl(LINK(this, OutlineView, RemovingPagesHdl));
	mpOutliner->SetIndentingPagesHdl(LINK(this, OutlineView, IndentingPagesHdl));
	mpOutliner->SetStatusEventHdl(LINK(this, OutlineView, StatusEventHdl));
	mpOutliner->SetBeginDropHdl(LINK(this,OutlineView, BeginDropHdl));
	mpOutliner->SetEndDropHdl(LINK(this,OutlineView, EndDropHdl));
    mpOutliner->SetPaintFirstLineHdl(LINK(this,OutlineView,PaintingFirstLineHdl));
    mpOutliner->SetBeginPasteOrDropHdl(LINK(this,OutlineView, BeginPasteOrDropHdl));
    mpOutliner->SetEndPasteOrDropHdl(LINK(this,OutlineView, EndPasteOrDropHdl));
}



/*************************************************************************
|*
|* Alte Links restaurieren
|*
\************************************************************************/

void OutlineView::ResetLinks() const
{
	// alte Links restaurieren
	Link aEmptyLink;
	mpOutliner->SetParaInsertedHdl(aEmptyLink);
	mpOutliner->SetParaRemovingHdl(aEmptyLink);
	mpOutliner->SetDepthChangedHdl(aEmptyLink);
	mpOutliner->SetBeginMovingHdl(aEmptyLink);
	mpOutliner->SetEndMovingHdl(aEmptyLink);
	mpOutliner->SetStatusEventHdl(aEmptyLink);
	mpOutliner->SetRemovingPagesHdl(aEmptyLink);
	mpOutliner->SetIndentingPagesHdl(aEmptyLink);
    mpOutliner->SetDrawPortionHdl(aEmptyLink);
    mpOutliner->SetBeginPasteOrDropHdl(aEmptyLink);
    mpOutliner->SetEndPasteOrDropHdl(aEmptyLink);
}

/*************************************************************************
|*
|* AcceptDrop
|*
\************************************************************************/

sal_Int8 OutlineView::AcceptDrop( const AcceptDropEvent&, DropTargetHelper&, ::sd::Window*, sal_uInt16, sal_uInt16)
{
	return DND_ACTION_NONE;
}

/*************************************************************************
|*
|* ExecuteDrop
|*
\************************************************************************/

sal_Int8 OutlineView::ExecuteDrop( const ExecuteDropEvent&, DropTargetHelper&, ::sd::Window*, sal_uInt16, sal_uInt16)
{
	return DND_ACTION_NONE;
}

// #97766# Re-implement GetScriptType for this view to get correct results
sal_uInt16 OutlineView::GetScriptType() const
{
	sal_uInt16 nScriptType = ::sd::View::GetScriptType();

	if(mpOutliner)
	{
		OutlinerParaObject* pTempOPObj = mpOutliner->CreateParaObject();

		if(pTempOPObj)
		{
			nScriptType = pTempOPObj->GetTextObject().GetScriptType();
			delete pTempOPObj;
		}
	}

	return nScriptType;
}

void OutlineView::onUpdateStyleSettings( bool bForceUpdate /* = false */ )
{
	const bool bHighContrastMode = Application::GetSettings().GetStyleSettings().GetHighContrastMode() != 0;
	if( bForceUpdate || (mbHighContrastMode != bHighContrastMode) )
	{
		if( mpOutliner )
		{
			mpOutliner->ForceAutoColor( bHighContrastMode );
		}
		mbHighContrastMode = bHighContrastMode;

	}

    svtools::ColorConfig aColorConfig;
    const Color aDocColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor );
	if( bForceUpdate || (maDocColor != aDocColor) )
	{
		sal_uInt16 nView;
		for( nView = 0; nView < MAX_OUTLINERVIEWS; nView++ )
		{
			if (mpOutlinerView[nView] != NULL)
			{
				mpOutlinerView[nView]->SetBackgroundColor( aDocColor );

				::Window* pWindow = mpOutlinerView[nView]->GetWindow();

				if( pWindow )
					pWindow->SetBackground( Wallpaper( aDocColor ) );

			}
		}

		if( mpOutliner )
			mpOutliner->SetBackgroundColor( aDocColor );

		maDocColor = aDocColor;
	}
}

IMPL_LINK( OutlineView, AppEventListenerHdl, void *, EMPTYARG )
{
	onUpdateStyleSettings();
	return 0;
}




IMPL_LINK(OutlineView, EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent*, pEvent)
{
    if (pEvent != NULL)
    {
        switch (pEvent->meEventId)
        {
            case tools::EventMultiplexerEvent::EID_CURRENT_PAGE:
                SetActualPage(mpOutlineViewShell->GetActualPage());
                InvalidateSlideNumberArea();
                break;

            case tools::EventMultiplexerEvent::EID_PAGE_ORDER:
                if (mpOutliner != NULL && mpDoc!=NULL && mpOutliner != NULL && dynamic_cast<Outliner*> ( mpOutliner )->GetIgnoreCurrentPageChangesLevel()==0)
                {
                    if (((mpDoc->GetPageCount()-1)%2) == 0)
                    {
                        mpOutliner->Clear();
                        FillOutliner();
                        ::sd::Window* pWindow = mpOutlineViewShell->GetActiveWindow();
                        if (pWindow != NULL)
                            pWindow->Invalidate();
                    }
                }
                break;
        }
    }
    return 0;
}

void OutlineView::IgnoreCurrentPageChanges (bool bIgnoreChanges)
{
	if ( mpOutliner )
	{
		if (bIgnoreChanges)
			dynamic_cast<Outliner*> ( mpOutliner )->IncreIgnoreCurrentPageChangesLevel();
		else
			dynamic_cast<Outliner*> ( mpOutliner )->DecreIgnoreCurrentPageChangesLevel();
	}
}

/** call this method before you do anything that can modify the outliner
	and or the drawing document model. It will create needed undo actions */
void OutlineView::BeginModelChange()
{
	const String aEmpty;
	mpOutliner->GetUndoManager().EnterListAction(aEmpty,aEmpty);
	const String aUndoStr(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT));
	BegUndo(aUndoStr);
}

/** call this method after BeginModelChange(), when all possible model
	changes are done. */
void OutlineView::EndModelChange()
{
	UpdateDocument();

	::svl::IUndoManager* pDocUndoMgr = mpDocSh->GetUndoManager();

	bool bHasUndoActions = pDocUndoMgr->GetUndoActionCount() != 0;

	EndUndo();

	DBG_ASSERT( bHasUndoActions == (mpOutliner->GetUndoManager().GetUndoActionCount() != 0), "sd::OutlineView::EndModelChange(), undo actions not in sync!" );

	if( bHasUndoActions )
	{
		SfxLinkUndoAction* pLink = new SfxLinkUndoAction(pDocUndoMgr);
		mpOutliner->GetUndoManager().AddUndoAction(pLink);
	}

	mpOutliner->GetUndoManager().LeaveListAction();

	if( bHasUndoActions && mpOutliner->GetEditEngine().HasTriedMergeOnLastAddUndo() )
		TryToMergeUndoActions();

    mpOutlineViewShell->Invalidate( SID_UNDO );
    mpOutlineViewShell->Invalidate( SID_REDO );
}

/** updates all changes in the outliner model to the draw model */
void OutlineView::UpdateDocument()
{
	const sal_uInt32 nPageCount = mpDoc->GetSdPageCount(PK_STANDARD);
	Paragraph* pPara = mpOutliner->GetParagraph( 0 );
	sal_uInt32 nPage;
	for (nPage = 0; nPage < nPageCount; nPage++)
	{
		SdPage* pPage = mpDoc->GetSdPage( (sal_uInt16)nPage, PK_STANDARD);
		mpDoc->SetSelected(pPage, sal_False);

		mpOutlineViewShell->UpdateTitleObject( pPage, pPara );
		mpOutlineViewShell->UpdateOutlineObject( pPage, pPara );

		if( pPara )
			pPara = GetNextTitle(pPara);
	}

	DBG_ASSERT( pPara == 0, "sd::OutlineView::UpdateDocument(), slides are out of sync, creating missing ones" );
	while( pPara )
	{
		SdPage* pPage = InsertSlideForParagraph( pPara );
		mpDoc->SetSelected(pPage, sal_False);

		mpOutlineViewShell->UpdateTitleObject( pPage, pPara );
		mpOutlineViewShell->UpdateOutlineObject( pPage, pPara );

		if( pPara )
			pPara = GetNextTitle(pPara);
	}
}

/** merge edit engine undo actions if possible */
void OutlineView::TryToMergeUndoActions()
{
	::svl::IUndoManager& rOutlineUndo = mpOutliner->GetUndoManager();
	if( rOutlineUndo.GetUndoActionCount() > 1 )
	{
		SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction(0) );
		SfxListUndoAction* pPrevListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction(1) );
		if( pListAction && pPrevListAction )
		{
			// find the top EditUndo action in the top undo action list
			size_t nAction = pListAction->aUndoActions.size();
			EditUndo* pEditUndo = 0;
			while( !pEditUndo && nAction )
			{
				pEditUndo = dynamic_cast< EditUndo* >(pListAction->aUndoActions[--nAction].pAction);
			}

			sal_uInt16 nEditPos = nAction; // we need this later to remove the merged undo actions

			// make sure it is the only EditUndo action in the top undo list
			while( pEditUndo && nAction )
			{
				if( dynamic_cast< EditUndo* >(pListAction->aUndoActions[--nAction].pAction) )
					pEditUndo = 0;
			}

			// do we have one and only one EditUndo action in the top undo list?
			if( pEditUndo )
			{
				// yes, see if we can merge it with the prev undo list

				nAction = pPrevListAction->aUndoActions.size();
				EditUndo* pPrevEditUndo = 0;
				while( !pPrevEditUndo && nAction )
					pPrevEditUndo = dynamic_cast< EditUndo* >(pPrevListAction->aUndoActions[--nAction].pAction);

				if( pPrevEditUndo && pPrevEditUndo->Merge( pEditUndo ) )
				{
					// ok we merged the only EditUndo of the top undo list with
					// the top EditUndo of the previous undo list

					// first remove the merged undo action
					DBG_ASSERT( pListAction->aUndoActions[nEditPos].pAction == pEditUndo,
                        "sd::OutlineView::TryToMergeUndoActions(), wrong edit pos!" );
					pListAction->aUndoActions.Remove(nEditPos);
					delete pEditUndo;

					// now check if we also can merge the draw undo actions
					::svl::IUndoManager* pDocUndoManager = mpDocSh->GetUndoManager();
					if( pDocUndoManager && ( pListAction->aUndoActions.size() == 1 ))
					{
						SfxLinkUndoAction* pLinkAction = dynamic_cast< SfxLinkUndoAction* >( pListAction->aUndoActions[0].pAction );
						SfxLinkUndoAction* pPrevLinkAction = 0;

						if( pLinkAction )
						{
							nAction = pPrevListAction->aUndoActions.size();
							while( !pPrevLinkAction && nAction )
								pPrevLinkAction = dynamic_cast< SfxLinkUndoAction* >(pPrevListAction->aUndoActions[--nAction].pAction);
						}

						if( pLinkAction && pPrevLinkAction &&
							( pLinkAction->GetAction() == pDocUndoManager->GetUndoAction(0) ) &&
							( pPrevLinkAction->GetAction() == pDocUndoManager->GetUndoAction(1) ) )
						{
							SfxListUndoAction* pSourceList = dynamic_cast< SfxListUndoAction* >(pLinkAction->GetAction());
							SfxListUndoAction* pDestinationList = dynamic_cast< SfxListUndoAction* >(pPrevLinkAction->GetAction());

							if( pSourceList && pDestinationList )
							{
								sal_uInt16 nCount = pSourceList->aUndoActions.size();
								sal_uInt16 nDestAction = pDestinationList->aUndoActions.size();
								while( nCount-- )
								{
									SfxUndoAction* pTemp = pSourceList->aUndoActions[0].pAction;
									pSourceList->aUndoActions.Remove(0);
									pDestinationList->aUndoActions.Insert( pTemp, nDestAction++ );
								}
								pDestinationList->nCurUndoAction = pDestinationList->aUndoActions.size();

								pListAction->aUndoActions.Remove(0);
								delete pLinkAction;

								pDocUndoManager->RemoveLastUndoAction();
							}
						}
					}

					if ( !pListAction->aUndoActions.empty() )
					{
						// now we have to move all remaining doc undo actions from the top undo
						// list to the previous undo list and remove the top undo list

						size_t nCount = pListAction->aUndoActions.size();
						size_t nDestAction = pPrevListAction->aUndoActions.size();
						while( nCount-- )
						{
							SfxUndoAction* pTemp = pListAction->aUndoActions[0].pAction;
							pListAction->aUndoActions.Remove(0);
							if( pTemp )
								pPrevListAction->aUndoActions.Insert( pTemp, nDestAction++ );
						}
						pPrevListAction->nCurUndoAction = pPrevListAction->aUndoActions.size();
					}

					rOutlineUndo.RemoveLastUndoAction();
				}
			}
		}
	}
}

IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo)
{
    if( pInfo && mpOutliner )
    {
        Paragraph* pPara = mpOutliner->GetParagraph( pInfo->mnPara );
        EditEngine& rEditEngine = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );

		Size aImageSize( pInfo->mpOutDev->PixelToLogic( maSlideImage.GetSizePixel()  ) );
		Size aOffset( 100, 100 );

	    // paint slide number
	    if( pPara && mpOutliner->HasParaFlag(pPara,PARAFLAG_ISPAGE) )
	    {
		    long nPage = 0; // todo, printing??
		    for ( sal_uInt16 n = 0; n <= pInfo->mnPara; n++ )
		    {
			    Paragraph* p = mpOutliner->GetParagraph( n );
			    if ( mpOutliner->HasParaFlag(p,PARAFLAG_ISPAGE) )
				    nPage++;
		    }

            long nBulletHeight = (long)mpOutliner->GetLineHeight( pInfo->mnPara );
            long nFontHeight = 0;
            if ( !rEditEngine.IsFlatMode() )
            {
//		        const SvxFontHeightItem& rFH = (const SvxFontHeightItem&)rEditEngine.GetParaAttrib( pInfo->mnPara, EE_CHAR_FONTHEIGHT );
//              nBulletHeight = rFH.GetHeight();
                nFontHeight = nBulletHeight / 5;
            }
            else
            {
//		        const SvxFontHeightItem& rFH = (const SvxFontHeightItem&)rEditEngine.GetEmptyItemSet().Get( EE_CHAR_FONTHEIGHT );
 //               nBulletHeight = rFH.GetHeight();
                nFontHeight = (nBulletHeight * 10) / 25;
            }

			Size aFontSz( 0, nFontHeight );

			Size aOutSize( 2000, nBulletHeight );

			const float fImageHeight = ((float)aOutSize.Height() * (float)4) / (float)7;
			const float fImageRatio  = (float)aImageSize.Height() / (float)aImageSize.Width();
			aImageSize.Width() = (long)( fImageRatio * fImageHeight );
			aImageSize.Height() = (long)( fImageHeight );

			Point aImagePos( pInfo->mrStartPos );
			aImagePos.X() += aOutSize.Width() - aImageSize.Width() - aOffset.Width() ;
			aImagePos.Y() += (aOutSize.Height() - aImageSize.Height()) / 2;

			pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage );

            const bool bVertical = mpOutliner->IsVertical();
            const bool bRightToLeftPara = rEditEngine.IsRightToLeft( pInfo->mnPara );

            LanguageType eLang = rEditEngine.GetDefaultLanguage();

            Point aTextPos( aImagePos.X() - aOffset.Width(), pInfo->mrStartPos.Y() );
            Font aNewFont( OutputDevice::GetDefaultFont( DEFAULTFONT_SANS_UNICODE, eLang, 0 ) );
		    aNewFont.SetSize( aFontSz );
//		    aNewFont.SetAlign( aBulletFont.GetAlign() );
		    aNewFont.SetVertical( bVertical );
		    aNewFont.SetOrientation( bVertical ? 2700 : 0 );
            aNewFont.SetColor( COL_AUTO );
		    pInfo->mpOutDev->SetFont( aNewFont );
		    String aPageText = String::CreateFromInt32( nPage );
		    Size aTextSz;
		    aTextSz.Width() = pInfo->mpOutDev->GetTextWidth( aPageText );
		    aTextSz.Height() = pInfo->mpOutDev->GetTextHeight();
//            long nBulletHeight = !bVertical ? aBulletArea.GetHeight() : aBulletArea.GetWidth();
		    if ( !bVertical )
		    {
			    aTextPos.Y() += (aOutSize.Height() - aTextSz.Height()) / 2;
                if ( !bRightToLeftPara )
                {
			        aTextPos.X() -= aTextSz.Width();
                }
                else
                {
			        aTextPos.X() += aTextSz.Width();
                }
		    }
		    else
		    {
			    aTextPos.Y() -= aTextSz.Width();
			    aTextPos.X() += nBulletHeight / 2;
		    }
		    pInfo->mpOutDev->DrawText( aTextPos, aPageText );
	    }
    }

    return 0;
}

#if 0
sal_Int32 OutlineView::GetPageNumberWidthPixel()
{
	Window* pActWin = mpOutlineViewShell->GetActiveWindow();
	if( pActWin )
	{
		Font aOldFont( pActWin->GetFont() );
		pActWin->SetFont( maPageNumberFont );
		Size aSize( pActWin->GetTextWidth( String( RTL_CONSTASCII_USTRINGPARAM("X" ) ) ), 0 );
		sal_Int32 nWidth = pActWin->LogicToPixel( aSize ).Width() * 5;

		const String aBulletStr( sal_Unicode( 0xE011 ) );
		pActWin->SetFont( maBulletFont);

		aSize.Width() = pActWin->GetTextWidth(aBulletStr);
		nWidth += pActWin->LogicToPixel( aSize ).Width();

		pActWin->SetFont( aOldFont );

		mnPageNumberWidthPixel = nWidth;
	}
	return mnPageNumberWidthPixel;
}
#endif

// --------------------------------------------------------------------

void OutlineView::UpdateParagraph( sal_uInt16 nPara )
{
	if( mpOutliner )
	{
	    SfxItemSet aNewAttrs2( mpOutliner->GetParaAttribs( nPara ) );
		aNewAttrs2.Put( maLRSpaceItem );
		mpOutliner->SetParaAttribs( nPara, aNewAttrs2 );
	}
}

// --------------------------------------------------------------------

void OutlineView::OnBeginPasteOrDrop( PasteOrDropInfos* /*pInfos*/ )
{
}

/** this is called after a paste or drop operation, make sure that the newly inserted paragraphs
	get the correct style sheet and new slides are inserted. */
void OutlineView::OnEndPasteOrDrop( PasteOrDropInfos* pInfos )
{
	SdPage* pPage = 0;
	SfxStyleSheetBasePool* pStylePool = GetDoc()->GetStyleSheetPool();

	for( sal_uInt16 nPara = pInfos->nStartPara; nPara <= pInfos->nEndPara; nPara++ )
	{
		Paragraph* pPara = mpOutliner->GetParagraph( nPara );

		bool bPage = mpOutliner->HasParaFlag( pPara, PARAFLAG_ISPAGE  );

		if( !bPage )
		{
			SdStyleSheet* pStyleSheet = dynamic_cast< SdStyleSheet* >( mpOutliner->GetStyleSheet( nPara ) );
			if( pStyleSheet )
			{
				const OUString aName( pStyleSheet->GetApiName() );
				if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("title" ) ) )
					bPage = true;
			}
		}

		if( !pPara )
			continue; // fatality!?

		if( bPage && (nPara != pInfos->nStartPara) )
		{
			// insert new slide for this paragraph
			pPage = InsertSlideForParagraph( pPara );
		}
		else
		{
			// newly inserted non page paragraphs get the outline style
			if( !pPage )
				pPage = GetPageForParagraph( pPara );

			if( pPage )
			{
				SfxStyleSheet* pStyle = pPage->GetStyleSheetForPresObj( bPage ? PRESOBJ_TITLE : PRESOBJ_OUTLINE );

				if( !bPage )
				{
					const sal_Int16 nDepth = mpOutliner->GetDepth( nPara );
					if( nDepth > 0 )
					{
						String aStyleSheetName( pStyle->GetName() );
						aStyleSheetName.Erase( aStyleSheetName.Len() - 1, 1 );
						aStyleSheetName += String::CreateFromInt32( nDepth );
						pStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pStyle->GetFamily() ) );
						DBG_ASSERT( pStyle, "sd::OutlineView::OnEndPasteOrDrop(), Style not found!" );
					}
				}

				mpOutliner->SetStyleSheet( nPara, pStyle );
			}

			UpdateParagraph( nPara );
		}
	}
}

// ====================================================================


OutlineViewModelChangeGuard::OutlineViewModelChangeGuard( OutlineView& rView )
: mrView( rView )
{
	mrView.BeginModelChange();
}

OutlineViewModelChangeGuard::~OutlineViewModelChangeGuard()
{
	mrView.EndModelChange();
}

OutlineViewPageChangesGuard::OutlineViewPageChangesGuard( OutlineView* pView )
: mpView( pView )
{
	if( mpView )
		mpView->IgnoreCurrentPageChanges( true );
}

OutlineViewPageChangesGuard::~OutlineViewPageChangesGuard()
{
	if( mpView )
		mpView->IgnoreCurrentPageChanges( false );
}


} // end of namespace sd
