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: */
|