Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "attarray.hxx"
21 : #include "scitems.hxx"
22 : #include <svx/algitem.hxx>
23 : #include <editeng/boxitem.hxx>
24 : #include <editeng/lineitem.hxx>
25 : #include <editeng/frmdiritem.hxx>
26 : #include <editeng/shaditem.hxx>
27 : #include <editeng/editobj.hxx>
28 : #include <editeng/justifyitem.hxx>
29 : #include <svl/poolcach.hxx>
30 : #include <editeng/fontitem.hxx>
31 : #include <unotools/fontcvt.hxx>
32 :
33 : #include "global.hxx"
34 : #include "document.hxx"
35 : #include "docpool.hxx"
36 : #include "patattr.hxx"
37 : #include "stlsheet.hxx"
38 : #include "stlpool.hxx"
39 : #include "markarr.hxx"
40 : #include "rechead.hxx"
41 : #include "globstr.hrc"
42 : #include "segmenttree.hxx"
43 : #include "editdataarray.hxx"
44 : #include "formulacell.hxx"
45 : #include "cellvalue.hxx"
46 : #include "editutil.hxx"
47 : #include <rtl/strbuf.hxx>
48 :
49 : // STATIC DATA -----------------------------------------------------------
50 :
51 : //------------------------------------------------------------------------
52 : using ::editeng::SvxBorderLine;
53 :
54 1658880 : ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
55 : nCol( nNewCol ),
56 : nTab( nNewTab ),
57 : pDocument( pDoc ),
58 : nCount(1),
59 : nLimit(1),
60 1658880 : pData(new ScAttrEntry[1])
61 : {
62 1658880 : pData[0].nRow = MAXROW;
63 1658880 : pData[0].pPattern = pDocument->GetDefPattern(); // no put
64 1658880 : }
65 :
66 : //------------------------------------------------------------------------
67 :
68 1554432 : ScAttrArray::~ScAttrArray()
69 : {
70 : #if OSL_DEBUG_LEVEL > 1
71 : TestData();
72 : #endif
73 :
74 1554432 : ScDocumentPool* pDocPool = pDocument->GetPool();
75 3228054 : for (SCSIZE i=0; i<nCount; i++)
76 1673622 : pDocPool->Remove(*pData[i].pPattern);
77 :
78 1554432 : delete[] pData;
79 1554432 : }
80 :
81 : //------------------------------------------------------------------------
82 : #if OSL_DEBUG_LEVEL > 1
83 : void ScAttrArray::TestData() const
84 : {
85 :
86 : sal_uInt16 nErr = 0;
87 : SCSIZE nPos;
88 : for (nPos=0; nPos<nCount; nPos++)
89 : {
90 : if (nPos > 0)
91 : if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
92 : ++nErr;
93 : if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
94 : ++nErr;
95 : }
96 : if ( nPos && pData[nPos-1].nRow != MAXROW )
97 : ++nErr;
98 :
99 : if (nErr)
100 : {
101 : OStringBuffer aMsg;
102 : aMsg.append(static_cast<sal_Int32>(nErr));
103 : aMsg.append(RTL_CONSTASCII_STRINGPARAM(
104 : " errors in attribute array, column "));
105 : aMsg.append(static_cast<sal_Int32>(nCol));
106 : OSL_FAIL(aMsg.getStr());
107 : }
108 : }
109 : #endif
110 :
111 : //------------------------------------------------------------------------
112 :
113 32695 : void ScAttrArray::Reset( const ScPatternAttr* pPattern )
114 : {
115 32695 : ScDocumentPool* pDocPool = pDocument->GetPool();
116 : const ScPatternAttr* pOldPattern;
117 32695 : ScAddress aAdrStart( nCol, 0, nTab );
118 32695 : ScAddress aAdrEnd ( nCol, 0, nTab );
119 :
120 65390 : for (SCSIZE i=0; i<nCount; i++)
121 : {
122 : // ensure that attributing changes text width of cell
123 32695 : pOldPattern = pData[i].pPattern;
124 : bool bNumFormatChanged;
125 32695 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
126 32695 : pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
127 : {
128 0 : aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
129 0 : aAdrEnd .SetRow( pData[i].nRow );
130 0 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
131 : }
132 32695 : pDocPool->Remove(*pOldPattern);
133 : }
134 32695 : delete[] pData;
135 :
136 32695 : if (pDocument->IsStreamValid(nTab))
137 0 : pDocument->SetStreamValid(nTab, false);
138 :
139 32695 : nCount = nLimit = 1;
140 32695 : pData = new ScAttrEntry[1];
141 32695 : ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
142 32695 : pData[0].nRow = MAXROW;
143 32695 : pData[0].pPattern = pNewPattern;
144 32695 : }
145 :
146 :
147 29411 : bool ScAttrArray::Concat(SCSIZE nPos)
148 : {
149 29411 : bool bRet = false;
150 29411 : if (nPos < nCount)
151 : {
152 29411 : if (nPos > 0)
153 : {
154 95 : if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
155 : {
156 5 : pData[nPos - 1].nRow = pData[nPos].nRow;
157 5 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
158 5 : memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
159 5 : pData[nCount - 1].pPattern = NULL;
160 5 : pData[nCount - 1].nRow = 0;
161 5 : nCount--;
162 5 : nPos--;
163 5 : bRet = true;
164 : }
165 : }
166 29411 : if (nPos + 1 < nCount)
167 : {
168 992 : if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
169 : {
170 0 : pData[nPos].nRow = pData[nPos + 1].nRow;
171 0 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
172 0 : memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
173 0 : pData[nCount - 1].pPattern = NULL;
174 0 : pData[nCount - 1].nRow = 0;
175 0 : nCount--;
176 0 : bRet = true;
177 : }
178 : }
179 : }
180 29411 : return bRet;
181 : }
182 :
183 : //------------------------------------------------------------------------
184 :
185 24100714 : bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
186 : {
187 24100714 : long nHi = static_cast<long>(nCount) - 1;
188 24100714 : long i = 0;
189 24100714 : bool bFound = (nCount == 1);
190 24100714 : long nLo = 0;
191 24100714 : long nStartRow = 0;
192 24100714 : long nEndRow = 0;
193 64746424 : while ( !bFound && nLo <= nHi )
194 : {
195 16544996 : i = (nLo + nHi) / 2;
196 16544996 : if (i > 0)
197 8569656 : nStartRow = (long) pData[i - 1].nRow;
198 : else
199 7975340 : nStartRow = -1;
200 16544996 : nEndRow = (long) pData[i].nRow;
201 16544996 : if (nEndRow < (long) nRow)
202 219475 : nLo = ++i;
203 : else
204 16325521 : if (nStartRow >= (long) nRow)
205 8163964 : nHi = --i;
206 : else
207 8161557 : bFound = true;
208 : }
209 :
210 24100714 : if (bFound)
211 24099380 : nIndex=(SCSIZE)i;
212 : else
213 1334 : nIndex=0;
214 24100714 : return bFound;
215 : }
216 :
217 :
218 114303 : const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
219 : {
220 : SCSIZE i;
221 114303 : if (Search( nRow, i ))
222 114303 : return pData[i].pPattern;
223 : else
224 0 : return NULL;
225 : }
226 :
227 :
228 4380 : const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
229 : SCROW& rEndRow, SCROW nRow ) const
230 : {
231 : SCSIZE nIndex;
232 4380 : if ( Search( nRow, nIndex ) )
233 : {
234 4380 : if ( nIndex > 0 )
235 59 : rStartRow = pData[nIndex-1].nRow + 1;
236 : else
237 4321 : rStartRow = 0;
238 4380 : rEndRow = pData[nIndex].nRow;
239 4380 : return pData[nIndex].pPattern;
240 : }
241 0 : return NULL;
242 : }
243 :
244 4360 : void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
245 : {
246 4360 : if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
247 0 : return;
248 :
249 4360 : if(nEndRow < nStartRow)
250 0 : return;
251 :
252 4360 : SCROW nTempStartRow = nStartRow;
253 4360 : SCROW nTempEndRow = nEndRow;
254 :
255 4360 : do
256 : {
257 4360 : const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
258 :
259 4360 : boost::scoped_ptr<ScPatternAttr> pNewPattern;
260 4360 : if(pPattern)
261 : {
262 4360 : pNewPattern.reset( new ScPatternAttr(*pPattern) );
263 : SCROW nPatternStartRow;
264 : SCROW nPatternEndRow;
265 4360 : GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
266 :
267 4360 : nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
268 4360 : const SfxPoolItem* pItem = NULL;
269 4360 : pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
270 4360 : std::vector< sal_uInt32 > aCondFormatData;
271 4360 : if(pItem)
272 2197 : aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
273 4360 : aCondFormatData.push_back(nIndex);
274 :
275 8720 : ScCondFormatItem aItem;
276 4360 : aItem.SetCondFormatData( aCondFormatData );
277 8720 : pNewPattern->GetItemSet().Put( aItem );
278 : }
279 : else
280 : {
281 0 : pNewPattern.reset( new ScPatternAttr( pDocument->GetPool() ) );
282 0 : ScCondFormatItem aItem;
283 0 : aItem.AddCondFormatData(nIndex);
284 0 : pNewPattern->GetItemSet().Put( aItem );
285 0 : nTempEndRow = nEndRow;
286 : }
287 :
288 4360 : SetPatternArea( nTempStartRow, nTempEndRow, pNewPattern.get(), true );
289 4360 : nTempStartRow = nTempEndRow + 1;
290 : }
291 4360 : while(nTempEndRow < nEndRow);
292 :
293 : }
294 :
295 0 : void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
296 : {
297 0 : if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
298 0 : return;
299 :
300 0 : if(nEndRow < nStartRow)
301 0 : return;
302 :
303 0 : SCROW nTempStartRow = nStartRow;
304 0 : SCROW nTempEndRow = nEndRow;
305 :
306 0 : do
307 : {
308 0 : const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
309 :
310 0 : if(pPattern)
311 : {
312 0 : ScPatternAttr aPattern( *pPattern );
313 : SCROW nPatternStartRow;
314 : SCROW nPatternEndRow;
315 0 : GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
316 :
317 0 : nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
318 0 : const SfxPoolItem* pItem = NULL;
319 0 : pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
320 0 : if(pItem)
321 : {
322 0 : std::vector< sal_uInt32 > aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
323 0 : std::vector<sal_uInt32>::iterator itr = std::find(aCondFormatData.begin(), aCondFormatData.end(), nIndex);
324 0 : if(itr != aCondFormatData.end())
325 : {
326 0 : ScCondFormatItem aItem;
327 0 : aCondFormatData.erase(itr);
328 0 : aItem.SetCondFormatData( aCondFormatData );
329 0 : aPattern.GetItemSet().Put( aItem );
330 0 : SetPatternArea( nTempStartRow, nTempEndRow, &aPattern, true );
331 0 : }
332 :
333 0 : }
334 : }
335 : else
336 : {
337 0 : return;
338 : }
339 :
340 0 : nTempStartRow = nTempEndRow + 1;
341 : }
342 0 : while(nTempEndRow < nEndRow);
343 :
344 : }
345 :
346 : //------------------------------------------------------------------------
347 :
348 2598 : void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool )
349 : {
350 2598 : SetPatternArea( nRow, nRow, pPattern, bPutToPool );
351 2598 : }
352 :
353 0 : void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
354 : const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
355 : {
356 0 : for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
357 : {
358 0 : ScAddress aPos(nCol, nRow, nTab);
359 0 : ScRefCellValue aCell;
360 0 : aCell.assign(*pDocument, aPos);
361 0 : if (aCell.meType != CELLTYPE_EDIT || !aCell.mpEditText)
362 0 : continue;
363 :
364 0 : EditTextObject* pOldData = NULL;
365 0 : if (pDataArray)
366 0 : pOldData = aCell.mpEditText->Clone();
367 :
368 : // Direct modification of cell content - something to watch out for if
369 : // we decide to share edit text instances in the future.
370 0 : ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.mpEditText), *pPattern);
371 :
372 0 : if (pDataArray)
373 : {
374 0 : EditTextObject* pNewData = aCell.mpEditText->Clone();
375 0 : pDataArray->AddItem(nTab, nCol, nRow, pOldData, pNewData);
376 : }
377 0 : }
378 0 : }
379 :
380 82949 : void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
381 : bool bPutToPool, ScEditDataArray* pDataArray )
382 : {
383 82949 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
384 : {
385 82949 : if (bPutToPool)
386 19179 : pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
387 :
388 82949 : if ((nStartRow == 0) && (nEndRow == MAXROW))
389 32695 : Reset(pPattern);
390 : else
391 : {
392 50254 : SCSIZE nNeeded = nCount + 2;
393 50254 : if ( nLimit < nNeeded )
394 : {
395 23549 : nLimit += SC_ATTRARRAY_DELTA;
396 23549 : if ( nLimit < nNeeded )
397 0 : nLimit = nNeeded;
398 23549 : ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
399 23549 : memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
400 23549 : delete[] pData;
401 23549 : pData = pNewData;
402 : }
403 :
404 50254 : ScAddress aAdrStart( nCol, 0, nTab );
405 50254 : ScAddress aAdrEnd ( nCol, 0, nTab );
406 :
407 50254 : SCSIZE ni = 0; // number of entries in beginning
408 50254 : SCSIZE nx = 0; // track position
409 50254 : SCROW ns = 0; // start row of track position
410 50254 : if ( nStartRow > 0 )
411 : {
412 : // skip beginning
413 : SCSIZE nIndex;
414 41341 : Search( nStartRow, nIndex );
415 41341 : ni = nIndex;
416 :
417 41341 : if ( ni > 0 )
418 : {
419 15326 : nx = ni;
420 15326 : ns = pData[ni-1].nRow+1;
421 : }
422 : }
423 :
424 : // ensure that attributing changes text width of cell
425 : // otherwise, conditional formats need to be reset or deleted
426 151984 : while ( ns <= nEndRow )
427 : {
428 51476 : const SfxItemSet& rNewSet = pPattern->GetItemSet();
429 51476 : const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
430 :
431 : bool bNumFormatChanged;
432 51476 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
433 51476 : rNewSet, rOldSet ) )
434 : {
435 5055 : aAdrStart.SetRow( std::max(nStartRow,ns) );
436 5055 : aAdrEnd .SetRow( std::min(nEndRow,pData[nx].nRow) );
437 5055 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
438 : }
439 51476 : ns = pData[nx].nRow + 1;
440 51476 : nx++;
441 : }
442 :
443 : // continue modifying data array
444 :
445 : SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
446 50254 : bool bCombined = false;
447 50254 : bool bSplit = false;
448 50254 : if ( nStartRow > 0 )
449 : {
450 41341 : nInsert = MAXROWCOUNT;
451 41341 : if ( pData[ni].pPattern != pPattern )
452 : {
453 17696 : if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
454 : { // may be a split or a simple insert or just a shrink,
455 : // row adjustment is done further down
456 3265 : if ( pData[ni].nRow > nEndRow )
457 2547 : bSplit = true;
458 3265 : ni++;
459 3265 : nInsert = ni;
460 : }
461 14431 : else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
462 14431 : nInsert = ni;
463 : }
464 41341 : if ( ni > 0 && pData[ni-1].pPattern == pPattern )
465 : { // combine
466 1879 : pData[ni-1].nRow = nEndRow;
467 1879 : nInsert = MAXROWCOUNT;
468 1879 : bCombined = true;
469 : }
470 : }
471 : else
472 8913 : nInsert = 0;
473 :
474 50254 : SCSIZE nj = ni; // stop position of range to replace
475 117451 : while ( nj < nCount && pData[nj].nRow <= nEndRow )
476 16943 : nj++;
477 50254 : if ( !bSplit )
478 : {
479 47707 : if ( nj < nCount && pData[nj].pPattern == pPattern )
480 : { // combine
481 27282 : if ( ni > 0 )
482 : {
483 955 : if ( pData[ni-1].pPattern == pPattern )
484 : { // adjacent entries
485 859 : pData[ni-1].nRow = pData[nj].nRow;
486 859 : nj++;
487 : }
488 96 : else if ( ni == nInsert )
489 20 : pData[ni-1].nRow = nStartRow - 1; // shrink
490 : }
491 27282 : nInsert = MAXROWCOUNT;
492 27282 : bCombined = true;
493 : }
494 20425 : else if ( ni > 0 && ni == nInsert )
495 13250 : pData[ni-1].nRow = nStartRow - 1; // shrink
496 : }
497 50254 : ScDocumentPool* pDocPool = pDocument->GetPool();
498 50254 : if ( bSplit )
499 : { // duplicate splitted entry in pool
500 2547 : pDocPool->Put( *pData[ni-1].pPattern );
501 : }
502 50254 : if ( ni < nj )
503 : { // remove middle entries
504 33529 : for ( SCSIZE nk=ni; nk<nj; nk++)
505 : { // remove entries from pool
506 17802 : pDocPool->Remove( *pData[nk].pPattern );
507 : }
508 15727 : if ( !bCombined )
509 : { // replace one entry
510 14364 : pData[ni].nRow = nEndRow;
511 14364 : pData[ni].pPattern = pPattern;
512 14364 : ni++;
513 14364 : nInsert = MAXROWCOUNT;
514 : }
515 15727 : if ( ni < nj )
516 : { // remove entries
517 1369 : memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
518 1369 : nCount -= nj - ni;
519 : }
520 : }
521 :
522 50254 : if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
523 : { // insert or append new entry
524 7588 : if ( nInsert <= nCount )
525 : {
526 7588 : if ( !bSplit )
527 5041 : memmove( pData + nInsert + 1, pData + nInsert,
528 10082 : (nCount - nInsert) * sizeof(ScAttrEntry) );
529 : else
530 : {
531 2547 : memmove( pData + nInsert + 2, pData + nInsert,
532 5094 : (nCount - nInsert) * sizeof(ScAttrEntry) );
533 2547 : pData[nInsert+1] = pData[nInsert-1];
534 2547 : nCount++;
535 : }
536 : }
537 7588 : if ( nInsert )
538 6314 : pData[nInsert-1].nRow = nStartRow - 1;
539 7588 : pData[nInsert].nRow = nEndRow;
540 7588 : pData[nInsert].pPattern = pPattern;
541 :
542 : // Remove character attributes from these cells if the pattern
543 : // is applied during normal session.
544 7588 : if (pDataArray)
545 0 : RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
546 :
547 7588 : nCount++;
548 : }
549 :
550 50254 : if (pDocument->IsStreamValid(nTab))
551 4 : pDocument->SetStreamValid(nTab, false);
552 : }
553 : }
554 :
555 : #if OSL_DEBUG_LEVEL > 1
556 : TestData();
557 : #endif
558 82949 : }
559 :
560 :
561 79604 : void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
562 : {
563 79604 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
564 : {
565 : SCSIZE nPos;
566 79604 : SCROW nStart=0;
567 79604 : if (!Search( nStartRow, nPos ))
568 : {
569 : OSL_FAIL("Search Failure");
570 79604 : return;
571 : }
572 :
573 79604 : ScAddress aAdrStart( nCol, 0, nTab );
574 79604 : ScAddress aAdrEnd ( nCol, 0, nTab );
575 :
576 79699 : do
577 : {
578 79699 : const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
579 79699 : ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
580 79699 : pNewPattern->SetStyleSheet(pStyle);
581 79699 : SCROW nY1 = nStart;
582 79699 : SCROW nY2 = pData[nPos].nRow;
583 79699 : nStart = pData[nPos].nRow + 1;
584 :
585 79699 : if ( *pNewPattern == *pOldPattern )
586 : {
587 : // keep the original pattern (might be default)
588 : // pNewPattern is deleted below
589 77936 : nPos++;
590 : }
591 1763 : else if ( nY1 < nStartRow || nY2 > nEndRow )
592 : {
593 1684 : if (nY1 < nStartRow) nY1=nStartRow;
594 1684 : if (nY2 > nEndRow) nY2=nEndRow;
595 1684 : SetPatternArea( nY1, nY2, pNewPattern, true );
596 1684 : Search( nStart, nPos );
597 : }
598 : else
599 : {
600 : // ensure attributing changes text width of cell; otherwise
601 : // there aren't (yet) template format changes
602 79 : const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
603 79 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
604 :
605 : bool bNumFormatChanged;
606 79 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
607 79 : rNewSet, rOldSet ) )
608 : {
609 4 : aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
610 4 : aAdrEnd .SetRow( pData[nPos].nRow );
611 4 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
612 : }
613 :
614 79 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
615 79 : pData[nPos].pPattern = (const ScPatternAttr*)
616 79 : &pDocument->GetPool()->Put(*pNewPattern);
617 79 : if (Concat(nPos))
618 0 : Search(nStart, nPos);
619 : else
620 79 : nPos++;
621 : }
622 79699 : delete pNewPattern;
623 : }
624 95 : while ((nStart <= nEndRow) && (nPos < nCount));
625 :
626 79604 : if (pDocument->IsStreamValid(nTab))
627 0 : pDocument->SetStreamValid(nTab, false);
628 : }
629 :
630 : #if OSL_DEBUG_LEVEL > 1
631 : TestData();
632 : #endif
633 : }
634 :
635 :
636 : // const cast, otherwise it will be too inefficient/complicated
637 : #define SET_LINECOLOR(dest,c) \
638 : if ((dest)) \
639 : { \
640 : ((SvxBorderLine*)(dest))->SetColor((c)); \
641 : }
642 :
643 : #define SET_LINE(dest,src) \
644 : if ((dest)) \
645 : { \
646 : SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
647 : pCast->SetBorderLineStyle( (src)->GetBorderLineStyle() ); \
648 : pCast->SetWidth( (src)->GetWidth( ) ); \
649 : }
650 :
651 0 : void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
652 : const SvxBorderLine* pLine, bool bColorOnly )
653 : {
654 0 : if ( bColorOnly && !pLine )
655 0 : return;
656 :
657 0 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
658 : {
659 : SCSIZE nPos;
660 0 : SCROW nStart=0;
661 0 : if (!Search( nStartRow, nPos ))
662 : {
663 : OSL_FAIL("Search failure");
664 0 : return;
665 : }
666 :
667 0 : do
668 : {
669 0 : const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
670 0 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
671 0 : const SfxPoolItem* pBoxItem = 0;
672 0 : SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, true, &pBoxItem );
673 0 : const SfxPoolItem* pTLBRItem = 0;
674 0 : SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
675 0 : const SfxPoolItem* pBLTRItem = 0;
676 0 : SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
677 :
678 0 : if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
679 : {
680 0 : ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
681 0 : SfxItemSet& rNewSet = pNewPattern->GetItemSet();
682 0 : SCROW nY1 = nStart;
683 0 : SCROW nY2 = pData[nPos].nRow;
684 :
685 0 : SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
686 0 : SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
687 0 : SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
688 :
689 : // fetch line and update attributes with parameters
690 :
691 0 : if ( !pLine )
692 : {
693 0 : if( pNewBoxItem )
694 : {
695 0 : if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
696 0 : if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
697 0 : if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
698 0 : if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
699 : }
700 0 : if( pNewTLBRItem && pNewTLBRItem->GetLine() )
701 0 : pNewTLBRItem->SetLine( 0 );
702 0 : if( pNewBLTRItem && pNewBLTRItem->GetLine() )
703 0 : pNewBLTRItem->SetLine( 0 );
704 : }
705 : else
706 : {
707 0 : if ( bColorOnly )
708 : {
709 0 : Color aColor( pLine->GetColor() );
710 0 : if( pNewBoxItem )
711 : {
712 0 : SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
713 0 : SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
714 0 : SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
715 0 : SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
716 : }
717 0 : if( pNewTLBRItem )
718 0 : SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
719 0 : if( pNewBLTRItem )
720 0 : SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
721 : }
722 : else
723 : {
724 0 : if( pNewBoxItem )
725 : {
726 0 : SET_LINE( pNewBoxItem->GetTop(), pLine );
727 0 : SET_LINE( pNewBoxItem->GetBottom(), pLine );
728 0 : SET_LINE( pNewBoxItem->GetLeft(), pLine );
729 0 : SET_LINE( pNewBoxItem->GetRight(), pLine );
730 : }
731 0 : if( pNewTLBRItem )
732 0 : SET_LINE( pNewTLBRItem->GetLine(), pLine );
733 0 : if( pNewBLTRItem )
734 0 : SET_LINE( pNewBLTRItem->GetLine(), pLine );
735 : }
736 : }
737 0 : if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
738 0 : if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
739 0 : if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
740 :
741 0 : nStart = pData[nPos].nRow + 1;
742 :
743 0 : if ( nY1 < nStartRow || nY2 > nEndRow )
744 : {
745 0 : if (nY1 < nStartRow) nY1=nStartRow;
746 0 : if (nY2 > nEndRow) nY2=nEndRow;
747 0 : SetPatternArea( nY1, nY2, pNewPattern, true );
748 0 : Search( nStart, nPos );
749 : }
750 : else
751 : {
752 : // remove from pool ?
753 0 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
754 0 : pData[nPos].pPattern = (const ScPatternAttr*)
755 0 : &pDocument->GetPool()->Put(*pNewPattern);
756 :
757 0 : if (Concat(nPos))
758 0 : Search(nStart, nPos);
759 : else
760 0 : nPos++;
761 : }
762 0 : delete pNewBoxItem;
763 0 : delete pNewTLBRItem;
764 0 : delete pNewBLTRItem;
765 0 : delete pNewPattern;
766 : }
767 : else
768 : {
769 0 : nStart = pData[nPos].nRow + 1;
770 0 : nPos++;
771 : }
772 : }
773 0 : while ((nStart <= nEndRow) && (nPos < nCount));
774 : }
775 : }
776 :
777 : #undef SET_LINECOLOR
778 : #undef SET_LINE
779 :
780 :
781 32537 : void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
782 : {
783 : #if OSL_DEBUG_LEVEL > 1
784 : TestData();
785 : #endif
786 :
787 32537 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
788 : {
789 : SCSIZE nPos;
790 32537 : SCROW nStart=0;
791 32537 : if (!Search( nStartRow, nPos ))
792 : {
793 : OSL_FAIL("Search Failure");
794 32537 : return;
795 : }
796 :
797 32537 : ScAddress aAdrStart( nCol, 0, nTab );
798 32537 : ScAddress aAdrEnd ( nCol, 0, nTab );
799 :
800 32595 : do
801 : {
802 32595 : const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
803 32595 : const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, true );
804 32595 : ScDocumentPool::CheckRef( *pOldPattern );
805 32595 : ScDocumentPool::CheckRef( *pNewPattern );
806 32595 : if (pNewPattern != pOldPattern)
807 : {
808 32403 : SCROW nY1 = nStart;
809 32403 : SCROW nY2 = pData[nPos].nRow;
810 32403 : nStart = pData[nPos].nRow + 1;
811 :
812 32403 : if ( nY1 < nStartRow || nY2 > nEndRow )
813 : {
814 3071 : if (nY1 < nStartRow) nY1=nStartRow;
815 3071 : if (nY2 > nEndRow) nY2=nEndRow;
816 3071 : SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
817 3071 : Search( nStart, nPos );
818 : }
819 : else
820 : {
821 : // ensure attributing changes text-width of cell
822 :
823 29332 : const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
824 29332 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
825 :
826 : bool bNumFormatChanged;
827 29332 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
828 29332 : rNewSet, rOldSet ) )
829 : {
830 568 : aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
831 568 : aAdrEnd .SetRow( pData[nPos].nRow );
832 568 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
833 : }
834 :
835 29332 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
836 29332 : pData[nPos].pPattern = pNewPattern;
837 29332 : if (Concat(nPos))
838 5 : Search(nStart, nPos);
839 : else
840 29327 : ++nPos;
841 : }
842 : }
843 : else
844 : {
845 192 : nStart = pData[nPos].nRow + 1;
846 192 : ++nPos;
847 : }
848 : }
849 : while (nStart <= nEndRow);
850 :
851 32537 : if (pDocument->IsStreamValid(nTab))
852 0 : pDocument->SetStreamValid(nTab, false);
853 : }
854 :
855 : #if OSL_DEBUG_LEVEL > 1
856 : TestData();
857 : #endif
858 : }
859 :
860 25281 : bool ScAttrArray::SetAttrEntries(ScAttrEntry* pNewData, SCSIZE nSize)
861 : {
862 25281 : ScDocumentPool* pDocPool = pDocument->GetPool();
863 50630 : for (SCSIZE i=0; i<nCount; i++)
864 25349 : pDocPool->Remove(*pData[i].pPattern);
865 :
866 25281 : delete[] pData;
867 :
868 25281 : pData = pNewData;
869 25281 : nCount = nLimit = nSize;
870 25281 : return true;
871 : }
872 :
873 79 : static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
874 : {
875 : const SfxPoolItem* pNewItem;
876 : const SfxPoolItem* pOldItem;
877 4503 : for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
878 : {
879 : // pMergeSet has no parent
880 4424 : SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem );
881 :
882 4424 : if ( eOldState == SFX_ITEM_DEFAULT )
883 : {
884 3374 : SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
885 3374 : if ( eNewState == SFX_ITEM_SET )
886 : {
887 46 : if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
888 6 : rMergeSet.InvalidateItem( nId );
889 : }
890 : }
891 1050 : else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
892 : {
893 1046 : SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
894 1046 : if ( eNewState == SFX_ITEM_SET )
895 : {
896 1032 : if ( pNewItem != pOldItem ) // beide gepuhlt
897 35 : rMergeSet.InvalidateItem( nId );
898 : }
899 : else // Default
900 : {
901 14 : if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
902 1 : rMergeSet.InvalidateItem( nId );
903 : }
904 : }
905 : // Dontcare remains Dontcare
906 : }
907 79 : }
908 :
909 :
910 62820 : void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
911 : ScMergePatternState& rState, bool bDeep ) const
912 : {
913 62820 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
914 : {
915 : SCSIZE nPos;
916 62820 : SCROW nStart=0;
917 62820 : if (!Search( nStartRow, nPos ))
918 : {
919 : OSL_FAIL("Search failure");
920 62820 : return;
921 : }
922 :
923 62969 : do
924 : {
925 : // similar patterns must not be repeated
926 :
927 62969 : const ScPatternAttr* pPattern = pData[nPos].pPattern;
928 62969 : if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
929 : {
930 10491 : const SfxItemSet& rThisSet = pPattern->GetItemSet();
931 10491 : if (rState.pItemSet)
932 : {
933 85 : if (bDeep)
934 79 : lcl_MergeDeep( *rState.pItemSet, rThisSet );
935 : else
936 6 : rState.pItemSet->MergeValues( rThisSet, false );
937 : }
938 : else
939 : {
940 : // first pattern - copied from parent
941 10406 : rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
942 10406 : rState.pItemSet->Set( rThisSet, bDeep );
943 : }
944 :
945 10491 : rState.pOld2 = rState.pOld1;
946 10491 : rState.pOld1 = pPattern;
947 : }
948 :
949 62969 : nStart = pData[nPos].nRow + 1;
950 62969 : ++nPos;
951 : }
952 : while (nStart <= nEndRow);
953 : }
954 : }
955 :
956 :
957 :
958 : // assemble border
959 :
960 1704 : static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
961 : sal_uInt8& rModified, const SvxBorderLine*& rpNew )
962 : {
963 1704 : if (rModified == SC_LINE_DONTCARE)
964 0 : return false; // don't go again
965 :
966 1704 : if (rModified == SC_LINE_EMPTY)
967 : {
968 292 : rModified = SC_LINE_SET;
969 292 : rpNew = pNewLine;
970 292 : return true; // initial value
971 : }
972 :
973 1412 : if (pOldLine == pNewLine)
974 : {
975 1412 : rpNew = pOldLine;
976 1412 : return false;
977 : }
978 :
979 0 : if (pOldLine && pNewLine)
980 0 : if (*pOldLine == *pNewLine)
981 : {
982 0 : rpNew = pOldLine;
983 0 : return false;
984 : }
985 :
986 0 : rModified = SC_LINE_DONTCARE;
987 0 : rpNew = NULL;
988 0 : return true; // another line -> don't care
989 : }
990 :
991 :
992 426 : static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
993 : ScLineFlags& rFlags, const ScPatternAttr* pPattern,
994 : bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
995 : {
996 : // right/bottom border set when connected together
997 426 : const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
998 426 : if ( rMerge.GetColMerge() == nDistRight + 1 )
999 0 : nDistRight = 0;
1000 426 : if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1001 0 : nDistBottom = 0;
1002 :
1003 426 : const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
1004 426 : const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
1005 426 : const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
1006 426 : const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
1007 426 : const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
1008 : const SvxBorderLine* pNew;
1009 :
1010 426 : if (bTop)
1011 : {
1012 176 : if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
1013 54 : pLineOuter->SetLine( pNew, BOX_LINE_TOP );
1014 : }
1015 : else
1016 : {
1017 250 : if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
1018 0 : pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
1019 : }
1020 :
1021 426 : if (nDistBottom == 0)
1022 : {
1023 176 : if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
1024 54 : pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
1025 : }
1026 : else
1027 : {
1028 250 : if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1029 38 : pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
1030 : }
1031 :
1032 426 : if (bLeft)
1033 : {
1034 116 : if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1035 54 : pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
1036 : }
1037 : else
1038 : {
1039 310 : if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1040 0 : pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1041 : }
1042 :
1043 426 : if (nDistRight == 0)
1044 : {
1045 116 : if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1046 54 : pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
1047 : }
1048 : else
1049 : {
1050 310 : if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1051 38 : pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1052 : }
1053 426 : }
1054 :
1055 :
1056 176 : void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1057 : ScLineFlags& rFlags,
1058 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
1059 : {
1060 : const ScPatternAttr* pPattern;
1061 :
1062 176 : if (nStartRow == nEndRow)
1063 : {
1064 16 : pPattern = GetPattern( nStartRow );
1065 16 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
1066 : }
1067 : else
1068 : {
1069 160 : pPattern = GetPattern( nStartRow );
1070 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
1071 160 : nEndRow-nStartRow );
1072 :
1073 : SCSIZE nStartIndex;
1074 : SCSIZE nEndIndex;
1075 160 : Search( nStartRow+1, nStartIndex );
1076 160 : Search( nEndRow-1, nEndIndex );
1077 250 : for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1078 : {
1079 90 : pPattern = (ScPatternAttr*) pData[i].pPattern;
1080 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
1081 90 : nEndRow - std::min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1082 : // nDistBottom here always > 0
1083 : }
1084 :
1085 160 : pPattern = GetPattern( nEndRow );
1086 160 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
1087 : }
1088 176 : }
1089 :
1090 : //
1091 : // apply border
1092 : //
1093 :
1094 : // ApplyFrame - on an entry into the array
1095 :
1096 2854 : bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1097 : const SvxBoxInfoItem* pBoxInfoItem,
1098 : SCROW nStartRow, SCROW nEndRow,
1099 : bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
1100 : {
1101 : OSL_ENSURE( pBoxItem && pBoxInfoItem, "Missing line attributes!" );
1102 :
1103 2854 : const ScPatternAttr* pPattern = GetPattern( nStartRow );
1104 : const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1105 2854 : &pPattern->GetItemSet().Get( ATTR_BORDER );
1106 :
1107 : // right/bottom border set when connected together
1108 2854 : const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1109 2854 : if ( rMerge.GetColMerge() == nDistRight + 1 )
1110 0 : nDistRight = 0;
1111 2854 : if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1112 0 : nDistBottom = 0;
1113 :
1114 2854 : SvxBoxItem aNewFrame( *pOldFrame );
1115 2854 : bool bRTL=pDocument->IsLayoutRTL(nTab);
1116 : // fdo#37464 check if the sheet are RTL then replace right <=> left
1117 2854 : if (bRTL)
1118 : {
1119 0 : if( bLeft && nDistRight==0)
1120 : {
1121 0 : if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1122 : aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1123 0 : BOX_LINE_RIGHT );
1124 0 : if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1125 : aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1126 0 : BOX_LINE_LEFT );
1127 : }
1128 : else
1129 : {
1130 0 : if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1131 : aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1132 0 : BOX_LINE_RIGHT );
1133 0 : if ( bLeft ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1134 : aNewFrame.SetLine( bLeft ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1135 0 : BOX_LINE_LEFT );
1136 : }
1137 : }
1138 : else
1139 : {
1140 2854 : if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1141 : aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1142 1356 : BOX_LINE_LEFT );
1143 2854 : if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1144 : aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1145 1357 : BOX_LINE_RIGHT );
1146 : }
1147 2854 : if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1148 : aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1149 1749 : BOX_LINE_TOP );
1150 2854 : if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1151 : aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1152 1749 : BOX_LINE_BOTTOM );
1153 :
1154 2854 : if (aNewFrame == *pOldFrame)
1155 : {
1156 : // nothing to do
1157 629 : return false;
1158 : }
1159 : else
1160 : {
1161 2225 : SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1162 2225 : ApplyCacheArea( nStartRow, nEndRow, &aCache );
1163 :
1164 2225 : return true;
1165 2854 : }
1166 : }
1167 :
1168 :
1169 1721 : void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1170 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
1171 : {
1172 1721 : if (nStartRow == nEndRow)
1173 1040 : ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
1174 : else
1175 : {
1176 : ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1177 681 : true, nEndRow-nStartRow );
1178 :
1179 681 : if ( nEndRow > nStartRow+1 ) // inner part available?
1180 : {
1181 : SCSIZE nStartIndex;
1182 : SCSIZE nEndIndex;
1183 355 : Search( nStartRow+1, nStartIndex );
1184 355 : Search( nEndRow-1, nEndIndex );
1185 355 : SCROW nTmpStart = nStartRow+1;
1186 : SCROW nTmpEnd;
1187 1162 : for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1188 : {
1189 452 : nTmpEnd = std::min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1190 : bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1191 452 : bLeft, nDistRight, false, nEndRow-nTmpEnd );
1192 452 : nTmpStart = nTmpEnd+1;
1193 452 : if (bChanged)
1194 : {
1195 219 : Search(nTmpStart, i);
1196 219 : Search(nEndRow-1, nEndIndex);
1197 : }
1198 : else
1199 233 : i++;
1200 : }
1201 : }
1202 :
1203 681 : ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0 );
1204 : }
1205 1721 : }
1206 :
1207 : // Test if field contains specific attribute
1208 :
1209 11564256 : bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
1210 : {
1211 : SCSIZE nStartIndex;
1212 : SCSIZE nEndIndex;
1213 11564256 : Search( nRow1, nStartIndex );
1214 11564256 : Search( nRow2, nEndIndex );
1215 11564256 : bool bFound = false;
1216 :
1217 23304446 : for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1218 : {
1219 11740190 : const ScPatternAttr* pPattern = pData[i].pPattern;
1220 11740190 : if ( nMask & HASATTR_MERGED )
1221 : {
1222 : const ScMergeAttr* pMerge =
1223 12816 : (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1224 12816 : if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1225 11 : bFound = true;
1226 : }
1227 11740190 : if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1228 : {
1229 : const ScMergeFlagAttr* pMergeFlag =
1230 23855 : (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1231 23855 : if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1232 5 : bFound = true;
1233 23855 : if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1234 0 : bFound = true;
1235 23855 : if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1236 0 : bFound = true;
1237 : }
1238 11740190 : if ( nMask & HASATTR_LINES )
1239 : {
1240 : const SvxBoxItem* pBox =
1241 66491 : (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1242 66491 : if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1243 40 : bFound = true;
1244 : }
1245 11740190 : if ( nMask & HASATTR_SHADOW )
1246 : {
1247 : const SvxShadowItem* pShadow =
1248 66389 : (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1249 66389 : if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1250 0 : bFound = true;
1251 : }
1252 11740190 : if ( nMask & HASATTR_CONDITIONAL )
1253 : {
1254 : bool bContainsCondFormat =
1255 9554238 : !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1256 9554238 : if ( bContainsCondFormat )
1257 527 : bFound = true;
1258 : }
1259 11740190 : if ( nMask & HASATTR_PROTECTED )
1260 : {
1261 : const ScProtectionAttr* pProtect =
1262 10 : (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1263 10 : bool bFoundTemp = false;
1264 10 : if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1265 10 : bFoundTemp = true;
1266 :
1267 : bool bContainsCondFormat =
1268 10 : !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1269 10 : if ( bContainsCondFormat )
1270 : {
1271 0 : SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? pData[i-1].nRow + 1: 0 );
1272 0 : SCROW nRowEndCond = std::min<SCROW>( nRow2, pData[i].nRow );
1273 0 : bool bFoundCond = false;
1274 0 : for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond)
1275 : {
1276 0 : const SfxItemSet* pSet = pDocument->GetCondResult( nCol, nRowCond, nTab );
1277 :
1278 : const SfxPoolItem* pItem;
1279 0 : if( pSet && pSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SFX_ITEM_SET )
1280 : {
1281 0 : const ScProtectionAttr* pCondProtect = static_cast<const ScProtectionAttr*>(pItem);
1282 0 : if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() )
1283 0 : bFoundCond = true;
1284 : else
1285 0 : break;
1286 : }
1287 : else
1288 : {
1289 : // well it is not true that we found one
1290 : // but existing one + cell where conditional
1291 : // formatting does not remove it
1292 : // => we should use the existing protection settting
1293 0 : bFoundCond = bFoundTemp;
1294 : }
1295 : }
1296 0 : bFoundTemp = bFoundCond;
1297 : }
1298 :
1299 10 : if(bFoundTemp)
1300 10 : bFound = true;
1301 : }
1302 11740190 : if ( nMask & HASATTR_ROTATE )
1303 : {
1304 : const SfxInt32Item* pRotate =
1305 30472 : (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1306 : // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1307 : // (see ScPatternAttr::GetCellOrientation)
1308 30472 : sal_Int32 nAngle = pRotate->GetValue();
1309 30472 : if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1310 336 : bFound = true;
1311 : }
1312 11740190 : if ( nMask & HASATTR_NEEDHEIGHT )
1313 : {
1314 7101 : if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1315 0 : bFound = true;
1316 7101 : else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1317 62 : bFound = true;
1318 7039 : else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1319 7039 : GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1320 0 : bFound = true;
1321 :
1322 7039 : else if (!static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData().empty())
1323 0 : bFound = true;
1324 7039 : else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1325 0 : bFound = true;
1326 : }
1327 11740190 : if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1328 : {
1329 : const SvxShadowItem* pShadow =
1330 228 : (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1331 228 : SvxShadowLocation eLoc = pShadow->GetLocation();
1332 228 : if ( nMask & HASATTR_SHADOW_RIGHT )
1333 68 : if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1334 0 : bFound = true;
1335 228 : if ( nMask & HASATTR_SHADOW_DOWN )
1336 160 : if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1337 0 : bFound = true;
1338 : }
1339 11740190 : if ( nMask & HASATTR_RTL )
1340 : {
1341 : const SvxFrameDirectionItem& rDirection =
1342 0 : (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1343 0 : if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1344 0 : bFound = true;
1345 : }
1346 11740190 : if ( nMask & HASATTR_RIGHTORCENTER )
1347 : {
1348 : // called only if the sheet is LTR, so physical=logical alignment can be assumed
1349 : SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1350 2154439 : ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1351 2154439 : if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1352 120 : bFound = true;
1353 : }
1354 : }
1355 :
1356 11564256 : return bFound;
1357 : }
1358 :
1359 : // Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1360 5977 : bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1361 : SCCOL& rPaintCol, SCROW& rPaintRow,
1362 : bool bRefresh )
1363 : {
1364 : const ScPatternAttr* pPattern;
1365 : const ScMergeAttr* pItem;
1366 : SCSIZE nStartIndex;
1367 : SCSIZE nEndIndex;
1368 5977 : Search( nStartRow, nStartIndex );
1369 5977 : Search( nEndRow, nEndIndex );
1370 5977 : bool bFound = false;
1371 :
1372 13113 : for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1373 : {
1374 7136 : pPattern = pData[i].pPattern;
1375 7136 : pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1376 7136 : SCsCOL nCountX = pItem->GetColMerge();
1377 7136 : SCsROW nCountY = pItem->GetRowMerge();
1378 7136 : if (nCountX>1 || nCountY>1)
1379 : {
1380 32 : SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1381 32 : SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1382 32 : SCROW nMergeEndRow = nThisRow + nCountY - 1;
1383 32 : if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1384 17 : rPaintCol = nMergeEndCol;
1385 32 : if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1386 18 : rPaintRow = nMergeEndRow;
1387 32 : bFound = true;
1388 :
1389 32 : if (bRefresh)
1390 : {
1391 1 : if ( nMergeEndCol > nThisCol )
1392 1 : pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1393 2 : nTab, SC_MF_HOR );
1394 1 : if ( nMergeEndRow > nThisRow )
1395 : pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1396 1 : nTab, SC_MF_VER );
1397 1 : if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1398 : pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1399 1 : nTab, SC_MF_HOR | SC_MF_VER );
1400 :
1401 1 : Search( nThisRow, i ); // Data changed
1402 1 : Search( nStartRow, nStartIndex );
1403 1 : Search( nEndRow, nEndIndex );
1404 : }
1405 : }
1406 : }
1407 :
1408 5977 : return bFound;
1409 : }
1410 :
1411 :
1412 9941 : bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1413 : {
1414 9941 : bool bFound = false;
1415 : const ScPatternAttr* pPattern;
1416 : const ScMergeAttr* pItem;
1417 : SCSIZE nIndex;
1418 :
1419 9941 : Search( nStartRow, nIndex );
1420 9941 : SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1421 9941 : if (nThisStart < nStartRow)
1422 5322 : nThisStart = nStartRow;
1423 :
1424 31045 : while ( nThisStart <= nEndRow )
1425 : {
1426 11163 : SCROW nThisEnd = pData[nIndex].nRow;
1427 11163 : if (nThisEnd > nEndRow)
1428 7608 : nThisEnd = nEndRow;
1429 :
1430 11163 : pPattern = pData[nIndex].pPattern;
1431 11163 : pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1432 11163 : SCsCOL nCountX = pItem->GetColMerge();
1433 11163 : SCsROW nCountY = pItem->GetRowMerge();
1434 11163 : if (nCountX>1 || nCountY>1)
1435 : {
1436 : const ScMergeAttr* pAttr = (const ScMergeAttr*)
1437 0 : &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1438 : const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1439 0 : &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1440 :
1441 : OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
1442 :
1443 0 : SCCOL nThisCol = nCol;
1444 0 : SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1445 0 : SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1446 :
1447 : // ApplyAttr for areas
1448 :
1449 0 : for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1450 0 : pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1451 :
1452 0 : ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1453 0 : SfxItemSet* pSet = &pNewPattern->GetItemSet();
1454 0 : pSet->Put( *pFlagAttr );
1455 : pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1456 0 : nTab, *pNewPattern );
1457 0 : delete pNewPattern;
1458 :
1459 0 : Search( nThisEnd, nIndex ); // data changed
1460 : }
1461 :
1462 11163 : ++nIndex;
1463 11163 : if ( nIndex < nCount )
1464 1558 : nThisStart = pData[nIndex-1].nRow+1;
1465 : else
1466 9605 : nThisStart = MAXROW+1; // End
1467 : }
1468 :
1469 9941 : return bFound;
1470 : }
1471 :
1472 : // Remove field, but leave MergeFlags
1473 :
1474 0 : void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1475 : {
1476 0 : SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), true );
1477 0 : }
1478 :
1479 :
1480 0 : void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1481 : const ScPatternAttr* pWantedPattern, bool bDefault )
1482 : {
1483 : const ScPatternAttr* pOldPattern;
1484 : const ScMergeFlagAttr* pItem;
1485 :
1486 : SCSIZE nIndex;
1487 : SCROW nRow;
1488 : SCROW nThisRow;
1489 0 : bool bFirstUse = true;
1490 :
1491 0 : Search( nStartRow, nIndex );
1492 0 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1493 0 : while ( nThisRow <= nEndRow )
1494 : {
1495 0 : pOldPattern = pData[nIndex].pPattern;
1496 0 : if (pOldPattern != pWantedPattern) //! else-Zweig ?
1497 : {
1498 0 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1499 0 : nRow = pData[nIndex].nRow;
1500 0 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1501 0 : pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1502 :
1503 0 : if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1504 : {
1505 : // default-constructing a ScPatternAttr for DeleteArea doesn't work
1506 : // because it would have no cell style information.
1507 : // Instead, the document's GetDefPattern is copied. Since it is passed as
1508 : // pWantedPattern, no special treatment of default is needed here anymore.
1509 0 : ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
1510 0 : SfxItemSet* pSet = &pNewPattern->GetItemSet();
1511 0 : pSet->Put( *pItem );
1512 0 : SetPatternArea( nThisRow, nAttrRow, pNewPattern, true );
1513 0 : delete pNewPattern;
1514 : }
1515 : else
1516 : {
1517 0 : if ( !bDefault )
1518 : {
1519 0 : if (bFirstUse)
1520 0 : bFirstUse = false;
1521 : else
1522 : // it's in the pool
1523 0 : pDocument->GetPool()->Put( *pWantedPattern );
1524 : }
1525 0 : SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1526 : }
1527 :
1528 0 : Search( nThisRow, nIndex ); // data changed
1529 : }
1530 :
1531 0 : ++nIndex;
1532 0 : nThisRow = pData[nIndex-1].nRow+1;
1533 : }
1534 0 : }
1535 :
1536 :
1537 4498 : bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1538 : {
1539 : const ScPatternAttr* pOldPattern;
1540 :
1541 : sal_Int16 nOldValue;
1542 : SCSIZE nIndex;
1543 : SCROW nRow;
1544 : SCROW nThisRow;
1545 4498 : bool bChanged = false;
1546 :
1547 4498 : Search( nStartRow, nIndex );
1548 4498 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1549 4498 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1550 :
1551 15573 : while ( nThisRow <= nEndRow )
1552 : {
1553 6577 : pOldPattern = pData[nIndex].pPattern;
1554 6577 : nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1555 6577 : if ( (nOldValue | nFlags) != nOldValue )
1556 : {
1557 6539 : nRow = pData[nIndex].nRow;
1558 6539 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1559 6539 : ScPatternAttr aNewPattern(*pOldPattern);
1560 6539 : aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1561 6539 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1562 6539 : Search( nThisRow, nIndex ); // data changed
1563 6539 : bChanged = true;
1564 : }
1565 :
1566 6577 : ++nIndex;
1567 6577 : nThisRow = pData[nIndex-1].nRow+1;
1568 : }
1569 :
1570 4498 : return bChanged;
1571 : }
1572 :
1573 :
1574 23181 : bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1575 : {
1576 : const ScPatternAttr* pOldPattern;
1577 :
1578 : sal_Int16 nOldValue;
1579 : SCSIZE nIndex;
1580 : SCROW nRow;
1581 : SCROW nThisRow;
1582 23181 : bool bChanged = false;
1583 :
1584 23181 : Search( nStartRow, nIndex );
1585 23181 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1586 23181 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1587 :
1588 69925 : while ( nThisRow <= nEndRow )
1589 : {
1590 23563 : pOldPattern = pData[nIndex].pPattern;
1591 23563 : nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1592 23563 : if ( (nOldValue & ~nFlags) != nOldValue )
1593 : {
1594 278 : nRow = pData[nIndex].nRow;
1595 278 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1596 278 : ScPatternAttr aNewPattern(*pOldPattern);
1597 278 : aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1598 278 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1599 278 : Search( nThisRow, nIndex ); // data changed
1600 278 : bChanged = true;
1601 : }
1602 :
1603 23563 : ++nIndex;
1604 23563 : nThisRow = pData[nIndex-1].nRow+1;
1605 : }
1606 :
1607 23181 : return bChanged;
1608 : }
1609 :
1610 :
1611 5 : void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1612 : {
1613 : const ScPatternAttr* pOldPattern;
1614 :
1615 : SCSIZE nIndex;
1616 : SCROW nRow;
1617 : SCROW nThisRow;
1618 :
1619 5 : Search( nStartRow, nIndex );
1620 5 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1621 5 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1622 :
1623 15 : while ( nThisRow <= nEndRow )
1624 : {
1625 5 : pOldPattern = pData[nIndex].pPattern;
1626 5 : if ( pOldPattern->HasItemsSet( pWhich ) )
1627 : {
1628 0 : ScPatternAttr aNewPattern(*pOldPattern);
1629 0 : aNewPattern.ClearItems( pWhich );
1630 :
1631 0 : nRow = pData[nIndex].nRow;
1632 0 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1633 0 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1634 0 : Search( nThisRow, nIndex ); // data changed
1635 : }
1636 :
1637 5 : ++nIndex;
1638 5 : nThisRow = pData[nIndex-1].nRow+1;
1639 : }
1640 5 : }
1641 :
1642 :
1643 26 : void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1644 : {
1645 : SCSIZE nIndex;
1646 26 : Search( nStartRow, nIndex );
1647 26 : SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1648 26 : if (nThisStart < nStartRow) nThisStart = nStartRow;
1649 :
1650 78 : while ( nThisStart <= nEndRow )
1651 : {
1652 26 : const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1653 26 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1654 : const SfxPoolItem* pItem;
1655 :
1656 26 : bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SFX_ITEM_SET
1657 26 : || (((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT &&
1658 26 : ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_RIGHT ));
1659 26 : sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1660 26 : sal_uInt16 nNewValue = nOldValue;
1661 : //to keep Increment indent from running outside the cell1659
1662 26 : long nColWidth = (long)pDocument->GetColWidth(nCol,nTab);
1663 26 : if ( bIncrement )
1664 : {
1665 13 : if ( nNewValue < nColWidth-SC_INDENT_STEP )
1666 : {
1667 13 : nNewValue += SC_INDENT_STEP;
1668 13 : if ( nNewValue > nColWidth-SC_INDENT_STEP ) nNewValue = nColWidth-SC_INDENT_STEP;
1669 : }
1670 : }
1671 : else
1672 : {
1673 13 : if ( nNewValue > 0 )
1674 : {
1675 13 : if ( nNewValue > SC_INDENT_STEP )
1676 0 : nNewValue -= SC_INDENT_STEP;
1677 : else
1678 13 : nNewValue = 0;
1679 : }
1680 : }
1681 :
1682 26 : if ( bNeedJust || nNewValue != nOldValue )
1683 : {
1684 26 : SCROW nThisEnd = pData[nIndex].nRow;
1685 26 : SCROW nAttrRow = std::min( nThisEnd, nEndRow );
1686 26 : ScPatternAttr aNewPattern(*pOldPattern);
1687 26 : aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1688 26 : if ( bNeedJust )
1689 13 : aNewPattern.GetItemSet().Put(
1690 26 : SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1691 26 : SetPatternArea( nThisStart, nAttrRow, &aNewPattern, true );
1692 :
1693 26 : nThisStart = nThisEnd + 1;
1694 26 : Search( nThisStart, nIndex ); // data changed
1695 : }
1696 : else
1697 : {
1698 0 : nThisStart = pData[nIndex].nRow + 1;
1699 0 : ++nIndex;
1700 : }
1701 : }
1702 26 : }
1703 :
1704 :
1705 0 : SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
1706 : {
1707 0 : long nRet = nRow;
1708 0 : if (ValidRow(nRow))
1709 : {
1710 : SCSIZE nIndex;
1711 0 : Search(nRow, nIndex);
1712 0 : while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1713 0 : GetItem(ATTR_PROTECTION)).GetProtection())
1714 : {
1715 0 : if (bUp)
1716 : {
1717 0 : if (nIndex==0)
1718 0 : return -1; // not found
1719 0 : --nIndex;
1720 0 : nRet = pData[nIndex].nRow;
1721 : }
1722 : else
1723 : {
1724 0 : nRet = pData[nIndex].nRow+1;
1725 0 : ++nIndex;
1726 0 : if (nIndex>=nCount)
1727 0 : return MAXROW+1; // not found
1728 : }
1729 : }
1730 : }
1731 0 : return nRet;
1732 : }
1733 :
1734 3075072 : void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1735 : {
1736 3075072 : SCROW nStart = 0;
1737 3075072 : SCSIZE nPos = 0;
1738 9226340 : while (nPos < nCount)
1739 : {
1740 3076196 : SCROW nEnd = pData[nPos].nRow;
1741 3076196 : if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1742 : {
1743 898048 : rUsedRows.setTrue(nStart, nEnd);
1744 :
1745 898048 : if (bReset)
1746 : {
1747 0 : ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1748 0 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1749 : pNewPattern->SetStyleSheet( (ScStyleSheet*)
1750 0 : pDocument->GetStyleSheetPool()->
1751 0 : Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1752 : SFX_STYLE_FAMILY_PARA,
1753 0 : SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1754 0 : pData[nPos].pPattern = (const ScPatternAttr*)
1755 0 : &pDocument->GetPool()->Put(*pNewPattern);
1756 0 : delete pNewPattern;
1757 :
1758 0 : if (Concat(nPos))
1759 : {
1760 0 : Search(nStart, nPos);
1761 0 : --nPos; // because ++ at end
1762 : }
1763 : }
1764 : }
1765 3076196 : nStart = nEnd + 1;
1766 3076196 : ++nPos;
1767 : }
1768 3075072 : }
1769 :
1770 :
1771 0 : bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1772 : bool bGatherAllStyles ) const
1773 : {
1774 0 : bool bIsUsed = false;
1775 0 : SCSIZE nPos = 0;
1776 :
1777 0 : while ( nPos < nCount )
1778 : {
1779 0 : const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1780 0 : if ( pStyle )
1781 : {
1782 0 : pStyle->SetUsage( ScStyleSheet::USED );
1783 0 : if ( pStyle == &rStyle )
1784 : {
1785 0 : if ( !bGatherAllStyles )
1786 0 : return true;
1787 0 : bIsUsed = true;
1788 : }
1789 : }
1790 0 : nPos++;
1791 : }
1792 :
1793 0 : return bIsUsed;
1794 : }
1795 :
1796 :
1797 11 : bool ScAttrArray::IsEmpty() const
1798 : {
1799 11 : if (nCount == 1)
1800 : {
1801 11 : if ( pData[0].pPattern != pDocument->GetDefPattern() )
1802 0 : return false;
1803 : else
1804 11 : return true;
1805 : }
1806 : else
1807 0 : return false;
1808 : }
1809 :
1810 :
1811 997376 : bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1812 : {
1813 : OSL_ENSURE( nCount, "nCount == 0" );
1814 :
1815 997376 : bool bFound = false;
1816 997376 : SCSIZE nStart = 0;
1817 :
1818 : // Skip first entry if more than 1 row.
1819 : // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1820 :
1821 997376 : SCSIZE nVisStart = 1;
1822 2063501 : while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1823 68749 : ++nVisStart;
1824 997376 : if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1825 997275 : nStart = nVisStart;
1826 :
1827 1995526 : while ( nStart < nCount && !bFound )
1828 : {
1829 774 : if ( pData[nStart].pPattern->IsVisible() )
1830 : {
1831 766 : rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1832 766 : bFound = true;
1833 : }
1834 : else
1835 8 : ++nStart;
1836 : }
1837 :
1838 997376 : return bFound;
1839 : }
1840 :
1841 : // size (rows) of a range of attributes after cell content where the search is stopped
1842 : // (more than a default page size, 2*42 because it's as good as any number)
1843 :
1844 : const SCROW SC_VISATTR_STOP = 84;
1845 :
1846 1559709 : bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bFullFormattedArea ) const
1847 : {
1848 : OSL_ENSURE( nCount, "nCount == 0" );
1849 :
1850 : // #i30830# changed behavior:
1851 : // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1852 : // below the last content cell
1853 :
1854 1559709 : if ( nLastData == MAXROW )
1855 : {
1856 0 : rLastRow = MAXROW; // can't look for attributes below MAXROW
1857 0 : return true;
1858 : }
1859 :
1860 : // Quick check: last data row in or immediately preceding a run that is the
1861 : // last attribution down to the end, e.g. default style or column style.
1862 1559709 : SCSIZE nPos = nCount - 1;
1863 1559709 : SCROW nStartRow = (nPos ? pData[nPos-1].nRow + 1 : 0);
1864 1559709 : if (nStartRow <= nLastData + 1)
1865 : {
1866 1494705 : if (bFullFormattedArea && pData[nPos].pPattern->IsVisible())
1867 : {
1868 0 : rLastRow = pData[nPos].nRow;
1869 0 : return true;
1870 : }
1871 : else
1872 : {
1873 : // Ignore here a few rows if data happens to end within
1874 : // SC_VISATTR_STOP rows before MAXROW.
1875 1494705 : rLastRow = nLastData;
1876 1494705 : return false;
1877 : }
1878 : }
1879 :
1880 : // Find a run below last data row.
1881 65004 : bool bFound = false;
1882 65004 : Search( nLastData, nPos );
1883 132983 : while ( nPos < nCount )
1884 : {
1885 : // find range of visually equal formats
1886 67979 : SCSIZE nEndPos = nPos;
1887 400236 : while ( nEndPos < nCount-1 &&
1888 133653 : pData[nEndPos].pPattern->IsVisibleEqual( *pData[nEndPos+1].pPattern))
1889 130625 : ++nEndPos;
1890 67979 : SCROW nAttrStartRow = ( nPos > 0 ) ? ( pData[nPos-1].nRow + 1 ) : 0;
1891 67979 : if ( nAttrStartRow <= nLastData )
1892 65004 : nAttrStartRow = nLastData + 1;
1893 67979 : SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1894 67979 : if ( nAttrSize >= SC_VISATTR_STOP && !bFullFormattedArea )
1895 : break; // while, ignore this range and below
1896 2975 : else if ( pData[nEndPos].pPattern->IsVisible() )
1897 : {
1898 2851 : rLastRow = pData[nEndPos].nRow;
1899 2851 : bFound = true;
1900 : }
1901 2975 : nPos = nEndPos + 1;
1902 : }
1903 :
1904 65004 : return bFound;
1905 : }
1906 :
1907 :
1908 0 : bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1909 : {
1910 : SCSIZE nIndex;
1911 0 : Search( nStartRow, nIndex );
1912 0 : SCROW nThisStart = nStartRow;
1913 0 : bool bFound = false;
1914 0 : while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1915 : {
1916 0 : if ( pData[nIndex].pPattern->IsVisible() )
1917 0 : bFound = true;
1918 :
1919 0 : nThisStart = pData[nIndex].nRow + 1;
1920 0 : ++nIndex;
1921 : }
1922 :
1923 0 : return bFound;
1924 : }
1925 :
1926 :
1927 11932 : bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1928 : SCROW nStartRow, SCROW nEndRow ) const
1929 : {
1930 11932 : bool bEqual = true;
1931 11932 : SCSIZE nThisPos = 0;
1932 11932 : SCSIZE nOtherPos = 0;
1933 11932 : if ( nStartRow > 0 )
1934 : {
1935 0 : Search( nStartRow, nThisPos );
1936 0 : rOther.Search( nStartRow, nOtherPos );
1937 : }
1938 :
1939 24406 : while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1940 : {
1941 12279 : SCROW nThisRow = pData[nThisPos].nRow;
1942 12279 : SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1943 12279 : const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1944 12279 : const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1945 12624 : bEqual = ( pThisPattern == pOtherPattern ||
1946 12624 : pThisPattern->IsVisibleEqual(*pOtherPattern) );
1947 :
1948 12279 : if ( nThisRow >= nOtherRow )
1949 : {
1950 11973 : if ( nOtherRow >= nEndRow ) break;
1951 236 : ++nOtherPos;
1952 : }
1953 542 : if ( nThisRow <= nOtherRow )
1954 : {
1955 406 : if ( nThisRow >= nEndRow ) break;
1956 406 : ++nThisPos;
1957 : }
1958 : }
1959 :
1960 11932 : return bEqual;
1961 : }
1962 :
1963 :
1964 19446 : bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
1965 : {
1966 : // summarised with IsVisibleEqual
1967 :
1968 19446 : bool bEqual = true;
1969 19446 : SCSIZE nThisPos = 0;
1970 19446 : SCSIZE nOtherPos = 0;
1971 19446 : if ( nStartRow > 0 )
1972 : {
1973 0 : Search( nStartRow, nThisPos );
1974 0 : rOther.Search( nStartRow, nOtherPos );
1975 : }
1976 :
1977 38958 : while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1978 : {
1979 19476 : SCROW nThisRow = pData[nThisPos].nRow;
1980 19476 : SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1981 19476 : const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1982 19476 : const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1983 19476 : bEqual = ( pThisPattern == pOtherPattern );
1984 :
1985 19476 : if ( nThisRow >= nOtherRow )
1986 : {
1987 19440 : if ( nOtherRow >= nEndRow ) break;
1988 30 : ++nOtherPos;
1989 : }
1990 66 : if ( nThisRow <= nOtherRow )
1991 : {
1992 38 : if ( nThisRow >= nEndRow ) break;
1993 38 : ++nThisPos;
1994 : }
1995 : }
1996 :
1997 19446 : return bEqual;
1998 : }
1999 :
2000 :
2001 0 : bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2002 : {
2003 : // Horizontal aggregate are not allowed to be moved out; if whole summary,
2004 : // here is not recognized
2005 :
2006 0 : bool bTest = true;
2007 0 : if (!IsEmpty())
2008 : {
2009 0 : SCSIZE nIndex = 0;
2010 0 : if ( nStartRow > 0 )
2011 0 : Search( nStartRow, nIndex );
2012 :
2013 0 : for ( ; nIndex < nCount; nIndex++ )
2014 : {
2015 0 : if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2016 0 : GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2017 : {
2018 0 : bTest = false; // may not be pushed out
2019 0 : break;
2020 : }
2021 0 : if ( pData[nIndex].nRow >= nEndRow ) // end of range
2022 0 : break;
2023 : }
2024 : }
2025 0 : return bTest;
2026 : }
2027 :
2028 :
2029 9221 : bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2030 : {
2031 : // if 1st row pushed out is vertically overlapped, summary would be broken
2032 :
2033 : // MAXROW + 1 - nSize = 1st row pushed out
2034 :
2035 9221 : SCSIZE nFirstLost = nCount-1;
2036 18442 : while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2037 0 : --nFirstLost;
2038 :
2039 18442 : if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2040 9221 : GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2041 0 : return false;
2042 :
2043 9221 : return true;
2044 : }
2045 :
2046 :
2047 9221 : void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2048 : {
2049 9221 : if (!pData)
2050 9221 : return;
2051 :
2052 9221 : SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2053 : SCSIZE nIndex;
2054 9221 : Search( nSearch, nIndex );
2055 :
2056 : // set ScMergeAttr may not be extended (so behind delete again)
2057 :
2058 9221 : bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2059 :
2060 9221 : SCSIZE nRemove = 0;
2061 : SCSIZE i;
2062 9226 : for (i = nIndex; i < nCount-1; i++)
2063 : {
2064 5 : SCROW nNew = pData[i].nRow + nSize;
2065 5 : if ( nNew >= MAXROW ) // at end?
2066 : {
2067 0 : nNew = MAXROW;
2068 0 : if (!nRemove)
2069 0 : nRemove = i+1; // remove the following?
2070 : }
2071 5 : pData[i].nRow = nNew;
2072 : }
2073 :
2074 : // Remove entries at end ?
2075 :
2076 9221 : if (nRemove && nRemove < nCount)
2077 0 : DeleteRange( nRemove, nCount-1 );
2078 :
2079 9221 : if (bDoMerge) // extensively repair (again) ScMergeAttr
2080 : {
2081 : // ApplyAttr for areas
2082 :
2083 0 : const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2084 0 : for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2085 0 : pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2086 :
2087 : // reply inserts in this area not summarized
2088 : }
2089 :
2090 : // Don't duplicate the merge flags in the inserted row.
2091 : // #i108488# SC_MF_SCENARIO has to be allowed.
2092 9221 : RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2093 : }
2094 :
2095 :
2096 8199 : void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2097 : {
2098 8199 : bool bFirst=true;
2099 8199 : SCSIZE nStartIndex = 0;
2100 8199 : SCSIZE nEndIndex = 0;
2101 : SCSIZE i;
2102 :
2103 8212 : for ( i = 0; i < nCount-1; i++)
2104 13 : if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2105 : {
2106 3 : if (bFirst)
2107 : {
2108 3 : nStartIndex = i;
2109 3 : bFirst = false;
2110 : }
2111 3 : nEndIndex = i;
2112 : }
2113 8199 : if (!bFirst)
2114 : {
2115 : SCROW nStart;
2116 3 : if (nStartIndex==0)
2117 0 : nStart = 0;
2118 : else
2119 3 : nStart = pData[nStartIndex-1].nRow + 1;
2120 :
2121 3 : if (nStart < nStartRow)
2122 : {
2123 1 : pData[nStartIndex].nRow = nStartRow - 1;
2124 1 : ++nStartIndex;
2125 : }
2126 3 : if (nEndIndex >= nStartIndex)
2127 : {
2128 2 : DeleteRange( nStartIndex, nEndIndex );
2129 2 : if (nStartIndex > 0)
2130 2 : if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2131 2 : DeleteRange( nStartIndex-1, nStartIndex-1 );
2132 : }
2133 : }
2134 8208 : for (i = 0; i < nCount-1; i++)
2135 9 : if (pData[i].nRow >= nStartRow)
2136 0 : pData[i].nRow -= nSize;
2137 :
2138 : // Below does not follow the pattern to detect pressure ranges;
2139 : // instead, only remove merge flags.
2140 8199 : RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2141 8199 : }
2142 :
2143 :
2144 4 : void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2145 : {
2146 4 : ScDocumentPool* pDocPool = pDocument->GetPool();
2147 8 : for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2148 4 : pDocPool->Remove(*pData[i].pPattern);
2149 :
2150 4 : memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2151 4 : nCount -= nEndIndex-nStartIndex+1;
2152 4 : }
2153 :
2154 :
2155 9941 : void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2156 : {
2157 9941 : RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
2158 :
2159 9941 : if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2160 9941 : SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2161 : else
2162 0 : DeleteAreaSafe( nStartRow, nEndRow ); // leave merge flags
2163 9941 : }
2164 :
2165 :
2166 94 : void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2167 : {
2168 94 : const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2169 : const ScPatternAttr* pOldPattern;
2170 :
2171 : SCSIZE nIndex;
2172 : SCROW nRow;
2173 : SCROW nThisRow;
2174 :
2175 94 : Search( nStartRow, nIndex );
2176 94 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2177 94 : if (nThisRow < nStartRow) nThisRow = nStartRow;
2178 :
2179 308 : while ( nThisRow <= nEndRow )
2180 : {
2181 120 : pOldPattern = pData[nIndex].pPattern;
2182 :
2183 120 : if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
2184 : {
2185 22 : nRow = pData[nIndex].nRow;
2186 22 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
2187 :
2188 22 : ScPatternAttr aNewPattern(*pOldPattern);
2189 22 : SfxItemSet& rSet = aNewPattern.GetItemSet();
2190 1254 : for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2191 1232 : if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2192 1188 : rSet.ClearItem(nId);
2193 :
2194 22 : if ( aNewPattern == *pDefPattern )
2195 20 : SetPatternArea( nThisRow, nAttrRow, pDefPattern, false );
2196 : else
2197 2 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
2198 :
2199 22 : Search( nThisRow, nIndex ); // data changed
2200 : }
2201 :
2202 120 : ++nIndex;
2203 120 : nThisRow = pData[nIndex-1].nRow+1;
2204 : }
2205 94 : }
2206 :
2207 :
2208 : // move within a document
2209 :
2210 6093 : void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2211 : {
2212 6093 : SCROW nStart = nStartRow;
2213 12313 : for (SCSIZE i = 0; i < nCount; i++)
2214 : {
2215 6220 : if ((pData[i].nRow >= nStartRow) && ((i==0) ? true : pData[i-1].nRow < nEndRow))
2216 : {
2217 : // copy (bPutToPool=TRUE)
2218 12186 : rAttrArray.SetPatternArea( nStart, std::min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2219 12186 : pData[i].pPattern, true );
2220 : }
2221 6220 : nStart = std::max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2222 : }
2223 6093 : DeleteArea(nStartRow, nEndRow);
2224 6093 : }
2225 :
2226 :
2227 : // copy between documents (Clipboard)
2228 :
2229 46398 : void ScAttrArray::CopyArea(
2230 : SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, sal_Int16 nStripFlags) const
2231 : {
2232 46398 : nStartRow -= nDy; // Source
2233 46398 : nEndRow -= nDy;
2234 :
2235 46398 : SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2236 46398 : SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2237 :
2238 46398 : ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2239 46398 : ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2240 46398 : bool bSamePool = (pSourceDocPool==pDestDocPool);
2241 :
2242 95882 : for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2243 : {
2244 49484 : if (pData[i].nRow >= nStartRow)
2245 : {
2246 48306 : const ScPatternAttr* pOldPattern = pData[i].pPattern;
2247 : const ScPatternAttr* pNewPattern;
2248 :
2249 48306 : if (IsDefaultItem( pOldPattern ))
2250 : {
2251 : // default: nothing changed
2252 :
2253 : pNewPattern = (const ScPatternAttr*)
2254 44690 : &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2255 : }
2256 3616 : else if ( nStripFlags )
2257 : {
2258 36 : ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2259 36 : sal_Int16 nNewFlags = 0;
2260 36 : if ( nStripFlags != SC_MF_ALL )
2261 0 : nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2262 0 : GetValue() & ~nStripFlags;
2263 :
2264 36 : if ( nNewFlags )
2265 0 : pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2266 : else
2267 36 : pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2268 :
2269 36 : if (bSamePool)
2270 36 : pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2271 : else
2272 0 : pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2273 36 : delete pTmpPattern;
2274 : }
2275 : else
2276 : {
2277 3580 : if (bSamePool)
2278 3573 : pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2279 : else
2280 7 : pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2281 : }
2282 :
2283 : rAttrArray.SetPatternArea(nDestStart,
2284 48306 : std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2285 : }
2286 :
2287 : // when pasting from clipboard and skipping filtered rows, the adjusted
2288 : // end position can be negative
2289 49484 : nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2290 : }
2291 46398 : }
2292 :
2293 :
2294 : // leave flags
2295 : // summarized with CopyArea
2296 :
2297 90 : void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2298 : {
2299 90 : nStartRow -= nDy; // Source
2300 90 : nEndRow -= nDy;
2301 :
2302 90 : SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2303 90 : SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2304 :
2305 90 : if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2306 : {
2307 90 : CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2308 180 : return;
2309 : }
2310 :
2311 0 : ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2312 0 : ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2313 0 : bool bSamePool = (pSourceDocPool==pDestDocPool);
2314 :
2315 0 : for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2316 : {
2317 0 : if (pData[i].nRow >= nStartRow)
2318 : {
2319 0 : const ScPatternAttr* pOldPattern = pData[i].pPattern;
2320 : const ScPatternAttr* pNewPattern;
2321 :
2322 0 : if (bSamePool)
2323 0 : pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2324 : else
2325 0 : pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2326 :
2327 : rAttrArray.SetPatternAreaSafe(nDestStart,
2328 0 : std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, false);
2329 : }
2330 :
2331 : // when pasting from clipboard and skipping filtered rows, the adjusted
2332 : // end position can be negative
2333 0 : nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2334 : }
2335 : }
2336 :
2337 :
2338 0 : SCsROW ScAttrArray::SearchStyle(
2339 : SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
2340 : const ScMarkArray* pMarkArray) const
2341 : {
2342 0 : bool bFound = false;
2343 :
2344 0 : if (pMarkArray)
2345 : {
2346 0 : nRow = pMarkArray->GetNextMarked( nRow, bUp );
2347 0 : if (!ValidRow(nRow))
2348 0 : return nRow;
2349 : }
2350 :
2351 : SCSIZE nIndex;
2352 0 : Search(nRow, nIndex);
2353 0 : const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2354 :
2355 0 : while (nIndex < nCount && !bFound)
2356 : {
2357 0 : if (pPattern->GetStyleSheet() == pSearchStyle)
2358 : {
2359 0 : if (pMarkArray)
2360 : {
2361 0 : nRow = pMarkArray->GetNextMarked( nRow, bUp );
2362 0 : SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2363 0 : if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2364 0 : bFound = true;
2365 : }
2366 : else
2367 0 : bFound = true;
2368 : }
2369 :
2370 0 : if (!bFound)
2371 : {
2372 0 : if (bUp)
2373 : {
2374 0 : if (nIndex==0)
2375 : {
2376 0 : nIndex = nCount;
2377 0 : nRow = -1;
2378 : }
2379 : else
2380 : {
2381 0 : --nIndex;
2382 0 : nRow = pData[nIndex].nRow;
2383 0 : pPattern = pData[nIndex].pPattern;
2384 : }
2385 : }
2386 : else
2387 : {
2388 0 : nRow = pData[nIndex].nRow+1;
2389 0 : ++nIndex;
2390 0 : if (nIndex<nCount)
2391 0 : pPattern = pData[nIndex].pPattern;
2392 : }
2393 : }
2394 : }
2395 :
2396 : OSL_ENSURE( bFound || !ValidRow(nRow), "Internal failure in in ScAttrArray::SearchStyle" );
2397 :
2398 0 : return nRow;
2399 : }
2400 :
2401 :
2402 0 : bool ScAttrArray::SearchStyleRange(
2403 : SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
2404 : const ScMarkArray* pMarkArray) const
2405 : {
2406 0 : SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2407 0 : if (ValidRow(nStartRow))
2408 : {
2409 : SCSIZE nIndex;
2410 0 : Search(nStartRow,nIndex);
2411 :
2412 0 : rRow = nStartRow;
2413 0 : if (bUp)
2414 : {
2415 0 : if (nIndex>0)
2416 0 : rEndRow = pData[nIndex-1].nRow + 1;
2417 : else
2418 0 : rEndRow = 0;
2419 0 : if (pMarkArray)
2420 : {
2421 0 : SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2422 0 : if (nMarkEnd>rEndRow)
2423 0 : rEndRow = nMarkEnd;
2424 : }
2425 : }
2426 : else
2427 : {
2428 0 : rEndRow = pData[nIndex].nRow;
2429 0 : if (pMarkArray)
2430 : {
2431 0 : SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2432 0 : if (nMarkEnd<rEndRow)
2433 0 : rEndRow = nMarkEnd;
2434 : }
2435 : }
2436 :
2437 0 : return true;
2438 : }
2439 : else
2440 0 : return false;
2441 93 : }
2442 :
2443 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|