1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 )
32 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
33 else if ( nDelta
< 0 && bShrink
&& rRef
>= nStart
+ nDelta
)
34 rRef
= nStart
+ nDelta
; //TODO: limit ???
40 else if ( rRef
> nMask
)
48 template< typename R
, typename S
, typename U
>
49 static bool lcl_MoveEnd( R
& rRef
, U nStart
, S nDelta
, U nMask
, bool bShrink
= true )
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 ???
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
);
78 if ( nDelta
> 0 ) // move backward
80 if ( rRef
>= nStart
&& rRef
<= nEnd
+ nDelta
)
83 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
85 rRef
-= nEnd
- nStart
+ 1; // move up
91 if ( rRef
>= nStart
+ nDelta
&& rRef
<= nEnd
)
94 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
96 rRef
+= nEnd
- nStart
+ 1; // move up
104 template< typename R
, typename S
, typename U
>
105 static bool lcl_MoveItCut( R
& rRef
, S nDelta
, U nMask
)
108 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
114 else if ( rRef
> nMask
)
122 template< typename R
, typename U
>
123 static void lcl_MoveItWrap( R
& rRef
, U nMask
)
125 rRef
= sal::static_int_cast
<R
>( rRef
);
128 else if ( rRef
> nMask
)
132 template< typename R
, typename S
, typename U
>
133 static bool IsExpand( R n1
, R n2
, U nStart
, S nD
)
134 { // before normal Move...
137 && n1
< n2
// at least two Cols/Rows/Tabs in Ref
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!
148 if ( n2
+ 1 == nStart
)
150 n2
= sal::static_int_cast
<R
>( n2
+ nD
);
154 n1
= sal::static_int_cast
<R
>( n1
- nD
);
157 static bool lcl_IsWrapBig( sal_Int64 nRef
, sal_Int32 nDelta
)
160 return nRef
> std::numeric_limits
<sal_Int64
>::max() - nDelta
;
162 return nRef
< std::numeric_limits
<sal_Int64
>::min() - nDelta
;
165 static bool lcl_MoveBig( sal_Int64
& rRef
, sal_Int64 nStart
, sal_Int32 nDelta
)
168 if ( rRef
>= nStart
)
171 bCut
= lcl_IsWrapBig( rRef
, nDelta
);
173 rRef
= ScBigRange::nRangeMax
;
180 static bool lcl_MoveItCutBig( sal_Int64
& rRef
, sal_Int32 nDelta
)
182 bool bCut
= lcl_IsWrapBig( rRef
, nDelta
);
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
;
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
)
219 else if (bCut2
&& theCol2
== 0)
221 else if ( bCut1
|| bCut2
)
225 Expand( theCol1
, theCol2
, nCol1
, nDx
);
228 if (eRet
!= UR_NOTHING
&& oldCol1
== 0 && oldCol2
== pDoc
->MaxCol())
234 else if (oldCol2
== pDoc
->MaxCol() && oldCol1
< pDoc
->MaxCol())
236 // End was sticky, but start may have been moved. Only on range.
238 if (eRet
== UR_NOTHING
)
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
)
255 else if (bCut2
&& theRow2
== 0)
257 else if ( bCut1
|| bCut2
)
261 Expand( theRow1
, theRow2
, nRow1
, nDy
);
264 if (eRet
!= UR_NOTHING
&& oldRow1
== 0 && oldRow2
== pDoc
->MaxRow())
270 else if (oldRow2
== pDoc
->MaxRow() && oldRow1
< pDoc
->MaxRow())
272 // End was sticky, but start may have been moved. Only on range.
274 if (eRet
== UR_NOTHING
)
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
)
293 else if ( bCut1
|| bCut2
)
297 Expand( theTab1
, theTab2
, nTab1
, nDz
);
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
))
309 bCut1
= lcl_MoveItCut( theCol1
, nDx
, pDoc
->MaxCol() );
310 bCut2
= lcl_MoveItCut( theCol2
, nDx
, pDoc
->MaxCol() );
311 if ( bCut1
|| bCut2
)
313 if (eRet
!= UR_NOTHING
&& oldCol1
== 0 && oldCol2
== pDoc
->MaxCol())
322 bCut1
= lcl_MoveItCut( theRow1
, nDy
, pDoc
->MaxRow() );
323 bCut2
= lcl_MoveItCut( theRow2
, nDy
, pDoc
->MaxRow() );
324 if ( bCut1
|| bCut2
)
326 if (eRet
!= UR_NOTHING
&& oldRow1
== 0 && oldRow2
== pDoc
->MaxRow())
335 SCTAB nMaxTab
= pDoc
->GetTableCount() - 1;
336 bCut1
= lcl_MoveItCut( theTab1
, nDz
, nMaxTab
);
337 bCut2
= lcl_MoveItCut( theTab2
, nDz
, nMaxTab
);
338 if ( bCut1
|| bCut2
)
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
)
358 if ( eRet
== UR_NOTHING
)
360 if (oldCol1
!= theCol1
361 || oldRow1
!= theRow1
362 || oldTab1
!= theTab1
363 || oldCol2
!= theCol2
364 || oldRow2
!= theRow2
365 || oldTab2
!= theTab2
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
,
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
);
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
)
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
)
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
)
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
)
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
)
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
)
453 rWhat
.aStart
.SetTab( theTab1
);
454 rWhat
.aEnd
.SetTab( theTab2
);
459 if ( eRet
== UR_NOTHING
&& rWhat
!= aOldRange
)
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();
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
);
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
);
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() );
579 rRef
.aEnd
.SetCol(sal::static_int_cast
<SCCOL
>(rRef
.aEnd
.Col() + nGrowX
));
584 rRef
.aEnd
.SetRow(sal::static_int_cast
<SCROW
>(rRef
.aEnd
.Row() + nGrowY
));
591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */