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