fdo#52182: Fixed click in frames located in header/footer

Using a distance to click to select the best object to select between
normal text and background object.

Change-Id: Ib5b53161c7af2c16f4df379382f2e53fc6d8092b
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 423dc35..914e189 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -600,7 +600,7 @@ sal_Bool SwNoTxtFrm::GetCharRect( SwRect &rRect, const SwPosition& rPos,


sal_Bool SwNoTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& ,
                             SwCrsrMoveState* ) const
                             SwCrsrMoveState*, bool ) const
{
    SwCntntNode* pCNd = (SwCntntNode*)GetNode();
    pPos->nNode = *pCNd;
diff --git a/sw/source/core/inc/cellfrm.hxx b/sw/source/core/inc/cellfrm.hxx
index 98a9713..050723c 100644
--- a/sw/source/core/inc/cellfrm.hxx
+++ b/sw/source/core/inc/cellfrm.hxx
@@ -39,7 +39,7 @@ public:
    SwCellFrm( const SwTableBox &, SwFrm*, bool bInsertContent = true );
    ~SwCellFrm();

    virtual sal_Bool GetCrsrOfst( SwPosition *, Point&, SwCrsrMoveState* = 0 ) const;
    virtual sal_Bool GetCrsrOfst( SwPosition *, Point&, SwCrsrMoveState* = 0, bool bTestBackground = false ) const;
    virtual void Paint( SwRect const&,
                        SwPrintData const*const pPrintData = NULL ) const;
    virtual void CheckDirection( sal_Bool bVert );
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index d3f62a6..abfd220 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -167,7 +167,7 @@ public:
                        SwPrintData const*const pPrintData = NULL ) const;
    virtual Size ChgSize( const Size& aNewSize );
    virtual sal_Bool GetCrsrOfst( SwPosition *, Point&,
                              SwCrsrMoveState* = 0 ) const;
                              SwCrsrMoveState* = 0, bool bTestBackground = false ) const;

    virtual void  CheckDirection( sal_Bool bVert );
    virtual void Cut();
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index b6db9cf..ebbde55 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -785,7 +785,7 @@ public:
    virtual bool    FillSelection( SwSelectionList& rList, const SwRect& rRect ) const;

    virtual sal_Bool    GetCrsrOfst( SwPosition *, Point&,
                                 SwCrsrMoveState* = 0 ) const;
                                 SwCrsrMoveState* = 0, bool bTestBackground = false ) const;
    virtual sal_Bool    GetCharRect( SwRect &, const SwPosition&,
                                 SwCrsrMoveState* = 0 ) const;
    virtual void Paint( SwRect const&,
diff --git a/sw/source/core/inc/layfrm.hxx b/sw/source/core/inc/layfrm.hxx
index 14c03b0..829c7fc 100644
--- a/sw/source/core/inc/layfrm.hxx
+++ b/sw/source/core/inc/layfrm.hxx
@@ -92,7 +92,7 @@ public:
    virtual bool    FillSelection( SwSelectionList& rList, const SwRect& rRect ) const;

    virtual sal_Bool  GetCrsrOfst( SwPosition *, Point&,
                               SwCrsrMoveState* = 0 ) const;
                               SwCrsrMoveState* = 0, bool bTestBackground = false ) const;

    virtual void Cut();
    virtual void Paste( SwFrm* pParent, SwFrm* pSibling = 0 );
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index cc680df..bce88c4 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -60,7 +60,7 @@ public:
    virtual sal_Bool GetCharRect( SwRect &, const SwPosition&,
                              SwCrsrMoveState* = 0) const;
    sal_Bool GetCrsrOfst(SwPosition* pPos, Point& aPoint,
                     SwCrsrMoveState* = 0) const;
                     SwCrsrMoveState* = 0, bool bTestBackground = false) const;

    const Size &GetGrfSize() const  { return GetSize(); }
    void GetGrfArea( SwRect &rRect, SwRect * = 0, bool bMirror = true ) const;
diff --git a/sw/source/core/inc/pagefrm.hxx b/sw/source/core/inc/pagefrm.hxx
index 271e161..fc4d93c 100644
--- a/sw/source/core/inc/pagefrm.hxx
+++ b/sw/source/core/inc/pagefrm.hxx
@@ -180,7 +180,7 @@ public:
    void PlaceFly( SwFlyFrm* pFly, SwFlyFrmFmt* pFmt );

    virtual sal_Bool GetCrsrOfst( SwPosition *, Point&,
                              SwCrsrMoveState* = 0 ) const;
                              SwCrsrMoveState* = 0, bool bTestBackground = false ) const;
        // erfrage vom Client Informationen
    virtual bool GetInfo( SfxPoolItem& ) const;

diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx
index fafdb0c..02014dc 100644
--- a/sw/source/core/inc/rootfrm.hxx
+++ b/sw/source/core/inc/rootfrm.hxx
@@ -195,7 +195,7 @@ public:
          void     SetDrawPage( SdrPage* pNew ){ pDrawPage = pNew; }

    virtual sal_Bool  GetCrsrOfst( SwPosition *, Point&,
                               SwCrsrMoveState* = 0 ) const;
                               SwCrsrMoveState* = 0, bool bTestBackground = false ) const;

    virtual void Paint( SwRect const&,
                        SwPrintData const*const pPrintData = NULL ) const;
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 3942759..cc1ceaf 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -277,7 +277,7 @@ public:
    //naechsten ist. Wenn der SPoint ausserhalb der SSize liegt,
    //liefert die Funktion sal_False, sal_True sonst.
    virtual sal_Bool GetCrsrOfst( SwPosition *, Point&,
                                  SwCrsrMoveState* = 0) const;
                                  SwCrsrMoveState* = 0, bool bTestBackground = false ) const;

    // GetKeyCrsrOfst sorgt dafuer, dass der Frame nicht gewechselt wird
    // (z.B. Wechsel in den zeichengebundenen Frame).
diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index 60660f1..856845f 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -29,6 +29,7 @@
#include <hintids.hxx>
#include <hints.hxx>
#include <tools/bigint.hxx>
#include <tools/line.hxx>
#include <editeng/opaqitem.hxx>
#include <editeng/protitem.hxx>
#include <vcl/settings.hxx>
@@ -63,9 +64,11 @@
#include <cfloat>
#include <swselectionlist.hxx>

#include <basegfx/numeric/ftools.hxx>

namespace {
    bool lcl_GetCrsrOfst_Objects( const SwPageFrm* pPageFrm, bool bSearchBackground,
           SwPosition *pPos, Point& rPoint, SwCrsrMoveState* pCMS, long& rSurface )
           SwPosition *pPos, Point& rPoint, SwCrsrMoveState* pCMS  )
    {
        bool bRet = false;
        Point aPoint( rPoint );
@@ -89,7 +92,6 @@ namespace {
                   !pFly->IsProtected() ) &&
                 pFly->GetCrsrOfst( pPos, aPoint, pCMS ) )
            {
                rSurface = pFly->Frm().Width() * pFly->Frm().Height();
                bRet = true;
                break;
            }
@@ -101,18 +103,19 @@ namespace {
        return bRet;
    }

    long lcl_GetSurface( SwPosition* pPos )
    double lcl_getDistance( const SwRect& rRect, const Point& rPoint )
    {
        SwRect aArea;
        double nDist = 0.0;

        SwNode& rNode = pPos->nNode.GetNode();
        // If the point is inside the rectangle, then distance is 0
        // Otherwise, compute the distance to the center of the rectangle.
        if ( !rRect.IsInside( rPoint ) )
        {
            Line aLine( rPoint, rRect.Center( ) );
            nDist = aLine.GetLength( );
        }

        if ( rNode.IsCntntNode() )
            aArea = rNode.GetCntntNode()->FindLayoutRect();

        // FIXME Handle the other kinds of nodes?

        return aArea.Height() * aArea.Width();
        return nDist;
    }
}

@@ -164,7 +167,7 @@ static SwCrsrOszControl aOszCtrl = { 0, 0, 0 };
|*
|*************************************************************************/
sal_Bool SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
                               SwCrsrMoveState* pCMS ) const
                               SwCrsrMoveState* pCMS, bool ) const
{
    sal_Bool bRet = sal_False;
    const SwFrm *pFrm = Lower();
@@ -199,7 +202,7 @@ sal_Bool SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
|*************************************************************************/

sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
                             SwCrsrMoveState* pCMS ) const
                             SwCrsrMoveState* pCMS, bool bTestBackground ) const
{
    sal_Bool bRet     = sal_False;
    Point aPoint( rPoint );
@@ -220,14 +223,11 @@ sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
    //hineinsetzen, dadurch sollten alle Aenderungen unmoeglich sein.
    if ( GetSortedObjs() )
    {
        long nObjSurface = 0; // Unused
        bRet = lcl_GetCrsrOfst_Objects( this, false, pPos, rPoint, pCMS, nObjSurface );
        bRet = lcl_GetCrsrOfst_Objects( this, false, pPos, rPoint, pCMS );
    }

    if ( !bRet )
    {
        long nTextSurface = 0;
        long nBackSurface = 0;
        SwPosition aBackPos( *pPos );
        SwPosition aTextPos( *pPos );

@@ -236,7 +236,6 @@ sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
        //aktuellen an. Mit Flys ist es dann allerdings vorbei.
        if ( SwLayoutFrm::GetCrsrOfst( &aTextPos, aPoint, pCMS ) )
        {
            nTextSurface = lcl_GetSurface( &aTextPos );
            bTextRet = sal_True;
        }
        else
@@ -250,8 +249,6 @@ sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
            if ( pCMS && pCMS->bStop )
                return sal_False;

            nTextSurface = pCnt->Frm().Height() * pCnt->Frm().Width();

            OSL_ENSURE( pCnt, "Crsr is gone to a Black hole" );
            if( pCMS && pCMS->pFill && pCnt->IsTxtFrm() )
                bTextRet = pCnt->GetCrsrOfst( &aTextPos, rPoint, pCMS );
@@ -270,11 +267,10 @@ sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
        // Check objects in the background if nothing else matched
        if ( GetSortedObjs() )
        {
            bBackRet = lcl_GetCrsrOfst_Objects( this, true, &aBackPos, rPoint, pCMS, nBackSurface );
            bBackRet = lcl_GetCrsrOfst_Objects( this, true, &aBackPos, rPoint, pCMS );
        }

        // TODO Pick up the best approaching selection
        if ( bTextRet && bBackRet && ( nTextSurface > nBackSurface ) )
        if ( ( bTestBackground && bBackRet ) || !bTextRet )
        {
            bRet = bBackRet;
            pPos->nNode = aBackPos.nNode;
@@ -282,9 +278,49 @@ sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
        }
        else
        {
            bRet = bTextRet;
            pPos->nNode = aTextPos.nNode;
            pPos->nContent = aTextPos.nContent;
            /* In order to provide a selection as accurable as possible when we have both
             * text and brackground object, then we compute the distance between both
             * would-be positions and the click point. The shortest distance wins.
             */
            SwCntntNode* pTextNd = aTextPos.nNode.GetNode( ).GetCntntNode( );
            double nTextDistance = 0;
            bool bValidTextDistance = false;
            if ( pTextNd )
            {
                SwCntntFrm* pTextFrm = pTextNd->getLayoutFrm( getRootFrm( ) );
                SwRect rTextRect;
                pTextFrm->GetCharRect( rTextRect, aTextPos );

                nTextDistance = lcl_getDistance( rTextRect, rPoint );
                bValidTextDistance = true;
            }

            double nBackDistance = 0;
            bool bValidBackDistance = false;
            SwCntntNode* pBackNd = aBackPos.nNode.GetNode( ).GetCntntNode( );
            if ( pBackNd )
            {
                // FIXME There are still cases were we don't have the proper node here.
                SwCntntFrm* pBackFrm = pBackNd->getLayoutFrm( getRootFrm( ) );
                SwRect rBackRect;
                pBackFrm->GetCharRect( rBackRect, aBackPos );

                nBackDistance = lcl_getDistance( rBackRect, rPoint );
                bValidBackDistance = true;
            }

            if ( bValidTextDistance && bValidBackDistance && basegfx::fTools::more( nTextDistance, nBackDistance ) )
            {
                bRet = bBackRet;
                pPos->nNode = aBackPos.nNode;
                pPos->nContent = aBackPos.nContent;
            }
            else
            {
                bRet = bTextRet;
                pPos->nNode = aTextPos.nNode;
                pPos->nContent = aTextPos.nContent;
            }
        }
    }

@@ -360,7 +396,7 @@ bool SwRootFrm::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) c
|*
|*************************************************************************/
sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
                             SwCrsrMoveState* pCMS ) const
                             SwCrsrMoveState* pCMS, bool bTestBackground ) const
{
    sal_Bool bOldAction = IsCallbackActionEnabled();
    ((SwRootFrm*)this)->SetCallbackActionEnabled( sal_False );
@@ -387,7 +423,7 @@ sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
    }
    if ( pPage )
    {
        pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS );
        pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS, bTestBackground );
    }

    ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction );
@@ -412,7 +448,7 @@ sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
|*
|*************************************************************************/
sal_Bool SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
                             SwCrsrMoveState* pCMS ) const
                             SwCrsrMoveState* pCMS, bool ) const
{
    // cell frame does not necessarily have a lower (split table cell)
    if ( !Lower() )
@@ -489,7 +525,7 @@ sal_Bool SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
//am weitesten oben liegt.

sal_Bool SwFlyFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
                            SwCrsrMoveState* pCMS ) const
                            SwCrsrMoveState* pCMS, bool ) const
{
    aOszCtrl.Entry( this );

diff --git a/sw/source/core/layout/unusedf.cxx b/sw/source/core/layout/unusedf.cxx
index d28eb5f..f12f19c 100644
--- a/sw/source/core/layout/unusedf.cxx
+++ b/sw/source/core/layout/unusedf.cxx
@@ -54,7 +54,7 @@ bool SwFrm::FillSelection( SwSelectionList& , const SwRect& ) const
    return false;
}

sal_Bool SwFrm::GetCrsrOfst( SwPosition *, Point&, SwCrsrMoveState*  ) const
sal_Bool SwFrm::GetCrsrOfst( SwPosition *, Point&, SwCrsrMoveState*, bool  ) const
{
    OSL_FAIL( "GetCrsrOfst of the base class, hi!" );
    return sal_False;
diff --git a/sw/source/core/text/frmcrsr.cxx b/sw/source/core/text/frmcrsr.cxx
index 9562f16..059499c 100644
--- a/sw/source/core/text/frmcrsr.cxx
+++ b/sw/source/core/text/frmcrsr.cxx
@@ -682,7 +682,7 @@ sal_Bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
 *************************************************************************/

sal_Bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
                               SwCrsrMoveState* pCMS ) const
                               SwCrsrMoveState* pCMS, bool ) const
{
    MSHORT nChgFrm = 2;
    if( pCMS )
diff --git a/sw/source/ui/docvw/edtwin.cxx b/sw/source/ui/docvw/edtwin.cxx
index e28afb1..99c4fbf 100644
--- a/sw/source/ui/docvw/edtwin.cxx
+++ b/sw/source/ui/docvw/edtwin.cxx
@@ -2779,11 +2779,12 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
    // How many clicks do we need to select a fly frame?
    FrameControlType eControl;
    bool bOverFly = false;
    bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly );
    bool bPageAnchored = false;
    bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
    int nNbFlyClicks = 1;
    // !bOverHeaderFooterFly doesn't mean we have a frame to select
    if ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
         ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) )
    if ( !bPageAnchored && ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
         ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
    {
        nNbFlyClicks = 2;
        if ( _rMEvt.GetClicks( ) < nNbFlyClicks )
@@ -4964,9 +4965,10 @@ void SwEditWin::Command( const CommandEvent& rCEvt )
            // Don't trigger the command on a frame anchored to header/footer is not editing it
            FrameControlType eControl;
            bool bOverFly = false;
            bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly );
            bool bPageAnchored = false;
            bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
            // !bOverHeaderFooterFly doesn't mean we have a frame to select
            if ( rCEvt.IsMouseEvent( ) &&
            if ( !bPageAnchored && rCEvt.IsMouseEvent( ) &&
                 ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
                   ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
            {
@@ -5950,13 +5952,13 @@ bool SwEditWin::IsInHeaderFooter( const Point &rDocPt, FrameControlType &rContro
    return false;
}

bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly ) const
bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly, bool& bPageAnchored ) const
{
    bool bRet = false;
    Point aPt( rDocPos );
    SwWrtShell &rSh = rView.GetWrtShell();
    SwPaM aPam( *rSh.GetCurrentShellCursor().GetPoint() );
    rSh.GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt );
    rSh.GetLayout()->GetCrsrOfst( aPam.GetPoint(), aPt, NULL, true );

    const SwStartNode* pStartFly = aPam.GetPoint()->nNode.GetNode().FindFlyStartNode();
    if ( pStartFly )
@@ -5977,6 +5979,8 @@ bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& r
                else if ( bInFooter )
                    rControl = Footer;
            }
            else
                bPageAnchored = pFlyFmt->GetAnchor( ).GetAnchorId( ) == FLY_AT_PAGE;
        }
    }
    else
diff --git a/sw/source/ui/inc/edtwin.hxx b/sw/source/ui/inc/edtwin.hxx
index cdc9fdf..5c15e32 100644
--- a/sw/source/ui/inc/edtwin.hxx
+++ b/sw/source/ui/inc/edtwin.hxx
@@ -228,7 +228,7 @@ protected:
    /// Returns true if in header/footer area, or in the header/footer control.
    bool    IsInHeaderFooter( const Point &rDocPt, FrameControlType &rControl ) const;

    bool    IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly ) const;
    bool    IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly, bool& bPageAnchored ) const;
public:

    void            UpdatePointer(const Point &, sal_uInt16 nButtons = 0);