summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vogelheim <dvo@openoffice.org>2002-02-27 16:28:54 +0000
committerDaniel Vogelheim <dvo@openoffice.org>2002-02-27 16:28:54 +0000
commitbbb08df9767e0d6599929e72283caf731280c54c (patch)
treefbe841267982d37410c55c4e1f6bf5603954d3d2
parentc605b04940e72f0ca43b10bd8f40301e479ad816 (diff)
#95586# added support for selection and character bounds
-rw-r--r--sw/source/core/access/accpara.cxx134
-rw-r--r--sw/source/core/access/accpara.hxx8
-rw-r--r--sw/source/core/access/accportions.cxx220
-rw-r--r--sw/source/core/access/accportions.hxx34
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.