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 "compiler.hxx"
23 #include "bigrange.hxx"
24 #include "chgtrack.hxx"
26 #include <osl/diagnose.h>
28 template< typename R
, typename S
, typename U
>
29 static bool lcl_MoveStart( R
& rRef
, U nStart
, S nDelta
, U nMask
)
33 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
34 else if ( nDelta
< 0 && rRef
>= nStart
+ nDelta
)
35 rRef
= nStart
+ nDelta
; //TODO: limit ???
41 else if ( rRef
> nMask
)
49 template< typename R
, typename S
, typename U
>
50 static bool lcl_MoveEnd( R
& rRef
, U nStart
, S nDelta
, U nMask
)
54 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
55 else if ( nDelta
< 0 && rRef
>= nStart
+ nDelta
)
56 rRef
= nStart
+ nDelta
- 1; //TODO: limit ???
62 else if ( rRef
> nMask
)
70 template< typename R
, typename S
, typename U
>
71 static bool lcl_MoveReorder( R
& rRef
, U nStart
, U nEnd
, S nDelta
)
73 if ( rRef
>= nStart
&& rRef
<= nEnd
)
75 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
79 if ( nDelta
> 0 ) // nach hinten schieben
81 if ( rRef
>= nStart
&& rRef
<= nEnd
+ nDelta
)
84 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
86 rRef
-= nEnd
- nStart
+ 1; // nachruecken
90 else // nach vorne schieben
92 if ( rRef
>= nStart
+ nDelta
&& rRef
<= nEnd
)
95 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
97 rRef
+= nEnd
- nStart
+ 1; // nachruecken
105 template< typename R
, typename S
, typename U
>
106 static bool lcl_MoveItCut( R
& rRef
, S nDelta
, U nMask
)
109 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
115 else if ( rRef
> nMask
)
123 template< typename R
, typename S
, typename U
>
124 static void lcl_MoveItWrap( R
& rRef
, S nDelta
, U nMask
)
126 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
129 else if ( rRef
> nMask
)
133 template< typename R
, typename S
, typename U
>
134 bool IsExpand( R n1
, R n2
, U nStart
, S nD
)
135 { // before normal Move...
138 && n1
< n2
// mindestens zwei Cols/Rows/Tabs in Ref
140 (nStart
<= n1
&& n1
< nStart
+ nD
) // n1 innerhalb des Insert
141 || (n2
+ 1 == nStart
) // n2 direkt vor Insert
142 ); // n1 < nStart <= n2 wird sowieso expanded!
145 template< typename R
, typename S
, typename U
>
146 void Expand( R
& n1
, R
& n2
, U nStart
, S nD
)
147 { // after normal Move..., only if IsExpand was true before!
149 if ( n2
+ 1 == nStart
)
151 n2
= sal::static_int_cast
<R
>( n2
+ nD
);
155 n1
= sal::static_int_cast
<R
>( n1
- nD
);
158 static bool lcl_IsWrapBig( sal_Int32 nRef
, sal_Int32 nDelta
)
160 if ( nRef
> 0 && nDelta
> 0 )
161 return nRef
+ nDelta
<= 0;
162 else if ( nRef
< 0 && nDelta
< 0 )
163 return nRef
+ nDelta
>= 0;
167 static bool lcl_MoveBig( sal_Int32
& rRef
, sal_Int32 nStart
, sal_Int32 nDelta
)
170 if ( rRef
>= nStart
)
173 bCut
= lcl_IsWrapBig( rRef
, nDelta
);
182 static bool lcl_MoveItCutBig( sal_Int32
& rRef
, sal_Int32 nDelta
)
184 bool bCut
= lcl_IsWrapBig( rRef
, nDelta
);
189 ScRefUpdateRes
ScRefUpdate::Update( ScDocument
* pDoc
, UpdateRefMode eUpdateRefMode
,
190 SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
191 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
,
192 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
193 SCCOL
& theCol1
, SCROW
& theRow1
, SCTAB
& theTab1
,
194 SCCOL
& theCol2
, SCROW
& theRow2
, SCTAB
& theTab2
)
196 ScRefUpdateRes eRet
= UR_NOTHING
;
198 SCCOL oldCol1
= theCol1
;
199 SCROW oldRow1
= theRow1
;
200 SCTAB oldTab1
= theTab1
;
201 SCCOL oldCol2
= theCol2
;
202 SCROW oldRow2
= theRow2
;
203 SCTAB oldTab2
= theTab2
;
207 if (eUpdateRefMode
== URM_INSDEL
)
209 bool bExpand
= pDoc
->IsExpandRefs();
210 if ( nDx
&& (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
211 (theTab1
>= nTab1
) && (theTab2
<= nTab2
))
213 bool bExp
= (bExpand
&& IsExpand( theCol1
, theCol2
, nCol1
, nDx
));
214 bCut1
= lcl_MoveStart( theCol1
, nCol1
, nDx
, MAXCOL
);
215 bCut2
= lcl_MoveEnd( theCol2
, nCol1
, nDx
, MAXCOL
);
216 if ( theCol2
< theCol1
)
221 else if ( bCut1
|| bCut2
)
225 Expand( theCol1
, theCol2
, nCol1
, nDx
);
228 if (eRet
!= UR_NOTHING
&& oldCol1
== 0 && oldCol2
== MAXCOL
)
235 if ( nDy
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
236 (theTab1
>= nTab1
) && (theTab2
<= nTab2
))
238 bool bExp
= (bExpand
&& IsExpand( theRow1
, theRow2
, nRow1
, nDy
));
239 bCut1
= lcl_MoveStart( theRow1
, nRow1
, nDy
, MAXROW
);
240 bCut2
= lcl_MoveEnd( theRow2
, nRow1
, nDy
, MAXROW
);
241 if ( theRow2
< theRow1
)
246 else if ( bCut1
|| bCut2
)
250 Expand( theRow1
, theRow2
, nRow1
, nDy
);
253 if (eRet
!= UR_NOTHING
&& oldRow1
== 0 && oldRow2
== MAXROW
)
260 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
261 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) )
263 SCsTAB nMaxTab
= pDoc
->GetTableCount() - 1;
264 nMaxTab
= sal::static_int_cast
<SCsTAB
>(nMaxTab
+ nDz
); // adjust to new count
265 bool bExp
= (bExpand
&& IsExpand( theTab1
, theTab2
, nTab1
, nDz
));
266 bCut1
= lcl_MoveStart( theTab1
, nTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
267 bCut2
= lcl_MoveEnd( theTab2
, nTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
268 if ( theTab2
< theTab1
)
273 else if ( bCut1
|| bCut2
)
277 Expand( theTab1
, theTab2
, nTab1
, nDz
);
282 else if (eUpdateRefMode
== URM_MOVE
)
284 if ((theCol1
>= nCol1
-nDx
) && (theRow1
>= nRow1
-nDy
) && (theTab1
>= nTab1
-nDz
) &&
285 (theCol2
<= nCol2
-nDx
) && (theRow2
<= nRow2
-nDy
) && (theTab2
<= nTab2
-nDz
))
289 bCut1
= lcl_MoveItCut( theCol1
, nDx
, MAXCOL
);
290 bCut2
= lcl_MoveItCut( theCol2
, nDx
, MAXCOL
);
291 if ( bCut1
|| bCut2
)
293 if (eRet
!= UR_NOTHING
&& oldCol1
== 0 && oldCol2
== MAXCOL
)
302 bCut1
= lcl_MoveItCut( theRow1
, nDy
, MAXROW
);
303 bCut2
= lcl_MoveItCut( theRow2
, nDy
, MAXROW
);
304 if ( bCut1
|| bCut2
)
306 if (eRet
!= UR_NOTHING
&& oldRow1
== 0 && oldRow2
== MAXROW
)
315 SCsTAB nMaxTab
= (SCsTAB
) pDoc
->GetTableCount() - 1;
316 bCut1
= lcl_MoveItCut( theTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
317 bCut2
= lcl_MoveItCut( theTab2
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
318 if ( bCut1
|| bCut2
)
323 else if (eUpdateRefMode
== URM_REORDER
)
325 // bisher nur fuer nDz (MoveTab)
326 OSL_ENSURE ( !nDx
&& !nDy
, "URM_REORDER for x and y not yet implemented" );
328 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
329 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) )
331 bCut1
= lcl_MoveReorder( theTab1
, nTab1
, nTab2
, nDz
);
332 bCut2
= lcl_MoveReorder( theTab2
, nTab1
, nTab2
, nDz
);
333 if ( bCut1
|| bCut2
)
338 if ( eRet
== UR_NOTHING
)
340 if (oldCol1
!= theCol1
341 || oldRow1
!= theRow1
342 || oldTab1
!= theTab1
343 || oldCol2
!= theCol2
344 || oldRow2
!= theRow2
345 || oldTab2
!= theTab2
352 // simples UpdateReference fuer ScBigRange (ScChangeAction/ScChangeTrack)
353 // Referenzen koennen auch ausserhalb des Dokuments liegen!
354 // Ganze Spalten/Zeilen (nInt32Min..nInt32Max) bleiben immer solche!
355 ScRefUpdateRes
ScRefUpdate::Update( UpdateRefMode eUpdateRefMode
,
356 const ScBigRange
& rWhere
, sal_Int32 nDx
, sal_Int32 nDy
, sal_Int32 nDz
,
359 ScRefUpdateRes eRet
= UR_NOTHING
;
360 const ScBigRange
aOldRange( rWhat
);
362 sal_Int32 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
;
363 sal_Int32 theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
;
364 rWhere
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
365 rWhat
.GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
369 if (eUpdateRefMode
== URM_INSDEL
)
371 if ( nDx
&& (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
372 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) &&
373 !(theCol1
== nInt32Min
&& theCol2
== nInt32Max
) )
375 bCut1
= lcl_MoveBig( theCol1
, nCol1
, nDx
);
376 bCut2
= lcl_MoveBig( theCol2
, nCol1
, nDx
);
377 if ( bCut1
|| bCut2
)
379 rWhat
.aStart
.SetCol( theCol1
);
380 rWhat
.aEnd
.SetCol( theCol2
);
382 if ( nDy
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
383 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) &&
384 !(theRow1
== nInt32Min
&& theRow2
== nInt32Max
) )
386 bCut1
= lcl_MoveBig( theRow1
, nRow1
, nDy
);
387 bCut2
= lcl_MoveBig( theRow2
, nRow1
, nDy
);
388 if ( bCut1
|| bCut2
)
390 rWhat
.aStart
.SetRow( theRow1
);
391 rWhat
.aEnd
.SetRow( theRow2
);
393 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
394 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
395 !(theTab1
== nInt32Min
&& theTab2
== nInt32Max
) )
397 bCut1
= lcl_MoveBig( theTab1
, nTab1
, nDz
);
398 bCut2
= lcl_MoveBig( theTab2
, nTab1
, nDz
);
399 if ( bCut1
|| bCut2
)
401 rWhat
.aStart
.SetTab( theTab1
);
402 rWhat
.aEnd
.SetTab( theTab2
);
405 else if (eUpdateRefMode
== URM_MOVE
)
407 if ( rWhere
.In( rWhat
) )
409 if ( nDx
&& !(theCol1
== nInt32Min
&& theCol2
== nInt32Max
) )
411 bCut1
= lcl_MoveItCutBig( theCol1
, nDx
);
412 bCut2
= lcl_MoveItCutBig( theCol2
, nDx
);
413 if ( bCut1
|| bCut2
)
415 rWhat
.aStart
.SetCol( theCol1
);
416 rWhat
.aEnd
.SetCol( theCol2
);
418 if ( nDy
&& !(theRow1
== nInt32Min
&& theRow2
== nInt32Max
) )
420 bCut1
= lcl_MoveItCutBig( theRow1
, nDy
);
421 bCut2
= lcl_MoveItCutBig( theRow2
, nDy
);
422 if ( bCut1
|| bCut2
)
424 rWhat
.aStart
.SetRow( theRow1
);
425 rWhat
.aEnd
.SetRow( theRow2
);
427 if ( nDz
&& !(theTab1
== nInt32Min
&& theTab2
== nInt32Max
) )
429 bCut1
= lcl_MoveItCutBig( theTab1
, nDz
);
430 bCut2
= lcl_MoveItCutBig( theTab2
, nDz
);
431 if ( bCut1
|| bCut2
)
433 rWhat
.aStart
.SetTab( theTab1
);
434 rWhat
.aEnd
.SetTab( theTab2
);
439 if ( eRet
== UR_NOTHING
&& rWhat
!= aOldRange
)
445 void ScRefUpdate::MoveRelWrap( ScDocument
* pDoc
, const ScAddress
& rPos
,
446 SCCOL nMaxCol
, SCROW nMaxRow
, ScComplexRefData
& rRef
)
448 ScRange aAbsRange
= rRef
.toAbs(rPos
);
449 if( rRef
.Ref1
.IsColRel() )
451 SCCOL nCol
= aAbsRange
.aStart
.Col();
452 lcl_MoveItWrap(nCol
, static_cast<SCsCOL
>(0), nMaxCol
);
453 aAbsRange
.aStart
.SetCol(nCol
);
455 if( rRef
.Ref2
.IsColRel() )
457 SCCOL nCol
= aAbsRange
.aEnd
.Col();
458 lcl_MoveItWrap(nCol
, static_cast<SCsCOL
>(0), nMaxCol
);
459 aAbsRange
.aEnd
.SetCol(nCol
);
461 if( rRef
.Ref1
.IsRowRel() )
463 SCROW nRow
= aAbsRange
.aStart
.Row();
464 lcl_MoveItWrap(nRow
, static_cast<SCsROW
>(0), nMaxRow
);
465 aAbsRange
.aStart
.SetRow(nRow
);
467 if( rRef
.Ref2
.IsRowRel() )
469 SCROW nRow
= aAbsRange
.aEnd
.Row();
470 lcl_MoveItWrap(nRow
, static_cast<SCsROW
>(0), nMaxRow
);
471 aAbsRange
.aEnd
.SetRow(nRow
);
473 SCsTAB nMaxTab
= (SCsTAB
) pDoc
->GetTableCount() - 1;
474 if( rRef
.Ref1
.IsTabRel() )
476 SCTAB nTab
= aAbsRange
.aStart
.Tab();
477 lcl_MoveItWrap(nTab
, static_cast<SCsTAB
>(0), static_cast<SCTAB
>(nMaxTab
));
478 aAbsRange
.aStart
.SetTab(nTab
);
480 if( rRef
.Ref2
.IsTabRel() )
482 SCTAB nTab
= aAbsRange
.aEnd
.Tab();
483 lcl_MoveItWrap(nTab
, static_cast<SCsTAB
>(0), static_cast<SCTAB
>(nMaxTab
));
484 aAbsRange
.aEnd
.SetTab(nTab
);
487 aAbsRange
.PutInOrder();
488 rRef
.SetRange(aAbsRange
, rPos
);
491 void ScRefUpdate::DoTranspose( SCsCOL
& rCol
, SCsROW
& rRow
, SCsTAB
& rTab
,
492 ScDocument
* pDoc
, const ScRange
& rSource
, const ScAddress
& rDest
)
494 SCsTAB nDz
= ((SCsTAB
)rDest
.Tab())-(SCsTAB
)rSource
.aStart
.Tab();
497 SCsTAB nNewTab
= rTab
+nDz
;
498 SCsTAB nCount
= pDoc
->GetTableCount();
499 while (nNewTab
<0) nNewTab
= sal::static_int_cast
<SCsTAB
>( nNewTab
+ nCount
);
500 while (nNewTab
>=nCount
) nNewTab
= sal::static_int_cast
<SCsTAB
>( nNewTab
- nCount
);
503 OSL_ENSURE( rCol
>=rSource
.aStart
.Col() && rRow
>=rSource
.aStart
.Row(),
504 "UpdateTranspose: Pos. falsch" );
506 SCsCOL nRelX
= rCol
- (SCsCOL
)rSource
.aStart
.Col();
507 SCsROW nRelY
= rRow
- (SCsROW
)rSource
.aStart
.Row();
509 rCol
= static_cast<SCsCOL
>(static_cast<SCsCOLROW
>(rDest
.Col()) +
510 static_cast<SCsCOLROW
>(nRelY
));
511 rRow
= static_cast<SCsROW
>(static_cast<SCsCOLROW
>(rDest
.Row()) +
512 static_cast<SCsCOLROW
>(nRelX
));
515 ScRefUpdateRes
ScRefUpdate::UpdateTranspose(
516 ScDocument
* pDoc
, const ScRange
& rSource
, const ScAddress
& rDest
, ScRange
& rRef
)
518 ScRefUpdateRes eRet
= UR_NOTHING
;
519 if (rRef
.aStart
.Col() >= rSource
.aStart
.Col() && rRef
.aEnd
.Col() <= rSource
.aEnd
.Col() &&
520 rRef
.aStart
.Row() >= rSource
.aStart
.Row() && rRef
.aEnd
.Row() <= rSource
.aEnd
.Row() &&
521 rRef
.aStart
.Tab() >= rSource
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rSource
.aEnd
.Tab())
523 // Source range contains the reference range.
524 SCCOL nCol1
= rRef
.aStart
.Col(), nCol2
= rRef
.aEnd
.Col();
525 SCROW nRow1
= rRef
.aStart
.Row(), nRow2
= rRef
.aEnd
.Row();
526 SCTAB nTab1
= rRef
.aStart
.Tab(), nTab2
= rRef
.aEnd
.Tab();
527 DoTranspose(nCol1
, nRow1
, nTab1
, pDoc
, rSource
, rDest
);
528 DoTranspose(nCol2
, nRow2
, nTab2
, pDoc
, rSource
, rDest
);
529 rRef
.aStart
= ScAddress(nCol1
, nRow1
, nTab1
);
530 rRef
.aEnd
= ScAddress(nCol2
, nRow2
, nTab2
);
536 // UpdateGrow - erweitert Referenzen, die genau auf den Bereich zeigen
537 // kommt ohne Dokument aus
539 ScRefUpdateRes
ScRefUpdate::UpdateGrow(
540 const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
, ScRange
& rRef
)
542 ScRefUpdateRes eRet
= UR_NOTHING
;
544 // in Y-Richtung darf die Ref auch eine Zeile weiter unten anfangen,
545 // falls ein Bereich Spaltenkoepfe enthaelt
547 bool bUpdateX
= ( nGrowX
&&
548 rRef
.aStart
.Col() == rArea
.aStart
.Col() && rRef
.aEnd
.Col() == rArea
.aEnd
.Col() &&
549 rRef
.aStart
.Row() >= rArea
.aStart
.Row() && rRef
.aEnd
.Row() <= rArea
.aEnd
.Row() &&
550 rRef
.aStart
.Tab() >= rArea
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rArea
.aEnd
.Tab() );
551 bool bUpdateY
= ( nGrowY
&&
552 rRef
.aStart
.Col() >= rArea
.aStart
.Col() && rRef
.aEnd
.Col() <= rArea
.aEnd
.Col() &&
553 (rRef
.aStart
.Row() == rArea
.aStart
.Row() || rRef
.aStart
.Row() == rArea
.aStart
.Row()+1) &&
554 rRef
.aEnd
.Row() == rArea
.aEnd
.Row() &&
555 rRef
.aStart
.Tab() >= rArea
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rArea
.aEnd
.Tab() );
559 rRef
.aEnd
.SetCol(sal::static_int_cast
<SCsCOL
>(rRef
.aEnd
.Col() + nGrowX
));
564 rRef
.aEnd
.SetRow(sal::static_int_cast
<SCsROW
>(rRef
.aEnd
.Row() + nGrowY
));
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */