Branch data 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 : 336 : void MultiSelection::ImplClear()
63 : : {
64 : : // no selected indexes
65 : 336 : nSelCount = 0;
66 : :
67 [ - + ]: 336 : for ( size_t i = 0, n = aSels.size(); i < n; ++i ) {
68 : 0 : delete aSels[ i ];
69 : : }
70 : 336 : aSels.clear();
71 : 336 : }
72 : :
73 : 3379 : size_t MultiSelection::ImplFindSubSelection( long nIndex ) const
74 : : {
75 : : // iterate through the sub selections
76 : 3379 : size_t n = 0;
77 [ + + + + ]: 7190 : for ( ;
[ + + ]
78 : 3811 : n < aSels.size() && nIndex > aSels[ n ]->Max();
79 : : ++n ) {} /* empty loop */
80 : 3379 : return n;
81 : : }
82 : :
83 : 10 : sal_Bool MultiSelection::ImplMergeSubSelections( size_t nPos1, size_t nPos2 )
84 : : {
85 : : // didn't a sub selection at nPos2 exist?
86 [ - + ]: 10 : if ( nPos2 >= aSels.size() )
87 : 0 : return sal_False;
88 : :
89 : : // did the sub selections touch each other?
90 [ + - ]: 10 : if ( (aSels[ nPos1 ]->Max() + 1) == aSels[ nPos2 ]->Min() )
91 : : {
92 : : // merge them
93 : 10 : aSels[ nPos1 ]->Max() = aSels[ nPos2 ]->Max();
94 : 10 : ImpSelList::iterator it = aSels.begin();
95 [ + - ]: 10 : ::std::advance( it, nPos2 );
96 : 10 : delete *it;
97 [ + - ]: 10 : aSels.erase( it );
98 : 10 : return sal_True;
99 : : }
100 : :
101 : 10 : return sal_False;
102 : : }
103 : :
104 : 80 : MultiSelection::MultiSelection():
105 : : aTotRange( 0, -1 ),
106 : : nCurSubSel(0),
107 : : nSelCount(0),
108 : : bCurValid(sal_False),
109 : 80 : bSelectNew(sal_False)
110 : : {
111 : 80 : }
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 : 38016 : MultiSelection::MultiSelection( const Range& rRange ):
131 : : aTotRange(rRange),
132 : : nCurSubSel(0),
133 : : nSelCount(0),
134 : : bCurValid(sal_False),
135 : 38016 : bSelectNew(sal_False)
136 : : {
137 : 38016 : }
138 : :
139 : 38096 : MultiSelection::~MultiSelection()
140 : : {
141 [ + + ]: 38788 : for ( size_t i = 0, n = aSels.size(); i < n; ++i )
142 : 692 : delete aSels[ i ];
143 : 38096 : aSels.clear();
144 : 38096 : }
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 : 336 : void MultiSelection::SelectAll( sal_Bool bSelect )
179 : : {
180 : : DBG(DbgOutf( "::SelectAll(%s)\n", bSelect ? "sal_True" : "sal_False" ));
181 : :
182 : 336 : ImplClear();
183 [ + + ]: 336 : if ( bSelect )
184 : : {
185 [ + - ]: 294 : aSels.push_back( new Range(aTotRange) );
186 : 294 : nSelCount = aTotRange.Len();
187 : : }
188 : :
189 : : DBG(Print( this ));
190 : 336 : }
191 : :
192 : 50 : 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 [ - + ]: 50 : if ( !aTotRange.IsInside(nIndex) )
198 : 0 : return sal_False;
199 : :
200 : : // find the virtual target position
201 : 50 : size_t nSubSelPos = ImplFindSubSelection( nIndex );
202 : :
203 [ + - ]: 50 : if ( bSelect )
204 : : {
205 : : // is it included in the found sub selection?
206 [ + - ][ + + ]: 50 : if ( nSubSelPos < aSels.size() && aSels[ nSubSelPos ]->IsInside( nIndex ) )
[ + + ]
207 : : // already selected, nothing to do
208 : 30 : return sal_False;
209 : :
210 : : // it will become selected
211 : 20 : ++nSelCount;
212 : :
213 : : // is it at the end of the previous sub selection
214 [ + + + - ]: 30 : if ( nSubSelPos > 0 &&
[ + + ]
215 : 10 : aSels[ nSubSelPos-1 ]->Max() == (nIndex-1) )
216 : : {
217 : : // expand the previous sub selection
218 : 10 : aSels[ nSubSelPos-1 ]->Max() = nIndex;
219 : :
220 : : // try to merge the previous sub selection
221 : 10 : ImplMergeSubSelections( nSubSelPos-1, nSubSelPos );
222 : : }
223 : : // is is at the beginning of the found sub selection
224 [ + - - + ]: 20 : else if ( nSubSelPos < aSels.size()
[ - + ]
225 : 10 : && 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 [ + - ]: 10 : if ( nSubSelPos < aSels.size() ) {
233 : 10 : ImpSelList::iterator it = aSels.begin();
234 [ + - ]: 10 : ::std::advance( it, nSubSelPos );
235 [ + - ][ + - ]: 10 : aSels.insert( it, new Range( nIndex, nIndex ) );
236 : : } else {
237 [ # # ]: 0 : aSels.push_back( new Range( nIndex, nIndex ) );
238 : : }
239 [ + - ][ + - ]: 10 : if ( bCurValid && nCurSubSel >= nSubSelPos )
240 : 10 : ++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 : 50 : return sal_True;
293 : : }
294 : :
295 : 654 : void MultiSelection::Select( const Range& rIndexRange, sal_Bool bSelect )
296 : : {
297 : : Range* pRange;
298 : : long nOld;
299 : :
300 : 654 : sal_uIntPtr nTmpMin = rIndexRange.Min();
301 : 654 : sal_uIntPtr nTmpMax = rIndexRange.Max();
302 [ + - ]: 654 : sal_uIntPtr nCurMin = FirstSelected();
303 [ + - ]: 654 : 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 [ + + ][ - + ]: 654 : if( nTmpMin <= nCurMin && nTmpMax >= nCurMax )
309 : : {
310 [ # # ]: 0 : ImplClear();
311 [ # # ]: 0 : if ( bSelect )
312 : : {
313 [ # # ][ # # ]: 0 : aSels.push_back( new Range(rIndexRange) );
314 : 0 : nSelCount = rIndexRange.Len();
315 : : }
316 : : return;
317 : : }
318 : : // expand on left side?
319 [ + + ]: 654 : if( nTmpMax < nCurMin )
320 : : {
321 [ + - ]: 310 : if( bSelect )
322 : : {
323 : : // extend first range?
324 [ + - ]: 310 : if( nCurMin > (nTmpMax+1) )
325 : : {
326 [ + - ]: 310 : pRange = new Range( rIndexRange );
327 [ + - ]: 310 : aSels.insert( aSels.begin() , pRange );
328 : 310 : 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 : 310 : bCurValid = sal_False;
338 : : }
339 : : return;
340 : : }
341 : : // expand on right side?
342 [ + + ]: 344 : else if( nTmpMin > nCurMax )
343 : : {
344 [ + - ]: 334 : if( bSelect )
345 : : {
346 : : // extend last range?
347 [ + + ]: 334 : if( nTmpMin > (nCurMax+1) )
348 : : {
349 [ + - ]: 88 : pRange = new Range( rIndexRange );
350 [ + - ]: 88 : aSels.push_back( pRange );
351 : 88 : nSelCount += pRange->Len();
352 : : }
353 : : else
354 : : {
355 [ + - ]: 246 : pRange = aSels.back();
356 : 246 : nOld = pRange->Max();
357 : 246 : pRange->Max() = (long)nTmpMax;
358 : 246 : nSelCount += ( nTmpMax - nOld );
359 : : }
360 : 334 : bCurValid = sal_False;
361 : : }
362 : : return;
363 : : }
364 : :
365 : : // TODO here is potential for optimization
366 [ + + ]: 704 : while( nTmpMin <= nTmpMax )
367 : : {
368 [ + - ]: 50 : Select( nTmpMin, bSelect );
369 : 50 : nTmpMin++;
370 : : }
371 : : }
372 : :
373 : 3079 : sal_Bool MultiSelection::IsSelected( long nIndex ) const
374 : : {
375 : : // find the virtual target position
376 : 3079 : size_t nSubSelPos = ImplFindSubSelection( nIndex );
377 : :
378 [ + - ][ + + ]: 3079 : return nSubSelPos < aSels.size() && aSels[ nSubSelPos ]->IsInside(nIndex);
379 : : }
380 : :
381 : 206 : 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 : 206 : size_t nSubSelPos = ImplFindSubSelection( nIndex );
387 : :
388 : : // did we need to shift the sub selections?
389 [ - + ]: 206 : 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 : 206 : bCurValid = sal_False;
430 : 206 : aTotRange.Max() += nCount;
431 [ - + ]: 206 : if ( bSelectNew )
432 : 0 : nSelCount += nCount;
433 : :
434 : : DBG(Print( this ));
435 : 206 : }
436 : :
437 : 44 : void MultiSelection::Remove( long nIndex )
438 : : {
439 : : DBG(DbgOutf( "::Remove(%ld)\n", nIndex ));
440 : :
441 : : // find the virtual target position
442 : 44 : size_t nSubSelPos = ImplFindSubSelection( nIndex );
443 : :
444 : : // did we remove from an existing sub selection?
445 [ - + ]: 44 : 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 [ - + ]: 44 : for ( size_t nPos = nSubSelPos; nPos < aSels.size(); ++nPos )
466 : : {
467 : 0 : --( aSels[ nPos ]->Min() );
468 : 0 : --( aSels[ nPos ]->Max() );
469 : : }
470 : :
471 : 44 : bCurValid = sal_False;
472 : 44 : aTotRange.Max() -= 1;
473 : :
474 : : DBG(Print( this ));
475 : 44 : }
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 : 734 : long MultiSelection::FirstSelected( sal_Bool bInverse )
494 : : {
495 : 734 : bInverseCur = bInverse;
496 : 734 : nCurSubSel = 0;
497 : :
498 [ - + ]: 734 : 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 : 734 : bCurValid = !aSels.empty();
510 [ + + ]: 734 : if ( bCurValid )
511 : 344 : return nCurIndex = aSels[ 0 ]->Min();
512 : : }
513 : :
514 : 734 : return SFX_ENDOFSELECTION;
515 : : }
516 : :
517 : 654 : long MultiSelection::LastSelected()
518 : : {
519 : 654 : nCurSubSel = aSels.size() - 1;
520 : 654 : bCurValid = !aSels.empty();
521 : :
522 [ + + ]: 654 : if ( bCurValid )
523 : 344 : return nCurIndex = aSels[ nCurSubSel ]->Max();
524 : :
525 : 654 : 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 : 333 : void MultiSelection::SetTotalRange( const Range& rTotRange )
554 : : {
555 : 333 : aTotRange = rTotRange;
556 : :
557 : : // adjust lower boundary
558 [ + - ]: 333 : Range* pRange = aSels.empty() ? NULL : aSels.front();
559 [ - + ]: 333 : 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 : 333 : size_t nCount = aSels.size();
579 [ - + ]: 333 : 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 : 333 : nSelCount = 0;
600 [ - + ]: 333 : for ( size_t i = 0, n = aSels.size(); i < n; ++ i ) {
601 : 0 : nSelCount += pRange->Len();
602 : : }
603 : :
604 : 333 : bCurValid = sal_False;
605 : 333 : nCurIndex = 0;
606 : 333 : }
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: */
|