/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_tools.hxx" #define _SV_MULTISEL_CXX #ifdef MI_DEBUG #define private public #include #endif #include #include #include "rtl/ustrbuf.hxx" #ifdef MI_DEBUG #define DBG(x) x #else #define DBG(x) #endif using namespace rtl; //================================================================== #ifdef MI_DEBUG static void Print( const MultiSelection* pSel ) { DbgOutf( "TotRange: %4ld-%4ld\n", pSel->aTotRange.Min(), pSel->aTotRange.Max() ); if ( pSel->bCurValid ) { DbgOutf( "CurSubSel: %4ld\n", pSel->nCurSubSel ); DbgOutf( "CurIndex: %4ld\n", pSel->nCurIndex ); } DbgOutf( "SelCount: %4ld\n", pSel->nSelCount ); DbgOutf( "SubCount: %4ld\n", pSel->aSels.Count() ); for ( sal_uIntPtr nPos = 0; nPos < pSel->aSels.Count(); ++nPos ) { DbgOutf( "SubSel #%2ld: %4ld-%4ld\n", nPos, pSel->aSels.GetObject(nPos)->Min(), pSel->aSels.GetObject(nPos)->Max() ); } DbgOutf( "\n" ); fclose( pFile ); } #endif // ----------------------------------------------------------------------- void MultiSelection::ImplClear() { // no selected indexes nSelCount = 0; Range* pRange = aSels.First(); while ( pRange ) { delete pRange; pRange = aSels.Next(); } aSels.Clear(); } // ----------------------------------------------------------------------- sal_uIntPtr MultiSelection::ImplFindSubSelection( long nIndex ) const { // iterate through the sub selections sal_uIntPtr n = 0; for ( ; n < aSels.Count() && nIndex > aSels.GetObject(n)->Max(); ++n ) {} /* empty loop */ return n; } // ----------------------------------------------------------------------- sal_Bool MultiSelection::ImplMergeSubSelections( sal_uIntPtr nPos1, sal_uIntPtr nPos2 ) { // didn't a sub selection at nPos2 exist? if ( nPos2 >= aSels.Count() ) return sal_False; // did the sub selections touch each other? if ( (aSels.GetObject(nPos1)->Max() + 1) == aSels.GetObject(nPos2)->Min() ) { // merge them aSels.GetObject(nPos1)->Max() = aSels.GetObject(nPos2)->Max(); delete aSels.Remove(nPos2); return sal_True; } return sal_False; } // ----------------------------------------------------------------------- MultiSelection::MultiSelection(): aTotRange( 0, -1 ), nCurSubSel(0), nSelCount(0), bCurValid(sal_False), bSelectNew(sal_False) { } // ----------------------------------------------------------------------- MultiSelection::MultiSelection( const UniString& rString, sal_Unicode cRange, sal_Unicode cSep ): aTotRange(0,RANGE_MAX), nCurSubSel(0), nSelCount(0), bCurValid(sal_False), bSelectNew(sal_False) { // Dies ist nur ein Schnellschuss und sollte bald optimiert, // an die verschiedenen Systeme (UNIX etc.) // und die gewuenschte Eingabe-Syntax angepasst werden. UniString aStr( rString ); sal_Unicode* pStr = aStr.GetBufferAccess(); sal_Unicode* pOld = pStr; sal_Bool bReady = sal_False; sal_Bool bUntil = sal_False; xub_StrLen nCut = 0; // Hier normieren wir den String, sodass nur Ziffern, // Semikola als Trenn- und Minus als VonBis-Zeichen // uebrigbleiben, z.B. "99-117;55;34;-17;37-43" while ( *pOld ) { switch( *pOld ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': DBG_ASSERT( *pOld != cRange, "digit for range char not allowed" ); DBG_ASSERT( *pOld != cSep, "digit for separator not allowed" ); if( bReady ) { *pStr++ = ';'; nCut++; bReady = sal_False; } *pStr++ = *pOld; nCut++; bUntil = sal_False; break; case '-': case ':': case '/': if ( *pOld != cSep ) { if ( !bUntil ) { *pStr++ = '-'; nCut++; bUntil = sal_True; } bReady = sal_False; } else bReady = sal_True; break; case ' ': DBG_ASSERT( *pOld != cRange, "SPACE for range char not allowed" ); DBG_ASSERT( *pOld != cSep, "SPACE for separator not allowed" ); bReady = !bUntil; break; default: if ( *pOld == cRange ) { if ( !bUntil ) { *pStr++ = '-'; nCut++; bUntil = sal_True; } bReady = sal_False; } else bReady = sal_True; break; } pOld++; } aStr.ReleaseBufferAccess( nCut ); // Jetzt wird der normierte String ausgewertet .. UniString aNumStr; Range aRg( 1, RANGE_MAX ); const sal_Unicode* pCStr = aStr.GetBuffer(); long nPage = 1; long nNum = 1; bUntil = sal_False; while ( *pCStr ) { switch ( *pCStr ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': aNumStr += *pCStr; break; case ';': nNum = aNumStr.ToInt32(); if ( bUntil ) { if ( !aNumStr.Len() ) nNum = RANGE_MAX; aRg.Min() = nPage; aRg.Max() = nNum; aRg.Justify(); Select( aRg ); } else Select( nNum ); nPage = 0; aNumStr.Erase(); bUntil = sal_False; break; case '-': nPage = aNumStr.ToInt32(); aNumStr.Erase(); bUntil = sal_True; break; } pCStr++; } nNum = aNumStr.ToInt32(); if ( bUntil ) { if ( !aNumStr.Len() ) nNum = RANGE_MAX; aRg.Min() = nPage; aRg.Max() = nNum; aRg.Justify(); Select( aRg ); } else Select( nNum ); } // ----------------------------------------------------------------------- MultiSelection::MultiSelection( const MultiSelection& rOrig ) : aTotRange(rOrig.aTotRange), nSelCount(rOrig.nSelCount), bCurValid(rOrig.bCurValid), bSelectNew(sal_False) { if ( bCurValid ) { nCurSubSel = rOrig.nCurSubSel; nCurIndex = rOrig.nCurIndex; } // copy the sub selections for ( sal_uIntPtr n = 0; n < rOrig.aSels.Count(); ++n ) aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND ); } // ----------------------------------------------------------------------- MultiSelection::MultiSelection( const Range& rRange ): aTotRange(rRange), nCurSubSel(0), nSelCount(0), bCurValid(sal_False), bSelectNew(sal_False) { } // ----------------------------------------------------------------------- MultiSelection::~MultiSelection() { Range* pRange = aSels.First(); while ( pRange ) { delete pRange; pRange = aSels.Next(); } } // ----------------------------------------------------------------------- MultiSelection& MultiSelection::operator= ( const MultiSelection& rOrig ) { aTotRange = rOrig.aTotRange; bCurValid = rOrig.bCurValid; if ( bCurValid ) { nCurSubSel = rOrig.nCurSubSel; nCurIndex = rOrig.nCurIndex; } // clear the old and copy the sub selections ImplClear(); for ( sal_uIntPtr n = 0; n < rOrig.aSels.Count(); ++n ) aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND ); nSelCount = rOrig.nSelCount; return *this; } // ----------------------------------------------------------------------- sal_Bool MultiSelection::operator== ( MultiSelection& rWith ) { if ( aTotRange != rWith.aTotRange || nSelCount != rWith.nSelCount || aSels.Count() != rWith.aSels.Count() ) return sal_False; // compare the sub seletions for ( sal_uIntPtr n = 0; n < aSels.Count(); ++n ) if ( *aSels.GetObject(n) != *rWith.aSels.GetObject(n) ) return sal_False; return sal_True; } // ----------------------------------------------------------------------- void MultiSelection::SelectAll( sal_Bool bSelect ) { DBG(DbgOutf( "::SelectAll(%s)\n", bSelect ? "sal_True" : "sal_False" )); ImplClear(); if ( bSelect ) { aSels.Insert( new Range(aTotRange), LIST_APPEND ); nSelCount = aTotRange.Len(); } DBG(Print( this )); } // ----------------------------------------------------------------------- sal_Bool MultiSelection::Select( long nIndex, sal_Bool bSelect ) { DBG_ASSERT( aTotRange.IsInside(nIndex), "selected index out of range" ); // out of range? if ( !aTotRange.IsInside(nIndex) ) return sal_False; // find the virtual target position sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); if ( bSelect ) { // is it included in the found sub selection? if ( nSubSelPos < aSels.Count() && aSels.GetObject(nSubSelPos)->IsInside( nIndex ) ) // already selected, nothing to do return sal_False; // it will become selected ++nSelCount; // is it at the end of the previous sub selection if ( nSubSelPos > 0 && aSels.GetObject(nSubSelPos-1)->Max() == (nIndex-1) ) { // expand the previous sub selection aSels.GetObject(nSubSelPos-1)->Max() = nIndex; // try to merge the previous sub selection ImplMergeSubSelections( nSubSelPos-1, nSubSelPos ); } // is is at the beginning of the found sub selection else if ( nSubSelPos < aSels.Count() && aSels.GetObject(nSubSelPos)->Min() == (nIndex+1) ) // expand the found sub selection aSels.GetObject(nSubSelPos)->Min() = nIndex; else { // create a new sub selection aSels.Insert( new Range( nIndex, nIndex ), nSubSelPos ); if ( bCurValid && nCurSubSel >= nSubSelPos ) ++nCurSubSel; } } else { // is it excluded from the found sub selection? if ( nSubSelPos >= aSels.Count() || !aSels.GetObject(nSubSelPos)->IsInside( nIndex ) ) { // not selected, nothing to do DBG(Print( this )); return sal_False; } // it will become deselected --nSelCount; // is it the only index in the found sub selection? if ( aSels.GetObject(nSubSelPos)->Len() == 1 ) { // remove the complete sub selection delete aSels.Remove( nSubSelPos ); DBG(Print( this )); return sal_True; } // is it at the beginning of the found sub selection? if ( aSels.GetObject(nSubSelPos)->Min() == nIndex ) ++aSels.GetObject(nSubSelPos)->Min(); // is it at the end of the found sub selection? else if ( aSels.GetObject(nSubSelPos)->Max() == nIndex ) --aSels.GetObject(nSubSelPos)->Max(); // it is in the middle of the found sub selection? else { // split the sub selection aSels.Insert( new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ), nSubSelPos ); aSels.GetObject(nSubSelPos+1)->Min() = nIndex + 1; } } DBG(Print( this )); return sal_True; } // ----------------------------------------------------------------------- void MultiSelection::Select( const Range& rIndexRange, sal_Bool bSelect ) { Range* pRange; long nOld; sal_uIntPtr nTmpMin = rIndexRange.Min(); sal_uIntPtr nTmpMax = rIndexRange.Max(); sal_uIntPtr nCurMin = FirstSelected(); sal_uIntPtr nCurMax = LastSelected(); DBG_ASSERT(aTotRange.IsInside(nTmpMax), "selected index out of range" ); DBG_ASSERT(aTotRange.IsInside(nTmpMin), "selected index out of range" ); // gesamte Selektion ersetzen ? if( nTmpMin <= nCurMin && nTmpMax >= nCurMax ) { ImplClear(); if ( bSelect ) { aSels.Insert( new Range(rIndexRange), LIST_APPEND ); nSelCount = rIndexRange.Len(); } return; } // links erweitern ? if( nTmpMax < nCurMin ) { if( bSelect ) { // ersten Range erweitern ? if( nCurMin > (nTmpMax+1) ) { pRange = new Range( rIndexRange ); aSels.Insert( pRange, (sal_uIntPtr)0 ); nSelCount += pRange->Len(); } else { pRange = aSels.First(); nOld = pRange->Min(); pRange->Min() = (long)nTmpMin; nSelCount += ( nOld - nTmpMin ); } bCurValid = sal_False; } return; } // rechts erweitern ? else if( nTmpMin > nCurMax ) { if( bSelect ) { // letzten Range erweitern ? if( nTmpMin > (nCurMax+1) ) { pRange = new Range( rIndexRange ); aSels.Insert( pRange, LIST_APPEND ); nSelCount += pRange->Len(); } else { pRange = aSels.Last(); nOld = pRange->Max(); pRange->Max() = (long)nTmpMax; nSelCount += ( nTmpMax - nOld ); } bCurValid = sal_False; } return; } //HACK(Hier muss noch optimiert werden) while( nTmpMin <= nTmpMax ) { Select( nTmpMin, bSelect ); nTmpMin++; } } // ----------------------------------------------------------------------- sal_Bool MultiSelection::IsSelected( long nIndex ) const { // find the virtual target position sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); return nSubSelPos < aSels.Count() && aSels.GetObject(nSubSelPos)->IsInside(nIndex); } // ----------------------------------------------------------------------- void MultiSelection::Insert( long nIndex, long nCount ) { DBG(DbgOutf( "::Insert(%ld, %ld)\n", nIndex, nCount )); // find the virtual target position sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); // did we need to shift the sub selections? if ( nSubSelPos < aSels.Count() ) { // did we insert an unselected into an existing sub selection? if ( !bSelectNew && aSels.GetObject(nSubSelPos)->Min() != nIndex && aSels.GetObject(nSubSelPos)->IsInside(nIndex) ) { // split the sub selection aSels.Insert( new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ), nSubSelPos ); ++nSubSelPos; aSels.GetObject(nSubSelPos)->Min() = nIndex; } // did we append an selected to an existing sub selection? else if ( bSelectNew && nSubSelPos > 0 && aSels.GetObject(nSubSelPos)->Max() == nIndex-1 ) // expand the previous sub selection aSels.GetObject(nSubSelPos-1)->Max() += nCount; // did we insert an selected into an existing sub selection? else if ( bSelectNew && aSels.GetObject(nSubSelPos)->Min() == nIndex ) { // expand the sub selection aSels.GetObject(nSubSelPos)->Max() += nCount; ++nSubSelPos; } // shift the sub selections behind the inserting position for ( sal_uIntPtr nPos = nSubSelPos; nPos < aSels.Count(); ++nPos ) { aSels.GetObject(nPos)->Min() += nCount; aSels.GetObject(nPos)->Max() += nCount; } } bCurValid = sal_False; aTotRange.Max() += nCount; if ( bSelectNew ) nSelCount += nCount; DBG(Print( this )); } // ----------------------------------------------------------------------- void MultiSelection::Remove( long nIndex ) { DBG(DbgOutf( "::Remove(%ld)\n", nIndex )); // find the virtual target position sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); // did we remove from an existing sub selection? if ( nSubSelPos < aSels.Count() && aSels.GetObject(nSubSelPos)->IsInside(nIndex) ) { // does this sub selection only contain the index to be deleted if ( aSels.GetObject(nSubSelPos)->Len() == 1 ) // completely remove the sub selection aSels.Remove(nSubSelPos); else // shorten this sub selection --( aSels.GetObject(nSubSelPos++)->Max() ); // adjust the selected counter --nSelCount; } // shift the sub selections behind the removed index for ( sal_uIntPtr nPos = nSubSelPos; nPos < aSels.Count(); ++nPos ) { --( aSels.GetObject(nPos)->Min() ); --( aSels.GetObject(nPos)->Max() ); } bCurValid = sal_False; aTotRange.Max() -= 1; DBG(Print( this )); } // ----------------------------------------------------------------------- void MultiSelection::Append( long nCount ) { long nPrevLast = aTotRange.Max(); aTotRange.Max() += nCount; if ( bSelectNew ) { nSelCount += nCount; aSels.Insert( new Range( nPrevLast+1, nPrevLast + nCount ), LIST_APPEND ); if ( aSels.Count() > 1 ) ImplMergeSubSelections( aSels.Count() - 2, aSels.Count() ); } } // ----------------------------------------------------------------------- long MultiSelection::ImplFwdUnselected() { if ( !bCurValid ) return SFX_ENDOFSELECTION; if ( ( nCurSubSel < aSels.Count() ) && ( aSels.GetObject(nCurSubSel)->Min() <= nCurIndex ) ) nCurIndex = aSels.GetObject(nCurSubSel++)->Max() + 1; if ( nCurIndex <= aTotRange.Max() ) return nCurIndex; else return SFX_ENDOFSELECTION; } // ----------------------------------------------------------------------- long MultiSelection::ImplBwdUnselected() { if ( !bCurValid ) return SFX_ENDOFSELECTION; if ( aSels.GetObject(nCurSubSel)->Max() < nCurIndex ) return nCurIndex; nCurIndex = aSels.GetObject(nCurSubSel--)->Min() - 1; if ( nCurIndex >= 0 ) return nCurIndex; else return SFX_ENDOFSELECTION; } // ----------------------------------------------------------------------- long MultiSelection::FirstSelected( sal_Bool bInverse ) { bInverseCur = bInverse; nCurSubSel = 0; if ( bInverseCur ) { bCurValid = nSelCount < sal_uIntPtr(aTotRange.Len()); if ( bCurValid ) { nCurIndex = 0; return ImplFwdUnselected(); } } else { bCurValid = aSels.Count() > 0; if ( bCurValid ) return nCurIndex = aSels.GetObject(0)->Min(); } return SFX_ENDOFSELECTION; } // ----------------------------------------------------------------------- long MultiSelection::LastSelected() { nCurSubSel = aSels.Count() - 1; bCurValid = aSels.Count() > 0; if ( bCurValid ) return nCurIndex = aSels.GetObject(nCurSubSel)->Max(); return SFX_ENDOFSELECTION; } // ----------------------------------------------------------------------- long MultiSelection::NextSelected() { if ( !bCurValid ) return SFX_ENDOFSELECTION; if ( bInverseCur ) { ++nCurIndex; return ImplFwdUnselected(); } else { // is the next index in the current sub selection too? if ( nCurIndex < aSels.GetObject(nCurSubSel)->Max() ) return ++nCurIndex; // are there further sub selections? if ( ++nCurSubSel < aSels.Count() ) return nCurIndex = aSels.GetObject(nCurSubSel)->Min(); // we are at the end! return SFX_ENDOFSELECTION; } } // ----------------------------------------------------------------------- long MultiSelection::PrevSelected() { if ( !bCurValid ) return SFX_ENDOFSELECTION; if ( bInverseCur ) { --nCurIndex; return ImplBwdUnselected(); } else { // is the previous index in the current sub selection too? if ( nCurIndex > aSels.GetObject(nCurSubSel)->Min() ) return --nCurIndex; // are there previous sub selections? if ( nCurSubSel > 0 ) { --nCurSubSel; return nCurIndex = aSels.GetObject(nCurSubSel)->Max(); } // we are at the beginning! return SFX_ENDOFSELECTION; } } // ----------------------------------------------------------------------- void MultiSelection::SetTotalRange( const Range& rTotRange ) { aTotRange = rTotRange; // die untere Bereichsgrenze anpassen Range* pRange = aSels.GetObject( 0 ); while( pRange ) { if( pRange->Max() < aTotRange.Min() ) { delete pRange; aSels.Remove( (sal_uIntPtr)0 ); } else if( pRange->Min() < aTotRange.Min() ) { pRange->Min() = aTotRange.Min(); break; } else break; pRange = aSels.GetObject( 0 ); } // die obere Bereichsgrenze anpassen sal_uIntPtr nCount = aSels.Count(); while( nCount ) { pRange = aSels.GetObject( nCount - 1 ); if( pRange->Min() > aTotRange.Max() ) { delete pRange; aSels.Remove( (sal_uIntPtr)(nCount - 1) ); } else if( pRange->Max() > aTotRange.Max() ) { pRange->Max() = aTotRange.Max(); break; } else break; nCount = aSels.Count(); } // Selection-Count neu berechnen nSelCount = 0; pRange = aSels.First(); while( pRange ) { nSelCount += pRange->Len(); pRange = aSels.Next(); } bCurValid = sal_False; nCurIndex = 0; } // ----------------------------------------------------------------------- // // StringRangeEnumerator // // ----------------------------------------------------------------------- StringRangeEnumerator::StringRangeEnumerator( const rtl::OUString& i_rInput, sal_Int32 i_nMinNumber, sal_Int32 i_nMaxNumber, sal_Int32 i_nLogicalOffset ) : mnCount( 0 ) , mnMin( i_nMinNumber ) , mnMax( i_nMaxNumber ) , mnOffset( i_nLogicalOffset ) { setRange( i_rInput ); } bool StringRangeEnumerator::checkValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const { if( mnMin >= 0 && i_nValue < mnMin ) return false; if( mnMax >= 0 && i_nValue > mnMax ) return false; if( i_nValue < 0 ) return false; if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) return false; return true; } bool StringRangeEnumerator::insertRange( sal_Int32 i_nFirst, sal_Int32 i_nLast, bool bSequence, bool bMayAdjust ) { bool bSuccess = true; if( bSequence ) { if( i_nFirst == -1 ) i_nFirst = mnMin; if( i_nLast == -1 ) i_nLast = mnMax; if( bMayAdjust ) { if( i_nFirst < mnMin ) i_nFirst = mnMin; if( i_nFirst > mnMax ) i_nFirst = mnMax; if( i_nLast < mnMin ) i_nLast = mnMin; if( i_nLast > mnMax ) i_nLast = mnMax; } if( checkValue( i_nFirst ) && checkValue( i_nLast ) ) { maSequence.push_back( Range( i_nFirst, i_nLast ) ); sal_Int32 nNumber = i_nLast - i_nFirst; nNumber = nNumber < 0 ? -nNumber : nNumber; mnCount += nNumber + 1; } else bSuccess = false; } else { if( i_nFirst >= 0 ) { if( checkValue( i_nFirst ) ) { maSequence.push_back( Range( i_nFirst, i_nFirst ) ); mnCount++; } else bSuccess = false; } if( i_nLast >= 0 ) { if( checkValue( i_nLast ) ) { maSequence.push_back( Range( i_nLast, i_nLast ) ); mnCount++; } else bSuccess = false; } } return bSuccess; } bool StringRangeEnumerator::setRange( const rtl::OUString& i_rNewRange, bool i_bStrict ) { mnCount = 0; maSequence.clear(); // we love special cases if( i_rNewRange.getLength() == 0 ) { if( mnMin >= 0 && mnMax >= 0 ) { insertRange( mnMin, mnMax, mnMin != mnMax, ! i_bStrict ); } return true; } const sal_Unicode* pInput = i_rNewRange.getStr(); rtl::OUStringBuffer aNumberBuf( 16 ); sal_Int32 nLastNumber = -1, nNumber = -1; bool bSequence = false; bool bSuccess = true; while( *pInput ) { while( *pInput >= sal_Unicode('0') && *pInput <= sal_Unicode('9') ) aNumberBuf.append( *pInput++ ); if( aNumberBuf.getLength() ) { if( nNumber != -1 ) { if( bSequence ) { if( ! insertRange( nLastNumber, nNumber, true, ! i_bStrict ) && i_bStrict ) { bSuccess = false; break; } nLastNumber = -1; } else { if( ! insertRange( nNumber, nNumber, false, ! i_bStrict ) && i_bStrict ) { bSuccess = false; break; } } } nNumber = aNumberBuf.makeStringAndClear().toInt32(); nNumber += mnOffset; } bool bInsertRange = false; if( *pInput == sal_Unicode('-') ) { nLastNumber = nNumber; nNumber = -1; bSequence = true; } else if( *pInput == ' ' ) { } else if( *pInput == sal_Unicode(',') || *pInput == sal_Unicode(';') ) bInsertRange = true; else if( *pInput ) { bSuccess = false; break; // parse error } if( bInsertRange ) { if( ! insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ) && i_bStrict ) { bSuccess = false; break; } nNumber = nLastNumber = -1; bSequence = false; } if( *pInput ) pInput++; } // insert last entries insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ); return bSuccess; } bool StringRangeEnumerator::hasValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const { if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) return false; size_t n = maSequence.size(); for( size_t i= 0; i < n; ++i ) { const StringRangeEnumerator::Range rRange( maSequence[i] ); if( rRange.nFirst < rRange.nLast ) { if( i_nValue >= rRange.nFirst && i_nValue <= rRange.nLast ) return true; } else { if( i_nValue >= rRange.nLast && i_nValue <= rRange.nFirst ) return true; } } return false; } StringRangeEnumerator::Iterator& StringRangeEnumerator::Iterator::operator++() { if( nRangeIndex >= 0 && nCurrent >= 0 && pEnumerator ) { const StringRangeEnumerator::Range& rRange( pEnumerator->maSequence[nRangeIndex] ); bool bRangeChange = false; if( rRange.nLast < rRange.nFirst ) { // backward range if( nCurrent > rRange.nLast ) nCurrent--; else bRangeChange = true; } else { // forward range if( nCurrent < rRange.nLast ) nCurrent++; else bRangeChange = true; } if( bRangeChange ) { nRangeIndex++; if( size_t(nRangeIndex) == pEnumerator->maSequence.size() ) { // reached the end nRangeIndex = nCurrent = -1; } else nCurrent = pEnumerator->maSequence[nRangeIndex].nFirst; } if( nRangeIndex != -1 && nCurrent != -1 ) { if( ! pEnumerator->checkValue( nCurrent, pPossibleValues ) ) return ++(*this); } } return *this; } sal_Int32 StringRangeEnumerator::Iterator::operator*() const { return nCurrent; } bool StringRangeEnumerator::Iterator::operator==( const Iterator& i_rCompare ) const { return i_rCompare.pEnumerator == pEnumerator && i_rCompare.nRangeIndex == nRangeIndex && i_rCompare.nCurrent == nCurrent; } StringRangeEnumerator::Iterator StringRangeEnumerator::begin( const std::set< sal_Int32 >* i_pPossibleValues ) const { StringRangeEnumerator::Iterator it( this, i_pPossibleValues, maSequence.empty() ? -1 : 0, maSequence.empty() ? -1 : maSequence[0].nFirst ); if( ! checkValue(*it, i_pPossibleValues ) ) ++it; return it; } StringRangeEnumerator::Iterator StringRangeEnumerator::end( const std::set< sal_Int32 >* i_pPossibleValues ) const { return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 ); } bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange, std::vector< sal_Int32 >& o_rPageVector, sal_Int32 i_nMinNumber, sal_Int32 i_nMaxNumber, sal_Int32 i_nLogicalOffset, std::set< sal_Int32 >* i_pPossibleValues ) { StringRangeEnumerator aEnum; aEnum.setMin( i_nMinNumber ); aEnum.setMax( i_nMaxNumber ); aEnum.setLogicalOffset( i_nLogicalOffset ); bool bRes = aEnum.setRange( i_rPageRange ); if( bRes ) { o_rPageVector.clear(); o_rPageVector.reserve( aEnum.size() ); for( StringRangeEnumerator::Iterator it = aEnum.begin( i_pPossibleValues ); it != aEnum.end( i_pPossibleValues ); ++it ) { o_rPageVector.push_back( *it ); } } return bRes; }