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 2458624 : ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
55 : nCol( nNewCol ),
56 : nTab( nNewTab ),
57 : pDocument( pDoc ),
58 : nCount(1),
59 : nLimit(1),
60 2458624 : pData(new ScAttrEntry[1])
61 : {
62 2458624 : pData[0].nRow = MAXROW;
63 2458624 : pData[0].pPattern = pDocument->GetDefPattern(); // no put
64 2458624 : }
65 :
66 2437120 : ScAttrArray::~ScAttrArray()
67 : {
68 : #if OSL_DEBUG_LEVEL > 1
69 : TestData();
70 : #endif
71 :
72 2437120 : ScDocumentPool* pDocPool = pDocument->GetPool();
73 5016800 : for (SCSIZE i=0; i<nCount; i++)
74 2579680 : pDocPool->Remove(*pData[i].pPattern);
75 :
76 2437120 : delete[] pData;
77 2437120 : }
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 56294 : void ScAttrArray::Reset( const ScPatternAttr* pPattern )
108 : {
109 56294 : ScDocumentPool* pDocPool = pDocument->GetPool();
110 56294 : ScAddress aAdrStart( nCol, 0, nTab );
111 56294 : ScAddress aAdrEnd ( nCol, 0, nTab );
112 :
113 112590 : for (SCSIZE i=0; i<nCount; i++)
114 : {
115 : // ensure that attributing changes text width of cell
116 56296 : const ScPatternAttr* pOldPattern = pData[i].pPattern;
117 : bool bNumFormatChanged;
118 56296 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
119 56296 : pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
120 : {
121 0 : aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
122 0 : aAdrEnd .SetRow( pData[i].nRow );
123 0 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
124 : }
125 56296 : pDocPool->Remove(*pOldPattern);
126 : }
127 56294 : delete[] pData;
128 :
129 56294 : if (pDocument->IsStreamValid(nTab))
130 0 : pDocument->SetStreamValid(nTab, false);
131 :
132 56294 : nCount = nLimit = 1;
133 56294 : pData = new ScAttrEntry[1];
134 56294 : const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pDocPool->Put(*pPattern) );
135 56294 : pData[0].nRow = MAXROW;
136 56294 : pData[0].pPattern = pNewPattern;
137 56294 : }
138 :
139 113425 : bool ScAttrArray::Concat(SCSIZE nPos)
140 : {
141 113425 : bool bRet = false;
142 113425 : if (nPos < nCount)
143 : {
144 113425 : if (nPos > 0)
145 : {
146 116 : if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
147 : {
148 5 : pData[nPos - 1].nRow = pData[nPos].nRow;
149 5 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
150 5 : memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
151 5 : pData[nCount - 1].pPattern = NULL;
152 5 : pData[nCount - 1].nRow = 0;
153 5 : nCount--;
154 5 : nPos--;
155 5 : bRet = true;
156 : }
157 : }
158 113425 : if (nPos + 1 < nCount)
159 : {
160 1064 : if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
161 : {
162 15 : pData[nPos].nRow = pData[nPos + 1].nRow;
163 15 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
164 15 : memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
165 15 : pData[nCount - 1].pPattern = NULL;
166 15 : pData[nCount - 1].nRow = 0;
167 15 : nCount--;
168 15 : bRet = true;
169 : }
170 : }
171 : }
172 113425 : return bRet;
173 : }
174 :
175 33814026 : bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
176 : {
177 33814026 : long nHi = static_cast<long>(nCount) - 1;
178 33814026 : long i = 0;
179 33814026 : bool bFound = (nCount == 1);
180 33814026 : long nLo = 0;
181 33814026 : long nStartRow = 0;
182 88864297 : while ( !bFound && nLo <= nHi )
183 : {
184 21236245 : i = (nLo + nHi) / 2;
185 21236245 : if (i > 0)
186 10949684 : nStartRow = (long) pData[i - 1].nRow;
187 : else
188 10286561 : nStartRow = -1;
189 21236245 : const long nEndRow = (long) pData[i].nRow;
190 21236245 : if (nEndRow < (long) nRow)
191 416493 : nLo = ++i;
192 : else
193 20819752 : if (nStartRow >= (long) nRow)
194 10319608 : nHi = --i;
195 : else
196 10500144 : bFound = true;
197 : }
198 :
199 33814026 : if (bFound)
200 33805709 : nIndex=(SCSIZE)i;
201 : else
202 8317 : nIndex=0;
203 33814026 : return bFound;
204 : }
205 :
206 135020 : const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
207 : {
208 : SCSIZE i;
209 135020 : if (Search( nRow, i ))
210 135020 : return pData[i].pPattern;
211 : else
212 0 : return NULL;
213 : }
214 :
215 6411 : const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
216 : SCROW& rEndRow, SCROW nRow ) const
217 : {
218 : SCSIZE nIndex;
219 6411 : if ( Search( nRow, nIndex ) )
220 : {
221 6411 : if ( nIndex > 0 )
222 63 : rStartRow = pData[nIndex-1].nRow + 1;
223 : else
224 6348 : rStartRow = 0;
225 6411 : rEndRow = pData[nIndex].nRow;
226 6411 : return pData[nIndex].pPattern;
227 : }
228 0 : return NULL;
229 : }
230 :
231 4343 : void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
232 : {
233 4343 : if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
234 0 : return;
235 :
236 4343 : if(nEndRow < nStartRow)
237 0 : return;
238 :
239 4343 : SCROW nTempStartRow = nStartRow;
240 4343 : SCROW nTempEndRow = nEndRow;
241 :
242 4343 : do
243 : {
244 4343 : const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
245 :
246 4343 : boost::scoped_ptr<ScPatternAttr> pNewPattern;
247 4343 : if(pPattern)
248 : {
249 4343 : pNewPattern.reset( new ScPatternAttr(*pPattern) );
250 : SCROW nPatternStartRow;
251 : SCROW nPatternEndRow;
252 4343 : GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
253 :
254 4343 : nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
255 4343 : const SfxPoolItem* pItem = NULL;
256 4343 : pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
257 4343 : std::vector< sal_uInt32 > aCondFormatData;
258 4343 : if(pItem)
259 2050 : aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
260 4343 : aCondFormatData.push_back(nIndex);
261 :
262 8686 : ScCondFormatItem aItem;
263 4343 : aItem.SetCondFormatData( aCondFormatData );
264 8686 : pNewPattern->GetItemSet().Put( aItem );
265 : }
266 : else
267 : {
268 0 : pNewPattern.reset( new ScPatternAttr( pDocument->GetPool() ) );
269 0 : ScCondFormatItem aItem;
270 0 : aItem.AddCondFormatData(nIndex);
271 0 : pNewPattern->GetItemSet().Put( aItem );
272 0 : nTempEndRow = nEndRow;
273 : }
274 :
275 4343 : SetPatternArea( nTempStartRow, nTempEndRow, pNewPattern.get(), true );
276 4343 : nTempStartRow = nTempEndRow + 1;
277 : }
278 4343 : while(nTempEndRow < nEndRow);
279 :
280 : }
281 :
282 2065 : void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
283 : {
284 2065 : if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
285 0 : return;
286 :
287 2065 : if(nEndRow < nStartRow)
288 0 : return;
289 :
290 2065 : SCROW nTempStartRow = nStartRow;
291 2065 : SCROW nTempEndRow = nEndRow;
292 :
293 2065 : do
294 : {
295 2065 : const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
296 :
297 2065 : if(pPattern)
298 : {
299 2065 : ScPatternAttr aPattern( *pPattern );
300 : SCROW nPatternStartRow;
301 : SCROW nPatternEndRow;
302 2065 : GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
303 :
304 2065 : nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
305 2065 : const SfxPoolItem* pItem = NULL;
306 2065 : pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
307 2065 : if(pItem)
308 : {
309 2 : std::vector< sal_uInt32 > aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
310 2 : std::vector<sal_uInt32>::iterator itr = std::find(aCondFormatData.begin(), aCondFormatData.end(), nIndex);
311 2 : if(itr != aCondFormatData.end() || nIndex == 0)
312 : {
313 2 : ScCondFormatItem aItem;
314 2 : if (nIndex == 0)
315 2 : aCondFormatData.clear();
316 : else
317 0 : aCondFormatData.erase(itr);
318 2 : aItem.SetCondFormatData( aCondFormatData );
319 2 : aPattern.GetItemSet().Put( aItem );
320 2 : SetPatternArea( nTempStartRow, nTempEndRow, &aPattern, true );
321 2 : }
322 2065 : }
323 : }
324 : else
325 : {
326 0 : return;
327 : }
328 :
329 2065 : nTempStartRow = nTempEndRow + 1;
330 : }
331 2065 : while(nTempEndRow < nEndRow);
332 :
333 : }
334 :
335 3041 : void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool )
336 : {
337 3041 : SetPatternArea( nRow, nRow, pPattern, bPutToPool );
338 3041 : }
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 172495 : void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
387 : bool bPutToPool, ScEditDataArray* pDataArray )
388 : {
389 172495 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
390 : {
391 172495 : if (bPutToPool)
392 29058 : pPattern = static_cast<const ScPatternAttr*>(&pDocument->GetPool()->Put(*pPattern));
393 :
394 172495 : if ((nStartRow == 0) && (nEndRow == MAXROW))
395 56294 : Reset(pPattern);
396 : else
397 : {
398 116201 : SCSIZE nNeeded = nCount + 2;
399 116201 : if ( nLimit < nNeeded )
400 : {
401 66355 : nLimit += SC_ATTRARRAY_DELTA;
402 66355 : if ( nLimit < nNeeded )
403 0 : nLimit = nNeeded;
404 66355 : ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
405 66355 : memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
406 66355 : delete[] pData;
407 66355 : pData = pNewData;
408 : }
409 :
410 116201 : ScAddress aAdrStart( nCol, 0, nTab );
411 116201 : ScAddress aAdrEnd ( nCol, 0, nTab );
412 :
413 116201 : SCSIZE ni = 0; // number of entries in beginning
414 116201 : SCSIZE nx = 0; // track position
415 116201 : SCROW ns = 0; // start row of track position
416 116201 : if ( nStartRow > 0 )
417 : {
418 : // skip beginning
419 : SCSIZE nIndex;
420 101616 : Search( nStartRow, nIndex );
421 101616 : ni = nIndex;
422 :
423 101616 : if ( ni > 0 )
424 : {
425 20514 : nx = ni;
426 20514 : 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 349890 : while ( ns <= nEndRow )
433 : {
434 117488 : const SfxItemSet& rNewSet = pPattern->GetItemSet();
435 117488 : const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
436 :
437 : bool bNumFormatChanged;
438 117488 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
439 : rNewSet, rOldSet ) )
440 : {
441 9603 : aAdrStart.SetRow( std::max(nStartRow,ns) );
442 9603 : aAdrEnd .SetRow( std::min(nEndRow,pData[nx].nRow) );
443 9603 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
444 : }
445 117488 : ns = pData[nx].nRow + 1;
446 117488 : nx++;
447 : }
448 :
449 : // continue modifying data array
450 :
451 : SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
452 116201 : bool bCombined = false;
453 116201 : bool bSplit = false;
454 116201 : if ( nStartRow > 0 )
455 : {
456 101616 : nInsert = MAXROWCOUNT;
457 101616 : if ( pData[ni].pPattern != pPattern )
458 : {
459 23518 : 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 4740 : if ( pData[ni].nRow > nEndRow )
463 3901 : bSplit = true;
464 4740 : ni++;
465 4740 : nInsert = ni;
466 : }
467 18778 : else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
468 18778 : nInsert = ni;
469 : }
470 101616 : if ( ni > 0 && pData[ni-1].pPattern == pPattern )
471 : { // combine
472 2031 : pData[ni-1].nRow = nEndRow;
473 2031 : nInsert = MAXROWCOUNT;
474 2031 : bCombined = true;
475 : }
476 : }
477 : else
478 14585 : nInsert = 0;
479 :
480 116201 : SCSIZE nj = ni; // stop position of range to replace
481 250121 : while ( nj < nCount && pData[nj].nRow <= nEndRow )
482 17719 : nj++;
483 116201 : if ( !bSplit )
484 : {
485 112300 : if ( nj < nCount && pData[nj].pPattern == pPattern )
486 : { // combine
487 86940 : if ( ni > 0 )
488 : {
489 1005 : if ( pData[ni-1].pPattern == pPattern )
490 : { // adjacent entries
491 879 : pData[ni-1].nRow = pData[nj].nRow;
492 879 : nj++;
493 : }
494 126 : else if ( ni == nInsert )
495 51 : pData[ni-1].nRow = nStartRow - 1; // shrink
496 : }
497 86940 : nInsert = MAXROWCOUNT;
498 86940 : bCombined = true;
499 : }
500 25360 : else if ( ni > 0 && ni == nInsert )
501 17535 : pData[ni-1].nRow = nStartRow - 1; // shrink
502 : }
503 116201 : ScDocumentPool* pDocPool = pDocument->GetPool();
504 116201 : if ( bSplit )
505 : { // duplicate splitted entry in pool
506 3901 : pDocPool->Put( *pData[ni-1].pPattern );
507 : }
508 116201 : if ( ni < nj )
509 : { // remove middle entries
510 35041 : for ( SCSIZE nk=ni; nk<nj; nk++)
511 : { // remove entries from pool
512 18598 : pDocPool->Remove( *pData[nk].pPattern );
513 : }
514 16443 : if ( !bCombined )
515 : { // replace one entry
516 14955 : pData[ni].nRow = nEndRow;
517 14955 : pData[ni].pPattern = pPattern;
518 14955 : ni++;
519 14955 : nInsert = MAXROWCOUNT;
520 : }
521 16443 : if ( ni < nj )
522 : { // remove entries
523 1495 : memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
524 1495 : nCount -= nj - ni;
525 : }
526 : }
527 :
528 116201 : if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
529 : { // insert or append new entry
530 13154 : if ( nInsert <= nCount )
531 : {
532 13154 : if ( !bSplit )
533 9253 : memmove( pData + nInsert + 1, pData + nInsert,
534 18506 : (nCount - nInsert) * sizeof(ScAttrEntry) );
535 : else
536 : {
537 3901 : memmove( pData + nInsert + 2, pData + nInsert,
538 7802 : (nCount - nInsert) * sizeof(ScAttrEntry) );
539 3901 : pData[nInsert+1] = pData[nInsert-1];
540 3901 : nCount++;
541 : }
542 : }
543 13154 : if ( nInsert )
544 9320 : pData[nInsert-1].nRow = nStartRow - 1;
545 13154 : pData[nInsert].nRow = nEndRow;
546 13154 : pData[nInsert].pPattern = pPattern;
547 :
548 : // Remove character attributes from these cells if the pattern
549 : // is applied during normal session.
550 13154 : if (pDataArray)
551 0 : RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
552 :
553 13154 : nCount++;
554 : }
555 :
556 116201 : if (pDocument->IsStreamValid(nTab))
557 6 : pDocument->SetStreamValid(nTab, false);
558 : }
559 : }
560 :
561 : #if OSL_DEBUG_LEVEL > 1
562 : TestData();
563 : #endif
564 172495 : }
565 :
566 404382 : void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
567 : {
568 404382 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
569 : {
570 : SCSIZE nPos;
571 404382 : SCROW nStart=0;
572 404382 : if (!Search( nStartRow, nPos ))
573 : {
574 : OSL_FAIL("Search Failure");
575 404382 : return;
576 : }
577 :
578 404382 : ScAddress aAdrStart( nCol, 0, nTab );
579 404382 : ScAddress aAdrEnd ( nCol, 0, nTab );
580 :
581 404519 : do
582 : {
583 404519 : const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
584 404519 : boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern));
585 404519 : pNewPattern->SetStyleSheet(pStyle);
586 404519 : SCROW nY1 = nStart;
587 404519 : SCROW nY2 = pData[nPos].nRow;
588 404519 : nStart = pData[nPos].nRow + 1;
589 :
590 404519 : if ( *pNewPattern == *pOldPattern )
591 : {
592 : // keep the original pattern (might be default)
593 : // pNewPattern is deleted below
594 402413 : nPos++;
595 : }
596 2106 : else if ( nY1 < nStartRow || nY2 > nEndRow )
597 : {
598 1998 : if (nY1 < nStartRow) nY1=nStartRow;
599 1998 : if (nY2 > nEndRow) nY2=nEndRow;
600 1998 : SetPatternArea( nY1, nY2, pNewPattern.get(), true );
601 1998 : 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 108 : const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
608 108 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
609 :
610 : bool bNumFormatChanged;
611 108 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
612 : rNewSet, rOldSet ) )
613 : {
614 4 : aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
615 4 : aAdrEnd .SetRow( pData[nPos].nRow );
616 4 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
617 : }
618 :
619 108 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
620 108 : pData[nPos].pPattern = static_cast<const ScPatternAttr*>(
621 108 : &pDocument->GetPool()->Put(*pNewPattern));
622 108 : if (Concat(nPos))
623 0 : Search(nStart, nPos);
624 : else
625 108 : nPos++;
626 404519 : }
627 : }
628 137 : while ((nStart <= nEndRow) && (nPos < nCount));
629 :
630 404382 : 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 : const_cast<SvxBorderLine*>(dest)->SetColor((c)); \
644 : }
645 :
646 : #define SET_LINE(dest,src) \
647 : if ((dest)) \
648 : { \
649 : SvxBorderLine* pCast = const_cast<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, SvxBoxItemLine::TOP );
699 0 : if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, SvxBoxItemLine::BOTTOM );
700 0 : if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, SvxBoxItemLine::LEFT );
701 0 : if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, SvxBoxItemLine::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 124069 : void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
783 : {
784 : #if OSL_DEBUG_LEVEL > 1
785 : TestData();
786 : #endif
787 :
788 124069 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
789 : {
790 : SCSIZE nPos;
791 124069 : SCROW nStart=0;
792 124069 : if (!Search( nStartRow, nPos ))
793 : {
794 : OSL_FAIL("Search Failure");
795 124069 : return;
796 : }
797 :
798 124069 : ScAddress aAdrStart( nCol, 0, nTab );
799 124069 : ScAddress aAdrEnd ( nCol, 0, nTab );
800 :
801 124133 : do
802 : {
803 124133 : const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
804 124133 : const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pCache->ApplyTo( *pOldPattern, true ) );
805 124133 : ScDocumentPool::CheckRef( *pOldPattern );
806 124133 : ScDocumentPool::CheckRef( *pNewPattern );
807 124133 : if (pNewPattern != pOldPattern)
808 : {
809 122466 : SCROW nY1 = nStart;
810 122466 : SCROW nY2 = pData[nPos].nRow;
811 122466 : nStart = pData[nPos].nRow + 1;
812 :
813 122466 : if ( nY1 < nStartRow || nY2 > nEndRow )
814 : {
815 9149 : if (nY1 < nStartRow) nY1=nStartRow;
816 9149 : if (nY2 > nEndRow) nY2=nEndRow;
817 9149 : SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
818 9149 : Search( nStart, nPos );
819 : }
820 : else
821 : {
822 : // ensure attributing changes text-width of cell
823 :
824 113317 : const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
825 113317 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
826 :
827 : bool bNumFormatChanged;
828 113317 : if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
829 : rNewSet, rOldSet ) )
830 : {
831 2615 : aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
832 2615 : aAdrEnd .SetRow( pData[nPos].nRow );
833 2615 : pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
834 : }
835 :
836 113317 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
837 113317 : pData[nPos].pPattern = pNewPattern;
838 113317 : if (Concat(nPos))
839 20 : Search(nStart, nPos);
840 : else
841 113297 : ++nPos;
842 : }
843 : }
844 : else
845 : {
846 1667 : nStart = pData[nPos].nRow + 1;
847 1667 : ++nPos;
848 : }
849 : }
850 : while (nStart <= nEndRow);
851 :
852 124069 : 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 34052 : bool ScAttrArray::SetAttrEntries(ScAttrEntry* pNewData, SCSIZE nSize)
862 : {
863 34052 : ScDocumentPool* pDocPool = pDocument->GetPool();
864 68104 : for (SCSIZE i=0; i<nCount; i++)
865 34052 : pDocPool->Remove(*pData[i].pPattern);
866 :
867 34052 : delete[] pData;
868 :
869 34052 : pData = pNewData;
870 34052 : nCount = nLimit = nSize;
871 34052 : return true;
872 : }
873 :
874 89 : static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
875 : {
876 : const SfxPoolItem* pNewItem;
877 : const SfxPoolItem* pOldItem;
878 5073 : for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
879 : {
880 : // pMergeSet has no parent
881 4984 : SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem );
882 :
883 4984 : if ( eOldState == SfxItemState::DEFAULT )
884 : {
885 3939 : SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
886 3939 : if ( eNewState == SfxItemState::SET )
887 : {
888 52 : if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
889 8 : rMergeSet.InvalidateItem( nId );
890 : }
891 : }
892 1045 : else if ( eOldState == SfxItemState::SET ) // Item set
893 : {
894 1034 : SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
895 1034 : if ( eNewState == SfxItemState::SET )
896 : {
897 1019 : if ( pNewItem != pOldItem ) // Both pulled
898 35 : rMergeSet.InvalidateItem( nId );
899 : }
900 : else // Default
901 : {
902 15 : if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
903 2 : rMergeSet.InvalidateItem( nId );
904 : }
905 : }
906 : // Dontcare remains Dontcare
907 : }
908 89 : }
909 :
910 103427 : void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
911 : ScMergePatternState& rState, bool bDeep ) const
912 : {
913 103427 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
914 : {
915 : SCSIZE nPos;
916 103427 : SCROW nStart=0;
917 103427 : if (!Search( nStartRow, nPos ))
918 : {
919 : OSL_FAIL("Search failure");
920 103427 : return;
921 : }
922 :
923 103602 : do
924 : {
925 : // similar patterns must not be repeated
926 103602 : const ScPatternAttr* pPattern = pData[nPos].pPattern;
927 103602 : if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
928 : {
929 17155 : const SfxItemSet& rThisSet = pPattern->GetItemSet();
930 17155 : if (rState.pItemSet)
931 : {
932 95 : if (bDeep)
933 89 : lcl_MergeDeep( *rState.pItemSet, rThisSet );
934 : else
935 6 : rState.pItemSet->MergeValues( rThisSet, false );
936 : }
937 : else
938 : {
939 : // first pattern - copied from parent
940 17060 : rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
941 17060 : rState.pItemSet->Set( rThisSet, bDeep );
942 : }
943 :
944 17155 : rState.pOld2 = rState.pOld1;
945 17155 : rState.pOld1 = pPattern;
946 : }
947 :
948 103602 : nStart = pData[nPos].nRow + 1;
949 103602 : ++nPos;
950 : }
951 : while (nStart <= nEndRow);
952 : }
953 : }
954 :
955 : // assemble border
956 :
957 1984 : static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
958 : sal_uInt8& rModified, const SvxBorderLine*& rpNew )
959 : {
960 1984 : if (rModified == SC_LINE_DONTCARE)
961 0 : return false; // don't go again
962 :
963 1984 : if (rModified == SC_LINE_EMPTY)
964 : {
965 328 : rModified = SC_LINE_SET;
966 328 : rpNew = pNewLine;
967 328 : return true; // initial value
968 : }
969 :
970 1656 : if (pOldLine == pNewLine)
971 : {
972 1656 : rpNew = pOldLine;
973 1656 : 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 496 : 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 496 : const ScMergeAttr& rMerge = static_cast<const ScMergeAttr&>(pPattern->GetItem(ATTR_MERGE));
994 496 : if ( rMerge.GetColMerge() == nDistRight + 1 )
995 0 : nDistRight = 0;
996 496 : if ( rMerge.GetRowMerge() == nDistBottom + 1 )
997 0 : nDistBottom = 0;
998 :
999 496 : const SvxBoxItem* pCellFrame = static_cast<const SvxBoxItem*>( &pPattern->GetItemSet().Get( ATTR_BORDER ) );
1000 496 : const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
1001 496 : const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
1002 496 : const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
1003 496 : const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
1004 : const SvxBorderLine* pNew;
1005 :
1006 496 : if (bTop)
1007 : {
1008 206 : if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
1009 60 : pLineOuter->SetLine( pNew, SvxBoxItemLine::TOP );
1010 : }
1011 : else
1012 : {
1013 290 : if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
1014 0 : pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI );
1015 : }
1016 :
1017 496 : if (nDistBottom == 0)
1018 : {
1019 206 : if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
1020 60 : pLineOuter->SetLine( pNew, SvxBoxItemLine::BOTTOM );
1021 : }
1022 : else
1023 : {
1024 290 : if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1025 44 : pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI );
1026 : }
1027 :
1028 496 : if (bLeft)
1029 : {
1030 130 : if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1031 60 : pLineOuter->SetLine( pNew, SvxBoxItemLine::LEFT );
1032 : }
1033 : else
1034 : {
1035 366 : if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1036 0 : pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT );
1037 : }
1038 :
1039 496 : if (nDistRight == 0)
1040 : {
1041 130 : if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1042 60 : pLineOuter->SetLine( pNew, SvxBoxItemLine::RIGHT );
1043 : }
1044 : else
1045 : {
1046 366 : if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1047 44 : pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT );
1048 : }
1049 496 : }
1050 :
1051 206 : 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 206 : if (nStartRow == nEndRow)
1058 : {
1059 16 : pPattern = GetPattern( nStartRow );
1060 16 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
1061 : }
1062 : else
1063 : {
1064 190 : pPattern = GetPattern( nStartRow );
1065 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
1066 190 : nEndRow-nStartRow );
1067 :
1068 : SCSIZE nStartIndex;
1069 : SCSIZE nEndIndex;
1070 190 : Search( nStartRow+1, nStartIndex );
1071 190 : Search( nEndRow-1, nEndIndex );
1072 290 : for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1073 : {
1074 100 : pPattern = pData[i].pPattern;
1075 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
1076 100 : nEndRow - std::min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1077 : // nDistBottom here always > 0
1078 : }
1079 :
1080 190 : pPattern = GetPattern( nEndRow );
1081 190 : lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
1082 : }
1083 206 : }
1084 :
1085 : // apply border
1086 :
1087 : // ApplyFrame - on an entry into the array
1088 :
1089 3180 : 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 3180 : const ScPatternAttr* pPattern = GetPattern( nStartRow );
1097 : const SvxBoxItem* pOldFrame = static_cast<const SvxBoxItem*>(
1098 3180 : &pPattern->GetItemSet().Get( ATTR_BORDER ));
1099 :
1100 : // right/bottom border set when connected together
1101 3180 : const ScMergeAttr& rMerge = static_cast<const ScMergeAttr&>(pPattern->GetItem(ATTR_MERGE));
1102 3180 : if ( rMerge.GetColMerge() == nDistRight + 1 )
1103 0 : nDistRight = 0;
1104 3180 : if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1105 0 : nDistBottom = 0;
1106 :
1107 3180 : SvxBoxItem aNewFrame( *pOldFrame );
1108 3180 : bool bRTL=pDocument->IsLayoutRTL(nTab);
1109 : // fdo#37464 check if the sheet are RTL then replace right <=> left
1110 3180 : if (bRTL)
1111 : {
1112 0 : if( bLeft && nDistRight==0)
1113 : {
1114 0 : if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
1115 0 : aNewFrame.SetLine( pBoxItem->GetLeft(), SvxBoxItemLine::RIGHT );
1116 0 : if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
1117 0 : aNewFrame.SetLine( pBoxItem->GetRight(), SvxBoxItemLine::LEFT );
1118 : }
1119 : else
1120 : {
1121 0 : if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1122 : aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1123 0 : SvxBoxItemLine::RIGHT );
1124 0 : if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1125 : aNewFrame.SetLine( bLeft ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1126 0 : SvxBoxItemLine::LEFT );
1127 : }
1128 : }
1129 : else
1130 : {
1131 3180 : if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1132 : aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1133 1558 : SvxBoxItemLine::LEFT );
1134 3180 : if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1135 : aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1136 1559 : SvxBoxItemLine::RIGHT );
1137 : }
1138 3180 : if ( bTop ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1139 : aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1140 1941 : SvxBoxItemLine::TOP );
1141 3180 : if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1142 : aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1143 1941 : SvxBoxItemLine::BOTTOM );
1144 :
1145 3180 : if (aNewFrame == *pOldFrame)
1146 : {
1147 : // nothing to do
1148 704 : return false;
1149 : }
1150 : else
1151 : {
1152 2476 : SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1153 2476 : ApplyCacheArea( nStartRow, nEndRow, &aCache );
1154 :
1155 2476 : return true;
1156 3180 : }
1157 : }
1158 :
1159 1908 : void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1160 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
1161 : {
1162 1908 : if (nStartRow == nEndRow)
1163 1141 : ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
1164 : else
1165 : {
1166 : ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1167 767 : true, nEndRow-nStartRow );
1168 :
1169 767 : if ( nEndRow > nStartRow+1 ) // inner part available?
1170 : {
1171 : SCSIZE nStartIndex;
1172 : SCSIZE nEndIndex;
1173 386 : Search( nStartRow+1, nStartIndex );
1174 386 : Search( nEndRow-1, nEndIndex );
1175 386 : SCROW nTmpStart = nStartRow+1;
1176 : SCROW nTmpEnd;
1177 1277 : for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1178 : {
1179 505 : nTmpEnd = std::min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1180 : bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1181 505 : bLeft, nDistRight, false, nEndRow-nTmpEnd );
1182 505 : nTmpStart = nTmpEnd+1;
1183 505 : if (bChanged)
1184 : {
1185 242 : Search(nTmpStart, i);
1186 242 : Search(nEndRow-1, nEndIndex);
1187 : }
1188 : else
1189 263 : i++;
1190 : }
1191 : }
1192 :
1193 767 : ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0 );
1194 : }
1195 1908 : }
1196 :
1197 : // Test if field contains specific attribute
1198 :
1199 15983325 : bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
1200 : {
1201 : SCSIZE nStartIndex;
1202 : SCSIZE nEndIndex;
1203 15983325 : Search( nRow1, nStartIndex );
1204 15983325 : Search( nRow2, nEndIndex );
1205 15983325 : bool bFound = false;
1206 :
1207 32144506 : for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1208 : {
1209 16161181 : const ScPatternAttr* pPattern = pData[i].pPattern;
1210 16161181 : if ( nMask & HASATTR_MERGED )
1211 : {
1212 : const ScMergeAttr* pMerge =
1213 220125 : static_cast<const ScMergeAttr*>( &pPattern->GetItem( ATTR_MERGE ) );
1214 220125 : if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1215 101 : bFound = true;
1216 : }
1217 16161181 : if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1218 : {
1219 : const ScMergeFlagAttr* pMergeFlag =
1220 250873 : static_cast<const ScMergeFlagAttr*>( &pPattern->GetItem( ATTR_MERGE_FLAG ) );
1221 250873 : if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1222 5 : bFound = true;
1223 250873 : if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1224 0 : bFound = true;
1225 250873 : if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1226 0 : bFound = true;
1227 : }
1228 16161181 : if ( nMask & HASATTR_LINES )
1229 : {
1230 : const SvxBoxItem* pBox =
1231 66842 : static_cast<const SvxBoxItem*>( &pPattern->GetItem( ATTR_BORDER ) );
1232 66842 : if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1233 44 : bFound = true;
1234 : }
1235 16161181 : if ( nMask & HASATTR_SHADOW )
1236 : {
1237 : const SvxShadowItem* pShadow =
1238 66740 : static_cast<const SvxShadowItem*>( &pPattern->GetItem( ATTR_SHADOW ) );
1239 66740 : if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1240 0 : bFound = true;
1241 : }
1242 16161181 : if ( nMask & HASATTR_CONDITIONAL )
1243 : {
1244 : bool bContainsCondFormat =
1245 10563050 : !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1246 10563050 : if ( bContainsCondFormat )
1247 77 : bFound = true;
1248 : }
1249 16161181 : if ( nMask & HASATTR_PROTECTED )
1250 : {
1251 : const ScProtectionAttr* pProtect =
1252 10 : static_cast<const ScProtectionAttr*>( &pPattern->GetItem( ATTR_PROTECTION ) );
1253 10 : bool bFoundTemp = false;
1254 10 : if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1255 10 : bFoundTemp = true;
1256 :
1257 : bool bContainsCondFormat =
1258 10 : !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1259 10 : 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 10 : if(bFoundTemp)
1290 10 : bFound = true;
1291 : }
1292 16161181 : if ( nMask & HASATTR_ROTATE )
1293 : {
1294 : const SfxInt32Item* pRotate =
1295 62138 : 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 62138 : sal_Int32 nAngle = pRotate->GetValue();
1299 62138 : if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1300 485 : bFound = true;
1301 : }
1302 16161181 : if ( nMask & HASATTR_NEEDHEIGHT )
1303 : {
1304 6279 : if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1305 0 : bFound = true;
1306 6279 : else if (static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1307 62 : bFound = true;
1308 6217 : else if ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
1309 6217 : GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1310 0 : bFound = true;
1311 :
1312 6217 : else if (!static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData().empty())
1313 0 : bFound = true;
1314 6217 : else if (static_cast<const SfxInt32Item&>(pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1315 0 : bFound = true;
1316 : }
1317 16161181 : if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1318 : {
1319 : const SvxShadowItem* pShadow =
1320 240 : static_cast<const SvxShadowItem*>( &pPattern->GetItem( ATTR_SHADOW ));
1321 240 : SvxShadowLocation eLoc = pShadow->GetLocation();
1322 240 : if ( nMask & HASATTR_SHADOW_RIGHT )
1323 64 : if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1324 0 : bFound = true;
1325 240 : if ( nMask & HASATTR_SHADOW_DOWN )
1326 176 : if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1327 0 : bFound = true;
1328 : }
1329 16161181 : 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 16161181 : 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 5336311 : static_cast<const SvxHorJustifyItem&>( pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1341 5336311 : if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1342 197 : bFound = true;
1343 : }
1344 : }
1345 :
1346 15983325 : return bFound;
1347 : }
1348 :
1349 17 : bool ScAttrArray::IsMerged( SCROW nRow ) const
1350 : {
1351 : SCSIZE nIndex;
1352 17 : Search(nRow, nIndex);
1353 : const ScMergeAttr& rItem =
1354 17 : static_cast<const ScMergeAttr&>(pData[nIndex].pPattern->GetItem(ATTR_MERGE));
1355 :
1356 17 : return rItem.IsMerged();
1357 : }
1358 :
1359 : /**
1360 : * Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1361 : */
1362 12380 : 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 12380 : Search( nStartRow, nStartIndex );
1371 12380 : Search( nEndRow, nEndIndex );
1372 12380 : bool bFound = false;
1373 :
1374 25880 : for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1375 : {
1376 13500 : pPattern = pData[i].pPattern;
1377 13500 : pItem = static_cast<const ScMergeAttr*>( &pPattern->GetItem( ATTR_MERGE ) );
1378 13500 : SCsCOL nCountX = pItem->GetColMerge();
1379 13500 : SCsROW nCountY = pItem->GetRowMerge();
1380 13500 : if (nCountX>1 || nCountY>1)
1381 : {
1382 36 : SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1383 36 : SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1384 36 : SCROW nMergeEndRow = nThisRow + nCountY - 1;
1385 36 : if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1386 21 : rPaintCol = nMergeEndCol;
1387 36 : if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1388 22 : rPaintRow = nMergeEndRow;
1389 36 : bFound = true;
1390 :
1391 36 : if (bRefresh)
1392 : {
1393 1 : if ( nMergeEndCol > nThisCol )
1394 1 : pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1395 2 : nTab, SC_MF_HOR );
1396 1 : if ( nMergeEndRow > nThisRow )
1397 : pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1398 1 : nTab, SC_MF_VER );
1399 1 : if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1400 : pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1401 1 : nTab, SC_MF_HOR | SC_MF_VER );
1402 :
1403 1 : Search( nThisRow, i ); // Data changed
1404 1 : Search( nStartRow, nStartIndex );
1405 1 : Search( nEndRow, nEndIndex );
1406 : }
1407 : }
1408 : }
1409 :
1410 12380 : return bFound;
1411 : }
1412 :
1413 33652 : bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1414 : {
1415 33652 : bool bFound = false;
1416 : const ScPatternAttr* pPattern;
1417 : const ScMergeAttr* pItem;
1418 : SCSIZE nIndex;
1419 :
1420 33652 : Search( nStartRow, nIndex );
1421 33652 : SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1422 33652 : if (nThisStart < nStartRow)
1423 26871 : nThisStart = nStartRow;
1424 :
1425 102245 : while ( nThisStart <= nEndRow )
1426 : {
1427 34941 : SCROW nThisEnd = pData[nIndex].nRow;
1428 34941 : if (nThisEnd > nEndRow)
1429 31241 : nThisEnd = nEndRow;
1430 :
1431 34941 : pPattern = pData[nIndex].pPattern;
1432 34941 : pItem = static_cast<const ScMergeAttr*>( &pPattern->GetItem( ATTR_MERGE ) );
1433 34941 : SCsCOL nCountX = pItem->GetColMerge();
1434 34941 : SCsROW nCountY = pItem->GetRowMerge();
1435 34941 : 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 34941 : ++nIndex;
1463 34941 : if ( nIndex < nCount )
1464 1660 : nThisStart = pData[nIndex-1].nRow+1;
1465 : else
1466 33281 : nThisStart = MAXROW+1; // End
1467 : }
1468 :
1469 33652 : 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 5486 : 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 5486 : bool bChanged = false;
1544 :
1545 5486 : Search( nStartRow, nIndex );
1546 5486 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1547 5486 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1548 :
1549 18871 : while ( nThisRow <= nEndRow )
1550 : {
1551 7899 : pOldPattern = pData[nIndex].pPattern;
1552 7899 : nOldValue = static_cast<const ScMergeFlagAttr*>( &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1553 7899 : if ( (nOldValue | nFlags) != nOldValue )
1554 : {
1555 7861 : nRow = pData[nIndex].nRow;
1556 7861 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1557 7861 : ScPatternAttr aNewPattern(*pOldPattern);
1558 7861 : aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1559 7861 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1560 7861 : Search( nThisRow, nIndex ); // data changed
1561 7861 : bChanged = true;
1562 : }
1563 :
1564 7899 : ++nIndex;
1565 7899 : nThisRow = pData[nIndex-1].nRow+1;
1566 : }
1567 :
1568 5486 : return bChanged;
1569 : }
1570 :
1571 105286 : 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 105286 : bool bChanged = false;
1580 :
1581 105286 : Search( nStartRow, nIndex );
1582 105286 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1583 105286 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1584 :
1585 316351 : while ( nThisRow <= nEndRow )
1586 : {
1587 105779 : pOldPattern = pData[nIndex].pPattern;
1588 105779 : nOldValue = static_cast<const ScMergeFlagAttr*>(&pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1589 105779 : if ( (nOldValue & ~nFlags) != nOldValue )
1590 : {
1591 345 : nRow = pData[nIndex].nRow;
1592 345 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1593 345 : ScPatternAttr aNewPattern(*pOldPattern);
1594 345 : aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1595 345 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1596 345 : Search( nThisRow, nIndex ); // data changed
1597 345 : bChanged = true;
1598 : }
1599 :
1600 105779 : ++nIndex;
1601 105779 : nThisRow = pData[nIndex-1].nRow+1;
1602 : }
1603 :
1604 105286 : return bChanged;
1605 : }
1606 :
1607 159 : void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1608 : {
1609 : SCSIZE nIndex;
1610 : SCROW nRow;
1611 : SCROW nThisRow;
1612 :
1613 159 : Search( nStartRow, nIndex );
1614 159 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1615 159 : if (nThisRow < nStartRow) nThisRow = nStartRow;
1616 :
1617 565 : while ( nThisRow <= nEndRow )
1618 : {
1619 247 : const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1620 247 : if ( pOldPattern->HasItemsSet( pWhich ) )
1621 : {
1622 0 : ScPatternAttr aNewPattern(*pOldPattern);
1623 0 : aNewPattern.ClearItems( pWhich );
1624 :
1625 0 : nRow = pData[nIndex].nRow;
1626 0 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1627 0 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1628 0 : Search( nThisRow, nIndex ); // data changed
1629 : }
1630 :
1631 247 : ++nIndex;
1632 247 : nThisRow = pData[nIndex-1].nRow+1;
1633 : }
1634 159 : }
1635 :
1636 26 : void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1637 : {
1638 : SCSIZE nIndex;
1639 26 : Search( nStartRow, nIndex );
1640 26 : SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1641 26 : if (nThisStart < nStartRow) nThisStart = nStartRow;
1642 :
1643 78 : while ( nThisStart <= nEndRow )
1644 : {
1645 26 : const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1646 26 : const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1647 : const SfxPoolItem* pItem;
1648 :
1649 26 : bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SfxItemState::SET
1650 26 : || (static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT &&
1651 26 : static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SVX_HOR_JUSTIFY_RIGHT ));
1652 26 : sal_uInt16 nOldValue = static_cast<const SfxUInt16Item&>(rOldSet.Get( ATTR_INDENT )).GetValue();
1653 26 : sal_uInt16 nNewValue = nOldValue;
1654 : // To keep Increment indent from running outside the cell1659
1655 26 : long nColWidth = (long)pDocument->GetColWidth(nCol,nTab);
1656 26 : if ( bIncrement )
1657 : {
1658 13 : if ( nNewValue < nColWidth-SC_INDENT_STEP )
1659 : {
1660 13 : nNewValue += SC_INDENT_STEP;
1661 13 : if ( nNewValue > nColWidth-SC_INDENT_STEP ) nNewValue = nColWidth-SC_INDENT_STEP;
1662 : }
1663 : }
1664 : else
1665 : {
1666 13 : if ( nNewValue > 0 )
1667 : {
1668 13 : if ( nNewValue > SC_INDENT_STEP )
1669 0 : nNewValue -= SC_INDENT_STEP;
1670 : else
1671 13 : nNewValue = 0;
1672 : }
1673 : }
1674 :
1675 26 : if ( bNeedJust || nNewValue != nOldValue )
1676 : {
1677 26 : SCROW nThisEnd = pData[nIndex].nRow;
1678 26 : SCROW nAttrRow = std::min( nThisEnd, nEndRow );
1679 26 : ScPatternAttr aNewPattern(*pOldPattern);
1680 26 : aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1681 26 : if ( bNeedJust )
1682 13 : aNewPattern.GetItemSet().Put(
1683 26 : SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1684 26 : SetPatternArea( nThisStart, nAttrRow, &aNewPattern, true );
1685 :
1686 26 : nThisStart = nThisEnd + 1;
1687 26 : Search( nThisStart, nIndex ); // data changed
1688 : }
1689 : else
1690 : {
1691 0 : nThisStart = pData[nIndex].nRow + 1;
1692 0 : ++nIndex;
1693 : }
1694 : }
1695 26 : }
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 (static_cast<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 6942720 : void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1727 : {
1728 6942720 : SCROW nStart = 0;
1729 6942720 : SCSIZE nPos = 0;
1730 20828160 : while (nPos < nCount)
1731 : {
1732 6942720 : SCROW nEnd = pData[nPos].nRow;
1733 6942720 : if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1734 : {
1735 2364416 : rUsedRows.setTrue(nStart, nEnd);
1736 :
1737 2364416 : if (bReset)
1738 : {
1739 0 : boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pData[nPos].pPattern));
1740 0 : pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1741 : pNewPattern->SetStyleSheet( static_cast<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 = static_cast<const ScPatternAttr*>(
1747 0 : &pDocument->GetPool()->Put(*pNewPattern));
1748 0 : pNewPattern.reset();
1749 :
1750 0 : if (Concat(nPos))
1751 : {
1752 0 : Search(nStart, nPos);
1753 0 : --nPos; // because ++ at end
1754 0 : }
1755 : }
1756 : }
1757 6942720 : nStart = nEnd + 1;
1758 6942720 : ++nPos;
1759 : }
1760 6942720 : }
1761 :
1762 0 : bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1763 : bool bGatherAllStyles ) const
1764 : {
1765 0 : bool bIsUsed = false;
1766 0 : SCSIZE nPos = 0;
1767 :
1768 0 : while ( nPos < nCount )
1769 : {
1770 0 : const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1771 0 : if ( pStyle )
1772 : {
1773 0 : pStyle->SetUsage( ScStyleSheet::USED );
1774 0 : if ( pStyle == &rStyle )
1775 : {
1776 0 : if ( !bGatherAllStyles )
1777 0 : return true;
1778 0 : bIsUsed = true;
1779 : }
1780 : }
1781 0 : nPos++;
1782 : }
1783 :
1784 0 : return bIsUsed;
1785 : }
1786 :
1787 60 : bool ScAttrArray::IsEmpty() const
1788 : {
1789 60 : if (nCount == 1)
1790 : {
1791 60 : if ( pData[0].pPattern != pDocument->GetDefPattern() )
1792 0 : return false;
1793 : else
1794 60 : return true;
1795 : }
1796 : else
1797 0 : return false;
1798 : }
1799 :
1800 2085888 : bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1801 : {
1802 : OSL_ENSURE( nCount, "nCount == 0" );
1803 :
1804 2085888 : bool bFound = false;
1805 2085888 : SCSIZE nStart = 0;
1806 :
1807 : // Skip first entry if more than 1 row.
1808 : // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1809 :
1810 2085888 : SCSIZE nVisStart = 1;
1811 4250828 : while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1812 79052 : ++nVisStart;
1813 2085888 : if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1814 2085638 : nStart = nVisStart;
1815 :
1816 4172770 : while ( nStart < nCount && !bFound )
1817 : {
1818 994 : if ( pData[nStart].pPattern->IsVisible() )
1819 : {
1820 946 : rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1821 946 : bFound = true;
1822 : }
1823 : else
1824 48 : ++nStart;
1825 : }
1826 :
1827 2085888 : return bFound;
1828 : }
1829 :
1830 : // size (rows) of a range of attributes after cell content where the search is stopped
1831 : // (more than a default page size, 2*42 because it's as good as any number)
1832 :
1833 : const SCROW SC_VISATTR_STOP = 84;
1834 :
1835 3248305 : bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bFullFormattedArea ) const
1836 : {
1837 : OSL_ENSURE( nCount, "nCount == 0" );
1838 :
1839 : // #i30830# changed behavior:
1840 : // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1841 : // below the last content cell
1842 :
1843 3248305 : if ( nLastData == MAXROW )
1844 : {
1845 0 : rLastRow = MAXROW; // can't look for attributes below MAXROW
1846 0 : return true;
1847 : }
1848 :
1849 : // Quick check: last data row in or immediately preceding a run that is the
1850 : // last attribution down to the end, e.g. default style or column style.
1851 3248305 : SCSIZE nPos = nCount - 1;
1852 3248305 : SCROW nStartRow = (nPos ? pData[nPos-1].nRow + 1 : 0);
1853 3248305 : if (nStartRow <= nLastData + 1)
1854 : {
1855 3180824 : if (bFullFormattedArea && pData[nPos].pPattern->IsVisible())
1856 : {
1857 0 : rLastRow = pData[nPos].nRow;
1858 0 : return true;
1859 : }
1860 : else
1861 : {
1862 : // Ignore here a few rows if data happens to end within
1863 : // SC_VISATTR_STOP rows before MAXROW.
1864 3180824 : rLastRow = nLastData;
1865 3180824 : return false;
1866 : }
1867 : }
1868 :
1869 : // Find a run below last data row.
1870 67481 : bool bFound = false;
1871 67481 : Search( nLastData, nPos );
1872 139048 : while ( nPos < nCount )
1873 : {
1874 : // find range of visually equal formats
1875 71567 : SCSIZE nEndPos = nPos;
1876 421283 : while ( nEndPos < nCount-1 &&
1877 141144 : pData[nEndPos].pPattern->IsVisibleEqual( *pData[nEndPos+1].pPattern))
1878 137005 : ++nEndPos;
1879 71567 : SCROW nAttrStartRow = ( nPos > 0 ) ? ( pData[nPos-1].nRow + 1 ) : 0;
1880 71567 : if ( nAttrStartRow <= nLastData )
1881 67481 : nAttrStartRow = nLastData + 1;
1882 71567 : SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1883 71567 : if ( nAttrSize >= SC_VISATTR_STOP && !bFullFormattedArea )
1884 : break; // while, ignore this range and below
1885 4086 : else if ( pData[nEndPos].pPattern->IsVisible() )
1886 : {
1887 3575 : rLastRow = pData[nEndPos].nRow;
1888 3575 : bFound = true;
1889 : }
1890 4086 : nPos = nEndPos + 1;
1891 : }
1892 :
1893 67481 : return bFound;
1894 : }
1895 :
1896 0 : bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1897 : {
1898 : SCSIZE nIndex;
1899 0 : Search( nStartRow, nIndex );
1900 0 : SCROW nThisStart = nStartRow;
1901 0 : bool bFound = false;
1902 0 : while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1903 : {
1904 0 : if ( pData[nIndex].pPattern->IsVisible() )
1905 0 : bFound = true;
1906 :
1907 0 : nThisStart = pData[nIndex].nRow + 1;
1908 0 : ++nIndex;
1909 : }
1910 :
1911 0 : return bFound;
1912 : }
1913 :
1914 12035 : bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1915 : SCROW nStartRow, SCROW nEndRow ) const
1916 : {
1917 12035 : bool bEqual = true;
1918 12035 : SCSIZE nThisPos = 0;
1919 12035 : SCSIZE nOtherPos = 0;
1920 12035 : if ( nStartRow > 0 )
1921 : {
1922 0 : Search( nStartRow, nThisPos );
1923 0 : rOther.Search( nStartRow, nOtherPos );
1924 : }
1925 :
1926 24730 : while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1927 : {
1928 12474 : SCROW nThisRow = pData[nThisPos].nRow;
1929 12474 : SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1930 12474 : const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1931 12474 : const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1932 12853 : bEqual = ( pThisPattern == pOtherPattern ||
1933 12853 : pThisPattern->IsVisibleEqual(*pOtherPattern) );
1934 :
1935 12474 : if ( nThisRow >= nOtherRow )
1936 : {
1937 12154 : if ( nOtherRow >= nEndRow ) break;
1938 340 : ++nOtherPos;
1939 : }
1940 660 : if ( nThisRow <= nOtherRow )
1941 : {
1942 505 : if ( nThisRow >= nEndRow ) break;
1943 505 : ++nThisPos;
1944 : }
1945 : }
1946 :
1947 12035 : return bEqual;
1948 : }
1949 :
1950 43998 : bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
1951 : {
1952 : // summarised with IsVisibleEqual
1953 :
1954 43998 : bool bEqual = true;
1955 43998 : SCSIZE nThisPos = 0;
1956 43998 : SCSIZE nOtherPos = 0;
1957 43998 : if ( nStartRow > 0 )
1958 : {
1959 0 : Search( nStartRow, nThisPos );
1960 0 : rOther.Search( nStartRow, nOtherPos );
1961 : }
1962 :
1963 88101 : while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1964 : {
1965 44046 : SCROW nThisRow = pData[nThisPos].nRow;
1966 44046 : SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1967 44046 : const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1968 44046 : const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1969 44046 : bEqual = ( pThisPattern == pOtherPattern );
1970 :
1971 44046 : if ( nThisRow >= nOtherRow )
1972 : {
1973 43994 : if ( nOtherRow >= nEndRow ) break;
1974 53 : ++nOtherPos;
1975 : }
1976 105 : if ( nThisRow <= nOtherRow )
1977 : {
1978 67 : if ( nThisRow >= nEndRow ) break;
1979 67 : ++nThisPos;
1980 : }
1981 : }
1982 :
1983 43998 : return bEqual;
1984 : }
1985 :
1986 0 : bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1987 : {
1988 : // Horizontal aggregate are not allowed to be moved out; if whole summary,
1989 : // here is not recognized
1990 :
1991 0 : bool bTest = true;
1992 0 : if (!IsEmpty())
1993 : {
1994 0 : SCSIZE nIndex = 0;
1995 0 : if ( nStartRow > 0 )
1996 0 : Search( nStartRow, nIndex );
1997 :
1998 0 : for ( ; nIndex < nCount; nIndex++ )
1999 : {
2000 0 : if ( static_cast<const ScMergeFlagAttr&>(pData[nIndex].pPattern->
2001 0 : GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2002 : {
2003 0 : bTest = false; // may not be pushed out
2004 0 : break;
2005 : }
2006 0 : if ( pData[nIndex].nRow >= nEndRow ) // end of range
2007 0 : break;
2008 : }
2009 : }
2010 0 : return bTest;
2011 : }
2012 :
2013 46089 : bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2014 : {
2015 : // if 1st row pushed out is vertically overlapped, summary would be broken
2016 :
2017 : // MAXROW + 1 - nSize = 1st row pushed out
2018 :
2019 46089 : SCSIZE nFirstLost = nCount-1;
2020 92178 : while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2021 0 : --nFirstLost;
2022 :
2023 92178 : if ( static_cast<const ScMergeFlagAttr&>(pData[nFirstLost].pPattern->
2024 46089 : GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2025 0 : return false;
2026 :
2027 46089 : return true;
2028 : }
2029 :
2030 46089 : void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2031 : {
2032 46089 : if (!pData)
2033 46089 : return;
2034 :
2035 46089 : SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2036 : SCSIZE nIndex;
2037 46089 : Search( nSearch, nIndex );
2038 :
2039 : // set ScMergeAttr may not be extended (so behind delete again)
2040 :
2041 46089 : bool bDoMerge = static_cast<const ScMergeAttr&>( pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2042 :
2043 46089 : SCSIZE nRemove = 0;
2044 : SCSIZE i;
2045 46098 : for (i = nIndex; i < nCount-1; i++)
2046 : {
2047 9 : SCROW nNew = pData[i].nRow + nSize;
2048 9 : if ( nNew >= MAXROW ) // at end?
2049 : {
2050 0 : nNew = MAXROW;
2051 0 : if (!nRemove)
2052 0 : nRemove = i+1; // remove the following?
2053 : }
2054 9 : pData[i].nRow = nNew;
2055 : }
2056 :
2057 : // Remove entries at end ?
2058 :
2059 46089 : if (nRemove && nRemove < nCount)
2060 0 : DeleteRange( nRemove, nCount-1 );
2061 :
2062 46089 : if (bDoMerge) // extensively repair (again) ScMergeAttr
2063 : {
2064 : // ApplyAttr for areas
2065 :
2066 0 : const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2067 0 : for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2068 0 : pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2069 :
2070 : // reply inserts in this area not summarized
2071 : }
2072 :
2073 : // Don't duplicate the merge flags in the inserted row.
2074 : // #i108488# SC_MF_SCENARIO has to be allowed.
2075 46089 : RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2076 : }
2077 :
2078 40971 : void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2079 : {
2080 40971 : bool bFirst=true;
2081 40971 : SCSIZE nStartIndex = 0;
2082 40971 : SCSIZE nEndIndex = 0;
2083 : SCSIZE i;
2084 :
2085 40978 : for ( i = 0; i < nCount-1; i++)
2086 7 : if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2087 : {
2088 2 : if (bFirst)
2089 : {
2090 2 : nStartIndex = i;
2091 2 : bFirst = false;
2092 : }
2093 2 : nEndIndex = i;
2094 : }
2095 40971 : if (!bFirst)
2096 : {
2097 : SCROW nStart;
2098 2 : if (nStartIndex==0)
2099 0 : nStart = 0;
2100 : else
2101 2 : nStart = pData[nStartIndex-1].nRow + 1;
2102 :
2103 2 : if (nStart < nStartRow)
2104 : {
2105 1 : pData[nStartIndex].nRow = nStartRow - 1;
2106 1 : ++nStartIndex;
2107 : }
2108 2 : if (nEndIndex >= nStartIndex)
2109 : {
2110 1 : DeleteRange( nStartIndex, nEndIndex );
2111 1 : if (nStartIndex > 0)
2112 1 : if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2113 1 : DeleteRange( nStartIndex-1, nStartIndex-1 );
2114 : }
2115 : }
2116 40976 : for (i = 0; i < nCount-1; i++)
2117 5 : if (pData[i].nRow >= nStartRow)
2118 0 : pData[i].nRow -= nSize;
2119 :
2120 : // Below does not follow the pattern to detect pressure ranges;
2121 : // instead, only remove merge flags.
2122 40971 : RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2123 40971 : }
2124 :
2125 2 : void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2126 : {
2127 2 : ScDocumentPool* pDocPool = pDocument->GetPool();
2128 4 : for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2129 2 : pDocPool->Remove(*pData[i].pPattern);
2130 :
2131 2 : memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2132 2 : nCount -= nEndIndex-nStartIndex+1;
2133 2 : }
2134 :
2135 33652 : void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2136 : {
2137 33652 : RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
2138 :
2139 33652 : if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2140 33652 : SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2141 : else
2142 0 : DeleteAreaSafe( nStartRow, nEndRow ); // leave merge flags
2143 33652 : }
2144 :
2145 94 : void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2146 : {
2147 94 : const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2148 :
2149 : SCSIZE nIndex;
2150 : SCROW nRow;
2151 : SCROW nThisRow;
2152 :
2153 94 : Search( nStartRow, nIndex );
2154 94 : nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2155 94 : if (nThisRow < nStartRow) nThisRow = nStartRow;
2156 :
2157 308 : while ( nThisRow <= nEndRow )
2158 : {
2159 120 : const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2160 :
2161 120 : if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
2162 : {
2163 22 : nRow = pData[nIndex].nRow;
2164 22 : SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
2165 :
2166 22 : ScPatternAttr aNewPattern(*pOldPattern);
2167 22 : SfxItemSet& rSet = aNewPattern.GetItemSet();
2168 1254 : for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2169 1232 : if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2170 1188 : rSet.ClearItem(nId);
2171 :
2172 22 : if ( aNewPattern == *pDefPattern )
2173 20 : SetPatternArea( nThisRow, nAttrRow, pDefPattern, false );
2174 : else
2175 2 : SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
2176 :
2177 22 : Search( nThisRow, nIndex ); // data changed
2178 : }
2179 :
2180 120 : ++nIndex;
2181 120 : nThisRow = pData[nIndex-1].nRow+1;
2182 : }
2183 94 : }
2184 :
2185 : /**
2186 : * Move within a document
2187 : */
2188 14267 : void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2189 : {
2190 14267 : SCROW nStart = nStartRow;
2191 28661 : for (SCSIZE i = 0; i < nCount; i++)
2192 : {
2193 14394 : if ((pData[i].nRow >= nStartRow) && (i == 0 || pData[i-1].nRow < nEndRow))
2194 : {
2195 : // copy (bPutToPool=TRUE)
2196 28534 : rAttrArray.SetPatternArea( nStart, std::min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2197 28534 : pData[i].pPattern, true );
2198 : }
2199 14394 : nStart = std::max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2200 : }
2201 14267 : DeleteArea(nStartRow, nEndRow);
2202 14267 : }
2203 :
2204 : /**
2205 : * Copy between documents (Clipboard)
2206 : */
2207 95759 : void ScAttrArray::CopyArea(
2208 : SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, sal_Int16 nStripFlags) const
2209 : {
2210 95759 : nStartRow -= nDy; // Source
2211 95759 : nEndRow -= nDy;
2212 :
2213 95759 : SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2214 95759 : SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2215 :
2216 95759 : ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2217 95759 : ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2218 95759 : bool bSamePool = (pSourceDocPool==pDestDocPool);
2219 :
2220 194692 : for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2221 : {
2222 98933 : if (pData[i].nRow >= nStartRow)
2223 : {
2224 97740 : const ScPatternAttr* pOldPattern = pData[i].pPattern;
2225 : const ScPatternAttr* pNewPattern;
2226 :
2227 97740 : if (IsDefaultItem( pOldPattern ))
2228 : {
2229 : // default: nothing changed
2230 :
2231 : pNewPattern = static_cast<const ScPatternAttr*>(
2232 91992 : &pDestDocPool->GetDefaultItem( ATTR_PATTERN ));
2233 : }
2234 5748 : else if ( nStripFlags )
2235 : {
2236 38 : boost::scoped_ptr<ScPatternAttr> pTmpPattern(new ScPatternAttr( *pOldPattern ));
2237 38 : sal_Int16 nNewFlags = 0;
2238 38 : if ( nStripFlags != SC_MF_ALL )
2239 0 : nNewFlags = static_cast<const ScMergeFlagAttr&>(pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2240 0 : GetValue() & ~nStripFlags;
2241 :
2242 38 : if ( nNewFlags )
2243 0 : pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2244 : else
2245 38 : pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2246 :
2247 38 : if (bSamePool)
2248 38 : pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pTmpPattern) );
2249 : else
2250 0 : pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2251 : }
2252 : else
2253 : {
2254 5710 : if (bSamePool)
2255 5638 : pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pOldPattern) );
2256 : else
2257 72 : pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2258 : }
2259 :
2260 : rAttrArray.SetPatternArea(nDestStart,
2261 97740 : std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2262 : }
2263 :
2264 : // when pasting from clipboard and skipping filtered rows, the adjusted
2265 : // end position can be negative
2266 98933 : nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2267 : }
2268 95759 : }
2269 :
2270 : /**
2271 : * Leave flags
2272 : * summarized with CopyArea
2273 : */
2274 120 : void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2275 : {
2276 120 : nStartRow -= nDy; // Source
2277 120 : nEndRow -= nDy;
2278 :
2279 120 : SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2280 120 : SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2281 :
2282 120 : if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2283 : {
2284 120 : CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2285 240 : return;
2286 : }
2287 :
2288 0 : ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2289 0 : ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2290 0 : bool bSamePool = (pSourceDocPool==pDestDocPool);
2291 :
2292 0 : for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2293 : {
2294 0 : if (pData[i].nRow >= nStartRow)
2295 : {
2296 0 : const ScPatternAttr* pOldPattern = pData[i].pPattern;
2297 : const ScPatternAttr* pNewPattern;
2298 :
2299 0 : if (bSamePool)
2300 0 : pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pOldPattern) );
2301 : else
2302 0 : pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2303 :
2304 : rAttrArray.SetPatternAreaSafe(nDestStart,
2305 0 : std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, false);
2306 : }
2307 :
2308 : // when pasting from clipboard and skipping filtered rows, the adjusted
2309 : // end position can be negative
2310 0 : nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2311 : }
2312 : }
2313 :
2314 0 : SCsROW ScAttrArray::SearchStyle(
2315 : SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
2316 : const ScMarkArray* pMarkArray) const
2317 : {
2318 0 : bool bFound = false;
2319 :
2320 0 : if (pMarkArray)
2321 : {
2322 0 : nRow = pMarkArray->GetNextMarked( nRow, bUp );
2323 0 : if (!ValidRow(nRow))
2324 0 : return nRow;
2325 : }
2326 :
2327 : SCSIZE nIndex;
2328 0 : Search(nRow, nIndex);
2329 0 : const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2330 :
2331 0 : while (nIndex < nCount && !bFound)
2332 : {
2333 0 : if (pPattern->GetStyleSheet() == pSearchStyle)
2334 : {
2335 0 : if (pMarkArray)
2336 : {
2337 0 : nRow = pMarkArray->GetNextMarked( nRow, bUp );
2338 0 : SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2339 0 : if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2340 0 : bFound = true;
2341 : }
2342 : else
2343 0 : bFound = true;
2344 : }
2345 :
2346 0 : if (!bFound)
2347 : {
2348 0 : if (bUp)
2349 : {
2350 0 : if (nIndex==0)
2351 : {
2352 0 : nIndex = nCount;
2353 0 : nRow = -1;
2354 : }
2355 : else
2356 : {
2357 0 : --nIndex;
2358 0 : nRow = pData[nIndex].nRow;
2359 0 : pPattern = pData[nIndex].pPattern;
2360 : }
2361 : }
2362 : else
2363 : {
2364 0 : nRow = pData[nIndex].nRow+1;
2365 0 : ++nIndex;
2366 0 : if (nIndex<nCount)
2367 0 : pPattern = pData[nIndex].pPattern;
2368 : }
2369 : }
2370 : }
2371 :
2372 : OSL_ENSURE( bFound || !ValidRow(nRow), "Internal failure in ScAttrArray::SearchStyle" );
2373 :
2374 0 : return nRow;
2375 : }
2376 :
2377 0 : bool ScAttrArray::SearchStyleRange(
2378 : SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
2379 : const ScMarkArray* pMarkArray) const
2380 : {
2381 0 : SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2382 0 : if (ValidRow(nStartRow))
2383 : {
2384 : SCSIZE nIndex;
2385 0 : Search(nStartRow,nIndex);
2386 :
2387 0 : rRow = nStartRow;
2388 0 : if (bUp)
2389 : {
2390 0 : if (nIndex>0)
2391 0 : rEndRow = pData[nIndex-1].nRow + 1;
2392 : else
2393 0 : rEndRow = 0;
2394 0 : if (pMarkArray)
2395 : {
2396 0 : SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2397 0 : if (nMarkEnd>rEndRow)
2398 0 : rEndRow = nMarkEnd;
2399 : }
2400 : }
2401 : else
2402 : {
2403 0 : rEndRow = pData[nIndex].nRow;
2404 0 : if (pMarkArray)
2405 : {
2406 0 : SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2407 0 : if (nMarkEnd<rEndRow)
2408 0 : rEndRow = nMarkEnd;
2409 : }
2410 : }
2411 :
2412 0 : return true;
2413 : }
2414 : else
2415 0 : return false;
2416 : }
2417 :
2418 113 : SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const
2419 : {
2420 : SCSIZE nIndex1, nIndex2;
2421 :
2422 113 : if( !Search( nStartRow, nIndex1 ) )
2423 0 : return 0;
2424 :
2425 113 : if( !Search( nEndRow, nIndex2 ) )
2426 0 : nIndex2 = nCount - 1;
2427 :
2428 113 : return nIndex2 - nIndex1 + 1;
2429 156 : }
2430 :
2431 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|