LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/tools/source/memtools - multisel.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 220 401 54.9 %
Date: 2013-07-09 Functions: 25 32 78.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #ifdef MI_DEBUG
      21             : #define private public
      22             : #include <stdio.h>
      23             : #endif
      24             : 
      25             : #include <tools/debug.hxx>
      26             : #include <tools/multisel.hxx>
      27             : 
      28             : #include "rtl/ustrbuf.hxx"
      29             : 
      30             : #ifdef MI_DEBUG
      31             : #define DBG(x) x
      32             : #else
      33             : #define DBG(x)
      34             : #endif
      35             : 
      36             : 
      37             : #ifdef MI_DEBUG
      38             : static void Print( const MultiSelection* pSel )
      39             : {
      40             :     DbgOutf( "TotRange:     %4ld-%4ld\n",
      41             :              pSel->aTotRange.Min(), pSel->aTotRange.Max() );
      42             :     if ( pSel->bCurValid )
      43             :     {
      44             :         DbgOutf( "CurSubSel:    %4ld\n", pSel->nCurSubSel );
      45             :         DbgOutf( "CurIndex:     %4ld\n", pSel->nCurIndex );
      46             :     }
      47             :     DbgOutf( "SelCount:     %4ld\n", pSel->nSelCount );
      48             :     DbgOutf( "SubCount:     %4ld\n", pSel->aSels.Count() );
      49             :     for ( sal_uIntPtr nPos = 0; nPos < pSel->aSels.Count(); ++nPos )
      50             :     {
      51             :         DbgOutf( "SubSel #%2ld:   %4ld-%4ld\n", nPos,
      52             :                  pSel->aSels.GetObject(nPos)->Min(),
      53             :                  pSel->aSels.GetObject(nPos)->Max() );
      54             :     }
      55             :     DbgOutf( "\n" );
      56             :     fclose( pFile );
      57             : }
      58             : #endif
      59             : 
      60         180 : void MultiSelection::ImplClear()
      61             : {
      62             :     // no selected indexes
      63         180 :     nSelCount = 0;
      64             : 
      65         183 :     for ( size_t i = 0, n = aSels.size(); i < n; ++i ) {
      66           3 :         delete aSels[ i ];
      67             :     }
      68         180 :     aSels.clear();
      69         180 : }
      70             : 
      71        1123 : size_t MultiSelection::ImplFindSubSelection( long nIndex ) const
      72             : {
      73             :     // iterate through the sub selections
      74        1123 :     size_t n = 0;
      75        2308 :     for ( ;
      76        1185 :           n < aSels.size() && nIndex > aSels[ n ]->Max();
      77             :           ++n ) {} /* empty loop */
      78        1123 :     return n;
      79             : }
      80             : 
      81           2 : bool MultiSelection::ImplMergeSubSelections( size_t nPos1, size_t nPos2 )
      82             : {
      83             :     // didn't a sub selection at nPos2 exist?
      84           2 :     if ( nPos2 >= aSels.size() )
      85           0 :         return false;
      86             : 
      87             :     // did the sub selections touch each other?
      88           2 :     if ( (aSels[ nPos1 ]->Max() + 1) == aSels[ nPos2 ]->Min() )
      89             :     {
      90             :         // merge them
      91           2 :         aSels[ nPos1 ]->Max() = aSels[ nPos2 ]->Max();
      92           2 :         ImpSelList::iterator it = aSels.begin();
      93           2 :         ::std::advance( it, nPos2 );
      94           2 :         delete *it;
      95           2 :         aSels.erase( it );
      96           2 :         return true;
      97             :     }
      98             : 
      99           0 :     return false;
     100             : }
     101             : 
     102          42 : MultiSelection::MultiSelection():
     103             :     aTotRange( 0, -1 ),
     104             :     nCurSubSel(0),
     105             :     nSelCount(0),
     106             :     bCurValid(false),
     107          42 :     bSelectNew(false)
     108             : {
     109          42 : }
     110             : 
     111           0 : MultiSelection::MultiSelection( const MultiSelection& rOrig ) :
     112             :     aTotRange(rOrig.aTotRange),
     113             :     nSelCount(rOrig.nSelCount),
     114             :     bCurValid(rOrig.bCurValid),
     115           0 :     bSelectNew(false)
     116             : {
     117           0 :     if ( bCurValid )
     118             :     {
     119           0 :         nCurSubSel = rOrig.nCurSubSel;
     120           0 :         nCurIndex = rOrig.nCurIndex;
     121             :     }
     122             : 
     123             :     // copy the sub selections
     124           0 :     for ( size_t n = 0; n < rOrig.aSels.size(); ++n )
     125           0 :         aSels.push_back( new Range( *rOrig.aSels[ n ] ) );
     126           0 : }
     127             : 
     128       16292 : MultiSelection::MultiSelection( const Range& rRange ):
     129             :     aTotRange(rRange),
     130             :     nCurSubSel(0),
     131             :     nSelCount(0),
     132             :     bCurValid(false),
     133       16292 :     bSelectNew(false)
     134             : {
     135       16292 : }
     136             : 
     137       32668 : MultiSelection::~MultiSelection()
     138             : {
     139       16748 :     for ( size_t i = 0, n = aSels.size(); i < n; ++i )
     140         414 :         delete aSels[ i ];
     141       16334 :     aSels.clear();
     142       16334 : }
     143             : 
     144           0 : MultiSelection& MultiSelection::operator= ( const MultiSelection& rOrig )
     145             : {
     146           0 :     aTotRange = rOrig.aTotRange;
     147           0 :     bCurValid = rOrig.bCurValid;
     148           0 :     if ( bCurValid )
     149             :     {
     150           0 :         nCurSubSel = rOrig.nCurSubSel;
     151           0 :         nCurIndex = rOrig.nCurIndex;
     152             :     }
     153             : 
     154             :     // clear the old and copy the sub selections
     155           0 :     ImplClear();
     156           0 :     for ( size_t n = 0; n < rOrig.aSels.size(); ++n )
     157           0 :         aSels.push_back( new Range( *rOrig.aSels[ n ] ) );
     158           0 :     nSelCount = rOrig.nSelCount;
     159             : 
     160           0 :     return *this;
     161             : }
     162             : 
     163           0 : bool MultiSelection::operator== ( MultiSelection& rWith )
     164             : {
     165           0 :     if ( aTotRange != rWith.aTotRange || nSelCount != rWith.nSelCount ||
     166           0 :          aSels.size() != rWith.aSels.size() )
     167           0 :         return false;
     168             : 
     169             :     // compare the sub seletions
     170           0 :     for ( size_t n = 0; n < aSels.size(); ++n )
     171           0 :         if ( *aSels[ n ] != *rWith.aSels[ n ] )
     172           0 :             return false;
     173           0 :     return true;
     174             : }
     175             : 
     176         177 : void MultiSelection::SelectAll( bool bSelect )
     177             : {
     178             :     DBG(DbgOutf( "::SelectAll(%s)\n", bSelect ? "sal_True" : "sal_False" ));
     179             : 
     180         177 :     ImplClear();
     181         177 :     if ( bSelect )
     182             :     {
     183         155 :         aSels.push_back( new Range(aTotRange) );
     184         155 :         nSelCount = aTotRange.Len();
     185             :     }
     186             : 
     187             :     DBG(Print( this ));
     188         177 : }
     189             : 
     190          10 : bool MultiSelection::Select( long nIndex, bool bSelect )
     191             : {
     192             :     DBG_ASSERT( aTotRange.IsInside(nIndex), "selected index out of range" );
     193             : 
     194             :     // out of range?
     195          10 :     if ( !aTotRange.IsInside(nIndex) )
     196           0 :         return false;
     197             : 
     198             :     // find the virtual target position
     199          10 :     size_t nSubSelPos = ImplFindSubSelection( nIndex );
     200             : 
     201          10 :     if ( bSelect )
     202             :     {
     203             :         // is it included in the found sub selection?
     204          10 :         if ( nSubSelPos < aSels.size() && aSels[ nSubSelPos ]->IsInside( nIndex ) )
     205             :             // already selected, nothing to do
     206           6 :             return false;
     207             : 
     208             :         // it will become selected
     209           4 :         ++nSelCount;
     210             : 
     211             :         // is it at the end of the previous sub selection
     212           6 :         if ( nSubSelPos > 0 &&
     213           2 :              aSels[ nSubSelPos-1 ]->Max() == (nIndex-1) )
     214             :         {
     215             :             // expand the previous sub selection
     216           2 :             aSels[ nSubSelPos-1 ]->Max() = nIndex;
     217             : 
     218             :             // try to merge the previous sub selection
     219           2 :             ImplMergeSubSelections( nSubSelPos-1, nSubSelPos );
     220             :         }
     221             :         // is is at the beginning of the found sub selection
     222           4 :         else if (  nSubSelPos < aSels.size()
     223           2 :                 && aSels[ nSubSelPos ]->Min() == (nIndex+1)
     224             :         )
     225             :             // expand the found sub selection
     226           0 :             aSels[ nSubSelPos ]->Min() = nIndex;
     227             :         else
     228             :         {
     229             :             // create a new sub selection
     230           2 :             if ( nSubSelPos < aSels.size() ) {
     231           2 :                 ImpSelList::iterator it = aSels.begin();
     232           2 :                 ::std::advance( it, nSubSelPos );
     233           2 :                 aSels.insert( it, new Range( nIndex, nIndex ) );
     234             :             } else {
     235           0 :                 aSels.push_back( new Range( nIndex, nIndex ) );
     236             :             }
     237           2 :             if ( bCurValid && nCurSubSel >= nSubSelPos )
     238           2 :                 ++nCurSubSel;
     239             :         }
     240             :     }
     241             :     else
     242             :     {
     243             :         // is it excluded from the found sub selection?
     244           0 :         if (  nSubSelPos >= aSels.size()
     245           0 :            || !aSels[ nSubSelPos ]->IsInside( nIndex )
     246             :         ) {
     247             :             // not selected, nothing to do
     248             :             DBG(Print( this ));
     249           0 :             return false;
     250             :         }
     251             : 
     252             :         // it will become deselected
     253           0 :         --nSelCount;
     254             : 
     255             :         // is it the only index in the found sub selection?
     256           0 :         if ( aSels[ nSubSelPos ]->Len() == 1 )
     257             :         {
     258             :             // remove the complete sub selection
     259           0 :             ImpSelList::iterator it = aSels.begin();
     260           0 :             ::std::advance( it, nSubSelPos );
     261           0 :             delete *it;
     262           0 :             aSels.erase( it );
     263             :             DBG(Print( this ));
     264           0 :             return true;
     265             :         }
     266             : 
     267             :         // is it at the beginning of the found sub selection?
     268           0 :         if ( aSels[ nSubSelPos ]->Min() == nIndex )
     269           0 :             ++aSels[ nSubSelPos ]->Min();
     270             :         // is it at the end of the found sub selection?
     271           0 :         else if ( aSels[ nSubSelPos ]->Max() == nIndex )
     272           0 :             --aSels[ nSubSelPos ]->Max();
     273             :         // it is in the middle of the found sub selection?
     274             :         else
     275             :         {
     276             :             // split the sub selection
     277           0 :             if ( nSubSelPos < aSels.size() ) {
     278           0 :                 ImpSelList::iterator it = aSels.begin();
     279           0 :                 ::std::advance( it, nSubSelPos );
     280           0 :                 aSels.insert( it, new Range( aSels[ nSubSelPos ]->Min(), nIndex-1 ) );
     281             :             } else {
     282           0 :                 aSels.push_back( new Range( aSels[ nSubSelPos ]->Min(), nIndex-1 ) );
     283             :             }
     284           0 :             aSels[ nSubSelPos+1 ]->Min() = nIndex + 1;
     285             :         }
     286             :     }
     287             : 
     288             :     DBG(Print( this ));
     289             : 
     290           4 :     return true;
     291             : }
     292             : 
     293         477 : void MultiSelection::Select( const Range& rIndexRange, bool bSelect )
     294             : {
     295             :     Range* pRange;
     296             :     long nOld;
     297             : 
     298         477 :     sal_uIntPtr nTmpMin = rIndexRange.Min();
     299         477 :     sal_uIntPtr nTmpMax = rIndexRange.Max();
     300         477 :     sal_uIntPtr nCurMin = FirstSelected();
     301         477 :     sal_uIntPtr nCurMax = LastSelected();
     302             :     DBG_ASSERT(aTotRange.IsInside(nTmpMax), "selected index out of range" );
     303             :     DBG_ASSERT(aTotRange.IsInside(nTmpMin), "selected index out of range" );
     304             : 
     305             :     // replace whole selection?
     306         477 :     if( nTmpMin <= nCurMin && nTmpMax >= nCurMax )
     307             :     {
     308           3 :         ImplClear();
     309           3 :         if ( bSelect )
     310             :         {
     311           3 :             aSels.push_back( new Range(rIndexRange) );
     312           3 :             nSelCount = rIndexRange.Len();
     313             :         }
     314         478 :         return;
     315             :     }
     316             :     // expand on left side?
     317         474 :     if( nTmpMax < nCurMin )
     318             :     {
     319         212 :         if( bSelect )
     320             :         {
     321             :             // extend first range?
     322         194 :             if( nCurMin > (nTmpMax+1)  )
     323             :             {
     324         194 :                 pRange = new Range( rIndexRange );
     325         194 :                 aSels.insert( aSels.begin() , pRange );
     326         194 :                 nSelCount += pRange->Len();
     327             :             }
     328             :             else
     329             :             {
     330           0 :                 pRange = aSels.front();
     331           0 :                 nOld = pRange->Min();
     332           0 :                 pRange->Min() = (long)nTmpMin;
     333           0 :                 nSelCount += ( nOld - nTmpMin );
     334             :             }
     335         194 :             bCurValid = false;
     336             :         }
     337         212 :         return;
     338             :     }
     339             :     // expand on right side?
     340         262 :     else if( nTmpMin > nCurMax )
     341             :     {
     342         260 :         if( bSelect )
     343             :         {
     344             :             // extend last range?
     345         260 :             if( nTmpMin > (nCurMax+1) )
     346             :             {
     347          65 :                 pRange = new Range( rIndexRange );
     348          65 :                 aSels.push_back( pRange );
     349          65 :                 nSelCount += pRange->Len();
     350             :             }
     351             :             else
     352             :             {
     353         195 :                 pRange = aSels.back();
     354         195 :                 nOld = pRange->Max();
     355         195 :                 pRange->Max() = (long)nTmpMax;
     356         195 :                 nSelCount += ( nTmpMax - nOld );
     357             :             }
     358         260 :             bCurValid = false;
     359             :         }
     360         260 :         return;
     361             :     }
     362             : 
     363             :     // TODO here is potential for optimization
     364          14 :     while( nTmpMin <= nTmpMax )
     365             :     {
     366          10 :         Select( nTmpMin, bSelect );
     367          10 :         nTmpMin++;
     368             :     }
     369             : }
     370             : 
     371         983 : bool MultiSelection::IsSelected( long nIndex ) const
     372             : {
     373             :     // find the virtual target position
     374         983 :     size_t nSubSelPos = ImplFindSubSelection( nIndex );
     375             : 
     376         983 :     return nSubSelPos < aSels.size() && aSels[ nSubSelPos ]->IsInside(nIndex);
     377             : }
     378             : 
     379         107 : void MultiSelection::Insert( long nIndex, long nCount )
     380             : {
     381             :     DBG(DbgOutf( "::Insert(%ld, %ld)\n", nIndex, nCount ));
     382             : 
     383             :     // find the virtual target position
     384         107 :     size_t nSubSelPos = ImplFindSubSelection( nIndex );
     385             : 
     386             :     // did we need to shift the sub selections?
     387         107 :     if ( nSubSelPos < aSels.size() )
     388             :     {   // did we insert an unselected into an existing sub selection?
     389           0 :         if (  !bSelectNew
     390           0 :            && aSels[ nSubSelPos ]->Min() != nIndex
     391           0 :            && aSels[ nSubSelPos ]->IsInside(nIndex)
     392             :         ) { // split the sub selection
     393           0 :             if ( nSubSelPos < aSels.size() ) {
     394           0 :                 ImpSelList::iterator it = aSels.begin();
     395           0 :                 ::std::advance( it, nSubSelPos );
     396           0 :                 aSels.insert( it, new Range( aSels[ nSubSelPos ]->Min(), nIndex-1 ) );
     397             :             } else {
     398           0 :                 aSels.push_back( new Range( aSels[ nSubSelPos ]->Min(), nIndex-1 ) );
     399             :             }
     400           0 :             ++nSubSelPos;
     401           0 :             aSels[ nSubSelPos ]->Min() = nIndex;
     402             :         }
     403             : 
     404             :         // did we append an selected to an existing sub selection?
     405           0 :         else if (  bSelectNew
     406           0 :                 && nSubSelPos > 0
     407           0 :                 && aSels[ nSubSelPos ]->Max() == nIndex-1
     408             :         )   // expand the previous sub selection
     409           0 :             aSels[ nSubSelPos-1 ]->Max() += nCount;
     410             : 
     411             :         // did we insert an selected into an existing sub selection?
     412           0 :         else if (  bSelectNew
     413           0 :                 && aSels[ nSubSelPos ]->Min() == nIndex
     414             :         ) { // expand the sub selection
     415           0 :             aSels[ nSubSelPos ]->Max() += nCount;
     416           0 :             ++nSubSelPos;
     417             :         }
     418             : 
     419             :         // shift the sub selections behind the inserting position
     420           0 :         for ( size_t nPos = nSubSelPos; nPos < aSels.size(); ++nPos )
     421             :         {
     422           0 :             aSels[ nPos ]->Min() += nCount;
     423           0 :             aSels[ nPos ]->Max() += nCount;
     424             :         }
     425             :     }
     426             : 
     427         107 :     bCurValid = false;
     428         107 :     aTotRange.Max() += nCount;
     429         107 :     if ( bSelectNew )
     430           0 :         nSelCount += nCount;
     431             : 
     432             :     DBG(Print( this ));
     433         107 : }
     434             : 
     435          23 : void MultiSelection::Remove( long nIndex )
     436             : {
     437             :     DBG(DbgOutf( "::Remove(%ld)\n", nIndex ));
     438             : 
     439             :     // find the virtual target position
     440          23 :     size_t nSubSelPos = ImplFindSubSelection( nIndex );
     441             : 
     442             :     // did we remove from an existing sub selection?
     443          46 :     if (  nSubSelPos < aSels.size()
     444          23 :        && aSels[ nSubSelPos ]->IsInside(nIndex)
     445             :     ) {
     446             :         // does this sub selection only contain the index to be deleted
     447           0 :         if ( aSels[ nSubSelPos ]->Len() == 1 ) {
     448             :             // completely remove the sub selection
     449           0 :             ImpSelList::iterator it = aSels.begin();
     450           0 :             ::std::advance( it, nSubSelPos );
     451           0 :             delete *it;
     452           0 :             aSels.erase( it );
     453             :         } else {
     454             :             // shorten this sub selection
     455           0 :             --( aSels[ nSubSelPos++ ]->Max() );
     456             :         }
     457             : 
     458             :         // adjust the selected counter
     459           0 :         --nSelCount;
     460             :     }
     461             : 
     462             :     // shift the sub selections behind the removed index
     463          23 :     for ( size_t nPos = nSubSelPos; nPos < aSels.size(); ++nPos )
     464             :     {
     465           0 :         --( aSels[ nPos ]->Min() );
     466           0 :         --( aSels[ nPos ]->Max() );
     467             :     }
     468             : 
     469          23 :     bCurValid = false;
     470          23 :     aTotRange.Max() -= 1;
     471             : 
     472             :     DBG(Print( this ));
     473          23 : }
     474             : 
     475           0 : long MultiSelection::ImplFwdUnselected()
     476             : {
     477           0 :     if ( !bCurValid )
     478           0 :         return SFX_ENDOFSELECTION;
     479             : 
     480           0 :     if (  ( nCurSubSel < aSels.size() )
     481           0 :        && ( aSels[ nCurSubSel ]->Min() <= nCurIndex )
     482             :     )
     483           0 :         nCurIndex = aSels[ nCurSubSel++ ]->Max() + 1;
     484             : 
     485           0 :     if ( nCurIndex <= aTotRange.Max() )
     486           0 :         return nCurIndex;
     487             :     else
     488           0 :         return SFX_ENDOFSELECTION;
     489             : }
     490             : 
     491         520 : long MultiSelection::FirstSelected( bool bInverse )
     492             : {
     493         520 :     bInverseCur = bInverse;
     494         520 :     nCurSubSel = 0;
     495             : 
     496         520 :     if ( bInverseCur )
     497             :     {
     498           0 :         bCurValid = nSelCount < sal_uIntPtr(aTotRange.Len());
     499           0 :         if ( bCurValid )
     500             :         {
     501           0 :             nCurIndex = 0;
     502           0 :             return ImplFwdUnselected();
     503             :         }
     504             :     }
     505             :     else
     506             :     {
     507         520 :         bCurValid = !aSels.empty();
     508         520 :         if ( bCurValid )
     509         265 :             return nCurIndex = aSels[ 0 ]->Min();
     510             :     }
     511             : 
     512         255 :     return SFX_ENDOFSELECTION;
     513             : }
     514             : 
     515         477 : long MultiSelection::LastSelected()
     516             : {
     517         477 :     nCurSubSel = aSels.size() - 1;
     518         477 :     bCurValid = !aSels.empty();
     519             : 
     520         477 :     if ( bCurValid )
     521         265 :         return nCurIndex = aSels[ nCurSubSel ]->Max();
     522             : 
     523         212 :     return SFX_ENDOFSELECTION;
     524             : }
     525             : 
     526           0 : long MultiSelection::NextSelected()
     527             : {
     528           0 :     if ( !bCurValid )
     529           0 :         return SFX_ENDOFSELECTION;
     530             : 
     531           0 :     if ( bInverseCur )
     532             :     {
     533           0 :         ++nCurIndex;
     534           0 :         return ImplFwdUnselected();
     535             :     }
     536             :     else
     537             :     {
     538             :         // is the next index in the current sub selection too?
     539           0 :         if ( nCurIndex < aSels[ nCurSubSel ]->Max() )
     540           0 :             return ++nCurIndex;
     541             : 
     542             :         // are there further sub selections?
     543           0 :         if ( ++nCurSubSel < aSels.size() )
     544           0 :             return nCurIndex = aSels[ nCurSubSel ]->Min();
     545             : 
     546             :         // we are at the end!
     547           0 :         return SFX_ENDOFSELECTION;
     548             :     }
     549             : }
     550             : 
     551         176 : void MultiSelection::SetTotalRange( const Range& rTotRange )
     552             : {
     553         176 :     aTotRange = rTotRange;
     554             : 
     555             :     // adjust lower boundary
     556         176 :     Range* pRange = aSels.empty() ? NULL : aSels.front();
     557         352 :     while( pRange )
     558             :     {
     559           0 :         if( pRange->Max() < aTotRange.Min() )
     560             :         {
     561           0 :             delete pRange;
     562           0 :             aSels.erase( aSels.begin() );
     563             :         }
     564           0 :         else if( pRange->Min() < aTotRange.Min() )
     565             :         {
     566           0 :             pRange->Min() = aTotRange.Min();
     567           0 :             break;
     568             :         }
     569             :         else
     570           0 :             break;
     571             : 
     572           0 :         pRange = aSels.empty() ? NULL : aSels.front();
     573             :     }
     574             : 
     575             :     // adjust upper boundary
     576         176 :     size_t nCount = aSels.size();
     577         352 :     while( nCount )
     578             :     {
     579           0 :         pRange = aSels[ nCount - 1 ];
     580           0 :         if( pRange->Min() > aTotRange.Max() )
     581             :         {
     582           0 :             delete pRange;
     583           0 :             aSels.pop_back();
     584             :         }
     585           0 :         else if( pRange->Max() > aTotRange.Max() )
     586             :         {
     587           0 :             pRange->Max() = aTotRange.Max();
     588           0 :             break;
     589             :         }
     590             :         else
     591           0 :             break;
     592             : 
     593           0 :         nCount = aSels.size();
     594             :     }
     595             : 
     596             :     // re-calculate selection count
     597         176 :     nSelCount = 0;
     598         176 :     for ( size_t i = 0, n = aSels.size(); i < n; ++ i )
     599           0 :         nSelCount += aSels[i]->Len();
     600             : 
     601         176 :     bCurValid = false;
     602         176 :     nCurIndex = 0;
     603         176 : }
     604             : 
     605             : // StringRangeEnumerator
     606             : 
     607           7 : StringRangeEnumerator::StringRangeEnumerator( const OUString& i_rInput,
     608             :                                               sal_Int32 i_nMinNumber,
     609             :                                               sal_Int32 i_nMaxNumber,
     610             :                                               sal_Int32 i_nLogicalOffset
     611             :                                               )
     612             :     : mnCount( 0 )
     613             :     , mnMin( i_nMinNumber )
     614             :     , mnMax( i_nMaxNumber )
     615             :     , mnOffset( i_nLogicalOffset )
     616           7 :     , mbValidInput( false )
     617             : {
     618             :     // Parse string only if boundaries are valid.
     619           7 :     if( mnMin >= 0 && mnMax >= 0 && mnMin <= mnMax )
     620           7 :         mbValidInput = setRange( i_rInput );
     621           7 : }
     622             : 
     623          16 : bool StringRangeEnumerator::checkValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const
     624             : {
     625          16 :     if( i_nValue < 0 || i_nValue < mnMin || i_nValue > mnMax )
     626           0 :         return false;
     627          16 :     if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() )
     628           0 :         return false;
     629          16 :     return true;
     630             : }
     631             : 
     632           7 : bool StringRangeEnumerator::insertRange( sal_Int32 i_nFirst, sal_Int32 i_nLast, bool bSequence, bool bMayAdjust )
     633             : {
     634           7 :     bool bSuccess = true;
     635           7 :     if( bSequence )
     636             :     {
     637           1 :         if( bMayAdjust )
     638             :         {
     639           1 :             if( i_nFirst < mnMin )
     640           0 :                 i_nFirst = mnMin;
     641           1 :             if( i_nFirst > mnMax )
     642           0 :                 i_nFirst = mnMax;
     643           1 :             if( i_nLast < mnMin )
     644           0 :                 i_nLast = mnMin;
     645           1 :             if( i_nLast > mnMax )
     646           0 :                 i_nLast = mnMax;
     647             :         }
     648           1 :         if( checkValue( i_nFirst ) && checkValue( i_nLast ) )
     649             :         {
     650           1 :             maSequence.push_back( Range( i_nFirst, i_nLast ) );
     651           1 :             sal_Int32 nNumber = i_nLast - i_nFirst;
     652           1 :             nNumber = nNumber < 0 ? -nNumber : nNumber;
     653           1 :             mnCount += nNumber + 1;
     654             :         }
     655             :         else
     656           0 :             bSuccess = false;
     657             :     }
     658             :     else
     659             :     {
     660           6 :         if( checkValue( i_nFirst ) )
     661             :         {
     662           6 :             maSequence.push_back( Range( i_nFirst, i_nFirst ) );
     663           6 :             mnCount++;
     664             :         }
     665           0 :         else if( checkValue( i_nLast ) )
     666             :         {
     667           0 :             maSequence.push_back( Range( i_nLast, i_nLast ) );
     668           0 :             mnCount++;
     669             :         }
     670             :         else
     671           0 :             bSuccess = false;
     672             :     }
     673             : 
     674           7 :     return bSuccess;
     675             : }
     676             : 
     677           7 : bool StringRangeEnumerator::insertJoinedRanges(
     678             :     const std::vector< sal_Int32 >& rNumbers, bool i_bStrict )
     679             : {
     680           7 :     size_t nCount = rNumbers.size();
     681           7 :     if( nCount == 0 )
     682           0 :         return true;
     683             : 
     684           7 :     if( nCount == 1 )
     685           0 :         return insertRange( rNumbers[0], -1, false, ! i_bStrict );
     686             : 
     687          14 :     for( size_t i = 0; i < nCount - 1; i++ )
     688             :     {
     689           7 :         sal_Int32 nFirst = rNumbers[i];
     690           7 :         sal_Int32 nLast  = rNumbers[i + 1];
     691           7 :         if( i > 0 )
     692             :         {
     693           0 :             if     ( nFirst > nLast ) nFirst--;
     694           0 :             else if( nFirst < nLast ) nFirst++;
     695             :         }
     696             : 
     697           7 :         if ( ! insertRange( nFirst, nLast, nFirst != nLast, ! i_bStrict ) && i_bStrict)
     698           0 :             return false;
     699             :     }
     700             : 
     701           7 :     return true;
     702             : }
     703             : 
     704           7 : bool StringRangeEnumerator::setRange( const OUString& i_rNewRange, bool i_bStrict )
     705             : {
     706           7 :     mnCount = 0;
     707           7 :     maSequence.clear();
     708             : 
     709           7 :     const sal_Unicode* pInput = i_rNewRange.getStr();
     710           7 :     OUStringBuffer aNumberBuf( 16 );
     711          14 :     std::vector< sal_Int32 > aNumbers;
     712           7 :     bool bSequence = false;
     713          28 :     while( *pInput )
     714             :     {
     715          42 :         while( *pInput >= sal_Unicode('0') && *pInput <= sal_Unicode('9') )
     716          14 :             aNumberBuf.append( *pInput++ );
     717          14 :         if( !aNumberBuf.isEmpty() )
     718             :         {
     719          14 :             sal_Int32 nNumber = aNumberBuf.makeStringAndClear().toInt32() + mnOffset;
     720          14 :             aNumbers.push_back( nNumber );
     721          14 :             bSequence = false;
     722             :         }
     723             : 
     724          14 :         if( *pInput == sal_Unicode('-') )
     725             :         {
     726           7 :             bSequence = true;
     727           7 :             if( aNumbers.empty() )
     728           0 :                 aNumbers.push_back( mnMin );
     729             :         }
     730           7 :         else if( *pInput == sal_Unicode(',') || *pInput == sal_Unicode(';') )
     731             :         {
     732           0 :             if( bSequence && !aNumbers.empty() )
     733           0 :                 aNumbers.push_back( mnMax );
     734           0 :             if( ! insertJoinedRanges( aNumbers, i_bStrict ) && i_bStrict )
     735           0 :                 return false;
     736             : 
     737           0 :             aNumbers.clear();
     738           0 :             bSequence = false;
     739             :         }
     740           7 :         else if( *pInput && *pInput != sal_Unicode(' ') )
     741           0 :             return false; // parse error
     742             : 
     743          14 :         if( *pInput )
     744           7 :             pInput++;
     745             :     }
     746             :     // insert last entries
     747           7 :     if( bSequence && !aNumbers.empty() )
     748           0 :         aNumbers.push_back( mnMax );
     749           7 :     if( ! insertJoinedRanges( aNumbers, i_bStrict ) && i_bStrict )
     750           0 :         return false;
     751             : 
     752          14 :     return true;
     753             : }
     754             : 
     755           0 : bool StringRangeEnumerator::hasValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const
     756             : {
     757           0 :     if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() )
     758           0 :         return false;
     759           0 :     size_t n = maSequence.size();
     760           0 :     for( size_t i= 0; i < n; ++i )
     761             :     {
     762           0 :         const StringRangeEnumerator::Range rRange( maSequence[i] );
     763           0 :         if( rRange.nFirst < rRange.nLast )
     764             :         {
     765           0 :             if( i_nValue >= rRange.nFirst && i_nValue <= rRange.nLast )
     766           0 :                 return true;
     767             :         }
     768             :         else
     769             :         {
     770           0 :             if( i_nValue >= rRange.nLast && i_nValue <= rRange.nFirst )
     771           0 :                 return true;
     772             :         }
     773             :     }
     774           0 :     return false;
     775             : }
     776             : 
     777           8 : StringRangeEnumerator::Iterator& StringRangeEnumerator::Iterator::operator++()
     778             : {
     779           8 :     if( nRangeIndex >= 0 && nCurrent >= 0 && pEnumerator )
     780             :     {
     781           8 :         const StringRangeEnumerator::Range& rRange( pEnumerator->maSequence[nRangeIndex] );
     782           8 :         bool bRangeChange = false;
     783           8 :         if( rRange.nLast < rRange.nFirst )
     784             :         {
     785             :             // backward range
     786           0 :             if( nCurrent > rRange.nLast )
     787           0 :                 nCurrent--;
     788             :             else
     789           0 :                 bRangeChange = true;
     790             :         }
     791             :         else
     792             :         {
     793             :             // forward range
     794           8 :             if( nCurrent < rRange.nLast )
     795           1 :                 nCurrent++;
     796             :             else
     797           7 :                 bRangeChange = true;
     798             :         }
     799           8 :         if( bRangeChange )
     800             :         {
     801           7 :             nRangeIndex++;
     802           7 :             if( size_t(nRangeIndex) == pEnumerator->maSequence.size() )
     803             :             {
     804             :                 // reached the end
     805           7 :                 nRangeIndex = nCurrent = -1;
     806             :             }
     807             :             else
     808           0 :                 nCurrent = pEnumerator->maSequence[nRangeIndex].nFirst;
     809             :         }
     810           8 :         if( nRangeIndex != -1 && nCurrent != -1 )
     811             :         {
     812           1 :             if( ! pEnumerator->checkValue( nCurrent, pPossibleValues ) )
     813           0 :                 return ++(*this);
     814             :         }
     815             :     }
     816           8 :     return *this;
     817             : }
     818             : 
     819          15 : sal_Int32 StringRangeEnumerator::Iterator::operator*() const
     820             : {
     821          15 :     return nCurrent;
     822             : }
     823             : 
     824          22 : bool StringRangeEnumerator::Iterator::operator==( const Iterator& i_rCompare ) const
     825             : {
     826          22 :     return i_rCompare.pEnumerator == pEnumerator && i_rCompare.nRangeIndex == nRangeIndex && i_rCompare.nCurrent == nCurrent;
     827             : }
     828             : 
     829           7 : StringRangeEnumerator::Iterator StringRangeEnumerator::begin( const std::set< sal_Int32 >* i_pPossibleValues ) const
     830             : {
     831             :     StringRangeEnumerator::Iterator it( this,
     832             :                                         i_pPossibleValues,
     833           7 :                                         maSequence.empty() ? -1 : 0,
     834          14 :                                         maSequence.empty() ? -1 : maSequence[0].nFirst );
     835           7 :     if( ! checkValue(*it, i_pPossibleValues ) )
     836           0 :         ++it;
     837           7 :     return it;
     838             : }
     839             : 
     840           7 : StringRangeEnumerator::Iterator StringRangeEnumerator::end( const std::set< sal_Int32 >* i_pPossibleValues ) const
     841             : {
     842           7 :     return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 );
     843             : }
     844             : 
     845           0 : bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange,
     846             :                                                  std::vector< sal_Int32 >& o_rPageVector,
     847             :                                                  sal_Int32 i_nMinNumber,
     848             :                                                  sal_Int32 i_nMaxNumber,
     849             :                                                  sal_Int32 i_nLogicalOffset,
     850             :                                                  std::set< sal_Int32 >* i_pPossibleValues
     851             :                                                )
     852             : {
     853           0 :     o_rPageVector.clear();
     854             : 
     855           0 :     StringRangeEnumerator aEnum( i_rPageRange, i_nMinNumber, i_nMaxNumber, i_nLogicalOffset ) ;
     856             : 
     857             :     //Even if the input range wasn't completely valid, return what ranges could
     858             :     //be extracted from the input.
     859           0 :     o_rPageVector.reserve( static_cast< size_t >( aEnum.size() ) );
     860           0 :     for( StringRangeEnumerator::Iterator it = aEnum.begin( i_pPossibleValues );
     861           0 :          it != aEnum.end( i_pPossibleValues ); ++it )
     862             :     {
     863           0 :         o_rPageVector.push_back( *it );
     864             :     }
     865             : 
     866           0 :     return aEnum.isValidInput();
     867             : }
     868             : 
     869             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10