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