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 "markarr.hxx" 38 #include "global.hxx" 39 #include "address.hxx" 40 41 // STATIC DATA ----------------------------------------------------------- 42 43 //------------------------------------------------------------------------ 44 45 ScMarkArray::ScMarkArray() : 46 nCount( 0 ), 47 nLimit( 0 ), 48 pData( NULL ) 49 { 50 // special case "no marks" with pData = NULL 51 } 52 53 //------------------------------------------------------------------------ 54 55 ScMarkArray::~ScMarkArray() 56 { 57 delete[] pData; 58 } 59 60 //------------------------------------------------------------------------ 61 62 void ScMarkArray::Reset( sal_Bool bMarked ) 63 { 64 // always create pData here 65 // (or have separate method to ensure pData) 66 67 delete[] pData; 68 69 nCount = nLimit = 1; 70 pData = new ScMarkEntry[1]; 71 pData[0].nRow = MAXROW; 72 pData[0].bMarked = bMarked; 73 } 74 75 //------------------------------------------------------------------------ 76 77 sal_Bool ScMarkArray::Search( SCROW nRow, SCSIZE& nIndex ) const 78 { 79 long nLo = 0; 80 long nHi = static_cast<long>(nCount) - 1; 81 long nStartRow = 0; 82 long nEndRow = 0; 83 long i = 0; 84 sal_Bool bFound = (nCount == 1); 85 if (pData) 86 { 87 while ( !bFound && nLo <= nHi ) 88 { 89 i = (nLo + nHi) / 2; 90 if (i > 0) 91 nStartRow = (long) pData[i - 1].nRow; 92 else 93 nStartRow = -1; 94 nEndRow = (long) pData[i].nRow; 95 if (nEndRow < (long) nRow) 96 nLo = ++i; 97 else 98 if (nStartRow >= (long) nRow) 99 nHi = --i; 100 else 101 bFound = sal_True; 102 } 103 } 104 else 105 bFound = sal_False; 106 107 if (bFound) 108 nIndex=(SCSIZE)i; 109 else 110 nIndex=0; 111 return bFound; 112 } 113 114 sal_Bool ScMarkArray::GetMark( SCROW nRow ) const 115 { 116 SCSIZE i; 117 if (Search( nRow, i )) 118 return pData[i].bMarked; 119 else 120 return sal_False; 121 122 } 123 124 //------------------------------------------------------------------------ 125 126 void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, sal_Bool bMarked ) 127 { 128 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 129 { 130 if ((nStartRow == 0) && (nEndRow == MAXROW)) 131 { 132 Reset(bMarked); 133 } 134 else 135 { 136 if (!pData) 137 Reset(sal_False); // create pData for further processing - could use special case handling! 138 139 SCSIZE nNeeded = nCount + 2; 140 if ( nLimit < nNeeded ) 141 { 142 nLimit += SC_MARKARRAY_DELTA; 143 if ( nLimit < nNeeded ) 144 nLimit = nNeeded; 145 ScMarkEntry* pNewData = new ScMarkEntry[nLimit]; 146 memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) ); 147 delete[] pData; 148 pData = pNewData; 149 } 150 151 SCSIZE ni; // number of entries in beginning 152 SCSIZE nInsert; // insert position (MAXROW+1 := no insert) 153 sal_Bool bCombined = sal_False; 154 sal_Bool bSplit = sal_False; 155 if ( nStartRow > 0 ) 156 { 157 // skip beginning 158 SCSIZE nIndex; 159 Search( nStartRow, nIndex ); 160 ni = nIndex; 161 162 nInsert = MAXROWCOUNT; 163 if ( pData[ni].bMarked != bMarked ) 164 { 165 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) ) 166 { // may be a split or a simple insert or just a shrink, 167 // row adjustment is done further down 168 if ( pData[ni].nRow > nEndRow ) 169 bSplit = sal_True; 170 ni++; 171 nInsert = ni; 172 } 173 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 ) 174 nInsert = ni; 175 } 176 if ( ni > 0 && pData[ni-1].bMarked == bMarked ) 177 { // combine 178 pData[ni-1].nRow = nEndRow; 179 nInsert = MAXROWCOUNT; 180 bCombined = sal_True; 181 } 182 } 183 else 184 { 185 nInsert = 0; 186 ni = 0; 187 } 188 189 SCSIZE nj = ni; // stop position of range to replace 190 while ( nj < nCount && pData[nj].nRow <= nEndRow ) 191 nj++; 192 if ( !bSplit ) 193 { 194 if ( nj < nCount && pData[nj].bMarked == bMarked ) 195 { // combine 196 if ( ni > 0 ) 197 { 198 if ( pData[ni-1].bMarked == bMarked ) 199 { // adjacent entries 200 pData[ni-1].nRow = pData[nj].nRow; 201 nj++; 202 } 203 else if ( ni == nInsert ) 204 pData[ni-1].nRow = nStartRow - 1; // shrink 205 } 206 nInsert = MAXROWCOUNT; 207 bCombined = sal_True; 208 } 209 else if ( ni > 0 && ni == nInsert ) 210 pData[ni-1].nRow = nStartRow - 1; // shrink 211 } 212 if ( ni < nj ) 213 { // remove middle entries 214 if ( !bCombined ) 215 { // replace one entry 216 pData[ni].nRow = nEndRow; 217 pData[ni].bMarked = bMarked; 218 ni++; 219 nInsert = MAXROWCOUNT; 220 } 221 if ( ni < nj ) 222 { // remove entries 223 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) ); 224 nCount -= nj - ni; 225 } 226 } 227 228 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) 229 { // insert or append new entry 230 if ( nInsert <= nCount ) 231 { 232 if ( !bSplit ) 233 memmove( pData + nInsert + 1, pData + nInsert, 234 (nCount - nInsert) * sizeof(ScMarkEntry) ); 235 else 236 { 237 memmove( pData + nInsert + 2, pData + nInsert, 238 (nCount - nInsert) * sizeof(ScMarkEntry) ); 239 pData[nInsert+1] = pData[nInsert-1]; 240 nCount++; 241 } 242 } 243 if ( nInsert ) 244 pData[nInsert-1].nRow = nStartRow - 1; 245 pData[nInsert].nRow = nEndRow; 246 pData[nInsert].bMarked = bMarked; 247 nCount++; 248 } 249 } 250 } 251 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute(); 252 } 253 254 //UNUSED2009-05 void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow) 255 //UNUSED2009-05 { 256 //UNUSED2009-05 SetMarkArea(nStartRow, nEndRow, sal_False); 257 //UNUSED2009-05 } 258 259 sal_Bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const 260 { 261 SCSIZE nStartIndex; 262 SCSIZE nEndIndex; 263 264 if (Search( nStartRow, nStartIndex )) 265 if (pData[nStartIndex].bMarked) 266 if (Search( nEndRow, nEndIndex )) 267 if (nEndIndex==nStartIndex) 268 return sal_True; 269 270 return sal_False; 271 } 272 273 sal_Bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const 274 { 275 sal_Bool bRet = sal_False; 276 if ( nCount == 1 ) 277 { 278 if ( pData[0].bMarked ) 279 { 280 rStartRow = 0; 281 rEndRow = MAXROW; 282 bRet = sal_True; 283 } 284 } 285 else if ( nCount == 2 ) 286 { 287 if ( pData[0].bMarked ) 288 { 289 rStartRow = 0; 290 rEndRow = pData[0].nRow; 291 } 292 else 293 { 294 rStartRow = pData[0].nRow + 1; 295 rEndRow = MAXROW; 296 } 297 bRet = sal_True; 298 } 299 else if ( nCount == 3 ) 300 { 301 if ( pData[1].bMarked ) 302 { 303 rStartRow = pData[0].nRow + 1; 304 rEndRow = pData[1].nRow; 305 bRet = sal_True; 306 } 307 } 308 return bRet; 309 } 310 311 void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const 312 { 313 delete[] rDestMarkArray.pData; 314 315 if (pData) 316 { 317 rDestMarkArray.pData = new ScMarkEntry[nCount]; 318 memmove( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) ); 319 } 320 else 321 rDestMarkArray.pData = NULL; 322 323 rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount; 324 } 325 326 SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, sal_Bool bUp ) const 327 { 328 if (!pData) 329 const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing 330 331 SCsROW nRet = nRow; 332 if (VALIDROW(nRow)) 333 { 334 SCSIZE nIndex; 335 Search(nRow, nIndex); 336 if (!pData[nIndex].bMarked) 337 { 338 if (bUp) 339 { 340 if (nIndex>0) 341 nRet = pData[nIndex-1].nRow; 342 else 343 nRet = -1; 344 } 345 else 346 nRet = pData[nIndex].nRow + 1; 347 } 348 } 349 return nRet; 350 } 351 352 SCROW ScMarkArray::GetMarkEnd( SCROW nRow, sal_Bool bUp ) const 353 { 354 if (!pData) 355 const_cast<ScMarkArray*>(this)->Reset(sal_False); // create pData for further processing 356 357 SCROW nRet; 358 SCSIZE nIndex; 359 Search(nRow, nIndex); 360 DBG_ASSERT( pData[nIndex].bMarked, "GetMarkEnd ohne bMarked" ); 361 if (bUp) 362 { 363 if (nIndex>0) 364 nRet = pData[nIndex-1].nRow + 1; 365 else 366 nRet = 0; 367 } 368 else 369 nRet = pData[nIndex].nRow; 370 371 return nRet; 372 } 373 374 // 375 // -------------- Iterator ---------------------------------------------- 376 // 377 378 ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) : 379 pArray( pNewArray ), 380 nPos( 0 ) 381 { 382 } 383 384 ScMarkArrayIter::~ScMarkArrayIter() 385 { 386 } 387 388 sal_Bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom ) 389 { 390 if ( nPos >= pArray->nCount ) 391 return sal_False; 392 while (!pArray->pData[nPos].bMarked) 393 { 394 ++nPos; 395 if ( nPos >= pArray->nCount ) 396 return sal_False; 397 } 398 rBottom = pArray->pData[nPos].nRow; 399 if (nPos==0) 400 rTop = 0; 401 else 402 rTop = pArray->pData[nPos-1].nRow + 1; 403 ++nPos; 404 return sal_True; 405 } 406 407 408 409 410 411