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

#include <accmap.hxx>
#include <acccontext.hxx>

#include <viewsh.hxx>
#include <rootfrm.hxx>
#include <flyfrm.hxx>
#include <pagefrm.hxx>
#include <cellfrm.hxx>
#include <swtable.hxx>
#include <dflyobj.hxx>
#include <frmfmt.hxx>
#include <fmtanchr.hxx>
#include <dcontact.hxx>

#include <vcl/window.hxx>

namespace css = ::com::sun::star;

namespace sw { namespace access {

SwAccessibleChild::SwAccessibleChild()
    : mpFrm( 0 )
    , mpDrawObj( 0 )
    , mpWindow( 0 )
{}

SwAccessibleChild::SwAccessibleChild( const SdrObject* pDrawObj )
    : mpFrm( 0 )
    , mpDrawObj( 0 )
    , mpWindow( 0 )
{
    Init( pDrawObj );
}

SwAccessibleChild::SwAccessibleChild( const SwFrm* pFrm )
    : mpFrm( 0 )
    , mpDrawObj( 0 )
    , mpWindow( 0 )
{
    Init( pFrm );
}

SwAccessibleChild::SwAccessibleChild( Window* pWindow )
    : mpFrm( 0 )
    , mpDrawObj( 0 )
    , mpWindow( 0 )
{
    Init( pWindow );
}


SwAccessibleChild::SwAccessibleChild( const SwFrm* pFrm,
                                      const SdrObject* pDrawObj,
                                      Window* pWindow )
{
    if ( pFrm )
    {
        Init( pFrm );
    }
    else if ( pDrawObj )
    {
        Init( pDrawObj );
    }
    else if ( pWindow )
    {
        Init( pWindow );
    }
    OSL_ENSURE( (!pFrm || pFrm == mpFrm) &&
            (!pDrawObj || pDrawObj == mpDrawObj) &&
            (!pWindow || pWindow == mpWindow),
            "invalid frame/object/window combination" );

}

void SwAccessibleChild::Init( const SdrObject* pDrawObj )
{
    mpDrawObj = pDrawObj;
    mpFrm = mpDrawObj && mpDrawObj->ISA(SwVirtFlyDrawObj)
            ? static_cast < const SwVirtFlyDrawObj * >( mpDrawObj )->GetFlyFrm()
            : 0;
    mpWindow = 0;
}

void SwAccessibleChild::Init( const SwFrm* pFrm )
{
    mpFrm = pFrm;
    mpDrawObj = mpFrm && mpFrm->IsFlyFrm()
                ? static_cast < const SwFlyFrm * >( mpFrm )->GetVirtDrawObj()
                : 0;
    mpWindow = 0;
}

void SwAccessibleChild::Init( Window* pWindow )
{
    mpWindow = pWindow;
    mpFrm = 0;
    mpDrawObj = 0;
}

bool SwAccessibleChild::IsAccessible( sal_Bool bPagePreview ) const
{
    bool bRet( false );

    if ( mpFrm )
    {
        bRet = mpFrm->IsAccessibleFrm() &&
               ( !mpFrm->IsCellFrm() ||
                 static_cast<const SwCellFrm *>( mpFrm )->GetTabBox()->GetSttNd() != 0 ) &&
               !mpFrm->IsInCoveredCell() &&
               ( bPagePreview ||
                 !mpFrm->IsPageFrm() );
    }
    else if ( mpDrawObj )
    {
        bRet = true;
    }
    else if ( mpWindow )
    {
        bRet = true;
    }

    return bRet;
}

bool SwAccessibleChild::IsBoundAsChar() const
{
    bool bRet( false );

    if ( mpFrm )
    {
        bRet = mpFrm->IsFlyFrm() &&
               static_cast< const SwFlyFrm *>(mpFrm)->IsFlyInCntFrm();
    }
    else if ( mpDrawObj )
    {
        const SwFrmFmt* mpFrmFmt = ::FindFrmFmt( mpDrawObj );
        bRet = mpFrmFmt
               ? (FLY_AS_CHAR == mpFrmFmt->GetAnchor().GetAnchorId())
               : false;
    }
    else if ( mpWindow )
    {
        bRet = false;
    }

    return bRet;
}

SwAccessibleChild::SwAccessibleChild( const SwAccessibleChild& r )
    : mpFrm( r.mpFrm )
    , mpDrawObj( r.mpDrawObj )
    , mpWindow( r.mpWindow )
{}

SwAccessibleChild& SwAccessibleChild::operator=( const SwAccessibleChild& r )
{
    mpDrawObj = r.mpDrawObj;
    mpFrm = r.mpFrm;
    mpWindow = r.mpWindow;

    return *this;
}

SwAccessibleChild& SwAccessibleChild::operator=( const SdrObject* pDrawObj )
{
    Init( pDrawObj );
    return *this;
}

SwAccessibleChild& SwAccessibleChild::operator=( const SwFrm* pFrm )
{
    Init( pFrm );
    return *this;
}

SwAccessibleChild& SwAccessibleChild::operator=( Window* pWindow )
{
    Init( pWindow );
    return *this;
}

bool SwAccessibleChild::operator==( const SwAccessibleChild& r ) const
{
    return mpFrm == r.mpFrm &&
           mpDrawObj == r.mpDrawObj &&
           mpWindow == r.mpWindow;
}

bool SwAccessibleChild::IsValid() const
{
    return mpFrm != 0 ||
           mpDrawObj != 0 ||
           mpWindow != 0;
}

const SdrObject* SwAccessibleChild::GetDrawObject() const
{
    return mpDrawObj;
}

const SwFrm *SwAccessibleChild::GetSwFrm() const
{
    return mpFrm;
}

Window* SwAccessibleChild::GetWindow() const
{
    return mpWindow;
}

bool SwAccessibleChild::IsVisibleChildrenOnly() const
{
    bool bRet( false );

    if ( !mpFrm )
    {
        bRet = true;
    }
    else
    {
        bRet = mpFrm->IsRootFrm() ||
               !( mpFrm->IsTabFrm() ||
                  mpFrm->IsInTab() ||
                  ( IsBoundAsChar() &&
                    static_cast<const SwFlyFrm*>(mpFrm)->GetAnchorFrm()->IsInTab() ) );
    }

    return bRet;
}

SwRect SwAccessibleChild::GetBox( const SwAccessibleMap& rAccMap ) const
{
    SwRect aBox;

    if ( mpFrm )
    {
        if ( mpFrm->IsPageFrm() &&
             static_cast< const SwPageFrm * >( mpFrm )->IsEmptyPage() )
        {
            aBox = SwRect( mpFrm->Frm().Left(), mpFrm->Frm().Top()-1, 1, 1 );
        }
        else if ( mpFrm->IsTabFrm() )
        {
            aBox = SwRect( mpFrm->Frm() );
            aBox.Intersection( mpFrm->GetUpper()->Frm() );
        }
        else
        {
            aBox = mpFrm->Frm();
        }
    }
    else if( mpDrawObj )
    {
        aBox = SwRect( mpDrawObj->GetCurrentBoundRect() );
    }
    else if ( mpWindow )
    {
        aBox = SwRect( rAccMap.GetShell()->GetWin()->PixelToLogic(
                                        Rectangle( mpWindow->GetPosPixel(),
                                                   mpWindow->GetSizePixel() ) ) );
}

    return aBox;
}

SwRect SwAccessibleChild::GetBounds( const SwAccessibleMap& rAccMap ) const
{
    SwRect aBound;

    if( mpFrm )
    {
        if( mpFrm->IsPageFrm() &&
            static_cast< const SwPageFrm * >( mpFrm )->IsEmptyPage() )
        {
            aBound = SwRect( mpFrm->Frm().Left(), mpFrm->Frm().Top()-1, 0, 0 );
        }
        else
            aBound = mpFrm->PaintArea();
    }
    else if( mpDrawObj )
    {
        aBound = GetBox( rAccMap );
    }
    else if ( mpWindow )
    {
        aBound = GetBox( rAccMap );
    }

    return aBound;
}

bool SwAccessibleChild::AlwaysIncludeAsChild() const
{
    bool bAlwaysIncludedAsChild( false );

    if ( mpWindow )
    {
        bAlwaysIncludedAsChild = true;
    }

    return bAlwaysIncludedAsChild;
}

const SwFrm* SwAccessibleChild::GetParent( const sal_Bool bInPagePreview ) const
{
    const SwFrm* pParent( 0 );

    if ( mpFrm )
    {
        if( mpFrm->IsFlyFrm() )
        {
            const SwFlyFrm* pFly = static_cast< const SwFlyFrm *>( mpFrm );
            if( pFly->IsFlyInCntFrm() )
            {
                // For FLY_AS_CHAR the parent is the anchor
                pParent = pFly->GetAnchorFrm();
                OSL_ENSURE( SwAccessibleChild( pParent ).IsAccessible( bInPagePreview ),
                        "parent is not accessible" );
            }
            else
            {
                // In any other case the parent is the root frm
                // (in page preview, the page frame)
                if( bInPagePreview )
                    pParent = pFly->FindPageFrm();
                else
                    pParent = pFly->getRootFrm();
            }
        }
        else
        {
            SwAccessibleChild aUpper( mpFrm->GetUpper() );
            while( aUpper.GetSwFrm() && !aUpper.IsAccessible(bInPagePreview) )
            {
                aUpper = aUpper.GetSwFrm()->GetUpper();
            }
            pParent = aUpper.GetSwFrm();
        }
    }
    else if( mpDrawObj )
    {
        const SwDrawContact *pContact =
            static_cast< const SwDrawContact* >( GetUserCall( mpDrawObj ) );
        OSL_ENSURE( pContact, "sdr contact is missing" );
        if( pContact )
        {
            const SwFrmFmt *pFrmFmt = pContact->GetFmt();
            OSL_ENSURE( pFrmFmt, "frame format is missing" );
            if( pFrmFmt && FLY_AS_CHAR == pFrmFmt->GetAnchor().GetAnchorId() )
            {
                // For FLY_AS_CHAR the parent is the anchor
                pParent = pContact->GetAnchorFrm();
                OSL_ENSURE( SwAccessibleChild( pParent ).IsAccessible( bInPagePreview ),
                        "parent is not accessible" );

            }
            else
            {
                // In any other case the parent is the root frm
                if( bInPagePreview )
                    pParent = pContact->GetAnchorFrm()->FindPageFrm();
                else
                    pParent = pContact->GetAnchorFrm()->getRootFrm();
            }
        }
    }
    else if ( mpWindow )
    {
        css::uno::Reference < css::accessibility::XAccessible > xAcc =
                                                    mpWindow->GetAccessible();
        if ( xAcc.is() )
        {
            css::uno::Reference < css::accessibility::XAccessibleContext > xAccContext =
                                                xAcc->getAccessibleContext();
            if ( xAccContext.is() )
            {
                css::uno::Reference < css::accessibility::XAccessible > xAccParent =
                                                xAccContext->getAccessibleParent();
                if ( xAccParent.is() )
                {
                    SwAccessibleContext* pAccParentImpl =
                                dynamic_cast< SwAccessibleContext *>( xAccParent.get() );
                    if ( pAccParentImpl )
                    {
                        pParent = pAccParentImpl->GetFrm();
                    }
                }
            }
        }
    }

    return pParent;
}

} } // eof of namespace sw::access

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