xref: /AOO41X/main/sc/source/core/data/attarray.cxx (revision 8f4c7c28c0e8f794fb1048a19304c40597e0d6b9)
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