tdf#148170 - Convert print range to an excel cell range
During export from Calc to XLS, ensure that the print range
is converted to a valid XLS print range. If the print range
exceeds XLS format limitations, it will be appropriately cropped
to fit within the constraints.
Change-Id: I2b233e4d57dfbe30f491448d2ee2972b8b717ea3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164469
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx
index 41d76cc..ff453d2 100644
--- a/sc/qa/unit/subsequent_export_test4.cxx
+++ b/sc/qa/unit/subsequent_export_test4.cxx
@@ -761,6 +761,26 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf51022_lostPrintRange)
CPPUNIT_ASSERT_EQUAL(aRange2, *pDoc->GetPrintRange(0, 1));
}
CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf148170_ExceedXlsPrintRange)
{
createScDoc();
// Create print range that exceeds the xls limitations
const auto aScSheeLimits = ScSheetLimits::CreateDefault();
ScRange aCalcPrintRange(0, 0, 0, aScSheeLimits.MaxCol(), aScSheeLimits.MaxRow(), 0);
ScDocument* pDoc = getScDoc();
pDoc->AddPrintRange(0, aCalcPrintRange);
saveAndReload("MS Excel 97");
// Check if print range was shrunk to xls limitations
pDoc = getScDoc();
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pDoc->GetPrintRangeCount(0));
// Check sc/source/filter/inc/xlconst.hxx for xls limitations
ScRange aXlsPrintRange(0, 0, 0, 16383, 65535, 0);
CPPUNIT_ASSERT_EQUAL(aXlsPrintRange, *pDoc->GetPrintRange(0, 0));
}
CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf138741_externalLinkSkipUnusedsCrash)
{
createScDoc("xlsx/tdf138741_externalLinkSkipUnusedsCrash.xlsx");
diff --git a/sc/source/filter/excel/xename.cxx b/sc/source/filter/excel/xename.cxx
index 84073da..8d97ffaa 100644
--- a/sc/source/filter/excel/xename.cxx
+++ b/sc/source/filter/excel/xename.cxx
@@ -36,6 +36,7 @@
#include <oox/export/utils.hxx>
#include <oox/token/tokens.hxx>
#include <com/sun/star/sheet/NamedRangeFlag.hdl>
#include <xihelper.hxx>
using namespace ::oox;
using namespace ::com::sun::star;
@@ -713,10 +714,17 @@ void XclExpNameManagerImpl::CreateBuiltInNames()
aRange.aStart.SetTab( nScTab );
aRange.aEnd.SetTab( nScTab );
aRange.PutInOrder();
aRangeList.push_back( aRange );
// tdf#148170 - convert print range to an excel cell range
XclRange aXclRange(ScAddress::UNINITIALIZED);
// create no warning if ranges are shrunken
if (GetAddressConverter().ConvertRange(aXclRange, aRange, false))
{
XclImpAddressConverter::FillRange(aXclRange, aRange);
aRangeList.push_back(aRange);
}
}
// create the NAME record (do not warn if ranges are shrunken)
GetAddressConverter().ValidateRangeList( aRangeList, false );
// create the NAME record
if( !aRangeList.empty() )
GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTAREA, aRangeList );
}
diff --git a/sc/source/filter/excel/xihelper.cxx b/sc/source/filter/excel/xihelper.cxx
index e095d22..2f05d67 100644
--- a/sc/source/filter/excel/xihelper.cxx
+++ b/sc/source/filter/excel/xihelper.cxx
@@ -98,6 +98,14 @@ ScAddress XclImpAddressConverter::CreateValidAddress(
// cell range -----------------------------------------------------------------
void XclImpAddressConverter::FillRange(const XclRange& rXclRange, ScRange& rScRange)
{
const XclAddress aXclStartAdr = rXclRange.maFirst;
lclFillAddress(rScRange.aStart, aXclStartAdr.mnCol, aXclStartAdr.mnRow, rScRange.aStart.Tab());
const XclAddress aXclEndAdr = rXclRange.maLast;
lclFillAddress(rScRange.aEnd, aXclEndAdr.mnCol, aXclEndAdr.mnRow, rScRange.aEnd.Tab());
}
bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
{
diff --git a/sc/source/filter/inc/xihelper.hxx b/sc/source/filter/inc/xihelper.hxx
index 746259e..fe6ba7c 100644
--- a/sc/source/filter/inc/xihelper.hxx
+++ b/sc/source/filter/inc/xihelper.hxx
@@ -71,6 +71,11 @@ public:
// cell range -------------------------------------------------------------
/** Fills the passed Calc cell range with the passed Excel cell range.
@param XclRange The Excel cell range to be transfered.
@param ScRange (Out) The filled Calc cell range. */
static void FillRange(const XclRange& rXclRange, ScRange& rScRange);
/** Converts the passed Excel cell range to a Calc cell range.
@param rScRange (Out) The converted Calc cell range, if valid.
@param rXclRange The Excel cell range to convert.