1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #define _SV_MULTISEL_CXX 32 33 #ifdef MI_DEBUG 34 #define private public 35 #include <stdio.h> 36 #endif 37 38 #include <tools/debug.hxx> 39 #include <tools/multisel.hxx> 40 41 #include "rtl/ustrbuf.hxx" 42 43 #ifdef MI_DEBUG 44 #define DBG(x) x 45 #else 46 #define DBG(x) 47 #endif 48 49 using namespace rtl; 50 51 //================================================================== 52 53 #ifdef MI_DEBUG 54 55 static void Print( const MultiSelection* pSel ) 56 { 57 DbgOutf( "TotRange: %4ld-%4ld\n", 58 pSel->aTotRange.Min(), pSel->aTotRange.Max() ); 59 if ( pSel->bCurValid ) 60 { 61 DbgOutf( "CurSubSel: %4ld\n", pSel->nCurSubSel ); 62 DbgOutf( "CurIndex: %4ld\n", pSel->nCurIndex ); 63 } 64 DbgOutf( "SelCount: %4ld\n", pSel->nSelCount ); 65 DbgOutf( "SubCount: %4ld\n", pSel->aSels.Count() ); 66 for ( sal_uIntPtr nPos = 0; nPos < pSel->aSels.Count(); ++nPos ) 67 { 68 DbgOutf( "SubSel #%2ld: %4ld-%4ld\n", nPos, 69 pSel->aSels.GetObject(nPos)->Min(), 70 pSel->aSels.GetObject(nPos)->Max() ); 71 } 72 DbgOutf( "\n" ); 73 fclose( pFile ); 74 } 75 76 #endif 77 78 // ----------------------------------------------------------------------- 79 80 void MultiSelection::ImplClear() 81 { 82 // no selected indexes 83 nSelCount = 0; 84 85 Range* pRange = aSels.First(); 86 while ( pRange ) 87 { 88 delete pRange; 89 pRange = aSels.Next(); 90 } 91 aSels.Clear(); 92 } 93 94 // ----------------------------------------------------------------------- 95 96 sal_uIntPtr MultiSelection::ImplFindSubSelection( long nIndex ) const 97 { 98 // iterate through the sub selections 99 sal_uIntPtr n = 0; 100 for ( ; 101 n < aSels.Count() && nIndex > aSels.GetObject(n)->Max(); 102 ++n ) {} /* empty loop */ 103 return n; 104 } 105 106 // ----------------------------------------------------------------------- 107 108 sal_Bool MultiSelection::ImplMergeSubSelections( sal_uIntPtr nPos1, sal_uIntPtr nPos2 ) 109 { 110 // didn't a sub selection at nPos2 exist? 111 if ( nPos2 >= aSels.Count() ) 112 return sal_False; 113 114 // did the sub selections touch each other? 115 if ( (aSels.GetObject(nPos1)->Max() + 1) == aSels.GetObject(nPos2)->Min() ) 116 { 117 // merge them 118 aSels.GetObject(nPos1)->Max() = aSels.GetObject(nPos2)->Max(); 119 delete aSels.Remove(nPos2); 120 return sal_True; 121 } 122 123 return sal_False; 124 } 125 126 // ----------------------------------------------------------------------- 127 128 MultiSelection::MultiSelection(): 129 aTotRange( 0, -1 ), 130 nCurSubSel(0), 131 nSelCount(0), 132 bCurValid(sal_False), 133 bSelectNew(sal_False) 134 { 135 } 136 137 // ----------------------------------------------------------------------- 138 139 MultiSelection::MultiSelection( const UniString& rString, sal_Unicode cRange, sal_Unicode cSep ): 140 aTotRange(0,RANGE_MAX), 141 nCurSubSel(0), 142 nSelCount(0), 143 bCurValid(sal_False), 144 bSelectNew(sal_False) 145 { 146 // Dies ist nur ein Schnellschuss und sollte bald optimiert, 147 // an die verschiedenen Systeme (UNIX etc.) 148 // und die gewuenschte Eingabe-Syntax angepasst werden. 149 150 UniString aStr( rString ); 151 sal_Unicode* pStr = aStr.GetBufferAccess(); 152 sal_Unicode* pOld = pStr; 153 sal_Bool bReady = sal_False; 154 sal_Bool bUntil = sal_False; 155 xub_StrLen nCut = 0; 156 157 // Hier normieren wir den String, sodass nur Ziffern, 158 // Semikola als Trenn- und Minus als VonBis-Zeichen 159 // uebrigbleiben, z.B. "99-117;55;34;-17;37-43" 160 while ( *pOld ) 161 { 162 switch( *pOld ) 163 { 164 case '0': 165 case '1': 166 case '2': 167 case '3': 168 case '4': 169 case '5': 170 case '6': 171 case '7': 172 case '8': 173 case '9': 174 DBG_ASSERT( *pOld != cRange, "digit for range char not allowed" ); 175 DBG_ASSERT( *pOld != cSep, "digit for separator not allowed" ); 176 if( bReady ) 177 { 178 *pStr++ = ';'; 179 nCut++; 180 bReady = sal_False; 181 } 182 *pStr++ = *pOld; 183 nCut++; 184 bUntil = sal_False; 185 break; 186 187 case '-': 188 case ':': 189 case '/': 190 if ( *pOld != cSep ) 191 { 192 if ( !bUntil ) 193 { 194 *pStr++ = '-'; 195 nCut++; 196 bUntil = sal_True; 197 } 198 bReady = sal_False; 199 } 200 else 201 bReady = sal_True; 202 break; 203 204 case ' ': 205 DBG_ASSERT( *pOld != cRange, "SPACE for range char not allowed" ); 206 DBG_ASSERT( *pOld != cSep, "SPACE for separator not allowed" ); 207 bReady = !bUntil; 208 break; 209 210 default: 211 if ( *pOld == cRange ) 212 { 213 if ( !bUntil ) 214 { 215 *pStr++ = '-'; 216 nCut++; 217 bUntil = sal_True; 218 } 219 bReady = sal_False; 220 } 221 else 222 bReady = sal_True; 223 break; 224 } 225 226 pOld++; 227 } 228 aStr.ReleaseBufferAccess( nCut ); 229 230 // Jetzt wird der normierte String ausgewertet .. 231 UniString aNumStr; 232 Range aRg( 1, RANGE_MAX ); 233 const sal_Unicode* pCStr = aStr.GetBuffer(); 234 long nPage = 1; 235 long nNum = 1; 236 bUntil = sal_False; 237 while ( *pCStr ) 238 { 239 switch ( *pCStr ) 240 { 241 case '0': 242 case '1': 243 case '2': 244 case '3': 245 case '4': 246 case '5': 247 case '6': 248 case '7': 249 case '8': 250 case '9': 251 aNumStr += *pCStr; 252 break; 253 case ';': 254 nNum = aNumStr.ToInt32(); 255 if ( bUntil ) 256 { 257 if ( !aNumStr.Len() ) 258 nNum = RANGE_MAX; 259 aRg.Min() = nPage; 260 aRg.Max() = nNum; 261 aRg.Justify(); 262 Select( aRg ); 263 } 264 else 265 Select( nNum ); 266 nPage = 0; 267 aNumStr.Erase(); 268 bUntil = sal_False; 269 break; 270 271 case '-': 272 nPage = aNumStr.ToInt32(); 273 aNumStr.Erase(); 274 bUntil = sal_True; 275 break; 276 } 277 278 pCStr++; 279 } 280 281 nNum = aNumStr.ToInt32(); 282 if ( bUntil ) 283 { 284 if ( !aNumStr.Len() ) 285 nNum = RANGE_MAX; 286 aRg.Min() = nPage; 287 aRg.Max() = nNum; 288 aRg.Justify(); 289 Select( aRg ); 290 } 291 else 292 Select( nNum ); 293 } 294 295 // ----------------------------------------------------------------------- 296 297 MultiSelection::MultiSelection( const MultiSelection& rOrig ) : 298 aTotRange(rOrig.aTotRange), 299 nSelCount(rOrig.nSelCount), 300 bCurValid(rOrig.bCurValid), 301 bSelectNew(sal_False) 302 { 303 if ( bCurValid ) 304 { 305 nCurSubSel = rOrig.nCurSubSel; 306 nCurIndex = rOrig.nCurIndex; 307 } 308 309 // copy the sub selections 310 for ( sal_uIntPtr n = 0; n < rOrig.aSels.Count(); ++n ) 311 aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND ); 312 } 313 314 // ----------------------------------------------------------------------- 315 316 MultiSelection::MultiSelection( const Range& rRange ): 317 aTotRange(rRange), 318 nCurSubSel(0), 319 nSelCount(0), 320 bCurValid(sal_False), 321 bSelectNew(sal_False) 322 { 323 } 324 325 // ----------------------------------------------------------------------- 326 327 MultiSelection::~MultiSelection() 328 { 329 Range* pRange = aSels.First(); 330 while ( pRange ) 331 { 332 delete pRange; 333 pRange = aSels.Next(); 334 } 335 } 336 337 // ----------------------------------------------------------------------- 338 339 MultiSelection& MultiSelection::operator= ( const MultiSelection& rOrig ) 340 { 341 aTotRange = rOrig.aTotRange; 342 bCurValid = rOrig.bCurValid; 343 if ( bCurValid ) 344 { 345 nCurSubSel = rOrig.nCurSubSel; 346 nCurIndex = rOrig.nCurIndex; 347 } 348 349 // clear the old and copy the sub selections 350 ImplClear(); 351 for ( sal_uIntPtr n = 0; n < rOrig.aSels.Count(); ++n ) 352 aSels.Insert( new Range( *rOrig.aSels.GetObject(n) ), LIST_APPEND ); 353 nSelCount = rOrig.nSelCount; 354 355 return *this; 356 } 357 358 // ----------------------------------------------------------------------- 359 360 sal_Bool MultiSelection::operator== ( MultiSelection& rWith ) 361 { 362 if ( aTotRange != rWith.aTotRange || nSelCount != rWith.nSelCount || 363 aSels.Count() != rWith.aSels.Count() ) 364 return sal_False; 365 366 // compare the sub seletions 367 for ( sal_uIntPtr n = 0; n < aSels.Count(); ++n ) 368 if ( *aSels.GetObject(n) != *rWith.aSels.GetObject(n) ) 369 return sal_False; 370 return sal_True; 371 } 372 373 // ----------------------------------------------------------------------- 374 375 void MultiSelection::SelectAll( sal_Bool bSelect ) 376 { 377 DBG(DbgOutf( "::SelectAll(%s)\n", bSelect ? "sal_True" : "sal_False" )); 378 379 ImplClear(); 380 if ( bSelect ) 381 { 382 aSels.Insert( new Range(aTotRange), LIST_APPEND ); 383 nSelCount = aTotRange.Len(); 384 } 385 386 DBG(Print( this )); 387 } 388 389 // ----------------------------------------------------------------------- 390 391 sal_Bool MultiSelection::Select( long nIndex, sal_Bool bSelect ) 392 { 393 DBG_ASSERT( aTotRange.IsInside(nIndex), "selected index out of range" ); 394 395 // out of range? 396 if ( !aTotRange.IsInside(nIndex) ) 397 return sal_False; 398 399 // find the virtual target position 400 sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); 401 402 if ( bSelect ) 403 { 404 // is it included in the found sub selection? 405 if ( nSubSelPos < aSels.Count() && 406 aSels.GetObject(nSubSelPos)->IsInside( nIndex ) ) 407 // already selected, nothing to do 408 return sal_False; 409 410 // it will become selected 411 ++nSelCount; 412 413 // is it at the end of the previous sub selection 414 if ( nSubSelPos > 0 && 415 aSels.GetObject(nSubSelPos-1)->Max() == (nIndex-1) ) 416 { 417 // expand the previous sub selection 418 aSels.GetObject(nSubSelPos-1)->Max() = nIndex; 419 420 // try to merge the previous sub selection 421 ImplMergeSubSelections( nSubSelPos-1, nSubSelPos ); 422 } 423 // is is at the beginning of the found sub selection 424 else if ( nSubSelPos < aSels.Count() && 425 aSels.GetObject(nSubSelPos)->Min() == (nIndex+1) ) 426 // expand the found sub selection 427 aSels.GetObject(nSubSelPos)->Min() = nIndex; 428 else 429 { 430 // create a new sub selection 431 aSels.Insert( new Range( nIndex, nIndex ), nSubSelPos ); 432 if ( bCurValid && nCurSubSel >= nSubSelPos ) 433 ++nCurSubSel; 434 } 435 } 436 else 437 { 438 // is it excluded from the found sub selection? 439 if ( nSubSelPos >= aSels.Count() || 440 !aSels.GetObject(nSubSelPos)->IsInside( nIndex ) ) 441 { 442 // not selected, nothing to do 443 DBG(Print( this )); 444 return sal_False; 445 } 446 447 // it will become deselected 448 --nSelCount; 449 450 // is it the only index in the found sub selection? 451 if ( aSels.GetObject(nSubSelPos)->Len() == 1 ) 452 { 453 // remove the complete sub selection 454 delete aSels.Remove( nSubSelPos ); 455 DBG(Print( this )); 456 return sal_True; 457 } 458 459 // is it at the beginning of the found sub selection? 460 if ( aSels.GetObject(nSubSelPos)->Min() == nIndex ) 461 ++aSels.GetObject(nSubSelPos)->Min(); 462 // is it at the end of the found sub selection? 463 else if ( aSels.GetObject(nSubSelPos)->Max() == nIndex ) 464 --aSels.GetObject(nSubSelPos)->Max(); 465 // it is in the middle of the found sub selection? 466 else 467 { 468 // split the sub selection 469 aSels.Insert( 470 new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ), 471 nSubSelPos ); 472 aSels.GetObject(nSubSelPos+1)->Min() = nIndex + 1; 473 } 474 } 475 476 DBG(Print( this )); 477 478 return sal_True; 479 } 480 481 // ----------------------------------------------------------------------- 482 483 void MultiSelection::Select( const Range& rIndexRange, sal_Bool bSelect ) 484 { 485 Range* pRange; 486 long nOld; 487 488 sal_uIntPtr nTmpMin = rIndexRange.Min(); 489 sal_uIntPtr nTmpMax = rIndexRange.Max(); 490 sal_uIntPtr nCurMin = FirstSelected(); 491 sal_uIntPtr nCurMax = LastSelected(); 492 DBG_ASSERT(aTotRange.IsInside(nTmpMax), "selected index out of range" ); 493 DBG_ASSERT(aTotRange.IsInside(nTmpMin), "selected index out of range" ); 494 495 // gesamte Selektion ersetzen ? 496 if( nTmpMin <= nCurMin && nTmpMax >= nCurMax ) 497 { 498 ImplClear(); 499 if ( bSelect ) 500 { 501 aSels.Insert( new Range(rIndexRange), LIST_APPEND ); 502 nSelCount = rIndexRange.Len(); 503 } 504 return; 505 } 506 // links erweitern ? 507 if( nTmpMax < nCurMin ) 508 { 509 if( bSelect ) 510 { 511 // ersten Range erweitern ? 512 if( nCurMin > (nTmpMax+1) ) 513 { 514 pRange = new Range( rIndexRange ); 515 aSels.Insert( pRange, (sal_uIntPtr)0 ); 516 nSelCount += pRange->Len(); 517 } 518 else 519 { 520 pRange = aSels.First(); 521 nOld = pRange->Min(); 522 pRange->Min() = (long)nTmpMin; 523 nSelCount += ( nOld - nTmpMin ); 524 } 525 bCurValid = sal_False; 526 } 527 return; 528 } 529 // rechts erweitern ? 530 else if( nTmpMin > nCurMax ) 531 { 532 if( bSelect ) 533 { 534 // letzten Range erweitern ? 535 if( nTmpMin > (nCurMax+1) ) 536 { 537 pRange = new Range( rIndexRange ); 538 aSels.Insert( pRange, LIST_APPEND ); 539 nSelCount += pRange->Len(); 540 } 541 else 542 { 543 pRange = aSels.Last(); 544 nOld = pRange->Max(); 545 pRange->Max() = (long)nTmpMax; 546 nSelCount += ( nTmpMax - nOld ); 547 } 548 bCurValid = sal_False; 549 } 550 return; 551 } 552 553 //HACK(Hier muss noch optimiert werden) 554 while( nTmpMin <= nTmpMax ) 555 { 556 Select( nTmpMin, bSelect ); 557 nTmpMin++; 558 } 559 } 560 561 // ----------------------------------------------------------------------- 562 563 sal_Bool MultiSelection::IsSelected( long nIndex ) const 564 { 565 // find the virtual target position 566 sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); 567 568 return nSubSelPos < aSels.Count() && 569 aSels.GetObject(nSubSelPos)->IsInside(nIndex); 570 } 571 572 // ----------------------------------------------------------------------- 573 574 void MultiSelection::Insert( long nIndex, long nCount ) 575 { 576 DBG(DbgOutf( "::Insert(%ld, %ld)\n", nIndex, nCount )); 577 578 // find the virtual target position 579 sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); 580 581 // did we need to shift the sub selections? 582 if ( nSubSelPos < aSels.Count() ) 583 { 584 // did we insert an unselected into an existing sub selection? 585 if ( !bSelectNew && aSels.GetObject(nSubSelPos)->Min() != nIndex && 586 aSels.GetObject(nSubSelPos)->IsInside(nIndex) ) 587 { 588 // split the sub selection 589 aSels.Insert( 590 new Range( aSels.GetObject(nSubSelPos)->Min(), nIndex-1 ), 591 nSubSelPos ); 592 ++nSubSelPos; 593 aSels.GetObject(nSubSelPos)->Min() = nIndex; 594 } 595 596 // did we append an selected to an existing sub selection? 597 else if ( bSelectNew && nSubSelPos > 0 && 598 aSels.GetObject(nSubSelPos)->Max() == nIndex-1 ) 599 // expand the previous sub selection 600 aSels.GetObject(nSubSelPos-1)->Max() += nCount; 601 602 // did we insert an selected into an existing sub selection? 603 else if ( bSelectNew && aSels.GetObject(nSubSelPos)->Min() == nIndex ) 604 { 605 // expand the sub selection 606 aSels.GetObject(nSubSelPos)->Max() += nCount; 607 ++nSubSelPos; 608 } 609 610 // shift the sub selections behind the inserting position 611 for ( sal_uIntPtr nPos = nSubSelPos; nPos < aSels.Count(); ++nPos ) 612 { 613 aSels.GetObject(nPos)->Min() += nCount; 614 aSels.GetObject(nPos)->Max() += nCount; 615 } 616 } 617 618 bCurValid = sal_False; 619 aTotRange.Max() += nCount; 620 if ( bSelectNew ) 621 nSelCount += nCount; 622 623 DBG(Print( this )); 624 } 625 626 // ----------------------------------------------------------------------- 627 628 void MultiSelection::Remove( long nIndex ) 629 { 630 DBG(DbgOutf( "::Remove(%ld)\n", nIndex )); 631 632 // find the virtual target position 633 sal_uIntPtr nSubSelPos = ImplFindSubSelection( nIndex ); 634 635 // did we remove from an existing sub selection? 636 if ( nSubSelPos < aSels.Count() && 637 aSels.GetObject(nSubSelPos)->IsInside(nIndex) ) 638 { 639 // does this sub selection only contain the index to be deleted 640 if ( aSels.GetObject(nSubSelPos)->Len() == 1 ) 641 // completely remove the sub selection 642 aSels.Remove(nSubSelPos); 643 else 644 // shorten this sub selection 645 --( aSels.GetObject(nSubSelPos++)->Max() ); 646 647 // adjust the selected counter 648 --nSelCount; 649 } 650 651 // shift the sub selections behind the removed index 652 for ( sal_uIntPtr nPos = nSubSelPos; nPos < aSels.Count(); ++nPos ) 653 { 654 --( aSels.GetObject(nPos)->Min() ); 655 --( aSels.GetObject(nPos)->Max() ); 656 } 657 658 bCurValid = sal_False; 659 aTotRange.Max() -= 1; 660 661 DBG(Print( this )); 662 } 663 664 // ----------------------------------------------------------------------- 665 666 void MultiSelection::Append( long nCount ) 667 { 668 long nPrevLast = aTotRange.Max(); 669 aTotRange.Max() += nCount; 670 if ( bSelectNew ) 671 { 672 nSelCount += nCount; 673 aSels.Insert( new Range( nPrevLast+1, nPrevLast + nCount ), 674 LIST_APPEND ); 675 if ( aSels.Count() > 1 ) 676 ImplMergeSubSelections( aSels.Count() - 2, aSels.Count() ); 677 } 678 } 679 680 // ----------------------------------------------------------------------- 681 682 long MultiSelection::ImplFwdUnselected() 683 { 684 if ( !bCurValid ) 685 return SFX_ENDOFSELECTION; 686 687 if ( ( nCurSubSel < aSels.Count() ) && 688 ( aSels.GetObject(nCurSubSel)->Min() <= nCurIndex ) ) 689 nCurIndex = aSels.GetObject(nCurSubSel++)->Max() + 1; 690 691 if ( nCurIndex <= aTotRange.Max() ) 692 return nCurIndex; 693 else 694 return SFX_ENDOFSELECTION; 695 } 696 697 // ----------------------------------------------------------------------- 698 699 long MultiSelection::ImplBwdUnselected() 700 { 701 if ( !bCurValid ) 702 return SFX_ENDOFSELECTION; 703 704 if ( aSels.GetObject(nCurSubSel)->Max() < nCurIndex ) 705 return nCurIndex; 706 707 nCurIndex = aSels.GetObject(nCurSubSel--)->Min() - 1; 708 if ( nCurIndex >= 0 ) 709 return nCurIndex; 710 else 711 return SFX_ENDOFSELECTION; 712 } 713 714 // ----------------------------------------------------------------------- 715 716 long MultiSelection::FirstSelected( sal_Bool bInverse ) 717 { 718 bInverseCur = bInverse; 719 nCurSubSel = 0; 720 721 if ( bInverseCur ) 722 { 723 bCurValid = nSelCount < sal_uIntPtr(aTotRange.Len()); 724 if ( bCurValid ) 725 { 726 nCurIndex = 0; 727 return ImplFwdUnselected(); 728 } 729 } 730 else 731 { 732 bCurValid = aSels.Count() > 0; 733 if ( bCurValid ) 734 return nCurIndex = aSels.GetObject(0)->Min(); 735 } 736 737 return SFX_ENDOFSELECTION; 738 } 739 740 // ----------------------------------------------------------------------- 741 742 long MultiSelection::LastSelected() 743 { 744 nCurSubSel = aSels.Count() - 1; 745 bCurValid = aSels.Count() > 0; 746 747 if ( bCurValid ) 748 return nCurIndex = aSels.GetObject(nCurSubSel)->Max(); 749 750 return SFX_ENDOFSELECTION; 751 } 752 753 // ----------------------------------------------------------------------- 754 755 long MultiSelection::NextSelected() 756 { 757 if ( !bCurValid ) 758 return SFX_ENDOFSELECTION; 759 760 if ( bInverseCur ) 761 { 762 ++nCurIndex; 763 return ImplFwdUnselected(); 764 } 765 else 766 { 767 // is the next index in the current sub selection too? 768 if ( nCurIndex < aSels.GetObject(nCurSubSel)->Max() ) 769 return ++nCurIndex; 770 771 // are there further sub selections? 772 if ( ++nCurSubSel < aSels.Count() ) 773 return nCurIndex = aSels.GetObject(nCurSubSel)->Min(); 774 775 // we are at the end! 776 return SFX_ENDOFSELECTION; 777 } 778 } 779 780 // ----------------------------------------------------------------------- 781 782 long MultiSelection::PrevSelected() 783 { 784 if ( !bCurValid ) 785 return SFX_ENDOFSELECTION; 786 787 if ( bInverseCur ) 788 { 789 --nCurIndex; 790 return ImplBwdUnselected(); 791 } 792 else 793 { 794 // is the previous index in the current sub selection too? 795 if ( nCurIndex > aSels.GetObject(nCurSubSel)->Min() ) 796 return --nCurIndex; 797 798 // are there previous sub selections? 799 if ( nCurSubSel > 0 ) 800 { 801 --nCurSubSel; 802 return nCurIndex = aSels.GetObject(nCurSubSel)->Max(); 803 } 804 805 // we are at the beginning! 806 return SFX_ENDOFSELECTION; 807 } 808 } 809 810 // ----------------------------------------------------------------------- 811 812 void MultiSelection::SetTotalRange( const Range& rTotRange ) 813 { 814 aTotRange = rTotRange; 815 816 // die untere Bereichsgrenze anpassen 817 Range* pRange = aSels.GetObject( 0 ); 818 while( pRange ) 819 { 820 if( pRange->Max() < aTotRange.Min() ) 821 { 822 delete pRange; 823 aSels.Remove( (sal_uIntPtr)0 ); 824 } 825 else if( pRange->Min() < aTotRange.Min() ) 826 { 827 pRange->Min() = aTotRange.Min(); 828 break; 829 } 830 else 831 break; 832 833 pRange = aSels.GetObject( 0 ); 834 } 835 836 // die obere Bereichsgrenze anpassen 837 sal_uIntPtr nCount = aSels.Count(); 838 while( nCount ) 839 { 840 pRange = aSels.GetObject( nCount - 1 ); 841 if( pRange->Min() > aTotRange.Max() ) 842 { 843 delete pRange; 844 aSels.Remove( (sal_uIntPtr)(nCount - 1) ); 845 } 846 else if( pRange->Max() > aTotRange.Max() ) 847 { 848 pRange->Max() = aTotRange.Max(); 849 break; 850 } 851 else 852 break; 853 854 nCount = aSels.Count(); 855 } 856 857 // Selection-Count neu berechnen 858 nSelCount = 0; 859 pRange = aSels.First(); 860 while( pRange ) 861 { 862 nSelCount += pRange->Len(); 863 pRange = aSels.Next(); 864 } 865 866 bCurValid = sal_False; 867 nCurIndex = 0; 868 } 869 870 // ----------------------------------------------------------------------- 871 // 872 // StringRangeEnumerator 873 // 874 // ----------------------------------------------------------------------- 875 StringRangeEnumerator::StringRangeEnumerator( const rtl::OUString& i_rInput, 876 sal_Int32 i_nMinNumber, 877 sal_Int32 i_nMaxNumber, 878 sal_Int32 i_nLogicalOffset 879 ) 880 : mnCount( 0 ) 881 , mnMin( i_nMinNumber ) 882 , mnMax( i_nMaxNumber ) 883 , mnOffset( i_nLogicalOffset ) 884 { 885 setRange( i_rInput ); 886 } 887 888 bool StringRangeEnumerator::checkValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const 889 { 890 if( mnMin >= 0 && i_nValue < mnMin ) 891 return false; 892 if( mnMax >= 0 && i_nValue > mnMax ) 893 return false; 894 if( i_nValue < 0 ) 895 return false; 896 if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) 897 return false; 898 return true; 899 } 900 901 bool StringRangeEnumerator::insertRange( sal_Int32 i_nFirst, sal_Int32 i_nLast, bool bSequence, bool bMayAdjust ) 902 { 903 bool bSuccess = true; 904 if( bSequence ) 905 { 906 if( i_nFirst == -1 ) 907 i_nFirst = mnMin; 908 if( i_nLast == -1 ) 909 i_nLast = mnMax; 910 if( bMayAdjust ) 911 { 912 if( i_nFirst < mnMin ) 913 i_nFirst = mnMin; 914 if( i_nFirst > mnMax ) 915 i_nFirst = mnMax; 916 if( i_nLast < mnMin ) 917 i_nLast = mnMin; 918 if( i_nLast > mnMax ) 919 i_nLast = mnMax; 920 } 921 if( checkValue( i_nFirst ) && checkValue( i_nLast ) ) 922 { 923 maSequence.push_back( Range( i_nFirst, i_nLast ) ); 924 sal_Int32 nNumber = i_nLast - i_nFirst; 925 nNumber = nNumber < 0 ? -nNumber : nNumber; 926 mnCount += nNumber + 1; 927 } 928 else 929 bSuccess = false; 930 } 931 else 932 { 933 if( i_nFirst >= 0 ) 934 { 935 if( checkValue( i_nFirst ) ) 936 { 937 maSequence.push_back( Range( i_nFirst, i_nFirst ) ); 938 mnCount++; 939 } 940 else 941 bSuccess = false; 942 } 943 if( i_nLast >= 0 ) 944 { 945 if( checkValue( i_nLast ) ) 946 { 947 maSequence.push_back( Range( i_nLast, i_nLast ) ); 948 mnCount++; 949 } 950 else 951 bSuccess = false; 952 } 953 } 954 955 return bSuccess; 956 } 957 958 bool StringRangeEnumerator::setRange( const rtl::OUString& i_rNewRange, bool i_bStrict ) 959 { 960 mnCount = 0; 961 maSequence.clear(); 962 963 // we love special cases 964 if( i_rNewRange.getLength() == 0 ) 965 { 966 if( mnMin >= 0 && mnMax >= 0 ) 967 { 968 insertRange( mnMin, mnMax, mnMin != mnMax, ! i_bStrict ); 969 } 970 return true; 971 } 972 973 const sal_Unicode* pInput = i_rNewRange.getStr(); 974 rtl::OUStringBuffer aNumberBuf( 16 ); 975 sal_Int32 nLastNumber = -1, nNumber = -1; 976 bool bSequence = false; 977 bool bSuccess = true; 978 while( *pInput ) 979 { 980 while( *pInput >= sal_Unicode('0') && *pInput <= sal_Unicode('9') ) 981 aNumberBuf.append( *pInput++ ); 982 if( aNumberBuf.getLength() ) 983 { 984 if( nNumber != -1 ) 985 { 986 if( bSequence ) 987 { 988 if( ! insertRange( nLastNumber, nNumber, true, ! i_bStrict ) && i_bStrict ) 989 { 990 bSuccess = false; 991 break; 992 } 993 nLastNumber = -1; 994 } 995 else 996 { 997 if( ! insertRange( nNumber, nNumber, false, ! i_bStrict ) && i_bStrict ) 998 { 999 bSuccess = false; 1000 break; 1001 } 1002 } 1003 } 1004 nNumber = aNumberBuf.makeStringAndClear().toInt32(); 1005 nNumber += mnOffset; 1006 } 1007 bool bInsertRange = false; 1008 if( *pInput == sal_Unicode('-') ) 1009 { 1010 nLastNumber = nNumber; 1011 nNumber = -1; 1012 bSequence = true; 1013 } 1014 else if( *pInput == ' ' ) 1015 { 1016 } 1017 else if( *pInput == sal_Unicode(',') || *pInput == sal_Unicode(';') ) 1018 bInsertRange = true; 1019 else if( *pInput ) 1020 { 1021 1022 bSuccess = false; 1023 break; // parse error 1024 } 1025 1026 if( bInsertRange ) 1027 { 1028 if( ! insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ) && i_bStrict ) 1029 { 1030 bSuccess = false; 1031 break; 1032 } 1033 nNumber = nLastNumber = -1; 1034 bSequence = false; 1035 } 1036 if( *pInput ) 1037 pInput++; 1038 } 1039 // insert last entries 1040 insertRange( nLastNumber, nNumber, bSequence, ! i_bStrict ); 1041 1042 return bSuccess; 1043 } 1044 1045 bool StringRangeEnumerator::hasValue( sal_Int32 i_nValue, const std::set< sal_Int32 >* i_pPossibleValues ) const 1046 { 1047 if( i_pPossibleValues && i_pPossibleValues->find( i_nValue ) == i_pPossibleValues->end() ) 1048 return false; 1049 size_t n = maSequence.size(); 1050 for( size_t i= 0; i < n; ++i ) 1051 { 1052 const StringRangeEnumerator::Range rRange( maSequence[i] ); 1053 if( rRange.nFirst < rRange.nLast ) 1054 { 1055 if( i_nValue >= rRange.nFirst && i_nValue <= rRange.nLast ) 1056 return true; 1057 } 1058 else 1059 { 1060 if( i_nValue >= rRange.nLast && i_nValue <= rRange.nFirst ) 1061 return true; 1062 } 1063 } 1064 return false; 1065 } 1066 1067 StringRangeEnumerator::Iterator& StringRangeEnumerator::Iterator::operator++() 1068 { 1069 if( nRangeIndex >= 0 && nCurrent >= 0 && pEnumerator ) 1070 { 1071 const StringRangeEnumerator::Range& rRange( pEnumerator->maSequence[nRangeIndex] ); 1072 bool bRangeChange = false; 1073 if( rRange.nLast < rRange.nFirst ) 1074 { 1075 // backward range 1076 if( nCurrent > rRange.nLast ) 1077 nCurrent--; 1078 else 1079 bRangeChange = true; 1080 } 1081 else 1082 { 1083 // forward range 1084 if( nCurrent < rRange.nLast ) 1085 nCurrent++; 1086 else 1087 bRangeChange = true; 1088 } 1089 if( bRangeChange ) 1090 { 1091 nRangeIndex++; 1092 if( size_t(nRangeIndex) == pEnumerator->maSequence.size() ) 1093 { 1094 // reached the end 1095 nRangeIndex = nCurrent = -1; 1096 } 1097 else 1098 nCurrent = pEnumerator->maSequence[nRangeIndex].nFirst; 1099 } 1100 if( nRangeIndex != -1 && nCurrent != -1 ) 1101 { 1102 if( ! pEnumerator->checkValue( nCurrent, pPossibleValues ) ) 1103 return ++(*this); 1104 } 1105 } 1106 return *this; 1107 } 1108 1109 sal_Int32 StringRangeEnumerator::Iterator::operator*() const 1110 { 1111 return nCurrent; 1112 } 1113 1114 bool StringRangeEnumerator::Iterator::operator==( const Iterator& i_rCompare ) const 1115 { 1116 return i_rCompare.pEnumerator == pEnumerator && i_rCompare.nRangeIndex == nRangeIndex && i_rCompare.nCurrent == nCurrent; 1117 } 1118 1119 StringRangeEnumerator::Iterator StringRangeEnumerator::begin( const std::set< sal_Int32 >* i_pPossibleValues ) const 1120 { 1121 StringRangeEnumerator::Iterator it( this, 1122 i_pPossibleValues, 1123 maSequence.empty() ? -1 : 0, 1124 maSequence.empty() ? -1 : maSequence[0].nFirst ); 1125 if( ! checkValue(*it, i_pPossibleValues ) ) 1126 ++it; 1127 return it; 1128 } 1129 1130 StringRangeEnumerator::Iterator StringRangeEnumerator::end( const std::set< sal_Int32 >* i_pPossibleValues ) const 1131 { 1132 return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 ); 1133 } 1134 1135 bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange, 1136 std::vector< sal_Int32 >& o_rPageVector, 1137 sal_Int32 i_nMinNumber, 1138 sal_Int32 i_nMaxNumber, 1139 sal_Int32 i_nLogicalOffset, 1140 std::set< sal_Int32 >* i_pPossibleValues 1141 ) 1142 { 1143 StringRangeEnumerator aEnum; 1144 aEnum.setMin( i_nMinNumber ); 1145 aEnum.setMax( i_nMaxNumber ); 1146 aEnum.setLogicalOffset( i_nLogicalOffset ); 1147 1148 bool bRes = aEnum.setRange( i_rPageRange ); 1149 if( bRes ) 1150 { 1151 o_rPageVector.clear(); 1152 o_rPageVector.reserve( aEnum.size() ); 1153 for( StringRangeEnumerator::Iterator it = aEnum.begin( i_pPossibleValues ); 1154 it != aEnum.end( i_pPossibleValues ); ++it ) 1155 { 1156 o_rPageVector.push_back( *it ); 1157 } 1158 } 1159 1160 return bRes; 1161 } 1162 1163