/* -*- 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.
 *
 ************************************************************************/

#include <stdio.h>

#ifdef WNT
#include <bf_svtools/bf_prewin.h>
#include <windows.h>
#include <bf_svtools/bf_postwin.h>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/sysdata.hxx>
#endif

#include <vcl/salbtype.hxx>
#include <vcl/window.hxx>
#include <bf_so3/client.hxx>
#include <tools/debug.hxx>
#include <tools/urlobj.hxx>
#include <bf_so3/embobj.hxx>
#include "bf_so3/soerr.hxx"

namespace binfilter {

TYPEINIT0(SvClientData);

SvClientData::SvClientData( SvEmbeddedClient * pCl, Window * pWin )
    : pClient( pCl )
    , aScaleWidth( 1, 1 )
    , aScaleHeight( 1, 1 )
    , pEditWin( pWin )
    , bInvalidate( pWin != NULL )
{
}

SvClientData::~SvClientData()
{
}

void SvClientData::Invalidate()
/*  [Beschreibung]

    Der Bereich des Objektes auf dem EditWin wird f"ur ung"ultig
    erkl"art, sodass ein asynchroner PaintEvent generiert wird. Dies
    passiert nur, wenn die Methode <SvClientData::IsInvalidate> TRUE
    liefert.

    [Querverweise]

    <Window::Paint>, <SvClientData::GetEditWin>,
    <SvClientData::SetInvalidate>.
*/
{
    if( bInvalidate )
    {
        Rectangle aR = GetObjArea();
        aR.SetSize( Size( Fraction( aR.GetWidth() ) * aScaleWidth,
                        Fraction( aR.GetHeight() ) * aScaleHeight ) );
        pEditWin->Invalidate( aR );
    }
}

Window * SvClientData::GetEditWin() const
/*  [Beschreibung]

    Diese Methode liefert das Fenster in dem das Objekt im
    Container dargestellt wird. Dieses Fenster wird als Parent bei
    InPlace-Aktivit"at benutzt.

    [R"uckgabewert]

    Window *    Das Fenster in dem das Objekt dargestellt wird.
                NULL, wenn das Objekt nciht dargestellt wird oder der
                Client kein Fenster liefert.
*/
{
    return pEditWin;
}

void SvClientData::SetSizeScale
(
    const Fraction & rScaleWidth,
    const Fraction & rScaleHeight
)
/*  [Beschreibung]

    Hat das Objekt abweichend vom OutputDevice des EditWin eine andere
    Skalierung, dann muss diese mitgeteilt werden. Die Skalierung ist
    relativ zum Outputdevice und bezieht sich nur auf die Gr"osse des
    Objektes.
*/
{
    aScaleWidth = rScaleWidth;
    aScaleHeight = rScaleHeight;
}

BOOL SvClientData::SetObjArea
(
    const Rectangle & rArea
)
/*  [Beschreibung]

    Die Gr"oesse des Objektes innerhalb des Containers in Einheiten
    des EditWin wird gesetzt. Die Methode l"ost ein
    <SvClientData::Invalidate> auf den alten und den neuen Bereich aus,
    wenn sich diese unterscheiden.

    [Querverweise]

    <SvClientData::GetObjArea>, <SvClientData::SetObjAreaPixel>
*/
{
    if( rArea != aObjRect )
    {
        Invalidate(); // auf Alte
        aObjRect = rArea;
        Invalidate(); // auf Neue
        return TRUE; // Bereich hat sich geandert
   }
   return FALSE;  // Bereich hat sich geandert
}

Rectangle SvClientData::GetObjArea() const
/*  [Beschreibung]

    [R"uckgabewert]

    Rectangle   Die Gr"oesse des Objektes innerhalb des Containers
                in Einheiten des EditWin wir zur"uckgegeben.

    [Querverweise]

    <SvClientData::SetObjArea>, <SvClientData::GetObjAreaPixel>

*/
{
    return aObjRect;
}

Rectangle SvClientData::PixelObjAreaToLogic
(
    const Rectangle & rPixRect
) const
/*  [Beschreibung]

    [R"uckgabewert]

    Rectangle   rPixRect wird in Einheiten des EditWin, unter
                Ber"ucksichtigung der extra Skalierung, umgerechnet.

    [Querverweise]

    <SvClientData::SetSizeScale>, <SvClientData::LogicObjAreaToPixel>

*/
{
    Rectangle aR = rPixRect;
    if( pEditWin )
    {
        aR.SetSize( pEditWin->PixelToLogic( aR.GetSize() ) );
        aR.SetPos( pEditWin->PixelToLogic( aR.TopLeft() ) );
    }
    aR.SetSize( Size( Fraction( aR.GetWidth() ) / aScaleWidth,
                        Fraction( aR.GetHeight() ) / aScaleHeight ) );

    return aR;
}

#include <math.h>

Rectangle SvClientData::LogicObjAreaToPixel
(
    const Rectangle & rRect
) const
/*  [Beschreibung]

    [R"uckgabewert]

    Rectangle   rRect in Einheiten des EditWin wird, unter
                Ber"ucksichtigung der extra Skalierung, in Pixel
                umgerechnet.

    [Querverweise]

    <SvClientData::SetSizeScale>, <SvClientData::PixelObjAreaToLogic>

*/
{
    Rectangle aR( rRect );
    // *must* happen before LogicToPixel conversion, as:
    // scaling down to pixel is integer, which leads to
    // rounding errors (#89984#)
    aR.SetSize( Size( FRound( double(Fraction( aR.GetWidth() ) * aScaleWidth) ),
                      FRound( double(Fraction( aR.GetHeight() ) * aScaleHeight ) ) ) );
    // Wenn kein Window, dann extern und somit Pixel
    if( pEditWin )
    {
        aR.SetSize( pEditWin->LogicToPixel( aR.GetSize() ) );
        aR.SetPos( pEditWin->LogicToPixel( aR.TopLeft() ) );
    }
    return aR;
}

/************** class SvEmbeddedClient **************************************/
SV_IMPL_FACTORY(SvEmbeddedClientFactory)
    {
    }
};
TYPEINIT1(SvEmbeddedClientFactory,SvFactory);

SO2_IMPL_STANDARD_CLASS1_DLL(SvEmbeddedClient,SvEmbeddedClientFactory,SvObject,
                             0xE4CAFE00L, 0x73AE, 0x101B,
                             0x80,0x4C,0xFD,0xFD,0xFD,0xFD,0xFD,0xFD );

::IUnknown * SvEmbeddedClient::GetMemberInterface( const SvGlobalName & rName )
{
    (void)rName;
    return NULL;
}

/************************************************************************
|*    SvEmbeddedClient::SvEmbeddedClient()
*************************************************************************/
//==============SvEmbeddedClient===========================================
#define INIT_CTOR                               \
      pParent           ( NULL )                \
    , nAspect           ( ASPECT_CONTENT )      \
    , bAutoForce        ( TRUE )                \
    , bDeleteData       ( FALSE )               \
    , bCanPlugIn        ( FALSE )

SvEmbeddedClient::SvEmbeddedClient()
    : pData( NULL )
    , INIT_CTOR
{
}

SvEmbeddedClient::~SvEmbeddedClient()
{
    if( bDeleteData )
        delete pData;
}

void SvEmbeddedClient::MakeViewData()
/*  [Beschreibung]

    Der Client liefert ein View-Environment, der IP-Aktivierung oder
    das Invalidieren des Objektbereichs in der View des Containers
    ermoeglicht. Wenn in dieser virtuellen Methode das Environment
    erzeugt wird, dann muss es mit <SvClientData::SetClientData>
    eingesetzt werden. Von den Klassen <SvClientData> oder
    <SvContainerEnvironment> muss ein Konstruktor gerufen werden, der
    ein <SvEmbeddedClient> !ubergeben bekommt.
    Wenn keine View vorhanden ist, dann wird wird in dieser Methode
    nichts getan oder eine View angelegt.

    [Beispiel]
    // die n"chsten beiden Zeilen sind Optional
    if( !HasView() )
        CreateView();

    if( HasView() )
    {
        SvClientData * pD = new SvClientData( this, aView.GetEditWin() );
        SetViewData( pD );
    }

    [Querverweise]

    <SvEmbeddedClient::HasViewData>, <SvEmbeddedClient::FreeViewData>
*/
{
    if( !Owner() && !pData )
    {
        pData = new SvClientData( this );
        bDeleteData = TRUE;
        // In ImpOleObject::DoVerb "ubergebenes Rectangle
        pData->SetObjAreaPixel( aDoVerbRectPixel );
    }
}

void SvEmbeddedClient::FreeViewData
(
    SvClientData * pDataP   /* View-Daten die zerst"ort werden k"onnen */
)
/*  [Beschreibung]

    Die View-Daten k"onnen freigegeben werden. Werden sie zerst"ort,
    dann m"ussen sie vorher mit <SvEmbeddedClient::SetViewData( NULL )>
    ausgetragen werden.

    [Beispiel]
    ...::FreeViewData( SvClientData * pData )
    {
        SetViewData( NULL );
        delete pData;
    }

    [Querverweise]

    <SvEmbeddedClient::HasViewData>, <SvEmbeddedClient::FreeViewData>
*/
{
#ifdef DBG_UTIL
    DBG_ASSERT( pDataP == pData, "pDataP != pData!" );
#else
    (void)pDataP;
#endif
    if( !Owner() && bDeleteData )
    {
        delete pData;
        pData = NULL;
    }
}

SvClientData * SvEmbeddedClient::GetClientData()
/*  [Beschreibung]

    Gibt die View-Daten zur"uck. Neue View-Daten werden
    nur angelegt, wenn der Client "Connected" ist.

    [R"uckgabewert]

    SvContainerEnvironment *    Das Environment zu diesem Client wird
                                zur"uckgegeben.

    [Querverweise]

    <SvProtocol::IsConnect>, <SvEmbeddedClient::MakeViewData>
*/
{
    if( !pData && GetProtocol().IsConnect() )
        MakeViewData();
    return pData;
}

BOOL SvEmbeddedClient::CanPlugIn()
{
    return bCanPlugIn;
}

ErrCode SvEmbeddedClient::GetContURL
(
    INetURLObject & rURL    /* Hier wird der URL des Containers
                               abgelegt. */
)
/*  [Beschreibung]

    Die URL des Dokumentes wird zur"uckgegeben. Defaultm"assig wird
    versucht die URL aus dem Moniker zu generieren.

    [R"uckgabewert]

    ERRCODE_NONE,   In rURL steht der URL des Dokumentes.
    ERRCODE_SO_GENERALERROR, rURL ist leer.

    [Querverweise]

    <SvEmbeddedClient::GetObjMoniker()>
*/
{
    (void)rURL;
    ULONG nRet = ERRCODE_SO_GENERALERROR;
    return nRet;
}

void SvEmbeddedClient::Embedded( BOOL bEmbed )
{
#ifdef DBG_UTIL_PROT
    String aTest( "Client---Embedded---" );
    aTest += Owner() ? "Intern" : "Extern: ";
    aTest += bEmbed ? "TRUE" : "FALSE";
    OSL_TRACE( "%s", aTest.GetBuffer() );
#endif

    if( Owner() )
    {
        if( !bEmbed && pData && pData->pEditWin )
        {
            pData->pEditWin->ToTop( TOTOP_FOREGROUNDTASK );
        }

        SvClientData * pD = GetClientData();
        if( pD )
            pD->Invalidate();
    }
    if( !bEmbed && HasViewData() )
        FreeViewData( pData );
}

void SvEmbeddedClient::PlugIn( BOOL bPlugIn )
{
#ifdef DBG_UTIL_PROT
    String aTest( "Client---PlugIn---" );
    aTest += Owner() ? "Intern" : "Extern: ";
    aTest += bPlugIn ? "TRUE" : "FALSE";
    OSL_TRACE( "%s", aTest.GetBuffer() )
#else
    (void)bPlugIn;
#endif

}

void SvEmbeddedClient::ViewChanged( USHORT nAspectP )
{
    if( Owner() )
    {
        if( GetAspect() == nAspectP )
        {
            SvClientData * pD = GetClientData();
            if( pD )
               pD->Invalidate();
        }
    }
}

BOOL SvEmbeddedClient::SaveObject()
{
    BOOL bRet = FALSE;
    if( Owner() )
    {
        SvEmbeddedObject * pE = GetEmbedObj();
        if( pE )
        {
            bRet = false;
            // was pE->DoSaveCompleted(); but return value is not checked
        }
    }
    return bRet;
}

SvEmbeddedObjectRef SvEmbeddedClient::GetContainer()
/*  [Beschreibung]

    Diese Methode liefert den Container (Dokument), in dem das,
    mit dem Client verbundene, Objekt enthalten ist.

    [R"uckgabewert]

    SvEmbeddedObjectRef     Der Container des Objektes oder NULL, wenn
                            das Objekt nirgentwo enthalten ist.
*/
{
    SvEmbeddedObjectRef xCont;
    if( Owner() )
    {
        if( GetParent() )
            xCont = GetParent()->GetEmbedObj();
        else
        {
            SvEmbeddedObject * pE = GetEmbedObj();
            if( pE )
                // nutzt die Hierarchie der SvPersist-Objekte fuer Default
                xCont = SvEmbeddedObjectRef( pE->GetParent() );
        }
    }
    return xCont;
}

void SvEmbeddedClient::MakeVisible()
/*  [Beschreibung]

    Das Objekt, mit dem dieser Client verbunden ist, soll in den
    sichtbaren Bereich des Containers geschoben werden.
*/
{
    if( GetParent() )
        GetParent()->MakeVisible();

}

/*************************************************************************
|*    InPlace Protocoll
*************************************************************************/
void SvEmbeddedClient::Connected( BOOL bConnect )
{ // Zu dieser Methode gibt es kein Ole2 aequivalent
#ifdef DBG_UTIL_PROT
    String aTest( "Client---Connected---" );
    aTest += Owner() ? "Intern" : "Extern: ";
    aTest += bConnect ? "TRUE" : "FALSE";
    OSL_TRACE( "%s", aTest.GetBuffer() )
#endif
    if( !bConnect && HasViewData() )
        FreeViewData( pData );
}

void SvEmbeddedClient::Closed()
{
    // genau in diesem muss die InClose-Variable zurueckgesetzt werden
    SvEditObjectProtocol aProt_( GetProtocol() );
    aProt_.SetInClosed( TRUE );
    if( Owner() )
        GetProtocol().Reset();
    aProt_.SetInClosed( FALSE );
}

void SvEmbeddedClient::Opened( BOOL bOpen )
{
#ifdef DBG_UTIL_PROT
    String aTest( "Client---Opened---" );
    aTest += Owner() ? "Intern" : "Extern: ";
    aTest += bOpen ? "TRUE" : "FALSE";
    OSL_TRACE( "%s", aTest.GetBuffer() )
#else
    (void)bOpen;
#endif

}

}

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