diff options
Diffstat (limited to 'sw/source')
-rw-r--r-- | sw/source/core/access/accpara.cxx | 134 | ||||
-rw-r--r-- | sw/source/core/access/accpara.hxx | 8 | ||||
-rw-r--r-- | sw/source/core/access/accportions.cxx | 220 | ||||
-rw-r--r-- | sw/source/core/access/accportions.hxx | 34 |
4 files changed, 367 insertions, 29 deletions
diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx index 941c806f1bb7..54c20bc4d608 100644 --- a/sw/source/core/access/accpara.cxx +++ b/sw/source/core/access/accpara.cxx @@ -2,9 +2,9 @@ * * $RCSfile: accpara.cxx,v $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * - * last change: $Author: mib $ $Date: 2002-02-27 09:32:33 $ + * last change: $Author: dvo $ $Date: 2002-02-27 17:28:54 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -74,6 +74,16 @@ #ifndef _UNOOBJ_HXX #include <unoobj.hxx> #endif +#ifndef _CRSTATE_HXX +#include <crstate.hxx> +#endif +#ifndef _ACCMAP_HXX +#include <accmap.hxx> +#endif +#ifndef _CRSRSH_HXX +#include <crsrsh.hxx> +#endif + #pragma hdrstop @@ -83,6 +93,9 @@ #ifndef _SV_SVAPP_HXX //autogen #include <vcl/svapp.hxx> #endif +#ifndef _SV_WINDOW_HXX +#include <vcl/window.hxx> +#endif #ifndef _RTL_USTRBUF_HXX_ #include <rtl/ustrbuf.hxx> #endif @@ -516,12 +529,43 @@ Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes( sal_Int32 return aSeq; } -com::sun::star::awt::Rectangle SwAccessibleParagraph::getCharacterBounds( sal_Int32 nIndex ) +com::sun::star::awt::Rectangle SwAccessibleParagraph::getCharacterBounds( + sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) { - // HACK: dummy implementation - com::sun::star::awt::Rectangle aRect; - return aRect; + vos::OGuard aGuard(Application::GetSolarMutex()); + CHECK_FOR_DEFUNC( XAccessibleContext ); // we have a frame? + + if( (nIndex < 0) || (nIndex >= GetString().getLength()) ) + throw IndexOutOfBoundsException(); + + // get model position & prepare GetCharRect() arguments + SwCrsrMoveState aMoveState; + aMoveState.bRealHeight = TRUE; + aMoveState.bRealWidth = TRUE; + SwSpecialPos aSpecialPos; + USHORT nPos = GetPortionData().FillSpecialPos( + nIndex, aSpecialPos, aMoveState.pSpecialPos ); + + // call GetCharRect + SwRect aCoreRect; + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + SwIndex aIndex( pNode, nPos ); + SwPosition aPosition( *pNode, aIndex ); + GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState ); + + // translate core coordinates into accessibility coordinates + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); + aCoreRect -= GetBounds().TopLeft(); + MapMode aMapMode = pWin->GetMapMode(); + aMapMode.SetOrigin( Point() ); + Rectangle aScreenRect( pWin->LogicToPixel( aCoreRect.SVRect(), aMapMode )); + + // convert into AWT Rectangle + return com::sun::star::awt::Rectangle( + aScreenRect.Left(), aScreenRect.Top(), + aScreenRect.GetWidth(), aScreenRect.GetHeight() ); } sal_Int32 SwAccessibleParagraph::getCharacterCount() @@ -542,22 +586,34 @@ sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const com::sun::star::awt::Poi OUString SwAccessibleParagraph::getSelectedText() throw (RuntimeException) { - // HACK: dummy implementation - return OUString(RTL_CONSTASCII_USTRINGPARAM("Peter")); + vos::OGuard aGuard(Application::GetSolarMutex()); + CHECK_FOR_DEFUNC( XAccessibleContext ); // we have a frame? + + sal_Int32 nStart, nEnd; + sal_Bool bSelected = GetSelection( nStart, nEnd ); + return bSelected ? GetString().copy( nStart, nEnd - nStart ) : OUString(); } sal_Int32 SwAccessibleParagraph::getSelectionStart() throw (RuntimeException) { - // HACK: dummy implementation - return 0; + vos::OGuard aGuard(Application::GetSolarMutex()); + CHECK_FOR_DEFUNC( XAccessibleContext ); // we have a frame? + + sal_Int32 nStart, nEnd; + GetSelection( nStart, nEnd ); + return nStart; } sal_Int32 SwAccessibleParagraph::getSelectionEnd() throw (RuntimeException) { - // HACK: dummy implementation - return 0; + vos::OGuard aGuard(Application::GetSolarMutex()); + CHECK_FOR_DEFUNC( XAccessibleContext ); // we have a frame? + + sal_Int32 nStart, nEnd; + GetSelection( nStart, nEnd ); + return nEnd; } sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) @@ -735,3 +791,57 @@ sal_Bool SwAccessibleParagraph::setText( const OUString& sText ) return replaceText(0, GetString().getLength(), sText); } + + + +sal_Bool SwAccessibleParagraph::GetSelection( + sal_Int32& nStart, sal_Int32& nEnd) +{ + sal_Bool bRet = sal_False; + nStart = -1; + nEnd = -1; + + // first, get the view shell + DBG_ASSERT( GetMap() != NULL, "no map?" ); + ViewShell* pViewShell = GetMap()->GetShell(); + DBG_ASSERT( pViewShell != NULL, + "No view shell? Then what are you looking at?" ); + + // get the cursor shell; if we don't have any, we don't have a + // selection either + if( pViewShell->ISA( SwCrsrShell ) ) + { + SwCrsrShell* pCrsrShell = static_cast<SwCrsrShell*>( pViewShell ); + + // get the selection, and test whether it affects our text node + SwPaM* pCrsr = pCrsrShell->GetCrsr( FALSE /* ??? */ ); + if( pCrsr != NULL ) + { + const SwTxtNode* pNode = GetTxtNode(); + + // get SwPosition for my node + ULONG nHere = pNode->GetIndex(); + + // check whether nHere is 'inside' pCrsr + SwPosition* pStart = pCrsr->Start(); + SwPosition* pEnd = pCrsr->End(); + if( ( nHere >= pStart->nNode.GetIndex() ) && + ( nHere <= pEnd->nNode.GetIndex() ) ) + { + // Yup, we are selected! + bRet = sal_True; + nStart = static_cast<sal_Int32>( + ( nHere > pStart->nNode.GetIndex() ) ? 0 + : pStart->nContent.GetIndex() ); + nEnd = static_cast<sal_Int32>( + ( nHere < pEnd->nNode.GetIndex() ) ? pNode->Len() + : pEnd->nContent.GetIndex() ); + } + // else: this paragraph isn't selected + } + // else: nocursor -> no selection + } + // else: no cursor shell -> no selection + + return bRet; +} diff --git a/sw/source/core/access/accpara.hxx b/sw/source/core/access/accpara.hxx index 79294a316290..787070aa11f8 100644 --- a/sw/source/core/access/accpara.hxx +++ b/sw/source/core/access/accpara.hxx @@ -2,9 +2,9 @@ * * $RCSfile: accpara.hxx,v $ * - * $Revision: 1.5 $ + * $Revision: 1.6 $ * - * last change: $Author: mib $ $Date: 2002-02-20 17:55:57 $ + * last change: $Author: dvo $ $Date: 2002-02-27 17:28:54 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -76,6 +76,7 @@ class SwTxtFrm; class SwTxtNode; +class SwPaM; class SwAccessiblePortionData; namespace rtl { class OUString; } namespace com { namespace sun { namespace star { @@ -104,6 +105,9 @@ class SwAccessibleParagraph : public SwAccessibleContext, /// get the (accessible) text string (requires frame; check before) rtl::OUString GetString(); + /// determine whether the current selection. Fill the values with + /// -1 if there is no selection in the this paragraph + sal_Bool GetSelection(sal_Int32& nStart, sal_Int32& nEnd); public: diff --git a/sw/source/core/access/accportions.cxx b/sw/source/core/access/accportions.cxx index 1e6b4cf2fcca..158a5f550325 100644 --- a/sw/source/core/access/accportions.cxx +++ b/sw/source/core/access/accportions.cxx @@ -2,9 +2,9 @@ * * $RCSfile: accportions.cxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * - * last change: $Author: dvo $ $Date: 2002-02-21 14:55:31 $ + * last change: $Author: dvo $ $Date: 2002-02-27 17:28:54 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -75,7 +75,12 @@ #include <com/sun/star/i18n/Boundary.hpp> #endif -// for GetWordBoundary, GetSentenceBoundary: +#ifndef _TXTTYPES_HXX +#include <txttypes.hxx> +#endif + + +// for GetWordBoundary(...), GetSentenceBoundary(...): #ifndef _BREAKIT_HXX #include <breakit.hxx> #endif @@ -89,6 +94,10 @@ #include <ndtxt.hxx> #endif +// for FillSpecialPos(...) +#ifndef _CRSTATE_HXX +#include "crstate.hxx" +#endif using rtl::OUString; @@ -109,7 +118,10 @@ SwAccessiblePortionData::SwAccessiblePortionData( aModelPositions(), aAccessiblePositions(), pWords( NULL ), - pSentences( NULL ) + pSentences( NULL ), + nBeforePortions( 0 ), + bLastIsSpecial( sal_False ) + { // reserve some space to reduce memory allocations aLineBreaks.reserve( 5 ); @@ -134,6 +146,10 @@ void SwAccessiblePortionData::Text(USHORT nLength) DBG_ASSERT( !bFinished, "We are already done!" ); + // ignore zero-length portions + if( nLength == 0 ) + return; + // store 'old' positions aModelPositions.push_back( nModelPosition ); aAccessiblePositions.push_back( aBuffer.getLength() ); @@ -141,26 +157,49 @@ void SwAccessiblePortionData::Text(USHORT nLength) // update buffer + nModelPosition aBuffer.append( sModelString.copy(nModelPosition, nLength) ); nModelPosition += nLength; + + bLastIsSpecial = sal_False; } void SwAccessiblePortionData::Special( USHORT nLength, const String& rText, USHORT nType) { DBG_ASSERT( nLength >= 0, "illegal length" ); + DBG_ASSERT( nModelPosition >= 0, "illegal position" ); DBG_ASSERT( (nModelPosition + nLength) <= sModelString.getLength(), "portion exceeds model string!" ) DBG_ASSERT( !bFinished, "We are already done!" ); - // for now, ignore the nType variable + // ignore zero/zero portions (except our terminators) + if( (nLength == 0) && (rText.Len() == 0) && (nType != 0) ) + return; - // store 'old' positions + // special case portions: (none so far) + // switch( nType ) + // { + // default: + // break; + // } + + // special treatment for zero length portion at the beginning: + // count as 'before' portion + if( ( nLength == 0 ) && ( nModelPosition == 0 ) ) + nBeforePortions++; + + // the default case: store the 'old' positions (and previous for + // zero-length portions) aModelPositions.push_back( nModelPosition ); aAccessiblePositions.push_back( aBuffer.getLength() ); // update buffer + nModelPosition aBuffer.append( OUString(rText) ); nModelPosition += nLength; + + // remember 'last' special portion (unless it's our own 'closing' + // portions from 'Finish()' + if( nType != 0 ) + bLastIsSpecial = sal_True; } void SwAccessiblePortionData::LineBreak() @@ -185,8 +224,8 @@ void SwAccessiblePortionData::Finish() // include terminator values: always include two 'last character' // markers in the position arrays to make sure we always find one // position before the end - Text( 0 ); - Text( 0 ); + Special( 0, String(), 0 ); + Special( 0, String(), 0 ); LineBreak(); LineBreak(); @@ -226,7 +265,7 @@ USHORT SwAccessiblePortionData::GetModelPosition( sal_Int32 nPos ) // else return that position if( (nEndPos - nStartPos) > 1 ) { - // 'wide' portions have to be of the same with + // 'wide' portions have to be of the same width DBG_ASSERT( ( nEndPos - nStartPos ) == ( aAccessiblePositions[nPortionNo+1] - aAccessiblePositions[nPortionNo] ), @@ -238,7 +277,7 @@ USHORT SwAccessiblePortionData::GetModelPosition( sal_Int32 nPos ) // else: return startPos unmodified DBG_ASSERT( (nStartPos >= 0) && (nStartPos < USHRT_MAX), - "Why can the SwTxtNode have so many characters?" ); + "How can the SwTxtNode have so many characters?" ); return static_cast<USHORT>(nStartPos); } @@ -309,6 +348,19 @@ size_t SwAccessiblePortionData::FindBreak( return nMin; } +size_t SwAccessiblePortionData::FindLastBreak( + const Positions_t& rPositions, + sal_Int32 nValue ) +{ + size_t nResult = FindBreak( rPositions, nValue ); + + // skip 'zero-length' portions + while( rPositions[nResult+1] <= nValue ) + nResult++; + + return nResult; +} + void SwAccessiblePortionData::GetWordBoundary( Boundary& rBound, @@ -391,12 +443,16 @@ void SwAccessiblePortionData::GetSentenceBoundary( USHORT nModelPos = GetModelPosition( nCurrent ); - nCurrent = pBreakIt->xBreak->endOfSentence( + sal_Int32 nNew = pBreakIt->xBreak->endOfSentence( sAccessibleString, nCurrent, pBreakIt->GetLocale( pNode->GetLang( nModelPos ) ) ) + 1; - if( (nCurrent < 0) && (nCurrent > nLength) ) - nCurrent = nLength; + if( (nNew < 0) && (nNew > nLength) ) + nNew = nLength; + else if (nNew <= nCurrent) + nNew = nCurrent + 1; // ensure forward progress + + nCurrent = nNew; } while (nCurrent < nLength); @@ -415,3 +471,141 @@ void SwAccessiblePortionData::GetSentenceBoundary( FillBoundary( rBound, *pSentences, FindBreak( *pSentences, nPos ) ); } + +sal_Int32 SwAccessiblePortionData::GetAccessiblePosition( USHORT nPos ) +{ + DBG_ASSERT( nPos <= sModelString.getLength(), "illegal position" ); + + // find the portion number + size_t nPortionNo = FindBreak( aModelPositions, + static_cast<sal_Int32>(nPos) ); + + sal_Int32 nRet = aAccessiblePositions[nPortionNo]; + + // if the model portion has more than one position, go into it; + // else return that position + sal_Int32 nStartPos = aModelPositions[nPortionNo]; + sal_Int32 nEndPos = aModelPositions[nPortionNo+1]; + if( (nEndPos - nStartPos) > 1 ) + { + // 'wide' portions have to be of the same width + DBG_ASSERT( ( nEndPos - nStartPos ) == + ( aAccessiblePositions[nPortionNo+1] - + aAccessiblePositions[nPortionNo] ), + "accesability portion disagrees with text model" ); + + sal_Int32 nWithinPortion = nPos - aModelPositions[nPortionNo]; + nRet += nWithinPortion; + } + // else: return nRet unmodified + + DBG_ASSERT( (nRet >= 0) && (nRet <= sAccessibleString.getLength()), + "too long!" ); + return nRet; +} + +sal_Int32 SwAccessiblePortionData::GetLineNumber( sal_Int32 nPos ) +{ + size_t nPortionNo = FindBreak( aLineBreaks, nPos ); + return nPortionNo; +} + + + +USHORT SwAccessiblePortionData::FillSpecialPos( + sal_Int32 nPos, + SwSpecialPos& rPos, + SwSpecialPos*& rpPos ) +{ + size_t nPortionNo = FindLastBreak( aAccessiblePositions, nPos ); + + BYTE nExtend; + sal_Int32 nRefPos; + sal_Int32 nModelPos; + + if( nPortionNo < nBeforePortions ) + { + nExtend = SP_EXTEND_RANGE_BEFORE; + nModelPos = 0; + nRefPos = 0; + rpPos = &rPos; + } + else + { + sal_Int32 nModelEndPos = aModelPositions[nPortionNo+1]; + nModelPos = aModelPositions[nPortionNo]; + + // skip backwards over zero-length portions, since GetCharRect() + // counts all model-zero-length portions as belonging to the + // previus portion + size_t nCorePortionNo = nPortionNo; + while( nModelPos == nModelEndPos ) + { + nCorePortionNo--; + nModelEndPos = nModelPos; + nModelPos = aModelPositions[nCorePortionNo]; + + DBG_ASSERT( nModelPos >= 0, "Can't happen." ); + DBG_ASSERT( nCorePortionNo >= nBeforePortions, "Can't happen." ); + } + DBG_ASSERT( nModelPos != nModelEndPos, + "portion with core-representation expected" ); + + // if we have anything except plain text, compute nExtend + nRefPos + if( (nModelEndPos - nModelPos == 1) && + (sModelString.getStr()[nModelPos] != + sAccessibleString.getStr()[nPos]) ) + { + // case 1: a one-character, non-text portion + // reference position is the first accessibilty for our + // core portion + nRefPos = aAccessiblePositions[ nCorePortionNo ]; + nExtend = SP_EXTEND_RANGE_NONE; + rpPos = &rPos; + } + else if(nPortionNo != nCorePortionNo) + { + // case 2: a multi-character (text!) portion, followed by + // zero-length portions + // reference position is the first character of the next + // portion, and we are 'behind' + nRefPos = aAccessiblePositions[ nCorePortionNo+1 ]; + nExtend = SP_EXTEND_RANGE_BEHIND; + rpPos = &rPos; + } + else + { + // case 3: regular text portion + DBG_ASSERT( ( nModelEndPos - nModelPos ) == + ( aAccessiblePositions[nPortionNo+1] - + aAccessiblePositions[nPortionNo] ), + "text portion expected" ); + + nModelPos += nPos - aAccessiblePositions[ nPortionNo ]; + rpPos = NULL; + } + } + if( rpPos != NULL ) + { + DBG_ASSERT( rpPos == &rPos, "Yes!" ); + DBG_ASSERT( nRefPos <= nPos, "wrong reference" ); + DBG_ASSERT( (nExtend == SP_EXTEND_RANGE_NONE) || + (nExtend == SP_EXTEND_RANGE_BEFORE) || + (nExtend == SP_EXTEND_RANGE_BEHIND), "need extend" ); + + // get the line number, and adjust nRefPos for the line + // (if necessary) + size_t nRefLine = FindBreak( aLineBreaks, nRefPos ); + size_t nMyLine = FindBreak( aLineBreaks, nPos ); + USHORT nLineOffset = static_cast<USHORT>( nMyLine - nRefLine ); + if( nLineOffset != 0 ) + nRefPos = aLineBreaks[ nMyLine ]; + + // fill char offset and 'special position' + rPos.nCharOfst = static_cast<USHORT>( nPos - nRefPos ); + rPos.nExtendRange = nExtend; + rPos.nLineOfst = nLineOffset; + } + + return static_cast<USHORT>( nModelPos ); +} diff --git a/sw/source/core/access/accportions.hxx b/sw/source/core/access/accportions.hxx index 6ae2d3b81bd1..321629683003 100644 --- a/sw/source/core/access/accportions.hxx +++ b/sw/source/core/access/accportions.hxx @@ -2,9 +2,9 @@ * * $RCSfile: accportions.hxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * - * last change: $Author: dvo $ $Date: 2002-02-21 14:55:31 $ + * last change: $Author: dvo $ $Date: 2002-02-27 17:28:54 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -76,6 +76,7 @@ class String; class SwTxtNode; +struct SwSpecialPos; namespace com { namespace sun { namespace star { namespace i18n { struct Boundary; } } } } @@ -107,10 +108,16 @@ class SwAccessiblePortionData : public SwPortionHandler Positions_t* pWords; /// positions of word breaks Positions_t* pSentences; /// positions of sentence breaks + size_t nBeforePortions; /// # of portions before first model character + sal_Bool bLastIsSpecial; /// set if last portion was 'Special()' + /// returns the index of the first position whose value is smaller /// or equal, and whose following value is equal or larger size_t FindBreak( const Positions_t& rPositions, sal_Int32 nValue ); + /// like FindBreak, but finds the last equal or larger position + size_t FindLastBreak( const Positions_t& rPositions, sal_Int32 nValue ); + /// fill the boundary with the values from rPositions[nPos] void FillBoundary(com::sun::star::i18n::Boundary& rBound, const Positions_t& rPositions, @@ -128,12 +135,35 @@ public: virtual void Finish(); + // access to the portion data + + /// get the text string, as presented by the layout const rtl::OUString& GetAccesibleString(); + + /// get the start & end positions of the sentence void GetLineBoundary( com::sun::star::i18n::Boundary& rBound, sal_Int32 nPos ); + + /// get the position in the model string for a given + /// (accessibility) position USHORT GetModelPosition( sal_Int32 nPos ); + /// get the position in the accessibility string for a given model position + sal_Int32 GetAccessiblePosition( USHORT nPos ); + + /// get the line number for a given (accessibility) position + sal_Int32 GetLineNumber( sal_Int32 nPos ); + + /// fill a SwSpecialPos structure, suitable for calling + /// SwTxtFrm->GetCharRect + /// Returns the core position, and fills thr rpPos either with NULL or + /// with the &rPos, after putting the appropriate data into it. + USHORT FillSpecialPos( sal_Int32 nPos, + SwSpecialPos& rPos, + SwSpecialPos*& rpPos ); + + // get boundaries of words/sentences. The data structures are // created on-demand. The SwTxtNode is needed to get the language // for the words. |