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