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 template< typename R
, typename S
, typename U
>
27 static bool lcl_MoveStart( R
& rRef
, U nStart
, S nDelta
, U nMask
)
31 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
32 else if ( nDelta
< 0 && rRef
>= nStart
+ nDelta
)
33 rRef
= nStart
+ nDelta
; //! begrenzen ???
39 else if ( rRef
> nMask
)
47 template< typename R
, typename S
, typename U
>
48 static bool lcl_MoveEnd( R
& rRef
, U nStart
, S nDelta
, U nMask
)
52 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
53 else if ( nDelta
< 0 && rRef
>= nStart
+ nDelta
)
54 rRef
= nStart
+ nDelta
- 1; //! begrenzen ???
60 else if ( rRef
> nMask
)
68 template< typename R
, typename S
, typename U
>
69 static bool lcl_MoveReorder( R
& rRef
, U nStart
, U nEnd
, S nDelta
)
71 if ( rRef
>= nStart
&& rRef
<= nEnd
)
73 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
77 if ( nDelta
> 0 ) // nach hinten schieben
79 if ( rRef
>= nStart
&& rRef
<= nEnd
+ nDelta
)
82 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
84 rRef
-= nEnd
- nStart
+ 1; // nachruecken
88 else // nach vorne schieben
90 if ( rRef
>= nStart
+ nDelta
&& rRef
<= nEnd
)
93 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
); // in the moved range
95 rRef
+= nEnd
- nStart
+ 1; // nachruecken
103 template< typename R
, typename S
, typename U
>
104 static bool lcl_MoveItCut( R
& rRef
, S nDelta
, U nMask
)
107 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
113 else if ( rRef
> nMask
)
121 template< typename R
, typename S
, typename U
>
122 static void lcl_MoveItWrap( R
& rRef
, S nDelta
, U nMask
)
124 rRef
= sal::static_int_cast
<R
>( rRef
+ nDelta
);
127 else if ( rRef
> nMask
)
131 template< typename R
, typename S
, typename U
>
132 static bool lcl_MoveRefPart( R
& rRef1Val
, bool& rRef1Del
, bool bDo1
,
133 R
& rRef2Val
, bool& rRef2Del
, bool bDo2
,
134 U nStart
, U nEnd
, S nDelta
, U nMask
)
138 bool bDel
, bCut1
, bCut2
;
139 bDel
= bCut1
= bCut2
= false;
146 if ( n
<= rRef1Val
&& rRef1Val
< nStart
147 && n
<= rRef2Val
&& rRef2Val
< nStart
)
153 if ( nEnd
< rRef1Val
&& rRef1Val
<= n
154 && nEnd
< rRef2Val
&& rRef2Val
<= n
)
159 { // move deleted along
160 rRef1Val
= sal::static_int_cast
<R
>( rRef1Val
+ nDelta
);
161 rRef2Val
= sal::static_int_cast
<R
>( rRef2Val
+ nDelta
);
168 rRef1Val
= sal::static_int_cast
<R
>( rRef1Val
+ nDelta
);
170 bCut1
= lcl_MoveStart( rRef1Val
, nStart
, nDelta
, nMask
);
175 rRef2Val
= sal::static_int_cast
<R
>( rRef2Val
+ nDelta
);
177 bCut2
= lcl_MoveEnd( rRef2Val
, nStart
, nDelta
, nMask
);
180 if ( bDel
|| (bCut1
&& bCut2
) )
181 rRef1Del
= rRef2Del
= true;
182 return bDel
|| bCut1
|| bCut2
|| rRef1Del
|| rRef2Del
;
188 template< typename R
, typename S
, typename U
>
189 bool IsExpand( R n1
, R n2
, U nStart
, S nD
)
190 { //! vor normalem Move...
193 && n1
< n2
// mindestens zwei Cols/Rows/Tabs in Ref
195 (nStart
<= n1
&& n1
< nStart
+ nD
) // n1 innerhalb des Insert
196 || (n2
+ 1 == nStart
) // n2 direkt vor Insert
197 ); // n1 < nStart <= n2 wird sowieso expanded!
200 template< typename R
, typename S
, typename U
>
201 void Expand( R
& n1
, R
& n2
, U nStart
, S nD
)
202 { //! nach normalem Move..., nur wenn IsExpand vorher true war!
204 if ( n2
+ 1 == nStart
)
206 n2
= sal::static_int_cast
<R
>( n2
+ nD
);
210 n1
= sal::static_int_cast
<R
>( n1
- nD
);
213 static bool lcl_IsWrapBig( sal_Int32 nRef
, sal_Int32 nDelta
)
215 if ( nRef
> 0 && nDelta
> 0 )
216 return nRef
+ nDelta
<= 0;
217 else if ( nRef
< 0 && nDelta
< 0 )
218 return nRef
+ nDelta
>= 0;
222 static bool lcl_MoveBig( sal_Int32
& rRef
, sal_Int32 nStart
, sal_Int32 nDelta
)
225 if ( rRef
>= nStart
)
228 bCut
= lcl_IsWrapBig( rRef
, nDelta
);
237 static bool lcl_MoveItCutBig( sal_Int32
& rRef
, sal_Int32 nDelta
)
239 bool bCut
= lcl_IsWrapBig( rRef
, nDelta
);
244 ScRefUpdateRes
ScRefUpdate::Update( ScDocument
* pDoc
, UpdateRefMode eUpdateRefMode
,
245 SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
246 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
,
247 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
248 SCCOL
& theCol1
, SCROW
& theRow1
, SCTAB
& theTab1
,
249 SCCOL
& theCol2
, SCROW
& theRow2
, SCTAB
& theTab2
)
251 ScRefUpdateRes eRet
= UR_NOTHING
;
253 SCCOL oldCol1
= theCol1
;
254 SCROW oldRow1
= theRow1
;
255 SCTAB oldTab1
= theTab1
;
256 SCCOL oldCol2
= theCol2
;
257 SCROW oldRow2
= theRow2
;
258 SCTAB oldTab2
= theTab2
;
262 if (eUpdateRefMode
== URM_INSDEL
)
264 bool bExpand
= pDoc
->IsExpandRefs();
265 if ( nDx
&& (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
266 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) )
268 bool bExp
= (bExpand
&& IsExpand( theCol1
, theCol2
, nCol1
, nDx
));
269 bCut1
= lcl_MoveStart( theCol1
, nCol1
, nDx
, MAXCOL
);
270 bCut2
= lcl_MoveEnd( theCol2
, nCol1
, nDx
, MAXCOL
);
271 if ( theCol2
< theCol1
)
276 else if ( bCut1
|| bCut2
)
280 Expand( theCol1
, theCol2
, nCol1
, nDx
);
284 if ( nDy
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
285 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) )
287 bool bExp
= (bExpand
&& IsExpand( theRow1
, theRow2
, nRow1
, nDy
));
288 bCut1
= lcl_MoveStart( theRow1
, nRow1
, nDy
, MAXROW
);
289 bCut2
= lcl_MoveEnd( theRow2
, nRow1
, nDy
, MAXROW
);
290 if ( theRow2
< theRow1
)
295 else if ( bCut1
|| bCut2
)
299 Expand( theRow1
, theRow2
, nRow1
, nDy
);
303 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
304 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) )
306 SCsTAB nMaxTab
= pDoc
->GetTableCount() - 1;
307 nMaxTab
= sal::static_int_cast
<SCsTAB
>(nMaxTab
+ nDz
); // adjust to new count
308 bool bExp
= (bExpand
&& IsExpand( theTab1
, theTab2
, nTab1
, nDz
));
309 bCut1
= lcl_MoveStart( theTab1
, nTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
310 bCut2
= lcl_MoveEnd( theTab2
, nTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
311 if ( theTab2
< theTab1
)
316 else if ( bCut1
|| bCut2
)
320 Expand( theTab1
, theTab2
, nTab1
, nDz
);
325 else if (eUpdateRefMode
== URM_MOVE
)
327 if ((theCol1
>= nCol1
-nDx
) && (theRow1
>= nRow1
-nDy
) && (theTab1
>= nTab1
-nDz
) &&
328 (theCol2
<= nCol2
-nDx
) && (theRow2
<= nRow2
-nDy
) && (theTab2
<= nTab2
-nDz
))
332 bCut1
= lcl_MoveItCut( theCol1
, nDx
, MAXCOL
);
333 bCut2
= lcl_MoveItCut( theCol2
, nDx
, MAXCOL
);
334 if ( bCut1
|| bCut2
)
339 bCut1
= lcl_MoveItCut( theRow1
, nDy
, MAXROW
);
340 bCut2
= lcl_MoveItCut( theRow2
, nDy
, MAXROW
);
341 if ( bCut1
|| bCut2
)
346 SCsTAB nMaxTab
= (SCsTAB
) pDoc
->GetTableCount() - 1;
347 bCut1
= lcl_MoveItCut( theTab1
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
348 bCut2
= lcl_MoveItCut( theTab2
, nDz
, static_cast<SCTAB
>(nMaxTab
) );
349 if ( bCut1
|| bCut2
)
354 else if (eUpdateRefMode
== URM_REORDER
)
356 // bisher nur fuer nDz (MoveTab)
357 OSL_ENSURE ( !nDx
&& !nDy
, "URM_REORDER for x and y not yet implemented" );
359 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
360 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) )
362 bCut1
= lcl_MoveReorder( theTab1
, nTab1
, nTab2
, nDz
);
363 bCut2
= lcl_MoveReorder( theTab2
, nTab1
, nTab2
, nDz
);
364 if ( bCut1
|| bCut2
)
369 if ( eRet
== UR_NOTHING
)
371 if (oldCol1
!= theCol1
372 || oldRow1
!= theRow1
373 || oldTab1
!= theTab1
374 || oldCol2
!= theCol2
375 || oldRow2
!= theRow2
376 || oldTab2
!= theTab2
383 // simples UpdateReference fuer ScBigRange (ScChangeAction/ScChangeTrack)
384 // Referenzen koennen auch ausserhalb des Dokuments liegen!
385 // Ganze Spalten/Zeilen (nInt32Min..nInt32Max) bleiben immer solche!
386 ScRefUpdateRes
ScRefUpdate::Update( UpdateRefMode eUpdateRefMode
,
387 const ScBigRange
& rWhere
, sal_Int32 nDx
, sal_Int32 nDy
, sal_Int32 nDz
,
390 ScRefUpdateRes eRet
= UR_NOTHING
;
391 const ScBigRange
aOldRange( rWhat
);
393 sal_Int32 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
;
394 sal_Int32 theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
;
395 rWhere
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
396 rWhat
.GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
400 if (eUpdateRefMode
== URM_INSDEL
)
402 if ( nDx
&& (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
403 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) &&
404 !(theCol1
== nInt32Min
&& theCol2
== nInt32Max
) )
406 bCut1
= lcl_MoveBig( theCol1
, nCol1
, nDx
);
407 bCut2
= lcl_MoveBig( theCol2
, nCol1
, nDx
);
408 if ( bCut1
|| bCut2
)
410 rWhat
.aStart
.SetCol( theCol1
);
411 rWhat
.aEnd
.SetCol( theCol2
);
413 if ( nDy
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
414 (theTab1
>= nTab1
) && (theTab2
<= nTab2
) &&
415 !(theRow1
== nInt32Min
&& theRow2
== nInt32Max
) )
417 bCut1
= lcl_MoveBig( theRow1
, nRow1
, nDy
);
418 bCut2
= lcl_MoveBig( theRow2
, nRow1
, nDy
);
419 if ( bCut1
|| bCut2
)
421 rWhat
.aStart
.SetRow( theRow1
);
422 rWhat
.aEnd
.SetRow( theRow2
);
424 if ( nDz
&& (theCol1
>= nCol1
) && (theCol2
<= nCol2
) &&
425 (theRow1
>= nRow1
) && (theRow2
<= nRow2
) &&
426 !(theTab1
== nInt32Min
&& theTab2
== nInt32Max
) )
428 bCut1
= lcl_MoveBig( theTab1
, nTab1
, nDz
);
429 bCut2
= lcl_MoveBig( theTab2
, nTab1
, nDz
);
430 if ( bCut1
|| bCut2
)
432 rWhat
.aStart
.SetTab( theTab1
);
433 rWhat
.aEnd
.SetTab( theTab2
);
436 else if (eUpdateRefMode
== URM_MOVE
)
438 if ( rWhere
.In( rWhat
) )
440 if ( nDx
&& !(theCol1
== nInt32Min
&& theCol2
== nInt32Max
) )
442 bCut1
= lcl_MoveItCutBig( theCol1
, nDx
);
443 bCut2
= lcl_MoveItCutBig( theCol2
, nDx
);
444 if ( bCut1
|| bCut2
)
446 rWhat
.aStart
.SetCol( theCol1
);
447 rWhat
.aEnd
.SetCol( theCol2
);
449 if ( nDy
&& !(theRow1
== nInt32Min
&& theRow2
== nInt32Max
) )
451 bCut1
= lcl_MoveItCutBig( theRow1
, nDy
);
452 bCut2
= lcl_MoveItCutBig( theRow2
, nDy
);
453 if ( bCut1
|| bCut2
)
455 rWhat
.aStart
.SetRow( theRow1
);
456 rWhat
.aEnd
.SetRow( theRow2
);
458 if ( nDz
&& !(theTab1
== nInt32Min
&& theTab2
== nInt32Max
) )
460 bCut1
= lcl_MoveItCutBig( theTab1
, nDz
);
461 bCut2
= lcl_MoveItCutBig( theTab2
, nDz
);
462 if ( bCut1
|| bCut2
)
464 rWhat
.aStart
.SetTab( theTab1
);
465 rWhat
.aEnd
.SetTab( theTab2
);
470 if ( eRet
== UR_NOTHING
&& rWhat
!= aOldRange
)
476 void ScRefUpdate::MoveRelWrap( ScDocument
* pDoc
, const ScAddress
& rPos
,
477 SCCOL nMaxCol
, SCROW nMaxRow
, ScComplexRefData
& rRef
)
479 ScRange aAbsRange
= rRef
.toAbs(rPos
);
480 if( rRef
.Ref1
.IsColRel() )
482 SCCOL nCol
= aAbsRange
.aStart
.Col();
483 lcl_MoveItWrap(nCol
, static_cast<SCsCOL
>(0), nMaxCol
);
484 aAbsRange
.aStart
.SetCol(nCol
);
486 if( rRef
.Ref2
.IsColRel() )
488 SCCOL nCol
= aAbsRange
.aEnd
.Col();
489 lcl_MoveItWrap(nCol
, static_cast<SCsCOL
>(0), nMaxCol
);
490 aAbsRange
.aEnd
.SetCol(nCol
);
492 if( rRef
.Ref1
.IsRowRel() )
494 SCROW nRow
= aAbsRange
.aStart
.Row();
495 lcl_MoveItWrap(nRow
, static_cast<SCsROW
>(0), nMaxRow
);
496 aAbsRange
.aStart
.SetRow(nRow
);
498 if( rRef
.Ref2
.IsRowRel() )
500 SCROW nRow
= aAbsRange
.aEnd
.Row();
501 lcl_MoveItWrap(nRow
, static_cast<SCsROW
>(0), nMaxRow
);
502 aAbsRange
.aEnd
.SetRow(nRow
);
504 SCsTAB nMaxTab
= (SCsTAB
) pDoc
->GetTableCount() - 1;
505 if( rRef
.Ref1
.IsTabRel() )
507 SCTAB nTab
= aAbsRange
.aStart
.Tab();
508 lcl_MoveItWrap(nTab
, static_cast<SCsTAB
>(0), static_cast<SCTAB
>(nMaxTab
));
509 aAbsRange
.aStart
.SetTab(nTab
);
511 if( rRef
.Ref2
.IsTabRel() )
513 SCTAB nTab
= aAbsRange
.aEnd
.Tab();
514 lcl_MoveItWrap(nTab
, static_cast<SCsTAB
>(0), static_cast<SCTAB
>(nMaxTab
));
515 aAbsRange
.aEnd
.SetTab(nTab
);
518 aAbsRange
.PutInOrder();
519 rRef
.SetRange(aAbsRange
, rPos
);
522 void ScRefUpdate::DoTranspose( SCsCOL
& rCol
, SCsROW
& rRow
, SCsTAB
& rTab
,
523 ScDocument
* pDoc
, const ScRange
& rSource
, const ScAddress
& rDest
)
525 SCsTAB nDz
= ((SCsTAB
)rDest
.Tab())-(SCsTAB
)rSource
.aStart
.Tab();
528 SCsTAB nNewTab
= rTab
+nDz
;
529 SCsTAB nCount
= pDoc
->GetTableCount();
530 while (nNewTab
<0) nNewTab
= sal::static_int_cast
<SCsTAB
>( nNewTab
+ nCount
);
531 while (nNewTab
>=nCount
) nNewTab
= sal::static_int_cast
<SCsTAB
>( nNewTab
- nCount
);
534 OSL_ENSURE( rCol
>=rSource
.aStart
.Col() && rRow
>=rSource
.aStart
.Row(),
535 "UpdateTranspose: Pos. falsch" );
537 SCsCOL nRelX
= rCol
- (SCsCOL
)rSource
.aStart
.Col();
538 SCsROW nRelY
= rRow
- (SCsROW
)rSource
.aStart
.Row();
540 rCol
= static_cast<SCsCOL
>(static_cast<SCsCOLROW
>(rDest
.Col()) +
541 static_cast<SCsCOLROW
>(nRelY
));
542 rRow
= static_cast<SCsROW
>(static_cast<SCsCOLROW
>(rDest
.Row()) +
543 static_cast<SCsCOLROW
>(nRelX
));
546 ScRefUpdateRes
ScRefUpdate::UpdateTranspose(
547 ScDocument
* pDoc
, const ScRange
& rSource
, const ScAddress
& rDest
, ScRange
& rRef
)
549 ScRefUpdateRes eRet
= UR_NOTHING
;
550 if (rRef
.aStart
.Col() >= rSource
.aStart
.Col() && rRef
.aEnd
.Col() <= rSource
.aEnd
.Col() &&
551 rRef
.aStart
.Row() >= rSource
.aStart
.Row() && rRef
.aEnd
.Row() <= rSource
.aEnd
.Row() &&
552 rRef
.aStart
.Tab() >= rSource
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rSource
.aEnd
.Tab())
554 // Source range contains the reference range.
555 SCCOL nCol1
= rRef
.aStart
.Col(), nCol2
= rRef
.aEnd
.Col();
556 SCROW nRow1
= rRef
.aStart
.Row(), nRow2
= rRef
.aEnd
.Row();
557 SCTAB nTab1
= rRef
.aStart
.Tab(), nTab2
= rRef
.aEnd
.Tab();
558 DoTranspose(nCol1
, nRow1
, nTab1
, pDoc
, rSource
, rDest
);
559 DoTranspose(nCol2
, nRow2
, nTab2
, pDoc
, rSource
, rDest
);
560 rRef
.aStart
= ScAddress(nCol1
, nRow1
, nTab1
);
561 rRef
.aEnd
= ScAddress(nCol2
, nRow2
, nTab2
);
567 // UpdateGrow - erweitert Referenzen, die genau auf den Bereich zeigen
568 // kommt ohne Dokument aus
570 ScRefUpdateRes
ScRefUpdate::UpdateGrow(
571 const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
, ScRange
& rRef
)
573 ScRefUpdateRes eRet
= UR_NOTHING
;
575 // in Y-Richtung darf die Ref auch eine Zeile weiter unten anfangen,
576 // falls ein Bereich Spaltenkoepfe enthaelt
578 bool bUpdateX
= ( nGrowX
&&
579 rRef
.aStart
.Col() == rArea
.aStart
.Col() && rRef
.aEnd
.Col() == rArea
.aEnd
.Col() &&
580 rRef
.aStart
.Row() >= rArea
.aStart
.Row() && rRef
.aEnd
.Row() <= rArea
.aEnd
.Row() &&
581 rRef
.aStart
.Tab() >= rArea
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rArea
.aEnd
.Tab() );
582 bool bUpdateY
= ( nGrowY
&&
583 rRef
.aStart
.Col() >= rArea
.aStart
.Col() && rRef
.aEnd
.Col() <= rArea
.aEnd
.Col() &&
584 (rRef
.aStart
.Row() == rArea
.aStart
.Row() || rRef
.aStart
.Row() == rArea
.aStart
.Row()+1) &&
585 rRef
.aEnd
.Row() == rArea
.aEnd
.Row() &&
586 rRef
.aStart
.Tab() >= rArea
.aStart
.Tab() && rRef
.aEnd
.Tab() <= rArea
.aEnd
.Tab() );
590 rRef
.aEnd
.SetCol(sal::static_int_cast
<SCsCOL
>(rRef
.aEnd
.Col() + nGrowX
));
595 rRef
.aEnd
.SetRow(sal::static_int_cast
<SCsROW
>(rRef
.aEnd
.Row() + nGrowY
));
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */