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