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_sc.hxx" 30 31 32 33 // INCLUDE --------------------------------------------------------------- 34 35 #include <tools/debug.hxx> 36 37 #include "markdata.hxx" 38 #include "markarr.hxx" 39 #include "rangelst.hxx" 40 41 // STATIC DATA ----------------------------------------------------------- 42 43 //------------------------------------------------------------------------ 44 45 ScMarkData::ScMarkData() : 46 pMultiSel( NULL ) 47 { 48 for (SCTAB i=0; i<=MAXTAB; i++) 49 bTabMarked[i] = sal_False; 50 51 ResetMark(); 52 } 53 54 ScMarkData::ScMarkData(const ScMarkData& rData) : 55 aMarkRange( rData.aMarkRange ), 56 aMultiRange( rData.aMultiRange ), 57 pMultiSel( NULL ) 58 { 59 bMarked = rData.bMarked; 60 bMultiMarked = rData.bMultiMarked; 61 bMarking = rData.bMarking; 62 bMarkIsNeg = rData.bMarkIsNeg; 63 64 for (SCTAB i=0; i<=MAXTAB; i++) 65 bTabMarked[i] = rData.bTabMarked[i]; 66 67 if (rData.pMultiSel) 68 { 69 pMultiSel = new ScMarkArray[MAXCOLCOUNT]; 70 for (SCCOL j=0; j<MAXCOLCOUNT; j++) 71 rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] ); 72 } 73 } 74 75 ScMarkData& ScMarkData::operator=(const ScMarkData& rData) 76 { 77 if ( &rData == this ) 78 return *this; 79 80 delete[] pMultiSel; 81 pMultiSel = NULL; 82 83 aMarkRange = rData.aMarkRange; 84 aMultiRange = rData.aMultiRange; 85 bMarked = rData.bMarked; 86 bMultiMarked = rData.bMultiMarked; 87 bMarking = rData.bMarking; 88 bMarkIsNeg = rData.bMarkIsNeg; 89 90 for (SCTAB i=0; i<=MAXTAB; i++) 91 bTabMarked[i] = rData.bTabMarked[i]; 92 93 if (rData.pMultiSel) 94 { 95 pMultiSel = new ScMarkArray[MAXCOLCOUNT]; 96 for (SCCOL j=0; j<MAXCOLCOUNT; j++) 97 rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] ); 98 } 99 100 return *this; 101 } 102 103 ScMarkData::~ScMarkData() 104 { 105 delete[] pMultiSel; 106 } 107 108 void ScMarkData::ResetMark() 109 { 110 delete[] pMultiSel; 111 pMultiSel = NULL; 112 113 bMarked = bMultiMarked = sal_False; 114 bMarking = bMarkIsNeg = sal_False; 115 } 116 117 void ScMarkData::SetMarkArea( const ScRange& rRange ) 118 { 119 aMarkRange = rRange; 120 aMarkRange.Justify(); 121 if ( !bMarked ) 122 { 123 // #77987# Upon creation of a document ScFormatShell GetTextAttrState 124 // may query (default) attributes although no sheet is marked yet. 125 // => mark that one. 126 if ( !GetSelectCount() ) 127 bTabMarked[ aMarkRange.aStart.Tab() ] = sal_True; 128 bMarked = sal_True; 129 } 130 } 131 132 void ScMarkData::GetMarkArea( ScRange& rRange ) const 133 { 134 rRange = aMarkRange; //! inline ? 135 } 136 137 void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const 138 { 139 rRange = aMultiRange; 140 } 141 142 void ScMarkData::SetMultiMarkArea( const ScRange& rRange, sal_Bool bMark ) 143 { 144 if (!pMultiSel) 145 { 146 pMultiSel = new ScMarkArray[MAXCOL+1]; 147 148 // if simple mark range is set, copy to multi marks 149 if ( bMarked && !bMarkIsNeg ) 150 { 151 bMarked = sal_False; 152 SetMultiMarkArea( aMarkRange, sal_True ); 153 } 154 } 155 156 SCCOL nStartCol = rRange.aStart.Col(); 157 SCROW nStartRow = rRange.aStart.Row(); 158 SCCOL nEndCol = rRange.aEnd.Col(); 159 SCROW nEndRow = rRange.aEnd.Row(); 160 PutInOrder( nStartRow, nEndRow ); 161 PutInOrder( nStartCol, nEndCol ); 162 163 SCCOL nCol; 164 for (nCol=nStartCol; nCol<=nEndCol; nCol++) 165 pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark ); 166 167 if ( bMultiMarked ) // aMultiRange updaten 168 { 169 if ( nStartCol < aMultiRange.aStart.Col() ) 170 aMultiRange.aStart.SetCol( nStartCol ); 171 if ( nStartRow < aMultiRange.aStart.Row() ) 172 aMultiRange.aStart.SetRow( nStartRow ); 173 if ( nEndCol > aMultiRange.aEnd.Col() ) 174 aMultiRange.aEnd.SetCol( nEndCol ); 175 if ( nEndRow > aMultiRange.aEnd.Row() ) 176 aMultiRange.aEnd.SetRow( nEndRow ); 177 } 178 else 179 { 180 aMultiRange = rRange; // neu 181 bMultiMarked = sal_True; 182 } 183 } 184 185 void ScMarkData::SetAreaTab( SCTAB nTab ) 186 { 187 aMarkRange.aStart.SetTab(nTab); 188 aMarkRange.aEnd.SetTab(nTab); 189 aMultiRange.aStart.SetTab(nTab); 190 aMultiRange.aEnd.SetTab(nTab); 191 } 192 193 void ScMarkData::SelectOneTable( SCTAB nTab ) 194 { 195 for (SCTAB i=0; i<=MAXTAB; i++) 196 bTabMarked[i] = ( nTab == i ); 197 } 198 199 SCTAB ScMarkData::GetSelectCount() const 200 { 201 SCTAB nCount = 0; 202 for (SCTAB i=0; i<=MAXTAB; i++) 203 if (bTabMarked[i]) 204 ++nCount; 205 206 return nCount; 207 } 208 209 SCTAB ScMarkData::GetFirstSelected() const 210 { 211 for (SCTAB i=0; i<=MAXTAB; i++) 212 if (bTabMarked[i]) 213 return i; 214 215 DBG_ERROR("GetFirstSelected: keine markiert"); 216 return 0; 217 } 218 219 void ScMarkData::MarkToMulti() 220 { 221 if ( bMarked && !bMarking ) 222 { 223 SetMultiMarkArea( aMarkRange, !bMarkIsNeg ); 224 bMarked = sal_False; 225 226 // check if all multi mark ranges have been removed 227 if ( bMarkIsNeg && !HasAnyMultiMarks() ) 228 ResetMark(); 229 } 230 } 231 232 void ScMarkData::MarkToSimple() 233 { 234 if ( bMarking ) 235 return; 236 237 if ( bMultiMarked && bMarked ) 238 MarkToMulti(); // may result in bMarked and bMultiMarked reset 239 240 if ( bMultiMarked ) 241 { 242 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 243 244 ScRange aNew = aMultiRange; 245 246 sal_Bool bOk = sal_False; 247 SCCOL nStartCol = aNew.aStart.Col(); 248 SCCOL nEndCol = aNew.aEnd.Col(); 249 250 while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() ) 251 ++nStartCol; 252 while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() ) 253 --nEndCol; 254 255 // Zeilen werden nur aus MarkArray genommen 256 SCROW nStartRow, nEndRow; 257 if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) ) 258 { 259 bOk = sal_True; 260 SCROW nCmpStart, nCmpEnd; 261 for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++) 262 if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd ) 263 || nCmpStart != nStartRow || nCmpEnd != nEndRow ) 264 bOk = sal_False; 265 } 266 267 if (bOk) 268 { 269 aNew.aStart.SetCol(nStartCol); 270 aNew.aStart.SetRow(nStartRow); 271 aNew.aEnd.SetCol(nEndCol); 272 aNew.aEnd.SetRow(nEndRow); 273 274 ResetMark(); 275 aMarkRange = aNew; 276 bMarked = sal_True; 277 bMarkIsNeg = sal_False; 278 } 279 } 280 } 281 282 sal_Bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, sal_Bool bNoSimple ) const 283 { 284 if ( bMarked && !bNoSimple && !bMarkIsNeg ) 285 if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol && 286 aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow ) 287 return sal_True; 288 289 if (bMultiMarked) 290 { 291 //! hier auf negative Markierung testen ? 292 293 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 294 return pMultiSel[nCol].GetMark( nRow ); 295 } 296 297 return sal_False; 298 } 299 300 sal_Bool ScMarkData::IsColumnMarked( SCCOL nCol ) const 301 { 302 // bMarkIsNeg inzwischen auch fuer Spaltenkoepfe 303 //! GetMarkColumnRanges fuer komplett markierte Spalten 304 305 if ( bMarked && !bMarkIsNeg && 306 aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol && 307 aMarkRange.aStart.Row() == 0 && aMarkRange.aEnd.Row() == MAXROW ) 308 return sal_True; 309 310 if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) ) 311 return sal_True; 312 313 return sal_False; 314 } 315 316 sal_Bool ScMarkData::IsRowMarked( SCROW nRow ) const 317 { 318 // bMarkIsNeg inzwischen auch fuer Zeilenkoepfe 319 //! GetMarkRowRanges fuer komplett markierte Zeilen 320 321 if ( bMarked && !bMarkIsNeg && 322 aMarkRange.aStart.Col() == 0 && aMarkRange.aEnd.Col() == MAXCOL && 323 aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow ) 324 return sal_True; 325 326 if ( bMultiMarked ) 327 { 328 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 329 for (SCCOL nCol=0; nCol<=MAXCOL; nCol++) 330 if (!pMultiSel[nCol].GetMark(nRow)) 331 return sal_False; 332 return sal_True; 333 } 334 335 return sal_False; 336 } 337 338 void ScMarkData::MarkFromRangeList( const ScRangeList& rList, sal_Bool bReset ) 339 { 340 if (bReset) 341 { 342 for (SCTAB i=0; i<=MAXTAB; i++) 343 bTabMarked[i] = sal_False; // Tabellen sind nicht in ResetMark 344 ResetMark(); 345 } 346 347 sal_uLong nCount = rList.Count(); 348 if ( nCount == 1 && !bMarked && !bMultiMarked ) 349 { 350 ScRange aRange = *rList.GetObject(0); 351 SetMarkArea( aRange ); 352 SelectTable( aRange.aStart.Tab(), sal_True ); 353 } 354 else 355 { 356 for (sal_uLong i=0; i<nCount; i++) 357 { 358 ScRange aRange = *rList.GetObject(i); 359 SetMultiMarkArea( aRange, sal_True ); 360 SelectTable( aRange.aStart.Tab(), sal_True ); 361 } 362 } 363 } 364 365 void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, sal_Bool bClear ) const 366 { 367 if (!pList) 368 return; 369 370 if (bClear) 371 pList->RemoveAll(); 372 373 //! bei mehreren selektierten Tabellen mehrere Ranges eintragen !!! 374 375 if ( bMultiMarked ) 376 { 377 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 378 379 SCTAB nTab = aMultiRange.aStart.Tab(); 380 381 SCCOL nStartCol = aMultiRange.aStart.Col(); 382 SCCOL nEndCol = aMultiRange.aEnd.Col(); 383 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) 384 if (pMultiSel[nCol].HasMarks()) 385 { 386 SCROW nTop, nBottom; 387 ScRange aRange( nCol, 0, nTab ); 388 ScMarkArrayIter aMarkIter( &pMultiSel[nCol] ); 389 while ( aMarkIter.Next( nTop, nBottom ) ) 390 { 391 aRange.aStart.SetRow( nTop ); 392 aRange.aEnd.SetRow( nBottom ); 393 pList->Join( aRange ); 394 } 395 } 396 } 397 398 if ( bMarked ) 399 pList->Append( aMarkRange ); 400 } 401 402 void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const 403 { 404 if (!pList) 405 return; 406 407 ScRangeList aOldList(*pList); 408 pList->RemoveAll(); //! oder die vorhandenen unten weglassen 409 410 for (SCTAB nTab=0; nTab<=MAXTAB; nTab++) 411 if (bTabMarked[nTab]) 412 { 413 sal_uLong nCount = aOldList.Count(); 414 for (sal_uLong i=0; i<nCount; i++) 415 { 416 ScRange aRange = *aOldList.GetObject(i); 417 aRange.aStart.SetTab(nTab); 418 aRange.aEnd.SetTab(nTab); 419 pList->Append( aRange ); 420 } 421 } 422 } 423 424 SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges ) 425 { 426 if (bMarked) 427 MarkToMulti(); 428 429 if (!bMultiMarked) 430 return 0; 431 432 DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0"); 433 434 const SCCOLROW nMultiStart = aMultiRange.aStart.Col(); 435 const SCCOLROW nMultiEnd = aMultiRange.aEnd.Col(); 436 if (nMultiStart == 0 && nMultiEnd == MAXCOL) 437 { 438 // One or more entire rows. 439 pRanges[0] = 0; 440 pRanges[1] = MAXCOL; 441 return 1; 442 } 443 444 SCCOLROW nRangeCnt = 0; 445 SCCOLROW nStart = nMultiStart; 446 while (nStart <= nMultiEnd) 447 { 448 while (nStart < nMultiEnd && !pMultiSel[nStart].HasMarks()) 449 ++nStart; 450 if (pMultiSel[nStart].HasMarks()) 451 { 452 SCCOLROW nEnd = nStart; 453 while (nEnd < nMultiEnd && pMultiSel[nEnd].HasMarks()) 454 ++nEnd; 455 if (!pMultiSel[nEnd].HasMarks()) 456 --nEnd; 457 pRanges[2*nRangeCnt ] = nStart; 458 pRanges[2*nRangeCnt+1] = nEnd; 459 ++nRangeCnt; 460 nStart = nEnd+1; 461 } 462 else 463 nStart = nMultiEnd+1; 464 } 465 466 return nRangeCnt; 467 } 468 469 SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges ) 470 { 471 if (bMarked) 472 MarkToMulti(); 473 474 if (!bMultiMarked) 475 return 0; 476 477 DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0"); 478 479 // Which rows are marked? 480 481 // Optimized to not loop over MAXCOL*MAXROW as worst case, i.e. Ctrl+A 482 483 const SCCOLROW nMultiStart = aMultiRange.aStart.Row(); 484 const SCCOLROW nMultiEnd = aMultiRange.aEnd.Row(); 485 486 sal_Bool* bRowMarked = new sal_Bool[MAXROWCOUNT]; 487 memset( bRowMarked, 0, sizeof(sal_Bool) * MAXROWCOUNT); 488 SCROW nRow; 489 SCCOL nCol; 490 491 SCROW nTop = -1, nBottom = -1; 492 for (nCol = aMultiRange.aStart.Col(); nCol <= aMultiRange.aEnd.Col(); ++nCol) 493 { 494 ScMarkArrayIter aMarkIter( &pMultiSel[nCol] ); 495 while (aMarkIter.Next( nTop, nBottom )) 496 for (nRow=nTop; nRow<=nBottom; nRow++) 497 bRowMarked[nRow] = sal_True; 498 if (nTop == nMultiStart && nBottom == nMultiEnd) 499 break; // for, all relevant rows marked 500 } 501 502 if (nTop == nMultiStart && nBottom == nMultiEnd) 503 { 504 pRanges[0] = nTop; 505 pRanges[1] = nBottom; 506 delete[] bRowMarked; 507 return 1; 508 } 509 510 // Combine to ranges of rows. 511 512 SCCOLROW nRangeCnt = 0; 513 SCCOLROW nStart = nMultiStart; 514 while (nStart <= nMultiEnd) 515 { 516 while (nStart < nMultiEnd && !bRowMarked[nStart]) 517 ++nStart; 518 if (bRowMarked[nStart]) 519 { 520 SCCOLROW nEnd = nStart; 521 while (nEnd < nMultiEnd && bRowMarked[nEnd]) 522 ++nEnd; 523 if (!bRowMarked[nEnd]) 524 --nEnd; 525 pRanges[2*nRangeCnt ] = nStart; 526 pRanges[2*nRangeCnt+1] = nEnd; 527 ++nRangeCnt; 528 nStart = nEnd+1; 529 } 530 else 531 nStart = nMultiEnd+1; 532 } 533 534 delete[] bRowMarked; 535 return nRangeCnt; 536 } 537 538 sal_Bool ScMarkData::IsAllMarked( const ScRange& rRange ) const 539 { 540 if ( !bMultiMarked ) 541 return sal_False; 542 543 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 544 545 SCCOL nStartCol = rRange.aStart.Col(); 546 SCROW nStartRow = rRange.aStart.Row(); 547 SCCOL nEndCol = rRange.aEnd.Col(); 548 SCROW nEndRow = rRange.aEnd.Row(); 549 sal_Bool bOk = sal_True; 550 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++) 551 if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) ) 552 bOk = sal_False; 553 554 return bOk; 555 } 556 557 SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, sal_Bool bUp ) const 558 { 559 if ( !bMultiMarked ) 560 return nRow; 561 562 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 563 564 return pMultiSel[nCol].GetNextMarked( nRow, bUp ); 565 } 566 567 sal_Bool ScMarkData::HasMultiMarks( SCCOL nCol ) const 568 { 569 if ( !bMultiMarked ) 570 return sal_False; 571 572 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 573 574 return pMultiSel[nCol].HasMarks(); 575 } 576 577 sal_Bool ScMarkData::HasAnyMultiMarks() const 578 { 579 if ( !bMultiMarked ) 580 return sal_False; 581 582 DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); 583 584 for (SCCOL nCol=0; nCol<=MAXCOL; nCol++) 585 if ( pMultiSel[nCol].HasMarks() ) 586 return sal_True; 587 588 return sal_False; // nix 589 } 590 591 void ScMarkData::InsertTab( SCTAB nTab ) 592 { 593 for (SCTAB i=MAXTAB; i>nTab; i--) 594 bTabMarked[i] = bTabMarked[i-1]; 595 bTabMarked[nTab] = sal_False; 596 } 597 598 void ScMarkData::DeleteTab( SCTAB nTab ) 599 { 600 for (SCTAB i=nTab; i<MAXTAB; i++) 601 bTabMarked[i] = bTabMarked[i+1]; 602 bTabMarked[MAXTAB] = sal_False; 603 } 604 605 606 607 608 609