summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/view/printfun.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/view/printfun.cxx')
-rw-r--r--sc/source/ui/view/printfun.cxx3229
1 files changed, 3229 insertions, 0 deletions
diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx
new file mode 100644
index 000000000..3cb543a8f
--- /dev/null
+++ b/sc/source/ui/view/printfun.cxx
@@ -0,0 +1,3229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <printfun.hxx>
+
+#include <editeng/adjustitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/editstat.hxx>
+#include <svx/fmview.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/pbinitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <sfx2/printer.hxx>
+#include <tools/multisel.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <editutil.hxx>
+#include <docsh.hxx>
+#include <output.hxx>
+#include <viewdata.hxx>
+#include <viewopti.hxx>
+#include <stlpool.hxx>
+#include <pagepar.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <dociter.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <pagedata.hxx>
+#include <printopt.hxx>
+#include <prevloc.hxx>
+#include <scmod.hxx>
+#include <drwlayer.hxx>
+#include <fillinfo.hxx>
+#include <postit.hxx>
+
+#include <memory>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#define ZOOM_MIN 10
+
+namespace{
+
+bool lcl_GetBool(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return static_cast<const SfxBoolItem&>(pSet->Get(nWhich)).GetValue();
+}
+
+sal_uInt16 lcl_GetUShort(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return static_cast<const SfxUInt16Item&>(pSet->Get(nWhich)).GetValue();
+}
+
+bool lcl_GetShow(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return ScVObjMode::VOBJ_MODE_SHOW == static_cast<const ScViewObjectModeItem&>(pSet->Get(nWhich)).GetValue();
+}
+
+
+} // namespace
+
+ScPageRowEntry::ScPageRowEntry(const ScPageRowEntry& r)
+{
+ nStartRow = r.nStartRow;
+ nEndRow = r.nEndRow;
+ nPagesX = r.nPagesX;
+ aHidden = r.aHidden;
+ aHidden.resize(nPagesX, false);
+}
+
+ScPageRowEntry& ScPageRowEntry::operator=(const ScPageRowEntry& r)
+{
+ nStartRow = r.nStartRow;
+ nEndRow = r.nEndRow;
+ nPagesX = r.nPagesX;
+ aHidden = r.aHidden;
+ aHidden.resize(nPagesX, false);
+ return *this;
+}
+
+void ScPageRowEntry::SetPagesX(size_t nNew)
+{
+ nPagesX = nNew;
+ aHidden.resize(nPagesX, false);
+}
+
+void ScPageRowEntry::SetHidden(size_t nX)
+{
+ if ( nX < nPagesX )
+ {
+ if ( nX+1 == nPagesX ) // last page?
+ --nPagesX;
+ else
+ {
+ aHidden.resize(nPagesX, false);
+ aHidden[nX] = true;
+ }
+ }
+}
+
+bool ScPageRowEntry::IsHidden(size_t nX) const
+{
+ return nX >= nPagesX || aHidden[nX]; //! inline?
+}
+
+size_t ScPageRowEntry::CountVisible() const
+{
+ if (!aHidden.empty())
+ {
+ size_t nVis = 0;
+ for (size_t i=0; i<nPagesX; i++)
+ if (!aHidden[i])
+ ++nVis;
+ return nVis;
+ }
+ else
+ return nPagesX;
+}
+
+static tools::Long lcl_LineTotal(const ::editeng::SvxBorderLine* pLine)
+{
+ return pLine ? ( pLine->GetScaledWidth() ) : 0;
+}
+
+void ScPrintFunc::Construct( const ScPrintOptions* pOptions )
+{
+ pDocShell->UpdatePendingRowHeights( nPrintTab );
+
+ SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use the printer, even for preview
+ if (pDocPrinter)
+ aOldPrinterMode = pDocPrinter->GetMapMode();
+
+ // unified MapMode for all calls (e.g. Repaint!!!)
+ // else, EditEngine outputs different text heights
+ pDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ pBorderItem = nullptr;
+ pBackgroundItem = nullptr;
+ pShadowItem = nullptr;
+
+ pEditEngine = nullptr;
+ pEditDefaults = nullptr;
+
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find(
+ rDoc.GetPageStyle( nPrintTab ),
+ SfxStyleFamily::Page );
+ if (pStyleSheet)
+ pParamSet = &pStyleSheet->GetItemSet();
+ else
+ {
+ OSL_FAIL("Template not found" );
+ pParamSet = nullptr;
+ }
+
+ if (!bFromPrintState)
+ nZoom = 100;
+ nManualZoom = 100;
+ bClearWin = false;
+ bUseStyleColor = false;
+ bIsRender = false;
+
+ InitParam(pOptions);
+
+ pPageData = nullptr; // is only needed for initialisation
+}
+
+ScPrintFunc::ScPrintFunc( ScDocShell* pShell, SfxPrinter* pNewPrinter, SCTAB nTab,
+ tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
+ const ScPrintOptions* pOptions,
+ ScPageBreakData* pData )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( pNewPrinter ),
+ pDrawView ( nullptr ),
+ nPrintTab ( nTab ),
+ nPageStart ( nPage ),
+ nDocPages ( nDocP ),
+ pUserArea ( pArea ),
+ bFromPrintState ( false ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ nTabPages ( 0 ),
+ nTotalPages ( 0 ),
+ bPrintAreaValid ( false ),
+ pPageData ( pData )
+{
+ pDev = pPrinter.get();
+ aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc(ScDocShell* pShell, SfxPrinter* pNewPrinter,
+ const ScPrintState& rState, const ScPrintOptions* pOptions)
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( pNewPrinter ),
+ pDrawView ( nullptr ),
+ pUserArea ( nullptr ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ pPageData ( nullptr )
+{
+ pDev = pPrinter.get();
+
+ nPrintTab = rState.nPrintTab;
+ nStartCol = rState.nStartCol;
+ nStartRow = rState.nStartRow;
+ nEndCol = rState.nEndCol;
+ nEndRow = rState.nEndRow;
+ bPrintAreaValid = rState.bPrintAreaValid;
+ nZoom = rState.nZoom;
+ m_aRanges.m_nPagesX = rState.nPagesX;
+ m_aRanges.m_nPagesY = rState.nPagesY;
+ nTabPages = rState.nTabPages;
+ nTotalPages = rState.nTotalPages;
+ nPageStart = rState.nPageStart;
+ nDocPages = rState.nDocPages;
+ bFromPrintState = true;
+
+ if (rState.bSavedStateRanges)
+ {
+ m_aRanges.m_nTotalY = rState.nTotalY;
+ m_aRanges.m_xPageEndX = rState.xPageEndX;
+ m_aRanges.m_xPageEndY = rState.xPageEndY;
+ m_aRanges.m_xPageRows = rState.xPageRows;
+ m_aRanges.m_aInput = rState.aPrintPageRangesInput;
+ }
+ else
+ {
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ }
+
+ aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell, SCTAB nTab,
+ tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
+ const ScPrintOptions* pOptions )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( nullptr ),
+ pDrawView ( nullptr ),
+ nPrintTab ( nTab ),
+ nPageStart ( nPage ),
+ nDocPages ( nDocP ),
+ pUserArea ( pArea ),
+ bFromPrintState ( false ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ nTabPages ( 0 ),
+ nTotalPages ( 0 ),
+ bPrintAreaValid ( false ),
+ pPageData ( nullptr )
+{
+ pDev = pOutDev;
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell,
+ const ScPrintState& rState, const ScPrintOptions* pOptions )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( nullptr ),
+ pDrawView ( nullptr ),
+ pUserArea ( nullptr ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ pPageData ( nullptr )
+{
+ pDev = pOutDev;
+
+ nPrintTab = rState.nPrintTab;
+ nStartCol = rState.nStartCol;
+ nStartRow = rState.nStartRow;
+ nEndCol = rState.nEndCol;
+ nEndRow = rState.nEndRow;
+ bPrintAreaValid = rState.bPrintAreaValid;
+ nZoom = rState.nZoom;
+ m_aRanges.m_nPagesX = rState.nPagesX;
+ m_aRanges.m_nPagesY = rState.nPagesY;
+ nTabPages = rState.nTabPages;
+ nTotalPages = rState.nTotalPages;
+ nPageStart = rState.nPageStart;
+ nDocPages = rState.nDocPages;
+ bFromPrintState = true;
+
+ if (rState.bSavedStateRanges)
+ {
+ m_aRanges.m_nTotalY = rState.nTotalY;
+ m_aRanges.m_xPageEndX = rState.xPageEndX;
+ m_aRanges.m_xPageEndY = rState.xPageEndY;
+ m_aRanges.m_xPageRows = rState.xPageRows;
+ m_aRanges.m_aInput = rState.aPrintPageRangesInput;
+ }
+ else
+ {
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ }
+
+ Construct( pOptions );
+}
+
+void ScPrintFunc::GetPrintState(ScPrintState& rState, bool bSavePageRanges)
+{
+ rState.nPrintTab = nPrintTab;
+ rState.nStartCol = nStartCol;
+ rState.nStartRow = nStartRow;
+ rState.nEndCol = nEndCol;
+ rState.nEndRow = nEndRow;
+ rState.bPrintAreaValid = bPrintAreaValid;
+ rState.nZoom = nZoom;
+ rState.nPagesX = m_aRanges.m_nPagesX;
+ rState.nPagesY = m_aRanges.m_nPagesY;
+ rState.nTabPages = nTabPages;
+ rState.nTotalPages = nTotalPages;
+ rState.nPageStart = nPageStart;
+ rState.nDocPages = nDocPages;
+ if (bSavePageRanges)
+ {
+ rState.bSavedStateRanges = true;
+ rState.nTotalY = m_aRanges.m_nTotalY;
+ rState.xPageEndX = m_aRanges.m_xPageEndX;
+ rState.xPageEndY = m_aRanges.m_xPageEndY;
+ rState.xPageRows = m_aRanges.m_xPageRows;
+ rState.aPrintPageRangesInput = m_aRanges.m_aInput;
+ }
+}
+
+bool ScPrintFunc::GetLastSourceRange( ScRange& rRange ) const
+{
+ rRange = aLastSourceRange;
+ return bSourceRangeValid;
+}
+
+void ScPrintFunc::FillPageData()
+{
+ if (!pPageData)
+ return;
+
+ sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
+ ScPrintRangeData& rData = pPageData->GetData(nCount); // count up
+
+ assert( bPrintAreaValid );
+ rData.SetPrintRange( ScRange( nStartCol, nStartRow, nPrintTab,
+ nEndCol, nEndRow, nPrintTab ) );
+ // #i123672#
+ if(m_aRanges.m_xPageEndX->empty())
+ {
+ OSL_ENSURE(false, "vector access error for maPageEndX (!)");
+ }
+ else
+ {
+ rData.SetPagesX( m_aRanges.m_nPagesX, m_aRanges.m_xPageEndX->data());
+ }
+
+ // #i123672#
+ if(m_aRanges.m_xPageEndY->empty())
+ {
+ OSL_ENSURE(false, "vector access error for maPageEndY (!)");
+ }
+ else
+ {
+ rData.SetPagesY( m_aRanges.m_nTotalY, m_aRanges.m_xPageEndY->data());
+ }
+
+ // Settings
+ rData.SetTopDown( aTableParam.bTopDown );
+ rData.SetAutomatic( !aAreaParam.bPrintArea );
+}
+
+ScPrintFunc::~ScPrintFunc()
+{
+ pEditDefaults.reset();
+ pEditEngine.reset();
+
+ // Printer settings are now restored from outside
+
+ // For DrawingLayer/Charts, the MapMode of the printer (RefDevice) must always be correct
+ SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use Preview also for the printer
+ if (pDocPrinter)
+ pDocPrinter->SetMapMode(aOldPrinterMode);
+}
+
+void ScPrintFunc::SetDrawView( FmFormView* pNew )
+{
+ pDrawView = pNew;
+}
+
+static void lcl_HidePrint( const ScTableInfo& rTabInfo, SCCOL nX1, SCCOL nX2 )
+{
+ for (SCSIZE nArrY=1; nArrY+1<rTabInfo.mnArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &rTabInfo.mpRowInfo[nArrY];
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nX);
+ ScBasicCellInfo& rBasicCellInfo = pThisRowInfo->basicCellInfo(nX);
+ if (!rBasicCellInfo.bEmptyCellText)
+ if (rCellInfo.pPatternAttr->
+ GetItem(ATTR_PROTECTION, rCellInfo.pConditionSet).GetHidePrint())
+ {
+ rCellInfo.maCell.clear();
+ rBasicCellInfo.bEmptyCellText = true;
+ }
+ }
+ }
+}
+
+// output to Device (static)
+//
+// us used for:
+// - Clipboard/Bitmap
+// - Ole-Object (DocShell::Draw)
+// - Preview of templates
+
+void ScPrintFunc::DrawToDev(ScDocument& rDoc, OutputDevice* pDev, double /* nPrintFactor */,
+ const tools::Rectangle& rBound, ScViewData* pViewData, bool bMetaFile)
+{
+ //! evaluate nPrintFactor !!!
+
+ SCTAB nTab = 0;
+ if (pViewData)
+ nTab = pViewData->GetTabNo();
+
+ bool bDoGrid, bNullVal, bFormula;
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
+ if (pStyleSheet)
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ bDoGrid = rSet.Get(ATTR_PAGE_GRID).GetValue();
+ bNullVal = rSet.Get(ATTR_PAGE_NULLVALS).GetValue();
+ bFormula = rSet.Get(ATTR_PAGE_FORMULAS).GetValue();
+ }
+ else
+ {
+ const ScViewOptions& rOpt = rDoc.GetViewOptions();
+ bDoGrid = rOpt.GetOption(VOPT_GRID);
+ bNullVal = rOpt.GetOption(VOPT_NULLVALS);
+ bFormula = rOpt.GetOption(VOPT_FORMULAS);
+ }
+
+ MapMode aMode = pDev->GetMapMode();
+
+ tools::Rectangle aRect = rBound;
+
+ if (aRect.Right() < aRect.Left() || aRect.Bottom() < aRect.Top())
+ aRect = tools::Rectangle( Point(), pDev->GetOutputSize() );
+
+ SCCOL nX1 = 0;
+ SCROW nY1 = 0;
+ SCCOL nX2 = OLE_STD_CELLS_X - 1;
+ SCROW nY2 = OLE_STD_CELLS_Y - 1;
+ if (bMetaFile)
+ {
+ ScRange aRange = rDoc.GetRange( nTab, rBound );
+ nX1 = aRange.aStart.Col();
+ nY1 = aRange.aStart.Row();
+ nX2 = aRange.aEnd.Col();
+ nY2 = aRange.aEnd.Row();
+ }
+ else if (pViewData)
+ {
+ ScSplitPos eWhich = pViewData->GetActivePart();
+ ScHSplitPos eHWhich = WhichH(eWhich);
+ ScVSplitPos eVWhich = WhichV(eWhich);
+ nX1 = pViewData->GetPosX(eHWhich);
+ nY1 = pViewData->GetPosY(eVWhich);
+ nX2 = nX1 + pViewData->VisibleCellsX(eHWhich);
+ if (nX2>nX1) --nX2;
+ nY2 = nY1 + pViewData->VisibleCellsY(eVWhich);
+ if (nY2>nY1) --nY2;
+ }
+
+ if (nX1 > rDoc.MaxCol()) nX1 = rDoc.MaxCol();
+ if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
+ if (nY1 > rDoc.MaxRow()) nY1 = rDoc.MaxRow();
+ if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
+
+ tools::Long nDevSizeX = aRect.Right()-aRect.Left()+1;
+ tools::Long nDevSizeY = aRect.Bottom()-aRect.Top()+1;
+
+ tools::Long nTwipsSizeX = 0;
+ for (SCCOL i=nX1; i<=nX2; i++)
+ nTwipsSizeX += rDoc.GetColWidth( i, nTab );
+ tools::Long nTwipsSizeY = rDoc.GetRowHeight( nY1, nY2, nTab );
+
+ // if no lines, still space for the outline frame (20 Twips = 1pt)
+ // (HasLines initializes aLines to 0,0,0,0)
+ nTwipsSizeX += 20;
+ nTwipsSizeY += 20;
+
+ double nScaleX = static_cast<double>(nDevSizeX) / nTwipsSizeX;
+ double nScaleY = static_cast<double>(nDevSizeY) / nTwipsSizeY;
+
+ //! hand over Flag at FillInfo !!!!!
+ ScRange aERange;
+ bool bEmbed = rDoc.IsEmbedded();
+ if (bEmbed)
+ {
+ rDoc.GetEmbedded(aERange);
+ rDoc.ResetEmbedded();
+ }
+
+ // Assemble data
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
+ nScaleX, nScaleY, false, bFormula );
+ lcl_HidePrint( aTabInfo, nX1, nX2 );
+
+ if (bEmbed)
+ rDoc.SetEmbedded(aERange);
+
+ tools::Long nScrX = aRect.Left();
+ tools::Long nScrY = aRect.Top();
+
+ // If no lines, still leave space for grid lines
+ // (would be elseways cut away)
+ nScrX += 1;
+ nScrY += 1;
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
+ aOutputData.SetMetaFileMode(bMetaFile);
+ aOutputData.SetShowNullValues(bNullVal);
+ aOutputData.SetShowFormulas(bFormula);
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ std::unique_ptr<FmFormView> pDrawView;
+
+ if( pModel )
+ {
+ pDrawView.reset(
+ new FmFormView(
+ *pModel,
+ pDev));
+ pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab));
+ pDrawView->SetPrintPreview();
+ aOutputData.SetDrawView( pDrawView.get() );
+ }
+
+ //! SetUseStyleColor ??
+
+ if ( bMetaFile && pDev->IsVirtual() )
+ aOutputData.SetSnapPixel();
+
+ Point aLogStart = pDev->PixelToLogic(Point(nScrX, nScrY), MapMode(MapUnit::Map100thMM));
+ tools::Long nLogStX = aLogStart.X();
+ tools::Long nLogStY = aLogStart.Y();
+
+ //! nZoom for GetFont in OutputData ???
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
+
+ // #i72502#
+ const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
+ aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(aMode);
+
+ aOutputData.DrawBackground(*pDev);
+
+ aOutputData.DrawShadow();
+ aOutputData.DrawFrame(*pDev);
+ aOutputData.DrawSparklines(*pDev);
+ aOutputData.DrawStrings();
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
+
+ aOutputData.DrawEdit(!bMetaFile);
+
+ if (bDoGrid)
+ {
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(aMode);
+
+ aOutputData.DrawGrid(*pDev, true, false); // no page breaks
+
+ pDev->SetLineColor( COL_BLACK );
+
+ Size aOne = pDev->PixelToLogic( Size(1,1) );
+ if (bMetaFile)
+ aOne = Size(1,1); // compatible with DrawGrid
+ tools::Long nRight = nScrX + aOutputData.GetScrW() - aOne.Width();
+ tools::Long nBottom = nScrY + aOutputData.GetScrH() - aOne.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ // extra line at the left edge for left-to-right, right for right-to-left
+ if ( bLayoutRTL )
+ pDev->DrawLine( Point(nRight,nScrY), Point(nRight,nBottom) );
+ else
+ pDev->DrawLine( Point(nScrX,nScrY), Point(nScrX,nBottom) );
+ // extra line at the top in both cases
+ pDev->DrawLine( Point(nScrX,nScrY), Point(nRight,nScrY) );
+ }
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
+ aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
+ aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
+}
+
+// Printing
+
+static void lcl_FillHFParam( ScPrintHFParam& rParam, const SfxItemSet* pHFSet )
+{
+ // nDistance must be initialized differently before
+
+ if ( pHFSet == nullptr )
+ {
+ rParam.bEnable = false;
+ rParam.pBorder = nullptr;
+ rParam.pBack = nullptr;
+ rParam.pShadow = nullptr;
+ }
+ else
+ {
+ rParam.bEnable = pHFSet->Get(ATTR_PAGE_ON).GetValue();
+ rParam.bDynamic = pHFSet->Get(ATTR_PAGE_DYNAMIC).GetValue();
+ rParam.bShared = pHFSet->Get(ATTR_PAGE_SHARED).GetValue();
+ rParam.bSharedFirst = pHFSet->Get(ATTR_PAGE_SHARED_FIRST).GetValue();
+ rParam.nHeight = pHFSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
+ const SvxLRSpaceItem* pHFLR = &pHFSet->Get(ATTR_LRSPACE);
+ tools::Long nTmp;
+ nTmp = pHFLR->GetLeft();
+ rParam.nLeft = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ nTmp = pHFLR->GetRight();
+ rParam.nRight = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ rParam.pBorder = &pHFSet->Get(ATTR_BORDER);
+ rParam.pBack = &pHFSet->Get(ATTR_BACKGROUND);
+ rParam.pShadow = &pHFSet->Get(ATTR_SHADOW);
+
+// now back in the dialog:
+// rParam.nHeight += rParam.nDistance; // not in the dialog any more ???
+
+ rParam.nHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() );
+
+ rParam.nManHeight = rParam.nHeight;
+ }
+
+ if (!rParam.bEnable)
+ rParam.nHeight = 0;
+}
+
+// bNew = TRUE: search for used part of the document
+// bNew = FALSE: only limit whole lines/columns
+
+bool ScPrintFunc::AdjustPrintArea( bool bNew )
+{
+ SCCOL nOldEndCol = nEndCol; // only important for !bNew
+ SCROW nOldEndRow = nEndRow;
+ bool bChangeCol = true; // at bNew both are being adjusted
+ bool bChangeRow = true;
+
+ bool bNotes = aTableParam.bNotes;
+ if ( bNew )
+ {
+ nStartCol = 0;
+ nStartRow = 0;
+ if (!rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes ))
+ return false; // nothing
+ bPrintAreaValid = true;
+ }
+ else
+ {
+ bool bFound = true;
+ bChangeCol = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
+ bChangeRow = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
+ bool bForcedChangeRow = false;
+
+ // #i53558# Crop entire column of old row limit to real print area with
+ // some fuzzyness.
+ if (!bChangeRow && nStartRow == 0)
+ {
+ SCROW nPAEndRow;
+ bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nPAEndRow, bNotes );
+ // Say we don't want to print more than ~1000 empty rows, which are
+ // about 14 pages intentionally left blank...
+ const SCROW nFuzzy = 23*42;
+ if (nPAEndRow + nFuzzy < nEndRow)
+ {
+ bForcedChangeRow = true;
+ nEndRow = nPAEndRow;
+ }
+ else
+ bFound = true; // user seems to _want_ to print some empty rows
+ }
+ // TODO: in case we extend the number of columns we may have to do the
+ // same for horizontal cropping.
+
+ if ( bChangeCol && bChangeRow )
+ bFound = rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes );
+ else if ( bChangeCol )
+ bFound = rDoc.GetPrintAreaHor( nPrintTab, nStartRow, nEndRow, nEndCol );
+ else if ( bChangeRow )
+ bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nEndRow, bNotes );
+
+ if (!bFound)
+ return false; // empty
+
+ bPrintAreaValid = true;
+ if (bForcedChangeRow)
+ bChangeRow = true;
+ }
+
+ assert( bPrintAreaValid );
+ rDoc.ExtendMerge( nStartCol,nStartRow, nEndCol,nEndRow, nPrintTab ); // no Refresh, incl. Attrs
+
+ if ( bChangeCol )
+ {
+ OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
+ pRefDev->SetMapMode(MapMode(MapUnit::MapPixel)); // important for GetNeededSize
+
+ rDoc.ExtendPrintArea( pRefDev,
+ nPrintTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ // changing nEndCol
+ }
+
+ if ( nEndCol < rDoc.MaxCol() && rDoc.HasAttrib(
+ nEndCol,nStartRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowRight ) )
+ ++nEndCol;
+ if ( nEndRow < rDoc.MaxRow() && rDoc.HasAttrib(
+ nStartCol,nEndRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowDown ) )
+ ++nEndRow;
+
+ if (!bChangeCol) nEndCol = nOldEndCol;
+ if (!bChangeRow) nEndRow = nOldEndRow;
+
+ return true;
+}
+
+tools::Long ScPrintFunc::TextHeight( const EditTextObject* pObject )
+{
+ if (!pObject)
+ return 0;
+
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+
+ return static_cast<tools::Long>(pEditEngine->GetTextHeight());
+}
+
+// nZoom must be set !!!
+// and the respective Twip-MapMode configured
+
+void ScPrintFunc::UpdateHFHeight( ScPrintHFParam& rParam )
+{
+ OSL_ENSURE( aPageSize.Width(), "UpdateHFHeight without aPageSize");
+
+ if (!(rParam.bEnable && rParam.bDynamic))
+ return;
+
+ // calculate nHeight from content
+
+ MakeEditEngine();
+ tools::Long nPaperWidth = ( aPageSize.Width() - nLeftMargin - nRightMargin -
+ rParam.nLeft - rParam.nRight ) * 100 / nZoom;
+ if (rParam.pBorder)
+ nPaperWidth -= ( rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT) +
+ lcl_LineTotal(rParam.pBorder->GetLeft()) +
+ lcl_LineTotal(rParam.pBorder->GetRight()) ) * 100 / nZoom;
+
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ nPaperWidth -= ( rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) ) * 100 / nZoom;
+
+ pEditEngine->SetPaperSize( Size( nPaperWidth, 10000 ) );
+
+ tools::Long nMaxHeight = 0;
+ if ( rParam.pLeft )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetRightArea() ) );
+ }
+ if ( rParam.pRight )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetRightArea() ) );
+ }
+ if ( rParam.pFirst )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetRightArea() ) );
+ }
+
+ rParam.nHeight = nMaxHeight + rParam.nDistance;
+ if (rParam.pBorder)
+ rParam.nHeight += rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM) +
+ lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() );
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ rParam.nHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+
+ if (rParam.nHeight < rParam.nManHeight)
+ rParam.nHeight = rParam.nManHeight; // configured minimum
+}
+
+void ScPrintFunc::InitParam( const ScPrintOptions* pOptions )
+{
+ if (!pParamSet)
+ return;
+
+ // TabPage "Page"
+ const SvxLRSpaceItem* pLRItem = &pParamSet->Get( ATTR_LRSPACE );
+ tools::Long nTmp;
+ nTmp = pLRItem->GetLeft();
+ nLeftMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ nTmp = pLRItem->GetRight();
+ nRightMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ const SvxULSpaceItem* pULItem = &pParamSet->Get( ATTR_ULSPACE );
+ nTopMargin = pULItem->GetUpper();
+ nBottomMargin = pULItem->GetLower();
+
+ const SvxPageItem* pPageItem = &pParamSet->Get( ATTR_PAGE );
+ nPageUsage = pPageItem->GetPageUsage();
+ bLandscape = pPageItem->IsLandscape();
+ aFieldData.eNumType = pPageItem->GetNumType();
+
+ bCenterHor = pParamSet->Get(ATTR_PAGE_HORCENTER).GetValue();
+ bCenterVer = pParamSet->Get(ATTR_PAGE_VERCENTER).GetValue();
+
+ aPageSize = pParamSet->Get(ATTR_PAGE_SIZE).GetSize();
+ if ( !aPageSize.Width() || !aPageSize.Height() )
+ {
+ OSL_FAIL("PageSize Null ?!?!?");
+ aPageSize = SvxPaperInfo::GetPaperSize( PAPER_A4 );
+ }
+
+ pBorderItem = &pParamSet->Get(ATTR_BORDER);
+ pBackgroundItem = &pParamSet->Get(ATTR_BACKGROUND);
+ pShadowItem = &pParamSet->Get(ATTR_SHADOW);
+
+ // TabPage "Headline"
+
+ aHdr.pLeft = &pParamSet->Get(ATTR_PAGE_HEADERLEFT); // Content
+ aHdr.pRight = &pParamSet->Get(ATTR_PAGE_HEADERRIGHT);
+ aHdr.pFirst = &pParamSet->Get(ATTR_PAGE_HEADERFIRST);
+
+ const SfxItemSet* pHeaderSet = nullptr;
+ if ( const SvxSetItem* pHeaderSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_HEADERSET, false ) )
+ {
+ pHeaderSet = &pHeaderSetItem->GetItemSet();
+ // Headline has space below
+ aHdr.nDistance = pHeaderSet->Get(ATTR_ULSPACE).GetLower();
+ }
+ lcl_FillHFParam( aHdr, pHeaderSet );
+
+ // TabPage "Footline"
+
+ aFtr.pLeft = &pParamSet->Get(ATTR_PAGE_FOOTERLEFT); // Content
+ aFtr.pRight = &pParamSet->Get(ATTR_PAGE_FOOTERRIGHT);
+ aFtr.pFirst = &pParamSet->Get(ATTR_PAGE_FOOTERFIRST);
+
+ const SfxItemSet* pFooterSet = nullptr;
+ if ( const SvxSetItem* pFooterSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_FOOTERSET, false ) )
+ {
+ pFooterSet = &pFooterSetItem->GetItemSet();
+ // Footline has space above
+ aFtr.nDistance = pFooterSet->Get(ATTR_ULSPACE).GetUpper();
+ }
+ lcl_FillHFParam( aFtr, pFooterSet );
+
+ // Compile Table-/Area-Params from single Items
+
+ // TabPage "Table"
+
+ const SfxUInt16Item* pScaleItem = nullptr;
+ const ScPageScaleToItem* pScaleToItem = nullptr;
+ const SfxUInt16Item* pScaleToPagesItem = nullptr;
+ SfxItemState eState;
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALE, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALE );
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALETO, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleToItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleToItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETO );
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALETOPAGES, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleToPagesItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleToPagesItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETOPAGES );
+
+ OSL_ENSURE( pScaleItem && pScaleToItem && pScaleToPagesItem, "Missing ScaleItem! :-/" );
+
+ aTableParam.bCellContent = true;
+ aTableParam.bNotes = lcl_GetBool(pParamSet,ATTR_PAGE_NOTES);
+ aTableParam.bGrid = lcl_GetBool(pParamSet,ATTR_PAGE_GRID);
+ aTableParam.bHeaders = lcl_GetBool(pParamSet,ATTR_PAGE_HEADERS);
+ aTableParam.bFormulas = lcl_GetBool(pParamSet,ATTR_PAGE_FORMULAS);
+ aTableParam.bNullVals = lcl_GetBool(pParamSet,ATTR_PAGE_NULLVALS);
+ aTableParam.bCharts = lcl_GetShow(pParamSet,ATTR_PAGE_CHARTS);
+ aTableParam.bObjects = lcl_GetShow(pParamSet,ATTR_PAGE_OBJECTS);
+ aTableParam.bDrawings = lcl_GetShow(pParamSet,ATTR_PAGE_DRAWINGS);
+ aTableParam.bTopDown = lcl_GetBool(pParamSet,ATTR_PAGE_TOPDOWN);
+ aTableParam.bLeftRight = !aTableParam.bLeftRight;
+ aTableParam.nFirstPageNo = lcl_GetUShort(pParamSet,ATTR_PAGE_FIRSTPAGENO);
+ if (!aTableParam.nFirstPageNo)
+ aTableParam.nFirstPageNo = static_cast<sal_uInt16>(nPageStart); // from previous table
+
+ if ( pScaleItem && pScaleToItem && pScaleToPagesItem )
+ {
+ sal_uInt16 nScaleAll = pScaleItem->GetValue();
+ sal_uInt16 nScaleToPages = pScaleToPagesItem->GetValue();
+
+ aTableParam.bScaleNone = (nScaleAll == 100);
+ aTableParam.bScaleAll = (nScaleAll > 0 );
+ aTableParam.bScaleTo = pScaleToItem->IsValid();
+ aTableParam.bScalePageNum = (nScaleToPages > 0 );
+ aTableParam.nScaleAll = nScaleAll;
+ aTableParam.nScaleWidth = pScaleToItem->GetWidth();
+ aTableParam.nScaleHeight = pScaleToItem->GetHeight();
+ aTableParam.nScalePageNum = nScaleToPages;
+ }
+ else
+ {
+ aTableParam.bScaleNone = true;
+ aTableParam.bScaleAll = false;
+ aTableParam.bScaleTo = false;
+ aTableParam.bScalePageNum = false;
+ aTableParam.nScaleAll = 0;
+ aTableParam.nScaleWidth = 0;
+ aTableParam.nScaleHeight = 0;
+ aTableParam.nScalePageNum = 0;
+ }
+
+ // skip empty pages only if options with that flag are passed
+ aTableParam.bSkipEmpty = pOptions && pOptions->GetSkipEmpty();
+ if ( pPageData )
+ aTableParam.bSkipEmpty = false;
+ // If pPageData is set, only the breaks are interesting for the
+ // pagebreak preview, empty pages are not addressed separately.
+
+ aTableParam.bForceBreaks = pOptions && pOptions->GetForceBreaks();
+
+ // TabPage "Parts":
+
+ //! walk through all PrintAreas of the table !!!
+ const ScRange* pPrintArea = rDoc.GetPrintRange( nPrintTab, 0 );
+ std::optional<ScRange> oRepeatCol = rDoc.GetRepeatColRange( nPrintTab );
+ std::optional<ScRange> oRepeatRow = rDoc.GetRepeatRowRange( nPrintTab );
+
+ // ignoring ATTR_PAGE_PRINTTABLES
+
+ bool bHasPrintRange = rDoc.HasPrintRange();
+ sal_uInt16 nPrintRangeCount = rDoc.GetPrintRangeCount(nPrintTab);
+ bool bPrintEntireSheet = rDoc.IsPrintEntireSheet(nPrintTab);
+
+ if (!bPrintEntireSheet && !nPrintRangeCount)
+ mbHasPrintRange = false;
+
+ if ( pUserArea ) // UserArea (selection) has priority
+ {
+ bPrintCurrentTable =
+ aAreaParam.bPrintArea = true; // Selection
+ aAreaParam.aPrintArea = *pUserArea;
+
+ // The table-query is already in DocShell::Print, here always
+ aAreaParam.aPrintArea.aStart.SetTab(nPrintTab);
+ aAreaParam.aPrintArea.aEnd.SetTab(nPrintTab);
+ }
+ else if (bHasPrintRange)
+ {
+ if ( pPrintArea ) // at least one set?
+ {
+ bPrintCurrentTable =
+ aAreaParam.bPrintArea = true;
+ aAreaParam.aPrintArea = *pPrintArea;
+
+ bMultiArea = nPrintRangeCount > 1;
+ }
+ else
+ {
+ // do not print hidden sheets with "Print entire sheet" flag
+ bPrintCurrentTable = rDoc.IsPrintEntireSheet( nPrintTab ) && rDoc.IsVisible( nPrintTab );
+ aAreaParam.bPrintArea = !bPrintCurrentTable; // otherwise the table is always counted
+ }
+ }
+ else
+ {
+ // don't print hidden tables if there's no print range defined there
+ if ( rDoc.IsVisible( nPrintTab ) )
+ {
+ aAreaParam.bPrintArea = false;
+ bPrintCurrentTable = true;
+ }
+ else
+ {
+ aAreaParam.bPrintArea = true; // otherwise the table is always counted
+ bPrintCurrentTable = false;
+ }
+ }
+
+ if ( oRepeatCol )
+ {
+ aAreaParam.bRepeatCol = true;
+ nRepeatStartCol = oRepeatCol->aStart.Col();
+ nRepeatEndCol = oRepeatCol->aEnd .Col();
+ }
+ else
+ {
+ aAreaParam.bRepeatCol = false;
+ nRepeatStartCol = nRepeatEndCol = SCCOL_REPEAT_NONE;
+ }
+
+ if ( oRepeatRow )
+ {
+ aAreaParam.bRepeatRow = true;
+ nRepeatStartRow = oRepeatRow->aStart.Row();
+ nRepeatEndRow = oRepeatRow->aEnd .Row();
+ }
+ else
+ {
+ aAreaParam.bRepeatRow = false;
+ nRepeatStartRow = nRepeatEndRow = SCROW_REPEAT_NONE;
+ }
+
+ // Split pages
+
+ if (!bPrintAreaValid)
+ {
+ nTabPages = CountPages(); // also calculates zoom
+ nTotalPages = nTabPages;
+ nTotalPages += CountNotePages();
+ }
+ else
+ {
+ CalcPages(); // search breaks only
+ CountNotePages(); // Count notes, even if number of pages is already known
+ }
+
+ if (nDocPages)
+ aFieldData.nTotalPages = nDocPages;
+ else
+ aFieldData.nTotalPages = nTotalPages;
+
+ SetDateTime( DateTime( DateTime::SYSTEM ) );
+
+ if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
+ aFieldData.aTitle = pDocShell->getDocProperties()->getTitle();
+ else
+ aFieldData.aTitle = pDocShell->GetTitle();
+
+ const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
+ aFieldData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ if ( !aFieldData.aLongDocName.isEmpty() )
+ aFieldData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ aFieldData.aShortDocName = aFieldData.aLongDocName = aFieldData.aTitle;
+
+ // Printer settings (Orientation, Paper) at DoPrint
+}
+
+Size ScPrintFunc::GetDataSize() const
+{
+ Size aSize = aPageSize;
+ aSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
+ aSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
+ aSize.AdjustHeight( -(aHdr.nHeight + aFtr.nHeight) );
+ return aSize;
+}
+
+void ScPrintFunc::GetScaleData( Size& rPhysSize, tools::Long& rDocHdr, tools::Long& rDocFtr )
+{
+ rPhysSize = aPageSize;
+ rPhysSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
+ rPhysSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
+
+ rDocHdr = aHdr.nHeight;
+ rDocFtr = aFtr.nHeight;
+}
+
+void ScPrintFunc::SetDateTime( const DateTime& rDateTime )
+{
+ aFieldData.aDateTime = rDateTime;
+}
+
+static void lcl_DrawGraphic( const Graphic &rGraphic, vcl::RenderContext& rOutDev,
+ const tools::Rectangle &rGrf, const tools::Rectangle &rOut )
+{
+ const bool bNotInside = !rOut.Contains( rGrf );
+ if ( bNotInside )
+ {
+ rOutDev.Push();
+ rOutDev.IntersectClipRegion( rOut );
+ }
+
+ rGraphic.Draw(rOutDev, rGrf.TopLeft(), rGrf.GetSize());
+
+ if ( bNotInside )
+ rOutDev.Pop();
+}
+
+static void lcl_DrawGraphic( const SvxBrushItem &rBrush, vcl::RenderContext& rOutDev, const OutputDevice* pRefDev,
+ const tools::Rectangle &rOrg, const tools::Rectangle &rOut,
+ OUString const & referer )
+{
+ Size aGrfSize(0,0);
+ const Graphic *pGraphic = rBrush.GetGraphic(referer);
+ SvxGraphicPosition ePos;
+ if ( pGraphic && pGraphic->IsSupportedGraphic() )
+ {
+ const MapMode aMapMM( MapUnit::Map100thMM );
+ if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aGrfSize = pRefDev->PixelToLogic( pGraphic->GetPrefSize(), aMapMM );
+ else
+ aGrfSize = OutputDevice::LogicToLogic( pGraphic->GetPrefSize(),
+ pGraphic->GetPrefMapMode(), aMapMM );
+ ePos = rBrush.GetGraphicPos();
+ }
+ else
+ ePos = GPOS_NONE;
+
+ Point aPos;
+ Size aDrawSize = aGrfSize;
+
+ bool bDraw = true;
+ switch ( ePos )
+ {
+ case GPOS_LT: aPos = rOrg.TopLeft();
+ break;
+ case GPOS_MT: aPos.setY( rOrg.Top() );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RT: aPos.setY( rOrg.Top() );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_LM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Left() );
+ break;
+ case GPOS_MM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_LB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Left() );
+ break;
+ case GPOS_MB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_AREA:
+ aPos = rOrg.TopLeft();
+ aDrawSize = rOrg.GetSize();
+ break;
+ case GPOS_TILED:
+ {
+ // use GraphicObject::DrawTiled instead of an own loop
+ // (pixel rounding is handled correctly, and a very small bitmap
+ // is duplicated into a bigger one for better performance)
+
+ GraphicObject aObject( *pGraphic );
+
+ if( rOutDev.GetOutDevType() == OUTDEV_PDF &&
+ (aObject.GetType() == GraphicType::Bitmap || aObject.GetType() == GraphicType::Default) )
+ {
+ // For PDF export, every draw
+ // operation for bitmaps takes a noticeable
+ // amount of place (~50 characters). Thus,
+ // optimize between tile bitmap size and
+ // number of drawing operations here.
+ //
+ // A_out
+ // n_chars = k1 * ---------- + k2 * A_bitmap
+ // A_bitmap
+ //
+ // minimum n_chars is obtained for (derive for
+ // A_bitmap, set to 0, take positive
+ // solution):
+ // k1
+ // A_bitmap = Sqrt( ---- A_out )
+ // k2
+ //
+ // where k1 is the number of chars per draw
+ // operation, and k2 is the number of chars
+ // per bitmap pixel. This is approximately 50
+ // and 7 for current PDF writer, respectively.
+
+ const double k1( 50 );
+ const double k2( 7 );
+ const Size aSize( rOrg.GetSize() );
+ const double Abitmap( k1/k2 * aSize.Width()*aSize.Height() );
+
+ aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0),
+ ::std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
+ }
+ else
+ {
+ aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0) );
+ }
+
+ bDraw = false;
+ }
+ break;
+
+ case GPOS_NONE:
+ bDraw = false;
+ break;
+
+ default: OSL_ENSURE( false, "new Graphic position?" );
+ }
+ tools::Rectangle aGrf( aPos,aDrawSize );
+ if ( bDraw && aGrf.Overlaps( rOut ) )
+ {
+ lcl_DrawGraphic( *pGraphic, rOutDev, aGrf, rOut );
+ }
+}
+
+// The frame is drawn inwards
+
+void ScPrintFunc::DrawBorder( tools::Long nScrX, tools::Long nScrY, tools::Long nScrW, tools::Long nScrH,
+ const SvxBoxItem* pBorderData, const SvxBrushItem* pBackground,
+ const SvxShadowItem* pShadow )
+{
+ //! direct output from SvxBoxItem !!!
+
+ if (pBorderData)
+ if ( !pBorderData->GetTop() && !pBorderData->GetBottom() && !pBorderData->GetLeft() &&
+ !pBorderData->GetRight() )
+ pBorderData = nullptr;
+
+ if (!pBorderData && !pBackground && !pShadow)
+ return; // nothing to do
+
+ tools::Long nLeft = 0;
+ tools::Long nRight = 0;
+ tools::Long nTop = 0;
+ tools::Long nBottom = 0;
+
+ // aFrameRect - outside around frame, without shadow
+ if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ nLeft += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
+ nRight += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
+ nTop += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
+ nBottom += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
+ }
+ tools::Rectangle aFrameRect( Point(nScrX+nLeft, nScrY+nTop),
+ Size(nScrW-nLeft-nRight, nScrH-nTop-nBottom) );
+
+ // center of frame, to paint lines through OutputData
+ if (pBorderData)
+ {
+ nLeft += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetLeft()) * nScaleX / 2 );
+ nRight += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetRight()) * nScaleX / 2 );
+ nTop += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetTop()) * nScaleY / 2 );
+ nBottom += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetBottom()) * nScaleY / 2 );
+ }
+ tools::Long nEffHeight = nScrH - nTop - nBottom;
+ tools::Long nEffWidth = nScrW - nLeft - nRight;
+ if (nEffHeight<=0 || nEffWidth<=0)
+ return; // empty
+
+ if ( pBackground )
+ {
+ if (pBackground->GetGraphicPos() != GPOS_NONE)
+ {
+ OutputDevice* pRefDev;
+ if ( bIsRender )
+ pRefDev = pDev; // don't use printer for PDF
+ else
+ pRefDev = rDoc.GetPrinter(); // use printer also for preview
+ OUString referer;
+ if (pDocShell->HasName()) {
+ referer = pDocShell->GetMedium()->GetName();
+ }
+ lcl_DrawGraphic(*pBackground, *pDev, pRefDev, aFrameRect, aFrameRect, referer);
+ }
+ else
+ {
+ pDev->SetFillColor(pBackground->GetColor());
+ pDev->SetLineColor();
+ pDev->DrawRect(aFrameRect);
+ }
+ }
+
+ if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ pDev->SetFillColor(pShadow->GetColor());
+ pDev->SetLineColor();
+ tools::Long nShadowX = static_cast<tools::Long>( pShadow->GetWidth() * nScaleX );
+ tools::Long nShadowY = static_cast<tools::Long>( pShadow->GetWidth() * nScaleY );
+ switch (pShadow->GetLocation())
+ {
+ case SvxShadowLocation::TopLeft:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()-nShadowX, aFrameRect.Top() ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Left(), aFrameRect.Bottom()-nShadowY ) );
+ break;
+ case SvxShadowLocation::TopRight:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()+nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Top() ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Right(), aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()-nShadowY ) );
+ break;
+ case SvxShadowLocation::BottomLeft:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Bottom(),
+ aFrameRect.Right()-nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()+nShadowY,
+ aFrameRect.Left(), aFrameRect.Bottom()+nShadowY ) );
+ break;
+ case SvxShadowLocation::BottomRight:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()+nShadowX, aFrameRect.Bottom(),
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Right(), aFrameRect.Top()+nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ if (!pBorderData)
+ return;
+
+ ScDocumentUniquePtr pBorderDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pBorderDoc->InitUndo( rDoc, 0,0, true,true );
+ pBorderDoc->ApplyAttr( 0,0,0, *pBorderData );
+
+ ScTableInfo aTabInfo;
+ pBorderDoc->FillInfo( aTabInfo, 0,0, 0,0, 0,
+ nScaleX, nScaleY, false, false );
+ OSL_ENSURE(aTabInfo.mnArrCount,"nArrCount == 0");
+
+ aTabInfo.mpRowInfo[1].nHeight = static_cast<sal_uInt16>(nEffHeight);
+ aTabInfo.mpRowInfo[0].basicCellInfo(0).nWidth =
+ aTabInfo.mpRowInfo[1].basicCellInfo(0).nWidth = static_cast<sal_uInt16>(nEffWidth);
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, pBorderDoc.get(), 0,
+ nScrX+nLeft, nScrY+nTop, 0,0, 0,0, nScaleX, nScaleY );
+ aOutputData.SetUseStyleColor( bUseStyleColor );
+
+ aOutputData.DrawFrame(*pDev);
+}
+
+void ScPrintFunc::PrintColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY )
+{
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+ SCCOL nCol;
+
+ tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ tools::Long nEndY = nScrY + nHeight - nOneY;
+
+ tools::Long nPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ nPosX += static_cast<tools::Long>( rDoc.GetColWidth( nCol, nPrintTab ) * nScaleX );
+ }
+ else
+ nPosX -= nOneX;
+ tools::Long nPosY = nScrY - nOneY;
+ OUString aText;
+
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ {
+ tools::Long nWidth = static_cast<tools::Long>(nDocW * nScaleX);
+ tools::Long nEndX = nPosX + nWidth * nLayoutSign;
+
+ pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
+
+ aText = ::ScColToAlpha( nCol);
+ tools::Long nTextWidth = pDev->GetTextWidth(aText);
+ tools::Long nTextHeight = pDev->GetTextHeight();
+ tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
+ tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
+ tools::Long nTextPosX = nPosX+nAddX;
+ if ( bLayoutRTL )
+ nTextPosX -= nWidth;
+ pDev->DrawText( Point( nTextPosX,nPosY+nAddY ), aText );
+
+ nPosX = nEndX;
+ }
+ }
+}
+
+void ScPrintFunc::PrintRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+
+ tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ tools::Long nEndX = nScrX + nWidth;
+ tools::Long nPosX = nScrX;
+ if ( !bLayoutRTL )
+ {
+ nEndX -= nOneX;
+ nPosX -= nOneX;
+ }
+ tools::Long nPosY = nScrY - nOneY;
+ OUString aText;
+
+ for (SCROW nRow=nY1; nRow<=nY2; nRow++)
+ {
+ sal_uInt16 nDocH = rDoc.GetRowHeight( nRow, nPrintTab );
+ if (nDocH)
+ {
+ tools::Long nHeight = static_cast<tools::Long>(nDocH * nScaleY);
+ tools::Long nEndY = nPosY + nHeight;
+
+ pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
+
+ aText = OUString::number( nRow+1 );
+ tools::Long nTextWidth = pDev->GetTextWidth(aText);
+ tools::Long nTextHeight = pDev->GetTextHeight();
+ tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
+ tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
+ pDev->DrawText( Point( nPosX+nAddX,nPosY+nAddY ), aText );
+
+ nPosY = nEndY;
+ }
+ }
+}
+
+void ScPrintFunc::LocateColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepCol, ScPreviewLocationData& rLocationData )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ tools::Long nEndY = nScrY + nHeight - nOneY;
+
+ tools::Long nPosX = nScrX - nOneX;
+ for (SCCOL nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ nPosX += static_cast<tools::Long>(nDocW * nScaleX);
+ }
+ tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nEndY );
+ rLocationData.AddColHeaders( aCellRect, nX1, nX2, bRepCol );
+}
+
+void ScPrintFunc::LocateRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepRow, ScPreviewLocationData& rLocationData )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+
+ tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ tools::Long nEndX = nScrX + nWidth;
+ if ( !bLayoutRTL )
+ nEndX -= nOneX;
+
+ tools::Long nPosY = nScrY - nOneY;
+ nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
+ tools::Rectangle aCellRect( nScrX, nScrY, nEndX, nPosY );
+ rLocationData.AddRowHeaders( aCellRect, nY1, nY2, bRepRow );
+}
+
+void ScPrintFunc::LocateArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY, bool bRepCol, bool bRepRow,
+ ScPreviewLocationData& rLocationData )
+{
+ // get MapMode for drawing objects (same MapMode as in ScOutputData::PrintDrawingLayer)
+
+ Point aLogPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
+ tools::Long nLogStX = aLogPos.X();
+ tools::Long nLogStY = aLogPos.Y();
+
+ SCCOL nCol;
+ Point aTwipOffset;
+ for (nCol=0; nCol<nX1; nCol++)
+ aTwipOffset.AdjustX( -(rDoc.GetColWidth( nCol, nPrintTab )) );
+ aTwipOffset.AdjustY( -sal_Int32(rDoc.GetRowHeight( 0, nY1-1, nPrintTab )) );
+
+ Point aMMOffset(o3tl::convert(aTwipOffset, o3tl::Length::twip, o3tl::Length::mm100));
+ aMMOffset += Point( nLogStX, nLogStY );
+ MapMode aDrawMapMode( MapUnit::Map100thMM, aMMOffset, aLogicMode.GetScaleX(), aLogicMode.GetScaleY() );
+
+ // get pixel rectangle
+
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nPosX = nScrX - nOneX;
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ nPosX += static_cast<tools::Long>(nDocW * nScaleX);
+ }
+
+ tools::Long nPosY = nScrY - nOneY;
+ nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
+ tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nPosY );
+ rLocationData.AddCellRange( aCellRect, ScRange( nX1,nY1,nPrintTab, nX2,nY2,nPrintTab ),
+ bRepCol, bRepRow, aDrawMapMode );
+}
+
+void ScPrintFunc::PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY,
+ bool bShLeft, bool bShTop, bool bShRight, bool bShBottom )
+{
+ // #i47547# nothing to do if the end of the print area is before the end of
+ // the repeat columns/rows (don't use negative size for ScOutputData)
+ if ( nX2 < nX1 || nY2 < nY1 )
+ return;
+
+ //! hand over Flag at FillInfo !!!!!
+ ScRange aERange;
+ bool bEmbed = rDoc.IsEmbedded();
+ if (bEmbed)
+ {
+ rDoc.GetEmbedded(aERange);
+ rDoc.ResetEmbedded();
+ }
+
+ Point aPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
+ tools::Long nLogStX = aPos.X();
+ tools::Long nLogStY = aPos.Y();
+
+ // Assemble data
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nPrintTab,
+ nScaleX, nScaleY, true, aTableParam.bFormulas );
+ lcl_HidePrint( aTabInfo, nX1, nX2 );
+
+ if (bEmbed)
+ rDoc.SetEmbedded(aERange);
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nPrintTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
+
+ aOutputData.SetDrawView( pDrawView );
+
+ // test if all paint parts are hidden, then a paint is not necessary at all
+ const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
+ const bool bHideAllDrawingLayer( pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart()
+ && pDrawView->getHideDraw() && pDrawView->getHideFormControl() );
+
+ if(!bHideAllDrawingLayer)
+ {
+ pDev->SetMapMode(aLogicMode);
+ // don's set Clipping here (Mapmode is being moved)
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
+ }
+
+ pDev->SetMapMode(aOffsetMode);
+
+ aOutputData.SetShowFormulas( aTableParam.bFormulas );
+ aOutputData.SetShowNullValues( aTableParam.bNullVals );
+ aOutputData.SetUseStyleColor( bUseStyleColor );
+
+ Color aGridColor( COL_BLACK );
+ if ( bUseStyleColor )
+ aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ aOutputData.SetGridColor( aGridColor );
+
+ if ( !pPrinter )
+ {
+ OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
+ Fraction aPrintFrac( nZoom, 100 ); // without nManualZoom
+ // MapMode, as it would arrive at the printer:
+ pRefDev->SetMapMode( MapMode( MapUnit::Map100thMM, Point(), aPrintFrac, aPrintFrac ) );
+
+ // when rendering (PDF), don't use printer as ref device, but printer's MapMode
+ // has to be set anyway, as charts still use it (#106409#)
+ if ( !bIsRender )
+ aOutputData.SetRefDevice( pRefDev );
+ }
+
+ if( aTableParam.bCellContent )
+ aOutputData.DrawBackground(*pDev);
+
+ pDev->SetClipRegion(vcl::Region(tools::Rectangle(
+ aPos, Size(aOutputData.GetScrW(), aOutputData.GetScrH()))));
+ pDev->SetClipRegion();
+
+ if( aTableParam.bCellContent )
+ {
+ aOutputData.DrawExtraShadow( bShLeft, bShTop, bShRight, bShBottom );
+ aOutputData.DrawFrame(*pDev);
+ aOutputData.DrawSparklines(*pDev);
+ aOutputData.DrawStrings();
+ aOutputData.DrawEdit(false);
+ }
+
+ if (aTableParam.bGrid)
+ aOutputData.DrawGrid(*pDev, true, false); // no page breaks
+
+ aOutputData.AddPDFNotes(); // has no effect if not rendering PDF with notes enabled
+
+ // test if all paint parts are hidden, then a paint is not necessary at all
+ if(!bHideAllDrawingLayer)
+ {
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
+ }
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
+ aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
+}
+
+bool ScPrintFunc::IsMirror( tools::Long nPageNo ) // Mirror margins?
+{
+ return nPageUsage == SvxPageUsage::Mirror && (nPageNo & 1);
+}
+
+bool ScPrintFunc::IsLeft( tools::Long nPageNo ) // left foot notes?
+{
+ bool bLeft;
+ if (nPageUsage == SvxPageUsage::Left)
+ bLeft = true;
+ else if (nPageUsage == SvxPageUsage::Right)
+ bLeft = false;
+ else
+ bLeft = (nPageNo & 1) != 0;
+ return bLeft;
+}
+
+void ScPrintFunc::MakeTableString()
+{
+ OUString aTmp;
+ rDoc.GetName(nPrintTab, aTmp);
+ aFieldData.aTabName = aTmp;
+}
+
+void ScPrintFunc::MakeEditEngine()
+{
+ if (!pEditEngine)
+ {
+ // can't use document's edit engine pool here,
+ // because pool must have twips as default metric
+ pEditEngine.reset( new ScHeaderEditEngine( EditEngine::CreatePool().get() ) );
+
+ pEditEngine->EnableUndo(false);
+ //fdo#45869 we want text to be positioned as it would be for the
+ //high dpi printed output, not as would be ideal for the 96dpi preview
+ //window itself
+ pEditEngine->SetRefDevice(pPrinter ? pPrinter : rDoc.GetRefDevice());
+ pEditEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters( pEditEngine->GetWordDelimiters() ) );
+ pEditEngine->SetControlWord( pEditEngine->GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
+ rDoc.ApplyAsianEditSettings( *pEditEngine );
+ pEditEngine->EnableAutoColor( bUseStyleColor );
+
+ // Default-Set for alignment
+ pEditDefaults.reset( new SfxItemSet( pEditEngine->GetEmptyItemSet() ) );
+
+ const ScPatternAttr& rPattern = rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
+ rPattern.FillEditItemSet( pEditDefaults.get() );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ pEditDefaults->Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ pEditDefaults->Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
+ pEditDefaults->Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ // don't use font color, because background color is not used
+ //! there's no way to set the background for note pages
+ pEditDefaults->ClearItem( EE_CHAR_COLOR );
+ if (ScGlobal::IsSystemRTL())
+ pEditDefaults->Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+ }
+
+ pEditEngine->SetData( aFieldData ); // Set page count etc.
+}
+
+// nStartY = logic
+void ScPrintFunc::PrintHF( tools::Long nPageNo, bool bHeader, tools::Long nStartY,
+ bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ const ScPrintHFParam& rParam = bHeader ? aHdr : aFtr;
+
+ pDev->SetMapMode( aTwipMode ); // Head-/Footlines in Twips
+
+ bool bFirst = 0 == nPageNo && !rParam.bSharedFirst;
+ bool bLeft = IsLeft(nPageNo) && !rParam.bShared;
+ const ScPageHFItem* pHFItem = bFirst ? rParam.pFirst : (bLeft ? rParam.pLeft : rParam.pRight);
+
+ tools::Long nLineStartX = aPageRect.Left() + rParam.nLeft;
+ tools::Long nLineEndX = aPageRect.Right() - rParam.nRight;
+ tools::Long nLineWidth = nLineEndX - nLineStartX + 1;
+
+ // Edit-Engine
+
+ Point aStart( nLineStartX, nStartY );
+ Size aPaperSize( nLineWidth, rParam.nHeight-rParam.nDistance );
+ if ( rParam.pBorder )
+ {
+ tools::Long nLeft = lcl_LineTotal( rParam.pBorder->GetLeft() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT);
+ tools::Long nTop = lcl_LineTotal( rParam.pBorder->GetTop() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::TOP);
+ aStart.AdjustX(nLeft );
+ aStart.AdjustY(nTop );
+ aPaperSize.AdjustWidth( -(nLeft + lcl_LineTotal( rParam.pBorder->GetRight() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT)) );
+ aPaperSize.AdjustHeight( -(nTop + lcl_LineTotal( rParam.pBorder->GetBottom() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM)) );
+ }
+
+ if ( rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ tools::Long nLeft = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT);
+ tools::Long nTop = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP);
+ aStart.AdjustX(nLeft );
+ aStart.AdjustY(nTop );
+ aPaperSize.AdjustWidth( -(nLeft + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
+ aPaperSize.AdjustHeight( -(nTop + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
+ }
+
+ aFieldData.nPageNo = nPageNo+aTableParam.nFirstPageNo;
+ MakeEditEngine();
+
+ pEditEngine->SetPaperSize(aPaperSize);
+
+ // Frame / Background
+
+ Point aBorderStart( nLineStartX, nStartY );
+ Size aBorderSize( nLineWidth, rParam.nHeight-rParam.nDistance );
+ if ( rParam.bDynamic )
+ {
+ // adjust here again, for even/odd head-/footlines
+ // and probably other breaks by variable (page number etc.)
+
+ tools::Long nMaxHeight = 0;
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetRightArea() ) );
+ if (rParam.pBorder)
+ nMaxHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() ) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM);
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ nMaxHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+
+ if (nMaxHeight < rParam.nManHeight-rParam.nDistance)
+ nMaxHeight = rParam.nManHeight-rParam.nDistance; // configured Minimum
+
+ aBorderSize.setHeight( nMaxHeight );
+ }
+
+ if ( bDoPrint )
+ {
+ double nOldScaleX = nScaleX;
+ double nOldScaleY = nScaleY;
+ nScaleX = nScaleY = 1.0; // output directly in Twips
+ DrawBorder( aBorderStart.X(), aBorderStart.Y(), aBorderSize.Width(), aBorderSize.Height(),
+ rParam.pBorder, rParam.pBack, rParam.pShadow );
+ nScaleX = nOldScaleX;
+ nScaleY = nOldScaleY;
+
+ // Clipping for Text
+
+ pDev->SetClipRegion(vcl::Region(tools::Rectangle(aStart, aPaperSize)));
+
+ // left
+
+ const EditTextObject* pObject = pHFItem->GetLeftArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ // center
+
+ pObject = pHFItem->GetCenterArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ // right
+
+ pObject = pHFItem->GetRightArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ pDev->SetClipRegion();
+ }
+
+ if ( pLocationData )
+ {
+ tools::Rectangle aHeaderRect( aBorderStart, aBorderSize );
+ pLocationData->AddHeaderFooter( aHeaderRect, bHeader, bLeft );
+ }
+}
+
+tools::Long ScPrintFunc::DoNotes( tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ if (bDoPrint)
+ pDev->SetMapMode(aTwipMode);
+
+ MakeEditEngine();
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ pEditEngine->SetDefaults( *pEditDefaults );
+
+ vcl::Font aMarkFont;
+ ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
+ rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).GetFont( aMarkFont, eColorMode );
+ pDev->SetFont( aMarkFont );
+ tools::Long nMarkLen = pDev->GetTextWidth("GW99999:");
+ // without Space-Char, because it rarely arrives there
+
+ Size aDataSize = aPageRect.GetSize();
+ if ( nMarkLen > aDataSize.Width() / 2 ) // everything much too small?
+ nMarkLen = aDataSize.Width() / 2; // split the page appropriately
+ aDataSize.AdjustWidth( -nMarkLen );
+
+ pEditEngine->SetPaperSize( aDataSize );
+ tools::Long nPosX = aPageRect.Left() + nMarkLen;
+ tools::Long nPosY = aPageRect.Top();
+
+ tools::Long nCount = 0;
+ tools::Long nSize = aNotePosList.size();
+ bool bOk;
+ do
+ {
+ bOk = false;
+ if ( nNoteStart + nCount < nSize)
+ {
+ ScAddress &rPos = aNotePosList[ nNoteStart + nCount ];
+
+ if( const ScPostIt* pNote = rDoc.GetNote( rPos ) )
+ {
+ if(const EditTextObject *pEditText = pNote->GetEditTextObject())
+ pEditEngine->SetTextCurrentDefaults(*pEditText);
+ tools::Long nTextHeight = pEditEngine->GetTextHeight();
+ if ( nPosY + nTextHeight < aPageRect.Bottom() )
+ {
+ if (bDoPrint)
+ {
+ pEditEngine->Draw(*pDev, Point(nPosX, nPosY));
+
+ OUString aMarkStr(rPos.Format(ScRefFlags::VALID, &rDoc, rDoc.GetAddressConvention()) + ":");
+
+ // cell position also via EditEngine, for correct positioning
+ pEditEngine->SetTextCurrentDefaults(aMarkStr);
+ pEditEngine->Draw(*pDev, Point(aPageRect.Left(), nPosY));
+ }
+
+ if ( pLocationData )
+ {
+ tools::Rectangle aTextRect( Point( nPosX, nPosY ), Size( aDataSize.Width(), nTextHeight ) );
+ pLocationData->AddNoteText( aTextRect, rPos );
+ tools::Rectangle aMarkRect( Point( aPageRect.Left(), nPosY ), Size( nMarkLen, nTextHeight ) );
+ pLocationData->AddNoteMark( aMarkRect, rPos );
+ }
+
+ nPosY += nTextHeight;
+ nPosY += 200; // Distance
+ ++nCount;
+ bOk = true;
+ }
+ }
+ }
+ }
+ while (bOk);
+
+ return nCount;
+}
+
+tools::Long ScPrintFunc::PrintNotes( tools::Long nPageNo, tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ if ( nNoteStart >= static_cast<tools::Long>(aNotePosList.size()) || !aTableParam.bNotes )
+ return 0;
+
+ if ( bDoPrint && bClearWin )
+ {
+ //! aggregate PrintPage !!!
+
+ Color aBackgroundColor( COL_WHITE );
+ if ( bUseStyleColor )
+ aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor();
+ pDev->SetFillColor(aBackgroundColor);
+ pDev->DrawRect(tools::Rectangle(Point(),
+ Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
+ static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
+ }
+
+ // adjust aPageRect for left/right page
+
+ tools::Rectangle aTempRect( Point(), aPageSize );
+ if (IsMirror(nPageNo))
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
+ }
+ else
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "StartPage does not exist anymore" );
+ }
+
+ if ( bDoPrint || pLocationData )
+ {
+ // Head and foot lines
+
+ if (aHdr.bEnable)
+ {
+ tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
+ PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
+ }
+ if (aFtr.bEnable)
+ {
+ tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
+ PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
+ }
+ }
+
+ tools::Long nCount = DoNotes( nNoteStart, bDoPrint, pLocationData );
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "EndPage does not exist anymore" );
+ }
+
+ return nCount;
+}
+
+void ScPrintFunc::PrintPage( tools::Long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ // nPageNo is the page number within all sheets of one "start page" setting
+
+ if ( bClearWin && bDoPrint )
+ {
+ // must exactly fit to painting the frame in preview.cxx !!!
+
+ Color aBackgroundColor( COL_WHITE );
+ if ( bUseStyleColor )
+ aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor();
+ pDev->SetFillColor(aBackgroundColor);
+ pDev->DrawRect(tools::Rectangle(Point(),
+ Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
+ static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
+ }
+
+ // adjust aPageRect for left/right page
+
+ tools::Rectangle aTempRect( Point(), aPageSize );
+ if (IsMirror(nPageNo))
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
+ }
+ else
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
+ }
+
+ if ( aAreaParam.bRepeatCol )
+ if ( nX1 > nRepeatStartCol && nX1 <= nRepeatEndCol )
+ nX1 = nRepeatEndCol + 1;
+ bool bDoRepCol = (aAreaParam.bRepeatCol && nX1 > nRepeatEndCol);
+ if ( aAreaParam.bRepeatRow )
+ if ( nY1 > nRepeatStartRow && nY1 <= nRepeatEndRow )
+ nY1 = nRepeatEndRow + 1;
+ bool bDoRepRow = (aAreaParam.bRepeatRow && nY1 > nRepeatEndRow);
+
+ // use new object hide flags in SdrPaintView
+ if(pDrawView)
+ {
+ pDrawView->setHideOle(!aTableParam.bObjects);
+ pDrawView->setHideChart(!aTableParam.bCharts);
+ pDrawView->setHideDraw(!aTableParam.bDrawings);
+ pDrawView->setHideFormControl(!aTableParam.bDrawings);
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "StartPage does not exist anymore" );
+ }
+
+ // head and foot lines (without centering)
+
+ if (aHdr.bEnable)
+ {
+ tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
+ PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
+ }
+ if (aFtr.bEnable)
+ {
+ tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
+ PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
+ }
+
+ // Position ( margins / centering )
+
+ tools::Long nLeftSpace = aPageRect.Left(); // Document-Twips
+ tools::Long nTopSpace = aPageRect.Top();
+ if ( bCenterHor || bLayoutRTL )
+ {
+ tools::Long nDataWidth = 0;
+ SCCOL i;
+ for (i=nX1; i<=nX2; i++)
+ nDataWidth += rDoc.GetColWidth( i,nPrintTab );
+ if (bDoRepCol)
+ for (i=nRepeatStartCol; i<=nRepeatEndCol; i++)
+ nDataWidth += rDoc.GetColWidth( i,nPrintTab );
+ if (aTableParam.bHeaders)
+ nDataWidth += tools::Long(PRINT_HEADER_WIDTH);
+ if (pBorderItem)
+ nDataWidth += pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT); //! Line width?
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ nDataWidth += pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT);
+ if ( bCenterHor )
+ {
+ nLeftSpace += ( aPageRect.GetWidth() - nDataWidth ) / 2; // LTR or RTL
+ if (pBorderItem)
+ nLeftSpace -= lcl_LineTotal(pBorderItem->GetLeft());
+ }
+ else if ( bLayoutRTL )
+ nLeftSpace += aPageRect.GetWidth() - nDataWidth; // align to the right edge of the page
+ }
+ if ( bCenterVer )
+ {
+ tools::Long nDataHeight = rDoc.GetRowHeight( nY1, nY2, nPrintTab);
+ if (bDoRepRow)
+ nDataHeight += rDoc.GetRowHeight( nRepeatStartRow,
+ nRepeatEndRow, nPrintTab);
+ if (aTableParam.bHeaders)
+ nDataHeight += tools::Long(PRINT_HEADER_HEIGHT);
+ if (pBorderItem)
+ nDataHeight += pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM); //! Line width?
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ nDataHeight += pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+ nTopSpace += ( aPageRect.GetHeight() - nDataHeight ) / 2;
+ if (pBorderItem)
+ nTopSpace -= lcl_LineTotal(pBorderItem->GetTop());
+ }
+
+ // calculate sizes of the elements for partitioning
+ // (header, repeat, data)
+
+ tools::Long nHeaderWidth = 0;
+ tools::Long nHeaderHeight = 0;
+ tools::Long nRepeatWidth = 0;
+ tools::Long nRepeatHeight = 0;
+ tools::Long nContentWidth = 0; // scaled - not the same as nDataWidth above
+ tools::Long nContentHeight = 0;
+ if (aTableParam.bHeaders)
+ {
+ nHeaderWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ nHeaderHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ }
+ if (bDoRepCol)
+ for (SCCOL i=nRepeatStartCol; i<=nRepeatEndCol; i++)
+ nRepeatWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
+ if (bDoRepRow)
+ nRepeatHeight += rDoc.GetScaledRowHeight( nRepeatStartRow,
+ nRepeatEndRow, nPrintTab, nScaleY);
+ for (SCCOL i=nX1; i<=nX2; i++)
+ nContentWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
+ nContentHeight += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab,
+ nScaleY);
+
+ // partition the page
+
+ tools::Long nStartX = static_cast<tools::Long>( nLeftSpace * nScaleX );
+ tools::Long nStartY = static_cast<tools::Long>( nTopSpace * nScaleY );
+ tools::Long nInnerStartX = nStartX;
+ tools::Long nInnerStartY = nStartY;
+ if (pBorderItem)
+ {
+ nInnerStartX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetLeft()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::LEFT) ) * nScaleX );
+ nInnerStartY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetTop()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::TOP) ) * nScaleY );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ nInnerStartX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
+ nInnerStartY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
+ }
+
+ if ( bLayoutRTL )
+ {
+ // arrange elements starting from the right edge
+ nInnerStartX += nHeaderWidth + nRepeatWidth + nContentWidth;
+
+ // make rounding easier so the elements are really next to each other in preview
+ Size aOffsetOnePixel = pDev->PixelToLogic( Size(1,1), aOffsetMode );
+ tools::Long nOffsetOneX = aOffsetOnePixel.Width();
+ nInnerStartX += nOffsetOneX / 2;
+ }
+
+ tools::Long nFrameStartX = nInnerStartX;
+ tools::Long nFrameStartY = nInnerStartY;
+
+ tools::Long nRepStartX = nInnerStartX + nHeaderWidth * nLayoutSign; // widths/heights are 0 if not used
+ tools::Long nRepStartY = nInnerStartY + nHeaderHeight;
+ tools::Long nDataX = nRepStartX + nRepeatWidth * nLayoutSign;
+ tools::Long nDataY = nRepStartY + nRepeatHeight;
+ tools::Long nEndX = nDataX + nContentWidth * nLayoutSign;
+ tools::Long nEndY = nDataY + nContentHeight;
+ tools::Long nFrameEndX = nEndX;
+ tools::Long nFrameEndY = nEndY;
+
+ if ( bLayoutRTL )
+ {
+ // each element's start position is its left edge
+ //! subtract one pixel less?
+ nInnerStartX -= nHeaderWidth; // used for header
+ nRepStartX -= nRepeatWidth;
+ nDataX -= nContentWidth;
+
+ // continue right of the main elements again
+ nEndX += nHeaderWidth + nRepeatWidth + nContentWidth;
+ }
+
+ // Page frame / background
+
+ //! adjust nEndX/Y
+
+ tools::Long nBorderEndX = nEndX;
+ tools::Long nBorderEndY = nEndY;
+ if (pBorderItem)
+ {
+ nBorderEndX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetRight()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT) ) * nScaleX );
+ nBorderEndY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetBottom()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM) ) * nScaleY );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ nBorderEndX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
+ nBorderEndY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
+ }
+
+ if ( bDoPrint )
+ {
+ pDev->SetMapMode( aOffsetMode );
+ DrawBorder( nStartX, nStartY, nBorderEndX-nStartX, nBorderEndY-nStartY,
+ pBorderItem, pBackgroundItem, pShadowItem );
+
+ pDev->SetMapMode( aTwipMode );
+ }
+
+ pDev->SetMapMode( aOffsetMode );
+
+ // Output repeating rows/columns
+
+ if (bDoRepCol && bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
+ nRepStartX,nRepStartY, true, true, false, false );
+ if ( pLocationData )
+ LocateArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
+ nRepStartX,nRepStartY, true, true, *pLocationData );
+ }
+ if (bDoRepCol)
+ {
+ if ( bDoPrint )
+ PrintArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY,
+ true, !bDoRepRow, false, true );
+ if ( pLocationData )
+ LocateArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY, true, false, *pLocationData );
+ }
+ if (bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY,
+ !bDoRepCol, true, true, false );
+ if ( pLocationData )
+ LocateArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY, false, true, *pLocationData );
+ }
+
+ // output data
+
+ if ( bDoPrint )
+ PrintArea( nX1,nY1, nX2,nY2, nDataX,nDataY, !bDoRepCol,!bDoRepRow, true, true );
+ if ( pLocationData )
+ LocateArea( nX1,nY1, nX2,nY2, nDataX,nDataY, false,false, *pLocationData );
+
+ // output column/row headers
+ // after data (through probably shadow)
+
+ Color aGridColor( COL_BLACK );
+ if ( bUseStyleColor )
+ aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+
+ if (aTableParam.bHeaders)
+ {
+ if ( bDoPrint )
+ {
+ pDev->SetLineColor( aGridColor );
+ pDev->SetFillColor();
+ pDev->SetMapMode(aOffsetMode);
+ }
+
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ vcl::Font aFont;
+ ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
+ aPattern.GetFont( aFont, eColorMode, pDev );
+ pDev->SetFont( aFont );
+
+ if (bDoRepCol)
+ {
+ if ( bDoPrint )
+ PrintColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY );
+ if ( pLocationData )
+ LocateColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY, true, *pLocationData );
+ }
+ if ( bDoPrint )
+ PrintColHdr( nX1,nX2, nDataX,nInnerStartY );
+ if ( pLocationData )
+ LocateColHdr( nX1,nX2, nDataX,nInnerStartY, false, *pLocationData );
+ if (bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY );
+ if ( pLocationData )
+ LocateRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY, true, *pLocationData );
+ }
+ if ( bDoPrint )
+ PrintRowHdr( nY1,nY2, nInnerStartX,nDataY );
+ if ( pLocationData )
+ LocateRowHdr( nY1,nY2, nInnerStartX,nDataY, false, *pLocationData );
+ }
+
+ // simple frame
+
+ if ( bDoPrint && ( aTableParam.bGrid || aTableParam.bHeaders ) )
+ {
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nLeftX = nFrameStartX;
+ tools::Long nTopY = nFrameStartY - nOneY;
+ tools::Long nRightX = nFrameEndX;
+ tools::Long nBottomY = nFrameEndY - nOneY;
+ if ( !bLayoutRTL )
+ {
+ nLeftX -= nOneX;
+ nRightX -= nOneX;
+ }
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor( aGridColor );
+ pDev->SetFillColor();
+ pDev->DrawRect( tools::Rectangle( nLeftX, nTopY, nRightX, nBottomY ) );
+ // nEndX/Y without frame-adaptation
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "EndPage does not exist anymore" );
+ }
+
+ aLastSourceRange = ScRange( nX1, nY1, nPrintTab, nX2, nY2, nPrintTab );
+ bSourceRangeValid = true;
+}
+
+void ScPrintFunc::SetOffset( const Point& rOfs )
+{
+ aSrcOffset = rOfs;
+}
+
+void ScPrintFunc::SetManualZoom( sal_uInt16 nNewZoom )
+{
+ nManualZoom = nNewZoom;
+}
+
+void ScPrintFunc::SetClearFlag( bool bFlag )
+{
+ bClearWin = bFlag;
+}
+
+void ScPrintFunc::SetUseStyleColor( bool bFlag )
+{
+ bUseStyleColor = bFlag;
+ if (pEditEngine)
+ pEditEngine->EnableAutoColor( bUseStyleColor );
+}
+
+void ScPrintFunc::SetRenderFlag( bool bFlag )
+{
+ bIsRender = bFlag; // set when using XRenderable (PDF)
+}
+
+void ScPrintFunc::SetExclusivelyDrawOleAndDrawObjects()
+{
+ aTableParam.bCellContent = false;
+ aTableParam.bNotes = false;
+ aTableParam.bGrid = false;
+ aTableParam.bHeaders = false;
+ aTableParam.bFormulas = false;
+ aTableParam.bNullVals = false;
+}
+
+// UpdatePages is only called from outside to set the breaks correctly for viewing
+// - always without UserArea
+
+bool ScPrintFunc::UpdatePages()
+{
+ if (!pParamSet)
+ return false;
+
+ // Zoom
+
+ nZoom = 100;
+ if (aTableParam.bScalePageNum || aTableParam.bScaleTo)
+ nZoom = ZOOM_MIN; // correct for breaks
+ else if (aTableParam.bScaleAll)
+ {
+ nZoom = aTableParam.nScaleAll;
+ if ( nZoom <= ZOOM_MIN )
+ nZoom = ZOOM_MIN;
+ }
+
+ OUString aName = rDoc.GetPageStyle( nPrintTab );
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( nTab==nPrintTab || rDoc.GetPageStyle(nTab)==aName )
+ {
+ // Repeating rows/columns
+ rDoc.SetRepeatArea( nTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
+
+ // set breaks
+ ResetBreaks(nTab);
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid);
+ }
+
+ return true;
+}
+
+tools::Long ScPrintFunc::CountPages() // sets also nPagesX, nPagesY
+{
+ bool bAreaOk = false;
+
+ if (rDoc.HasTable( nPrintTab ))
+ {
+ if (aAreaParam.bPrintArea) // Specify print area?
+ {
+ if ( bPrintCurrentTable )
+ {
+ ScRange& rRange = aAreaParam.aPrintArea;
+
+ // Here, no comparison of the tables any more. Area is always valid for this table
+ // If comparison should be done here, the table of print ranges must be adjusted
+ // when inserting tables etc.!
+
+ nStartCol = rRange.aStart.Col();
+ nStartRow = rRange.aStart.Row();
+ nEndCol = rRange.aEnd .Col();
+ nEndRow = rRange.aEnd .Row();
+ bAreaOk = AdjustPrintArea(false); // limit
+ }
+ else
+ bAreaOk = false;
+ }
+ else // search from document
+ bAreaOk = AdjustPrintArea(true);
+ }
+
+ if (bAreaOk)
+ {
+ tools::Long nPages = 0;
+ size_t nY;
+ if (bMultiArea)
+ {
+ sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
+ for (sal_uInt16 i=0; i<nRCount; i++)
+ {
+ CalcZoom(i);
+ if ( aTableParam.bSkipEmpty )
+ for (nY=0; nY< m_aRanges.m_nPagesY; nY++)
+ nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
+ else
+ nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
+ if ( pPageData )
+ FillPageData();
+ }
+ }
+ else
+ {
+ CalcZoom(RANGENO_NORANGE); // calculate Zoom
+ if ( aTableParam.bSkipEmpty )
+ for (nY=0; nY<m_aRanges.m_nPagesY; nY++)
+ nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
+ else
+ nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
+ if ( pPageData )
+ FillPageData();
+ }
+ return nPages;
+ }
+ else
+ {
+ m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
+ return 0;
+ }
+}
+
+tools::Long ScPrintFunc::CountNotePages()
+{
+ if ( !aTableParam.bNotes || !bPrintCurrentTable )
+ return 0;
+
+ bool bError = false;
+ if (!aAreaParam.bPrintArea)
+ bError = !AdjustPrintArea(true); // completely search in Doc
+
+ sal_uInt16 nRepeats = 1; // how often go through it ?
+ if (bMultiArea)
+ nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
+ if (bError)
+ nRepeats = 0;
+
+ for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
+ {
+ bool bDoThis = true;
+ if (bMultiArea) // go through all Areas
+ {
+ const ScRange* pThisRange = rDoc.GetPrintRange( nPrintTab, nStep );
+ if ( pThisRange )
+ {
+ nStartCol = pThisRange->aStart.Col();
+ nStartRow = pThisRange->aStart.Row();
+ nEndCol = pThisRange->aEnd .Col();
+ nEndRow = pThisRange->aEnd .Row();
+ bDoThis = AdjustPrintArea(false);
+ }
+ }
+
+ if (bDoThis)
+ {
+ assert( bPrintAreaValid );
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ if (rDoc.HasColNotes(nCol, nPrintTab))
+ {
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
+ {
+ if ( rDoc.HasNote(nCol, nRow, nPrintTab) )
+ aNotePosList.emplace_back( nCol, nRow, nPrintTab );
+ }
+ }
+ }
+ }
+ }
+
+ tools::Long nPages = 0;
+ tools::Long nNoteNr = 0;
+ tools::Long nNoteAdd;
+ do
+ {
+ nNoteAdd = PrintNotes( nPages, nNoteNr, false, nullptr );
+ if (nNoteAdd)
+ {
+ nNoteNr += nNoteAdd;
+ ++nPages;
+ }
+ }
+ while (nNoteAdd);
+
+ return nPages;
+}
+
+void ScPrintFunc::InitModes() // set MapModes from nZoom etc.
+{
+ aOffset = Point( aSrcOffset.X()*100/nZoom, aSrcOffset.Y()*100/nZoom );
+
+ tools::Long nEffZoom = nZoom * static_cast<tools::Long>(nManualZoom);
+ constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
+ nScaleX = nScaleY = HMM_PER_TWIPS; // output in 1/100 mm
+
+ Fraction aZoomFract( nEffZoom,10000 );
+ Fraction aHorFract = aZoomFract;
+
+ if ( !pPrinter && !bIsRender ) // adjust scale for preview
+ {
+ double nFact = pDocShell->GetOutputFactor();
+ aHorFract = Fraction( static_cast<tools::Long>( nEffZoom / nFact ), 10000 );
+ }
+
+ aLogicMode = MapMode( MapUnit::Map100thMM, Point(), aHorFract, aZoomFract );
+
+ Point aLogicOfs( -aOffset.X(), -aOffset.Y() );
+ aOffsetMode = MapMode( MapUnit::Map100thMM, aLogicOfs, aHorFract, aZoomFract );
+
+ Point aTwipsOfs( static_cast<tools::Long>( -aOffset.X() / nScaleX + 0.5 ), static_cast<tools::Long>( -aOffset.Y() / nScaleY + 0.5 ) );
+ aTwipMode = MapMode( MapUnit::MapTwip, aTwipsOfs, aHorFract, aZoomFract );
+}
+
+void ScPrintFunc::ApplyPrintSettings()
+{
+ if ( !pPrinter )
+ return;
+
+ // Configure Printer to Printing
+
+ Size aEnumSize = aPageSize;
+
+ pPrinter->SetOrientation( bLandscape ? Orientation::Landscape : Orientation::Portrait );
+ if ( bLandscape )
+ {
+ // landscape is always interpreted as a rotation by 90 degrees !
+ // this leads to non WYSIWIG but at least it prints!
+ // #i21775#
+ tools::Long nTemp = aEnumSize.Width();
+ aEnumSize.setWidth( aEnumSize.Height() );
+ aEnumSize.setHeight( nTemp );
+ }
+ Paper ePaper = SvxPaperInfo::GetSvxPaper( aEnumSize, MapUnit::MapTwip );
+ sal_uInt16 nPaperBin = pParamSet->Get(ATTR_PAGE_PAPERBIN).GetValue();
+
+ pPrinter->SetPaper( ePaper );
+ if ( PAPER_USER == ePaper )
+ {
+ MapMode aPrinterMode = pPrinter->GetMapMode();
+ MapMode aLocalMode( MapUnit::MapTwip );
+ pPrinter->SetMapMode( aLocalMode );
+ pPrinter->SetPaperSizeUser( aEnumSize );
+ pPrinter->SetMapMode( aPrinterMode );
+ }
+
+ pPrinter->SetPaperBin( nPaperBin );
+}
+
+// rPageRanges = range for all tables
+// nStartPage = rPageRanges starts at nStartPage
+// nDisplayStart = continuous number for displaying the page number
+
+tools::Long ScPrintFunc::DoPrint( const MultiSelection& rPageRanges,
+ tools::Long nStartPage, tools::Long nDisplayStart, bool bDoPrint,
+ ScPreviewLocationData* pLocationData )
+{
+ OSL_ENSURE(pDev,"Device == NULL");
+ if (!pParamSet)
+ return 0;
+
+ if ( pPrinter && bDoPrint )
+ ApplyPrintSettings();
+
+ InitModes();
+ if ( pLocationData )
+ {
+ pLocationData->SetCellMapMode( aOffsetMode );
+ pLocationData->SetPrintTab( nPrintTab );
+ }
+
+ MakeTableString();
+
+ tools::Long nPageNo = 0;
+ tools::Long nPrinted = 0;
+ tools::Long nEndPage = rPageRanges.GetTotalRange().Max();
+
+ sal_uInt16 nRepeats = 1;
+ if (bMultiArea)
+ nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
+ for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
+ {
+ if (bMultiArea) // replace area
+ {
+ CalcZoom(nStep); // also sets nStartCol etc. new
+ InitModes();
+ }
+
+ SCCOL nX1;
+ SCROW nY1;
+ SCCOL nX2;
+ SCROW nY2;
+ size_t nCountX;
+ size_t nCountY;
+
+ if (aTableParam.bTopDown) // top-bottom
+ {
+ nX1 = nStartCol;
+ for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
+ {
+ OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX (!)");
+ nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
+ for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
+ {
+ auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+ if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
+ {
+ if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
+ {
+ PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
+ bDoPrint, pLocationData );
+ ++nPrinted;
+ }
+ ++nPageNo;
+ }
+ }
+ nX1 = nX2 + 1;
+ }
+ }
+ else // left to right
+ {
+ for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
+ {
+ auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+ nX1 = nStartCol;
+ for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
+ {
+ OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX");
+ nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
+ if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
+ {
+ if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
+ {
+ PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
+ bDoPrint, pLocationData );
+ ++nPrinted;
+ }
+ ++nPageNo;
+ }
+ nX1 = nX2 + 1;
+ }
+ }
+ }
+ }
+
+ aFieldData.aTabName = ScResId( STR_NOTES );
+
+ tools::Long nNoteNr = 0;
+ tools::Long nNoteAdd;
+ do
+ {
+ if ( nPageNo+nStartPage <= nEndPage )
+ {
+ bool bPageSelected = rPageRanges.IsSelected( nPageNo+nStartPage+1 );
+ nNoteAdd = PrintNotes( nPageNo+nStartPage, nNoteNr, bDoPrint && bPageSelected,
+ ( bPageSelected ? pLocationData : nullptr ) );
+ if ( nNoteAdd )
+ {
+ nNoteNr += nNoteAdd;
+ if (bPageSelected)
+ {
+ ++nPrinted;
+ bSourceRangeValid = false; // last page was no cell range
+ }
+ ++nPageNo;
+ }
+ }
+ else
+ nNoteAdd = 0;
+ }
+ while (nNoteAdd);
+
+ if ( bMultiArea )
+ ResetBreaks(nPrintTab); //breaks correct for displaying
+
+ return nPrinted;
+}
+
+void ScPrintFunc::CalcZoom( sal_uInt16 nRangeNo ) // calculate zoom
+{
+ sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
+ const ScRange* pThisRange = nullptr;
+ if (nRangeNo != RANGENO_NORANGE && nRangeNo < nRCount)
+ pThisRange = rDoc.GetPrintRange( nPrintTab, nRangeNo );
+ if ( pThisRange )
+ {
+ nStartCol = pThisRange->aStart.Col();
+ nStartRow = pThisRange->aStart.Row();
+ nEndCol = pThisRange->aEnd .Col();
+ nEndRow = pThisRange->aEnd .Row();
+ }
+
+ if (!AdjustPrintArea(false)) // empty
+ {
+ nZoom = 100;
+ m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
+ return;
+ }
+
+ rDoc.SetRepeatArea( nPrintTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
+
+ if (aTableParam.bScalePageNum)
+ {
+ nZoom = 100;
+ sal_uInt16 nPagesToFit = aTableParam.nScalePageNum;
+
+ // If manual breaks are forced, calculate minimum # pages required
+ if (aTableParam.bForceBreaks)
+ {
+ sal_uInt16 nMinPages = 0;
+ std::set<SCROW> aRowBreaks;
+ std::set<SCCOL> aColBreaks;
+ rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
+ rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
+ nMinPages = (aRowBreaks.size() + 1) * (aColBreaks.size() + 1);
+
+ // #i54993# use min forced by breaks if it's > # pages in
+ // scale parameter to avoid bottoming out at <= ZOOM_MIN
+ nPagesToFit = std::max(nMinPages, nPagesToFit);
+ }
+
+ sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
+ while (true)
+ {
+ if (nZoom <= ZOOM_MIN)
+ break;
+
+ CalcPages();
+ bool bFitsPage = (m_aRanges.m_nPagesX * m_aRanges.m_nPagesY <= nPagesToFit);
+
+ if (bFitsPage)
+ {
+ if (nZoom == 100)
+ // If it fits at 100%, it's good enough for me.
+ break;
+
+ nLastFitZoom = nZoom;
+ nZoom = (nLastNonFitZoom + nZoom) / 2;
+
+ if (nLastFitZoom == nZoom)
+ // It converged. Use this zoom level.
+ break;
+ }
+ else
+ {
+ if (nZoom - nLastFitZoom <= 1)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ break;
+ }
+
+ nLastNonFitZoom = nZoom;
+ nZoom = (nLastFitZoom + nZoom) / 2;
+ }
+ }
+ }
+ else if (aTableParam.bScaleTo)
+ {
+ nZoom = 100;
+ sal_uInt16 nW = aTableParam.nScaleWidth;
+ sal_uInt16 nH = aTableParam.nScaleHeight;
+
+ // If manual breaks are forced, calculate minimum # pages required
+ if (aTableParam.bForceBreaks)
+ {
+ sal_uInt16 nMinPagesW = 0, nMinPagesH = 0;
+ std::set<SCROW> aRowBreaks;
+ std::set<SCCOL> aColBreaks;
+ rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
+ rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
+ nMinPagesW = aColBreaks.size() + 1;
+ nMinPagesH = aRowBreaks.size() + 1;
+
+ // #i54993# use min forced by breaks if it's > # pages in
+ // scale parameters to avoid bottoming out at <= ZOOM_MIN
+ nW = std::max(nMinPagesW, nW);
+ nH = std::max(nMinPagesH, nH);
+ }
+
+ sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
+ while (true)
+ {
+ if (nZoom <= ZOOM_MIN)
+ break;
+
+ CalcPages();
+ bool bFitsPage = ((!nW || (m_aRanges.m_nPagesX <= nW)) && (!nH || (m_aRanges.m_nPagesY <= nH)));
+
+ if (bFitsPage)
+ {
+ if (nZoom == 100)
+ // If it fits at 100%, it's good enough for me.
+ break;
+
+ nLastFitZoom = nZoom;
+ nZoom = (nLastNonFitZoom + nZoom) / 2;
+
+ if (nLastFitZoom == nZoom)
+ // It converged. Use this zoom level.
+ break;
+ }
+ else
+ {
+ if (nZoom - nLastFitZoom <= 1)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ break;
+ }
+
+ nLastNonFitZoom = nZoom;
+ nZoom = (nLastFitZoom + nZoom) / 2;
+ }
+ }
+ // tdf#103516 remove the almost blank page(s) for better
+ // interoperability by using slightly smaller zoom
+ if (nW > 0 && nH == 0 && m_aRanges.m_nPagesY > 1)
+ {
+ sal_uInt32 nLastPagesY = m_aRanges.m_nPagesY;
+ nLastFitZoom = nZoom;
+ nZoom *= 0.98;
+ if (nZoom < nLastFitZoom)
+ {
+ CalcPages();
+ // same page count with smaller zoom: use the original zoom
+ if (m_aRanges.m_nPagesY == nLastPagesY)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ }
+ }
+ }
+ }
+ else if (aTableParam.bScaleAll)
+ {
+ nZoom = aTableParam.nScaleAll;
+ if ( nZoom <= ZOOM_MIN )
+ nZoom = ZOOM_MIN;
+ CalcPages();
+ }
+ else
+ {
+ OSL_ENSURE( aTableParam.bScaleNone, "no scale flag is set" );
+ nZoom = 100;
+ CalcPages();
+ }
+}
+
+Size ScPrintFunc::GetDocPageSize()
+{
+ // Adjust height of head/foot line
+
+ InitModes(); // initialize aTwipMode from nZoom
+ pDev->SetMapMode( aTwipMode ); // head/foot line in Twips
+ UpdateHFHeight( aHdr );
+ UpdateHFHeight( aFtr );
+
+ // Page size in Document-Twips
+ // Calculating Left / Right also in PrintPage
+
+ aPageRect = tools::Rectangle( Point(), aPageSize );
+ aPageRect.SetLeft( ( aPageRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aPageRect.Right() - nRightMargin ) * 100 / nZoom );
+ aPageRect.SetTop( ( aPageRect.Top() + nTopMargin ) * 100 / nZoom + aHdr.nHeight );
+ aPageRect.SetBottom( ( aPageRect.Bottom() - nBottomMargin ) * 100 / nZoom - aFtr.nHeight );
+
+ Size aDocPageSize = aPageRect.GetSize();
+ if (aTableParam.bHeaders)
+ {
+ aDocPageSize.AdjustWidth( -(tools::Long(PRINT_HEADER_WIDTH)) );
+ aDocPageSize.AdjustHeight( -(tools::Long(PRINT_HEADER_HEIGHT)) );
+ }
+ if (pBorderItem)
+ {
+ aDocPageSize.AdjustWidth( -(lcl_LineTotal(pBorderItem->GetLeft()) +
+ lcl_LineTotal(pBorderItem->GetRight()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT)) );
+ aDocPageSize.AdjustHeight( -(lcl_LineTotal(pBorderItem->GetTop()) +
+ lcl_LineTotal(pBorderItem->GetBottom()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM)) );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ aDocPageSize.AdjustWidth( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
+ aDocPageSize.AdjustHeight( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
+ }
+ return aDocPageSize;
+}
+
+void ScPrintFunc::ResetBreaks( SCTAB nTab ) // Set Breaks correctly for view
+{
+ rDoc.SetPageSize( nTab, GetDocPageSize() );
+ rDoc.UpdatePageBreaks( nTab );
+}
+
+static void lcl_SetHidden( const ScDocument& rDoc, SCTAB nPrintTab, ScPageRowEntry& rPageRowEntry,
+ SCCOL nStartCol, const std::vector< SCCOL >& rPageEndX )
+{
+ size_t nPagesX = rPageRowEntry.GetPagesX();
+ SCROW nStartRow = rPageRowEntry.GetStartRow();
+ SCROW nEndRow = rPageRowEntry.GetEndRow();
+
+ bool bLeftIsEmpty = false;
+ ScRange aTempRange;
+ tools::Rectangle aTempRect = rDoc.GetMMRect( 0,0, 0,0, 0 );
+
+ for (size_t i=0; i<nPagesX; i++)
+ {
+ OSL_ENSURE(i < rPageEndX.size(), "vector access error for aPageEndX");
+ SCCOL nEndCol = rPageEndX[i];
+ if ( rDoc.IsPrintEmpty( nStartCol, nStartRow, nEndCol, nEndRow, nPrintTab,
+ bLeftIsEmpty, &aTempRange, &aTempRect ) )
+ {
+ rPageRowEntry.SetHidden(i);
+ bLeftIsEmpty = true;
+ }
+ else
+ bLeftIsEmpty = false;
+
+ nStartCol = nEndCol+1;
+ }
+}
+
+void ScPrintFunc::CalcPages() // calculates aPageRect and pages from nZoom
+{
+ assert( bPrintAreaValid );
+ m_aRanges.calculate(rDoc, aTableParam.bSkipEmpty, aAreaParam.bPrintArea, nStartRow, nEndRow, nStartCol, nEndCol, nPrintTab, GetDocPageSize());
+}
+
+namespace sc
+{
+
+PrintPageRanges::PrintPageRanges()
+ : m_nPagesX(0)
+ , m_nPagesY(0)
+ , m_nTotalY(0)
+{}
+
+bool PrintPageRanges::checkIfAlreadyCalculatedAndSet(
+ bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow,
+ SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & rDocSize)
+{
+ if (bSkipEmpty == m_aInput.m_bSkipEmpty &&
+ bPrintArea == m_aInput.m_bPrintArea &&
+ nStartRow == m_aInput.m_nStartRow && nEndRow == m_aInput.m_nEndRow &&
+ nStartCol == m_aInput.m_nStartCol && nEndCol == m_aInput.m_nEndCol &&
+ nPrintTab == m_aInput.m_nPrintTab &&
+ rDocSize == m_aInput.m_aDocSize)
+ {
+ return true;
+ }
+
+ m_aInput.m_bSkipEmpty = bSkipEmpty;
+ m_aInput.m_bPrintArea = bPrintArea;
+ m_aInput.m_nStartRow = nStartRow;
+ m_aInput.m_nEndRow = nEndRow;
+ m_aInput.m_nStartCol = nStartCol;
+ m_aInput.m_nEndCol = nEndCol;
+ m_aInput.m_nPrintTab = nPrintTab;
+ m_aInput.m_aDocSize = rDocSize;
+
+ return false;
+}
+
+void PrintPageRanges::calculate(ScDocument& rDoc,
+ bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow,
+ SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & rDocSize)
+{
+ // Already calculated?
+ if (checkIfAlreadyCalculatedAndSet(bSkipEmpty, bPrintArea,
+ nStartRow, nEndRow, nStartCol, nEndCol,
+ nPrintTab, rDocSize))
+ return;
+
+ rDoc.SetPageSize(nPrintTab, rDocSize);
+
+ // Clear the map to prevent any outdated values to "survive" when
+ // we have to recalculate the new values anyway
+ m_xPageRows->clear();
+
+ // #i123672# use dynamic mem to react on size changes
+ if (m_xPageEndX->size() < static_cast<size_t>(rDoc.MaxCol()) + 1)
+ {
+ m_xPageEndX->resize(rDoc.MaxCol()+1, SCCOL());
+ }
+
+ if (bPrintArea)
+ {
+ ScRange aRange(nStartCol, nStartRow, nPrintTab, nEndCol, nEndRow, nPrintTab);
+ rDoc.UpdatePageBreaks(nPrintTab, &aRange);
+ }
+ else
+ {
+ rDoc.UpdatePageBreaks(nPrintTab); // else, end is marked
+ }
+
+ const size_t nRealCnt = nEndRow - nStartRow + 1;
+
+ // #i123672# use dynamic mem to react on size changes
+ if (m_xPageEndY->size() < nRealCnt+1)
+ {
+ m_xPageEndY->resize(nRealCnt + 1, SCROW());
+ }
+
+ // Page alignment/splitting after breaks in Col/RowFlags
+ // Of several breaks in a hidden area, only one counts.
+
+ m_nPagesX = 0;
+ m_nPagesY = 0;
+ m_nTotalY = 0;
+
+ bool bVisCol = false;
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ {
+ bool bHidden = rDoc.ColHidden(i, nPrintTab);
+ bool bPageBreak(rDoc.HasColBreak(i, nPrintTab) & ScBreakType::Page);
+ if (i > nStartCol && bVisCol && bPageBreak)
+ {
+ OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
+ (*m_xPageEndX)[m_nPagesX] = i-1;
+ ++m_nPagesX;
+ bVisCol = false;
+ }
+ if (!bHidden)
+ bVisCol = true;
+ }
+ 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] = nEndCol;
+ ++m_nPagesX;
+ }
+
+ bool bVisRow = false;
+ SCROW nPageStartRow = nStartRow;
+ SCROW nLastVisibleRow = -1;
+
+ std::unique_ptr<ScRowBreakIterator> pRowBreakIter(rDoc.GetRowBreakIterator(nPrintTab));
+ SCROW nNextPageBreak = pRowBreakIter->first();
+ while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND && nNextPageBreak < nStartRow)
+ // Skip until the page break position is at the start row or greater.
+ nNextPageBreak = pRowBreakIter->next();
+
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ bool bPageBreak = (nNextPageBreak == nRow);
+ if (bPageBreak)
+ nNextPageBreak = pRowBreakIter->next();
+
+ if (nRow > nStartRow && bVisRow && bPageBreak)
+ {
+ OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for rPageEndY");
+ (*m_xPageEndY)[m_nTotalY] = nRow - 1;
+ ++m_nTotalY;
+
+ if (!bSkipEmpty || !rDoc.IsPrintEmpty(nStartCol, nPageStartRow, nEndCol, nRow-1, nPrintTab))
+ {
+ auto& rPageRow = (*m_xPageRows)[m_nPagesY];
+ rPageRow.SetStartRow(nPageStartRow);
+ rPageRow.SetEndRow(nRow - 1);
+ rPageRow.SetPagesX(m_nPagesX);
+ if (bSkipEmpty)
+ lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
+ ++m_nPagesY;
+ }
+
+ nPageStartRow = nRow;
+ bVisRow = false;
+ }
+
+ if (nRow <= nLastVisibleRow)
+ {
+ // This row is still visible. Don't bother calling RowHidden() to
+ // find out, for speed optimization.
+ bVisRow = true;
+ continue;
+ }
+
+ SCROW nLastRow = -1;
+ if (!rDoc.RowHidden(nRow, nPrintTab, nullptr, &nLastRow))
+ {
+ bVisRow = true;
+ nLastVisibleRow = nLastRow;
+ }
+ else
+ {
+ // Skip all hidden rows until next pagebreak.
+ nRow = ((nNextPageBreak == ScRowBreakIterator::NOT_FOUND) ? nLastRow :
+ std::min(nLastRow, nNextPageBreak - 1));
+ }
+ }
+
+ if (!bVisRow)
+ return;
+
+ OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for maPageEndY");
+ (*m_xPageEndY)[m_nTotalY] = nEndRow;
+ ++m_nTotalY;
+
+ if (!bSkipEmpty || !rDoc.IsPrintEmpty(nStartCol, nPageStartRow, nEndCol, nEndRow, nPrintTab))
+ {
+ auto& rPageRow = (*m_xPageRows)[m_nPagesY];
+ rPageRow.SetStartRow(nPageStartRow);
+ rPageRow.SetEndRow(nEndRow);
+ rPageRow.SetPagesX(m_nPagesX);
+ if (bSkipEmpty)
+ lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
+ ++m_nPagesY;
+ }
+}
+
+} // end namespace sc
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */