/* -*- 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 .
*/
// get default values to use in dialog from documents SwPrintData const SwPrintData &rPrintData = pDocShell->GetDoc()->getIDocumentDeviceAccess().getPrintData();
// Get current page number
sal_uInt16 nCurrentPage = 1; const SwWrtShell* pSh = pDocShell->GetWrtShell(); const SwRootFrame *pFrame = nullptr; if (pSh)
{
SwPaM* pShellCursor = pSh->GetCursor();
nCurrentPage = pShellCursor->GetPageNum();
pFrame = pSh->GetLayout();
} elseif (!bSwSrcView)
{ const SwPagePreview* pPreview = dynamic_cast< const SwPagePreview* >(pView);
OSL_ENSURE(pPreview, "Unexpected type of the view shell"); if (pPreview)
{
nCurrentPage = pPreview->GetSelectedPage();
pFrame = pPreview->GetViewShell()->GetLayout();
}
}
// If blanks are skipped, account for them in initial page range value if (pFrame && !rPrintData.IsPrintEmptyPages())
{
sal_uInt16 nMax = nCurrentPage; const SwPageFrame *pPage = dynamic_cast<const SwPageFrame*>(pFrame->Lower()); while (pPage && nMax > 0)
{
nMax--; if (pPage->getFrameArea().Height() == 0)
nCurrentPage--;
pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
}
} return std::make_unique<SwPrintUIOptions>( nCurrentPage, bWebDoc, bSwSrcView, bHasSelection, bHasPostIts, rPrintData );
}
class SwXTextDocument::Impl
{ public:
std::mutex m_Mutex; // just for OInterfaceContainerHelper4
::comphelper::OInterfaceContainerHelper4<css::util::XRefreshListener> m_RefreshListeners;
};
void SwXTextDocument::ThrowIfInvalid() const
{ if (!m_pDocShell) throw DisposedException(u"SwXTextDocument not valid"_ustr, const_cast<SwXTextDocument*>(this)->getXWeak());
}
SwDoc& SwXTextDocument::GetDocOrThrow() const
{
ThrowIfInvalid(); if (SwDoc* pDoc = m_pDocShell->GetDoc()) return *pDoc; throw css::lang::NotInitializedException(
u"Document not initialized by a call to attachResource() or load()"_ustr, const_cast<SwXTextDocument*>(this)->getXWeak());
}
SwXTextDocument::~SwXTextDocument()
{
InitNewDoc(); if(m_xNumFormatAgg.is())
{
m_xNumFormatAgg->setDelegator({});
m_xNumFormatAgg.clear();
}
m_pPrintUIOptions.reset(); if (m_pRenderData && m_pRenderData->IsViewOptionAdjust())
{ // rhbz#827695: this can happen if the last page is not printed // the SwViewShell has been deleted already by SwView::~SwView // FIXME: replace this awful implementation of XRenderable with // something less insane that has its own view
m_pRenderData->ViewOptionAdjustCrashPreventionKludge();
}
m_pRenderData.reset();
}
void SwXTextDocument::dispose()
{ // Delete UnoActionContexts before deleting the SwDoc, as the first has unowned pointers to the // second.
maActionArr.clear();
void SwXTextDocument::InitNewDoc()
{ if (auto xNumTunnel = comphelper::query_aggregation<XUnoTunnel>(m_xNumFormatAgg))
{ auto pNumFormat = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xNumTunnel);
OSL_ENSURE(pNumFormat, "No number formatter available"); if (pNumFormat)
pNumFormat->SetNumberFormatter(nullptr);
}
// first invalidate all collections, then delete references and Set to zero if(mxXTextTables.is())
{
mxXTextTables->Invalidate();
mxXTextTables.clear();
}
if(m_xDrawPage.is())
{ // #i91798#, #i91895# // dispose XDrawPage here. We are the owner and know that it is no longer in a valid condition.
m_xDrawPage->dispose();
m_xDrawPage->InvalidateSwDoc();
m_xDrawPage.clear();
}
if ( mxXNumberingRules.is() )
{
mxXNumberingRules->Invalidate();
mxXNumberingRules.clear();
}
const SwServiceType nType = SwXServiceProvider::GetProviderType(rServiceName); if (nType != SwServiceType::Invalid)
{ return SwXServiceProvider::MakeInstance(nType, GetDocOrThrow());
} if (rServiceName == "com.sun.star.drawing.DashTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Dash);
} if (rServiceName == "com.sun.star.drawing.GradientTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Gradient);
} if (rServiceName == "com.sun.star.drawing.HatchTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Hatch);
} if (rServiceName == "com.sun.star.drawing.BitmapTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Bitmap);
} if (rServiceName == "com.sun.star.drawing.TransparencyGradientTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::TransGradient);
} if (rServiceName == "com.sun.star.drawing.MarkerTable")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Marker);
} if (rServiceName == "com.sun.star.drawing.Defaults")
{ return GetPropertyHelper()->GetDrawTable(SwCreateDrawTable::Defaults);
} if (rServiceName == "com.sun.star.document.Settings")
{ return Reference<XInterface>(*new SwXDocumentSettings(this));
} if (rServiceName == "com.sun.star.document.ImportEmbeddedObjectResolver")
{ return cppu::getXWeak( new SvXMLEmbeddedObjectHelper(
*m_pDocShell, SvXMLEmbeddedObjectHelperMode::Read));
} if (rServiceName == "com.sun.star.text.DocumentSettings")
{ return Reference<XInterface>(*new SwXDocumentSettings(this));
} if (rServiceName == "com.sun.star.chart2.data.DataProvider")
{ return Reference<XInterface>(
cppu::getXWeak(
m_pDocShell->getIDocumentChartDataProviderAccess().
GetChartDataProvider()));
} if (!rServiceName.startsWith("com.sun.star.")
|| rServiceName.endsWith(".OLE2Shape"))
{ // We do not want to insert OLE2 Shapes (e.g., // "com.sun.star.drawing.OLE2Shape", ...) like this (by creating them // with the documents factory and adding the shapes to the draw page); // for inserting OLE objects the proper way is to use // "com.sun.star.text.TextEmbeddedObject": throw ServiceNotRegisteredException();
} // The XML import is allowed to create instances of // "com.sun.star.drawing.OLE2Shape"; thus, a temporary service name is // introduced to make this possible:
OUString aTmpServiceName(rServiceName); if (rServiceName == "com.sun.star.drawing.temporaryForXMLImportOLE2Shape")
{
aTmpServiceName = "com.sun.star.drawing.OLE2Shape";
}
Reference<XInterface> xTmp(
arguments == nullptr
? SvxFmMSFactory::createInstance(aTmpServiceName)
: SvxFmMSFactory::createInstanceWithArguments(
aTmpServiceName, *arguments)); if (rServiceName == "com.sun.star.drawing.GroupShape"
|| rServiceName == "com.sun.star.drawing.Shape3DSceneObject")
{ return *new SwXGroupShape(xTmp, m_pDocShell->GetDoc());
} if (rServiceName.startsWith("com.sun.star.drawing."))
{ return *new SwXShape(xTmp, m_pDocShell->GetDoc());
} return xTmp;
}
if(!pEntry) throw UnknownPropertyException(rPropertyName); if(pEntry->nFlags & PropertyAttribute::READONLY) throw PropertyVetoException(); switch(pEntry->nWID)
{ case WID_DOC_CHAR_COUNT : case WID_DOC_PARA_COUNT : case WID_DOC_WORD_COUNT : throw RuntimeException(
u"bad WID"_ustr,
getXWeak()); case WID_DOC_WORD_SEPARATOR :
{
OUString sDelim;
aValue >>= sDelim;
SwModule::get()->GetModuleConfig()->SetWordDelimiter(sDelim);
} break; case WID_DOC_CHANGES_RECORD: case WID_DOC_CHANGES_SHOW:
{
SwDoc& rDoc = GetDocOrThrow();
sw::DocumentRedlineManager& rRedlineManager = rDoc.GetDocumentRedlineManager(); bool bSet = *o3tl::doAccess<bool>(aValue);
RedlineFlags eMode = rRedlineManager.GetRedlineFlags(); if(WID_DOC_CHANGES_SHOW == pEntry->nWID)
{
eMode |= RedlineFlags(RedlineFlags::ShowInsert | RedlineFlags::ShowDelete); if( !bSet )
rRedlineManager.SetHideRedlines(true);
} elseif(WID_DOC_CHANGES_RECORD == pEntry->nWID)
{
eMode = bSet ? eMode|RedlineFlags::On : eMode&~RedlineFlags::On;
}
rRedlineManager.SetRedlineFlags(eMode);
} break; case WID_DOC_CHANGES_PASSWORD:
{
Sequence <sal_Int8> aNew; if(aValue >>= aNew)
{ auto& rRedlineAccess = GetDocOrThrow().getIDocumentRedlineAccess();
rRedlineAccess.SetRedlinePassword(aNew); if(aNew.hasElements())
{
RedlineFlags eMode = rRedlineAccess.GetRedlineFlags();
eMode |= RedlineFlags::On;
rRedlineAccess.SetRedlineFlags(eMode);
}
}
} break; case WID_DOC_AUTO_MARK_URL :
{
OUString sURL;
aValue >>= sURL;
GetDocOrThrow().SetTOIAutoMarkURL(sURL);
} break; case WID_DOC_HIDE_TIPS :
SwModule::get()->GetModuleConfig()->SetHideFieldTips(*o3tl::doAccess<bool>(aValue)); break; case WID_DOC_REDLINE_DISPLAY:
{ auto& rRedlineAccess = GetDocOrThrow().getIDocumentRedlineAccess();
RedlineFlags eRedMode = rRedlineAccess.GetRedlineFlags();
eRedMode = eRedMode & (~RedlineFlags::ShowMask);
sal_Int16 nSet = 0;
aValue >>= nSet; switch(nSet)
{ case RedlineDisplayType::NONE: break; case RedlineDisplayType::INSERTED: eRedMode |= RedlineFlags::ShowInsert; break; case RedlineDisplayType::REMOVED: eRedMode |= RedlineFlags::ShowDelete; break; case RedlineDisplayType::
INSERTED_AND_REMOVED: eRedMode |= RedlineFlags::ShowInsert|RedlineFlags::ShowDelete; break; default: throw IllegalArgumentException();
}
rRedlineAccess.SetRedlineFlags(eRedMode);
} break; case WID_DOC_TWO_DIGIT_YEAR:
{
sal_Int16 nYear = 0;
aValue >>= nYear;
SfxRequest aRequest ( SID_ATTR_YEAR2000, SfxCallMode::SLOT, GetDocOrThrow().GetAttrPool());
aRequest.AppendItem(SfxUInt16Item( SID_ATTR_YEAR2000, static_cast < sal_uInt16 > ( nYear ) ) );
m_pDocShell->Execute ( aRequest );
} break; case WID_DOC_AUTOMATIC_CONTROL_FOCUS:
{ auto& rDrawModelAccess = GetDocOrThrow().getIDocumentDrawModelAccess(); bool bAuto = *o3tl::doAccess<bool>(aValue); // if setting to true, and we don't have an // SdrModel, then we are changing the default and // must thus create an SdrModel, if we don't have an // SdrModel and we are leaving the default at false, // we don't need to make an SdrModel and can do nothing // #i52858# - method name changed
SwDrawModel* pDrawDoc
= bAuto ? &rDrawModelAccess.GetOrCreateDrawModel() : rDrawModelAccess.GetDrawModel();
if ( nullptr != pDrawDoc )
pDrawDoc->SetAutoControlFocus( bAuto );
} break; case WID_DOC_APPLY_FORM_DESIGN_MODE:
{ auto& rDrawModelAccess = GetDocOrThrow().getIDocumentDrawModelAccess(); bool bMode = *o3tl::doAccess<bool>(aValue); // if setting to false, and we don't have an // SdrModel, then we are changing the default and // must thus create an SdrModel, if we don't have an // SdrModel and we are leaving the default at true, // we don't need to make an SdrModel and can do // nothing // #i52858# - method name changed
SwDrawModel* pDrawDoc
= bMode ? rDrawModelAccess.GetDrawModel() : &rDrawModelAccess.GetOrCreateDrawModel();
if ( nullptr != pDrawDoc )
pDrawDoc->SetOpenInDesignMode( bMode );
} break; // #i42634# New property to set the bInReading // flag at the document, used during binary import case WID_DOC_LOCK_UPDATES :
{ bool bBool (false); if( aValue >>= bBool )
{
GetDocOrThrow().SetInReading( bBool );
}
} break; case WID_DOC_WRITERFILTER:
{
SwDoc& rDoc = GetDocOrThrow(); bool bBool = {}; if (aValue >>= bBool)
{ // HACK: writerfilter has to use API to set this :( bool bOld = rDoc.IsInWriterfilterImport();
rDoc.SetInWriterfilterImport(bBool); if (bOld && !bBool)
{
rDoc.getIDocumentFieldsAccess().SetFieldsDirty(false, nullptr, SwNodeOffset(0));
}
}
} break; case WID_DOC_BUILDID:
aValue >>= maBuildId; break;
case WID_DOC_DEFAULT_PAGE_MODE:
{ bool bDefaultPageMode( false );
aValue >>= bDefaultPageMode;
GetDocOrThrow().SetDefaultPageMode( bDefaultPageMode );
} break; case WID_DOC_INTEROP_GRAB_BAG:
setGrabBagItem(aValue); break;
Any SwXTextDocument::getPropertyValue(const OUString& rPropertyName)
{
SolarMutexGuard aGuard;
ThrowIfInvalid();
if (rPropertyName == "ODFExport_ListNodes")
{ // A hack to avoid writing random list ids to ODF when they are not referred later // see XMLTextParagraphExport::DocumentListNodes ctor
// Sequence of nodes, each of them represented by three-element sequence: // [ index, styleIntPtr, list_id ]
std::vector<css::uno::Sequence<css::uno::Any>> nodes;
void SwXTextDocument::NotifyRefreshListeners()
{ // why does SwBaseShell not just call refresh? maybe because it's rSh is // (sometimes) a different shell than GetWrtShell()?
lang::EventObject const ev(getXWeak());
std::unique_lock aGuard(m_pImpl->m_Mutex);
m_pImpl->m_RefreshListeners.notifyEach(aGuard,
& util::XRefreshListener::refreshed, ev);
}
/* * GetRenderDoc: * returns the document to be rendered, usually this will be the 'regular' * document but in case of PDF export of (multi-)selection it will * be a temporary document that gets created if not already done. * The rpView variable will be set (if not already done) to the used * SfxViewShell.
*/
SwDoc * SwXTextDocument::GetRenderDoc(
SfxViewShell *&rpView, const uno::Any& rSelection, bool bIsPDFExport )
{
SwDoc *pDoc = nullptr;
if (rSelection.hasValue()) // is anything selected ?
{ // this part should only be called when a temporary document needs to be created, // for example for PDF export or printing of (multi-)selection only.
if (!rpView)
{ bool bIsSwSrcView = false; // aside from maybe PDF export the view should always have been provided!
OSL_ENSURE( bIsPDFExport, "view is missing, guessing one..." );
rpView = GuessViewShell( bIsSwSrcView );
}
OSL_ENSURE( rpView, "SwViewShell missing" ); // the view shell should be SwView for documents PDF export. // for the page preview no selection should be possible // (the export dialog does not allow for this option) if (auto pSwView = dynamic_cast<SwView *>( rpView ))
{ if (!m_pRenderData)
{
OSL_FAIL("GetRenderDoc: no renderdata"); return nullptr;
}
SfxObjectShellLock xDocSh(m_pRenderData->GetTempDocShell()); if (!xDocSh.Is())
{
xDocSh = pSwView->CreateTmpSelectionDoc();
m_pRenderData->SetTempDocShell(xDocSh);
} if (xDocSh.Is())
{
pDoc = static_cast<SwDocShell*>(&xDocSh)->GetDoc();
rpView = pDoc->GetDocShell()->GetView();
}
} else
{
OSL_FAIL("unexpected SwViewShell" );
}
}
} return pDoc;
}
// save current UI options from the print dialog for the next call to that dialog
lcl_SavePrintUIOptionsToDocumentPrintData( *pDoc, *m_pPrintUIOptions, bIsPDFExport );
// TODO/mba: we really need a generic way to get the SwViewShell!
SwViewShell* pViewShell = nullptr;
SwView* pSwView = dynamic_cast<SwView*>( pView ); if ( pSwView )
{
pViewShell = pSwView->GetWrtShellPtr();
} else
{ if ( bIsPDFExport && bFormat )
{ //create a hidden view to be able to export as PDF also in print preview //pView and pSwView are not changed intentionally!
m_pHiddenViewFrame = SfxViewFrame::LoadHiddenDocument( *pRenderDocShell, SFX_INTERFACE_SFXDOCSH );
pViewShell = static_cast<SwView*>(m_pHiddenViewFrame->GetViewShell())->GetWrtShellPtr();
} else
pViewShell = static_cast<SwPagePreview*>(pView)->GetViewShell();
}
if (!pViewShell || !pViewShell->GetLayout()) return 0;
// reformatting the document for printing will show the changes in the view // which is likely to produce many unwanted and not nice to view actions. // We don't want that! Thus we disable updating of the view.
pViewShell->StartAction();
if (pSwView)
{ if (m_pRenderData && m_pRenderData->NeedNewViewOptionAdjust( *pViewShell ) )
m_pRenderData->ViewOptionAdjustStop(); if (m_pRenderData && !m_pRenderData->IsViewOptionAdjust())
{
m_pRenderData->ViewOptionAdjustStart(
*pViewShell, *pViewShell->GetViewOptions() );
}
}
if (pSwView)
{ // PDF export should not make use of the SwPrtOptions const SwPrintData *pPrtOptions = bIsPDFExport
? nullptr : m_pRenderData->GetSwPrtOptions(); bool setShowPlaceHoldersInPDF = false; if(bIsPDFExport)
setShowPlaceHoldersInPDF = lcl_GetBoolProperty( rxOptions, "ExportPlaceholders" );
m_pRenderData->ViewOptionAdjust( pPrtOptions, setShowPlaceHoldersInPDF );
}
// since printing now also use the API for PDF export this option // should be set for printing as well ...
pViewShell->SetPDFExportOption( true );
// there is some redundancy between those two function calls, but right now // there is no time to sort this out. //TODO: check what exactly needs to be done and make just one function for that
pViewShell->CalcLayout();
// #122919# Force field update before PDF export, but after layout init (tdf#121962) bool bStateChanged = false; // check configuration: shall update of printing information in DocInfo set the document to "modified"? if (pRenderDocShell->IsEnableSetModified() && !officecfg::Office::Common::Print::PrintingModifiesDocument::get())
{
pRenderDocShell->EnableSetModified( false );
bStateChanged = true;
}
pViewShell->SwViewShell::UpdateFields(true); if( bStateChanged )
pRenderDocShell->EnableSetModified();
// get set of valid document pages (according to the current settings) // and their start frames
SwDoc::CalculatePagesForPrinting( *pViewShell->GetLayout(), *m_pRenderData, *m_pPrintUIOptions, bIsPDFExport, nPageCount );
nRet = m_pRenderData->GetPagesToPrint().size();
}
}
OSL_ENSURE( nRet >= 0, "negative number of pages???" ); // tdf#144989 the layout is complete now - prevent DoIdleJobs() from // messing it up, particularly SwDocUpdateField::MakeFieldList_() unhiding // sections
pDoc->getIDocumentTimerAccess().BlockIdling();
// m_pRenderData should NOT be created here! // That should only be done in getRendererCount. If this function is called before // getRendererCount was called then the caller will probably just retrieve the extra UI options // and is not interested in getting valid information about the other data that would // otherwise be provided here! // if( ! m_pRenderData ) // m_pRenderData = new SwRenderData; if (!m_pPrintUIOptions)
m_pPrintUIOptions = lcl_GetPrintUIOptions( m_pDocShell, pView );
m_pPrintUIOptions->processProperties( rxOptions ); constbool bPrintProspect = m_pPrintUIOptions->getBoolValue( "PrintProspect" ); constbool bIsSkipEmptyPages = !m_pPrintUIOptions->IsPrintEmptyPages( bIsPDFExport ); constbool bPrintPaperFromSetup = m_pPrintUIOptions->getBoolValue( "PrintPaperFromSetup" );
// due to #110067# (document page count changes sometimes during // PDF export/printing) we can not check for the upper bound properly. // Thus instead of throwing the exception we silently return. if (0 > nRenderer) throw IllegalArgumentException();
sal_Int32 nMaxRenderer = 0; if (!bIsSwSrcView && m_pRenderData)
{
OSL_ENSURE( m_pRenderData, "m_pRenderData missing!!" );
nMaxRenderer = bPrintProspect?
m_pRenderData->GetPagePairsForProspectPrinting().size() - 1 :
m_pRenderData->GetPagesToPrint().size() - 1;
} // since SwSrcView::PrintSource is a poor implementation to get the number of pages to print // we obmit checking of the upper bound in this case. if (!bIsSwSrcView && m_pRenderData && nRenderer > nMaxRenderer) return uno::Sequence< beans::PropertyValue >();
uno::Sequence< beans::PropertyValue > aRenderer; if (m_pRenderData)
{ // #i114210# // determine the correct page number from the renderer index // #i114875 // consider brochure print const sal_Int32 nPage = bPrintProspect
? nRenderer + 1
: m_pRenderData->GetPagesToPrint()[ nRenderer ];
// get paper tray to use ...
sal_Int32 nPrinterPaperTray = -1; if (! bPrintPaperFromSetup)
{ // ... from individual page style (see the page tab in Format/Page dialog) const std::map< sal_Int32, sal_Int32 > &rPaperTrays = m_pRenderData->GetPrinterPaperTrays();
std::map< sal_Int32, sal_Int32 >::const_iterator aIt( rPaperTrays.find( nPage ) ); if (aIt != rPaperTrays.end())
nPrinterPaperTray = aIt->second;
}
// TODO/mba: we really need a generic way to get the SwViewShell!
SwViewShell* pVwSh = nullptr;
SwView* pSwView = dynamic_cast<SwView*>( pView ); if ( pSwView )
pVwSh = pSwView->GetWrtShellPtr(); else
pVwSh = static_cast<SwPagePreview*>(pView)->GetViewShell();
awt::Size aPageSize;
awt::Point aPagePos;
awt::Size aPreferredPageSize;
Size aTmpSize; #ifdef MACOSX bool bChangeOrientation = false;
css::view::PaperOrientation nNewOrientation = css::view::PaperOrientation::PaperOrientation_PORTRAIT; #endif if (bIsSwSrcView || bPrintProspect)
{ // for printing of HTML source code and prospect printing we should use // the printers paper size since // a) HTML source view has no page size // b) prospect printing has a different page size from the documents page // since two document pages will get rendered on one printer page
// since PageIncludesNonprintableArea will be set to true we can return the // printers paper size here. // Sometimes 'getRenderer' is only called to get "ExtraPrintUIOptions", in this // case we won't get an OutputDevice here, but then the caller also has no need // for the correct PageSize right now...
VclPtr< Printer > pPrinter = dynamic_cast< Printer * >(lcl_GetOutputDevice( *m_pPrintUIOptions ).get()); if (pPrinter)
{ // HTML source view and prospect adapt to the printer's paper size
aTmpSize = pPrinter->GetPaperSize();
aTmpSize = OutputDevice::LogicToLogic( aTmpSize,
pPrinter->GetMapMode(), MapMode( MapUnit::Map100thMM ));
aPageSize = awt::Size( aTmpSize.Width(), aTmpSize.Height() ); #ifdef MACOSX // Related: tdf#163126 when brochure printing on macOS, set the // printer's page size to match the preferred page size. Unlike // most other platforms, the native print dialog is always // displayed on macOS and it displays a preview of the print // output which the user can make layout changes to. The user // can also change the printer or even send the print output // to PDF instead of a printer from within the native print // dialog so set the printer's paper to the preferred size so // that the initial preview more closely matches the page size // and rotation that LibreOffice expects. if (bPrintProspect)
{ // we just state what output size we would need // which may cause vcl to set that page size on the printer // (if available and not overridden by the user) if( pVwSh )
aTmpSize = pVwSh->GetPageSize( nPage, bIsSkipEmptyPages );
// Related: tdf#163126 set both page size properties as // they do two different things. The preferred page size // tells the printer to set its paper size. But the page // size is the size that LibreOffice will actually draw. // Fortunately on macOS, there is a good chance that the // print output will closely match the preferred page size // since there is no problem printing to a page size not // supported by an underlying physical printer. In such // cases, the native print dialog will display at the // requested paper size as will saving to PDF or opening // in the Preview application.
aPreferredPageSize = aPageSize = awt::Size( convertTwipToMm100( 2 * aTmpSize.Width() ),
convertTwipToMm100( aTmpSize.Height() ));
// Related: tdf#163126 try to match any paper rotations in // the native printing code in vcl.
bChangeOrientation = true; if( aPageSize.Width < aPageSize.Height )
nNewOrientation = css::view::PaperOrientation::PaperOrientation_PORTRAIT; else
nNewOrientation = css::view::PaperOrientation::PaperOrientation_LANDSCAPE;
} #else // #i115048# it seems users didn't like getting double the formatted page size // revert to "old" behavior scaling to the current paper size of the printer if( bPrintProspect )
{ // just switch to an appropriate portrait/landscape format // FIXME: brochure printing with landscape pages puts the // pages next to each other, so landscape is currently always // the better choice if( aPageSize.Width < aPageSize.Height )
{
aPreferredPageSize.Width = aPageSize.Height;
aPreferredPageSize.Height = aPageSize.Width;
}
} #endif
}
} else
{ if (pVwSh)
{
aTmpSize = pVwSh->GetPageSize( nPage, bIsSkipEmptyPages );
aPageSize = awt::Size ( convertTwipToMm100( aTmpSize.Width() ),
convertTwipToMm100( aTmpSize.Height() ));
Point aPoint = pVwSh->GetPagePos(nPage);
aPagePos = awt::Point(convertTwipToMm100(aPoint.X()), convertTwipToMm100(aPoint.Y()));
}
}
SfxViewShell * SwXTextDocument::GuessViewShell( /* out */ bool &rbIsSwSrcView, const uno::Reference< css::frame::XController >& rController )
{ // #130810# SfxViewShell::Current() / SfxViewShell::GetObjectShell() // must not be used (see comment from MBA)
// look for the view shell with the same controller in use, // otherwise look for a suitable view, preferably a SwView, // if that one is not found use a SwPagePreview if found. while (pFrame)
{
pView = pFrame->GetViewShell();
pSwView = dynamic_cast< SwView * >(pView);
pSwSrcView = dynamic_cast< SwSrcView * >(pView); if (!pSwPagePreview)
pSwPagePreview = dynamic_cast< SwPagePreview * >(pView); if (rController.is())
{ if (pView && pView->GetController() == rController) break;
} elseif (pSwView || pSwSrcView) break;
pFrame = SfxViewFrame::GetNext( *pFrame, m_pDocShell, false );
}
OSL_ENSURE( pSwView || pSwPagePreview || pSwSrcView, "failed to get view shell" ); if (pView)
rbIsSwSrcView = pSwSrcView != nullptr; return pView;
}
// due to #110067# (document page count changes sometimes during // PDF export/printing) we can not check for the upper bound properly. // Thus instead of throwing the exception we silently return. if (0 > nRenderer) throw IllegalArgumentException();
// tdf#135244: prevent jumping to cursor at any temporary modification auto aLock = m_pDocShell->LockAllViews();
OSL_ENSURE( m_pRenderData, "data should have been created already in getRendererCount...");
OSL_ENSURE( m_pPrintUIOptions, "data should have been created already in getRendererCount..." ); if (!bIsSwSrcView && !m_pRenderData)
m_pRenderData.reset(new SwRenderData); if (!m_pPrintUIOptions)
m_pPrintUIOptions = lcl_GetPrintUIOptions( m_pDocShell, pView );
m_pPrintUIOptions->processProperties( rxOptions ); constbool bPrintProspect = m_pPrintUIOptions->getBoolValue( "PrintProspect" ); constbool bLastPage = m_pPrintUIOptions->getBoolValue( "IsLastPage" );
SwDoc *pDoc = GetRenderDoc( pView, rSelection, bIsPDFExport );
OSL_ENSURE( pDoc && pView, "doc or view shell missing!" ); if (pDoc && pView)
{
sal_Int32 nMaxRenderer = 0; if (!bIsSwSrcView)
{
OSL_ENSURE( m_pRenderData, "m_pRenderData missing!!" );
nMaxRenderer = bPrintProspect?
m_pRenderData->GetPagePairsForProspectPrinting().size() - 1 :
m_pRenderData->GetPagesToPrint().size() - 1;
} // since SwSrcView::PrintSource is a poor implementation to get the number of pages to print // we obmit checking of the upper bound in this case. if (bIsSwSrcView || nRenderer <= nMaxRenderer)
{ if (bIsSwSrcView)
{
SwSrcView& rSwSrcView = dynamic_cast<SwSrcView&>(*pView);
VclPtr< OutputDevice > pOutDev = lcl_GetOutputDevice( *m_pPrintUIOptions );
rSwSrcView.PrintSource(pOutDev, nRenderer + 1, false);
} else
{ // the view shell should be SwView for documents PDF export // or SwPagePreview for PDF export of the page preview
SwViewShell* pVwSh = nullptr; // TODO/mba: we really need a generic way to get the SwViewShell! const SwView* pSwView = dynamic_cast<const SwView*>(pView); if (pSwView)
pVwSh = pSwView->GetWrtShellPtr(); else
pVwSh = static_cast<SwPagePreview*>(pView)->GetViewShell();
// get output device to use
VclPtr< OutputDevice > pOut = lcl_GetOutputDevice( *m_pPrintUIOptions );
// since printing now also use the API for PDF export this option // should be set for printing as well ...
pVwSh->SetPDFExportOption( true );
// #i12836# enhanced pdf export
// First, we have to export hyperlinks, notes, and outline to pdf. // During this process, additional information required for tagging // the pdf file are collected, which are evaluated during painting.
if (bPrintProspect)
pVwSh->PrintProspect( pOut, rSwPrtOptions, nRenderer ); else// normal printing and PDF export
pVwSh->PrintOrPDFExport( pOut, rSwPrtOptions, nRenderer, bIsPDFExport );
// #i35176#
// After printing the last page, we take care for the links coming // from the EditEngine. The links are generated during the painting // process, but the destinations are still missing.
// last page to be rendered? (not necessarily the last page of the document) // -> do clean-up of data if (bLastPage)
{ // #i96167# haggai: delete ViewOptionsAdjust here because it makes use // of the shell, which might get destroyed in lcl_DisposeView! if (m_pRenderData->IsViewOptionAdjust())
m_pRenderData->ViewOptionAdjustStop();
if (m_pRenderData->HasPostItData())
m_pRenderData->DeletePostItData(); if (m_pHiddenViewFrame)
{
lcl_DisposeView( m_pHiddenViewFrame, m_pDocShell );
m_pHiddenViewFrame = nullptr;
// prevent crash described in #i108805 if (SwDocShell *pRenderDocShell = pDoc->GetDocShell())
pRenderDocShell->GetMedium()->GetItemSet().Put( SfxBoolItem( SID_HIDDEN, false ) );
}
}
}
}
}
} if( bLastPage )
{ // tdf#144989 enable DoIdleJobs() again after last page // Related: tdf#163126 on macOS, if the "print selection only" // checkbox is changed and then the restarted print dialog is // cancelled, idling will have already been unblocked so check // if it is blocked before unblocking it. if( pDoc->getIDocumentTimerAccess().IsIdlingBlocked() )
pDoc->getIDocumentTimerAccess().UnblockIdling();
m_pRenderData.reset();
m_pPrintUIOptions.reset();
}
}
// create a new document - hidden - copy the storage and return it // SfxObjectShellRef is used here, since the model should control object lifetime after creation // and thus SfxObjectShellLock is not allowed here // the model holds reference to the shell, so the shell will not destructed at the end of method
SfxObjectShellRef pShell = GetDocOrThrow().CreateCopy(false, false);
uno::Reference< frame::XModel > xNewModel = pShell->GetModel();
uno::Reference< embed::XStorage > xNewStorage = ::comphelper::OStorageHelper::GetTemporaryStorage( );
uno::Sequence< beans::PropertyValue > aTempMediaDescriptor;
storeToStorage( xNewStorage, aTempMediaDescriptor );
uno::Reference< document::XStorageBasedDocument > xStorageDoc( xNewModel, uno::UNO_QUERY );
xStorageDoc->loadFromStorage( xNewStorage, aTempMediaDescriptor ); return uno::Reference< util::XCloneable >( xNewModel, UNO_QUERY );
}
void SwXTextDocument::setClientVisibleArea(const tools::Rectangle& rRectangle)
{ if (SwView* pView = m_pDocShell->GetView())
{ // set the PgUp/PgDown offset
pView->ForcePageUpDownOffset(2 * rRectangle.GetHeight() / 3);
}
if (SwViewShell* pViewShell = m_pDocShell->GetWrtShell())
{
pViewShell->setLOKVisibleArea(rRectangle);
}
}
void SwXTextDocument::setClientZoom(int nTilePixelWidth_, int/*nTilePixelHeight_*/, int nTileTwipWidth_, int/*nTileTwipHeight_*/)
{ // Here we set the zoom value as it has been set by the user in the client. // This value is used in postMouseEvent and setGraphicSelection methods // for in place chart editing. We assume that x and y scale is roughly // the same.
SfxInPlaceClient* pIPClient = m_pDocShell->GetView()->GetIPClient(); if (!pIPClient) return;
// Changing the zoom value doesn't always trigger the updating of // the client ole object area, so we call it directly.
pIPClient->VisAreaChanged();
}
}
void SwXTextDocument::getTrackedChanges(tools::JsonWriter& rJson)
{ auto redlinesNode = rJson.startArray("redlines");
// Disable since usability is very low beyond some small number of changes. staticbool bDisableRedlineComments = getenv("DISABLE_REDLINE") != nullptr; if (bDisableRedlineComments) return;
const SwRedlineTable& rRedlineTable
= GetDocOrThrow().getIDocumentRedlineAccess().GetRedlineTable(); for (SwRedlineTable::size_type i = 0; i < rRedlineTable.size(); ++i)
{ auto redlineNode = rJson.startStruct();
rJson.put("index", rRedlineTable[i]->GetId());
rJson.put("author", rRedlineTable[i]->GetAuthorString(1));
rJson.put("type", SwRedlineTypeToOUString(
rRedlineTable[i]->GetRedlineData().GetType()));
rJson.put("comment",
rRedlineTable[i]->GetRedlineData().GetComment());
rJson.put("description", rRedlineTable[i]->GetDescr());
OUString sDateTime = utl::toISO8601(
rRedlineTable[i]->GetRedlineData().GetTimeStamp().GetUNODateTime());
rJson.put("dateTime", sDateTime);
if (!sidebarItem->maLayoutInfo.mPositionFromCommentAnchor)
{ // Comments on frames: anchor position is the corner position, not the whole frame.
aSVRect.SetSize(Size(0, 0));
}
// Disable field shadings: the result would depend on the cursor position.
aViewOption.SetAppearanceFlag(ViewOptFlags::FieldShadings, false); // The fancy header/footer controls don't work in tiled mode anyway, so // explicitly disable them to enable skipping invalidating the view for // the case of clicking in the header area of a document with no headers
aViewOption.SetUseHeaderFooterMenu(false);
for (const beans::PropertyValue& rValue : rArguments)
{ if (rValue.Name == ".uno:HideWhitespace" && rValue.Value.has<bool>())
aViewOption.SetHideWhitespaceMode(rValue.Value.get<bool>()); elseif (rValue.Name == ".uno:ShowBorderShadow" && rValue.Value.has<bool>())
aViewOption.SetAppearanceFlag(ViewOptFlags::Shadow , rValue.Value.get<bool>()); elseif (rValue.Name == ".uno:Author" && rValue.Value.has<OUString>())
{
sAuthor = rValue.Value.get<OUString>(); // Store the author name in the view.
pView->SetRedlineAuthor(sAuthor); // Let the actual author name pick up the value from the current // view, which would normally happen only during the next view // switch.
m_pDocShell->SetView(pView);
} elseif (rValue.Name == ".uno:SpellOnline" && rValue.Value.has<bool>())
aViewOption.SetOnlineSpell(rValue.Value.get<bool>()); elseif (rValue.Name == ".uno:ChangeTheme" && rValue.Value.has<OUString>())
sThemeName = rValue.Value.get<OUString>(); elseif (rValue.Name == ".uno:InvertBackground" && rValue.Value.has<OUString>())
sBackgroundThemeName = rValue.Value.get<OUString>();
}
if (!sAuthor.isEmpty() && sAuthor != sOrigAuthor)
{
SwView* pFirstView = static_cast<SwView*>(SfxViewShell::GetFirst()); if (pFirstView && SfxViewShell::GetNext(*pFirstView) == nullptr)
{ if (SwEditShell* pShell = &pFirstView->GetWrtShell())
{
pShell->SwViewShell::UpdateFields(true, /*bSetModified=*/false);
}
}
}
// Set the initial zoom value to 1; usually it is set in setClientZoom and // SwViewShell::PaintTile; zoom value is used for chart in place // editing, see postMouseEvent and setGraphicSelection methods.
aViewOption.SetZoom(1 * 100);
// position the pages again after setting view options. Eg: if postit // rendering is false, then there would be no sidebar, so width of the // document needs to be adjusted
pViewShell->GetLayout()->CheckViewLayout( pViewShell->GetViewOptions(), nullptr );
// Disable map mode, so that it's possible to send mouse event coordinates // directly in twips.
SwEditWin& rEditWin = m_pDocShell->GetView()->GetEditWin();
rEditWin.EnableMapMode(false);
// when the "This document may contain formatting or content that cannot // be saved..." dialog appears, it is auto-cancelled with tiled rendering, // causing 'Save' being disabled; so let's always save to the original // format auto xChanges = comphelper::ConfigurationChanges::create();
officecfg::Office::Common::Save::Document::WarnAlienFormat::set(false, xChanges);
xChanges->commit();
// disable word auto-completion suggestions, the tooltips are not visible, // and the editeng-like auto-completion is annoying
SvxAutoCorrCfg::Get().GetAutoCorrect()->GetSwFlags().bAutoCompleteWords = false;
// don't change the whitespace at the beginning of paragraphs, this is // annoying when taking minutes without further formatting
SwEditShell::GetAutoFormatFlags()->bAFormatByInpDelSpacesAtSttEnd = false;
// if we know what theme the user wants, then we can dispatch that now early if (!sThemeName.isEmpty())
{
css::uno::Sequence<css::beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
{
{ "NewTheme", uno::Any(sThemeName) }
}));
comphelper::dispatchCommand(u".uno:ChangeTheme"_ustr, aPropertyValues);
} if (!sBackgroundThemeName.isEmpty())
{
css::uno::Sequence<css::beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
{
{ "NewTheme", uno::Any(sBackgroundThemeName) }
}));
comphelper::dispatchCommand(".uno:InvertBackground", aPropertyValues);
}
}
void SwXTextDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
{
SolarMutexGuard aGuard;
SfxLokHelper::postKeyEventAsync(getDocWindow(), nType, nCharCode, nKeyCode);
}
void SwXTextDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
{
SolarMutexGuard aGuard;
SwViewShell* pWrtViewShell = m_pDocShell->GetWrtShell(); if (!pWrtViewShell)
{ return;
}
//TODO/mba: it's a strange concept that a view is needed to retrieve core data
SwWrtShell *pWrtSh = m_pDocShell->GetWrtShell();
SdrView *pSdrView = pWrtSh->GetDrawView();
// disable anything in the view that should not be printed (or exported to PDF) by default // (see also dialog "Tools/Options - StarOffice Writer - Formatting Aids" // in section "Display of ...")
aRenderViewOptions.SetParagraph( false ); // paragraph end
aRenderViewOptions.SetSoftHyph( false ); // aka custom hyphens
aRenderViewOptions.SetBlank( false ); // spaces
aRenderViewOptions.SetHardBlank( false ); // non-breaking spaces
aRenderViewOptions.SetTab( false ); // tabs
aRenderViewOptions.SetShowBookmarks( false ); // bookmarks
aRenderViewOptions.SetLineBreak( false ); // breaks (type 1)
aRenderViewOptions.SetPageBreak( false ); // breaks (type 2)
aRenderViewOptions.SetColumnBreak( false ); // breaks (type 3) bool bVal = pPrtOptions && pPrtOptions->m_bPrintHiddenText; if (bContainsHiddenChars)
aRenderViewOptions.SetShowHiddenChar( bVal ); // hidden text if (bContainsHiddenFields)
aRenderViewOptions.SetShowHiddenField( bVal ); if (bContainsHiddenParagraphs)
aRenderViewOptions.SetShowHiddenPara( bVal );
if (bContainsPlaceHolders)
{ // should always be printed in PDF export!
bVal = !pPrtOptions ? setShowPlaceHoldersInPDF : pPrtOptions->m_bPrintTextPlaceholder;
aRenderViewOptions.SetShowPlaceHolderFields( bVal );
}
if (bContainsFields)
aRenderViewOptions.SetFieldName( false );
// we need to set this flag in order to get to see the visible effect of // some of the above settings (needed for correct rendering)
aRenderViewOptions.SetViewMetaChars( true );
if (m_aOldViewOptions != aRenderViewOptions) // check if reformatting is necessary
{
aRenderViewOptions.SetPrinting( pPrtOptions != nullptr );
m_pShell->ApplyViewOptions( aRenderViewOptions );
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.