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