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 // INCLUDE ---------------------------------------------------------------
30
31 #include <map>
32
33 #include <svl/poolcach.hxx>
34 #include <svl/zforlist.hxx>
35 #include <editeng/scripttypeitem.hxx>
36 #include <string.h>
37
38 #include "scitems.hxx"
39 #include "column.hxx"
40 #include "cell.hxx"
41 #include "document.hxx"
42 #include "docpool.hxx"
43 #include "attarray.hxx"
44 #include "patattr.hxx"
45 #include "compiler.hxx"
46 #include "brdcst.hxx"
47 #include "markdata.hxx"
48 #include "detfunc.hxx" // for Notes in Sort/Swap
49 #include "postit.hxx"
50
51 //#pragma optimize ( "", off )
52 // nur Search ohne Optimierung!
53
54 // STATIC DATA -----------------------------------------------------------
55 using namespace formula;
56
IsAmbiguousScriptNonZero(sal_uInt8 nScript)57 inline sal_Bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
58 {
59 //! move to a header file
60 return ( nScript != SCRIPTTYPE_LATIN &&
61 nScript != SCRIPTTYPE_ASIAN &&
62 nScript != SCRIPTTYPE_COMPLEX &&
63 nScript != 0 );
64 }
65
66 // -----------------------------------------------------------------------------------------
67
68
ScColumn()69 ScColumn::ScColumn() :
70 nCol( 0 ),
71 nCount( 0 ),
72 nLimit( 0 ),
73 pItems( NULL ),
74 pAttrArray( NULL ),
75 pDocument( NULL )
76 {
77 }
78
79
~ScColumn()80 ScColumn::~ScColumn()
81 {
82 FreeAll();
83 if (pAttrArray) delete pAttrArray;
84 }
85
86
Init(SCCOL nNewCol,SCTAB nNewTab,ScDocument * pDoc)87 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
88 {
89 nCol = nNewCol;
90 nTab = nNewTab;
91 pDocument = pDoc;
92 pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
93 }
94
95
GetNextUnprotected(SCROW nRow,sal_Bool bUp) const96 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, sal_Bool bUp ) const
97 {
98 return pAttrArray->GetNextUnprotected(nRow, bUp);
99 }
100
101
GetBlockMatrixEdges(SCROW nRow1,SCROW nRow2,sal_uInt16 nMask) const102 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
103 {
104 // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
105 if ( !pItems )
106 return 0;
107 if ( nRow1 == nRow2 )
108 {
109 SCSIZE nIndex;
110 if ( Search( nRow1, nIndex ) )
111 {
112 ScBaseCell* pCell = pItems[nIndex].pCell;
113 if ( pCell->GetCellType() == CELLTYPE_FORMULA
114 && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
115 {
116 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
117 return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
118 }
119 }
120 return 0;
121 }
122 else
123 {
124 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
125 sal_Bool bOpen = sal_False;
126 sal_uInt16 nEdges = 0;
127 SCSIZE nIndex;
128 Search( nRow1, nIndex );
129 while ( nIndex < nCount && pItems[nIndex].nRow <= nRow2 )
130 {
131 ScBaseCell* pCell = pItems[nIndex].pCell;
132 if ( pCell->GetCellType() == CELLTYPE_FORMULA
133 && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
134 {
135 nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
136 if ( nEdges )
137 {
138 if ( nEdges & 8 )
139 bOpen = sal_True; // obere Kante oeffnet, weitersehen
140 else if ( !bOpen )
141 return nEdges | 32; // es gibt was, was nicht geoeffnet wurde
142 else if ( nEdges & 1 )
143 return nEdges; // mittendrin
144 // (nMask & 16 und (4 und nicht 16)) oder
145 // (nMask & 4 und (16 und nicht 4))
146 if ( ((nMask & 16) && (nEdges & 4) && !(nEdges & 16))
147 || ((nMask & 4) && (nEdges & 16) && !(nEdges & 4)) )
148 return nEdges; // nur linke/rechte Kante
149 if ( nEdges & 2 )
150 bOpen = sal_False; // untere Kante schliesst
151 }
152 }
153 nIndex++;
154 }
155 if ( bOpen )
156 nEdges |= 32; // es geht noch weiter
157 return nEdges;
158 }
159 }
160
161
HasSelectionMatrixFragment(const ScMarkData & rMark) const162 sal_Bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
163 {
164 if ( rMark.IsMultiMarked() )
165 {
166 sal_Bool bFound = sal_False;
167
168 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
169 ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
170 SCROW nTop, nBottom;
171 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
172 while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
173 {
174 sal_Bool bOpen = sal_False;
175 sal_uInt16 nEdges;
176 SCSIZE nIndex;
177 Search( nTop, nIndex );
178 while ( !bFound && nIndex < nCount && pItems[nIndex].nRow <= nBottom )
179 {
180 ScBaseCell* pCell = pItems[nIndex].pCell;
181 if ( pCell->GetCellType() == CELLTYPE_FORMULA
182 && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
183 {
184 nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
185 if ( nEdges )
186 {
187 if ( nEdges & 8 )
188 bOpen = sal_True; // obere Kante oeffnet, weitersehen
189 else if ( !bOpen )
190 return sal_True; // es gibt was, was nicht geoeffnet wurde
191 else if ( nEdges & 1 )
192 bFound = sal_True; // mittendrin, alles selektiert?
193 // (4 und nicht 16) oder (16 und nicht 4)
194 if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
195 bFound = sal_True; // nur linke/rechte Kante, alles selektiert?
196 if ( nEdges & 2 )
197 bOpen = sal_False; // untere Kante schliesst
198
199 if ( bFound )
200 { // alles selektiert?
201 if ( aCurOrg != aOrg )
202 { // neue Matrix zu pruefen?
203 aCurOrg = aOrg;
204 ScFormulaCell* pFCell;
205 if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
206 == MM_REFERENCE )
207 pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
208 else
209 pFCell = (ScFormulaCell*)pCell;
210 SCCOL nC;
211 SCROW nR;
212 pFCell->GetMatColsRows( nC, nR );
213 ScRange aRange( aOrg, ScAddress(
214 aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
215 aOrg.Tab() ) );
216 if ( rMark.IsAllMarked( aRange ) )
217 bFound = sal_False;
218 }
219 else
220 bFound = sal_False; // war schon
221 }
222 }
223 }
224 nIndex++;
225 }
226 if ( bOpen )
227 return sal_True;
228 }
229 return bFound;
230 }
231 else
232 return sal_False;
233 }
234
235
236 //UNUSED2009-05 sal_Bool ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
237 //UNUSED2009-05 sal_Bool bLeft, sal_Bool bRight ) const
238 //UNUSED2009-05 {
239 //UNUSED2009-05 return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
240 //UNUSED2009-05 }
241
242
HasAttrib(SCROW nRow1,SCROW nRow2,sal_uInt16 nMask) const243 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
244 {
245 return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
246 }
247
248
HasAttribSelection(const ScMarkData & rMark,sal_uInt16 nMask) const249 sal_Bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
250 {
251 sal_Bool bFound = sal_False;
252
253 SCROW nTop;
254 SCROW nBottom;
255
256 if (rMark.IsMultiMarked())
257 {
258 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
259 while (aMarkIter.Next( nTop, nBottom ) && !bFound)
260 {
261 if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
262 bFound = sal_True;
263 }
264 }
265
266 return bFound;
267 }
268
269
ExtendMerge(SCCOL nThisCol,SCROW nStartRow,SCROW nEndRow,SCCOL & rPaintCol,SCROW & rPaintRow,sal_Bool bRefresh,sal_Bool bAttrs)270 sal_Bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
271 SCCOL& rPaintCol, SCROW& rPaintRow,
272 sal_Bool bRefresh, sal_Bool bAttrs )
273 {
274 return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs );
275 }
276
277
MergeSelectionPattern(ScMergePatternState & rState,const ScMarkData & rMark,sal_Bool bDeep) const278 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_Bool bDeep ) const
279 {
280 SCROW nTop;
281 SCROW nBottom;
282
283 if ( rMark.IsMultiMarked() )
284 {
285 const ScMarkArray* pArray = rMark.GetArray() + nCol;
286 if ( pArray->HasMarks() )
287 {
288 ScMarkArrayIter aMarkIter( pArray );
289 while (aMarkIter.Next( nTop, nBottom ))
290 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
291 }
292 }
293 }
294
295
MergePatternArea(ScMergePatternState & rState,SCROW nRow1,SCROW nRow2,sal_Bool bDeep) const296 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, sal_Bool bDeep ) const
297 {
298 pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
299 }
300
301
MergeBlockFrame(SvxBoxItem * pLineOuter,SvxBoxInfoItem * pLineInner,ScLineFlags & rFlags,SCROW nStartRow,SCROW nEndRow,sal_Bool bLeft,SCCOL nDistRight) const302 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
303 ScLineFlags& rFlags,
304 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const
305 {
306 pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
307 }
308
309
ApplyBlockFrame(const SvxBoxItem * pLineOuter,const SvxBoxInfoItem * pLineInner,SCROW nStartRow,SCROW nEndRow,sal_Bool bLeft,SCCOL nDistRight)310 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
311 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
312 {
313 pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
314 }
315
316
GetPattern(SCROW nRow) const317 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
318 {
319 return pAttrArray->GetPattern( nRow );
320 }
321
GetPatternRange(SCROW & rStartRow,SCROW & rEndRow,SCROW nRow) const322 const ScPatternAttr* ScColumn::GetPatternRange( SCROW& rStartRow, SCROW& rEndRow, SCROW nRow ) const
323 {
324 return pAttrArray->GetPatternRange( rStartRow, rEndRow, nRow );
325 }
326
GetAttr(SCROW nRow,sal_uInt16 nWhich) const327 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
328 {
329 return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
330 }
331
332
GetMostUsedPattern(SCROW nStartRow,SCROW nEndRow) const333 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
334 {
335 ::std::map< const ScPatternAttr*, size_t > aAttrMap;
336 const ScPatternAttr* pMaxPattern = 0;
337 size_t nMaxCount = 0;
338
339 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
340 const ScPatternAttr* pPattern;
341 SCROW nAttrRow1 = 0, nAttrRow2 = 0;
342
343 while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
344 {
345 size_t& rnCount = aAttrMap[ pPattern ];
346 rnCount += (nAttrRow2 - nAttrRow1 + 1);
347 if( rnCount > nMaxCount )
348 {
349 pMaxPattern = pPattern;
350 nMaxCount = rnCount;
351 }
352 }
353
354 return pMaxPattern;
355 }
356
357
GetNumberFormat(SCROW nRow) const358 sal_uLong ScColumn::GetNumberFormat( SCROW nRow ) const
359 {
360 return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
361 }
362
363
ApplySelectionCache(SfxItemPoolCache * pCache,const ScMarkData & rMark)364 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
365 {
366 SCROW nTop = 0;
367 SCROW nBottom = 0;
368 sal_Bool bFound = sal_False;
369
370 if ( rMark.IsMultiMarked() )
371 {
372 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
373 while (aMarkIter.Next( nTop, nBottom ))
374 {
375 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache );
376 bFound = sal_True;
377 }
378 }
379
380 if (!bFound)
381 return -1;
382 else if (nTop==0 && nBottom==MAXROW)
383 return 0;
384 else
385 return nBottom;
386 }
387
388
ChangeSelectionIndent(sal_Bool bIncrement,const ScMarkData & rMark)389 void ScColumn::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
390 {
391 SCROW nTop;
392 SCROW nBottom;
393
394 if ( pAttrArray && rMark.IsMultiMarked() )
395 {
396 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
397 while (aMarkIter.Next( nTop, nBottom ))
398 pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
399 }
400 }
401
402
ClearSelectionItems(const sal_uInt16 * pWhich,const ScMarkData & rMark)403 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
404 {
405 SCROW nTop;
406 SCROW nBottom;
407
408 if ( pAttrArray && rMark.IsMultiMarked() )
409 {
410 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
411 while (aMarkIter.Next( nTop, nBottom ))
412 pAttrArray->ClearItems(nTop, nBottom, pWhich);
413 }
414 }
415
416
DeleteSelection(sal_uInt16 nDelFlag,const ScMarkData & rMark)417 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
418 {
419 SCROW nTop;
420 SCROW nBottom;
421
422 if ( rMark.IsMultiMarked() )
423 {
424 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
425 while (aMarkIter.Next( nTop, nBottom ))
426 DeleteArea(nTop, nBottom, nDelFlag);
427 }
428 }
429
430
ApplyPattern(SCROW nRow,const ScPatternAttr & rPatAttr)431 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
432 {
433 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
434 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
435
436 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
437
438 // sal_True = alten Eintrag behalten
439
440 ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
441 ScDocumentPool::CheckRef( *pPattern );
442 ScDocumentPool::CheckRef( *pNewPattern );
443
444 if (pNewPattern != pPattern)
445 pAttrArray->SetPattern( nRow, pNewPattern );
446 }
447
448
ApplyPatternArea(SCROW nStartRow,SCROW nEndRow,const ScPatternAttr & rPatAttr)449 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr )
450 {
451 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
452 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
453 pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache );
454 }
455
456
ApplyPatternIfNumberformatIncompatible(const ScRange & rRange,const ScPatternAttr & rPattern,short nNewType)457 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
458 const ScPatternAttr& rPattern, short nNewType )
459 {
460 const SfxItemSet* pSet = &rPattern.GetItemSet();
461 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
462 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
463 SCROW nEndRow = rRange.aEnd.Row();
464 for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
465 {
466 SCROW nRow1, nRow2;
467 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
468 nRow1, nRow2, nRow );
469 sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter );
470 short nOldType = pFormatter->GetType( nFormat );
471 if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
472 nRow = nRow2;
473 else
474 {
475 SCROW nNewRow1 = Max( nRow1, nRow );
476 SCROW nNewRow2 = Min( nRow2, nEndRow );
477 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
478 nRow = nNewRow2;
479 }
480 }
481 }
482
483
ApplyStyle(SCROW nRow,const ScStyleSheet & rStyle)484 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
485 {
486 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
487 ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
488 if (pNewPattern)
489 {
490 pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
491 pAttrArray->SetPattern(nRow, pNewPattern, sal_True);
492 delete pNewPattern;
493 }
494 }
495
496
ApplyStyleArea(SCROW nStartRow,SCROW nEndRow,const ScStyleSheet & rStyle)497 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
498 {
499 pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
500 }
501
502
ApplySelectionStyle(const ScStyleSheet & rStyle,const ScMarkData & rMark)503 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
504 {
505 SCROW nTop;
506 SCROW nBottom;
507
508 if ( rMark.IsMultiMarked() )
509 {
510 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
511 while (aMarkIter.Next( nTop, nBottom ))
512 pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
513 }
514 }
515
516
ApplySelectionLineStyle(const ScMarkData & rMark,const SvxBorderLine * pLine,sal_Bool bColorOnly)517 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
518 const SvxBorderLine* pLine, sal_Bool bColorOnly )
519 {
520 if ( bColorOnly && !pLine )
521 return;
522
523 SCROW nTop;
524 SCROW nBottom;
525
526 if (rMark.IsMultiMarked())
527 {
528 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
529 while (aMarkIter.Next( nTop, nBottom ))
530 pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
531 }
532 }
533
534
GetStyle(SCROW nRow) const535 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
536 {
537 return pAttrArray->GetPattern( nRow )->GetStyleSheet();
538 }
539
540
GetSelectionStyle(const ScMarkData & rMark,sal_Bool & rFound) const541 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, sal_Bool& rFound ) const
542 {
543 rFound = sal_False;
544 if (!rMark.IsMultiMarked())
545 {
546 DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
547 return NULL;
548 }
549
550 sal_Bool bEqual = sal_True;
551
552 const ScStyleSheet* pStyle = NULL;
553 const ScStyleSheet* pNewStyle;
554
555 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
556 SCROW nTop;
557 SCROW nBottom;
558 while (bEqual && aMarkIter.Next( nTop, nBottom ))
559 {
560 ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
561 SCROW nRow;
562 SCROW nDummy;
563 const ScPatternAttr* pPattern;
564 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
565 {
566 pNewStyle = pPattern->GetStyleSheet();
567 rFound = sal_True;
568 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
569 bEqual = sal_False; // unterschiedliche
570 pStyle = pNewStyle;
571 }
572 }
573
574 return bEqual ? pStyle : NULL;
575 }
576
577
GetAreaStyle(sal_Bool & rFound,SCROW nRow1,SCROW nRow2) const578 const ScStyleSheet* ScColumn::GetAreaStyle( sal_Bool& rFound, SCROW nRow1, SCROW nRow2 ) const
579 {
580 rFound = sal_False;
581
582 sal_Bool bEqual = sal_True;
583
584 const ScStyleSheet* pStyle = NULL;
585 const ScStyleSheet* pNewStyle;
586
587 ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
588 SCROW nRow;
589 SCROW nDummy;
590 const ScPatternAttr* pPattern;
591 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
592 {
593 pNewStyle = pPattern->GetStyleSheet();
594 rFound = sal_True;
595 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
596 bEqual = sal_False; // unterschiedliche
597 pStyle = pNewStyle;
598 }
599
600 return bEqual ? pStyle : NULL;
601 }
602
FindStyleSheet(const SfxStyleSheetBase * pStyleSheet,ScFlatBoolRowSegments & rUsedRows,bool bReset)603 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
604 {
605 pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
606 }
607
IsStyleSheetUsed(const ScStyleSheet & rStyle,sal_Bool bGatherAllStyles) const608 sal_Bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
609 {
610 return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
611 }
612
613
ApplyFlags(SCROW nStartRow,SCROW nEndRow,sal_Int16 nFlags)614 sal_Bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
615 {
616 return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
617 }
618
619
RemoveFlags(SCROW nStartRow,SCROW nEndRow,sal_Int16 nFlags)620 sal_Bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
621 {
622 return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
623 }
624
625
ClearItems(SCROW nStartRow,SCROW nEndRow,const sal_uInt16 * pWhich)626 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
627 {
628 pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
629 }
630
631
SetPattern(SCROW nRow,const ScPatternAttr & rPatAttr,sal_Bool bPutToPool)632 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
633 {
634 pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
635 }
636
637
SetPatternArea(SCROW nStartRow,SCROW nEndRow,const ScPatternAttr & rPatAttr,sal_Bool bPutToPool)638 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
639 const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
640 {
641 pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
642 }
643
644
ApplyAttr(SCROW nRow,const SfxPoolItem & rAttr)645 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
646 {
647 // um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache.
648 //! Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ??
649
650 ScDocumentPool* pDocPool = pDocument->GetPool();
651
652 const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
653 ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
654 pTemp->GetItemSet().Put(rAttr);
655 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
656
657 if ( pNewPattern != pOldPattern )
658 pAttrArray->SetPattern( nRow, pNewPattern );
659 else
660 pDocPool->Remove( *pNewPattern ); // ausser Spesen nichts gewesen
661
662 delete pTemp;
663
664 // alte Version mit SfxItemPoolCache:
665 #if 0
666 SfxItemPoolCache aCache( pDocument->GetPool(), &rAttr );
667
668 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
669
670 // sal_True = alten Eintrag behalten
671
672 ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
673 ScDocumentPool::CheckRef( *pPattern );
674 ScDocumentPool::CheckRef( *pNewPattern );
675
676 if (pNewPattern != pPattern)
677 pAttrArray->SetPattern( nRow, pNewPattern );
678 #endif
679 }
680
681 #ifdef _MSC_VER
682 #pragma optimize ( "", off )
683 #endif
684
685
Search(SCROW nRow,SCSIZE & nIndex) const686 sal_Bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
687 {
688 if ( !pItems || !nCount )
689 {
690 nIndex = 0;
691 return sal_False;
692 }
693 SCROW nMinRow = pItems[0].nRow;
694 if ( nRow <= nMinRow )
695 {
696 nIndex = 0;
697 return nRow == nMinRow;
698 }
699 SCROW nMaxRow = pItems[nCount-1].nRow;
700 if ( nRow >= nMaxRow )
701 {
702 if ( nRow == nMaxRow )
703 {
704 nIndex = nCount - 1;
705 return sal_True;
706 }
707 else
708 {
709 nIndex = nCount;
710 return sal_False;
711 }
712 }
713
714 long nOldLo, nOldHi;
715 long nLo = nOldLo = 0;
716 long nHi = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
717 long i = 0;
718 sal_Bool bFound = sal_False;
719 // quite continuous distribution? => interpolating search
720 sal_Bool bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2);
721 SCROW nR;
722
723 while ( !bFound && nLo <= nHi )
724 {
725 if ( !bInterpol || nHi - nLo < 3 )
726 i = (nLo+nHi) / 2; // no effort, no division by zero
727 else
728 { // interpolating search
729 long nLoRow = pItems[nLo].nRow; // no unsigned underflow upon subtraction
730 i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo)
731 / (pItems[nHi].nRow - nLoRow));
732 if ( i < 0 || static_cast<SCSIZE>(i) >= nCount )
733 { // oops ...
734 i = (nLo+nHi) / 2;
735 bInterpol = sal_False;
736 }
737 }
738 nR = pItems[i].nRow;
739 if ( nR < nRow )
740 {
741 nLo = i+1;
742 if ( bInterpol )
743 {
744 if ( nLo <= nOldLo )
745 bInterpol = sal_False;
746 else
747 nOldLo = nLo;
748 }
749 }
750 else
751 {
752 if ( nR > nRow )
753 {
754 nHi = i-1;
755 if ( bInterpol )
756 {
757 if ( nHi >= nOldHi )
758 bInterpol = sal_False;
759 else
760 nOldHi = nHi;
761 }
762 }
763 else
764 bFound = sal_True;
765 }
766 }
767 if (bFound)
768 nIndex = static_cast<SCSIZE>(i);
769 else
770 nIndex = static_cast<SCSIZE>(nLo); // rear index
771 return bFound;
772 }
773
774 #ifdef _MSC_VER
775 #pragma optimize ( "", on )
776 #endif
777
778
GetCell(SCROW nRow) const779 ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
780 {
781 SCSIZE nIndex;
782 if (Search(nRow, nIndex))
783 return pItems[nIndex].pCell;
784 return NULL;
785 }
786
787
Resize(SCSIZE nSize)788 void ScColumn::Resize( SCSIZE nSize )
789 {
790 if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
791 nSize = MAXROWCOUNT;
792 if (nSize < nCount)
793 nSize = nCount;
794
795 ColEntry* pNewItems;
796 if (nSize)
797 {
798 SCSIZE nNewSize = nSize + COLUMN_DELTA - 1;
799 nNewSize -= nNewSize % COLUMN_DELTA;
800 nLimit = nNewSize;
801 pNewItems = new ColEntry[nLimit];
802 }
803 else
804 {
805 nLimit = 0;
806 pNewItems = NULL;
807 }
808 if (pItems)
809 {
810 if (pNewItems)
811 memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
812 delete[] pItems;
813 }
814 pItems = pNewItems;
815 }
816
817 // SwapRow zum Sortieren
818
819 namespace {
820
821 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
lclTakeBroadcaster(ScBaseCell * & rpCell,SvtBroadcaster * pBC)822 void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC )
823 {
824 if( pBC )
825 {
826 if( rpCell )
827 rpCell->TakeBroadcaster( pBC );
828 else
829 rpCell = new ScNoteCell( pBC );
830 }
831 }
832
833 } // namespace
834
SwapRow(SCROW nRow1,SCROW nRow2)835 void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
836 {
837 /* Simple swap of cell pointers does not work if broadcasters exist (crash
838 if cell broadcasts directly or indirectly to itself). While swapping
839 the cells, broadcasters have to remain at old positions! */
840
841 /* While cloning cells, do not clone notes, but move note pointers to new
842 cells. This prevents creation of new caption drawing objects for every
843 swap operation while sorting. */
844
845 ScBaseCell* pCell1 = 0;
846 SCSIZE nIndex1;
847 if ( Search( nRow1, nIndex1 ) )
848 pCell1 = pItems[nIndex1].pCell;
849
850 ScBaseCell* pCell2 = 0;
851 SCSIZE nIndex2;
852 if ( Search( nRow2, nIndex2 ) )
853 pCell2 = pItems[nIndex2].pCell;
854
855 // no cells found, nothing to do
856 if ( !pCell1 && !pCell2 )
857 return ;
858
859 // swap variables if first cell is empty, to save some code below
860 if ( !pCell1 )
861 {
862 ::std::swap( nRow1, nRow2 );
863 ::std::swap( nIndex1, nIndex2 );
864 ::std::swap( pCell1, pCell2 );
865 }
866
867 // from here: first cell (pCell1, nIndex1) exists always
868
869 ScAddress aPos1( nCol, nRow1, nTab );
870 ScAddress aPos2( nCol, nRow2, nTab );
871
872 CellType eType1 = pCell1->GetCellType();
873 CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE;
874
875 ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
876 ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
877
878 // simple swap if no formula cells present
879 if ( !pFmlaCell1 && !pFmlaCell2 )
880 {
881 // remember cell broadcasters, must remain at old position
882 SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
883
884 if ( pCell2 )
885 {
886 /* Both cells exist, no formula cells involved, a simple swap can
887 be performed (but keep broadcasters and notes at old position). */
888 pItems[nIndex1].pCell = pCell2;
889 pItems[nIndex2].pCell = pCell1;
890
891 SvtBroadcaster* pBC2 = pCell2->ReleaseBroadcaster();
892 pCell1->TakeBroadcaster( pBC2 );
893 pCell2->TakeBroadcaster( pBC1 );
894 }
895 else
896 {
897 ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0;
898 if ( pDummyCell )
899 {
900 // insert dummy note cell (without note) containing old broadcaster
901 pItems[nIndex1].pCell = pDummyCell;
902 }
903 else
904 {
905 // remove ColEntry at old position
906 --nCount;
907 memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
908 pItems[nCount].nRow = 0;
909 pItems[nCount].pCell = 0;
910 }
911
912 // insert ColEntry at new position
913 Insert( nRow2, pCell1 );
914 }
915
916 return;
917 }
918
919 // from here: at least one of the cells is a formula cell
920
921 /* Never move any array formulas. Disabling sort if parts of array
922 formulas are contained is done at UI. */
923 if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) )
924 return;
925
926 // do not swap, if formulas are equal
927 if ( pFmlaCell1 && pFmlaCell2 )
928 {
929 ScTokenArray* pCode1 = pFmlaCell1->GetCode();
930 ScTokenArray* pCode2 = pFmlaCell2->GetCode();
931
932 if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN
933 {
934 sal_Bool bEqual = sal_True;
935 sal_uInt16 nLen = pCode1->GetLen();
936 FormulaToken** ppToken1 = pCode1->GetArray();
937 FormulaToken** ppToken2 = pCode2->GetArray();
938 for (sal_uInt16 i=0; i<nLen; i++)
939 {
940 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
941 ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
942 {
943 bEqual = sal_False;
944 break;
945 }
946 }
947
948 // do not swap formula cells with equal formulas, but swap notes
949 if (bEqual)
950 {
951 ScPostIt* pNote1 = pCell1->ReleaseNote();
952 pCell1->TakeNote( pCell2->ReleaseNote() );
953 pCell2->TakeNote( pNote1 );
954 return;
955 }
956 }
957 }
958
959 // hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen
960 // long dy = (long)nRow2 - (long)nRow1;
961
962 /* Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
963 variable swapping above). Do not clone the note, but move pointer of
964 old note to new cell. */
965 ScBaseCell* pNew2 = pCell1->CloneWithoutNote( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL );
966 pNew2->TakeNote( pCell1->ReleaseNote() );
967
968 /* Create clone of pCell2 at position of pCell1. Do not clone the note,
969 but move pointer of old note to new cell. */
970 ScBaseCell* pNew1 = 0;
971 if ( pCell2 )
972 {
973 pNew1 = pCell2->CloneWithoutNote( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL );
974 pNew1->TakeNote( pCell2->ReleaseNote() );
975 }
976
977 // move old broadcasters new cells at the same old position
978 SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
979 lclTakeBroadcaster( pNew1, pBC1 );
980 SvtBroadcaster* pBC2 = pCell2 ? pCell2->ReleaseBroadcaster() : 0;
981 lclTakeBroadcaster( pNew2, pBC2 );
982
983 /* Insert the new cells. Old cell has to be deleted, if there is no new
984 cell (call to Insert deletes old cell by itself). */
985 if ( !pNew1 )
986 Delete( nRow1 ); // deletes pCell1
987 else
988 Insert( nRow1, pNew1 ); // deletes pCell1, inserts pNew1
989
990 if ( pCell2 && !pNew2 )
991 Delete( nRow2 ); // deletes pCell2
992 else if ( pNew2 )
993 Insert( nRow2, pNew2 ); // deletes pCell2 (if existing), inserts pNew2
994 }
995
996
SwapCell(SCROW nRow,ScColumn & rCol)997 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
998 {
999 ScBaseCell* pCell1 = 0;
1000 SCSIZE nIndex1;
1001 if ( Search( nRow, nIndex1 ) )
1002 pCell1 = pItems[nIndex1].pCell;
1003
1004 ScBaseCell* pCell2 = 0;
1005 SCSIZE nIndex2;
1006 if ( rCol.Search( nRow, nIndex2 ) )
1007 pCell2 = rCol.pItems[nIndex2].pCell;
1008
1009 // reverse call if own cell is missing (ensures own existing cell in following code)
1010 if( !pCell1 )
1011 {
1012 if( pCell2 )
1013 rCol.SwapCell( nRow, *this );
1014 return;
1015 }
1016
1017 // from here: own cell (pCell1, nIndex1) exists always
1018
1019 ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
1020 ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
1021
1022 if ( pCell2 )
1023 {
1024 // Tauschen
1025 pItems[nIndex1].pCell = pCell2;
1026 rCol.pItems[nIndex2].pCell = pCell1;
1027 // Referenzen aktualisieren
1028 SCsCOL dx = rCol.nCol - nCol;
1029 if ( pFmlaCell1 )
1030 {
1031 ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1032 ScAddress( rCol.nCol, MAXROW, nTab ) );
1033 pFmlaCell1->aPos.SetCol( rCol.nCol );
1034 pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1035 }
1036 if ( pFmlaCell2 )
1037 {
1038 ScRange aRange( ScAddress( nCol, 0, nTab ),
1039 ScAddress( nCol, MAXROW, nTab ) );
1040 pFmlaCell2->aPos.SetCol( nCol );
1041 pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0);
1042 }
1043 }
1044 else
1045 {
1046 // Loeschen
1047 --nCount;
1048 memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
1049 pItems[nCount].nRow = 0;
1050 pItems[nCount].pCell = 0;
1051 // Referenzen aktualisieren
1052 SCsCOL dx = rCol.nCol - nCol;
1053 if ( pFmlaCell1 )
1054 {
1055 ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1056 ScAddress( rCol.nCol, MAXROW, nTab ) );
1057 pFmlaCell1->aPos.SetCol( rCol.nCol );
1058 pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1059 }
1060 // Einfuegen
1061 rCol.Insert(nRow, pCell1);
1062 }
1063 }
1064
1065
TestInsertCol(SCROW nStartRow,SCROW nEndRow) const1066 sal_Bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1067 {
1068 if (!IsEmpty())
1069 {
1070 sal_Bool bTest = sal_True;
1071 if (pItems)
1072 for (SCSIZE i=0; (i<nCount) && bTest; i++)
1073 bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow)
1074 || pItems[i].pCell->IsBlank();
1075
1076 // AttrArray testet nur zusammengefasste
1077
1078 if ((bTest) && (pAttrArray))
1079 bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
1080
1081 //! rausgeschobene Attribute bei Undo beruecksichtigen
1082
1083 return bTest;
1084 }
1085 else
1086 return sal_True;
1087 }
1088
1089
TestInsertRow(SCSIZE nSize) const1090 sal_Bool ScColumn::TestInsertRow( SCSIZE nSize ) const
1091 {
1092 // AttrArray only looks for merged cells
1093
1094 if ( pItems && nCount )
1095 return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
1096 pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
1097 else
1098 return pAttrArray->TestInsertRow( nSize );
1099
1100 #if 0
1101 //! rausgeschobene Attribute bei Undo beruecksichtigen
1102
1103 if ( nSize > static_cast<SCSIZE>(MAXROW) )
1104 return sal_False;
1105
1106 SCSIZE nVis = nCount;
1107 while ( nVis && pItems[nVis-1].pCell->IsBlank() )
1108 --nVis;
1109
1110 if ( nVis )
1111 return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1112 else
1113 return sal_True;
1114 #endif
1115 }
1116
1117
InsertRow(SCROW nStartRow,SCSIZE nSize)1118 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1119 {
1120 pAttrArray->InsertRow( nStartRow, nSize );
1121
1122 //! Search
1123
1124 if ( !pItems || !nCount )
1125 return;
1126
1127 SCSIZE i;
1128 Search( nStartRow, i );
1129 if ( i >= nCount )
1130 return ;
1131
1132 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1133 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
1134
1135 SCSIZE nNewCount = nCount;
1136 sal_Bool bCountChanged = sal_False;
1137 ScAddress aAdr( nCol, 0, nTab );
1138 ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL ); // only areas (ScBaseCell* == NULL)
1139 ScAddress& rAddress = aHint.GetAddress();
1140 // for sparse occupation use single broadcasts, not ranges
1141 sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
1142 (nCount - i)) > 1);
1143 if ( bSingleBroadcasts )
1144 {
1145 SCROW nLastBroadcast = MAXROW+1;
1146 for ( ; i < nCount; i++)
1147 {
1148 SCROW nOldRow = pItems[i].nRow;
1149 // #43940# Aenderung Quelle broadcasten
1150 if ( nLastBroadcast != nOldRow )
1151 { // direkt aufeinanderfolgende nicht doppelt broadcasten
1152 rAddress.SetRow( nOldRow );
1153 pDocument->AreaBroadcast( aHint );
1154 }
1155 SCROW nNewRow = (pItems[i].nRow += nSize);
1156 // #43940# Aenderung Ziel broadcasten
1157 rAddress.SetRow( nNewRow );
1158 pDocument->AreaBroadcast( aHint );
1159 nLastBroadcast = nNewRow;
1160 ScBaseCell* pCell = pItems[i].pCell;
1161 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1162 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1163 if ( nNewRow > MAXROW && !bCountChanged )
1164 {
1165 nNewCount = i;
1166 bCountChanged = sal_True;
1167 }
1168 }
1169 }
1170 else
1171 {
1172 rAddress.SetRow( pItems[i].nRow );
1173 ScRange aRange( rAddress );
1174 for ( ; i < nCount; i++)
1175 {
1176 SCROW nNewRow = (pItems[i].nRow += nSize);
1177 ScBaseCell* pCell = pItems[i].pCell;
1178 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1179 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1180 if ( nNewRow > MAXROW && !bCountChanged )
1181 {
1182 nNewCount = i;
1183 bCountChanged = sal_True;
1184 aRange.aEnd.SetRow( MAXROW );
1185 }
1186 }
1187 if ( !bCountChanged )
1188 aRange.aEnd.SetRow( pItems[nCount-1].nRow );
1189 pDocument->AreaBroadcastInRange( aRange, aHint );
1190 }
1191
1192 if (bCountChanged)
1193 {
1194 SCSIZE nDelCount = nCount - nNewCount;
1195 ScBaseCell** ppDelCells = new ScBaseCell*[nDelCount];
1196 SCROW* pDelRows = new SCROW[nDelCount];
1197 for (i = 0; i < nDelCount; i++)
1198 {
1199 ppDelCells[i] = pItems[nNewCount+i].pCell;
1200 pDelRows[i] = pItems[nNewCount+i].nRow;
1201 }
1202 nCount = nNewCount;
1203
1204 for (i = 0; i < nDelCount; i++)
1205 {
1206 ScBaseCell* pCell = ppDelCells[i];
1207 DBG_ASSERT( pCell->IsBlank(), "sichtbare Zelle weggeschoben" );
1208 SvtBroadcaster* pBC = pCell->GetBroadcaster();
1209 if (pBC)
1210 {
1211 MoveListeners( *pBC, pDelRows[i] - nSize );
1212 pCell->DeleteBroadcaster();
1213 pCell->Delete();
1214 }
1215 }
1216
1217 delete [] pDelRows;
1218 delete [] ppDelCells;
1219 }
1220
1221 pDocument->SetAutoCalc( bOldAutoCalc );
1222 }
1223
1224
CopyToClip(SCROW nRow1,SCROW nRow2,ScColumn & rColumn,sal_Bool bKeepScenarioFlags,sal_Bool bCloneNoteCaptions)1225 void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, sal_Bool bKeepScenarioFlags, sal_Bool bCloneNoteCaptions)
1226 {
1227 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1228 bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1229
1230 SCSIZE i;
1231 SCSIZE nBlockCount = 0;
1232 SCSIZE nStartIndex = 0, nEndIndex = 0;
1233 for (i = 0; i < nCount; i++)
1234 if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1235 {
1236 if (!nBlockCount)
1237 nStartIndex = i;
1238 nEndIndex = i;
1239 ++nBlockCount;
1240
1241 // im Clipboard muessen interpretierte Zellen stehen, um andere Formate
1242 // (Text, Grafik...) erzueugen zu koennen
1243
1244 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1245 {
1246 ScFormulaCell* pFCell = (ScFormulaCell*) pItems[i].pCell;
1247 if (pFCell->GetDirty() && pDocument->GetAutoCalc())
1248 pFCell->Interpret();
1249 }
1250 }
1251
1252 if (nBlockCount)
1253 {
1254 int nCloneFlags = bCloneNoteCaptions ? SC_CLONECELL_DEFAULT : SC_CLONECELL_NOCAPTION;
1255 rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1256 ScAddress aOwnPos( nCol, 0, nTab );
1257 ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1258 for (i = nStartIndex; i <= nEndIndex; i++)
1259 {
1260 aOwnPos.SetRow( pItems[i].nRow );
1261 aDestPos.SetRow( pItems[i].nRow );
1262 ScBaseCell* pNewCell = pItems[i].pCell->CloneWithNote( aOwnPos, *rColumn.pDocument, aDestPos, nCloneFlags );
1263 rColumn.Append( aDestPos.Row(), pNewCell );
1264 }
1265 }
1266 }
1267
1268
CopyToColumn(SCROW nRow1,SCROW nRow2,sal_uInt16 nFlags,sal_Bool bMarked,ScColumn & rColumn,const ScMarkData * pMarkData,sal_Bool bAsLink)1269 void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1270 ScColumn& rColumn, const ScMarkData* pMarkData, sal_Bool bAsLink )
1271 {
1272 if (bMarked)
1273 {
1274 SCROW nStart, nEnd;
1275 if (pMarkData && pMarkData->IsMultiMarked())
1276 {
1277 ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1278
1279 while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1280 {
1281 if ( nEnd >= nRow1 )
1282 CopyToColumn( Max(nRow1,nStart), Min(nRow2,nEnd),
1283 nFlags, sal_False, rColumn, pMarkData, bAsLink );
1284 }
1285 }
1286 else
1287 {
1288 DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
1289 }
1290 return;
1291 }
1292
1293 if ( (nFlags & IDF_ATTRIB) != 0 )
1294 {
1295 if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1296 { // StyleSheets im Zieldokument bleiben erhalten
1297 // z.B. DIF und RTF Clipboard-Import
1298 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1299 {
1300 const ScStyleSheet* pStyle =
1301 rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1302 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1303 ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern );
1304 pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
1305 rColumn.pAttrArray->SetPattern( nRow, pNewPattern, sal_True );
1306 delete pNewPattern;
1307 }
1308 }
1309 else
1310 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1311 }
1312
1313
1314 if ((nFlags & IDF_CONTENTS) != 0)
1315 {
1316 SCSIZE i;
1317 SCSIZE nBlockCount = 0;
1318 SCSIZE nStartIndex = 0, nEndIndex = 0;
1319 for (i = 0; i < nCount; i++)
1320 if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1321 {
1322 if (!nBlockCount)
1323 nStartIndex = i;
1324 nEndIndex = i;
1325 ++nBlockCount;
1326 }
1327
1328 if (nBlockCount)
1329 {
1330 rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1331 ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1332 for (i = nStartIndex; i <= nEndIndex; i++)
1333 {
1334 aDestPos.SetRow( pItems[i].nRow );
1335 ScBaseCell* pNew = bAsLink ?
1336 CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) :
1337 CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
1338
1339 if (pNew)
1340 rColumn.Insert(pItems[i].nRow, pNew);
1341 }
1342 }
1343 }
1344 }
1345
1346
UndoToColumn(SCROW nRow1,SCROW nRow2,sal_uInt16 nFlags,sal_Bool bMarked,ScColumn & rColumn,const ScMarkData * pMarkData)1347 void ScColumn::UndoToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1348 ScColumn& rColumn, const ScMarkData* pMarkData )
1349 {
1350 if (nRow1 > 0)
1351 CopyToColumn( 0, nRow1-1, IDF_FORMULA, sal_False, rColumn );
1352
1353 CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData ); //! bMarked ????
1354
1355 if (nRow2 < MAXROW)
1356 CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, sal_False, rColumn );
1357 }
1358
1359
CopyUpdated(const ScColumn & rPosCol,ScColumn & rDestCol) const1360 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
1361 {
1362 ScDocument& rDestDoc = *rDestCol.pDocument;
1363 ScAddress aOwnPos( nCol, 0, nTab );
1364 ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
1365
1366 SCSIZE nPosCount = rPosCol.nCount;
1367 for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
1368 {
1369 aOwnPos.SetRow( rPosCol.pItems[nPosIndex].nRow );
1370 aDestPos.SetRow( aOwnPos.Row() );
1371 SCSIZE nThisIndex;
1372 if ( Search( aDestPos.Row(), nThisIndex ) )
1373 {
1374 ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos );
1375 rDestCol.Insert( aDestPos.Row(), pNew );
1376 }
1377 }
1378
1379 // Dummy:
1380 // CopyToColumn( 0,MAXROW, IDF_FORMULA, sal_False, rDestCol, NULL, sal_False );
1381 }
1382
1383
CopyScenarioFrom(const ScColumn & rSrcCol)1384 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
1385 {
1386 // Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
1387
1388 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1389 SCROW nStart = -1, nEnd = -1;
1390 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1391 while (pPattern)
1392 {
1393 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1394 {
1395 DeleteArea( nStart, nEnd, IDF_CONTENTS );
1396 ((ScColumn&)rSrcCol).
1397 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, *this );
1398
1399 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1400
1401 SCsTAB nDz = nTab - rSrcCol.nTab;
1402 UpdateReference(URM_COPY, nCol, nStart, nTab,
1403 nCol, nEnd, nTab,
1404 0, 0, nDz, NULL);
1405 UpdateCompile();
1406 }
1407
1408 //! CopyToColumn "const" machen !!!
1409
1410 pPattern = aAttrIter.Next( nStart, nEnd );
1411 }
1412 }
1413
1414
CopyScenarioTo(ScColumn & rDestCol) const1415 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1416 {
1417 // Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert
1418
1419 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1420 SCROW nStart = -1, nEnd = -1;
1421 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1422 while (pPattern)
1423 {
1424 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1425 {
1426 rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1427 ((ScColumn*)this)->
1428 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, rDestCol );
1429
1430 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1431
1432 SCsTAB nDz = rDestCol.nTab - nTab;
1433 rDestCol.UpdateReference(URM_COPY, rDestCol.nCol, nStart, rDestCol.nTab,
1434 rDestCol.nCol, nEnd, rDestCol.nTab,
1435 0, 0, nDz, NULL);
1436 rDestCol.UpdateCompile();
1437 }
1438
1439 //! CopyToColumn "const" machen !!!
1440
1441 pPattern = aAttrIter.Next( nStart, nEnd );
1442 }
1443 }
1444
1445
TestCopyScenarioTo(const ScColumn & rDestCol) const1446 sal_Bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1447 {
1448 sal_Bool bOk = sal_True;
1449 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1450 SCROW nStart = 0, nEnd = 0;
1451 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1452 while (pPattern && bOk)
1453 {
1454 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1455 if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
1456 bOk = sal_False;
1457
1458 pPattern = aAttrIter.Next( nStart, nEnd );
1459 }
1460 return bOk;
1461 }
1462
1463
MarkScenarioIn(ScMarkData & rDestMark) const1464 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1465 {
1466 ScRange aRange( nCol, 0, nTab );
1467
1468 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1469 SCROW nStart = -1, nEnd = -1;
1470 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1471 while (pPattern)
1472 {
1473 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1474 {
1475 aRange.aStart.SetRow( nStart );
1476 aRange.aEnd.SetRow( nEnd );
1477 rDestMark.SetMultiMarkArea( aRange, sal_True );
1478 }
1479
1480 pPattern = aAttrIter.Next( nStart, nEnd );
1481 }
1482 }
1483
1484
SwapCol(ScColumn & rCol)1485 void ScColumn::SwapCol(ScColumn& rCol)
1486 {
1487 SCSIZE nTemp;
1488
1489 nTemp = rCol.nCount;
1490 rCol.nCount = nCount;
1491 nCount = nTemp;
1492
1493 nTemp = rCol.nLimit;
1494 rCol.nLimit = nLimit;
1495 nLimit = nTemp;
1496
1497 ColEntry* pTempItems = rCol.pItems;
1498 rCol.pItems = pItems;
1499 pItems = pTempItems;
1500
1501 ScAttrArray* pTempAttr = rCol.pAttrArray;
1502 rCol.pAttrArray = pAttrArray;
1503 pAttrArray = pTempAttr;
1504
1505 // #38415# AttrArray muss richtige Spaltennummer haben
1506 pAttrArray->SetCol(nCol);
1507 rCol.pAttrArray->SetCol(rCol.nCol);
1508
1509 SCSIZE i;
1510 if (pItems)
1511 for (i = 0; i < nCount; i++)
1512 {
1513 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1514 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1515 pCell->aPos.SetCol(nCol);
1516 }
1517 if (rCol.pItems)
1518 for (i = 0; i < rCol.nCount; i++)
1519 {
1520 ScFormulaCell* pCell = (ScFormulaCell*) rCol.pItems[i].pCell;
1521 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1522 pCell->aPos.SetCol(rCol.nCol);
1523 }
1524 }
1525
1526
MoveTo(SCROW nStartRow,SCROW nEndRow,ScColumn & rCol)1527 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1528 {
1529 pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1530
1531 if (pItems)
1532 {
1533 ::std::vector<SCROW> aRows;
1534 bool bConsecutive = true;
1535 SCSIZE i;
1536 Search( nStartRow, i); // i points to start row or position thereafter
1537 SCSIZE nStartPos = i;
1538 for ( ; i < nCount && pItems[i].nRow <= nEndRow; ++i)
1539 {
1540 SCROW nRow = pItems[i].nRow;
1541 aRows.push_back( nRow);
1542 rCol.Insert( nRow, pItems[i].pCell);
1543 if (nRow != pItems[i].nRow)
1544 { // Listener inserted
1545 bConsecutive = false;
1546 Search( nRow, i);
1547 }
1548 }
1549 SCSIZE nStopPos = i;
1550 if (nStartPos < nStopPos)
1551 {
1552 // Create list of ranges of cell entry positions
1553 typedef ::std::pair<SCSIZE,SCSIZE> PosPair;
1554 typedef ::std::vector<PosPair> EntryPosPairs;
1555 EntryPosPairs aEntries;
1556 if (bConsecutive)
1557 aEntries.push_back( PosPair(nStartPos, nStopPos));
1558 else
1559 {
1560 bool bFirst = true;
1561 nStopPos = 0;
1562 for (::std::vector<SCROW>::const_iterator it( aRows.begin());
1563 it != aRows.end() && nStopPos < nCount; ++it,
1564 ++nStopPos)
1565 {
1566 if (!bFirst && *it != pItems[nStopPos].nRow)
1567 {
1568 aEntries.push_back( PosPair(nStartPos, nStopPos));
1569 bFirst = true;
1570 }
1571 if (bFirst && Search( *it, nStartPos))
1572 {
1573 bFirst = false;
1574 nStopPos = nStartPos;
1575 }
1576 }
1577 if (!bFirst && nStartPos < nStopPos)
1578 aEntries.push_back( PosPair(nStartPos, nStopPos));
1579 }
1580 // Broadcast changes
1581 ScAddress aAdr( nCol, 0, nTab );
1582 ScHint aHint( SC_HINT_DYING, aAdr, NULL ); // areas only
1583 ScAddress& rAddress = aHint.GetAddress();
1584 ScNoteCell* pNoteCell = new ScNoteCell; // Dummy like in DeleteRange
1585
1586 // #121990# must iterate backwards, because indexes of following cells become invalid
1587 for (EntryPosPairs::reverse_iterator it( aEntries.rbegin());
1588 it != aEntries.rend(); ++it)
1589 {
1590 nStartPos = (*it).first;
1591 nStopPos = (*it).second;
1592 for (i=nStartPos; i<nStopPos; ++i)
1593 pItems[i].pCell = pNoteCell;
1594 for (i=nStartPos; i<nStopPos; ++i)
1595 {
1596 rAddress.SetRow( pItems[i].nRow );
1597 pDocument->AreaBroadcast( aHint );
1598 }
1599 nCount -= nStopPos - nStartPos;
1600 memmove( &pItems[nStartPos], &pItems[nStopPos],
1601 (nCount - nStartPos) * sizeof(ColEntry) );
1602 }
1603 delete pNoteCell;
1604 pItems[nCount].nRow = 0;
1605 pItems[nCount].pCell = NULL;
1606 }
1607 }
1608 }
1609
1610
UpdateReference(UpdateRefMode eUpdateRefMode,SCCOL nCol1,SCROW nRow1,SCTAB nTab1,SCCOL nCol2,SCROW nRow2,SCTAB nTab2,SCsCOL nDx,SCsROW nDy,SCsTAB nDz,ScDocument * pUndoDoc)1611 void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1612 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
1613 ScDocument* pUndoDoc )
1614 {
1615 if (pItems)
1616 {
1617 ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ),
1618 ScAddress( nCol2, nRow2, nTab2 ) );
1619 if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 )
1620 { // z.B. eine einzelne Zelle aus dem Clipboard eingefuegt
1621 SCSIZE nIndex;
1622 if ( Search( nRow1, nIndex ) )
1623 {
1624 ScFormulaCell* pCell = (ScFormulaCell*) pItems[nIndex].pCell;
1625 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1626 pCell->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1627 }
1628 }
1629 else
1630 {
1631 // #90279# For performance reasons two loop bodies instead of
1632 // testing for update mode in each iteration.
1633 // Anyways, this is still a bottleneck on large arrays with few
1634 // formulas cells.
1635 if ( eUpdateRefMode == URM_COPY )
1636 {
1637 SCSIZE i;
1638 Search( nRow1, i );
1639 for ( ; i < nCount; i++ )
1640 {
1641 SCROW nRow = pItems[i].nRow;
1642 if ( nRow > nRow2 )
1643 break;
1644 ScBaseCell* pCell = pItems[i].pCell;
1645 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1646 {
1647 ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1648 if ( nRow != pItems[i].nRow )
1649 Search( nRow, i ); // Listener removed/inserted?
1650 }
1651 }
1652 }
1653 else
1654 {
1655 SCSIZE i = 0;
1656 for ( ; i < nCount; i++ )
1657 {
1658 ScBaseCell* pCell = pItems[i].pCell;
1659 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1660 {
1661 SCROW nRow = pItems[i].nRow;
1662 // When deleting rows on several sheets, the formula's position may be updated with the first call,
1663 // so the undo position must be passed from here.
1664 ScAddress aUndoPos( nCol, nRow, nTab );
1665 ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos );
1666 if ( nRow != pItems[i].nRow )
1667 Search( nRow, i ); // Listener removed/inserted?
1668 }
1669 }
1670 }
1671 }
1672 }
1673 }
1674
1675
UpdateTranspose(const ScRange & rSource,const ScAddress & rDest,ScDocument * pUndoDoc)1676 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1677 ScDocument* pUndoDoc )
1678 {
1679 if (pItems)
1680 for (SCSIZE i=0; i<nCount; i++)
1681 {
1682 ScBaseCell* pCell = pItems[i].pCell;
1683 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1684 {
1685 SCROW nRow = pItems[i].nRow;
1686 ((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc );
1687 if ( nRow != pItems[i].nRow )
1688 Search( nRow, i ); // Listener geloescht/eingefuegt?
1689 }
1690 }
1691 }
1692
1693
UpdateGrow(const ScRange & rArea,SCCOL nGrowX,SCROW nGrowY)1694 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1695 {
1696 if (pItems)
1697 for (SCSIZE i=0; i<nCount; i++)
1698 {
1699 ScBaseCell* pCell = pItems[i].pCell;
1700 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1701 {
1702 SCROW nRow = pItems[i].nRow;
1703 ((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY );
1704 if ( nRow != pItems[i].nRow )
1705 Search( nRow, i ); // Listener geloescht/eingefuegt?
1706 }
1707 }
1708 }
1709
1710
UpdateInsertTab(SCTAB nTable)1711 void ScColumn::UpdateInsertTab( SCTAB nTable)
1712 {
1713 if (nTab >= nTable)
1714 pAttrArray->SetTab(++nTab);
1715 if( pItems )
1716 UpdateInsertTabOnlyCells( nTable );
1717 }
1718
1719
UpdateInsertTabOnlyCells(SCTAB nTable)1720 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable)
1721 {
1722 if (pItems)
1723 for (SCSIZE i = 0; i < nCount; i++)
1724 {
1725 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1726 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1727 {
1728 SCROW nRow = pItems[i].nRow;
1729 pCell->UpdateInsertTab(nTable);
1730 if ( nRow != pItems[i].nRow )
1731 Search( nRow, i ); // Listener geloescht/eingefuegt?
1732 }
1733 }
1734 }
1735
1736
UpdateInsertTabAbs(SCTAB nTable)1737 void ScColumn::UpdateInsertTabAbs(SCTAB nTable)
1738 {
1739 if (pItems)
1740 for (SCSIZE i = 0; i < nCount; i++)
1741 {
1742 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1743 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1744 {
1745 SCROW nRow = pItems[i].nRow;
1746 pCell->UpdateInsertTabAbs(nTable);
1747 if ( nRow != pItems[i].nRow )
1748 Search( nRow, i ); // Listener geloescht/eingefuegt?
1749 }
1750 }
1751 }
1752
1753
UpdateDeleteTab(SCTAB nTable,sal_Bool bIsMove,ScColumn * pRefUndo)1754 void ScColumn::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScColumn* pRefUndo )
1755 {
1756 if (nTab > nTable)
1757 pAttrArray->SetTab(--nTab);
1758
1759 if (pItems)
1760 for (SCSIZE i = 0; i < nCount; i++)
1761 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1762 {
1763 SCROW nRow = pItems[i].nRow;
1764 ScFormulaCell* pOld = (ScFormulaCell*)pItems[i].pCell;
1765
1766 /* Do not copy cell note to the undo document. Undo will copy
1767 back the formula cell while keeping the original note. */
1768 ScBaseCell* pSave = pRefUndo ? pOld->CloneWithoutNote( *pDocument ) : 0;
1769
1770 sal_Bool bChanged = pOld->UpdateDeleteTab(nTable, bIsMove);
1771 if ( nRow != pItems[i].nRow )
1772 Search( nRow, i ); // Listener geloescht/eingefuegt?
1773
1774 if (pRefUndo)
1775 {
1776 if (bChanged)
1777 pRefUndo->Insert( nRow, pSave );
1778 else if(pSave)
1779 pSave->Delete();
1780 }
1781 }
1782 }
1783
1784
UpdateMoveTab(SCTAB nOldPos,SCTAB nNewPos,SCTAB nTabNo)1785 void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1786 {
1787 nTab = nTabNo;
1788 pAttrArray->SetTab( nTabNo );
1789 if (pItems)
1790 for (SCSIZE i = 0; i < nCount; i++)
1791 {
1792 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1793 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1794 {
1795 SCROW nRow = pItems[i].nRow;
1796 pCell->UpdateMoveTab( nOldPos, nNewPos, nTabNo );
1797 if ( nRow != pItems[i].nRow )
1798 Search( nRow, i ); // Listener geloescht/eingefuegt?
1799 }
1800 }
1801 }
1802
1803
UpdateCompile(sal_Bool bForceIfNameInUse)1804 void ScColumn::UpdateCompile( sal_Bool bForceIfNameInUse )
1805 {
1806 if (pItems)
1807 for (SCSIZE i = 0; i < nCount; i++)
1808 {
1809 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1810 if( p->GetCellType() == CELLTYPE_FORMULA )
1811 {
1812 SCROW nRow = pItems[i].nRow;
1813 p->UpdateCompile( bForceIfNameInUse );
1814 if ( nRow != pItems[i].nRow )
1815 Search( nRow, i ); // Listener geloescht/eingefuegt?
1816 }
1817 }
1818 }
1819
1820
SetTabNo(SCTAB nNewTab)1821 void ScColumn::SetTabNo(SCTAB nNewTab)
1822 {
1823 nTab = nNewTab;
1824 pAttrArray->SetTab( nNewTab );
1825 if (pItems)
1826 for (SCSIZE i = 0; i < nCount; i++)
1827 {
1828 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1829 if( p->GetCellType() == CELLTYPE_FORMULA )
1830 p->aPos.SetTab( nNewTab );
1831 }
1832 }
1833
1834
IsRangeNameInUse(SCROW nRow1,SCROW nRow2,sal_uInt16 nIndex) const1835 sal_Bool ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, sal_uInt16 nIndex) const
1836 {
1837 sal_Bool bInUse = sal_False;
1838 if (pItems)
1839 for (SCSIZE i = 0; !bInUse && (i < nCount); i++)
1840 if ((pItems[i].nRow >= nRow1) &&
1841 (pItems[i].nRow <= nRow2) &&
1842 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1843 bInUse = ((ScFormulaCell*)pItems[i].pCell)->IsRangeNameInUse(nIndex);
1844 return bInUse;
1845 }
1846
FindRangeNamesInUse(SCROW nRow1,SCROW nRow2,std::set<sal_uInt16> & rIndexes) const1847 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
1848 {
1849 if (pItems)
1850 for (SCSIZE i = 0; i < nCount; i++)
1851 if ((pItems[i].nRow >= nRow1) &&
1852 (pItems[i].nRow <= nRow2) &&
1853 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1854 ((ScFormulaCell*)pItems[i].pCell)->FindRangeNamesInUse(rIndexes);
1855 }
1856
ReplaceRangeNamesInUse(SCROW nRow1,SCROW nRow2,const ScRangeData::IndexMap & rMap)1857 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1, SCROW nRow2,
1858 const ScRangeData::IndexMap& rMap )
1859 {
1860 if (pItems)
1861 for (SCSIZE i = 0; i < nCount; i++)
1862 {
1863 if ((pItems[i].nRow >= nRow1) &&
1864 (pItems[i].nRow <= nRow2) &&
1865 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1866 {
1867 SCROW nRow = pItems[i].nRow;
1868 ((ScFormulaCell*)pItems[i].pCell)->ReplaceRangeNamesInUse( rMap );
1869 if ( nRow != pItems[i].nRow )
1870 Search( nRow, i ); // Listener geloescht/eingefuegt?
1871 }
1872 }
1873 }
1874
SetDirtyVar()1875 void ScColumn::SetDirtyVar()
1876 {
1877 for (SCSIZE i=0; i<nCount; i++)
1878 {
1879 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1880 if( p->GetCellType() == CELLTYPE_FORMULA )
1881 p->SetDirtyVar();
1882 }
1883 }
1884
1885
SetDirty()1886 void ScColumn::SetDirty()
1887 {
1888 // wird nur dokumentweit verwendet, kein FormulaTrack
1889 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1890 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
1891 for (SCSIZE i=0; i<nCount; i++)
1892 {
1893 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1894 if( p->GetCellType() == CELLTYPE_FORMULA )
1895 {
1896 p->SetDirtyVar();
1897 if ( !pDocument->IsInFormulaTree( p ) )
1898 pDocument->PutInFormulaTree( p );
1899 }
1900 }
1901 pDocument->SetAutoCalc( bOldAutoCalc );
1902 }
1903
1904
SetDirty(const ScRange & rRange)1905 void ScColumn::SetDirty( const ScRange& rRange )
1906 { // broadcastet alles innerhalb eines Range, mit FormulaTrack
1907 if ( !pItems || !nCount )
1908 return ;
1909 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1910 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
1911 SCROW nRow2 = rRange.aEnd.Row();
1912 ScAddress aPos( nCol, 0, nTab );
1913 ScHint aHint( SC_HINT_DATACHANGED, aPos, NULL );
1914 SCROW nRow;
1915 SCSIZE nIndex;
1916 Search( rRange.aStart.Row(), nIndex );
1917 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1918 {
1919 ScBaseCell* pCell = pItems[nIndex].pCell;
1920 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1921 ((ScFormulaCell*)pCell)->SetDirty();
1922 else
1923 {
1924 aHint.GetAddress().SetRow( nRow );
1925 aHint.SetCell( pCell );
1926 pDocument->Broadcast( aHint );
1927 }
1928 nIndex++;
1929 }
1930 pDocument->SetAutoCalc( bOldAutoCalc );
1931 }
1932
1933
SetTableOpDirty(const ScRange & rRange)1934 void ScColumn::SetTableOpDirty( const ScRange& rRange )
1935 {
1936 if ( !pItems || !nCount )
1937 return ;
1938 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1939 pDocument->SetAutoCalc( sal_False ); // no multiple recalculation
1940 SCROW nRow2 = rRange.aEnd.Row();
1941 ScAddress aPos( nCol, 0, nTab );
1942 ScHint aHint( SC_HINT_TABLEOPDIRTY, aPos, NULL );
1943 SCROW nRow;
1944 SCSIZE nIndex;
1945 Search( rRange.aStart.Row(), nIndex );
1946 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1947 {
1948 ScBaseCell* pCell = pItems[nIndex].pCell;
1949 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1950 ((ScFormulaCell*)pCell)->SetTableOpDirty();
1951 else
1952 {
1953 aHint.GetAddress().SetRow( nRow );
1954 aHint.SetCell( pCell );
1955 pDocument->Broadcast( aHint );
1956 }
1957 nIndex++;
1958 }
1959 pDocument->SetAutoCalc( bOldAutoCalc );
1960 }
1961
1962
SetDirtyAfterLoad()1963 void ScColumn::SetDirtyAfterLoad()
1964 {
1965 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1966 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
1967 for (SCSIZE i=0; i<nCount; i++)
1968 {
1969 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1970 #if 1
1971 // Simply set dirty and append to FormulaTree, without broadcasting,
1972 // which is a magnitude faster. This is used to calculate the entire
1973 // document, e.g. when loading alien file formats.
1974 if ( p->GetCellType() == CELLTYPE_FORMULA )
1975 p->SetDirtyAfterLoad();
1976 #else
1977 /* This was used with the binary file format that stored results, where only
1978 * newly compiled and volatile functions and their dependents had to be
1979 * recalculated, which was faster then. Since that was moved to 'binfilter' to
1980 * convert to an XML file this isn't needed anymore, and not used for other
1981 * file formats. Kept for reference in case mechanism needs to be reactivated
1982 * for some file formats, we'd have to introduce a controlling parameter to
1983 * this method here then.
1984 */
1985
1986 // If the cell was alsready dirty because of CalcAfterLoad,
1987 // FormulaTracking has to take place.
1988 if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() )
1989 p->SetDirty();
1990 #endif
1991 }
1992 pDocument->SetAutoCalc( bOldAutoCalc );
1993 }
1994
1995
SetRelNameDirty()1996 void ScColumn::SetRelNameDirty()
1997 {
1998 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1999 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
2000 for (SCSIZE i=0; i<nCount; i++)
2001 {
2002 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
2003 if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() )
2004 p->SetDirty();
2005 }
2006 pDocument->SetAutoCalc( bOldAutoCalc );
2007 }
2008
2009
CalcAll()2010 void ScColumn::CalcAll()
2011 {
2012 if (pItems)
2013 for (SCSIZE i=0; i<nCount; i++)
2014 {
2015 ScBaseCell* pCell = pItems[i].pCell;
2016 if (pCell->GetCellType() == CELLTYPE_FORMULA)
2017 {
2018 #if OSL_DEBUG_LEVEL > 1
2019 // nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree
2020 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
2021 double nOldVal, nNewVal;
2022 nOldVal = pFCell->GetValue();
2023 #endif
2024 ((ScFormulaCell*)pCell)->Interpret();
2025 #if OSL_DEBUG_LEVEL > 1
2026 if ( pFCell->GetCode()->IsRecalcModeNormal() )
2027 nNewVal = pFCell->GetValue();
2028 else
2029 nNewVal = nOldVal; // random(), jetzt() etc.
2030 DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
2031 #endif
2032 }
2033 }
2034 }
2035
2036
CompileAll()2037 void ScColumn::CompileAll()
2038 {
2039 if (pItems)
2040 for (SCSIZE i = 0; i < nCount; i++)
2041 {
2042 ScBaseCell* pCell = pItems[i].pCell;
2043 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2044 {
2045 SCROW nRow = pItems[i].nRow;
2046 // fuer unbedingtes kompilieren
2047 // bCompile=sal_True und pCode->nError=0
2048 ((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 );
2049 ((ScFormulaCell*)pCell)->SetCompile( sal_True );
2050 ((ScFormulaCell*)pCell)->CompileTokenArray();
2051 if ( nRow != pItems[i].nRow )
2052 Search( nRow, i ); // Listener geloescht/eingefuegt?
2053 }
2054 }
2055 }
2056
2057
CompileXML(ScProgress & rProgress)2058 void ScColumn::CompileXML( ScProgress& rProgress )
2059 {
2060 if (pItems)
2061 for (SCSIZE i = 0; i < nCount; i++)
2062 {
2063 ScBaseCell* pCell = pItems[i].pCell;
2064 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2065 {
2066 SCROW nRow = pItems[i].nRow;
2067 ((ScFormulaCell*)pCell)->CompileXML( rProgress );
2068 if ( nRow != pItems[i].nRow )
2069 Search( nRow, i ); // Listener geloescht/eingefuegt?
2070 }
2071 }
2072 }
2073
2074
CalcAfterLoad()2075 void ScColumn::CalcAfterLoad()
2076 {
2077 if (pItems)
2078 for (SCSIZE i = 0; i < nCount; i++)
2079 {
2080 ScBaseCell* pCell = pItems[i].pCell;
2081 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2082 ((ScFormulaCell*)pCell)->CalcAfterLoad();
2083 }
2084 }
2085
2086
ResetChanged(SCROW nStartRow,SCROW nEndRow)2087 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
2088 {
2089 if (pItems)
2090 {
2091 SCSIZE nIndex;
2092 Search(nStartRow,nIndex);
2093 while (nIndex<nCount && pItems[nIndex].nRow <= nEndRow)
2094 {
2095 ScBaseCell* pCell = pItems[nIndex].pCell;
2096 if (pCell->GetCellType() == CELLTYPE_FORMULA)
2097 ((ScFormulaCell*)pCell)->ResetChanged();
2098 ++nIndex;
2099 }
2100 }
2101 }
2102
2103
HasEditCells(SCROW nStartRow,SCROW nEndRow,SCROW & rFirst) const2104 sal_Bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
2105 {
2106 // used in GetOptimalHeight - ambiguous script type counts as edit cell
2107
2108 SCROW nRow = 0;
2109 SCSIZE nIndex;
2110 Search(nStartRow,nIndex);
2111 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
2112 {
2113 ScBaseCell* pCell = pItems[nIndex].pCell;
2114 CellType eCellType = pCell->GetCellType();
2115 if ( eCellType == CELLTYPE_EDIT ||
2116 IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ||
2117 ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) )
2118 {
2119 rFirst = nRow;
2120 return sal_True;
2121 }
2122 ++nIndex;
2123 }
2124
2125 return sal_False;
2126 }
2127
2128
SearchStyle(SCsROW nRow,const ScStyleSheet * pSearchStyle,sal_Bool bUp,sal_Bool bInSelection,const ScMarkData & rMark)2129 SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2130 sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2131 {
2132 if (bInSelection)
2133 {
2134 if (rMark.IsMultiMarked())
2135 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp,
2136 (ScMarkArray*) rMark.GetArray()+nCol ); //! const
2137 else
2138 return -1;
2139 }
2140 else
2141 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
2142 }
2143
2144
SearchStyleRange(SCsROW & rRow,SCsROW & rEndRow,const ScStyleSheet * pSearchStyle,sal_Bool bUp,sal_Bool bInSelection,const ScMarkData & rMark)2145 sal_Bool ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle,
2146 sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2147 {
2148 if (bInSelection)
2149 {
2150 if (rMark.IsMultiMarked())
2151 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
2152 (ScMarkArray*) rMark.GetArray()+nCol ); //! const
2153 else
2154 return sal_False;
2155 }
2156 else
2157 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
2158 }
2159
2160
2161