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