1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28
29 //------------------------------------------------------------------------
30
31 #include "scitems.hxx"
32 #include <svx/algitem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/bolnitem.hxx>
35 #include <editeng/frmdiritem.hxx>
36 #include <editeng/shaditem.hxx>
37 #include <svl/poolcach.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <unotools/fontcvt.hxx>
40
41 #include "attarray.hxx"
42 #include "global.hxx"
43 #include "document.hxx"
44 #include "docpool.hxx"
45 #include "patattr.hxx"
46 #include "stlsheet.hxx"
47 #include "stlpool.hxx"
48 #include "markarr.hxx"
49 #include "rechead.hxx"
50 #include "globstr.hrc"
51 #include "segmenttree.hxx"
52
53 #undef DBG_INVALIDATE
54 #define DBGOUTPUT(s) \
55 DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \
56 + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \
57 + String(" bis ") \
58 + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \
59 );
60
61 // STATIC DATA -----------------------------------------------------------
62
63
64 //------------------------------------------------------------------------
65
ScAttrArray(SCCOL nNewCol,SCTAB nNewTab,ScDocument * pDoc)66 ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
67 nCol( nNewCol ),
68 nTab( nNewTab ),
69 pDocument( pDoc )
70 {
71 nCount = nLimit = 1;
72 pData = new ScAttrEntry[1];
73 if (pData)
74 {
75 pData[0].nRow = MAXROW;
76 pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!!
77 }
78 }
79
80 //------------------------------------------------------------------------
81
~ScAttrArray()82 ScAttrArray::~ScAttrArray()
83 {
84 #ifdef DBG_UTIL
85 TestData();
86 #endif
87
88 if (pData)
89 {
90 ScDocumentPool* pDocPool = pDocument->GetPool();
91 for (SCSIZE i=0; i<nCount; i++)
92 pDocPool->Remove(*pData[i].pPattern);
93
94 delete[] pData;
95 }
96 }
97
98 //------------------------------------------------------------------------
99 #ifdef DBG_UTIL
TestData() const100 void ScAttrArray::TestData() const
101 {
102
103 sal_uInt16 nErr = 0;
104 if (pData)
105 {
106 SCSIZE nPos;
107 for (nPos=0; nPos<nCount; nPos++)
108 {
109 if (nPos > 0)
110 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
111 ++nErr;
112 if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
113 ++nErr;
114 }
115 if ( nPos && pData[nPos-1].nRow != MAXROW )
116 ++nErr;
117 }
118 if (nErr)
119 {
120 ByteString aMsg = ByteString::CreateFromInt32(nErr);
121 aMsg += " errors in attribute array, column ";
122 aMsg += ByteString::CreateFromInt32(nCol);
123 DBG_ERROR( aMsg.GetBuffer() );
124 }
125 }
126 #endif
127
128 //------------------------------------------------------------------------
129
Reset(const ScPatternAttr * pPattern,sal_Bool bAlloc)130 void ScAttrArray::Reset( const ScPatternAttr* pPattern, sal_Bool bAlloc )
131 {
132 if (pData)
133 {
134 ScDocumentPool* pDocPool = pDocument->GetPool();
135 const ScPatternAttr* pOldPattern;
136 ScAddress aAdrStart( nCol, 0, nTab );
137 ScAddress aAdrEnd ( nCol, 0, nTab );
138
139 for (SCSIZE i=0; i<nCount; i++)
140 {
141 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
142 pOldPattern = pData[i].pPattern;
143 sal_Bool bNumFormatChanged;
144 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
145 pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
146 {
147 aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
148 aAdrEnd .SetRow( pData[i].nRow );
149 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
150 #ifdef DBG_INVALIDATE
151 DBGOUTPUT("Reset");
152 #endif
153 }
154 // bedingtes Format gesetzt oder geloescht?
155 if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) )
156 {
157 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
158 pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
159 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
160 pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
161 }
162 pDocPool->Remove(*pOldPattern);
163 }
164 delete[] pData;
165
166 if (pDocument->IsStreamValid(nTab))
167 pDocument->SetStreamValid(nTab, sal_False);
168
169 if (bAlloc)
170 {
171 nCount = nLimit = 1;
172 pData = new ScAttrEntry[1];
173 if (pData)
174 {
175 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
176 pData[0].nRow = MAXROW;
177 pData[0].pPattern = pNewPattern;
178 }
179 }
180 else
181 {
182 nCount = nLimit = 0;
183 pData = NULL; // muss sofort wieder belegt werden !
184 }
185 }
186 }
187
188
Concat(SCSIZE nPos)189 sal_Bool ScAttrArray::Concat(SCSIZE nPos)
190 {
191 sal_Bool bRet = sal_False;
192 if (pData && (nPos < nCount))
193 {
194 if (nPos > 0)
195 {
196 if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
197 {
198 pData[nPos - 1].nRow = pData[nPos].nRow;
199 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
200 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
201 pData[nCount - 1].pPattern = NULL;
202 pData[nCount - 1].nRow = 0;
203 nCount--;
204 nPos--;
205 bRet = sal_True;
206 }
207 }
208 if (nPos + 1 < nCount)
209 {
210 if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
211 {
212 pData[nPos].nRow = pData[nPos + 1].nRow;
213 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
214 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
215 pData[nCount - 1].pPattern = NULL;
216 pData[nCount - 1].nRow = 0;
217 nCount--;
218 bRet = sal_True;
219 }
220 }
221 }
222 return bRet;
223 }
224
225 //------------------------------------------------------------------------
226
Search(SCROW nRow,SCSIZE & nIndex) const227 sal_Bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
228 {
229 long nLo = 0;
230 long nHi = static_cast<long>(nCount) - 1;
231 long nStartRow = 0;
232 long nEndRow = 0;
233 long i = 0;
234 sal_Bool bFound = (nCount == 1);
235 if (pData)
236 {
237 while ( !bFound && nLo <= nHi )
238 {
239 i = (nLo + nHi) / 2;
240 if (i > 0)
241 nStartRow = (long) pData[i - 1].nRow;
242 else
243 nStartRow = -1;
244 nEndRow = (long) pData[i].nRow;
245 if (nEndRow < (long) nRow)
246 nLo = ++i;
247 else
248 if (nStartRow >= (long) nRow)
249 nHi = --i;
250 else
251 bFound = sal_True;
252 }
253 }
254 else
255 bFound = sal_False;
256
257 if (bFound)
258 nIndex=(SCSIZE)i;
259 else
260 nIndex=0;
261 return bFound;
262 }
263
264
GetPattern(SCROW nRow) const265 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
266 {
267 SCSIZE i;
268 if (Search( nRow, i ))
269 return pData[i].pPattern;
270 else
271 return NULL;
272 }
273
274
GetPatternRange(SCROW & rStartRow,SCROW & rEndRow,SCROW nRow) const275 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
276 SCROW& rEndRow, SCROW nRow ) const
277 {
278 SCSIZE nIndex;
279 if ( Search( nRow, nIndex ) )
280 {
281 if ( nIndex > 0 )
282 rStartRow = pData[nIndex-1].nRow + 1;
283 else
284 rStartRow = 0;
285 rEndRow = pData[nIndex].nRow;
286 return pData[nIndex].pPattern;
287 }
288 return NULL;
289 }
290
291 //------------------------------------------------------------------------
292
SetPattern(SCROW nRow,const ScPatternAttr * pPattern,sal_Bool bPutToPool)293 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, sal_Bool bPutToPool )
294 {
295 SetPatternArea( nRow, nRow, pPattern, bPutToPool );
296 }
297
Reserve(SCSIZE nReserve)298 bool ScAttrArray::Reserve( SCSIZE nReserve )
299 {
300 if ( nCount <= nReserve )
301 {
302 if( ScAttrEntry* pNewData = new (std::nothrow) ScAttrEntry[nReserve] )
303 {
304 nLimit = nReserve;
305 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
306 delete[] pData;
307 pData = pNewData;
308 return true;
309 }
310 else
311 return false;
312 }
313 else
314 return false;
315 }
316
SetPatternArea(SCROW nStartRow,SCROW nEndRow,const ScPatternAttr * pPattern,sal_Bool bPutToPool)317 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, sal_Bool bPutToPool )
318 {
319 if (ValidRow(nStartRow) && ValidRow(nEndRow))
320 {
321 if (bPutToPool)
322 pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
323
324 if ((nStartRow == 0) && (nEndRow == MAXROW))
325 Reset(pPattern);
326 else
327 {
328 SCSIZE nNeeded = nCount + 2;
329 if ( nLimit < nNeeded )
330 {
331 nLimit += SC_ATTRARRAY_DELTA;
332 if ( nLimit < nNeeded )
333 nLimit = nNeeded;
334 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
335 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
336 delete[] pData;
337 pData = pNewData;
338 }
339
340 ScAddress aAdrStart( nCol, 0, nTab );
341 ScAddress aAdrEnd ( nCol, 0, nTab );
342
343 SCSIZE ni = 0; // number of entries in beginning
344 SCSIZE nx = 0; // track position
345 SCROW ns = 0; // start row of track position
346 if ( nStartRow > 0 )
347 {
348 // skip beginning
349 SCSIZE nIndex;
350 Search( nStartRow, nIndex );
351 ni = nIndex;
352
353 if ( ni > 0 )
354 {
355 nx = ni;
356 ns = pData[ni-1].nRow+1;
357 }
358 }
359
360 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
361 // oder bedingte Formate neu gesetzt oder geloescht werden
362 while ( ns <= nEndRow )
363 {
364 const SfxItemSet& rNewSet = pPattern->GetItemSet();
365 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
366
367 sal_Bool bNumFormatChanged;
368 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
369 rNewSet, rOldSet ) )
370 {
371 aAdrStart.SetRow( Max(nStartRow,ns) );
372 aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) );
373 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
374 #ifdef DBG_INVALIDATE
375 DBGOUTPUT("SetPatternArea");
376 #endif
377 }
378 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
379 {
380 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
381 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
382 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
383 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
384 }
385 ns = pData[nx].nRow + 1;
386 nx++;
387 }
388
389 // continue modifying data array
390
391 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
392 sal_Bool bCombined = sal_False;
393 sal_Bool bSplit = sal_False;
394 if ( nStartRow > 0 )
395 {
396 nInsert = MAXROWCOUNT;
397 if ( pData[ni].pPattern != pPattern )
398 {
399 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
400 { // may be a split or a simple insert or just a shrink,
401 // row adjustment is done further down
402 if ( pData[ni].nRow > nEndRow )
403 bSplit = sal_True;
404 ni++;
405 nInsert = ni;
406 }
407 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
408 nInsert = ni;
409 }
410 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
411 { // combine
412 pData[ni-1].nRow = nEndRow;
413 nInsert = MAXROWCOUNT;
414 bCombined = sal_True;
415 }
416 }
417 else
418 nInsert = 0;
419
420 SCSIZE nj = ni; // stop position of range to replace
421 while ( nj < nCount && pData[nj].nRow <= nEndRow )
422 nj++;
423 if ( !bSplit )
424 {
425 if ( nj < nCount && pData[nj].pPattern == pPattern )
426 { // combine
427 if ( ni > 0 )
428 {
429 if ( pData[ni-1].pPattern == pPattern )
430 { // adjacent entries
431 pData[ni-1].nRow = pData[nj].nRow;
432 nj++;
433 }
434 else if ( ni == nInsert )
435 pData[ni-1].nRow = nStartRow - 1; // shrink
436 }
437 nInsert = MAXROWCOUNT;
438 bCombined = sal_True;
439 }
440 else if ( ni > 0 && ni == nInsert )
441 pData[ni-1].nRow = nStartRow - 1; // shrink
442 }
443 ScDocumentPool* pDocPool = pDocument->GetPool();
444 if ( bSplit )
445 { // duplicate splitted entry in pool
446 pDocPool->Put( *pData[ni-1].pPattern );
447 }
448 if ( ni < nj )
449 { // remove middle entries
450 for ( SCSIZE nk=ni; nk<nj; nk++)
451 { // remove entries from pool
452 pDocPool->Remove( *pData[nk].pPattern );
453 }
454 if ( !bCombined )
455 { // replace one entry
456 pData[ni].nRow = nEndRow;
457 pData[ni].pPattern = pPattern;
458 ni++;
459 nInsert = MAXROWCOUNT;
460 }
461 if ( ni < nj )
462 { // remove entries
463 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
464 nCount -= nj - ni;
465 }
466 }
467
468 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
469 { // insert or append new entry
470 if ( nInsert <= nCount )
471 {
472 if ( !bSplit )
473 memmove( pData + nInsert + 1, pData + nInsert,
474 (nCount - nInsert) * sizeof(ScAttrEntry) );
475 else
476 {
477 memmove( pData + nInsert + 2, pData + nInsert,
478 (nCount - nInsert) * sizeof(ScAttrEntry) );
479 pData[nInsert+1] = pData[nInsert-1];
480 nCount++;
481 }
482 }
483 if ( nInsert )
484 pData[nInsert-1].nRow = nStartRow - 1;
485 pData[nInsert].nRow = nEndRow;
486 pData[nInsert].pPattern = pPattern;
487 nCount++;
488 }
489
490 if (pDocument->IsStreamValid(nTab))
491 pDocument->SetStreamValid(nTab, sal_False);
492 }
493 }
494 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
495
496 #ifdef DBG_UTIL
497 TestData();
498 #endif
499 }
500
501
ApplyStyleArea(SCROW nStartRow,SCROW nEndRow,ScStyleSheet * pStyle)502 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
503 {
504 if (ValidRow(nStartRow) && ValidRow(nEndRow))
505 {
506 SCSIZE nPos;
507 SCROW nStart=0;
508 if (!Search( nStartRow, nPos ))
509 {
510 DBG_ERROR("Search-Fehler");
511 return;
512 }
513
514 ScAddress aAdrStart( nCol, 0, nTab );
515 ScAddress aAdrEnd ( nCol, 0, nTab );
516
517 do
518 {
519 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
520 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
521 pNewPattern->SetStyleSheet(pStyle);
522 SCROW nY1 = nStart;
523 SCROW nY2 = pData[nPos].nRow;
524 nStart = pData[nPos].nRow + 1;
525
526 if ( *pNewPattern == *pOldPattern )
527 {
528 // keep the original pattern (might be default)
529 // pNewPattern is deleted below
530 nPos++;
531 }
532 else if ( nY1 < nStartRow || nY2 > nEndRow )
533 {
534 if (nY1 < nStartRow) nY1=nStartRow;
535 if (nY2 > nEndRow) nY2=nEndRow;
536 SetPatternArea( nY1, nY2, pNewPattern, sal_True );
537 Search( nStart, nPos );
538 }
539 else
540 {
541 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
542 // bedingte Formate in Vorlagen gibt es (noch) nicht
543
544 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
545 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
546
547 sal_Bool bNumFormatChanged;
548 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
549 rNewSet, rOldSet ) )
550 {
551 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
552 aAdrEnd .SetRow( pData[nPos].nRow );
553 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
554 #ifdef DBG_INVALIDATE
555 DBGOUTPUT("ApplyStyleArea");
556 #endif
557 }
558
559 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
560 pData[nPos].pPattern = (const ScPatternAttr*)
561 &pDocument->GetPool()->Put(*pNewPattern);
562 if (Concat(nPos))
563 Search(nStart, nPos);
564 else
565 nPos++;
566 }
567 delete pNewPattern;
568 }
569 while ((nStart <= nEndRow) && (nPos < nCount));
570
571 if (pDocument->IsStreamValid(nTab))
572 pDocument->SetStreamValid(nTab, sal_False);
573 }
574
575 #ifdef DBG_UTIL
576 TestData();
577 #endif
578 }
579
580
581 // const wird weggecastet, weil es sonst
582 // zu ineffizient/kompliziert wird!
583 #define SET_LINECOLOR(dest,c) \
584 if ((dest)) \
585 { \
586 ((SvxBorderLine*)(dest))->SetColor((c)); \
587 }
588
589 #define SET_LINE(dest,src) \
590 if ((dest)) \
591 { \
592 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
593 pCast->SetOutWidth((src)->GetOutWidth()); \
594 pCast->SetInWidth ((src)->GetInWidth()); \
595 pCast->SetDistance((src)->GetDistance()); \
596 }
597
ApplyLineStyleArea(SCROW nStartRow,SCROW nEndRow,const SvxBorderLine * pLine,sal_Bool bColorOnly)598 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
599 const SvxBorderLine* pLine, sal_Bool bColorOnly )
600 {
601 if ( bColorOnly && !pLine )
602 return;
603
604 if (ValidRow(nStartRow) && ValidRow(nEndRow))
605 {
606 SCSIZE nPos;
607 SCROW nStart=0;
608 if (!Search( nStartRow, nPos ))
609 {
610 DBG_ERROR("Search-Fehler");
611 return;
612 }
613
614 do
615 {
616 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
617 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
618 const SfxPoolItem* pBoxItem = 0;
619 SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, sal_True, &pBoxItem );
620 const SfxPoolItem* pTLBRItem = 0;
621 SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pTLBRItem );
622 const SfxPoolItem* pBLTRItem = 0;
623 SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, sal_True, &pBLTRItem );
624
625 if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
626 {
627 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
628 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
629 SCROW nY1 = nStart;
630 SCROW nY2 = pData[nPos].nRow;
631
632 SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
633 SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
634 SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
635
636 // Linienattribute holen und mit Parametern aktualisieren
637
638 if ( !pLine )
639 {
640 if( pNewBoxItem )
641 {
642 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
643 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
644 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
645 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
646 }
647 if( pNewTLBRItem && pNewTLBRItem->GetLine() )
648 pNewTLBRItem->SetLine( 0 );
649 if( pNewBLTRItem && pNewBLTRItem->GetLine() )
650 pNewBLTRItem->SetLine( 0 );
651 }
652 else
653 {
654 if ( bColorOnly )
655 {
656 Color aColor( pLine->GetColor() );
657 if( pNewBoxItem )
658 {
659 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
660 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
661 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
662 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
663 }
664 if( pNewTLBRItem )
665 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
666 if( pNewBLTRItem )
667 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
668 }
669 else
670 {
671 if( pNewBoxItem )
672 {
673 SET_LINE( pNewBoxItem->GetTop(), pLine );
674 SET_LINE( pNewBoxItem->GetBottom(), pLine );
675 SET_LINE( pNewBoxItem->GetLeft(), pLine );
676 SET_LINE( pNewBoxItem->GetRight(), pLine );
677 }
678 if( pNewTLBRItem )
679 SET_LINE( pNewTLBRItem->GetLine(), pLine );
680 if( pNewBLTRItem )
681 SET_LINE( pNewBLTRItem->GetLine(), pLine );
682 }
683 }
684 if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
685 if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
686 if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
687
688 nStart = pData[nPos].nRow + 1;
689
690 if ( nY1 < nStartRow || nY2 > nEndRow )
691 {
692 if (nY1 < nStartRow) nY1=nStartRow;
693 if (nY2 > nEndRow) nY2=nEndRow;
694 SetPatternArea( nY1, nY2, pNewPattern, sal_True );
695 Search( nStart, nPos );
696 }
697 else
698 {
699 //! aus Pool loeschen?
700 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
701 pData[nPos].pPattern = (const ScPatternAttr*)
702 &pDocument->GetPool()->Put(*pNewPattern);
703
704 if (Concat(nPos))
705 Search(nStart, nPos);
706 else
707 nPos++;
708 }
709 delete pNewBoxItem;
710 delete pNewTLBRItem;
711 delete pNewBLTRItem;
712 delete pNewPattern;
713 }
714 else
715 {
716 nStart = pData[nPos].nRow + 1;
717 nPos++;
718 }
719 }
720 while ((nStart <= nEndRow) && (nPos < nCount));
721 }
722 }
723
724 #undef SET_LINECOLOR
725 #undef SET_LINE
726
727
ApplyCacheArea(SCROW nStartRow,SCROW nEndRow,SfxItemPoolCache * pCache)728 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache )
729 {
730 #ifdef DBG_UTIL
731 TestData();
732 #endif
733
734 if (ValidRow(nStartRow) && ValidRow(nEndRow))
735 {
736 SCSIZE nPos;
737 SCROW nStart=0;
738 if (!Search( nStartRow, nPos ))
739 {
740 DBG_ERROR("Search-Fehler");
741 return;
742 }
743
744 ScAddress aAdrStart( nCol, 0, nTab );
745 ScAddress aAdrEnd ( nCol, 0, nTab );
746
747 do
748 {
749 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
750 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, sal_True );
751 ScDocumentPool::CheckRef( *pOldPattern );
752 ScDocumentPool::CheckRef( *pNewPattern );
753 if (pNewPattern != pOldPattern)
754 {
755 SCROW nY1 = nStart;
756 SCROW nY2 = pData[nPos].nRow;
757 nStart = pData[nPos].nRow + 1;
758
759 if ( nY1 < nStartRow || nY2 > nEndRow )
760 {
761 if (nY1 < nStartRow) nY1=nStartRow;
762 if (nY2 > nEndRow) nY2=nEndRow;
763 SetPatternArea( nY1, nY2, pNewPattern );
764 Search( nStart, nPos );
765 }
766 else
767 {
768 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
769
770 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
771 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
772
773 sal_Bool bNumFormatChanged;
774 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
775 rNewSet, rOldSet ) )
776 {
777 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
778 aAdrEnd .SetRow( pData[nPos].nRow );
779 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
780 #ifdef DBG_INVALIDATE
781 DBGOUTPUT("ApplyCacheArea");
782 #endif
783 }
784
785 // bedingte Formate neu gesetzt oder geloescht ?
786
787 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
788 {
789 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
790 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
791 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
792 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
793 }
794
795 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
796 pData[nPos].pPattern = pNewPattern;
797 if (Concat(nPos))
798 Search(nStart, nPos);
799 else
800 ++nPos;
801 }
802 }
803 else
804 {
805 //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
806 //! pDocument->GetPool()->Remove(*pNewPattern);
807 nStart = pData[nPos].nRow + 1;
808 ++nPos;
809 }
810 }
811 while (nStart <= nEndRow);
812
813 if (pDocument->IsStreamValid(nTab))
814 pDocument->SetStreamValid(nTab, sal_False);
815 }
816
817 #ifdef DBG_UTIL
818 TestData();
819 #endif
820 }
821
822
lcl_MergeDeep(SfxItemSet & rMergeSet,const SfxItemSet & rSource)823 void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
824 {
825 const SfxPoolItem* pNewItem;
826 const SfxPoolItem* pOldItem;
827 for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
828 {
829 // pMergeSet hat keinen Parent
830 SfxItemState eOldState = rMergeSet.GetItemState( nId, sal_False, &pOldItem );
831
832 if ( eOldState == SFX_ITEM_DEFAULT ) // Default
833 {
834 SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem );
835 if ( eNewState == SFX_ITEM_SET )
836 {
837 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
838 rMergeSet.InvalidateItem( nId );
839 }
840 }
841 else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
842 {
843 SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem );
844 if ( eNewState == SFX_ITEM_SET )
845 {
846 if ( pNewItem != pOldItem ) // beide gepuhlt
847 rMergeSet.InvalidateItem( nId );
848 }
849 else // Default
850 {
851 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
852 rMergeSet.InvalidateItem( nId );
853 }
854 }
855 // Dontcare bleibt Dontcare
856 }
857 }
858
859
MergePatternArea(SCROW nStartRow,SCROW nEndRow,ScMergePatternState & rState,sal_Bool bDeep) const860 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
861 ScMergePatternState& rState, sal_Bool bDeep ) const
862 {
863 if (ValidRow(nStartRow) && ValidRow(nEndRow))
864 {
865 SCSIZE nPos;
866 SCROW nStart=0;
867 if (!Search( nStartRow, nPos ))
868 {
869 DBG_ERROR("Search-Fehler");
870 return;
871 }
872
873 do
874 {
875 // gleiche Patterns muessen nicht mehrfach angesehen werden
876
877 const ScPatternAttr* pPattern = pData[nPos].pPattern;
878 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
879 {
880 const SfxItemSet& rThisSet = pPattern->GetItemSet();
881 if (rState.pItemSet)
882 {
883 // (*ppSet)->MergeValues( rThisSet, sal_False );
884 // geht nicht, weil die Vorlagen nicht beruecksichtigt werden
885
886 if (bDeep)
887 lcl_MergeDeep( *rState.pItemSet, rThisSet );
888 else
889 rState.pItemSet->MergeValues( rThisSet, sal_False );
890 }
891 else
892 {
893 // erstes Pattern - in Set ohne Parent kopieren
894 rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
895 rState.pItemSet->Set( rThisSet, bDeep );
896 }
897
898 rState.pOld2 = rState.pOld1;
899 rState.pOld1 = pPattern;
900 }
901
902 nStart = pData[nPos].nRow + 1;
903 ++nPos;
904 }
905 while (nStart <= nEndRow);
906 }
907 }
908
909
910
911 // Umrandung zusammenbauen
912
lcl_TestAttr(const SvxBorderLine * pOldLine,const SvxBorderLine * pNewLine,sal_uInt8 & rModified,const SvxBorderLine * & rpNew)913 sal_Bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
914 sal_uInt8& rModified, const SvxBorderLine*& rpNew )
915 {
916 if (rModified == SC_LINE_DONTCARE)
917 return sal_False; // weiter geht's nicht
918
919 if (rModified == SC_LINE_EMPTY)
920 {
921 rModified = SC_LINE_SET;
922 rpNew = pNewLine;
923 return sal_True; // zum ersten mal gesetzt
924 }
925
926 if (pOldLine == pNewLine)
927 {
928 rpNew = pOldLine;
929 return sal_False;
930 }
931
932 if (pOldLine && pNewLine)
933 if (*pOldLine == *pNewLine)
934 {
935 rpNew = pOldLine;
936 return sal_False;
937 }
938
939 rModified = SC_LINE_DONTCARE;
940 rpNew = NULL;
941 return sal_True; // andere Linie -> dontcare
942 }
943
944
lcl_MergeToFrame(SvxBoxItem * pLineOuter,SvxBoxInfoItem * pLineInner,ScLineFlags & rFlags,const ScPatternAttr * pPattern,sal_Bool bLeft,SCCOL nDistRight,sal_Bool bTop,SCROW nDistBottom)945 void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
946 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
947 sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom )
948 {
949 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
950 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
951 if ( rMerge.GetColMerge() == nDistRight + 1 )
952 nDistRight = 0;
953 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
954 nDistBottom = 0;
955
956 const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
957 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
958 const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
959 const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
960 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
961 const SvxBorderLine* pNew;
962
963 if (bTop)
964 {
965 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
966 pLineOuter->SetLine( pNew, BOX_LINE_TOP );
967 }
968 else
969 {
970 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
971 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
972 }
973
974 if (nDistBottom == 0)
975 {
976 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
977 pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
978 }
979 else
980 {
981 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
982 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
983 }
984
985 if (bLeft)
986 {
987 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
988 pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
989 }
990 else
991 {
992 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
993 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
994 }
995
996 if (nDistRight == 0)
997 {
998 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
999 pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
1000 }
1001 else
1002 {
1003 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1004 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1005 }
1006 }
1007
1008
MergeBlockFrame(SvxBoxItem * pLineOuter,SvxBoxInfoItem * pLineInner,ScLineFlags & rFlags,SCROW nStartRow,SCROW nEndRow,sal_Bool bLeft,SCCOL nDistRight) const1009 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1010 ScLineFlags& rFlags,
1011 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const
1012 {
1013 const ScPatternAttr* pPattern;
1014
1015 if (nStartRow == nEndRow)
1016 {
1017 pPattern = GetPattern( nStartRow );
1018 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 0 );
1019 }
1020 else
1021 {
1022 pPattern = GetPattern( nStartRow );
1023 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True,
1024 nEndRow-nStartRow );
1025
1026 SCSIZE nStartIndex;
1027 SCSIZE nEndIndex;
1028 Search( nStartRow+1, nStartIndex );
1029 Search( nEndRow-1, nEndIndex );
1030 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1031 {
1032 pPattern = (ScPatternAttr*) pData[i].pPattern;
1033 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False,
1034 nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1035 // nDistBottom hier immer > 0
1036 }
1037
1038 pPattern = GetPattern( nEndRow );
1039 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 0 );
1040 }
1041 }
1042
1043 //
1044 // Rahmen anwenden
1045 //
1046
1047 // ApplyFrame - auf einen Eintrag im Array
1048
1049
ApplyFrame(const SvxBoxItem * pBoxItem,const SvxBoxInfoItem * pBoxInfoItem,SCROW nStartRow,SCROW nEndRow,sal_Bool bLeft,SCCOL nDistRight,sal_Bool bTop,SCROW nDistBottom)1050 sal_Bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1051 const SvxBoxInfoItem* pBoxInfoItem,
1052 SCROW nStartRow, SCROW nEndRow,
1053 sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom )
1054 {
1055 DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
1056
1057 const ScPatternAttr* pPattern = GetPattern( nStartRow );
1058 const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1059 &pPattern->GetItemSet().Get( ATTR_BORDER );
1060
1061 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
1062 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1063 if ( rMerge.GetColMerge() == nDistRight + 1 )
1064 nDistRight = 0;
1065 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1066 nDistBottom = 0;
1067
1068 SvxBoxItem aNewFrame( *pOldFrame );
1069
1070 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1071 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1072 BOX_LINE_LEFT );
1073 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1074 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1075 BOX_LINE_RIGHT );
1076 if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1077 aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1078 BOX_LINE_TOP );
1079 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1080 aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1081 BOX_LINE_BOTTOM );
1082
1083 if (aNewFrame == *pOldFrame)
1084 {
1085 // nothing to do
1086 return sal_False;
1087 }
1088 else
1089 {
1090 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1091 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1092
1093 /* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
1094 pNewPattern->GetItemSet().Put( aNewFrame );
1095 SetPatternArea( nStartRow, nEndRow, pNewPattern, sal_True );
1096 */
1097 return sal_True;
1098 }
1099 }
1100
1101
ApplyBlockFrame(const SvxBoxItem * pLineOuter,const SvxBoxInfoItem * pLineInner,SCROW nStartRow,SCROW nEndRow,sal_Bool bLeft,SCCOL nDistRight)1102 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1103 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
1104 {
1105 if (nStartRow == nEndRow)
1106 ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, sal_True, 0 );
1107 else
1108 {
1109 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1110 sal_True, nEndRow-nStartRow );
1111
1112 if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden?
1113 {
1114 SCSIZE nStartIndex;
1115 SCSIZE nEndIndex;
1116 Search( nStartRow+1, nStartIndex );
1117 Search( nEndRow-1, nEndIndex );
1118 SCROW nTmpStart = nStartRow+1;
1119 SCROW nTmpEnd;
1120 for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1121 {
1122 nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1123 sal_Bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1124 bLeft, nDistRight, sal_False, nEndRow-nTmpEnd );
1125 nTmpStart = nTmpEnd+1;
1126 if (bChanged)
1127 {
1128 Search(nTmpStart, i);
1129 Search(nEndRow-1, nEndIndex);
1130 }
1131 else
1132 i++;
1133 }
1134 }
1135
1136 ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, sal_False, 0 );
1137 }
1138 }
1139
1140
lcl_LineSize(const SvxBorderLine & rLine)1141 long lcl_LineSize( const SvxBorderLine& rLine )
1142 {
1143 // nur eine Linie -> halbe Breite, min. 20
1144 // doppelte Linie -> halber Abstand + eine Linie (je min. 20)
1145
1146 long nTotal = 0;
1147 sal_uInt16 nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
1148 sal_uInt16 nDist = rLine.GetDistance();
1149 if (nDist)
1150 {
1151 DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(),
1152 "Linie hat Abstand, aber nur eine Breite ???" );
1153
1154 // nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20;
1155 nTotal += ( nDist > 20 ) ? nDist : 20;
1156 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1157 }
1158 else if (nWidth)
1159 // nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20;
1160 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1161
1162 //! auch halbieren ???
1163
1164 return nTotal;
1165 }
1166
1167
HasLines(SCROW nRow1,SCROW nRow2,Rectangle & rSizes,sal_Bool bLeft,sal_Bool bRight) const1168 sal_Bool ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
1169 sal_Bool bLeft, sal_Bool bRight ) const
1170 {
1171 SCSIZE nStartIndex;
1172 SCSIZE nEndIndex;
1173 Search( nRow1, nStartIndex );
1174 Search( nRow2, nEndIndex );
1175 sal_Bool bFound = sal_False;
1176
1177 const SvxBoxItem* pItem = 0;
1178 const SvxBorderLine* pLine = 0;
1179 long nCmp;
1180
1181 // oben
1182
1183 pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER);
1184 pLine = pItem->GetTop();
1185 if (pLine)
1186 {
1187 nCmp = lcl_LineSize(*pLine);
1188 if ( nCmp > rSizes.Top() )
1189 rSizes.Top() = nCmp;
1190 bFound = sal_True;
1191 }
1192
1193 // unten
1194
1195 if ( nEndIndex != nStartIndex )
1196 pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER);
1197 pLine = pItem->GetBottom();
1198 if (pLine)
1199 {
1200 nCmp = lcl_LineSize(*pLine);
1201 if ( nCmp > rSizes.Bottom() )
1202 rSizes.Bottom() = nCmp;
1203 bFound = sal_True;
1204 }
1205
1206 if ( bLeft || bRight )
1207 for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1208 {
1209 pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER);
1210
1211 // links
1212
1213 if (bLeft)
1214 {
1215 pLine = pItem->GetLeft();
1216 if (pLine)
1217 {
1218 nCmp = lcl_LineSize(*pLine);
1219 if ( nCmp > rSizes.Left() )
1220 rSizes.Left() = nCmp;
1221 bFound = sal_True;
1222 }
1223 }
1224
1225 // rechts
1226
1227 if (bRight)
1228 {
1229 pLine = pItem->GetRight();
1230 if (pLine)
1231 {
1232 nCmp = lcl_LineSize(*pLine);
1233 if ( nCmp > rSizes.Right() )
1234 rSizes.Right() = nCmp;
1235 bFound = sal_True;
1236 }
1237 }
1238 }
1239
1240 return bFound;
1241 }
1242
1243 // Testen, ob Bereich bestimmtes Attribut enthaelt
1244
HasAttrib(SCROW nRow1,SCROW nRow2,sal_uInt16 nMask) const1245 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
1246 {
1247 SCSIZE nStartIndex;
1248 SCSIZE nEndIndex;
1249 Search( nRow1, nStartIndex );
1250 Search( nRow2, nEndIndex );
1251 bool bFound = false;
1252
1253 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1254 {
1255 const ScPatternAttr* pPattern = pData[i].pPattern;
1256 if ( nMask & HASATTR_MERGED )
1257 {
1258 const ScMergeAttr* pMerge =
1259 (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1260 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1261 bFound = true;
1262 }
1263 if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1264 {
1265 const ScMergeFlagAttr* pMergeFlag =
1266 (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1267 if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1268 bFound = true;
1269 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1270 bFound = true;
1271 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1272 bFound = true;
1273 }
1274 if ( nMask & HASATTR_LINES )
1275 {
1276 const SvxBoxItem* pBox =
1277 (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1278 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1279 bFound = true;
1280 }
1281 if ( nMask & HASATTR_SHADOW )
1282 {
1283 const SvxShadowItem* pShadow =
1284 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1285 if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1286 bFound = true;
1287 }
1288 if ( nMask & HASATTR_CONDITIONAL )
1289 {
1290 const SfxUInt32Item* pConditional =
1291 (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL );
1292 if ( pConditional->GetValue() != 0 )
1293 bFound = true;
1294 }
1295 if ( nMask & HASATTR_PROTECTED )
1296 {
1297 const ScProtectionAttr* pProtect =
1298 (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1299 if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1300 bFound = true;
1301 }
1302 if ( nMask & HASATTR_ROTATE )
1303 {
1304 const SfxInt32Item* pRotate =
1305 (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1306 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1307 // (see ScPatternAttr::GetCellOrientation)
1308 sal_Int32 nAngle = pRotate->GetValue();
1309 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1310 bFound = true;
1311 }
1312 if ( nMask & HASATTR_NEEDHEIGHT )
1313 {
1314 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1315 bFound = true;
1316 else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1317 bFound = true;
1318 else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1319 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1320 bFound = true;
1321 else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue())
1322 bFound = true;
1323 else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1324 bFound = true;
1325 }
1326 if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1327 {
1328 const SvxShadowItem* pShadow =
1329 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1330 SvxShadowLocation eLoc = pShadow->GetLocation();
1331 if ( nMask & HASATTR_SHADOW_RIGHT )
1332 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1333 bFound = true;
1334 if ( nMask & HASATTR_SHADOW_DOWN )
1335 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1336 bFound = true;
1337 }
1338 if ( nMask & HASATTR_RTL )
1339 {
1340 const SvxFrameDirectionItem& rDirection =
1341 (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1342 if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1343 bFound = true;
1344 }
1345 if ( nMask & HASATTR_RIGHTORCENTER )
1346 {
1347 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1348 SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1349 ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1350 if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1351 bFound = true;
1352 }
1353 }
1354
1355 return bFound;
1356 }
1357
1358 // Bereich um evtl. enthaltene Zusammenfassungen erweitern
1359 // und evtl. MergeFlag anpassen (bRefresh)
1360
ExtendMerge(SCCOL nThisCol,SCROW nStartRow,SCROW nEndRow,SCCOL & rPaintCol,SCROW & rPaintRow,sal_Bool bRefresh,sal_Bool bAttrs)1361 sal_Bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1362 SCCOL& rPaintCol, SCROW& rPaintRow,
1363 sal_Bool bRefresh, sal_Bool bAttrs )
1364 {
1365 const ScPatternAttr* pPattern;
1366 const ScMergeAttr* pItem;
1367 SCSIZE nStartIndex;
1368 SCSIZE nEndIndex;
1369 Search( nStartRow, nStartIndex );
1370 Search( nEndRow, nEndIndex );
1371 sal_Bool bFound = sal_False;
1372
1373 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1374 {
1375 pPattern = pData[i].pPattern;
1376 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1377 SCsCOL nCountX = pItem->GetColMerge();
1378 SCsROW nCountY = pItem->GetRowMerge();
1379 if (nCountX>1 || nCountY>1)
1380 {
1381 SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1382 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1383 SCROW nMergeEndRow = nThisRow + nCountY - 1;
1384 if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1385 rPaintCol = nMergeEndCol;
1386 if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1387 rPaintRow = nMergeEndRow;
1388 bFound = sal_True;
1389
1390 if (bAttrs)
1391 {
1392 const SvxShadowItem* pShadow =
1393 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1394 SvxShadowLocation eLoc = pShadow->GetLocation();
1395 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1396 if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL )
1397 rPaintCol = nMergeEndCol+1;
1398 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1399 if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW )
1400 rPaintRow = nMergeEndRow+1;
1401 }
1402
1403 if (bRefresh)
1404 {
1405 if ( nMergeEndCol > nThisCol )
1406 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1407 nTab, SC_MF_HOR );
1408 if ( nMergeEndRow > nThisRow )
1409 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1410 nTab, SC_MF_VER );
1411 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1412 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1413 nTab, SC_MF_HOR | SC_MF_VER );
1414
1415 Search( nThisRow, i ); // Daten wurden veraendert
1416 Search( nStartRow, nStartIndex );
1417 Search( nEndRow, nEndIndex );
1418 }
1419 }
1420 }
1421
1422 return bFound;
1423 }
1424
1425
RemoveAreaMerge(SCROW nStartRow,SCROW nEndRow)1426 sal_Bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1427 {
1428 sal_Bool bFound = sal_False;
1429 const ScPatternAttr* pPattern;
1430 const ScMergeAttr* pItem;
1431 SCSIZE nIndex;
1432
1433 Search( nStartRow, nIndex );
1434 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1435 if (nThisStart < nStartRow)
1436 nThisStart = nStartRow;
1437
1438 while ( nThisStart <= nEndRow )
1439 {
1440 SCROW nThisEnd = pData[nIndex].nRow;
1441 if (nThisEnd > nEndRow)
1442 nThisEnd = nEndRow;
1443
1444 pPattern = pData[nIndex].pPattern;
1445 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1446 SCsCOL nCountX = pItem->GetColMerge();
1447 SCsROW nCountY = pItem->GetRowMerge();
1448 if (nCountX>1 || nCountY>1)
1449 {
1450 const ScMergeAttr* pAttr = (const ScMergeAttr*)
1451 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1452 const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1453 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1454
1455 DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" );
1456
1457 SCCOL nThisCol = nCol;
1458 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1459 SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1460
1461 //! ApplyAttr fuer Bereiche !!!
1462
1463 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1464 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1465
1466 ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1467 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1468 pSet->Put( *pFlagAttr );
1469 pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1470 nTab, *pNewPattern );
1471 delete pNewPattern;
1472
1473 Search( nThisEnd, nIndex ); // Daten wurden veraendert !!!
1474 }
1475
1476 ++nIndex;
1477 if ( nIndex < nCount )
1478 nThisStart = pData[nIndex-1].nRow+1;
1479 else
1480 nThisStart = MAXROW+1; // Ende
1481 }
1482
1483 return bFound;
1484 }
1485
1486 // Bereich loeschen, aber Merge-Flags stehenlassen
1487
DeleteAreaSafe(SCROW nStartRow,SCROW nEndRow)1488 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1489 {
1490 SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), sal_True );
1491 }
1492
1493
SetPatternAreaSafe(SCROW nStartRow,SCROW nEndRow,const ScPatternAttr * pWantedPattern,sal_Bool bDefault)1494 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1495 const ScPatternAttr* pWantedPattern, sal_Bool bDefault )
1496 {
1497 const ScPatternAttr* pOldPattern;
1498 const ScMergeFlagAttr* pItem;
1499
1500 SCSIZE nIndex;
1501 SCROW nRow;
1502 SCROW nThisRow;
1503 sal_Bool bFirstUse = sal_True;
1504
1505 Search( nStartRow, nIndex );
1506 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1507 while ( nThisRow <= nEndRow )
1508 {
1509 pOldPattern = pData[nIndex].pPattern;
1510 if (pOldPattern != pWantedPattern) //! else-Zweig ?
1511 {
1512 if (nThisRow < nStartRow) nThisRow = nStartRow;
1513 nRow = pData[nIndex].nRow;
1514 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1515 pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1516
1517 if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1518 {
1519 // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work
1520 // because it would have no cell style information.
1521 // Instead, the document's GetDefPattern is copied. Since it is passed as
1522 // pWantedPattern, no special treatment of default is needed here anymore.
1523 ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
1524 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1525 pSet->Put( *pItem );
1526 SetPatternArea( nThisRow, nAttrRow, pNewPattern, sal_True );
1527 delete pNewPattern;
1528 }
1529 else
1530 {
1531 if ( !bDefault )
1532 {
1533 if (bFirstUse)
1534 bFirstUse = sal_False;
1535 else
1536 pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon!
1537 }
1538 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1539 }
1540
1541 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1542 }
1543
1544 ++nIndex;
1545 nThisRow = pData[nIndex-1].nRow+1;
1546 }
1547 }
1548
1549
ApplyFlags(SCROW nStartRow,SCROW nEndRow,sal_Int16 nFlags)1550 sal_Bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1551 {
1552 const ScPatternAttr* pOldPattern;
1553
1554 sal_Int16 nOldValue;
1555 SCSIZE nIndex;
1556 SCROW nRow;
1557 SCROW nThisRow;
1558 sal_Bool bChanged = sal_False;
1559
1560 Search( nStartRow, nIndex );
1561 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1562 if (nThisRow < nStartRow) nThisRow = nStartRow;
1563
1564 while ( nThisRow <= nEndRow )
1565 {
1566 pOldPattern = pData[nIndex].pPattern;
1567 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1568 if ( (nOldValue | nFlags) != nOldValue )
1569 {
1570 nRow = pData[nIndex].nRow;
1571 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1572 ScPatternAttr aNewPattern(*pOldPattern);
1573 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1574 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1575 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1576 bChanged = sal_True;
1577 }
1578
1579 ++nIndex;
1580 nThisRow = pData[nIndex-1].nRow+1;
1581 }
1582
1583 return bChanged;
1584 }
1585
1586
RemoveFlags(SCROW nStartRow,SCROW nEndRow,sal_Int16 nFlags)1587 sal_Bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1588 {
1589 const ScPatternAttr* pOldPattern;
1590
1591 sal_Int16 nOldValue;
1592 SCSIZE nIndex;
1593 SCROW nRow;
1594 SCROW nThisRow;
1595 sal_Bool bChanged = sal_False;
1596
1597 Search( nStartRow, nIndex );
1598 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1599 if (nThisRow < nStartRow) nThisRow = nStartRow;
1600
1601 while ( nThisRow <= nEndRow )
1602 {
1603 pOldPattern = pData[nIndex].pPattern;
1604 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1605 if ( (nOldValue & ~nFlags) != nOldValue )
1606 {
1607 nRow = pData[nIndex].nRow;
1608 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1609 ScPatternAttr aNewPattern(*pOldPattern);
1610 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1611 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1612 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1613 bChanged = sal_True;
1614 }
1615
1616 ++nIndex;
1617 nThisRow = pData[nIndex-1].nRow+1;
1618 }
1619
1620 return bChanged;
1621 }
1622
1623
ClearItems(SCROW nStartRow,SCROW nEndRow,const sal_uInt16 * pWhich)1624 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1625 {
1626 const ScPatternAttr* pOldPattern;
1627
1628 SCSIZE nIndex;
1629 SCROW nRow;
1630 SCROW nThisRow;
1631
1632 Search( nStartRow, nIndex );
1633 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1634 if (nThisRow < nStartRow) nThisRow = nStartRow;
1635
1636 while ( nThisRow <= nEndRow )
1637 {
1638 pOldPattern = pData[nIndex].pPattern;
1639 if ( pOldPattern->HasItemsSet( pWhich ) )
1640 {
1641 ScPatternAttr aNewPattern(*pOldPattern);
1642 aNewPattern.ClearItems( pWhich );
1643
1644 nRow = pData[nIndex].nRow;
1645 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1646 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1647 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1648 }
1649
1650 ++nIndex;
1651 nThisRow = pData[nIndex-1].nRow+1;
1652 }
1653 }
1654
1655
ChangeIndent(SCROW nStartRow,SCROW nEndRow,sal_Bool bIncrement)1656 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, sal_Bool bIncrement )
1657 {
1658 SCSIZE nIndex;
1659 Search( nStartRow, nIndex );
1660 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1661 if (nThisStart < nStartRow) nThisStart = nStartRow;
1662
1663 while ( nThisStart <= nEndRow )
1664 {
1665 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1666 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1667 const SfxPoolItem* pItem;
1668
1669 sal_Bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, sal_False, &pItem ) != SFX_ITEM_SET
1670 || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
1671 sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1672 sal_uInt16 nNewValue = nOldValue;
1673 if ( bIncrement )
1674 {
1675 if ( nNewValue < SC_MAX_INDENT )
1676 {
1677 nNewValue += SC_INDENT_STEP;
1678 if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
1679 }
1680 }
1681 else
1682 {
1683 if ( nNewValue > 0 )
1684 {
1685 if ( nNewValue > SC_INDENT_STEP )
1686 nNewValue -= SC_INDENT_STEP;
1687 else
1688 nNewValue = 0;
1689 }
1690 }
1691
1692 if ( bNeedJust || nNewValue != nOldValue )
1693 {
1694 SCROW nThisEnd = pData[nIndex].nRow;
1695 SCROW nAttrRow = Min( nThisEnd, nEndRow );
1696 ScPatternAttr aNewPattern(*pOldPattern);
1697 aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1698 if ( bNeedJust )
1699 aNewPattern.GetItemSet().Put(
1700 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1701 SetPatternArea( nThisStart, nAttrRow, &aNewPattern, sal_True );
1702
1703 nThisStart = nThisEnd + 1;
1704 Search( nThisStart, nIndex ); // Daten wurden veraendert !!!
1705 }
1706 else
1707 {
1708 nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen...
1709 ++nIndex;
1710 }
1711 }
1712 }
1713
1714
GetNextUnprotected(SCsROW nRow,sal_Bool bUp) const1715 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, sal_Bool bUp ) const
1716 {
1717 long nRet = nRow;
1718 if (VALIDROW(nRow))
1719 {
1720 SCSIZE nIndex;
1721 Search(nRow, nIndex);
1722 while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1723 GetItem(ATTR_PROTECTION)).GetProtection())
1724 {
1725 if (bUp)
1726 {
1727 if (nIndex==0)
1728 return -1; // nichts gefunden
1729 --nIndex;
1730 nRet = pData[nIndex].nRow;
1731 }
1732 else
1733 {
1734 nRet = pData[nIndex].nRow+1;
1735 ++nIndex;
1736 if (nIndex>=nCount)
1737 return MAXROW+1; // nichts gefunden
1738 }
1739 }
1740 }
1741 return nRet;
1742 }
1743
FindStyleSheet(const SfxStyleSheetBase * pStyleSheet,ScFlatBoolRowSegments & rUsedRows,bool bReset)1744 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1745 {
1746 SCROW nStart = 0;
1747 SCSIZE nPos = 0;
1748 while (nPos < nCount)
1749 {
1750 SCROW nEnd = pData[nPos].nRow;
1751 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1752 {
1753 // for (SCROW nRow = nStart; nRow <= nEnd; nRow++)
1754 // pUsed[nRow] = sal_True;
1755
1756 rUsedRows.setTrue(nStart, nEnd);
1757
1758 if (bReset)
1759 {
1760 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1761 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1762 pNewPattern->SetStyleSheet( (ScStyleSheet*)
1763 pDocument->GetStyleSheetPool()->
1764 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1765 SFX_STYLE_FAMILY_PARA,
1766 SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1767 pData[nPos].pPattern = (const ScPatternAttr*)
1768 &pDocument->GetPool()->Put(*pNewPattern);
1769 delete pNewPattern;
1770
1771 if (Concat(nPos))
1772 {
1773 Search(nStart, nPos);
1774 --nPos; // wegen ++ am Ende
1775 }
1776 }
1777 }
1778 nStart = nEnd + 1;
1779 ++nPos;
1780 }
1781 }
1782
1783
IsStyleSheetUsed(const ScStyleSheet & rStyle,sal_Bool bGatherAllStyles) const1784 sal_Bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1785 sal_Bool bGatherAllStyles ) const
1786 {
1787 sal_Bool bIsUsed = sal_False;
1788 SCSIZE nPos = 0;
1789
1790 while ( nPos < nCount )
1791 {
1792 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1793 if ( pStyle )
1794 {
1795 pStyle->SetUsage( ScStyleSheet::USED );
1796 if ( pStyle == &rStyle )
1797 {
1798 if ( !bGatherAllStyles )
1799 return sal_True;
1800 bIsUsed = sal_True;
1801 }
1802 }
1803 nPos++;
1804 }
1805
1806 return bIsUsed;
1807 }
1808
1809
IsEmpty() const1810 sal_Bool ScAttrArray::IsEmpty() const
1811 {
1812 if (nCount == 1)
1813 {
1814 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1815 return sal_False;
1816 else
1817 return sal_True;
1818 }
1819 else
1820 return sal_False;
1821 }
1822
1823
1824 //UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const
1825 //UNUSED2008-05 {
1826 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" );
1827 //UNUSED2008-05
1828 //UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1829 //UNUSED2008-05 return 0;
1830 //UNUSED2008-05 else
1831 //UNUSED2008-05 {
1832 //UNUSED2008-05 if (nCount==1)
1833 //UNUSED2008-05 return 0; // leer
1834 //UNUSED2008-05 else
1835 //UNUSED2008-05 return pData[0].nRow + 1;
1836 //UNUSED2008-05 }
1837 //UNUSED2008-05 }
1838 //UNUSED2008-05
1839 //UNUSED2008-05
1840 //UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( sal_Bool bIncludeBottom ) const
1841 //UNUSED2008-05 {
1842 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" );
1843 //UNUSED2008-05
1844 //UNUSED2008-05 if (bIncludeBottom)
1845 //UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() );
1846 //UNUSED2008-05
1847 //UNUSED2008-05 if (bIncludeBottom)
1848 //UNUSED2008-05 return MAXROW;
1849 //UNUSED2008-05 else
1850 //UNUSED2008-05 {
1851 //UNUSED2008-05 if (nCount<=1)
1852 //UNUSED2008-05 return 0; // leer
1853 //UNUSED2008-05 else
1854 //UNUSED2008-05 return pData[nCount-2].nRow;
1855 //UNUSED2008-05 }
1856 //UNUSED2008-05 }
1857
1858
GetFirstVisibleAttr(SCROW & rFirstRow) const1859 sal_Bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1860 {
1861 DBG_ASSERT( nCount, "nCount == 0" );
1862
1863 sal_Bool bFound = sal_False;
1864 SCSIZE nStart = 0;
1865
1866 // Skip first entry if more than 1 row.
1867 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1868
1869 SCSIZE nVisStart = 1;
1870 while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1871 ++nVisStart;
1872 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1873 nStart = nVisStart;
1874
1875 while ( nStart < nCount && !bFound )
1876 {
1877 if ( pData[nStart].pPattern->IsVisible() )
1878 {
1879 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1880 bFound = sal_True;
1881 }
1882 else
1883 ++nStart;
1884 }
1885
1886 return bFound;
1887 }
1888
1889 // size (rows) of a range of attributes after cell content where the search is stopped
1890 // (more than a default page size, 2*42 because it's as good as any number)
1891
1892 const SCROW SC_VISATTR_STOP = 84;
1893
GetLastVisibleAttr(SCROW & rLastRow,SCROW nLastData) const1894 sal_Bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1895 {
1896 // #i30830# changed behavior:
1897 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1898 // below the last content cell
1899
1900 if ( nLastData == MAXROW )
1901 {
1902 rLastRow = MAXROW; // can't look for attributes below MAXROW
1903 return sal_True;
1904 }
1905
1906 sal_Bool bFound = sal_False;
1907
1908 // loop backwards from the end instead of using Search, assuming that
1909 // there usually aren't many attributes below the last cell
1910
1911 SCSIZE nPos = nCount;
1912 while ( nPos > 0 && pData[nPos-1].nRow > nLastData )
1913 {
1914 SCSIZE nEndPos = nPos - 1;
1915 SCSIZE nStartPos = nEndPos; // find range of visually equal formats
1916 while ( nStartPos > 0 &&
1917 pData[nStartPos-1].nRow > nLastData &&
1918 pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) )
1919 --nStartPos;
1920
1921 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0;
1922 if ( nAttrStartRow <= nLastData )
1923 nAttrStartRow = nLastData + 1;
1924 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1925 if ( nAttrSize >= SC_VISATTR_STOP )
1926 {
1927 bFound = sal_False; // ignore this range and below
1928 }
1929 else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
1930 {
1931 rLastRow = pData[nEndPos].nRow;
1932 bFound = sal_True;
1933 }
1934
1935 nPos = nStartPos; // look further from the top of the range
1936 }
1937
1938 return bFound;
1939 }
1940
GetLastAttr(SCROW & rLastRow,SCROW nLastData) const1941 sal_Bool ScAttrArray::GetLastAttr( SCROW& rLastRow, SCROW nLastData ) const
1942 {
1943 if ( nLastData == MAXROW )
1944 {
1945 rLastRow = MAXROW;
1946 return sal_True;
1947 }
1948
1949 sal_Bool bFound = sal_False;
1950
1951 // Loop backwards from the end instead of using Search, assuming that
1952 // there usually aren't many attributes below the last cell.
1953 SCSIZE nPos = nCount;
1954 while ( nPos > 0 && pData[nPos - 1].nRow > nLastData )
1955 {
1956 SCSIZE nEndPos = nPos - 1;
1957 SCSIZE nStartPos = nEndPos;
1958 while ( nStartPos > 0 && pData[nStartPos - 1].nRow > nLastData &&
1959 pData[nStartPos - 1].pPattern->IsEqual( *pData[nStartPos].pPattern ) )
1960 --nStartPos;
1961
1962 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos - 1].nRow + 1 ) : 0;
1963 if ( nAttrStartRow <= nLastData )
1964 nAttrStartRow = nLastData + 1;
1965 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1966 if ( nAttrSize >= SC_VISATTR_STOP )
1967 {
1968 bFound = sal_False;
1969 }
1970 else if ( !bFound )
1971 {
1972 rLastRow = pData[nEndPos].nRow;
1973 bFound = sal_True;
1974 }
1975
1976 // look further from the top of the range.
1977 nPos = nStartPos;
1978 }
1979
1980 return bFound;
1981 }
1982
1983
HasVisibleAttrIn(SCROW nStartRow,SCROW nEndRow) const1984 sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1985 {
1986 SCSIZE nIndex;
1987 Search( nStartRow, nIndex );
1988 SCROW nThisStart = nStartRow;
1989 sal_Bool bFound = sal_False;
1990 while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1991 {
1992 if ( pData[nIndex].pPattern->IsVisible() )
1993 bFound = sal_True;
1994
1995 nThisStart = pData[nIndex].nRow + 1;
1996 ++nIndex;
1997 }
1998
1999 return bFound;
2000 }
2001
2002
IsVisibleEqual(const ScAttrArray & rOther,SCROW nStartRow,SCROW nEndRow) const2003 sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
2004 SCROW nStartRow, SCROW nEndRow ) const
2005 {
2006 sal_Bool bEqual = sal_True;
2007 SCSIZE nThisPos = 0;
2008 SCSIZE nOtherPos = 0;
2009 if ( nStartRow > 0 )
2010 {
2011 Search( nStartRow, nThisPos );
2012 rOther.Search( nStartRow, nOtherPos );
2013 }
2014
2015 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
2016 {
2017 SCROW nThisRow = pData[nThisPos].nRow;
2018 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2019 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2020 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2021 bEqual = ( pThisPattern == pOtherPattern ||
2022 pThisPattern->IsVisibleEqual(*pOtherPattern) );
2023
2024 if ( nThisRow >= nOtherRow )
2025 {
2026 if ( nOtherRow >= nEndRow ) break;
2027 ++nOtherPos;
2028 }
2029 if ( nThisRow <= nOtherRow )
2030 {
2031 if ( nThisRow >= nEndRow ) break;
2032 ++nThisPos;
2033 }
2034 }
2035
2036 return bEqual;
2037 }
2038
2039
IsAllEqual(const ScAttrArray & rOther,SCROW nStartRow,SCROW nEndRow) const2040 sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2041 {
2042 //! mit IsVisibleEqual zusammenfassen?
2043
2044 sal_Bool bEqual = sal_True;
2045 SCSIZE nThisPos = 0;
2046 SCSIZE nOtherPos = 0;
2047 if ( nStartRow > 0 )
2048 {
2049 Search( nStartRow, nThisPos );
2050 rOther.Search( nStartRow, nOtherPos );
2051 }
2052
2053 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
2054 {
2055 SCROW nThisRow = pData[nThisPos].nRow;
2056 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2057 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2058 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2059 bEqual = ( pThisPattern == pOtherPattern );
2060
2061 if ( nThisRow >= nOtherRow )
2062 {
2063 if ( nOtherRow >= nEndRow ) break;
2064 ++nOtherPos;
2065 }
2066 if ( nThisRow <= nOtherRow )
2067 {
2068 if ( nThisRow >= nEndRow ) break;
2069 ++nThisPos;
2070 }
2071 }
2072
2073 return bEqual;
2074 }
2075
2076
TestInsertCol(SCROW nStartRow,SCROW nEndRow) const2077 sal_Bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2078 {
2079 // horizontal zusammengefasste duerfen nicht herausgeschoben werden
2080 // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2081
2082 sal_Bool bTest = sal_True;
2083 if (!IsEmpty())
2084 {
2085 SCSIZE nIndex = 0;
2086 if ( nStartRow > 0 )
2087 Search( nStartRow, nIndex );
2088
2089 for ( ; nIndex < nCount; nIndex++ )
2090 {
2091 if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2092 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2093 {
2094 bTest = sal_False; // darf nicht herausgeschoben werden
2095 break;
2096 }
2097 if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs
2098 break;
2099 }
2100 }
2101 return bTest;
2102 }
2103
2104
TestInsertRow(SCSIZE nSize) const2105 sal_Bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2106 {
2107 // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2108 // wuerde eine kaputte Zusammenfassung uebrigbleiben
2109
2110 if (pData)
2111 {
2112 // MAXROW + 1 - nSize = erste herausgeschobene Zeile
2113
2114 SCSIZE nFirstLost = nCount-1;
2115 while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2116 --nFirstLost;
2117
2118 if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2119 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2120 return sal_False;
2121 }
2122
2123 return sal_True;
2124 }
2125
2126
InsertRow(SCROW nStartRow,SCSIZE nSize)2127 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2128 {
2129 if (!pData)
2130 return;
2131
2132 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern
2133 SCSIZE nIndex;
2134 Search( nSearch, nIndex );
2135
2136 // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
2137 // (darum hinterher wieder loeschen)
2138
2139 sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2140
2141 SCSIZE nRemove = 0;
2142 SCSIZE i;
2143 for (i = nIndex; i < nCount-1; i++)
2144 {
2145 SCROW nNew = pData[i].nRow + nSize;
2146 if ( nNew >= MAXROW ) // Ende erreicht ?
2147 {
2148 nNew = MAXROW;
2149 if (!nRemove)
2150 nRemove = i+1; // folgende loeschen
2151 }
2152 pData[i].nRow = nNew;
2153 }
2154
2155 // muessen Eintraege am Ende geloescht werden?
2156
2157 if (nRemove && nRemove < nCount)
2158 DeleteRange( nRemove, nCount-1 );
2159
2160 if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren
2161 {
2162 //! ApplyAttr fuer Bereiche !!!
2163
2164 const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2165 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2166 pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2167
2168 // im eingefuegten Bereich ist nichts zusammengefasst
2169 }
2170
2171 // Don't duplicate the merge flags in the inserted row.
2172 // #i108488# SC_MF_SCENARIO has to be allowed.
2173 RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2174 }
2175
2176
DeleteRow(SCROW nStartRow,SCSIZE nSize)2177 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2178 {
2179 if (pData)
2180 {
2181 sal_Bool bFirst=sal_True;
2182 SCSIZE nStartIndex = 0;
2183 SCSIZE nEndIndex = 0;
2184 SCSIZE i;
2185
2186 for ( i = 0; i < nCount-1; i++)
2187 if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2188 {
2189 if (bFirst)
2190 {
2191 nStartIndex = i;
2192 bFirst = sal_False;
2193 }
2194 nEndIndex = i;
2195 }
2196 if (!bFirst)
2197 {
2198 SCROW nStart;
2199 if (nStartIndex==0)
2200 nStart = 0;
2201 else
2202 nStart = pData[nStartIndex-1].nRow + 1;
2203
2204 if (nStart < nStartRow)
2205 {
2206 pData[nStartIndex].nRow = nStartRow - 1;
2207 ++nStartIndex;
2208 }
2209 if (nEndIndex >= nStartIndex)
2210 {
2211 DeleteRange( nStartIndex, nEndIndex );
2212 if (nStartIndex > 0)
2213 if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2214 DeleteRange( nStartIndex-1, nStartIndex-1 );
2215 }
2216 }
2217 for (i = 0; i < nCount-1; i++)
2218 if (pData[i].nRow >= nStartRow)
2219 pData[i].nRow -= nSize;
2220
2221 // unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
2222 // stattdessen nur Merge-Flags loeschen
2223
2224 RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2225 }
2226 }
2227
2228
DeleteRange(SCSIZE nStartIndex,SCSIZE nEndIndex)2229 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2230 {
2231 ScDocumentPool* pDocPool = pDocument->GetPool();
2232 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2233 pDocPool->Remove(*pData[i].pPattern);
2234
2235 memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2236 nCount -= nEndIndex-nStartIndex+1;
2237 }
2238
2239
DeleteArea(SCROW nStartRow,SCROW nEndRow)2240 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2241 {
2242 RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen
2243
2244 if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2245 SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2246 else
2247 DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen
2248 }
2249
2250
DeleteHardAttr(SCROW nStartRow,SCROW nEndRow)2251 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2252 {
2253 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2254 const ScPatternAttr* pOldPattern;
2255
2256 SCSIZE nIndex;
2257 SCROW nRow;
2258 SCROW nThisRow;
2259
2260 Search( nStartRow, nIndex );
2261 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2262 if (nThisRow < nStartRow) nThisRow = nStartRow;
2263
2264 while ( nThisRow <= nEndRow )
2265 {
2266 pOldPattern = pData[nIndex].pPattern;
2267
2268 if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ?
2269 {
2270 nRow = pData[nIndex].nRow;
2271 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
2272
2273 ScPatternAttr aNewPattern(*pOldPattern);
2274 SfxItemSet& rSet = aNewPattern.GetItemSet();
2275 for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2276 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2277 rSet.ClearItem(nId);
2278
2279 if ( aNewPattern == *pDefPattern )
2280 SetPatternArea( nThisRow, nAttrRow, pDefPattern, sal_False );
2281 else
2282 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2283
2284 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
2285 }
2286
2287 ++nIndex;
2288 nThisRow = pData[nIndex-1].nRow+1;
2289 }
2290 }
2291
2292 // Verschieben innerhalb eines Dokuments
2293
MoveTo(SCROW nStartRow,SCROW nEndRow,ScAttrArray & rAttrArray)2294 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2295 {
2296 SCROW nStart = nStartRow;
2297 for (SCSIZE i = 0; i < nCount; i++)
2298 {
2299 if ((pData[i].nRow >= nStartRow) && ((i==0) ? sal_True : pData[i-1].nRow < nEndRow))
2300 {
2301 // Kopieren (bPutToPool=sal_True)
2302 rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2303 pData[i].pPattern, sal_True );
2304 }
2305 nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2306 }
2307 DeleteArea(nStartRow, nEndRow);
2308 }
2309
2310
2311 // Kopieren zwischen Dokumenten (Clipboard)
2312
CopyArea(SCROW nStartRow,SCROW nEndRow,long nDy,ScAttrArray & rAttrArray,sal_Int16 nStripFlags)2313 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
2314 sal_Int16 nStripFlags )
2315 {
2316 nStartRow -= nDy; // Source
2317 nEndRow -= nDy;
2318
2319 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2320 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2321
2322 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2323 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2324 sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2325
2326 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2327 {
2328 if (pData[i].nRow >= nStartRow)
2329 {
2330 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2331 const ScPatternAttr* pNewPattern;
2332
2333 if (IsDefaultItem( pOldPattern ))
2334 {
2335 // am Default muss nichts veraendert werden
2336
2337 pNewPattern = (const ScPatternAttr*)
2338 &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2339 }
2340 else if ( nStripFlags )
2341 {
2342 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2343 sal_Int16 nNewFlags = 0;
2344 if ( nStripFlags != SC_MF_ALL )
2345 nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2346 GetValue() & ~nStripFlags;
2347
2348 if ( nNewFlags )
2349 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2350 else
2351 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2352
2353 if (bSamePool)
2354 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2355 else
2356 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2357 delete pTmpPattern;
2358 }
2359 else
2360 {
2361 if (bSamePool)
2362 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2363 else
2364 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2365 }
2366
2367 rAttrArray.SetPatternArea(nDestStart,
2368 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2369 }
2370
2371 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2372 // can be negative
2373 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2374 }
2375 }
2376
2377 // Flags stehenlassen
2378 //! mit CopyArea zusammenfassen !!!
2379
CopyAreaSafe(SCROW nStartRow,SCROW nEndRow,long nDy,ScAttrArray & rAttrArray)2380 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2381 {
2382 nStartRow -= nDy; // Source
2383 nEndRow -= nDy;
2384
2385 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2386 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2387
2388 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2389 {
2390 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2391 return;
2392 }
2393
2394 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2395 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2396 sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2397
2398 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2399 {
2400 if (pData[i].nRow >= nStartRow)
2401 {
2402 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2403 const ScPatternAttr* pNewPattern;
2404
2405 if (bSamePool)
2406 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2407 else
2408 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2409
2410 rAttrArray.SetPatternAreaSafe(nDestStart,
2411 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, sal_False);
2412 }
2413
2414 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2415 // can be negative
2416 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2417 }
2418 }
2419
2420
SearchStyle(SCsROW nRow,const ScStyleSheet * pSearchStyle,sal_Bool bUp,ScMarkArray * pMarkArray)2421 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2422 sal_Bool bUp, ScMarkArray* pMarkArray )
2423 {
2424 sal_Bool bFound = sal_False;
2425
2426 if (pMarkArray)
2427 {
2428 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2429 if (!VALIDROW(nRow))
2430 return nRow;
2431 }
2432
2433 SCSIZE nIndex;
2434 Search(nRow, nIndex);
2435 const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2436
2437 while (nIndex < nCount && !bFound)
2438 {
2439 if (pPattern->GetStyleSheet() == pSearchStyle)
2440 {
2441 if (pMarkArray)
2442 {
2443 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2444 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2445 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2446 bFound = sal_True;
2447 }
2448 else
2449 bFound = sal_True;
2450 }
2451
2452 if (!bFound)
2453 {
2454 if (bUp)
2455 {
2456 if (nIndex==0)
2457 {
2458 nIndex = nCount;
2459 nRow = -1;
2460 }
2461 else
2462 {
2463 --nIndex;
2464 nRow = pData[nIndex].nRow;
2465 pPattern = pData[nIndex].pPattern;
2466 }
2467 }
2468 else
2469 {
2470 nRow = pData[nIndex].nRow+1;
2471 ++nIndex;
2472 if (nIndex<nCount)
2473 pPattern = pData[nIndex].pPattern;
2474 }
2475 }
2476 }
2477
2478 DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
2479
2480 return nRow;
2481 }
2482
2483
SearchStyleRange(SCsROW & rRow,SCsROW & rEndRow,const ScStyleSheet * pSearchStyle,sal_Bool bUp,ScMarkArray * pMarkArray)2484 sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
2485 const ScStyleSheet* pSearchStyle, sal_Bool bUp, ScMarkArray* pMarkArray )
2486 {
2487 SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2488 if (VALIDROW(nStartRow))
2489 {
2490 SCSIZE nIndex;
2491 Search(nStartRow,nIndex);
2492
2493 rRow = nStartRow;
2494 if (bUp)
2495 {
2496 if (nIndex>0)
2497 rEndRow = pData[nIndex-1].nRow + 1;
2498 else
2499 rEndRow = 0;
2500 if (pMarkArray)
2501 {
2502 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_True );
2503 if (nMarkEnd>rEndRow)
2504 rEndRow = nMarkEnd;
2505 }
2506 }
2507 else
2508 {
2509 rEndRow = pData[nIndex].nRow;
2510 if (pMarkArray)
2511 {
2512 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False );
2513 if (nMarkEnd<rEndRow)
2514 rEndRow = nMarkEnd;
2515 }
2516 }
2517
2518 return sal_True;
2519 }
2520 else
2521 return sal_False;
2522 }
2523
2524 //------------------------------------------------------------------------
2525 //
2526 // Laden / Speichern
2527 //
2528
2529
2530 #if 0
2531 void ScAttrArray::Save( SvStream& /* rStream */ ) const
2532 {
2533 #if SC_ROWLIMIT_STREAM_ACCESS
2534 #error address types changed!
2535 ScWriteHeader aHdr( rStream, 8 );
2536
2537 ScDocumentPool* pDocPool = pDocument->GetPool();
2538
2539 sal_uInt16 nSaveCount = nCount;
2540 SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
2541 if ( nSaveMaxRow != MAXROW )
2542 {
2543 if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
2544 {
2545 pDocument->SetLostData(); // Warnung ausgeben
2546 do
2547 --nSaveCount;
2548 while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
2549 }
2550 }
2551
2552 rStream << nSaveCount;
2553
2554 const SfxPoolItem* pItem;
2555 for (SCSIZE i=0; i<nSaveCount; i++)
2556 {
2557 rStream << Min( pData[i].nRow, nSaveMaxRow );
2558
2559 const ScPatternAttr* pPattern = pData[i].pPattern;
2560 pDocPool->StoreSurrogate( rStream, pPattern );
2561
2562 // sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
2563 if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET)
2564 pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2565
2566 if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_False,&pItem) == SFX_ITEM_SET)
2567 pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2568 }
2569 #endif // SC_ROWLIMIT_STREAM_ACCESS
2570 }
2571
2572
2573 void ScAttrArray::Load( SvStream& /* rStream */ )
2574 {
2575 #if SC_ROWLIMIT_STREAM_ACCESS
2576 #error address types changed!
2577 ScDocumentPool* pDocPool = pDocument->GetPool();
2578
2579 ScReadHeader aHdr( rStream );
2580
2581 sal_uInt16 nNewCount;
2582 rStream >> nNewCount;
2583 if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross?
2584 {
2585 pDocument->SetLostData();
2586 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2587 return;
2588 }
2589
2590 Reset( pDocument->GetDefPattern(), sal_False ); // loeschen
2591 pData = new ScAttrEntry[nNewCount]; // neu anlegen
2592 for (SCSIZE i=0; i<nNewCount; i++)
2593 {
2594 rStream >> pData[i].nRow;
2595
2596 sal_uInt16 nWhich = ATTR_PATTERN;
2597 const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
2598 pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
2599 if (!pNewPattern)
2600 {
2601 // da is was schiefgelaufen
2602 DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
2603 pNewPattern = pDocument->GetDefPattern();
2604 }
2605 ScDocumentPool::CheckRef( *pNewPattern );
2606 pData[i].pPattern = pNewPattern;
2607
2608 // LoadSurrogate erhoeht auch die Ref
2609 }
2610 nCount = nLimit = nNewCount;
2611
2612 if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
2613 {
2614 pDocument->SetLostData();
2615 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2616 return;
2617 }
2618
2619 if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen?
2620 {
2621 // Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
2622
2623 DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
2624 pData[nCount-1].nRow = MAXROW;
2625 }
2626 #endif // SC_ROWLIMIT_STREAM_ACCESS
2627 }
2628 #endif
2629
2630
2631 //UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad()
2632 //UNUSED2008-05 {
2633 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
2634 //UNUSED2008-05 const sal_uLong nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
2635 //UNUSED2008-05 SCSIZE nIndex = 0;
2636 //UNUSED2008-05 SCROW nThisRow = 0;
2637 //UNUSED2008-05
2638 //UNUSED2008-05 while ( nThisRow <= MAXROW )
2639 //UNUSED2008-05 {
2640 //UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2641 //UNUSED2008-05 const SfxPoolItem* pItem;
2642 //UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, sal_False, &pItem ) == SFX_ITEM_SET )
2643 //UNUSED2008-05 {
2644 //UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
2645 //UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName();
2646 //UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
2647 //UNUSED2008-05 if ( xFontConverter )
2648 //UNUSED2008-05 {
2649 //UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) );
2650 //UNUSED2008-05 if ( aNewName != rOldName )
2651 //UNUSED2008-05 {
2652 //UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow;
2653 //UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
2654 //UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(),
2655 //UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
2656 //UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern );
2657 //UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem );
2658 //UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2659 //UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed
2660 //UNUSED2008-05 }
2661 //UNUSED2008-05 }
2662 //UNUSED2008-05 }
2663 //UNUSED2008-05 ++nIndex;
2664 //UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1;
2665 //UNUSED2008-05 }
2666 //UNUSED2008-05 }
2667
Count(SCROW nStartRow,SCROW nEndRow)2668 SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow )
2669 {
2670 SCSIZE nIndex1, nIndex2;
2671
2672 if( !Search( nStartRow, nIndex1 ) )
2673 return 0;
2674
2675 if( !Search( nEndRow, nIndex2 ) )
2676 nIndex2 = this->nCount - 1;
2677
2678 return nIndex2 - nIndex1 + 1;
2679 }
2680