/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

#include "DrawDocShell.hxx"
#include <vcl/msgbox.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svxdlg.hxx>
#include <svx/dialogs.hrc>

#include "helpids.h"
#include "ViewShell.hxx"
#include "drawview.hxx"
#include "FrameView.hxx"
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include "View.hxx"
#include "ClientView.hxx"
#include "Window.hxx"
#include "strings.hrc"
#include "res_bmp.hrc"
#include "sdresid.hxx"
#include "strmname.h"
#include "fupoor.hxx"
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>

namespace sd {

/*************************************************************************
|*
|* Zeichnen der DocShell (mittels der Hilfsklasse SdDrawViewShell)
|*
\************************************************************************/

void DrawDocShell::Draw(OutputDevice* pOut, const JobSetup&, USHORT nAspect)
{
    if (nAspect == ASPECT_THUMBNAIL)
    {
        /**********************************************************************
        * THUMBNAIL: Hier koennte ev. einmal der Draft-Mode gesetzt werden
        **********************************************************************/
    }

    ClientView* pView = new ClientView(this, pOut, NULL);

    pView->SetHlplVisible(FALSE);
    pView->SetGridVisible(FALSE);
    pView->SetBordVisible(FALSE);
    pView->SetPageVisible(FALSE);
    pView->SetGlueVisible(FALSE);

    SdPage* pSelectedPage = NULL;

    List* pFrameViewList = mpDoc->GetFrameViewList();
    if( pFrameViewList && pFrameViewList->Count() )
    {
        FrameView* pFrameView = (FrameView*)pFrameViewList->GetObject(0);
        if( pFrameView && pFrameView->GetPageKind() == PK_STANDARD )
        {
            USHORT nSelectedPage = pFrameView->GetSelectedPage();
            pSelectedPage = mpDoc->GetSdPage(nSelectedPage, PK_STANDARD);
        }
    }

    if( NULL == pSelectedPage )
    {
        SdPage* pPage = NULL;
        USHORT nSelectedPage = 0;
        USHORT nPageCnt = (USHORT) mpDoc->GetSdPageCount(PK_STANDARD);

        for (USHORT i = 0; i < nPageCnt; i++)
        {
            pPage = mpDoc->GetSdPage(i, PK_STANDARD);

            if ( pPage->IsSelected() )
            {
                nSelectedPage = i;
                pSelectedPage = pPage;
            }
        }

        if( NULL == pSelectedPage )
            pSelectedPage = mpDoc->GetSdPage(0, PK_STANDARD);
    }

    Rectangle aVisArea = GetVisArea(nAspect);
    pOut->IntersectClipRegion(aVisArea);
    pView->ShowSdrPage(pSelectedPage);

    if (pOut->GetOutDevType() != OUTDEV_WINDOW)
    {
        MapMode aOldMapMode = pOut->GetMapMode();

        if (pOut->GetOutDevType() == OUTDEV_PRINTER)
        {
            MapMode aMapMode = aOldMapMode;
            Point aOrigin = aMapMode.GetOrigin();
            aOrigin.X() += 1;
            aOrigin.Y() += 1;
            aMapMode.SetOrigin(aOrigin);
            pOut->SetMapMode(aMapMode);
        }

        Region aRegion(aVisArea);
        pView->CompleteRedraw(pOut, aRegion);

        if (pOut->GetOutDevType() == OUTDEV_PRINTER)
        {
            pOut->SetMapMode(aOldMapMode);
        }
    }

    delete pView;

//  Fuer Testzwecke: Bitte nicht entfernen!
//
//  GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
//
//  if( pMtf )
//  {
//		String aURLStr;
//
//		if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( String( RTL_CONSTASCII_USTRINGPARAM( "d:\\gdi.mtf" ) ), aURLStr ) )
//		{
//			SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aURLStr, STREAM_WRITE | STREAM_TRUNC );
//
//			if( pOStm )
//			{
//				*pOStm << *pMtf;
//				delete pOStm;
//			}
//		}
//  }
}

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

Rectangle DrawDocShell::GetVisArea(USHORT nAspect) const
{
    Rectangle aVisArea;

    if( ( ASPECT_THUMBNAIL == nAspect ) || ( ASPECT_DOCPRINT == nAspect ) )
    {
        // Groesse der ersten Seite herausgeben
        MapMode aSrcMapMode(MAP_PIXEL);
        MapMode aDstMapMode(MAP_100TH_MM);
        Size aSize = mpDoc->GetSdPage(0, PK_STANDARD)->GetSize();
        aSrcMapMode.SetMapUnit(MAP_100TH_MM);

        aSize = Application::GetDefaultDevice()->LogicToLogic(aSize, &aSrcMapMode, &aDstMapMode);
        aVisArea.SetSize(aSize);
    }
    else
    {
        aVisArea = SfxObjectShell::GetVisArea(nAspect);
    }

    if (aVisArea.IsEmpty() && mpViewShell)
    {
        Window* pWin = mpViewShell->GetActiveWindow();

        if (pWin)
        {
            aVisArea = pWin->PixelToLogic(Rectangle(Point(0,0), pWin->GetOutputSizePixel()));
        }
    }

    return (aVisArea);
}

/*************************************************************************
|*
|* ViewShell anmelden
|*
\************************************************************************/

void DrawDocShell::Connect(ViewShell* pViewSh)
{
    mpViewShell = pViewSh;
}

/*************************************************************************
|*
|* ViewShell abmelden
|*
\************************************************************************/

void DrawDocShell::Disconnect(ViewShell* pViewSh)
{
    if (mpViewShell == pViewSh)
    {
        mpViewShell = NULL;
    }
}

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

FrameView* DrawDocShell::GetFrameView()
{
    FrameView* pFrameView = NULL;

    if (mpViewShell)
    {
        pFrameView = mpViewShell->GetFrameView();
    }

    return(pFrameView);
}

/*************************************************************************
|*
|* Groesse der ersten Seite zurueckgeben
|*
\************************************************************************/

Size DrawDocShell::GetFirstPageSize()
{
    return SfxObjectShell::GetFirstPageSize();
}

/*************************************************************************
|*
|* Bitmap einer beliebigen Seite erzeugen
|*
\************************************************************************/

Bitmap DrawDocShell::GetPagePreviewBitmap(SdPage* pPage, USHORT nMaxEdgePixel)
{
    MapMode			aMapMode( MAP_100TH_MM );
    const Size		aSize( pPage->GetSize() );
    const Point		aNullPt;
    VirtualDevice	aVDev( *Application::GetDefaultDevice() );

    aVDev.SetMapMode( aMapMode );

    const Size	aPixSize( aVDev.LogicToPixel( aSize ) );
    const ULONG	nMaxEdgePix = Max( aPixSize.Width(), aPixSize.Height() );
    Fraction	aFrac( nMaxEdgePixel, nMaxEdgePix );

    aMapMode.SetScaleX( aFrac );
    aMapMode.SetScaleY( aFrac );
    aVDev.SetMapMode( aMapMode );
    aVDev.SetOutputSize( aSize );

    // damit die dunklen Linien am rechten und unteren Seitenrans mitkommen
    aFrac = Fraction( nMaxEdgePixel - 1, nMaxEdgePix );
    aMapMode.SetScaleX( aFrac );
    aMapMode.SetScaleY( aFrac );
    aVDev.SetMapMode( aMapMode );

    ClientView*	pView = new ClientView( this, &aVDev, NULL );
    FrameView*		pFrameView = GetFrameView();
    pView->ShowSdrPage( pPage );

    if ( GetFrameView() )
    {
        // Initialisierungen der Zeichen-(Bildschirm-)Attribute
        pView->SetGridCoarse( pFrameView->GetGridCoarse() );
        pView->SetGridFine( pFrameView->GetGridFine() );
        pView->SetSnapGridWidth(pFrameView->GetSnapGridWidthX(), pFrameView->GetSnapGridWidthY());
        pView->SetGridVisible( pFrameView->IsGridVisible() );
        pView->SetGridFront( pFrameView->IsGridFront() );
        pView->SetSnapAngle( pFrameView->GetSnapAngle() );
        pView->SetGridSnap( pFrameView->IsGridSnap() );
        pView->SetBordSnap( pFrameView->IsBordSnap() );
        pView->SetHlplSnap( pFrameView->IsHlplSnap() );
        pView->SetOFrmSnap( pFrameView->IsOFrmSnap() );
        pView->SetOPntSnap( pFrameView->IsOPntSnap() );
        pView->SetOConSnap( pFrameView->IsOConSnap() );
        pView->SetDragStripes( pFrameView->IsDragStripes() );
        pView->SetFrameDragSingles( pFrameView->IsFrameDragSingles() );
        pView->SetSnapMagneticPixel( pFrameView->GetSnapMagneticPixel() );
        pView->SetMarkedHitMovesAlways( pFrameView->IsMarkedHitMovesAlways() );
        pView->SetMoveOnlyDragging( pFrameView->IsMoveOnlyDragging() );
        pView->SetSlantButShear( pFrameView->IsSlantButShear() );
        pView->SetNoDragXorPolys( pFrameView->IsNoDragXorPolys() );
        pView->SetCrookNoContortion( pFrameView->IsCrookNoContortion() );
        pView->SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() );
        pView->SetBigOrtho( pFrameView->IsBigOrtho() );
        pView->SetOrtho( pFrameView->IsOrtho() );

        SdrPageView* pPageView = pView->GetSdrPageView();

        if (pPageView)
        {
            if ( pPageView->GetVisibleLayers() != pFrameView->GetVisibleLayers() )
                pPageView->SetVisibleLayers( pFrameView->GetVisibleLayers() );

            if ( pPageView->GetPrintableLayers() != pFrameView->GetPrintableLayers() )
                pPageView->SetPrintableLayers( pFrameView->GetPrintableLayers() );

            if ( pPageView->GetLockedLayers() != pFrameView->GetLockedLayers() )
                pPageView->SetLockedLayers( pFrameView->GetLockedLayers() );

    //				  if ( pPageView->GetHelpLines() != pFrameView->GetHelpLines() )
                pPageView->SetHelpLines( pFrameView->GetStandardHelpLines() );
        }

        if ( pView->GetActiveLayer() != pFrameView->GetActiveLayer() )
            pView->SetActiveLayer( pFrameView->GetActiveLayer() );
    }

    pView->CompleteRedraw( &aVDev, Rectangle( aNullPt, aSize ) );

    // #111097# IsRedrawReady() always gives sal_True while ( !pView->IsRedrawReady() ) {}
    delete pView;

    aVDev.SetMapMode( MapMode() );

    Bitmap aPreview( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );

    DBG_ASSERT(!!aPreview, "Vorschau-Bitmap konnte nicht erzeugt werden");

    return aPreview;
}


/*************************************************************************
|*
|* Pruefen, ob die Seite vorhanden ist und dann den Anwender zwingen einen
|* noch nicht vorhandenen Namen einzugeben. Wird FALSE zurueckgegeben,
|* wurde die Aktion vom Anwender abgebrochen.
|*
\************************************************************************/

BOOL DrawDocShell::CheckPageName (::Window* pWin, String& rName )
{
    const String aStrForDlg( rName );
    bool bIsNameValid = IsNewPageNameValid( rName, true );

    if( ! bIsNameValid )
    {
        String aDesc( SdResId( STR_WARN_PAGE_EXISTS ) );
        SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
        AbstractSvxNameDialog* aNameDlg = pFact ? pFact->CreateSvxNameDialog( pWin, aStrForDlg, aDesc ) : 0;
        if( aNameDlg )
        {
            aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );

            if( mpViewShell )
                aNameDlg->SetCheckNameHdl( LINK( this, DrawDocShell, RenameSlideHdl ) );

            FunctionReference xFunc( mpViewShell->GetCurrentFunction() );
            if( xFunc.is() )
                xFunc->cancel();

            if( aNameDlg->Execute() == RET_OK )
            {
                aNameDlg->GetName( rName );
                bIsNameValid = IsNewPageNameValid( rName );
            }
            delete aNameDlg;
        }
    }

    return ( bIsNameValid ? TRUE : FALSE );
}

bool DrawDocShell::IsNewPageNameValid( String & rInOutPageName, bool bResetStringIfStandardName /* = false */ )
{
    bool bCanUseNewName = false;

    // check if name is something like 'Slide n'
    String aStrPage( SdResId( STR_SD_PAGE ) );
    aStrPage += ' ';

    bool bIsStandardName = false;

    // prevent also _future_ slide names of the form "'STR_SD_PAGE' + ' ' + '[0-9]+|[a-z]|[A-Z]|[CDILMVX]+|[cdilmvx]+'"
    // (arabic, lower- and upper case single letter, lower- and upper case roman numbers)
    if( 0 == rInOutPageName.Search( aStrPage ) )
    {
        if( rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) >= '0' &&
            rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) <= '9' )
        {
            // check for arabic numbering

            // gobble up all following numbers
            String sRemainder = rInOutPageName.GetToken( 1, sal_Unicode(' ') );
            while( sRemainder.Len() &&
                   sRemainder.GetChar(0) >= '0' &&
                   sRemainder.GetChar(0) <= '9' )
            {
                // trim by one
                sRemainder.Erase(0, 1);
            }

            // EOL? Reserved name!
            if( !sRemainder.Len() )
            {
                bIsStandardName = true;
            }
        }
        else if( rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) >= 'a' &&
                 rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) <= 'z' &&
                 rInOutPageName.GetToken( 1, sal_Unicode(' ') ).Len() == 1 )
        {
            // lower case, single character: reserved
            bIsStandardName = true;
        }
        else if( rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) >= 'A' &&
                 rInOutPageName.GetToken( 1, sal_Unicode(' ') ).GetChar(0) <= 'Z' &&
                 rInOutPageName.GetToken( 1, sal_Unicode(' ') ).Len() == 1 )
        {
            // upper case, single character: reserved
            bIsStandardName = true;
        }
        else
        {
            // check for upper/lower case roman numbering
            String sReserved( String::CreateFromAscii( "cdilmvx" ) );

            // gobble up all following characters contained in one reserved class
            String sRemainder = rInOutPageName.GetToken( 1, sal_Unicode(' ') );
            if( sReserved.Search( sRemainder.GetChar(0) ) == STRING_NOTFOUND )
                sReserved.ToUpperAscii();

            while( sReserved.Search( sRemainder.GetChar(0) ) != STRING_NOTFOUND )
            {
                // trim by one
                sRemainder.Erase(0, 1);
            }

            // EOL? Reserved name!
            if( !sRemainder.Len() )
            {
                bIsStandardName = true;
            }
        }
    }

    if( bIsStandardName )
    {
        if( bResetStringIfStandardName )
        {
            // this is for insertion of slides from other files with standard
            // name.  They get a new standard name, if the string is set to an
            // empty one.
            rInOutPageName = String();
            bCanUseNewName = true;
        }
        else
            bCanUseNewName = false;
    }
    else
    {
        if( rInOutPageName.Len() > 0 )
        {
            BOOL   bOutDummy;
            USHORT nExistingPageNum = mpDoc->GetPageByName( rInOutPageName, bOutDummy );
            bCanUseNewName = ( nExistingPageNum == SDRPAGE_NOTFOUND );
        }
        else
            bCanUseNewName = false;
    }

    return bCanUseNewName;
}

IMPL_LINK( DrawDocShell, RenameSlideHdl, AbstractSvxNameDialog*, pDialog )
{
    if( ! pDialog )
        return 0;

    String aNewName;
    pDialog->GetName( aNewName );

    return IsNewPageNameValid( aNewName );
}
} // end of namespace sd

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
