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 // INCLUDE ---------------------------------------------------------------
28
29 #include "scitems.hxx"
30 #include <svx/algitem.hxx>
31 #include <unotools/textsearch.hxx>
32 #include <sfx2/objsh.hxx>
33
34 #include "attrib.hxx"
35 #include "patattr.hxx"
36 #include "cell.hxx"
37 #include "table.hxx"
38 #include "document.hxx"
39 #include "drwlayer.hxx"
40 #include "olinetab.hxx"
41 #include "stlsheet.hxx"
42 #include "global.hxx"
43 #include "globstr.hrc"
44 #include "refupdat.hxx"
45 #include "markdata.hxx"
46 #include "progress.hxx"
47 #include "hints.hxx" // fuer Paint-Broadcast
48 #include "prnsave.hxx"
49 #include "tabprotection.hxx"
50 #include "sheetevents.hxx"
51 #include "segmenttree.hxx"
52
53 // -----------------------------------------------------------------------
54
ScTable(ScDocument * pDoc,SCTAB nNewTab,const String & rNewName,sal_Bool bColInfo,sal_Bool bRowInfo)55 ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
56 sal_Bool bColInfo, sal_Bool bRowInfo ) :
57 aName( rNewName ),
58 aCodeName( rNewName ),
59 bScenario( sal_False ),
60 bLayoutRTL( sal_False ),
61 bLoadingRTL( sal_False ),
62 nLinkMode( 0 ),
63 aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ),
64 bPageSizeValid( sal_False ),
65 nRepeatStartX( SCCOL_REPEAT_NONE ),
66 nRepeatStartY( SCROW_REPEAT_NONE ),
67 pTabProtection( NULL ),
68 pColWidth( NULL ),
69 mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ),
70 pColFlags( NULL ),
71 pRowFlags( NULL ),
72 mpHiddenCols(new ScFlatBoolColSegments),
73 mpHiddenRows(new ScFlatBoolRowSegments),
74 mpFilteredCols(new ScFlatBoolColSegments),
75 mpFilteredRows(new ScFlatBoolRowSegments),
76 pOutlineTable( NULL ),
77 pSheetEvents( NULL ),
78 bTableAreaValid( sal_False ),
79 bVisible( sal_True ),
80 bStreamValid( sal_False ),
81 bPendingRowHeights( sal_False ),
82 bCalcNotification( sal_False ),
83 nTab( nNewTab ),
84 nRecalcLvl( 0 ),
85 pDocument( pDoc ),
86 pSearchParam( NULL ),
87 pSearchText ( NULL ),
88 pSortCollator( NULL ),
89 bPrintEntireSheet( sal_False ),
90 pRepeatColRange( NULL ),
91 pRepeatRowRange( NULL ),
92 nLockCount( 0 ),
93 pScenarioRanges( NULL ),
94 aScenarioColor( COL_LIGHTGRAY ),
95 aTabBgColor( COL_AUTO ),
96 nScenarioFlags( 0 ),
97 bActiveScenario( sal_False ),
98 mbPageBreaksValid(false)
99 {
100
101 if (bColInfo)
102 {
103 pColWidth = new sal_uInt16[ MAXCOL+1 ];
104 pColFlags = new sal_uInt8[ MAXCOL+1 ];
105
106 for (SCCOL i=0; i<=MAXCOL; i++)
107 {
108 pColWidth[i] = STD_COL_WIDTH;
109 pColFlags[i] = 0;
110 }
111 }
112
113 if (bRowInfo)
114 {
115 mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight));
116 pRowFlags = new ScBitMaskCompressedArray< SCROW, sal_uInt8>( MAXROW, 0);
117 }
118
119 if ( pDocument->IsDocVisible() )
120 {
121 // when a sheet is added to a visible document,
122 // initialize its RTL flag from the system locale
123 bLayoutRTL = ScGlobal::IsSystemRTL();
124 }
125
126 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
127 if (pDrawLayer)
128 {
129 if ( pDrawLayer->ScAddPage( nTab ) ) // sal_False (not inserted) during Undo
130 {
131 pDrawLayer->ScRenamePage( nTab, aName );
132 sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS );
133 sal_uLong ny = (sal_uLong) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS );
134 pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false );
135 }
136 }
137
138 for (SCCOL k=0; k<=MAXCOL; k++)
139 aCol[k].Init( k, nTab, pDocument );
140 }
141
~ScTable()142 ScTable::~ScTable()
143 {
144 if (!pDocument->IsInDtorClear())
145 {
146 // nicht im dtor die Pages in der falschen Reihenfolge loeschen
147 // (nTab stimmt dann als Page-Number nicht!)
148 // In ScDocument::Clear wird hinterher per Clear am Draw Layer alles geloescht.
149
150 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
151 if (pDrawLayer)
152 pDrawLayer->ScRemovePage( nTab );
153 }
154
155 delete[] pColWidth;
156 delete[] pColFlags;
157 delete pRowFlags;
158 delete pSheetEvents;
159 delete pOutlineTable;
160 delete pSearchParam;
161 delete pSearchText;
162 delete pRepeatColRange;
163 delete pRepeatRowRange;
164 delete pScenarioRanges;
165 DestroySortCollator();
166 }
167
GetName(String & rName) const168 void ScTable::GetName( String& rName ) const
169 {
170 rName = aName;
171 }
172
SetName(const String & rNewName)173 void ScTable::SetName( const String& rNewName )
174 {
175 aName = rNewName;
176 aUpperName.Erase(); // invalidated if the name is changed
177
178 // SetStreamValid is handled in ScDocument::RenameTab
179 }
180
GetUpperName() const181 const String& ScTable::GetUpperName() const
182 {
183 if ( !aUpperName.Len() && aName.Len() )
184 aUpperName = ScGlobal::pCharClass->upper( aName );
185 return aUpperName;
186 }
187
SetVisible(sal_Bool bVis)188 void ScTable::SetVisible( sal_Bool bVis )
189 {
190 if (bVisible != bVis && IsStreamValid())
191 SetStreamValid(sal_False);
192
193 bVisible = bVis;
194 }
195
SetStreamValid(sal_Bool bSet,sal_Bool bIgnoreLock)196 void ScTable::SetStreamValid( sal_Bool bSet, sal_Bool bIgnoreLock )
197 {
198 if ( bIgnoreLock || !pDocument->IsStreamValidLocked() )
199 bStreamValid = bSet;
200 }
201
SetPendingRowHeights(sal_Bool bSet)202 void ScTable::SetPendingRowHeights( sal_Bool bSet )
203 {
204 bPendingRowHeights = bSet;
205 }
206
SetLayoutRTL(sal_Bool bSet)207 void ScTable::SetLayoutRTL( sal_Bool bSet )
208 {
209 bLayoutRTL = bSet;
210 }
211
SetLoadingRTL(sal_Bool bSet)212 void ScTable::SetLoadingRTL( sal_Bool bSet )
213 {
214 bLoadingRTL = bSet;
215 }
216
GetTabBgColor() const217 const Color& ScTable::GetTabBgColor() const
218 {
219 return aTabBgColor;
220 }
221
SetTabBgColor(const Color & rColor)222 void ScTable::SetTabBgColor(const Color& rColor)
223 {
224 if (aTabBgColor != rColor)
225 {
226 // The tab color has changed. Set this table 'modified'.
227 aTabBgColor = rColor;
228 if (IsStreamValid())
229 SetStreamValid(false);
230 }
231 }
232
SetScenario(sal_Bool bFlag)233 void ScTable::SetScenario( sal_Bool bFlag )
234 {
235 bScenario = bFlag;
236 }
237
SetLink(sal_uInt8 nMode,const String & rDoc,const String & rFlt,const String & rOpt,const String & rTab,sal_uLong nRefreshDelay)238 void ScTable::SetLink( sal_uInt8 nMode,
239 const String& rDoc, const String& rFlt, const String& rOpt,
240 const String& rTab, sal_uLong nRefreshDelay )
241 {
242 nLinkMode = nMode;
243 aLinkDoc = rDoc; // Datei
244 aLinkFlt = rFlt; // Filter
245 aLinkOpt = rOpt; // Filter-Optionen
246 aLinkTab = rTab; // Tabellenname in Quelldatei
247 nLinkRefreshDelay = nRefreshDelay; // refresh delay in seconds, 0==off
248
249 if (IsStreamValid())
250 SetStreamValid(sal_False);
251 }
252
GetOptimalColWidth(SCCOL nCol,OutputDevice * pDev,double nPPTX,double nPPTY,const Fraction & rZoomX,const Fraction & rZoomY,sal_Bool bFormula,const ScMarkData * pMarkData,sal_Bool bSimpleTextImport)253 sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev,
254 double nPPTX, double nPPTY,
255 const Fraction& rZoomX, const Fraction& rZoomY,
256 sal_Bool bFormula, const ScMarkData* pMarkData,
257 sal_Bool bSimpleTextImport )
258 {
259 return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY,
260 bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, bSimpleTextImport );
261 }
262
GetNeededSize(SCCOL nCol,SCROW nRow,OutputDevice * pDev,double nPPTX,double nPPTY,const Fraction & rZoomX,const Fraction & rZoomY,sal_Bool bWidth,sal_Bool bTotalSize)263 long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow,
264 OutputDevice* pDev,
265 double nPPTX, double nPPTY,
266 const Fraction& rZoomX, const Fraction& rZoomY,
267 sal_Bool bWidth, sal_Bool bTotalSize )
268 {
269 ScNeededSizeOptions aOptions;
270 aOptions.bSkipMerged = sal_False; // zusammengefasste mitzaehlen
271 aOptions.bTotalSize = bTotalSize;
272
273 return aCol[nCol].GetNeededSize
274 ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions );
275 }
276
SetOptimalHeight(SCROW nStartRow,SCROW nEndRow,sal_uInt16 nExtra,OutputDevice * pDev,double nPPTX,double nPPTY,const Fraction & rZoomX,const Fraction & rZoomY,sal_Bool bForce,ScProgress * pOuterProgress,sal_uLong nProgressStart)277 sal_Bool ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra,
278 OutputDevice* pDev,
279 double nPPTX, double nPPTY,
280 const Fraction& rZoomX, const Fraction& rZoomY,
281 sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart )
282 {
283 DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" );
284
285 if ( !pDocument->IsAdjustHeightEnabled() )
286 {
287 return sal_False;
288 }
289
290 sal_Bool bChanged = sal_False;
291 SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1);
292
293 ScProgress* pProgress = NULL;
294 if ( pOuterProgress )
295 pProgress = pOuterProgress;
296 else if ( nCount > 1 )
297 pProgress = new ScProgress( pDocument->GetDocumentShell(),
298 ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), GetWeightedCount() );
299
300 sal_uInt16* pHeight = new sal_uInt16[nCount]; // Twips !
301 memset( pHeight, 0, sizeof(sal_uInt16) * nCount );
302
303 // zuerst einmal ueber den ganzen Bereich
304 // (mit der letzten Spalte in der Hoffnung, dass die am ehesten noch auf
305 // Standard formatiert ist)
306
307 aCol[MAXCOL].GetOptimalHeight(
308 nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 0, 0 );
309
310 // daraus Standardhoehe suchen, die im unteren Bereich gilt
311
312 sal_uInt16 nMinHeight = pHeight[nCount-1];
313 SCSIZE nPos = nCount-1;
314 while ( nPos && pHeight[nPos-1] >= nMinHeight )
315 --nPos;
316 SCROW nMinStart = nStartRow + nPos;
317
318 sal_uLong nWeightedCount = 0;
319 for (SCCOL nCol=0; nCol<MAXCOL; nCol++) // MAXCOL schon oben
320 {
321 aCol[nCol].GetOptimalHeight(
322 nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce,
323 nMinHeight, nMinStart );
324
325 if (pProgress)
326 {
327 sal_uLong nWeight = aCol[nCol].GetWeightedCount();
328 if (nWeight) // nochmal denselben Status muss auch nicht sein
329 {
330 nWeightedCount += nWeight;
331 pProgress->SetState( nWeightedCount + nProgressStart );
332 }
333 }
334 }
335
336 IncRecalcLevel(); // #i116460# avoid problems with Excel files
337
338 SCROW nRngStart = 0;
339 SCROW nRngEnd = 0;
340 sal_uInt16 nLast = 0;
341 for (SCSIZE i=0; i<nCount; i++)
342 {
343 size_t nIndex;
344 SCROW nRegionEndRow;
345 sal_uInt8 nRowFlag = pRowFlags->GetValue( nStartRow+i, nIndex, nRegionEndRow );
346 if ( nRegionEndRow > nEndRow )
347 nRegionEndRow = nEndRow;
348 SCSIZE nMoreRows = nRegionEndRow - ( nStartRow+i ); // additional equal rows after first
349
350 bool bAutoSize = ((nRowFlag & CR_MANUALSIZE) == 0);
351 if ( bAutoSize || bForce )
352 {
353 if (nExtra)
354 {
355 if (bAutoSize)
356 pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag | CR_MANUALSIZE);
357 }
358 else if (!bAutoSize)
359 pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag & ~CR_MANUALSIZE);
360
361 for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner)
362 {
363 if (nLast)
364 {
365 if (pHeight[nInner]+nExtra == nLast)
366 nRngEnd = nStartRow+nInner;
367 else
368 {
369 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
370 nLast = 0;
371 }
372 }
373 if (!nLast)
374 {
375 nLast = pHeight[nInner]+nExtra;
376 nRngStart = nStartRow+nInner;
377 nRngEnd = nStartRow+nInner;
378 }
379 }
380 }
381 else
382 {
383 if (nLast)
384 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
385 nLast = 0;
386 }
387 i += nMoreRows; // already handled - skip
388 }
389 if (nLast)
390 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
391
392 DecRecalcLevel(); // #i116460# avoid problems with Excel files
393
394 delete[] pHeight;
395 if ( pProgress != pOuterProgress )
396 delete pProgress;
397
398 return bChanged;
399 }
400
GetCellArea(SCCOL & rEndCol,SCROW & rEndRow) const401 sal_Bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
402 {
403 sal_Bool bFound = sal_False;
404 SCCOL nMaxX = 0;
405 SCROW nMaxY = 0;
406 for (SCCOL i=0; i<=MAXCOL; i++)
407 if (!aCol[i].IsEmptyVisData(sal_True)) // sal_True = Notizen zaehlen auch
408 {
409 bFound = sal_True;
410 nMaxX = i;
411 SCROW nColY = aCol[i].GetLastVisDataPos(sal_True);
412 if (nColY > nMaxY)
413 nMaxY = nColY;
414 }
415
416 rEndCol = nMaxX;
417 rEndRow = nMaxY;
418 return bFound;
419 }
420
GetTableArea(SCCOL & rEndCol,SCROW & rEndRow) const421 sal_Bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const
422 {
423 sal_Bool bRet = sal_True; //! merken?
424 if (!bTableAreaValid)
425 {
426 bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX,
427 ((ScTable*)this)->nTableAreaY, sal_True );
428 ((ScTable*)this)->bTableAreaValid = sal_True;
429 }
430 rEndCol = nTableAreaX;
431 rEndRow = nTableAreaY;
432 return bRet;
433 }
434
GetLastAttrCell(SCCOL & rEndCol,SCROW & rEndRow) const435 void ScTable::GetLastAttrCell( SCCOL& rEndCol, SCROW& rEndRow ) const
436 {
437 SCCOL nMaxX = 0;
438 SCROW nMaxY = 0;
439 SCCOL i;
440 for ( i = 0; i <= MAXCOL; i++ )
441 {
442 SCROW nLastRow;
443 aCol[i].GetLastAttr( nLastRow );
444 if ( nLastRow > nMaxY && nLastRow > 0 && nLastRow <= MAXROW )
445 {
446 nMaxY = nLastRow;
447 nMaxX = i;
448 }
449 }
450 rEndCol = nMaxX;
451 rEndRow = nMaxY;
452 }
453 /* vorher:
454
455 sal_Bool bFound = sal_False;
456 SCCOL nMaxX = 0;
457 SCROW nMaxY = 0;
458 for (SCCOL i=0; i<=MAXCOL; i++)
459 if (!aCol[i].IsEmpty())
460 {
461 bFound = sal_True;
462 nMaxX = i;
463 SCCOL nColY = aCol[i].GetLastEntryPos();
464 if (nColY > nMaxY)
465 nMaxY = nColY;
466 }
467
468 rEndCol = nMaxX;
469 rEndRow = nMaxY;
470 return bFound;
471 */
472
473 const SCCOL SC_COLUMNS_STOP = 30;
474
GetPrintArea(SCCOL & rEndCol,SCROW & rEndRow,sal_Bool bNotes) const475 sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const
476 {
477 sal_Bool bFound = sal_False;
478 SCCOL nMaxX = 0;
479 SCROW nMaxY = 0;
480 SCCOL i;
481
482 for (i=0; i<=MAXCOL; i++) // Daten testen
483 if (!aCol[i].IsEmptyVisData(bNotes))
484 {
485 bFound = sal_True;
486 if (i>nMaxX)
487 nMaxX = i;
488 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
489 if (nColY > nMaxY)
490 nMaxY = nColY;
491 }
492
493 SCCOL nMaxDataX = nMaxX;
494
495 for (i=0; i<=MAXCOL; i++) // Attribute testen
496 {
497 SCROW nLastRow;
498 if (aCol[i].GetLastVisibleAttr( nLastRow ))
499 {
500 bFound = sal_True;
501 nMaxX = i;
502 if (nLastRow > nMaxY)
503 nMaxY = nLastRow;
504 }
505 }
506
507 if (nMaxX == MAXCOL) // Attribute rechts weglassen
508 {
509 --nMaxX;
510 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) )
511 --nMaxX;
512 }
513
514 if ( nMaxX < nMaxDataX )
515 {
516 nMaxX = nMaxDataX;
517 }
518 else if ( nMaxX > nMaxDataX )
519 {
520 SCCOL nAttrStartX = nMaxDataX + 1;
521 while ( nAttrStartX < MAXCOL )
522 {
523 SCCOL nAttrEndX = nAttrStartX;
524 while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) )
525 ++nAttrEndX;
526 if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP )
527 {
528 // found equally-formatted columns behind data -> stop before these columns
529 nMaxX = nAttrStartX - 1;
530
531 // also don't include default-formatted columns before that
532 SCROW nDummyRow;
533 while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) )
534 --nMaxX;
535 break;
536 }
537 nAttrStartX = nAttrEndX + 1;
538 }
539 }
540
541 rEndCol = nMaxX;
542 rEndRow = nMaxY;
543 return bFound;
544 }
545
GetPrintAreaHor(SCROW nStartRow,SCROW nEndRow,SCCOL & rEndCol,sal_Bool) const546 sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
547 SCCOL& rEndCol, sal_Bool /* bNotes */ ) const
548 {
549 sal_Bool bFound = sal_False;
550 SCCOL nMaxX = 0;
551 SCCOL i;
552
553 for (i=0; i<=MAXCOL; i++) // Attribute testen
554 {
555 if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow ))
556 {
557 bFound = sal_True;
558 nMaxX = i;
559 }
560 }
561
562 if (nMaxX == MAXCOL) // Attribute rechts weglassen
563 {
564 --nMaxX;
565 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) )
566 --nMaxX;
567 }
568
569 for (i=0; i<=MAXCOL; i++) // Daten testen
570 {
571 if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //! bNotes ??????
572 {
573 bFound = sal_True;
574 if (i>nMaxX)
575 nMaxX = i;
576 }
577 }
578
579 rEndCol = nMaxX;
580 return bFound;
581 }
582
GetPrintAreaVer(SCCOL nStartCol,SCCOL nEndCol,SCROW & rEndRow,sal_Bool bNotes) const583 sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
584 SCROW& rEndRow, sal_Bool bNotes ) const
585 {
586 sal_Bool bFound = sal_False;
587 SCROW nMaxY = 0;
588 SCCOL i;
589
590 for (i=nStartCol; i<=nEndCol; i++) // Attribute testen
591 {
592 SCROW nLastRow;
593 if (aCol[i].GetLastVisibleAttr( nLastRow ))
594 {
595 bFound = sal_True;
596 if (nLastRow > nMaxY)
597 nMaxY = nLastRow;
598 }
599 }
600
601 for (i=nStartCol; i<=nEndCol; i++) // Daten testen
602 if (!aCol[i].IsEmptyVisData(bNotes))
603 {
604 bFound = sal_True;
605 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
606 if (nColY > nMaxY)
607 nMaxY = nColY;
608 }
609
610 rEndRow = nMaxY;
611 return bFound;
612 }
613
GetDataStart(SCCOL & rStartCol,SCROW & rStartRow) const614 sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
615 {
616 sal_Bool bFound = sal_False;
617 SCCOL nMinX = MAXCOL;
618 SCROW nMinY = MAXROW;
619 SCCOL i;
620
621 for (i=0; i<=MAXCOL; i++) // Attribute testen
622 {
623 SCROW nFirstRow;
624 if (aCol[i].GetFirstVisibleAttr( nFirstRow ))
625 {
626 if (!bFound)
627 nMinX = i;
628 bFound = sal_True;
629 if (nFirstRow < nMinY)
630 nMinY = nFirstRow;
631 }
632 }
633
634 if (nMinX == 0) // Attribute links weglassen
635 {
636 if ( aCol[0].IsVisibleAttrEqual(aCol[1]) ) // keine einzelnen
637 {
638 ++nMinX;
639 while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) )
640 ++nMinX;
641 }
642 }
643
644 sal_Bool bDatFound = sal_False;
645 for (i=0; i<=MAXCOL; i++) // Daten testen
646 if (!aCol[i].IsEmptyVisData(sal_True))
647 {
648 if (!bDatFound && i<nMinX)
649 nMinX = i;
650 bFound = bDatFound = sal_True;
651 SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True);
652 if (nColY < nMinY)
653 nMinY = nColY;
654 }
655
656 rStartCol = nMinX;
657 rStartRow = nMinY;
658 return bFound;
659 }
660
GetDataArea(SCCOL & rStartCol,SCROW & rStartRow,SCCOL & rEndCol,SCROW & rEndRow,sal_Bool bIncludeOld,bool bOnlyDown) const661 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
662 sal_Bool bIncludeOld, bool bOnlyDown ) const
663 {
664 sal_Bool bLeft = sal_False;
665 sal_Bool bRight = sal_False;
666 sal_Bool bTop = sal_False;
667 sal_Bool bBottom = sal_False;
668 sal_Bool bChanged;
669 sal_Bool bFound;
670 SCCOL i;
671 SCROW nTest;
672
673 do
674 {
675 bChanged = sal_False;
676
677 if (!bOnlyDown)
678 {
679 SCROW nStart = rStartRow;
680 SCROW nEnd = rEndRow;
681 if (nStart>0) --nStart;
682 if (nEnd<MAXROW) ++nEnd;
683
684 if (rEndCol < MAXCOL)
685 if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
686 {
687 ++rEndCol;
688 bChanged = sal_True;
689 bRight = sal_True;
690 }
691
692 if (rStartCol > 0)
693 if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
694 {
695 --rStartCol;
696 bChanged = sal_True;
697 bLeft = sal_True;
698 }
699
700 if (rStartRow > 0)
701 {
702 nTest = rStartRow-1;
703 bFound = sal_False;
704 for (i=rStartCol; i<=rEndCol && !bFound; i++)
705 if (aCol[i].HasDataAt(nTest))
706 bFound = sal_True;
707 if (bFound)
708 {
709 --rStartRow;
710 bChanged = sal_True;
711 bTop = sal_True;
712 }
713 }
714 }
715
716 if (rEndRow < MAXROW)
717 {
718 nTest = rEndRow+1;
719 bFound = sal_False;
720 for (i=rStartCol; i<=rEndCol && !bFound; i++)
721 if (aCol[i].HasDataAt(nTest))
722 bFound = sal_True;
723 if (bFound)
724 {
725 ++rEndRow;
726 bChanged = sal_True;
727 bBottom = sal_True;
728 }
729 }
730 }
731 while( bChanged );
732
733 if ( !bIncludeOld )
734 {
735 if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol )
736 if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
737 ++rStartCol;
738 if ( !bRight && rEndCol > 0 && rStartCol < rEndCol )
739 if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
740 --rEndCol;
741 if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow )
742 {
743 bFound = sal_False;
744 for (i=rStartCol; i<=rEndCol && !bFound; i++)
745 if (aCol[i].HasDataAt(rStartRow))
746 bFound = sal_True;
747 if (!bFound)
748 ++rStartRow;
749 }
750 if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow )
751 {
752 bFound = sal_False;
753 for (i=rStartCol; i<=rEndCol && !bFound; i++)
754 if (aCol[i].HasDataAt(rEndRow))
755 bFound = sal_True;
756 if (!bFound)
757 --rEndRow;
758 }
759 }
760 }
761
762
ShrinkToUsedDataArea(bool & o_bShrunk,SCCOL & rStartCol,SCROW & rStartRow,SCCOL & rEndCol,SCROW & rEndRow,bool bColumnsOnly) const763 bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
764 SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
765 {
766 o_bShrunk = false;
767
768 PutInOrder( rStartCol, rEndCol);
769 PutInOrder( rStartRow, rEndRow);
770 if (rStartCol < 0)
771 rStartCol = 0, o_bShrunk = true;
772 if (rStartRow < 0)
773 rStartRow = 0, o_bShrunk = true;
774 if (rEndCol > MAXCOL)
775 rEndCol = MAXCOL, o_bShrunk = true;
776 if (rEndRow > MAXROW)
777 rEndRow = MAXROW, o_bShrunk = true;
778
779 bool bChanged;
780 do
781 {
782 bChanged = false;
783
784 while (rStartCol < rEndCol)
785 {
786 if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
787 {
788 --rEndCol;
789 bChanged = true;
790 }
791 else
792 break; // while
793 }
794
795 while (rStartCol < rEndCol)
796 {
797 if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
798 {
799 ++rStartCol;
800 bChanged = true;
801 }
802 else
803 break; // while
804 }
805
806 if (!bColumnsOnly)
807 {
808 if (rStartRow < rEndRow)
809 {
810 bool bFound = false;
811 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
812 if (aCol[i].HasDataAt( rStartRow))
813 bFound = true;
814 if (!bFound)
815 {
816 ++rStartRow;
817 bChanged = true;
818 }
819 }
820
821 if (rStartRow < rEndRow)
822 {
823 bool bFound = false;
824 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
825 if (aCol[i].HasDataAt( rEndRow))
826 bFound = true;
827 if (!bFound)
828 {
829 --rEndRow;
830 bChanged = true;
831 }
832 }
833 }
834
835 if (bChanged)
836 o_bShrunk = true;
837 } while( bChanged );
838
839 return rStartCol != rEndCol || (bColumnsOnly ?
840 !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) :
841 (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
842 }
843
844
GetEmptyLinesInBlock(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,ScDirection eDir)845 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
846 SCCOL nEndCol, SCROW nEndRow, ScDirection eDir )
847 {
848 SCSIZE nCount = 0;
849 SCCOL nCol;
850 if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP))
851 {
852 nCount = static_cast<SCSIZE>(nEndRow - nStartRow);
853 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
854 nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir));
855 }
856 else if (eDir == DIR_RIGHT)
857 {
858 nCol = nEndCol;
859 while (((SCsCOL)nCol >= (SCsCOL)nStartCol) &&
860 aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
861 {
862 nCount++;
863 nCol--;
864 }
865 }
866 else
867 {
868 nCol = nStartCol;
869 while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
870 {
871 nCount++;
872 nCol++;
873 }
874 }
875 return nCount;
876 }
877
IsEmptyLine(SCROW nRow,SCCOL nStartCol,SCCOL nEndCol)878 sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol )
879 {
880 sal_Bool bFound = sal_False;
881 for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
882 if (aCol[i].HasDataAt(nRow))
883 bFound = sal_True;
884 return !bFound;
885 }
886
LimitChartArea(SCCOL & rStartCol,SCROW & rStartRow,SCCOL & rEndCol,SCROW & rEndRow)887 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow )
888 {
889 while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
890 ++rStartCol;
891
892 while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
893 --rEndCol;
894
895 while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) )
896 ++rStartRow;
897
898 while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) )
899 --rEndRow;
900 }
901
FindAreaPos(SCCOL & rCol,SCROW & rRow,SCsCOL nMovX,SCsROW nMovY)902 void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY )
903 {
904 if (nMovX)
905 {
906 SCsCOL nNewCol = (SCsCOL) rCol;
907 sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow);
908 sal_Bool bFnd;
909 if (bThere)
910 {
911 do
912 {
913 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
914 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_False;
915 }
916 while (bFnd);
917 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX );
918
919 if (nNewCol == (SCsCOL)rCol)
920 bThere = sal_False;
921 }
922
923 if (!bThere)
924 {
925 do
926 {
927 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
928 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True;
929 }
930 while (!bFnd);
931 }
932
933 if (nNewCol<0) nNewCol=0;
934 if (nNewCol>MAXCOL) nNewCol=MAXCOL;
935 rCol = (SCCOL) nNewCol;
936 }
937
938 if (nMovY)
939 aCol[rCol].FindDataAreaPos(rRow,nMovY);
940 }
941
ValidNextPos(SCCOL nCol,SCROW nRow,const ScMarkData & rMark,sal_Bool bMarked,sal_Bool bUnprotected)942 sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark,
943 sal_Bool bMarked, sal_Bool bUnprotected )
944 {
945 if (!ValidCol(nCol) || !ValidRow(nRow))
946 return sal_False;
947
948 if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED))
949 // Skip an overlapped cell.
950 return false;
951
952 if (bMarked && !rMark.IsCellMarked(nCol,nRow))
953 return sal_False;
954
955 if (bUnprotected && ((const ScProtectionAttr*)
956 GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection())
957 return sal_False;
958
959 if (bMarked || bUnprotected) //! auch sonst ???
960 {
961 // #53697# ausgeblendete muessen uebersprungen werden, weil der Cursor sonst
962 // auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist.
963 //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ???
964
965 if (RowHidden(nRow))
966 return sal_False;
967
968 if (ColHidden(nCol))
969 return sal_False;
970 }
971
972 return sal_True;
973 }
974
GetNextPos(SCCOL & rCol,SCROW & rRow,SCsCOL nMovX,SCsROW nMovY,sal_Bool bMarked,sal_Bool bUnprotected,const ScMarkData & rMark)975 void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY,
976 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
977 {
978 if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt?
979 bUnprotected = sal_False;
980
981 sal_uInt16 nWrap = 0;
982 SCsCOL nCol = rCol;
983 SCsROW nRow = rRow;
984
985 nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX );
986 nRow = sal::static_int_cast<SCsROW>( nRow + nMovY );
987
988 DBG_ASSERT( !nMovY || !bUnprotected,
989 "GetNextPos mit bUnprotected horizontal nicht implementiert" );
990
991 if ( nMovY && bMarked )
992 {
993 sal_Bool bUp = ( nMovY < 0 );
994 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
995 while ( VALIDROW(nRow) &&
996 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
997 {
998 // #53697# ausgeblendete ueberspringen (s.o.)
999 nRow += nMovY;
1000 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1001 }
1002
1003 while ( nRow < 0 || nRow > MAXROW )
1004 {
1005 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) );
1006 while ( VALIDCOL(nCol) && ColHidden(nCol) )
1007 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); // #53697# skip hidden rows (see above)
1008 if (nCol < 0)
1009 {
1010 nCol = MAXCOL;
1011 if (++nWrap >= 2)
1012 return;
1013 }
1014 else if (nCol > MAXCOL)
1015 {
1016 nCol = 0;
1017 if (++nWrap >= 2)
1018 return;
1019 }
1020 if (nRow < 0)
1021 nRow = MAXROW;
1022 else if (nRow > MAXROW)
1023 nRow = 0;
1024 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1025 while ( VALIDROW(nRow) &&
1026 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
1027 {
1028 // #53697# ausgeblendete ueberspringen (s.o.)
1029 nRow += nMovY;
1030 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1031 }
1032 }
1033 }
1034
1035 if ( nMovX && ( bMarked || bUnprotected ) )
1036 {
1037 // initiales Weiterzaehlen wrappen:
1038 if (nCol<0)
1039 {
1040 nCol = MAXCOL;
1041 --nRow;
1042 if (nRow<0)
1043 nRow = MAXROW;
1044 }
1045 if (nCol>MAXCOL)
1046 {
1047 nCol = 0;
1048 ++nRow;
1049 if (nRow>MAXROW)
1050 nRow = 0;
1051 }
1052
1053 if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) )
1054 {
1055 SCsROW* pNextRows = new SCsROW[MAXCOL+1];
1056 SCCOL i;
1057
1058 if ( nMovX > 0 ) // vorwaerts
1059 {
1060 for (i=0; i<=MAXCOL; i++)
1061 pNextRows[i] = (i<nCol) ? (nRow+1) : nRow;
1062 do
1063 {
1064 SCsROW nNextRow = pNextRows[nCol] + 1;
1065 if ( bMarked )
1066 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_False );
1067 if ( bUnprotected )
1068 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_False );
1069 pNextRows[nCol] = nNextRow;
1070
1071 SCsROW nMinRow = MAXROW+1;
1072 for (i=0; i<=MAXCOL; i++)
1073 if (pNextRows[i] < nMinRow) // bei gleichen den linken
1074 {
1075 nMinRow = pNextRows[i];
1076 nCol = i;
1077 }
1078 nRow = nMinRow;
1079
1080 if ( nRow > MAXROW )
1081 {
1082 if (++nWrap >= 2) break; // ungueltigen Wert behalten
1083 nCol = 0;
1084 nRow = 0;
1085 for (i=0; i<=MAXCOL; i++)
1086 pNextRows[i] = 0; // alles ganz von vorne
1087 }
1088 }
1089 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
1090 }
1091 else // rueckwaerts
1092 {
1093 for (i=0; i<=MAXCOL; i++)
1094 pNextRows[i] = (i>nCol) ? (nRow-1) : nRow;
1095 do
1096 {
1097 SCsROW nNextRow = pNextRows[nCol] - 1;
1098 if ( bMarked )
1099 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_True );
1100 if ( bUnprotected )
1101 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_True );
1102 pNextRows[nCol] = nNextRow;
1103
1104 SCsROW nMaxRow = -1;
1105 for (i=0; i<=MAXCOL; i++)
1106 if (pNextRows[i] >= nMaxRow) // bei gleichen den rechten
1107 {
1108 nMaxRow = pNextRows[i];
1109 nCol = i;
1110 }
1111 nRow = nMaxRow;
1112
1113 if ( nRow < 0 )
1114 {
1115 if (++nWrap >= 2) break; // ungueltigen Wert behalten
1116 nCol = MAXCOL;
1117 nRow = MAXROW;
1118 for (i=0; i<=MAXCOL; i++)
1119 pNextRows[i] = MAXROW; // alles ganz von vorne
1120 }
1121 }
1122 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
1123 }
1124
1125 delete[] pNextRows;
1126 }
1127 }
1128
1129 // ungueltige Werte kommen z.b. bei Tab heraus,
1130 // wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand),
1131 // dann Werte unveraendert lassen
1132
1133 if (VALIDCOLROW(nCol,nRow))
1134 {
1135 rCol = nCol;
1136 rRow = nRow;
1137 }
1138 }
1139
GetNextMarkedCell(SCCOL & rCol,SCROW & rRow,const ScMarkData & rMark)1140 sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark )
1141 {
1142 const ScMarkArray* pMarkArray = rMark.GetArray();
1143 DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray");
1144 if ( !pMarkArray )
1145 return sal_False;
1146
1147 ++rRow; // naechste Zelle ist gesucht
1148
1149 while ( rCol <= MAXCOL )
1150 {
1151 const ScMarkArray& rArray = pMarkArray[rCol];
1152 while ( rRow <= MAXROW )
1153 {
1154 SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, sal_False );
1155 if ( nStart <= MAXROW )
1156 {
1157 SCROW nEnd = rArray.GetMarkEnd( nStart, sal_False );
1158 ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd );
1159 SCROW nCellRow;
1160 ScBaseCell* pCell = NULL;
1161 while ( aColIter.Next( nCellRow, pCell ) )
1162 {
1163 if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE )
1164 {
1165 rRow = nCellRow;
1166 return sal_True; // Zelle gefunden
1167 }
1168 }
1169 rRow = nEnd + 1; // naechsten markierten Bereich suchen
1170 }
1171 else
1172 rRow = MAXROW + 1; // Ende der Spalte
1173 }
1174 rRow = 0;
1175 ++rCol; // naechste Spalte testen
1176 }
1177
1178 return sal_False; // alle Spalten durch
1179 }
1180
UpdateDrawRef(UpdateRefMode eUpdateRefMode,SCCOL nCol1,SCROW nRow1,SCTAB nTab1,SCCOL nCol2,SCROW nRow2,SCTAB nTab2,SCsCOL nDx,SCsROW nDy,SCsTAB nDz,bool bUpdateNoteCaptionPos)1181 void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1182 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1183 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bUpdateNoteCaptionPos )
1184 {
1185 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table
1186 {
1187 InitializeNoteCaptions();
1188 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
1189 if ( eUpdateRefMode != URM_COPY && pDrawLayer )
1190 {
1191 if ( eUpdateRefMode == URM_MOVE )
1192 { // source range
1193 nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx );
1194 nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy );
1195 nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx );
1196 nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy );
1197 }
1198 pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy,
1199 (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos );
1200 }
1201 }
1202 }
1203
UpdateReference(UpdateRefMode eUpdateRefMode,SCCOL nCol1,SCROW nRow1,SCTAB nTab1,SCCOL nCol2,SCROW nRow2,SCTAB nTab2,SCsCOL nDx,SCsROW nDy,SCsTAB nDz,ScDocument * pUndoDoc,sal_Bool bIncludeDraw,bool bUpdateNoteCaptionPos)1204 void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1205 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
1206 ScDocument* pUndoDoc, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos )
1207 {
1208 SCCOL i;
1209 SCCOL iMax;
1210 if ( eUpdateRefMode == URM_COPY )
1211 {
1212 i = nCol1;
1213 iMax = nCol2;
1214 }
1215 else
1216 {
1217 i = 0;
1218 iMax = MAXCOL;
1219 }
1220 for ( ; i<=iMax; i++)
1221 aCol[i].UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
1222 nDx, nDy, nDz, pUndoDoc );
1223
1224 if ( bIncludeDraw )
1225 UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos );
1226
1227 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table
1228 {
1229 SCTAB nSTab = nTab;
1230 SCTAB nETab = nTab;
1231 SCCOL nSCol = 0;
1232 SCROW nSRow = 0;
1233 SCCOL nECol = 0;
1234 SCROW nERow = 0;
1235 sal_Bool bRecalcPages = sal_False;
1236
1237 for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt )
1238 {
1239 nSCol = aIt->aStart.Col();
1240 nSRow = aIt->aStart.Row();
1241 nECol = aIt->aEnd.Col();
1242 nERow = aIt->aEnd.Row();
1243
1244 // do not try to modify sheet index of print range
1245 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1246 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1247 nDx,nDy,0,
1248 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1249 {
1250 *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1251 bRecalcPages = sal_True;
1252 }
1253 }
1254
1255 if ( pRepeatColRange )
1256 {
1257 nSCol = pRepeatColRange->aStart.Col();
1258 nSRow = pRepeatColRange->aStart.Row();
1259 nECol = pRepeatColRange->aEnd.Col();
1260 nERow = pRepeatColRange->aEnd.Row();
1261
1262 // do not try to modify sheet index of repeat range
1263 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1264 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1265 nDx,nDy,0,
1266 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1267 {
1268 *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1269 bRecalcPages = sal_True;
1270 nRepeatStartX = nSCol; // fuer UpdatePageBreaks
1271 nRepeatEndX = nECol;
1272 }
1273 }
1274
1275 if ( pRepeatRowRange )
1276 {
1277 nSCol = pRepeatRowRange->aStart.Col();
1278 nSRow = pRepeatRowRange->aStart.Row();
1279 nECol = pRepeatRowRange->aEnd.Col();
1280 nERow = pRepeatRowRange->aEnd.Row();
1281
1282 // do not try to modify sheet index of repeat range
1283 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1284 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1285 nDx,nDy,0,
1286 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1287 {
1288 *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1289 bRecalcPages = sal_True;
1290 nRepeatStartY = nSRow; // fuer UpdatePageBreaks
1291 nRepeatEndY = nERow;
1292 }
1293 }
1294
1295 // updating print ranges is not necessary with multiple print ranges
1296 if ( bRecalcPages && GetPrintRangeCount() <= 1 )
1297 {
1298 UpdatePageBreaks(NULL);
1299
1300 pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) );
1301 }
1302 }
1303 }
1304
UpdateTranspose(const ScRange & rSource,const ScAddress & rDest,ScDocument * pUndoDoc)1305 void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1306 ScDocument* pUndoDoc )
1307 {
1308 for ( SCCOL i=0; i<=MAXCOL; i++ )
1309 aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc );
1310 }
1311
UpdateGrow(const ScRange & rArea,SCCOL nGrowX,SCROW nGrowY)1312 void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1313 {
1314 for ( SCCOL i=0; i<=MAXCOL; i++ )
1315 aCol[i].UpdateGrow( rArea, nGrowX, nGrowY );
1316 }
1317
UpdateInsertTab(SCTAB nTable)1318 void ScTable::UpdateInsertTab(SCTAB nTable)
1319 {
1320 if (nTab >= nTable) nTab++;
1321 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable);
1322
1323 if (IsStreamValid())
1324 SetStreamValid(sal_False);
1325 }
1326
1327 //UNUSED2008-05 void ScTable::UpdateInsertTabOnlyCells(SCTAB nTable)
1328 //UNUSED2008-05 {
1329 //UNUSED2008-05 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTabOnlyCells(nTable);
1330 //UNUSED2008-05 }
1331
UpdateDeleteTab(SCTAB nTable,sal_Bool bIsMove,ScTable * pRefUndo)1332 void ScTable::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScTable* pRefUndo )
1333 {
1334 if (nTab > nTable) nTab--;
1335
1336 SCCOL i;
1337 if (pRefUndo)
1338 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]);
1339 else
1340 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL);
1341
1342 if (IsStreamValid())
1343 SetStreamValid(sal_False);
1344 }
1345
UpdateMoveTab(SCTAB nOldPos,SCTAB nNewPos,SCTAB nTabNo,ScProgress & rProgress)1346 void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo,
1347 ScProgress& rProgress )
1348 {
1349 nTab = nTabNo;
1350 for ( SCCOL i=0; i <= MAXCOL; i++ )
1351 {
1352 aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo );
1353 rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() );
1354 }
1355
1356 if (IsStreamValid())
1357 SetStreamValid(sal_False);
1358 }
1359
UpdateCompile(sal_Bool bForceIfNameInUse)1360 void ScTable::UpdateCompile( sal_Bool bForceIfNameInUse )
1361 {
1362 for (SCCOL i=0; i <= MAXCOL; i++)
1363 {
1364 aCol[i].UpdateCompile( bForceIfNameInUse );
1365 }
1366 }
1367
SetTabNo(SCTAB nNewTab)1368 void ScTable::SetTabNo(SCTAB nNewTab)
1369 {
1370 nTab = nNewTab;
1371 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab);
1372 }
1373
IsRangeNameInUse(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,sal_uInt16 nIndex) const1374 sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1375 sal_uInt16 nIndex) const
1376 {
1377 sal_Bool bInUse = sal_False;
1378 for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++)
1379 bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex);
1380 return bInUse;
1381 }
1382
FindRangeNamesInUse(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,std::set<sal_uInt16> & rIndexes) const1383 void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1384 std::set<sal_uInt16>& rIndexes) const
1385 {
1386 for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++)
1387 aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes);
1388 }
1389
ReplaceRangeNamesInUse(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,const ScRangeData::IndexMap & rMap)1390 void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1,
1391 SCCOL nCol2, SCROW nRow2,
1392 const ScRangeData::IndexMap& rMap )
1393 {
1394 for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++)
1395 {
1396 aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap );
1397 }
1398 }
1399
ExtendPrintArea(OutputDevice * pDev,SCCOL,SCROW nStartRow,SCCOL & rEndCol,SCROW nEndRow)1400 void ScTable::ExtendPrintArea( OutputDevice* pDev,
1401 SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
1402 {
1403 if ( !pColFlags || !pRowFlags )
1404 {
1405 DBG_ERROR("keine ColInfo oder RowInfo in ExtendPrintArea");
1406 return;
1407 }
1408
1409 Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
1410 double nPPTX = aPix1000.X() / 1000.0;
1411 double nPPTY = aPix1000.Y() / 1000.0;
1412
1413 // First, mark those columns that we need to skip i.e. hidden and empty columns.
1414
1415 ScFlatBoolColSegments aSkipCols;
1416 aSkipCols.setInsertFromBack(true); // speed optimazation.
1417 aSkipCols.setFalse(0, MAXCOL);
1418 for (SCCOL i = 0; i <= MAXCOL; ++i)
1419 {
1420 SCCOL nLastCol = i;
1421 if (ColHidden(i, NULL, &nLastCol))
1422 {
1423 // Columns are hidden in this range.
1424 aSkipCols.setTrue(i, nLastCol);
1425 }
1426 else
1427 {
1428 // These columns are visible. Check for empty columns.
1429 for (SCCOL j = i; j <= nLastCol; ++j)
1430 {
1431 if (aCol[j].GetCellCount() == 0)
1432 // empty
1433 aSkipCols.setTrue(j,j);
1434 }
1435 }
1436 i = nLastCol;
1437 }
1438
1439 ScFlatBoolColSegments::RangeData aColData;
1440 for (SCCOL nCol = rEndCol; nCol >= 0; --nCol)
1441 {
1442 if (!aSkipCols.getRangeData(nCol, aColData))
1443 // Failed to get the data. This should never happen!
1444 return;
1445
1446 if (aColData.mbValue)
1447 {
1448 // Skip these columns.
1449 nCol = aColData.mnCol1; // move toward 0.
1450 continue;
1451 }
1452
1453 // These are visible and non-empty columns.
1454 for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol)
1455 {
1456 SCCOL nPrintCol = nDataCol;
1457 VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]);
1458 ScBaseCell* pCell = aIter.reset(nStartRow);
1459 if (!pCell)
1460 // No visible cells found in this column. Skip it.
1461 continue;
1462
1463 while (pCell)
1464 {
1465 SCCOL nNewCol = nDataCol;
1466 SCROW nRow = aIter.getRow();
1467 if (nRow > nEndRow)
1468 // Went past the last row position. Bail out.
1469 break;
1470
1471 MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY);
1472 if (nNewCol > nPrintCol)
1473 nPrintCol = nNewCol;
1474 pCell = aIter.next();
1475 }
1476
1477 if (nPrintCol > rEndCol)
1478 // Make sure we don't shrink the print area.
1479 rEndCol = nPrintCol;
1480 }
1481 nCol = aColData.mnCol1; // move toward 0.
1482 }
1483 }
1484
MaybeAddExtraColumn(SCCOL & rCol,SCROW nRow,OutputDevice * pDev,double nPPTX,double nPPTY)1485 void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY)
1486 {
1487 ScBaseCell* pCell = aCol[rCol].GetCell(nRow);
1488 if (!pCell || !pCell->HasStringData())
1489 return;
1490
1491 bool bFormula = false; //! ueberge
1492 long nPixel = pCell->GetTextWidth();
1493
1494 // Breite bereits im Idle-Handler berechnet?
1495 if ( TEXTWIDTH_DIRTY == nPixel )
1496 {
1497 ScNeededSizeOptions aOptions;
1498 aOptions.bTotalSize = sal_True;
1499 aOptions.bFormula = bFormula;
1500 aOptions.bSkipMerged = sal_False;
1501
1502 Fraction aZoom(1,1);
1503 nPixel = aCol[rCol].GetNeededSize(
1504 nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions );
1505 pCell->SetTextWidth( (sal_uInt16)nPixel );
1506 }
1507
1508 long nTwips = (long) (nPixel / nPPTX);
1509 long nDocW = GetColWidth( rCol );
1510
1511 long nMissing = nTwips - nDocW;
1512 if ( nMissing > 0 )
1513 {
1514 // look at alignment
1515
1516 const ScPatternAttr* pPattern = GetPattern( rCol, nRow );
1517 const SfxItemSet* pCondSet = NULL;
1518 if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
1519 pCondSet = pDocument->GetCondResult( rCol, nRow, nTab );
1520
1521 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
1522 pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
1523 if ( eHorJust == SVX_HOR_JUSTIFY_CENTER )
1524 nMissing /= 2; // distributed into both directions
1525 else
1526 {
1527 // STANDARD is LEFT (only text is handled here)
1528 bool bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT );
1529 if ( IsLayoutRTL() )
1530 bRight = !bRight;
1531 if ( bRight )
1532 nMissing = 0; // extended only to the left (logical)
1533 }
1534 }
1535
1536 SCCOL nNewCol = rCol;
1537 while (nMissing > 0 && nNewCol < MAXCOL)
1538 {
1539 ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow);
1540 if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE)
1541 // Cell content in a next column ends display of this string.
1542 nMissing = 0;
1543 else
1544 nMissing -= GetColWidth(++nNewCol);
1545 }
1546 rCol = nNewCol;
1547 }
1548
DoColResize(SCCOL nCol1,SCCOL nCol2,SCSIZE nAdd)1549 void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
1550 {
1551 for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
1552 aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd);
1553 }
1554
1555 #define SET_PRINTRANGE( p1, p2 ) \
1556 if ( (p2) ) \
1557 { \
1558 if ( (p1) ) \
1559 *(p1) = *(p2); \
1560 else \
1561 (p1) = new ScRange( *(p2) ); \
1562 } \
1563 else \
1564 DELETEZ( (p1) )
1565
SetRepeatColRange(const ScRange * pNew)1566 void ScTable::SetRepeatColRange( const ScRange* pNew )
1567 {
1568 SET_PRINTRANGE( pRepeatColRange, pNew );
1569
1570 if (IsStreamValid())
1571 SetStreamValid(sal_False);
1572 }
1573
SetRepeatRowRange(const ScRange * pNew)1574 void ScTable::SetRepeatRowRange( const ScRange* pNew )
1575 {
1576 SET_PRINTRANGE( pRepeatRowRange, pNew );
1577
1578 if (IsStreamValid())
1579 SetStreamValid(sal_False);
1580 }
1581
ClearPrintRanges()1582 void ScTable::ClearPrintRanges()
1583 {
1584 aPrintRanges.clear();
1585 bPrintEntireSheet = sal_False;
1586 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
1587
1588 if (IsStreamValid())
1589 SetStreamValid(sal_False);
1590 }
1591
AddPrintRange(const ScRange & rNew)1592 void ScTable::AddPrintRange( const ScRange& rNew )
1593 {
1594 bPrintEntireSheet = sal_False;
1595 if( aPrintRanges.size() < 0xFFFF )
1596 aPrintRanges.push_back( rNew );
1597
1598 if (IsStreamValid())
1599 SetStreamValid(sal_False);
1600 }
1601
1602 //UNUSED2009-05 void ScTable::SetPrintRange( const ScRange& rNew )
1603 //UNUSED2009-05 {
1604 //UNUSED2009-05 ClearPrintRanges();
1605 //UNUSED2009-05 AddPrintRange( rNew );
1606 //UNUSED2009-05 }
1607
SetPrintEntireSheet()1608 void ScTable::SetPrintEntireSheet()
1609 {
1610 if( !IsPrintEntireSheet() )
1611 {
1612 ClearPrintRanges();
1613 bPrintEntireSheet = sal_True;
1614 }
1615 }
1616
GetPrintRange(sal_uInt16 nPos) const1617 const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const
1618 {
1619 return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL;
1620 }
1621
FillPrintSaver(ScPrintSaverTab & rSaveTab) const1622 void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const
1623 {
1624 rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet );
1625 rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange );
1626 }
1627
RestorePrintRanges(const ScPrintSaverTab & rSaveTab)1628 void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab )
1629 {
1630 aPrintRanges = rSaveTab.GetPrintRanges();
1631 bPrintEntireSheet = rSaveTab.IsEntireSheet();
1632 SetRepeatColRange( rSaveTab.GetRepeatCol() );
1633 SetRepeatRowRange( rSaveTab.GetRepeatRow() );
1634
1635 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
1636 UpdatePageBreaks(NULL);
1637 }
1638
1639 SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1;
1640
VisibleDataCellIterator(ScFlatBoolRowSegments & rRowSegs,ScColumn & rColumn)1641 ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) :
1642 mrRowSegs(rRowSegs),
1643 mrColumn(rColumn),
1644 mpCell(NULL),
1645 mnCurRow(ROW_NOT_FOUND),
1646 mnUBound(ROW_NOT_FOUND)
1647 {
1648 }
1649
~VisibleDataCellIterator()1650 ScTable::VisibleDataCellIterator::~VisibleDataCellIterator()
1651 {
1652 }
1653
reset(SCROW nRow)1654 ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow)
1655 {
1656 if (nRow > MAXROW)
1657 {
1658 mnCurRow = ROW_NOT_FOUND;
1659 return NULL;
1660 }
1661
1662 ScFlatBoolRowSegments::RangeData aData;
1663 if (!mrRowSegs.getRangeData(nRow, aData))
1664 {
1665 mnCurRow = ROW_NOT_FOUND;
1666 return NULL;
1667 }
1668
1669 if (!aData.mbValue)
1670 {
1671 // specified row is visible. Take it.
1672 mnCurRow = nRow;
1673 mnUBound = aData.mnRow2;
1674 }
1675 else
1676 {
1677 // specified row is not-visible. The first visible row is the start of
1678 // the next segment.
1679 mnCurRow = aData.mnRow2 + 1;
1680 mnUBound = mnCurRow; // get range data on the next iteration.
1681 if (mnCurRow > MAXROW)
1682 {
1683 // Make sure the row doesn't exceed our current limit.
1684 mnCurRow = ROW_NOT_FOUND;
1685 return NULL;
1686 }
1687 }
1688
1689 mpCell = mrColumn.GetCell(mnCurRow);
1690 if (mpCell)
1691 // First visible cell found.
1692 return mpCell;
1693
1694 // Find a first visible cell below this row (if any).
1695 return next();
1696 }
1697
next()1698 ScBaseCell* ScTable::VisibleDataCellIterator::next()
1699 {
1700 if (mnCurRow == ROW_NOT_FOUND)
1701 return NULL;
1702
1703 while (mrColumn.GetNextDataPos(mnCurRow))
1704 {
1705 if (mnCurRow > mnUBound)
1706 {
1707 // We don't know the visibility of this row range. Query it.
1708 ScFlatBoolRowSegments::RangeData aData;
1709 if (!mrRowSegs.getRangeData(mnCurRow, aData))
1710 {
1711 mnCurRow = ROW_NOT_FOUND;
1712 return NULL;
1713 }
1714
1715 if (aData.mbValue)
1716 {
1717 // This row is invisible. Skip to the last invisible row and
1718 // try again.
1719 mnCurRow = mnUBound = aData.mnRow2;
1720 continue;
1721 }
1722
1723 // This row is visible.
1724 mnUBound = aData.mnRow2;
1725 }
1726
1727 mpCell = mrColumn.GetCell(mnCurRow);
1728 if (mpCell)
1729 return mpCell;
1730 }
1731 mnCurRow = ROW_NOT_FOUND;
1732 return NULL;
1733 }
1734
getRow() const1735 SCROW ScTable::VisibleDataCellIterator::getRow() const
1736 {
1737 return mnCurRow;
1738 }
1739
1740