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 <sal/config.h>
24 #include <refdata.hxx>
25 #include <document.hxx>
27 void ScSingleRefData::InitAddress( const ScAddress
& rAdr
)
29 InitAddress( rAdr
.Col(), rAdr
.Row(), rAdr
.Tab());
32 void ScSingleRefData::InitAddress( SCCOL nColP
, SCROW nRowP
, SCTAB nTabP
)
40 void ScSingleRefData::InitAddressRel( const ScDocument
& rDoc
, const ScAddress
& rAdr
, const ScAddress
& rPos
)
46 SetAddress(rDoc
.GetSheetLimits(), rAdr
, rPos
);
49 void ScSingleRefData::InitFromRefAddress( const ScDocument
& rDoc
, const ScRefAddress
& rRef
, const ScAddress
& rPos
)
52 SetColRel( rRef
.IsRelCol());
53 SetRowRel( rRef
.IsRelRow());
54 SetTabRel( rRef
.IsRelTab());
55 SetFlag3D( rRef
.Tab() != rPos
.Tab());
56 SetAddress( rDoc
.GetSheetLimits(), rRef
.GetAddress(), rPos
);
59 void ScSingleRefData::SetAbsCol( SCCOL nVal
)
61 Flags
.bColRel
= false;
65 void ScSingleRefData::SetRelCol( SCCOL nVal
)
71 void ScSingleRefData::IncCol( SCCOL nInc
)
76 void ScSingleRefData::SetAbsRow( SCROW nVal
)
78 Flags
.bRowRel
= false;
82 void ScSingleRefData::SetRelRow( SCROW nVal
)
88 void ScSingleRefData::IncRow( SCROW nInc
)
93 void ScSingleRefData::SetAbsTab( SCTAB nVal
)
95 Flags
.bTabRel
= false;
99 void ScSingleRefData::SetRelTab( SCTAB nVal
)
101 Flags
.bTabRel
= true;
105 void ScSingleRefData::IncTab( SCTAB nInc
)
110 void ScSingleRefData::SetColDeleted( bool bVal
)
112 Flags
.bColDeleted
= bVal
;
115 void ScSingleRefData::SetRowDeleted( bool bVal
)
117 Flags
.bRowDeleted
= bVal
;
120 void ScSingleRefData::SetTabDeleted( bool bVal
)
122 Flags
.bTabDeleted
= bVal
;
125 bool ScSingleRefData::IsDeleted() const
127 return IsColDeleted() || IsRowDeleted() || IsTabDeleted();
130 bool ScSingleRefData::Valid(const ScDocument
& rDoc
) const
132 return !IsDeleted() && ColValid(rDoc
) && RowValid(rDoc
) && TabValid(rDoc
);
135 bool ScSingleRefData::ColValid(const ScDocument
& rDoc
) const
139 if (mnCol
< -rDoc
.MaxCol() || rDoc
.MaxCol() < mnCol
)
144 if (mnCol
< 0 || rDoc
.MaxCol() < mnCol
)
151 bool ScSingleRefData::RowValid(const ScDocument
& rDoc
) const
155 if (mnRow
< -rDoc
.MaxRow() || rDoc
.MaxRow() < mnRow
)
160 if (mnRow
< 0 || rDoc
.MaxRow() < mnRow
)
167 bool ScSingleRefData::TabValid(const ScDocument
& rDoc
) const
171 if (mnTab
< -MAXTAB
|| MAXTAB
< mnTab
)
176 if (mnTab
< 0 || rDoc
.GetTableCount() <= mnTab
)
183 bool ScSingleRefData::ValidExternal(const ScDocument
& rDoc
) const
185 return ColValid(rDoc
) && RowValid(rDoc
) && mnTab
>= -1;
188 ScAddress
ScSingleRefData::toAbs( const ScDocument
& rDoc
, const ScAddress
& rPos
) const
190 return toAbs(rDoc
.GetSheetLimits(), rPos
);
193 ScAddress
ScSingleRefData::toAbs( const ScSheetLimits
& rLimits
, const ScAddress
& rPos
) const
195 SCCOL nRetCol
= Flags
.bColRel
? mnCol
+ rPos
.Col() : mnCol
;
196 SCROW nRetRow
= Flags
.bRowRel
? mnRow
+ rPos
.Row() : mnRow
;
197 SCTAB nRetTab
= Flags
.bTabRel
? mnTab
+ rPos
.Tab() : mnTab
;
199 ScAddress
aAbs(ScAddress::INITIALIZE_INVALID
);
201 if (rLimits
.ValidCol(nRetCol
))
202 aAbs
.SetCol(nRetCol
);
204 if (rLimits
.ValidRow(nRetRow
))
205 aAbs
.SetRow(nRetRow
);
207 if (ValidTab(nRetTab
))
208 aAbs
.SetTab(nRetTab
);
213 void ScSingleRefData::SetAddress( const ScSheetLimits
& rLimits
, const ScAddress
& rAddr
, const ScAddress
& rPos
)
216 mnCol
= rAddr
.Col() - rPos
.Col();
220 if (!rLimits
.ValidCol(rAddr
.Col()))
224 mnRow
= rAddr
.Row() - rPos
.Row();
228 if (!rLimits
.ValidRow(rAddr
.Row()))
232 mnTab
= rAddr
.Tab() - rPos
.Tab();
236 if (!ValidTab( rAddr
.Tab(), MAXTAB
))
240 SCROW
ScSingleRefData::Row() const
242 if (Flags
.bRowDeleted
)
247 SCCOL
ScSingleRefData::Col() const
249 if (Flags
.bColDeleted
)
254 SCTAB
ScSingleRefData::Tab() const
256 if (Flags
.bTabDeleted
)
262 void ScSingleRefData::PutInOrder( ScSingleRefData
& rRef1
, ScSingleRefData
& rRef2
, const ScAddress
& rPos
)
264 const sal_uInt8 kCOL
= 1;
265 const sal_uInt8 kROW
= 2;
266 const sal_uInt8 kTAB
= 4;
268 sal_uInt8 nRelState1
= rRef1
.Flags
.bRelName
?
269 ((rRef1
.Flags
.bTabRel
? kTAB
: 0) |
270 (rRef1
.Flags
.bRowRel
? kROW
: 0) |
271 (rRef1
.Flags
.bColRel
? kCOL
: 0)) :
274 sal_uInt8 nRelState2
= rRef2
.Flags
.bRelName
?
275 ((rRef2
.Flags
.bTabRel
? kTAB
: 0) |
276 (rRef2
.Flags
.bRowRel
? kROW
: 0) |
277 (rRef2
.Flags
.bColRel
? kCOL
: 0)) :
280 SCCOL nCol1
= rRef1
.Flags
.bColRel
? rPos
.Col() + rRef1
.mnCol
: rRef1
.mnCol
;
281 SCCOL nCol2
= rRef2
.Flags
.bColRel
? rPos
.Col() + rRef2
.mnCol
: rRef2
.mnCol
;
284 rRef1
.mnCol
= rRef2
.Flags
.bColRel
? nCol2
- rPos
.Col() : nCol2
;
285 rRef2
.mnCol
= rRef1
.Flags
.bColRel
? nCol1
- rPos
.Col() : nCol1
;
286 if (rRef1
.Flags
.bRelName
&& rRef1
.Flags
.bColRel
)
290 if (rRef2
.Flags
.bRelName
&& rRef2
.Flags
.bColRel
)
294 bool bTmp
= rRef1
.Flags
.bColRel
;
295 rRef1
.Flags
.bColRel
= rRef2
.Flags
.bColRel
;
296 rRef2
.Flags
.bColRel
= bTmp
;
297 bTmp
= rRef1
.Flags
.bColDeleted
;
298 rRef1
.Flags
.bColDeleted
= rRef2
.Flags
.bColDeleted
;
299 rRef2
.Flags
.bColDeleted
= bTmp
;
302 SCROW nRow1
= rRef1
.Flags
.bRowRel
? rPos
.Row() + rRef1
.mnRow
: rRef1
.mnRow
;
303 SCROW nRow2
= rRef2
.Flags
.bRowRel
? rPos
.Row() + rRef2
.mnRow
: rRef2
.mnRow
;
306 rRef1
.mnRow
= rRef2
.Flags
.bRowRel
? nRow2
- rPos
.Row() : nRow2
;
307 rRef2
.mnRow
= rRef1
.Flags
.bRowRel
? nRow1
- rPos
.Row() : nRow1
;
308 if (rRef1
.Flags
.bRelName
&& rRef1
.Flags
.bRowRel
)
312 if (rRef2
.Flags
.bRelName
&& rRef2
.Flags
.bRowRel
)
316 bool bTmp
= rRef1
.Flags
.bRowRel
;
317 rRef1
.Flags
.bRowRel
= rRef2
.Flags
.bRowRel
;
318 rRef2
.Flags
.bRowRel
= bTmp
;
319 bTmp
= rRef1
.Flags
.bRowDeleted
;
320 rRef1
.Flags
.bRowDeleted
= rRef2
.Flags
.bRowDeleted
;
321 rRef2
.Flags
.bRowDeleted
= bTmp
;
324 SCTAB nTab1
= rRef1
.Flags
.bTabRel
? rPos
.Tab() + rRef1
.mnTab
: rRef1
.mnTab
;
325 SCTAB nTab2
= rRef2
.Flags
.bTabRel
? rPos
.Tab() + rRef2
.mnTab
: rRef2
.mnTab
;
328 rRef1
.mnTab
= rRef2
.Flags
.bTabRel
? nTab2
- rPos
.Tab() : nTab2
;
329 rRef2
.mnTab
= rRef1
.Flags
.bTabRel
? nTab1
- rPos
.Tab() : nTab1
;
330 if (rRef1
.Flags
.bRelName
&& rRef1
.Flags
.bTabRel
)
334 if (rRef2
.Flags
.bRelName
&& rRef2
.Flags
.bTabRel
)
338 bool bTmp
= rRef1
.Flags
.bTabRel
;
339 rRef1
.Flags
.bTabRel
= rRef2
.Flags
.bTabRel
;
340 rRef2
.Flags
.bTabRel
= bTmp
;
341 bTmp
= rRef1
.Flags
.bTabDeleted
;
342 rRef1
.Flags
.bTabDeleted
= rRef2
.Flags
.bTabDeleted
;
343 rRef2
.Flags
.bTabDeleted
= bTmp
;
346 // bFlag3D stays the same on both references.
348 rRef1
.Flags
.bRelName
= (nRelState1
!= 0);
349 rRef2
.Flags
.bRelName
= (nRelState2
!= 0);
352 bool ScSingleRefData::operator==( const ScSingleRefData
& r
) const
354 return mnFlagValue
== r
.mnFlagValue
&& mnCol
== r
.mnCol
&& mnRow
== r
.mnRow
&& mnTab
== r
.mnTab
;
357 bool ScSingleRefData::operator!=( const ScSingleRefData
& r
) const
359 return !operator==(r
);
362 #if DEBUG_FORMULA_COMPILER
363 void ScSingleRefData::Dump( int nIndent
) const
366 for (int i
= 0; i
< nIndent
; ++i
)
369 cout
<< aIndent
<< "address type column: " << (IsColRel()?"relative":"absolute")
370 << " row : " << (IsRowRel()?"relative":"absolute") << " sheet: "
371 << (IsTabRel()?"relative":"absolute") << endl
;
372 cout
<< aIndent
<< "deleted column: " << (IsColDeleted()?"yes":"no")
373 << " row : " << (IsRowDeleted()?"yes":"no") << " sheet: "
374 << (IsTabDeleted()?"yes":"no") << endl
;
375 cout
<< aIndent
<< "column: " << mnCol
<< " row: " << mnRow
<< " sheet: " << mnTab
<< endl
;
376 cout
<< aIndent
<< "3d ref: " << (IsFlag3D()?"yes":"no") << endl
;
380 void ScComplexRefData::InitFromRefAddresses( const ScDocument
& rDoc
, const ScRefAddress
& rRef1
, const ScRefAddress
& rRef2
, const ScAddress
& rPos
)
383 Ref1
.SetColRel( rRef1
.IsRelCol());
384 Ref1
.SetRowRel( rRef1
.IsRelRow());
385 Ref1
.SetTabRel( rRef1
.IsRelTab());
386 Ref1
.SetFlag3D( rRef1
.Tab() != rPos
.Tab() || rRef1
.Tab() != rRef2
.Tab());
387 Ref2
.SetColRel( rRef2
.IsRelCol());
388 Ref2
.SetRowRel( rRef2
.IsRelRow());
389 Ref2
.SetTabRel( rRef2
.IsRelTab());
390 Ref2
.SetFlag3D( rRef1
.Tab() != rRef2
.Tab());
391 SetRange( rDoc
.GetSheetLimits(), ScRange( rRef1
.GetAddress(), rRef2
.GetAddress()), rPos
);
394 ScComplexRefData
& ScComplexRefData::Extend( const ScSheetLimits
& rLimits
, const ScSingleRefData
& rRef
, const ScAddress
& rPos
)
396 bool bInherit3D
= (Ref1
.IsFlag3D() && !Ref2
.IsFlag3D() && !rRef
.IsFlag3D());
397 ScRange aAbsRange
= toAbs(rLimits
, rPos
);
399 ScSingleRefData aRef
= rRef
;
400 // If no sheet was given in the extending part, let it point to the same
401 // sheet as this reference's end point, inheriting the absolute/relative
403 // [$]Sheet1.A5:A6:A7 on Sheet2 do still reference only Sheet1.
404 if (!rRef
.IsFlag3D())
407 aRef
.SetRelTab( Ref2
.Tab());
409 aRef
.SetAbsTab( Ref2
.Tab());
411 ScAddress aAbs
= aRef
.toAbs(rLimits
, rPos
);
413 if (aAbs
.Col() < aAbsRange
.aStart
.Col())
414 aAbsRange
.aStart
.SetCol(aAbs
.Col());
416 if (aAbs
.Row() < aAbsRange
.aStart
.Row())
417 aAbsRange
.aStart
.SetRow(aAbs
.Row());
419 if (aAbs
.Tab() < aAbsRange
.aStart
.Tab())
420 aAbsRange
.aStart
.SetTab(aAbs
.Tab());
422 if (aAbsRange
.aEnd
.Col() < aAbs
.Col())
423 aAbsRange
.aEnd
.SetCol(aAbs
.Col());
425 if (aAbsRange
.aEnd
.Row() < aAbs
.Row())
426 aAbsRange
.aEnd
.SetRow(aAbs
.Row());
428 if (aAbsRange
.aEnd
.Tab() < aAbs
.Tab())
429 aAbsRange
.aEnd
.SetTab(aAbs
.Tab());
431 // In Ref2 inherit absolute/relative addressing from the extending part.
432 // A$5:A5 => A$5:A$5:A5 => A$5:A5, and not A$5:A$5
433 // A$6:$A5 => A$6:A$6:$A5 => A5:$A$6
434 if (aAbsRange
.aEnd
.Col() == aAbs
.Col())
435 Ref2
.SetColRel( rRef
.IsColRel());
436 if (aAbsRange
.aEnd
.Row() == aAbs
.Row())
437 Ref2
.SetRowRel( rRef
.IsRowRel());
439 // In Ref1 inherit relative sheet from extending part if given.
440 if (aAbsRange
.aStart
.Tab() == aAbs
.Tab() && rRef
.IsFlag3D())
441 Ref1
.SetTabRel( rRef
.IsTabRel());
443 // In Ref2 inherit relative sheet from either Ref1 or extending part.
444 // Use the original 3D flags to determine which.
445 // $Sheet1.$A$5:$A$6 => $Sheet1.$A$5:$A$5:$A$6 => $Sheet1.$A$5:$A$6, and
446 // not $Sheet1.$A$5:Sheet1.$A$6 (with invisible second 3D, but relative).
447 if (aAbsRange
.aEnd
.Tab() == aAbs
.Tab())
448 Ref2
.SetTabRel( bInherit3D
? Ref1
.IsTabRel() : rRef
.IsTabRel());
450 // Force 3D flag in Ref1 if different sheet or more than one sheet
452 if (aAbsRange
.aStart
.Tab() != rPos
.Tab() || aAbsRange
.aStart
.Tab() != aAbsRange
.aEnd
.Tab())
453 Ref1
.SetFlag3D(true);
455 // Force 3D flag in Ref2 if more than one sheet referenced.
456 if (aAbsRange
.aStart
.Tab() != aAbsRange
.aEnd
.Tab())
457 Ref2
.SetFlag3D(true);
459 // Inherit 3D flag in Ref1 from extending part in case range wasn't
460 // extended as in A5:A5:Sheet1.A5 if on Sheet1.
462 Ref1
.SetFlag3D( true);
464 // Inherit RelNameRef from extending part.
465 if (rRef
.IsRelName())
466 Ref2
.SetRelName(true);
468 SetRange(rLimits
, aAbsRange
, rPos
);
473 ScComplexRefData
& ScComplexRefData::Extend( const ScSheetLimits
& rLimits
, const ScComplexRefData
& rRef
, const ScAddress
& rPos
)
475 return Extend( rLimits
, rRef
.Ref1
, rPos
).Extend( rLimits
, rRef
.Ref2
, rPos
);
478 bool ScComplexRefData::Valid(const ScDocument
& rDoc
) const
480 return Ref1
.Valid(rDoc
) && Ref2
.Valid(rDoc
);
483 bool ScComplexRefData::ValidExternal(const ScDocument
& rDoc
) const
485 return Ref1
.ValidExternal(rDoc
) && Ref2
.ColValid(rDoc
) && Ref2
.RowValid(rDoc
) && Ref1
.Tab() <= Ref2
.Tab();
488 ScRange
ScComplexRefData::toAbs( const ScDocument
& rDoc
, const ScAddress
& rPos
) const
490 return toAbs(rDoc
.GetSheetLimits(), rPos
);
493 ScRange
ScComplexRefData::toAbs( const ScSheetLimits
& rLimits
, const ScAddress
& rPos
) const
495 return ScRange(Ref1
.toAbs(rLimits
, rPos
), Ref2
.toAbs(rLimits
, rPos
));
498 void ScComplexRefData::SetRange( const ScSheetLimits
& rLimits
, const ScRange
& rRange
, const ScAddress
& rPos
)
500 Ref1
.SetAddress(rLimits
, rRange
.aStart
, rPos
);
501 Ref2
.SetAddress(rLimits
, rRange
.aEnd
, rPos
);
504 void ScComplexRefData::PutInOrder( const ScAddress
& rPos
)
506 ScSingleRefData::PutInOrder( Ref1
, Ref2
, rPos
);
509 bool ScComplexRefData::IsEntireCol( const ScSheetLimits
& rLimits
) const
511 // Both row anchors must be absolute.
512 return Ref1
.Row() == 0 && Ref2
.Row() == rLimits
.MaxRow() && !Ref1
.IsRowRel() && !Ref2
.IsRowRel();
515 /** Whether this references entire rows, 1:1 */
516 bool ScComplexRefData::IsEntireRow( const ScSheetLimits
& rLimits
) const
518 // Both column anchors must be absolute.
519 return Ref1
.Col() == 0 && Ref2
.Col() == rLimits
.MaxCol() && !Ref1
.IsColRel() && !Ref2
.IsColRel();
522 bool ScComplexRefData::IncEndColSticky( const ScDocument
& rDoc
, SCCOL nDelta
, const ScAddress
& rPos
)
524 SCCOL nCol1
= Ref1
.IsColRel() ? Ref1
.Col() + rPos
.Col() : Ref1
.Col();
525 SCCOL nCol2
= Ref2
.IsColRel() ? Ref2
.Col() + rPos
.Col() : Ref2
.Col();
528 // Less than two columns => not sticky.
529 Ref2
.IncCol( nDelta
);
533 if (nCol2
== rDoc
.MaxCol())
537 if (nCol2
< rDoc
.MaxCol())
539 SCCOL nCol
= ::std::min( static_cast<SCCOL
>(nCol2
+ nDelta
), rDoc
.MaxCol());
541 Ref2
.SetRelCol( nCol
- rPos
.Col());
543 Ref2
.SetAbsCol( nCol
);
546 Ref2
.IncCol( nDelta
); // was greater than rDoc.MaxCol(), caller should know...
551 bool ScComplexRefData::IncEndRowSticky( const ScDocument
& rDoc
, SCROW nDelta
, const ScAddress
& rPos
)
553 SCROW nRow1
= Ref1
.IsRowRel() ? Ref1
.Row() + rPos
.Row() : Ref1
.Row();
554 SCROW nRow2
= Ref2
.IsRowRel() ? Ref2
.Row() + rPos
.Row() : Ref2
.Row();
557 // Less than two rows => not sticky.
558 Ref2
.IncRow( nDelta
);
562 if (nRow2
== rDoc
.MaxRow())
566 if (nRow2
< rDoc
.MaxRow())
568 SCROW nRow
= ::std::min( static_cast<SCROW
>(nRow2
+ nDelta
), rDoc
.MaxRow());
570 Ref2
.SetRelRow( nRow
- rPos
.Row());
572 Ref2
.SetAbsRow( nRow
);
575 Ref2
.IncRow( nDelta
); // was greater than rDoc.MaxRow(), caller should know...
580 bool ScComplexRefData::IsDeleted() const
582 return Ref1
.IsDeleted() || Ref2
.IsDeleted();
585 #if DEBUG_FORMULA_COMPILER
586 void ScComplexRefData::Dump( int nIndent
) const
589 for (int i
= 0; i
< nIndent
; ++i
)
592 cout
<< aIndent
<< "ref 1" << endl
;
593 Ref1
.Dump(nIndent
+1);
594 cout
<< aIndent
<< "ref 2" << endl
;
595 Ref2
.Dump(nIndent
+1);
599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */