merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / access / accportions.cxx
blob48f4b23136b927df3483c7a5a57de27a1051af5c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accportions.cxx,v $
10 * $Revision: 1.35 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "accportions.hxx"
34 #include <tools/debug.hxx>
35 #include <rtl/ustring.hxx>
36 #include <com/sun/star/i18n/Boundary.hpp>
37 #include <txttypes.hxx>
39 // for portion replacement in Special()
40 #ifndef _ACCESS_HRC
41 #include "access.hrc"
42 #endif
43 #include <tools/resid.hxx>
44 #include "viewopt.hxx"
46 // for GetWordBoundary(...), GetSentenceBoundary(...):
47 #include <breakit.hxx>
48 #include <com/sun/star/i18n/WordType.hpp>
49 #include <com/sun/star/i18n/XBreakIterator.hpp>
50 #include <ndtxt.hxx>
52 // for FillSpecialPos(...)
53 #include "crstate.hxx"
55 // for SwAccessibleContext::GetResource()
56 #include "acccontext.hxx"
58 // for Post-It replacement text:
59 #include "txatbase.hxx"
60 #include "fmtfld.hxx"
61 #include "fldbas.hxx"
62 #include "docufld.hxx"
64 // for in-line graphics replacement:
65 #include "ndindex.hxx"
66 #include "ndnotxt.hxx"
67 #include "fmtflcnt.hxx"
68 #include "frmfmt.hxx"
69 #include "fmtcntnt.hxx"
72 using namespace ::com::sun::star;
74 using rtl::OUString;
75 using rtl::OUStringBuffer;
76 using i18n::Boundary;
79 // 'portion type' for terminating portions
80 #define POR_TERMINATE 0
83 // portion attributes
84 #define PORATTR_SPECIAL 1
85 #define PORATTR_READONLY 2
86 #define PORATTR_GRAY 4
87 #define PORATTR_TERM 128
89 SwAccessiblePortionData::SwAccessiblePortionData(
90 const SwTxtNode* pTxtNd,
91 const SwViewOption* pViewOpt ) :
92 SwPortionHandler(),
93 pTxtNode( pTxtNd ),
94 aBuffer(),
95 nModelPosition( 0 ),
96 bFinished( sal_False ),
97 pViewOptions( pViewOpt ),
98 sAccessibleString(),
99 aLineBreaks(),
100 aModelPositions(),
101 aAccessiblePositions(),
102 pSentences( 0 ),
103 nBeforePortions( 0 ),
104 bLastIsSpecial( sal_False )
106 DBG_ASSERT( pTxtNode != NULL, "Text node is needed!" );
108 // reserve some space to reduce memory allocations
109 aLineBreaks.reserve( 5 );
110 aModelPositions.reserve( 10 );
111 aAccessiblePositions.reserve( 10 );
113 // always include 'first' line-break position
114 aLineBreaks.push_back( 0 );
117 SwAccessiblePortionData::~SwAccessiblePortionData()
119 delete pSentences;
122 void SwAccessiblePortionData::Text(USHORT nLength, USHORT nType)
124 DBG_ASSERT( (nModelPosition + nLength) <= pTxtNode->GetTxt().Len(),
125 "portion exceeds model string!" );
127 DBG_ASSERT( !bFinished, "We are already done!" );
129 // ignore zero-length portions
130 if( nLength == 0 )
131 return;
133 // store 'old' positions
134 aModelPositions.push_back( nModelPosition );
135 aAccessiblePositions.push_back( aBuffer.getLength() );
137 // store portion attributes
138 sal_uInt8 nAttr = IsGrayPortionType(nType) ? PORATTR_GRAY : 0;
139 aPortionAttrs.push_back( nAttr );
141 // update buffer + nModelPosition
142 aBuffer.append( OUString(
143 pTxtNode->GetTxt().Copy(
144 static_cast<USHORT>( nModelPosition ),
145 nLength ) ) );
146 nModelPosition += nLength;
148 bLastIsSpecial = sal_False;
151 void SwAccessiblePortionData::Special(
152 USHORT nLength, const String& rText, USHORT nType)
154 DBG_ASSERT( nModelPosition >= 0, "illegal position" );
155 DBG_ASSERT( (nModelPosition + nLength) <= pTxtNode->GetTxt().Len(),
156 "portion exceeds model string!" );
158 DBG_ASSERT( !bFinished, "We are already done!" );
160 // construct string with representation; either directly from
161 // rText, or use resources for special case portions
162 String sDisplay;
163 switch( nType )
165 case POR_POSTITS:
166 case POR_FLYCNT:
167 case POR_GRFNUM:
168 sDisplay = String(sal_Unicode(0xfffc));
170 break;
171 case POR_NUMBER:
173 OUStringBuffer aTmpBuffer( rText.Len() + 1 );
174 aTmpBuffer.append( rText );
175 aTmpBuffer.append( sal_Unicode(' ') );
176 sDisplay = aTmpBuffer.makeStringAndClear();
177 break;
179 default:
180 sDisplay = rText;
181 break;
184 // ignore zero/zero portions (except for terminators)
185 if( (nLength == 0) && (sDisplay.Len() == 0) && (nType != POR_TERMINATE) )
186 return;
188 // special treatment for zero length portion at the beginning:
189 // count as 'before' portion
190 if( ( nLength == 0 ) && ( nModelPosition == 0 ) )
191 nBeforePortions++;
193 // store the 'old' positions
194 aModelPositions.push_back( nModelPosition );
195 aAccessiblePositions.push_back( aBuffer.getLength() );
197 // store portion attributes
198 sal_uInt8 nAttr = PORATTR_SPECIAL;
199 if( IsGrayPortionType(nType) ) nAttr |= PORATTR_GRAY;
200 if( nLength == 0 ) nAttr |= PORATTR_READONLY;
201 if( nType == POR_TERMINATE ) nAttr |= PORATTR_TERM;
202 aPortionAttrs.push_back( nAttr );
204 // update buffer + nModelPosition
205 aBuffer.append( OUString(sDisplay) );
206 nModelPosition += nLength;
208 // remember 'last' special portion (unless it's our own 'closing'
209 // portions from 'Finish()'
210 if( nType != POR_TERMINATE )
211 bLastIsSpecial = sal_True;
214 void SwAccessiblePortionData::LineBreak()
216 DBG_ASSERT( !bFinished, "We are already done!" );
218 aLineBreaks.push_back( aBuffer.getLength() );
221 void SwAccessiblePortionData::Skip(USHORT nLength)
223 DBG_ASSERT( !bFinished, "We are already done!" );
224 DBG_ASSERT( aModelPositions.size() == 0, "Never Skip() after portions" );
225 DBG_ASSERT( nLength <= pTxtNode->GetTxt().Len(), "skip exceeds model string!" );
227 nModelPosition += nLength;
230 void SwAccessiblePortionData::Finish()
232 DBG_ASSERT( !bFinished, "We are already done!" );
234 // include terminator values: always include two 'last character'
235 // markers in the position arrays to make sure we always find one
236 // position before the end
237 Special( 0, String(), POR_TERMINATE );
238 Special( 0, String(), POR_TERMINATE );
239 LineBreak();
240 LineBreak();
242 sAccessibleString = aBuffer.makeStringAndClear();
243 bFinished = sal_True;
247 sal_Bool SwAccessiblePortionData::IsPortionAttrSet(
248 size_t nPortionNo, sal_uInt8 nAttr ) const
250 DBG_ASSERT( nPortionNo < aPortionAttrs.size(),
251 "Illegal portion number" );
252 return (aPortionAttrs[nPortionNo] & nAttr) != 0;
255 sal_Bool SwAccessiblePortionData::IsSpecialPortion( size_t nPortionNo ) const
257 return IsPortionAttrSet(nPortionNo, PORATTR_SPECIAL);
260 sal_Bool SwAccessiblePortionData::IsReadOnlyPortion( size_t nPortionNo ) const
262 return IsPortionAttrSet(nPortionNo, PORATTR_READONLY);
265 sal_Bool SwAccessiblePortionData::IsGrayPortion( size_t nPortionNo ) const
267 return IsPortionAttrSet(nPortionNo, PORATTR_GRAY);
271 sal_Bool SwAccessiblePortionData::IsGrayPortionType( USHORT nType ) const
273 // gray portions?
274 // Compare with: inftxt.cxx, SwTxtPaintInfo::DrawViewOpt(...)
275 sal_Bool bGray = sal_False;
276 switch( nType )
278 case POR_FTN:
279 case POR_ISOREF:
280 case POR_REF:
281 case POR_QUOVADIS:
282 case POR_NUMBER:
283 case POR_FLD:
284 case POR_URL:
285 case POR_ISOTOX:
286 case POR_TOX:
287 case POR_HIDDEN:
288 bGray = !pViewOptions->IsPagePreview() &&
289 !pViewOptions->IsReadonly() && SwViewOption::IsFieldShadings();
290 break;
291 case POR_TAB: bGray = pViewOptions->IsTab(); break;
292 case POR_SOFTHYPH: bGray = pViewOptions->IsSoftHyph(); break;
293 case POR_BLANK: bGray = pViewOptions->IsHardBlank(); break;
294 default:
295 break; // bGray is false
297 return bGray;
301 const OUString& SwAccessiblePortionData::GetAccessibleString() const
303 DBG_ASSERT( bFinished, "Shouldn't call this before we are done!" );
305 return sAccessibleString;
309 void SwAccessiblePortionData::GetLineBoundary(
310 Boundary& rBound,
311 sal_Int32 nPos ) const
313 FillBoundary( rBound, aLineBreaks,
314 FindBreak( aLineBreaks, nPos ) );
317 // --> OD 2008-05-30 #i89175#
318 sal_Int32 SwAccessiblePortionData::GetLineCount() const
320 size_t nBreaks = aLineBreaks.size();
321 // A non-empty paragraph has at least 4 breaks: one for each line3 and
322 // 3 additional ones.
323 // An empty paragraph has 3 breaks.
324 // Less than 3 breaks is an error case.
325 sal_Int32 nLineCount = ( nBreaks > 3 )
326 ? nBreaks - 3
327 : ( ( nBreaks == 3 ) ? 1 : 0 );
328 return nLineCount;
331 sal_Int32 SwAccessiblePortionData::GetLineNo( const sal_Int32 nPos ) const
333 sal_Int32 nLineNo = FindBreak( aLineBreaks, nPos );
335 // handling of position after last character
336 const sal_Int32 nLineCount( GetLineCount() );
337 if ( nLineNo >= nLineCount )
339 nLineNo = nLineCount - 1;
342 return nLineNo;
345 void SwAccessiblePortionData::GetBoundaryOfLine( const sal_Int32 nLineNo,
346 i18n::Boundary& rLineBound )
348 FillBoundary( rLineBound, aLineBreaks, nLineNo );
350 // <--
352 void SwAccessiblePortionData::GetLastLineBoundary(
353 Boundary& rBound ) const
355 DBG_ASSERT( aLineBreaks.size() >= 2, "need min + max value" );
357 // The last two positions except the two deleimiters are the ones
358 // we are looking for, except for empty paragraphs (nBreaks==3)
359 size_t nBreaks = aLineBreaks.size();
360 FillBoundary( rBound, aLineBreaks, nBreaks <= 3 ? 0 : nBreaks-4 );
363 USHORT SwAccessiblePortionData::GetModelPosition( sal_Int32 nPos ) const
365 DBG_ASSERT( nPos >= 0, "illegal position" );
366 DBG_ASSERT( nPos <= sAccessibleString.getLength(), "illegal position" );
368 // find the portion number
369 size_t nPortionNo = FindBreak( aAccessiblePositions, nPos );
371 // get model portion size
372 sal_Int32 nStartPos = aModelPositions[nPortionNo];
374 // if it's a non-special portion, move into the portion, else
375 // return the portion start
376 if( ! IsSpecialPortion( nPortionNo ) )
378 // 'wide' portions have to be of the same width
379 DBG_ASSERT( ( aModelPositions[nPortionNo+1] - nStartPos ) ==
380 ( aAccessiblePositions[nPortionNo+1] -
381 aAccessiblePositions[nPortionNo] ),
382 "accesability portion disagrees with text model" );
384 sal_Int32 nWithinPortion = nPos - aAccessiblePositions[nPortionNo];
385 nStartPos += nWithinPortion;
387 // else: return nStartPos unmodified
389 DBG_ASSERT( (nStartPos >= 0) && (nStartPos < USHRT_MAX),
390 "How can the SwTxtNode have so many characters?" );
391 return static_cast<USHORT>(nStartPos);
394 void SwAccessiblePortionData::FillBoundary(
395 Boundary& rBound,
396 const Positions_t& rPositions,
397 size_t nPos ) const
399 rBound.startPos = rPositions[nPos];
400 rBound.endPos = rPositions[nPos+1];
404 size_t SwAccessiblePortionData::FindBreak(
405 const Positions_t& rPositions,
406 sal_Int32 nValue ) const
408 DBG_ASSERT( rPositions.size() >= 2, "need min + max value" );
409 DBG_ASSERT( rPositions[0] <= nValue, "need min value" );
410 DBG_ASSERT( rPositions[rPositions.size()-1] >= nValue,
411 "need first terminator value" );
412 DBG_ASSERT( rPositions[rPositions.size()-2] >= nValue,
413 "need second terminator value" );
415 size_t nMin = 0;
416 size_t nMax = rPositions.size()-2;
418 // loop until no more than two candidates are left
419 while( nMin+1 < nMax )
421 // check loop invariants
422 DBG_ASSERT( ( (nMin == 0) && (rPositions[nMin] <= nValue) ) ||
423 ( (nMin != 0) && (rPositions[nMin] < nValue) ),
424 "minvalue not minimal" );
425 DBG_ASSERT( nValue <= rPositions[nMax], "max value not maximal" );
427 // get middle (and ensure progress)
428 size_t nMiddle = (nMin + nMax)/2;
429 DBG_ASSERT( nMin < nMiddle, "progress?" );
430 DBG_ASSERT( nMiddle < nMax, "progress?" );
432 // check array
433 DBG_ASSERT( rPositions[nMin] <= rPositions[nMiddle],
434 "garbled positions array" );
435 DBG_ASSERT( rPositions[nMiddle] <= rPositions[nMax],
436 "garbled positions array" );
438 if( nValue > rPositions[nMiddle] )
439 nMin = nMiddle;
440 else
441 nMax = nMiddle;
444 // only two are left; we only need to check which one is the winner
445 DBG_ASSERT( (nMax == nMin) || (nMax == nMin+1), "only two left" );
446 if( (rPositions[nMin] < nValue) && (rPositions[nMin+1] <= nValue) )
447 nMin = nMin+1;
449 // finally, check to see whether the returned value is the 'right' position
450 DBG_ASSERT( rPositions[nMin] <= nValue, "not smaller or equal" );
451 DBG_ASSERT( nValue <= rPositions[nMin+1], "not equal or larger" );
452 DBG_ASSERT( (nMin == 0) || (rPositions[nMin-1] <= nValue),
453 "earlier value should have been returned" );
455 DBG_ASSERT( nMin < rPositions.size()-1,
456 "shouldn't return last position (due to termintator values)" );
458 return nMin;
461 size_t SwAccessiblePortionData::FindLastBreak(
462 const Positions_t& rPositions,
463 sal_Int32 nValue ) const
465 size_t nResult = FindBreak( rPositions, nValue );
467 // skip 'zero-length' portions
468 // --> OD 2006-10-19 #i70538#
469 // consider size of <rPosition> and ignore last entry
470 // while( rPositions[nResult+1] <= nValue )
471 while ( nResult < rPositions.size() - 2 &&
472 rPositions[nResult+1] <= nValue )
474 nResult++;
476 // <--
478 return nResult;
482 void SwAccessiblePortionData::GetSentenceBoundary(
483 Boundary& rBound,
484 sal_Int32 nPos )
486 DBG_ASSERT( nPos >= 0, "illegal position; check before" );
487 DBG_ASSERT( nPos < sAccessibleString.getLength(), "illegal position" );
489 if( pSentences == NULL )
491 DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
492 DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
493 if( pBreakIt->GetBreakIter().is() )
495 pSentences = new Positions_t();
496 pSentences->reserve(10);
498 // use xBreak->endOfSentence to iterate over all words; store
499 // positions in pSentences
500 sal_Int32 nCurrent = 0;
501 sal_Int32 nLength = sAccessibleString.getLength();
504 pSentences->push_back( nCurrent );
506 USHORT nModelPos = GetModelPosition( nCurrent );
508 sal_Int32 nNew = pBreakIt->GetBreakIter()->endOfSentence(
509 sAccessibleString, nCurrent,
510 pBreakIt->GetLocale(pTxtNode->GetLang(nModelPos)) ) + 1;
512 if( (nNew < 0) && (nNew > nLength) )
513 nNew = nLength;
514 else if (nNew <= nCurrent)
515 nNew = nCurrent + 1; // ensure forward progress
517 nCurrent = nNew;
519 while (nCurrent < nLength);
521 // finish with two terminators
522 pSentences->push_back( nLength );
523 pSentences->push_back( nLength );
525 else
527 // no break iterator -> empty word
528 rBound.startPos = 0;
529 rBound.endPos = 0;
530 return;
534 FillBoundary( rBound, *pSentences, FindBreak( *pSentences, nPos ) );
537 void SwAccessiblePortionData::GetAttributeBoundary(
538 Boundary& rBound,
539 sal_Int32 nPos) const
541 DBG_ASSERT( pTxtNode != NULL, "Need SwTxtNode!" );
543 // attribute boundaries can only occur on portion boundaries
544 FillBoundary( rBound, aAccessiblePositions,
545 FindBreak( aAccessiblePositions, nPos ) );
549 sal_Int32 SwAccessiblePortionData::GetAccessiblePosition( USHORT nPos ) const
551 DBG_ASSERT( nPos <= pTxtNode->GetTxt().Len(), "illegal position" );
553 // find the portion number
554 // --> OD 2006-10-19 #i70538#
555 // consider "empty" model portions - e.g. number portion
556 size_t nPortionNo = FindLastBreak( aModelPositions,
557 static_cast<sal_Int32>(nPos) );
558 // <--
560 sal_Int32 nRet = aAccessiblePositions[nPortionNo];
562 // if the model portion has more than one position, go into it;
563 // else return that position
564 sal_Int32 nStartPos = aModelPositions[nPortionNo];
565 sal_Int32 nEndPos = aModelPositions[nPortionNo+1];
566 if( (nEndPos - nStartPos) > 1 )
568 // 'wide' portions have to be of the same width
569 DBG_ASSERT( ( nEndPos - nStartPos ) ==
570 ( aAccessiblePositions[nPortionNo+1] -
571 aAccessiblePositions[nPortionNo] ),
572 "accesability portion disagrees with text model" );
574 sal_Int32 nWithinPortion = nPos - aModelPositions[nPortionNo];
575 nRet += nWithinPortion;
577 // else: return nRet unmodified
579 DBG_ASSERT( (nRet >= 0) && (nRet <= sAccessibleString.getLength()),
580 "too long!" );
581 return nRet;
584 USHORT SwAccessiblePortionData::FillSpecialPos(
585 sal_Int32 nPos,
586 SwSpecialPos& rPos,
587 SwSpecialPos*& rpPos ) const
589 size_t nPortionNo = FindLastBreak( aAccessiblePositions, nPos );
591 BYTE nExtend(SP_EXTEND_RANGE_NONE);
592 sal_Int32 nRefPos(0);
593 sal_Int32 nModelPos(0);
595 if( nPortionNo < nBeforePortions )
597 nExtend = SP_EXTEND_RANGE_BEFORE;
598 rpPos = &rPos;
600 else
602 sal_Int32 nModelEndPos = aModelPositions[nPortionNo+1];
603 nModelPos = aModelPositions[nPortionNo];
605 // skip backwards over zero-length portions, since GetCharRect()
606 // counts all model-zero-length portions as belonging to the
607 // previus portion
608 size_t nCorePortionNo = nPortionNo;
609 while( nModelPos == nModelEndPos )
611 nCorePortionNo--;
612 nModelEndPos = nModelPos;
613 nModelPos = aModelPositions[nCorePortionNo];
615 DBG_ASSERT( nModelPos >= 0, "Can't happen." );
616 DBG_ASSERT( nCorePortionNo >= nBeforePortions, "Can't happen." );
618 DBG_ASSERT( nModelPos != nModelEndPos,
619 "portion with core-representation expected" );
621 // if we have anything except plain text, compute nExtend + nRefPos
622 if( (nModelEndPos - nModelPos == 1) &&
623 (pTxtNode->GetTxt().GetChar(static_cast<USHORT>(nModelPos)) !=
624 sAccessibleString.getStr()[nPos]) )
626 // case 1: a one-character, non-text portion
627 // reference position is the first accessibilty for our
628 // core portion
629 nRefPos = aAccessiblePositions[ nCorePortionNo ];
630 nExtend = SP_EXTEND_RANGE_NONE;
631 rpPos = &rPos;
633 else if(nPortionNo != nCorePortionNo)
635 // case 2: a multi-character (text!) portion, followed by
636 // zero-length portions
637 // reference position is the first character of the next
638 // portion, and we are 'behind'
639 nRefPos = aAccessiblePositions[ nCorePortionNo+1 ];
640 nExtend = SP_EXTEND_RANGE_BEHIND;
641 rpPos = &rPos;
643 else
645 // case 3: regular text portion
646 DBG_ASSERT( ( nModelEndPos - nModelPos ) ==
647 ( aAccessiblePositions[nPortionNo+1] -
648 aAccessiblePositions[nPortionNo] ),
649 "text portion expected" );
651 nModelPos += nPos - aAccessiblePositions[ nPortionNo ];
652 rpPos = NULL;
655 if( rpPos != NULL )
657 DBG_ASSERT( rpPos == &rPos, "Yes!" );
658 DBG_ASSERT( nRefPos <= nPos, "wrong reference" );
659 DBG_ASSERT( (nExtend == SP_EXTEND_RANGE_NONE) ||
660 (nExtend == SP_EXTEND_RANGE_BEFORE) ||
661 (nExtend == SP_EXTEND_RANGE_BEHIND), "need extend" );
663 // get the line number, and adjust nRefPos for the line
664 // (if necessary)
665 size_t nRefLine = FindBreak( aLineBreaks, nRefPos );
666 size_t nMyLine = FindBreak( aLineBreaks, nPos );
667 USHORT nLineOffset = static_cast<USHORT>( nMyLine - nRefLine );
668 if( nLineOffset != 0 )
669 nRefPos = aLineBreaks[ nMyLine ];
671 // fill char offset and 'special position'
672 rPos.nCharOfst = static_cast<USHORT>( nPos - nRefPos );
673 rPos.nExtendRange = nExtend;
674 rPos.nLineOfst = nLineOffset;
677 return static_cast<USHORT>( nModelPos );
680 void SwAccessiblePortionData::AdjustAndCheck(
681 sal_Int32 nPos,
682 size_t& nPortionNo,
683 USHORT& nCorePos,
684 sal_Bool& bEdit) const
686 // find portion and get mode position
687 nPortionNo = FindBreak( aAccessiblePositions, nPos );
688 nCorePos = static_cast<USHORT>( aModelPositions[ nPortionNo ] );
690 // for special portions, make sure we're on a portion boundary
691 // for text portions, add the in-portion offset
692 if( IsSpecialPortion( nPortionNo ) )
693 bEdit &= nPos == aAccessiblePositions[nPortionNo];
694 else
695 nCorePos = static_cast<USHORT>( nCorePos +
696 nPos - aAccessiblePositions[nPortionNo] );
699 sal_Bool SwAccessiblePortionData::GetEditableRange(
700 sal_Int32 nStart, sal_Int32 nEnd,
701 USHORT& nCoreStart, USHORT& nCoreEnd ) const
703 sal_Bool bIsEditable = sal_True;
705 // get start and end portions
706 size_t nStartPortion, nEndPortion;
707 AdjustAndCheck( nStart, nStartPortion, nCoreStart, bIsEditable );
708 AdjustAndCheck( nEnd, nEndPortion, nCoreEnd, bIsEditable );
710 // iterate over portions, and make sure there is no read-only portion
711 // in-between
712 size_t nLastPortion = nEndPortion;
714 // don't count last portion if we're in front of a special portion
715 if( IsSpecialPortion(nLastPortion) )
717 if (nLastPortion > 0)
718 nLastPortion--;
719 else
720 // special case: because size_t is usually unsigned, we can't just
721 // decrease nLastPortion to -1 (which would normally do the job, so
722 // this whole if wouldn't be needed). Instead, we'll do this
723 // special case and just increae the start portion beyond the last
724 // portion to make sure the loop below will have zero iteration.
725 nStartPortion = nLastPortion + 1;
728 for( size_t nPor = nStartPortion; nPor <= nLastPortion; nPor ++ )
730 bIsEditable &= ! IsReadOnlyPortion( nPor );
733 return bIsEditable;
736 sal_Bool SwAccessiblePortionData::IsValidCorePosition( USHORT nPos ) const
738 // a position is valid its within the model positions that we know
739 return ( aModelPositions[0] <= nPos ) &&
740 ( nPos <= aModelPositions[ aModelPositions.size()-1 ] );
743 USHORT SwAccessiblePortionData::GetFirstValidCorePosition() const
745 return static_cast<USHORT>( aModelPositions[0] );
748 USHORT SwAccessiblePortionData::GetLastValidCorePosition() const
750 return static_cast<USHORT>( aModelPositions[ aModelPositions.size()-1 ] );