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