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