diff --git a/sc/CppunitTest_sc_uicalc2.mk b/sc/CppunitTest_sc_uicalc2.mk
index 991ecc846108..84848c35c838 100644
--- a/sc/CppunitTest_sc_uicalc2.mk
+++ b/sc/CppunitTest_sc_uicalc2.mk
@@ -36,6 +36,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_uicalc2, \
svx \
svxcore \
test \
+ tk \
tl \
unotest \
utl \
diff --git a/sc/qa/unit/uicalc/data/tdf171366.fods b/sc/qa/unit/uicalc/data/tdf171366.fods
new file mode 100644
index 000000000000..04d76dddaf03
--- /dev/null
+++ b/sc/qa/unit/uicalc/data/tdf171366.fods
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ row1
+ row2
+ row3
+ row4
+ row5
+ row6
+ row7
+ row8
+ row9
+ row10
+ row11
+ row12
+ row13
+ row14
+ row15
+ row16
+ row17
+ row18
+ row19
+ row20
+ row21
+ row22
+ row23
+ row24
+ row25
+ row26
+ row27
+ row28
+ row29
+ row30
+ row31
+ row32
+ row33
+ row34
+ row35
+ row36
+ row37
+ row38
+ row39
+ row40
+ row41
+ row42
+ row43
+ row44
+ row45
+ row46
+ row47
+ row48
+ row49
+ row50
+ row51
+ row52
+ row53
+ row54
+ row55
+ row56
+ row57
+ row58
+ row59
+ row60
+ row61
+ row62
+ row63
+ row64
+ row65
+ row66
+ row67
+ row68
+ row69
+ row70
+ row71
+ row72
+ row73
+ row74
+ row75
+ row76
+ row77
+ row78
+ row79
+ row80
+ row81
+ row82
+ row83
+ row84
+ row85
+ row86
+ row87
+ row88
+ row89
+ row90
+ row91
+ row92
+ row93
+ row94
+ row95
+ row96
+ row97
+ row98
+ row99
+ row100
+
+
+
+
diff --git a/sc/qa/unit/uicalc/uicalc2.cxx b/sc/qa/unit/uicalc/uicalc2.cxx
index f21aa1e882c2..65d66b2ed9b9 100644
--- a/sc/qa/unit/uicalc/uicalc2.cxx
+++ b/sc/qa/unit/uicalc/uicalc2.cxx
@@ -14,23 +14,33 @@
#include
#include
#include
+#include
+#include
#include
#include
+#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -2595,6 +2605,120 @@ CPPUNIT_TEST_FIXTURE(ScUiCalcTest2, testSetHyperlinkKeepSelection)
CPPUNIT_ASSERT_EQUAL(u"foo"_ustr, pURLField->GetRepresentation());
}
+namespace
+{
+// Prints the document once and collects the cell text of each page, in drawing order. The
+// printer records into a metafile, so this is the text that would have reached the paper.
+std::vector>
+lcl_getPrintedPages(const uno::Reference& xComponent, Printer* pPrinter)
+{
+ rtl::Reference pVclDevice = new VCLXDevice();
+ pVclDevice->SetOutputDevice(pPrinter);
+
+ uno::Reference xRenderable(xComponent, uno::UNO_QUERY_THROW);
+ css::uno::Any aSelection(xComponent);
+
+ std::vector aOptions{
+ comphelper::makePropertyValue(u"RenderDevice"_ustr,
+ uno::Reference(pVclDevice)),
+ comphelper::makePropertyValue(u"IsPrinter"_ustr, true),
+ comphelper::makePropertyValue(u"IsLastPage"_ustr, false),
+ };
+
+ sal_Int32 nPages
+ = xRenderable->getRendererCount(aSelection, comphelper::containerToSequence(aOptions));
+
+ std::vector> aPages;
+ for (sal_Int32 nPage = 0; nPage < nPages; ++nPage)
+ {
+ aOptions.back().Value <<= (nPage + 1 == nPages);
+ css::uno::Sequence aSequence
+ = comphelper::containerToSequence(aOptions);
+
+ GDIMetaFile aMetaFile;
+ pPrinter->SetConnectMetaFile(&aMetaFile);
+ xRenderable->getRenderer(nPage, aSelection, aSequence);
+ xRenderable->render(nPage, aSelection, aSequence);
+ pPrinter->SetConnectMetaFile(nullptr);
+
+ std::vector aTexts;
+ for (size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction)
+ {
+ MetaAction* pAction = aMetaFile.GetAction(nAction);
+ OUString aText;
+ if (pAction->GetType() == MetaActionType::TEXTARRAY)
+ aText = static_cast(pAction)->GetText();
+ else if (pAction->GetType() == MetaActionType::TEXT)
+ aText = static_cast(pAction)->GetText();
+ else if (pAction->GetType() == MetaActionType::STRETCHTEXT)
+ aText = static_cast(pAction)->GetText();
+ if (aText.startsWith(u"row"))
+ aTexts.push_back(aText);
+ }
+ aPages.push_back(std::move(aTexts));
+ }
+ return aPages;
+}
+
+// Names the first and the last cell of every page on one line. A failure then shows which rows
+// each page carried.
+OUString lcl_describePages(const std::vector>& rPages)
+{
+ OUStringBuffer aBuffer;
+ for (const auto& rPage : rPages)
+ {
+ if (!aBuffer.isEmpty())
+ aBuffer.append(" ");
+ if (rPage.empty())
+ aBuffer.append("empty");
+ else
+ aBuffer.append(rPage.front() + ".." + rPage.back());
+ }
+ return aBuffer.makeStringAndClear();
+}
+}
+
+CPPUNIT_TEST_FIXTURE(ScUiCalcTest2, testTdf171366)
+{
+ // The sheet holds 100 rows on A4 portrait paper. That is few enough per landscape page that
+ // the two orientations break the sheet at different rows.
+ createScDoc("tdf171366.fods");
+
+ // The view shell hands back the document's own printer, which is the one a print job uses.
+ SfxViewShell* pViewShell = getViewShell();
+ SfxPrinter* pPrinter = pViewShell->GetPrinter(true);
+ CPPUNIT_ASSERT(pPrinter);
+
+ // The Print Dialog turns the paper size itself and hands it on in 1/100 mm.
+ const Size aTurnedPaper(29700, 21001);
+
+ // The user chooses Landscape in the Print Dialog. The dialog gives the printer the turned
+ // size and marks the printer as carrying a setting of its own.
+ pPrinter->SetPrintPageSize(aTurnedPaper);
+ pPrinter->SetOrientation(Orientation::Landscape);
+ pPrinter->SetUsePrintDialogSetting(true);
+ const OUString aFromDialog = lcl_describePages(lcl_getPrintedPages(mxComponent, pPrinter));
+
+ // The user makes the same turn in Format - Page Style instead. That path always worked.
+ pPrinter->SetUsePrintDialogSetting(false);
+ uno::Reference xSupplier(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Reference xPageStyles(
+ xSupplier->getStyleFamilies()->getByName(u"PageStyles"_ustr), uno::UNO_QUERY_THROW);
+ uno::Reference xPageStyle(xPageStyles->getByName(u"Default"_ustr),
+ uno::UNO_QUERY_THROW);
+ xPageStyle->setPropertyValue(u"IsLandscape"_ustr, css::uno::Any(true));
+ xPageStyle->setPropertyValue(
+ u"Size"_ustr, css::uno::Any(awt::Size(aTurnedPaper.Width(), aTurnedPaper.Height())));
+ const OUString aFromPageStyle = lcl_describePages(lcl_getPrintedPages(mxComponent, pPrinter));
+
+ // Turning the paper in the Print Dialog splits the sheet the same way as turning it in the
+ // page style. Without the accompanying fix, only the first page was laid out for landscape
+ // paper and the rest kept the portrait splits, so this test failed with:
+ // - Expected: row1..row37 row38..row74 row75..row100
+ // - Actual : row1..row37 row57..row100 empty
+ CPPUNIT_ASSERT_EQUAL(aFromPageStyle, aFromDialog);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/printfun.hxx b/sc/source/ui/inc/printfun.hxx
index 2fa314daed79..539f868ddb56 100644
--- a/sc/source/ui/inc/printfun.hxx
+++ b/sc/source/ui/inc/printfun.hxx
@@ -174,7 +174,9 @@ public:
size_t m_nPagesY;
size_t m_nTotalY;
- PrintPageRangesInput m_aInput;
+ // The ranges above were calculated for this input. Every copy shares both, so the input
+ // always matches the result.
+ std::shared_ptr m_pInput;
void calculate(ScDocument& rDoc, PrintPageRangesInput const& rInput);
};
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 9efeea10b9d2..6f5d2ea239b3 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -2928,19 +2928,6 @@ void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelec
(void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, true, nullptr );
- if (pPrinter)
- {
- // reset the print area created by the Print Dialog to the page style's print area
- if (pPrinter->IsUsePrintDialogSetting())
- {
- bUsePrintDialogSetting = false;
- if (m_pPrintState && m_pPrintState->nPrintTab == nTab && !pSelRange)
- pPrintFunc.reset(new ScPrintFunc(pDev, *pDocShell, *m_pPrintState,
- &aStatus.GetOptions(), aPrintPageSize,
- bPrintPageLandscape, bUsePrintDialogSetting));
- }
- }
-
vcl::PDFExtOutDevData* pPDFData = dynamic_cast(pDev->GetExtOutDevData());
const bool bFinishTagging(pPDFData && pPDFData->GetIsExportTaggedPDF() && bIsLastPage);
if (bFinishTagging)
@@ -2956,6 +2943,12 @@ void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelec
if (bFinishTagging)
lcl_PDFExportFinishTagging(*pPDFData);
+
+ // The document carried the Print Dialog's paper size and orientation for the length of the
+ // job. A last count after the final page puts back the page size and the page breaks that
+ // the page style describes.
+ if (pPrinter && pPrinter->IsUsePrintDialogSetting() && bIsLastPage)
+ pPrintFuncCache.reset(new ScPrintFuncCache(*pDocShell, aMark, aStatus));
}
// XLinkTargetSupplier
diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx
index ae8ef36a4453..0ae390238e3a 100644
--- a/sc/source/ui/view/printfun.cxx
+++ b/sc/source/ui/view/printfun.cxx
@@ -3072,17 +3072,18 @@ PrintPageRanges::PrintPageRanges()
: m_nPagesX(0)
, m_nPagesY(0)
, m_nTotalY(0)
+ , m_pInput(std::make_shared())
{}
void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rInput)
{
// Already calculated?
- if (m_aInput == rInput)
+ if (*m_pInput == rInput)
return;
- m_aInput = rInput;
+ *m_pInput = rInput;
- rDoc.SetPageSize(m_aInput.getPrintTab(), m_aInput.m_aDocSize);
+ rDoc.SetPageSize(m_pInput->getPrintTab(), m_pInput->m_aDocSize);
// Clear the map to prevent any outdated values to "survive" when
// we have to recalculate the new values anyway
@@ -3094,17 +3095,18 @@ void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rI
m_xPageEndX->resize(rDoc.MaxCol()+1, SCCOL());
}
- if (m_aInput.m_bPrintArea)
+ if (m_pInput->m_bPrintArea)
{
- ScRange aRange(m_aInput.getStartColumn(), m_aInput.getStartRow(), m_aInput.getPrintTab(), m_aInput.getEndColumn(), m_aInput.getEndRow(), m_aInput.getPrintTab());
- rDoc.UpdatePageBreaks(m_aInput.getPrintTab(), &aRange);
+ ScRange aRange(m_pInput->getStartColumn(), m_pInput->getStartRow(), m_pInput->getPrintTab(),
+ m_pInput->getEndColumn(), m_pInput->getEndRow(), m_pInput->getPrintTab());
+ rDoc.UpdatePageBreaks(m_pInput->getPrintTab(), &aRange);
}
else
{
- rDoc.UpdatePageBreaks(m_aInput.getPrintTab()); // else, end is marked
+ rDoc.UpdatePageBreaks(m_pInput->getPrintTab()); // else, end is marked
}
- const size_t nRealCnt = m_aInput.getEndRow() - m_aInput.getStartRow() + 1;
+ const size_t nRealCnt = m_pInput->getEndRow() - m_pInput->getStartRow() + 1;
// #i123672# use dynamic mem to react on size changes
if (m_xPageEndY->size() < nRealCnt+1)
@@ -3120,11 +3122,11 @@ void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rI
m_nTotalY = 0;
bool bVisCol = false;
- for (SCCOL i = m_aInput.getStartColumn(); i <= m_aInput.getEndColumn(); i++)
+ for (SCCOL i = m_pInput->getStartColumn(); i <= m_pInput->getEndColumn(); i++)
{
- bool bHidden = rDoc.ColHidden(i, m_aInput.getPrintTab());
- bool bPageBreak(rDoc.HasColBreak(i, m_aInput.getPrintTab()) & ScBreakType::Page);
- if (i > m_aInput.getStartColumn() && bVisCol && bPageBreak)
+ bool bHidden = rDoc.ColHidden(i, m_pInput->getPrintTab());
+ bool bPageBreak(rDoc.HasColBreak(i, m_pInput->getPrintTab()) & ScBreakType::Page);
+ if (i > m_pInput->getStartColumn() && bVisCol && bPageBreak)
{
OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
(*m_xPageEndX)[m_nPagesX] = i-1;
@@ -3137,40 +3139,45 @@ void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rI
if (bVisCol) // also at the end, no empty pages
{
OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
- (*m_xPageEndX)[m_nPagesX] = m_aInput.getEndColumn();
+ (*m_xPageEndX)[m_nPagesX] = m_pInput->getEndColumn();
++m_nPagesX;
}
bool bVisRow = false;
- SCROW nPageStartRow = m_aInput.getStartRow();
+ SCROW nPageStartRow = m_pInput->getStartRow();
SCROW nLastVisibleRow = -1;
- std::unique_ptr pRowBreakIter(rDoc.GetRowBreakIterator(m_aInput.getPrintTab()));
+ std::unique_ptr pRowBreakIter(
+ rDoc.GetRowBreakIterator(m_pInput->getPrintTab()));
SCROW nNextPageBreak = pRowBreakIter->first();
- while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND && nNextPageBreak < m_aInput.getStartRow())
+ while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND
+ && nNextPageBreak < m_pInput->getStartRow())
// Skip until the page break position is at the start row or greater.
nNextPageBreak = pRowBreakIter->next();
- for (SCROW nRow = m_aInput.getStartRow(); nRow <= m_aInput.getEndRow(); ++nRow)
+ for (SCROW nRow = m_pInput->getStartRow(); nRow <= m_pInput->getEndRow(); ++nRow)
{
bool bPageBreak = (nNextPageBreak == nRow);
if (bPageBreak)
nNextPageBreak = pRowBreakIter->next();
- if (nRow > m_aInput.getStartRow() && bVisRow && bPageBreak)
+ if (nRow > m_pInput->getStartRow() && bVisRow && bPageBreak)
{
OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for rPageEndY");
(*m_xPageEndY)[m_nTotalY] = nRow - 1;
++m_nTotalY;
- if (!m_aInput.m_bSkipEmpty || !rDoc.IsPrintEmpty(m_aInput.getStartColumn(), nPageStartRow, m_aInput.getEndColumn(), nRow-1, m_aInput.getPrintTab()))
+ if (!m_pInput->m_bSkipEmpty
+ || !rDoc.IsPrintEmpty(m_pInput->getStartColumn(), nPageStartRow,
+ m_pInput->getEndColumn(), nRow-1, m_pInput->getPrintTab()))
{
auto& rPageRow = (*m_xPageRows)[m_nPagesY];
rPageRow.SetStartRow(nPageStartRow);
rPageRow.SetEndRow(nRow - 1);
rPageRow.SetPagesX(m_nPagesX);
- if (m_aInput.m_bSkipEmpty)
- lcl_SetHidden(rDoc, m_aInput.getPrintTab(), rPageRow, m_aInput.getStartColumn(), *m_xPageEndX);
+ if (m_pInput->m_bSkipEmpty)
+ lcl_SetHidden(rDoc, m_pInput->getPrintTab(), rPageRow,
+ m_pInput->getStartColumn(), *m_xPageEndX);
++m_nPagesY;
}
@@ -3187,7 +3194,7 @@ void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rI
}
SCROW nLastRow = -1;
- if (!rDoc.RowHidden(nRow, m_aInput.getPrintTab(), nullptr, &nLastRow))
+ if (!rDoc.RowHidden(nRow, m_pInput->getPrintTab(), nullptr, &nLastRow))
{
bVisRow = true;
nLastVisibleRow = nLastRow;
@@ -3204,17 +3211,20 @@ void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rI
return;
OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for maPageEndY");
- (*m_xPageEndY)[m_nTotalY] = m_aInput.getEndRow();
+ (*m_xPageEndY)[m_nTotalY] = m_pInput->getEndRow();
++m_nTotalY;
- if (!m_aInput.m_bSkipEmpty || !rDoc.IsPrintEmpty(m_aInput.getStartColumn(), nPageStartRow, m_aInput.getEndColumn(), m_aInput.getEndRow(), m_aInput.getPrintTab()))
+ if (!m_pInput->m_bSkipEmpty
+ || !rDoc.IsPrintEmpty(m_pInput->getStartColumn(), nPageStartRow, m_pInput->getEndColumn(),
+ m_pInput->getEndRow(), m_pInput->getPrintTab()))
{
auto& rPageRow = (*m_xPageRows)[m_nPagesY];
rPageRow.SetStartRow(nPageStartRow);
- rPageRow.SetEndRow(m_aInput.getEndRow());
+ rPageRow.SetEndRow(m_pInput->getEndRow());
rPageRow.SetPagesX(m_nPagesX);
- if (m_aInput.m_bSkipEmpty)
- lcl_SetHidden(rDoc, m_aInput.getPrintTab(), rPageRow, m_aInput.getStartColumn(), *m_xPageEndX);
+ if (m_pInput->m_bSkipEmpty)
+ lcl_SetHidden(rDoc, m_pInput->getPrintTab(), rPageRow, m_pInput->getStartColumn(),
+ *m_xPageEndX);
++m_nPagesY;
}
}