Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / tool / refupdat.cxx
blob62a661aa1a97fbdab5c361502c67cf48bc82c3d6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <refupdat.hxx>
21 #include <document.hxx>
22 #include <bigrange.hxx>
23 #include <refdata.hxx>
25 #include <osl/diagnose.h>
27 template< typename R, typename S, typename U >
28 static bool lcl_MoveStart( R& rRef, U nStart, S nDelta, U nMask, bool bShrink = true )
30 bool bCut = false;
31 if ( rRef >= nStart )
32 rRef = sal::static_int_cast<R>( rRef + nDelta );
33 else if ( nDelta < 0 && bShrink && rRef >= nStart + nDelta )
34 rRef = nStart + nDelta; //TODO: limit ???
35 if ( rRef < 0 )
37 rRef = 0;
38 bCut = true;
40 else if ( rRef > nMask )
42 rRef = nMask;
43 bCut = true;
45 return bCut;
48 template< typename R, typename S, typename U >
49 static bool lcl_MoveEnd( R& rRef, U nStart, S nDelta, U nMask, bool bShrink = true )
51 bool bCut = false;
52 if ( rRef >= nStart )
53 rRef = sal::static_int_cast<R>( rRef + nDelta );
54 else if ( nDelta < 0 && bShrink && rRef >= nStart + nDelta )
55 rRef = nStart + nDelta - 1; //TODO: limit ???
56 if (rRef < 0)
58 rRef = 0;
59 bCut = true;
61 else if(rRef > nMask)
63 rRef = nMask;
64 bCut = true;
66 return bCut;
69 template< typename R, typename S, typename U >
70 static bool lcl_MoveReorder( R& rRef, U nStart, U nEnd, S nDelta )
72 if ( rRef >= nStart && rRef <= nEnd )
74 rRef = sal::static_int_cast<R>( rRef + nDelta );
75 return true;
78 if ( nDelta > 0 ) // move backward
80 if ( rRef >= nStart && rRef <= nEnd + nDelta )
82 if ( rRef <= nEnd )
83 rRef = sal::static_int_cast<R>( rRef + nDelta ); // in the moved range
84 else
85 rRef -= nEnd - nStart + 1; // move up
86 return true;
89 else // move forward
91 if ( rRef >= nStart + nDelta && rRef <= nEnd )
93 if ( rRef >= nStart )
94 rRef = sal::static_int_cast<R>( rRef + nDelta ); // in the moved range
95 else
96 rRef += nEnd - nStart + 1; // move up
97 return true;
101 return false;
104 template< typename R, typename S, typename U >
105 static bool lcl_MoveItCut( R& rRef, S nDelta, U nMask )
107 bool bCut = false;
108 rRef = sal::static_int_cast<R>( rRef + nDelta );
109 if ( rRef < 0 )
111 rRef = 0;
112 bCut = true;
114 else if ( rRef > nMask )
116 rRef = nMask;
117 bCut = true;
119 return bCut;
122 template< typename R, typename U >
123 static void lcl_MoveItWrap( R& rRef, U nMask )
125 rRef = sal::static_int_cast<R>( rRef );
126 if ( rRef < 0 )
127 rRef += nMask+1;
128 else if ( rRef > nMask )
129 rRef -= nMask+1;
132 template< typename R, typename S, typename U >
133 static bool IsExpand( R n1, R n2, U nStart, S nD )
134 { // before normal Move...
135 return
136 nD > 0 // Insert
137 && n1 < n2 // at least two Cols/Rows/Tabs in Ref
138 && (
139 (nStart <= n1 && n1 < nStart + nD) // n1 within the Insert
140 || (n2 + 1 == nStart) // n2 directly before Insert
141 ); // n1 < nStart <= n2 is expanded anyway!
144 template< typename R, typename S, typename U >
145 static void Expand( R& n1, R& n2, U nStart, S nD )
146 { // after normal Move..., only if IsExpand was true before!
147 // first the End
148 if ( n2 + 1 == nStart )
149 { // at End
150 n2 = sal::static_int_cast<R>( n2 + nD );
151 return;
153 // at the beginning
154 n1 = sal::static_int_cast<R>( n1 - nD );
157 static bool lcl_IsWrapBig( sal_Int64 nRef, sal_Int32 nDelta )
159 if (nDelta > 0)
160 return nRef > std::numeric_limits<sal_Int64>::max() - nDelta;
161 else
162 return nRef < std::numeric_limits<sal_Int64>::min() - nDelta;
165 static bool lcl_MoveBig( sal_Int64& rRef, sal_Int64 nStart, sal_Int32 nDelta )
167 bool bCut = false;
168 if ( rRef >= nStart )
170 if ( nDelta > 0 )
171 bCut = lcl_IsWrapBig( rRef, nDelta );
172 if ( bCut )
173 rRef = ScBigRange::nRangeMax;
174 else
175 rRef += nDelta;
177 return bCut;
180 static bool lcl_MoveItCutBig( sal_Int64& rRef, sal_Int32 nDelta )
182 bool bCut = lcl_IsWrapBig( rRef, nDelta );
183 rRef += nDelta;
184 return bCut;
187 ScRefUpdateRes ScRefUpdate::Update( const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
188 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
189 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
190 SCCOL nDx, SCROW nDy, SCTAB nDz,
191 SCCOL& theCol1, SCROW& theRow1, SCTAB& theTab1,
192 SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2 )
194 ScRefUpdateRes eRet = UR_NOTHING;
196 SCCOL oldCol1 = theCol1;
197 SCROW oldRow1 = theRow1;
198 SCTAB oldTab1 = theTab1;
199 SCCOL oldCol2 = theCol2;
200 SCROW oldRow2 = theRow2;
201 SCTAB oldTab2 = theTab2;
203 bool bCut1, bCut2;
205 if (eUpdateRefMode == URM_INSDEL)
207 bool bExpand = pDoc->IsExpandRefs();
208 if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
209 (theTab1 >= nTab1) && (theTab2 <= nTab2))
211 bool bExp = (bExpand && IsExpand( theCol1, theCol2, nCol1, nDx ));
212 bCut1 = lcl_MoveStart( theCol1, nCol1, nDx, pDoc->MaxCol() );
213 bCut2 = lcl_MoveEnd( theCol2, nCol1, nDx, pDoc->MaxCol() );
214 if ( theCol2 < theCol1 )
216 eRet = UR_INVALID;
217 theCol2 = theCol1;
219 else if (bCut2 && theCol2 == 0)
220 eRet = UR_INVALID;
221 else if ( bCut1 || bCut2 )
222 eRet = UR_UPDATED;
223 if ( bExp )
225 Expand( theCol1, theCol2, nCol1, nDx );
226 eRet = UR_UPDATED;
228 if (eRet != UR_NOTHING && oldCol1 == 0 && oldCol2 == pDoc->MaxCol())
230 eRet = UR_STICKY;
231 theCol1 = oldCol1;
232 theCol2 = oldCol2;
234 else if (oldCol2 == pDoc->MaxCol() && oldCol1 < pDoc->MaxCol())
236 // End was sticky, but start may have been moved. Only on range.
237 theCol2 = oldCol2;
238 if (eRet == UR_NOTHING)
239 eRet = UR_STICKY;
241 // Else, if (bCut2 && theCol2 == pDoc->MaxCol()) then end becomes sticky,
242 // but currently there's nothing to do.
244 if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
245 (theTab1 >= nTab1) && (theTab2 <= nTab2))
247 bool bExp = (bExpand && IsExpand( theRow1, theRow2, nRow1, nDy ));
248 bCut1 = lcl_MoveStart( theRow1, nRow1, nDy, pDoc->MaxRow() );
249 bCut2 = lcl_MoveEnd( theRow2, nRow1, nDy, pDoc->MaxRow() );
250 if ( theRow2 < theRow1 )
252 eRet = UR_INVALID;
253 theRow2 = theRow1;
255 else if (bCut2 && theRow2 == 0)
256 eRet = UR_INVALID;
257 else if ( bCut1 || bCut2 )
258 eRet = UR_UPDATED;
259 if ( bExp )
261 Expand( theRow1, theRow2, nRow1, nDy );
262 eRet = UR_UPDATED;
264 if (eRet != UR_NOTHING && oldRow1 == 0 && oldRow2 == pDoc->MaxRow())
266 eRet = UR_STICKY;
267 theRow1 = oldRow1;
268 theRow2 = oldRow2;
270 else if (oldRow2 == pDoc->MaxRow() && oldRow1 < pDoc->MaxRow())
272 // End was sticky, but start may have been moved. Only on range.
273 theRow2 = oldRow2;
274 if (eRet == UR_NOTHING)
275 eRet = UR_STICKY;
277 // Else, if (bCut2 && theRow2 == pDoc->MaxRow()) then end becomes sticky,
278 // but currently there's nothing to do.
280 if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
281 (theRow1 >= nRow1) && (theRow2 <= nRow2) )
283 SCTAB nMaxTab = pDoc->GetTableCount() - 1;
284 nMaxTab = sal::static_int_cast<SCTAB>(nMaxTab + nDz); // adjust to new count
285 bool bExp = (bExpand && IsExpand( theTab1, theTab2, nTab1, nDz ));
286 bCut1 = lcl_MoveStart( theTab1, nTab1, nDz, nMaxTab, false /*bShrink*/);
287 bCut2 = lcl_MoveEnd( theTab2, nTab1, nDz, nMaxTab, false /*bShrink*/);
288 if ( theTab2 < theTab1 )
290 eRet = UR_INVALID;
291 theTab2 = theTab1;
293 else if ( bCut1 || bCut2 )
294 eRet = UR_UPDATED;
295 if ( bExp )
297 Expand( theTab1, theTab2, nTab1, nDz );
298 eRet = UR_UPDATED;
302 else if (eUpdateRefMode == URM_MOVE)
304 if ((theCol1 >= nCol1-nDx) && (theRow1 >= nRow1-nDy) && (theTab1 >= nTab1-nDz) &&
305 (theCol2 <= nCol2-nDx) && (theRow2 <= nRow2-nDy) && (theTab2 <= nTab2-nDz))
307 if ( nDx )
309 bCut1 = lcl_MoveItCut( theCol1, nDx, pDoc->MaxCol() );
310 bCut2 = lcl_MoveItCut( theCol2, nDx, pDoc->MaxCol() );
311 if ( bCut1 || bCut2 )
312 eRet = UR_UPDATED;
313 if (eRet != UR_NOTHING && oldCol1 == 0 && oldCol2 == pDoc->MaxCol())
315 eRet = UR_STICKY;
316 theCol1 = oldCol1;
317 theCol2 = oldCol2;
320 if ( nDy )
322 bCut1 = lcl_MoveItCut( theRow1, nDy, pDoc->MaxRow() );
323 bCut2 = lcl_MoveItCut( theRow2, nDy, pDoc->MaxRow() );
324 if ( bCut1 || bCut2 )
325 eRet = UR_UPDATED;
326 if (eRet != UR_NOTHING && oldRow1 == 0 && oldRow2 == pDoc->MaxRow())
328 eRet = UR_STICKY;
329 theRow1 = oldRow1;
330 theRow2 = oldRow2;
333 if ( nDz )
335 SCTAB nMaxTab = pDoc->GetTableCount() - 1;
336 bCut1 = lcl_MoveItCut( theTab1, nDz, nMaxTab );
337 bCut2 = lcl_MoveItCut( theTab2, nDz, nMaxTab );
338 if ( bCut1 || bCut2 )
339 eRet = UR_UPDATED;
343 else if (eUpdateRefMode == URM_REORDER)
345 // so far only for nDz (MoveTab)
346 OSL_ENSURE ( !nDx && !nDy, "URM_REORDER for x and y not yet implemented" );
348 if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
349 (theRow1 >= nRow1) && (theRow2 <= nRow2) )
351 bCut1 = lcl_MoveReorder( theTab1, nTab1, nTab2, nDz );
352 bCut2 = lcl_MoveReorder( theTab2, nTab1, nTab2, nDz );
353 if ( bCut1 || bCut2 )
354 eRet = UR_UPDATED;
358 if ( eRet == UR_NOTHING )
360 if (oldCol1 != theCol1
361 || oldRow1 != theRow1
362 || oldTab1 != theTab1
363 || oldCol2 != theCol2
364 || oldRow2 != theRow2
365 || oldTab2 != theTab2
367 eRet = UR_UPDATED;
369 return eRet;
372 // simple UpdateReference for ScBigRange (ScChangeAction/ScChangeTrack)
373 // References can also be located outside of the document!
374 // Whole columns/rows (ScBigRange::nRangeMin..ScBigRange::nRangeMax) stay as such!
375 ScRefUpdateRes ScRefUpdate::Update( UpdateRefMode eUpdateRefMode,
376 const ScBigRange& rWhere, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz,
377 ScBigRange& rWhat )
379 ScRefUpdateRes eRet = UR_NOTHING;
380 const ScBigRange aOldRange( rWhat );
382 sal_Int64 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2;
383 sal_Int64 theCol1, theRow1, theTab1, theCol2, theRow2, theTab2;
384 rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
385 rWhat.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
387 bool bCut1, bCut2;
389 if (eUpdateRefMode == URM_INSDEL)
391 if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
392 (theTab1 >= nTab1) && (theTab2 <= nTab2) &&
393 (theCol1 != ScBigRange::nRangeMin || theCol2 != ScBigRange::nRangeMax) )
395 bCut1 = lcl_MoveBig( theCol1, nCol1, nDx );
396 bCut2 = lcl_MoveBig( theCol2, nCol1, nDx );
397 if ( bCut1 || bCut2 )
398 eRet = UR_UPDATED;
399 rWhat.aStart.SetCol( theCol1 );
400 rWhat.aEnd.SetCol( theCol2 );
402 if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
403 (theTab1 >= nTab1) && (theTab2 <= nTab2) &&
404 (theRow1 != ScBigRange::nRangeMin || theRow2 != ScBigRange::nRangeMax) )
406 bCut1 = lcl_MoveBig( theRow1, nRow1, nDy );
407 bCut2 = lcl_MoveBig( theRow2, nRow1, nDy );
408 if ( bCut1 || bCut2 )
409 eRet = UR_UPDATED;
410 rWhat.aStart.SetRow( theRow1 );
411 rWhat.aEnd.SetRow( theRow2 );
413 if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
414 (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
415 (theTab1 != ScBigRange::nRangeMin || theTab2 != ScBigRange::nRangeMax) )
417 bCut1 = lcl_MoveBig( theTab1, nTab1, nDz );
418 bCut2 = lcl_MoveBig( theTab2, nTab1, nDz );
419 if ( bCut1 || bCut2 )
420 eRet = UR_UPDATED;
421 rWhat.aStart.SetTab( theTab1 );
422 rWhat.aEnd.SetTab( theTab2 );
425 else if (eUpdateRefMode == URM_MOVE)
427 if ( rWhere.Contains( rWhat ) )
429 if ( nDx && (theCol1 != ScBigRange::nRangeMin || theCol2 != ScBigRange::nRangeMax) )
431 bCut1 = lcl_MoveItCutBig( theCol1, nDx );
432 bCut2 = lcl_MoveItCutBig( theCol2, nDx );
433 if ( bCut1 || bCut2 )
434 eRet = UR_UPDATED;
435 rWhat.aStart.SetCol( theCol1 );
436 rWhat.aEnd.SetCol( theCol2 );
438 if ( nDy && (theRow1 != ScBigRange::nRangeMin || theRow2 != ScBigRange::nRangeMax) )
440 bCut1 = lcl_MoveItCutBig( theRow1, nDy );
441 bCut2 = lcl_MoveItCutBig( theRow2, nDy );
442 if ( bCut1 || bCut2 )
443 eRet = UR_UPDATED;
444 rWhat.aStart.SetRow( theRow1 );
445 rWhat.aEnd.SetRow( theRow2 );
447 if ( nDz && (theTab1 != ScBigRange::nRangeMin || theTab2 != ScBigRange::nRangeMax) )
449 bCut1 = lcl_MoveItCutBig( theTab1, nDz );
450 bCut2 = lcl_MoveItCutBig( theTab2, nDz );
451 if ( bCut1 || bCut2 )
452 eRet = UR_UPDATED;
453 rWhat.aStart.SetTab( theTab1 );
454 rWhat.aEnd.SetTab( theTab2 );
459 if ( eRet == UR_NOTHING && rWhat != aOldRange )
460 eRet = UR_UPDATED;
462 return eRet;
465 void ScRefUpdate::MoveRelWrap( const ScDocument& rDoc, const ScAddress& rPos,
466 SCCOL nMaxCol, SCROW nMaxRow, ScComplexRefData& rRef )
468 ScRange aAbsRange = rRef.toAbs(rDoc, rPos);
469 if( rRef.Ref1.IsColRel() )
471 SCCOL nCol = aAbsRange.aStart.Col();
472 lcl_MoveItWrap(nCol, nMaxCol);
473 aAbsRange.aStart.SetCol(nCol);
475 if( rRef.Ref2.IsColRel() )
477 SCCOL nCol = aAbsRange.aEnd.Col();
478 lcl_MoveItWrap(nCol, nMaxCol);
479 aAbsRange.aEnd.SetCol(nCol);
481 if( rRef.Ref1.IsRowRel() )
483 SCROW nRow = aAbsRange.aStart.Row();
484 lcl_MoveItWrap(nRow, nMaxRow);
485 aAbsRange.aStart.SetRow(nRow);
487 if( rRef.Ref2.IsRowRel() )
489 SCROW nRow = aAbsRange.aEnd.Row();
490 lcl_MoveItWrap(nRow, nMaxRow);
491 aAbsRange.aEnd.SetRow(nRow);
493 SCTAB nMaxTab = rDoc.GetTableCount() - 1;
494 if( rRef.Ref1.IsTabRel() )
496 SCTAB nTab = aAbsRange.aStart.Tab();
497 lcl_MoveItWrap(nTab, nMaxTab);
498 aAbsRange.aStart.SetTab(nTab);
500 if( rRef.Ref2.IsTabRel() )
502 SCTAB nTab = aAbsRange.aEnd.Tab();
503 lcl_MoveItWrap(nTab, nMaxTab);
504 aAbsRange.aEnd.SetTab(nTab);
507 aAbsRange.PutInOrder();
508 rRef.SetRange(rDoc.GetSheetLimits(), aAbsRange, rPos);
511 void ScRefUpdate::DoTranspose( SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
512 const ScDocument& rDoc, const ScRange& rSource, const ScAddress& rDest )
514 SCTAB nDz = rDest.Tab() - rSource.aStart.Tab();
515 if (nDz)
517 SCTAB nNewTab = rTab+nDz;
518 SCTAB nCount = rDoc.GetTableCount();
519 while (nNewTab<0) nNewTab = sal::static_int_cast<SCTAB>( nNewTab + nCount );
520 while (nNewTab>=nCount) nNewTab = sal::static_int_cast<SCTAB>( nNewTab - nCount );
521 rTab = nNewTab;
523 OSL_ENSURE( rCol>=rSource.aStart.Col() && rRow>=rSource.aStart.Row(),
524 "UpdateTranspose: pos. wrong" );
526 SCCOL nRelX = rCol - rSource.aStart.Col();
527 SCROW nRelY = rRow - rSource.aStart.Row();
529 rCol = static_cast<SCCOL>(static_cast<SCCOLROW>(rDest.Col()) +
530 static_cast<SCCOLROW>(nRelY));
531 rRow = static_cast<SCROW>(static_cast<SCCOLROW>(rDest.Row()) +
532 static_cast<SCCOLROW>(nRelX));
535 ScRefUpdateRes ScRefUpdate::UpdateTranspose(
536 const ScDocument& rDoc, const ScRange& rSource, const ScAddress& rDest, ScRange& rRef )
538 ScRefUpdateRes eRet = UR_NOTHING;
539 // Only references in source range must be updated, i.e. no references in destination area.
540 // Otherwise existing references pointing to destination area will be wrongly transposed.
541 if (rSource.Contains(rRef))
543 // Source range contains the reference range.
544 SCCOL nCol1 = rRef.aStart.Col(), nCol2 = rRef.aEnd.Col();
545 SCROW nRow1 = rRef.aStart.Row(), nRow2 = rRef.aEnd.Row();
546 SCTAB nTab1 = rRef.aStart.Tab(), nTab2 = rRef.aEnd.Tab();
547 DoTranspose(nCol1, nRow1, nTab1, rDoc, rSource, rDest);
548 DoTranspose(nCol2, nRow2, nTab2, rDoc, rSource, rDest);
549 rRef.aStart = ScAddress(nCol1, nRow1, nTab1);
550 rRef.aEnd = ScAddress(nCol2, nRow2, nTab2);
551 eRet = UR_UPDATED;
553 return eRet;
556 // UpdateGrow - expands references which point exactly to the area
557 // gets by without document
559 ScRefUpdateRes ScRefUpdate::UpdateGrow(
560 const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY, ScRange& rRef )
562 ScRefUpdateRes eRet = UR_NOTHING;
564 // in y-direction the Ref may also start one row further below,
565 // if an area contains column heads
567 bool bUpdateX = ( nGrowX &&
568 rRef.aStart.Col() == rArea.aStart.Col() && rRef.aEnd.Col() == rArea.aEnd.Col() &&
569 rRef.aStart.Row() >= rArea.aStart.Row() && rRef.aEnd.Row() <= rArea.aEnd.Row() &&
570 rRef.aStart.Tab() >= rArea.aStart.Tab() && rRef.aEnd.Tab() <= rArea.aEnd.Tab() );
571 bool bUpdateY = ( nGrowY &&
572 rRef.aStart.Col() >= rArea.aStart.Col() && rRef.aEnd.Col() <= rArea.aEnd.Col() &&
573 (rRef.aStart.Row() == rArea.aStart.Row() || rRef.aStart.Row() == rArea.aStart.Row()+1) &&
574 rRef.aEnd.Row() == rArea.aEnd.Row() &&
575 rRef.aStart.Tab() >= rArea.aStart.Tab() && rRef.aEnd.Tab() <= rArea.aEnd.Tab() );
577 if ( bUpdateX )
579 rRef.aEnd.SetCol(sal::static_int_cast<SCCOL>(rRef.aEnd.Col() + nGrowX));
580 eRet = UR_UPDATED;
582 if ( bUpdateY )
584 rRef.aEnd.SetRow(sal::static_int_cast<SCROW>(rRef.aEnd.Row() + nGrowY));
585 eRet = UR_UPDATED;
588 return eRet;
591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */