From e8fbe97900f13305b17015d9044993bde4adab36 Mon Sep 17 00:00:00 2001 From: Cédric Bosdonnat Date: Fri, 23 Nov 2012 17:51:16 +0100 Subject: 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 --- sw/source/core/doc/notxtfrm.cxx | 2 +- sw/source/core/inc/cellfrm.hxx | 2 +- sw/source/core/inc/flyfrm.hxx | 2 +- sw/source/core/inc/frame.hxx | 2 +- sw/source/core/inc/layfrm.hxx | 2 +- sw/source/core/inc/notxtfrm.hxx | 2 +- sw/source/core/inc/pagefrm.hxx | 2 +- sw/source/core/inc/rootfrm.hxx | 2 +- sw/source/core/inc/txtfrm.hxx | 2 +- sw/source/core/layout/trvlfrm.cxx | 96 +++++++++++++++++++++++++++------------ sw/source/core/layout/unusedf.cxx | 2 +- sw/source/core/text/frmcrsr.cxx | 2 +- sw/source/ui/docvw/edtwin.cxx | 18 +++++--- sw/source/ui/inc/edtwin.hxx | 2 +- 14 files changed, 89 insertions(+), 49 deletions(-) diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx index 423dc355d2a9..914e189a2707 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 98a9713691e7..050723ccea3e 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 d3f62a6dc7f7..abfd2209e6ff 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 b6db9cf82f46..ebbde55d34f8 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 14c03b088009..829c7fc8b7fa 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 cc680df185a7..bce88c45f209 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 271e161a88e7..fc4d93c72a59 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 fafdb0c762ff..02014dcd5cde 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 3942759dc1d1..cc1ceaf5ce5f 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 60660f17c170..856845f5428d 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,11 @@ #include #include +#include + 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; - - SwNode& rNode = pPos->nNode.GetNode(); - - if ( rNode.IsCntntNode() ) - aArea = rNode.GetCntntNode()->FindLayoutRect(); + double nDist = 0.0; - // FIXME Handle the other kinds of nodes? + // 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( ); + } - 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 d28eb5fedb7a..f12f19cb8fb6 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 9562f1609808..059499c16c37 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 e28afb12b3e2..99c4fbffc5f8 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 cdc9fdf71f18..5c15e325f892 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); -- cgit v1.2.3