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