/* -*- 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 <sal/config.h>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/uno/Any.h>
#include <comphelper/fileformat.h>
#include <comphelper/accessibletexthelper.hxx>
#include <comphelper/string.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/ustring.hxx>
#include <sal/log.hxx>
#include <unotools/eventcfg.hxx>
#include <sfx2/event.hxx>
#include <sfx2/app.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/printer.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <comphelper/classids.hxx>
#include <sot/formats.hxx>
#include <sot/storage.hxx>
#include <svl/eitem.hxx>
#include <svl/intitem.hxx>
#include <svl/itempool.hxx>
#include <svl/slstitm.hxx>
#include <svl/hint.hxx>
#include <svl/stritem.hxx>
#include <svl/undo.hxx>
#include <svl/whiter.hxx>
#include <vcl/mapmod.hxx>
#include <vcl/virdev.hxx>
#include <tools/mapunit.hxx>
#include <vcl/settings.hxx>
#include <document.hxx>
#include <action.hxx>
#include <dialog.hxx>
#include <format.hxx>
#include <parse.hxx>
#include <starmath.hrc>
#include <strings.hrc>
#include <smmod.hxx>
#include <symbol.hxx>
#include <unomodel.hxx>
#include <utility.hxx>
#include <view.hxx>
#include "mathtype.hxx"
#include "ooxmlexport.hxx"
#include "ooxmlimport.hxx"
#include "rtfexport.hxx"
#include <mathmlimport.hxx>
#include <mathmlexport.hxx>
#include <svx/svxids.hrc>
#include <cursor.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <visitors.hxx>
#include "accessibility.hxx"
#include <cfgitem.hxx>
#include <utility>
#include <oox/mathml/imexport.hxx>
#include <ElementsDockingWindow.hxx>
#include <smediteng.hxx>
#include <editeng/editund2.hxx>
#define ShellClass_SmDocShell
#include <smslots.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::uno;
SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
void SmDocShell::InitInterface_Impl()
{
GetStaticInterface()->RegisterPopupMenu(u"view"_ustr);
}
void SmDocShell::SetSmSyntaxVersion(sal_Int16 nSmSyntaxVersion)
{
mnSmSyntaxVersion = nSmSyntaxVersion;
maParser.reset(starmathdatabase::GetVersionSmParser(mnSmSyntaxVersion));
}
SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), u"smath"_ustr )
void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
{
if (rHint.GetId() == SfxHintId::MathFormatChanged)
{
SetFormulaArranged(false);
mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
Repaint();
}
}
void SmDocShell::LoadSymbols()
{
SmModule *pp = SM_MOD();
pp->GetSymbolManager().Load();
}
OUString SmDocShell::GetComment() const
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
GetModel(), uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties> xDocProps(
xDPS->getDocumentProperties());
return xDocProps->getDescription();
}
void SmDocShell::SetText(const OUString& rBuffer)
{
if (rBuffer == maText)
return;
bool bIsEnabled = IsEnableSetModified();
if( bIsEnabled )
EnableSetModified( false );
maText = rBuffer;
SetFormulaArranged( false );
Parse();
SmViewShell *pViewSh = SmGetActiveView();
if (pViewSh)
{
pViewSh->GetViewFrame().GetBindings().Invalidate(SID_TEXT);
if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
{
// have SwOleClient::FormatChanged() to align the modified formula properly
// even if the visible area does not change (e.g. when formula text changes from
// "{a over b + c} over d" to "d over {a over b + c}"
SfxGetpApp()->NotifyEvent(SfxEventHint( SfxEventHintId::VisAreaChanged, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
Repaint();
}
else
pViewSh->GetGraphicWidget().Invalidate();
}
if ( bIsEnabled )
EnableSetModified( bIsEnabled );
SetModified();
// launch accessible event if necessary
SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWidget().GetAccessible_Impl() : nullptr;
if (pAcc)
{
Any aOldValue, aNewValue;
if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
{
pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
aOldValue, aNewValue );
}
}
if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
OnDocumentPrinterChanged(nullptr);
}
void SmDocShell::SetFormat(SmFormat const & rFormat)
{
maFormat = rFormat;
SetFormulaArranged( false );
SetModified();
mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
// don't use SmGetActiveView since the view shell might not be active (0 pointer)
// if for example the Basic Macro dialog currently has the focus. Thus:
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
while (pFrm)
{
pFrm->GetBindings().Invalidate(SID_GRAPHIC_SM);
pFrm = SfxViewFrame::GetNext( *pFrm, this );
}
}
OUString const & SmDocShell::GetAccessibleText()
{
ArrangeFormula();
if (maAccText.isEmpty())
{
OSL_ENSURE( mpTree, "Tree missing" );
if (mpTree)
{
OUStringBuffer aBuf;
mpTree->GetAccessibleText(aBuf);
maAccText = aBuf.makeStringAndClear();
}
}
return maAccText;
}
void SmDocShell::Parse()
{
mpTree.reset();
ReplaceBadChars();
mpTree = maParser->Parse(maText);
mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
SetFormulaArranged( false );
InvalidateCursor();
maUsedSymbols = maParser->GetUsedSymbols();
}
void SmDocShell::ArrangeFormula()
{
if (mbFormulaArranged)
return;
// Only for the duration of the existence of this object the correct settings
// at the printer are guaranteed!
SmPrinterAccess aPrtAcc(*this);
OutputDevice* pOutDev = aPrtAcc.GetRefDev();
SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
// if necessary get another OutputDevice for which we format
if (!pOutDev)
{
if (SmViewShell *pView = SmGetActiveView())
pOutDev = &pView->GetGraphicWidget().GetDrawingArea()->get_ref_device();
else
{
pOutDev = &SM_MOD()->GetDefaultVirtualDev();
pOutDev->SetMapMode( MapMode(SmMapUnit()) );
}
}
OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == SmMapUnit(),
"Sm : wrong MapMode");
const SmFormat &rFormat = GetFormat();
mpTree->Prepare(rFormat, *this, 0);
pOutDev->Push(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE);
// We want the device to always be LTR, we handle RTL formulas ourselves.
bool bOldRTL = pOutDev->IsRTLEnabled();
pOutDev->EnableRTL(false);
// For RTL formulas, we want the brackets to be mirrored.
bool bRTL = GetFormat().IsRightToLeft();
pOutDev->SetLayoutMode(bRTL ? vcl::text::ComplexTextLayoutFlags::BiDiRtl
: vcl::text::ComplexTextLayoutFlags::Default);
// Numbers should not be converted, for now.
pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
mpTree->Arrange(*pOutDev, rFormat);
pOutDev->EnableRTL(bOldRTL);
pOutDev->Pop();
SetFormulaArranged(true);
// invalidate accessible text
maAccText.clear();
}
void SmDocShell::UpdateEditEngineDefaultFonts()
{
SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
}
EditEngine& SmDocShell::GetEditEngine()
{
if (!mpEditEngine)
{
//!
//! see also SmEditWindow::DataChanged !
//!
mpEditEngineItemPool = EditEngine::CreatePool();
SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
mpEditEngine.reset( new SmEditEngine( mpEditEngineItemPool.get() ) );
mpEditEngine->EraseVirtualDevice();
// set initial text if the document already has some...
// (may be the case when reloading a doc)
OUString aTxt( GetText() );
if (!aTxt.isEmpty())
mpEditEngine->SetText( aTxt );
mpEditEngine->ClearModifyFlag();
}
return *mpEditEngine;
}
void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
{
if (!mpTree)
Parse();
OSL_ENSURE(mpTree, "Sm : NULL pointer");
ArrangeFormula();
bool bRTL = GetFormat().IsRightToLeft();
// Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
// device and aren't aligned to that either. So now there can be a difference between the
// VisArea (i.e. the size within the client) and the current size.
// Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE ) );
Point aPosition(rPosition);
if (bRTL && rDev.GetOutDevType() != OUTDEV_WINDOW)
aPosition.AdjustX(GetSize().Width()
- maFormat.GetDistance(DIS_LEFTSPACE)
- maFormat.GetDistance(DIS_RIGHTSPACE));
//! in case of high contrast-mode (accessibility option!)
//! the draw mode needs to be set to default, because when embedding
//! Math for example in Calc in "a over b" the fraction bar may not
//! be visible else. More generally: the FillColor may have been changed.
DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
bool bRestoreDrawMode = false;
if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
rDev.GetOwnerWindow()->GetSettings().GetStyleSettings().GetHighContrastMode())
{
nOldDrawMode = rDev.GetDrawMode();
rDev.SetDrawMode( DrawModeFlags::Default );
bRestoreDrawMode = true;
}
rDev.Push(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE);
// We want the device to always be LTR, we handle RTL formulas ourselves.
bool bOldRTL = rDev.IsRTLEnabled();
if (rDev.GetOutDevType() == OUTDEV_WINDOW)
rDev.EnableRTL(bRTL);
else
rDev.EnableRTL(false);
auto nLayoutFlags = vcl::text::ComplexTextLayoutFlags::Default;
if (bRTL)
{
// For RTL formulas, we want the brackets to be mirrored.
nLayoutFlags |= vcl::text::ComplexTextLayoutFlags::BiDiRtl;
if (rDev.GetOutDevType() == OUTDEV_WINDOW)
nLayoutFlags |= vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
}
rDev.SetLayoutMode(nLayoutFlags);
// Numbers should not be converted, for now.
rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
//Set selection if any
if(mpCursor && bDrawSelection){
mpCursor->AnnotateSelection();
SmSelectionDrawingVisitor(rDev, mpTree.get(), aPosition);
}
//Drawing using visitor
SmDrawingVisitor(rDev, aPosition, mpTree.get(), GetFormat());
rDev.EnableRTL(bOldRTL);
rDev.Pop();
if (bRestoreDrawMode)
rDev.SetDrawMode( nOldDrawMode );
}
Size SmDocShell::GetSize()
{
Size aRet;
if (!mpTree)
Parse();
if (mpTree)
{
ArrangeFormula();
aRet = mpTree->GetSize();
if ( !aRet.Width() || aRet.Width() == 1 )
aRet.setWidth( 2000 );
else
aRet.AdjustWidth(maFormat.GetDistance( DIS_LEFTSPACE ) +
maFormat.GetDistance( DIS_RIGHTSPACE ) );
if ( !aRet.Height() )
aRet.setHeight( 1000 );
else
aRet.AdjustHeight(maFormat.GetDistance( DIS_TOPSPACE ) +
maFormat.GetDistance( DIS_BOTTOMSPACE ) );
}
return aRet;
}
void SmDocShell::InvalidateCursor(){
mpCursor.reset();
}
SmCursor& SmDocShell::GetCursor(){
if(!mpCursor)
mpCursor.reset(new SmCursor(mpTree.get(), this));
return *mpCursor;
}
bool SmDocShell::HasCursor() const { return mpCursor != nullptr; }
SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
{
pPrinter = rDocShell.GetPrt();
if ( pPrinter )
{
pPrinter->Push( vcl::PushFlags::MAPMODE );
if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
{
// if it is an embedded object (without its own printer)
// we change the MapMode temporarily.
//!If it is a document with its own printer the MapMode should
//!be set correct (once) elsewhere(!), in order to avoid numerous
//!superfluous pushing and popping of the MapMode when using
//!this class.
const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
if ( SmMapUnit() != eOld )
{
MapMode aMap( pPrinter->GetMapMode() );
aMap.SetMapUnit( SmMapUnit() );
Point aTmp( aMap.GetOrigin() );
aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
aMap.SetOrigin( aTmp );
pPrinter->SetMapMode( aMap );
}
}
}
pRefDev = rDocShell.GetRefDev();
if ( !pRefDev || pPrinter.get() == pRefDev.get() )
return;
pRefDev->Push( vcl::PushFlags::MAPMODE );
if ( SfxObjectCreateMode::EMBEDDED != rDocShell.GetCreateMode() )
return;
// if it is an embedded object (without its own printer)
// we change the MapMode temporarily.
//!If it is a document with its own printer the MapMode should
//!be set correct (once) elsewhere(!), in order to avoid numerous
//!superfluous pushing and popping of the MapMode when using
//!this class.
const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
if ( SmMapUnit() != eOld )
{
MapMode aMap( pRefDev->GetMapMode() );
aMap.SetMapUnit( SmMapUnit() );
Point aTmp( aMap.GetOrigin() );
aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
aMap.SetOrigin( aTmp );
pRefDev->SetMapMode( aMap );
}
}
SmPrinterAccess::~SmPrinterAccess()
{
if ( pPrinter )
pPrinter->Pop();
if ( pRefDev && pRefDev != pPrinter )
pRefDev->Pop();
}
Printer* SmDocShell::GetPrt()
{
if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
{
// Normally the server provides the printer. But if it doesn't provide one (e.g. because
// there is no connection) it still can be the case that we know the printer because it
// has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
Printer* pPrt = GetDocumentPrinter();
if (!pPrt && mpTmpPrinter)
pPrt = mpTmpPrinter;
return pPrt;
}
else if (!mpPrinter)
{
auto pOptions = std::make_unique<SfxItemSetFixed<
SID_PRINTTITLE, SID_PRINTZOOM,
SID_NO_RIGHT_SPACES, SID_SAVE_ONLY_USED_SYMBOLS,
SID_AUTO_CLOSE_BRACKETS, SID_SMEDITWINDOWZOOM,
SID_INLINE_EDIT_ENABLE, SID_INLINE_EDIT_ENABLE>>(GetPool());
SmModule *pp = SM_MOD();
pp->GetConfig()->ConfigToItemSet(*pOptions);
mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pOptions));
mpPrinter->SetMapMode(MapMode(SmMapUnit()));
}
return mpPrinter;
}
OutputDevice* SmDocShell::GetRefDev()
{
if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
{
OutputDevice* pOutDev = GetDocumentRefDev();
if (pOutDev)
return pOutDev;
}
return GetPrt();
}
void SmDocShell::SetPrinter( SfxPrinter *pNew )
{
mpPrinter.disposeAndClear();
mpPrinter = pNew; //Transfer ownership
mpPrinter->SetMapMode( MapMode(SmMapUnit()) );
SetFormulaArranged(false);
Repaint();
}
void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
{
mpTmpPrinter = pPrt;
SetFormulaArranged(false);
Size aOldSize = GetVisArea().GetSize();
Repaint();
if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
SetModified();
mpTmpPrinter = nullptr;
}
void SmDocShell::Repaint()
{
bool bIsEnabled = IsEnableSetModified();
if (bIsEnabled)
EnableSetModified( false );
SetFormulaArranged(false);
Size aVisSize = GetSize();
SetVisAreaSize(aVisSize);
if (SmViewShell* pViewSh = SmGetActiveView())
pViewSh->GetGraphicWidget().Invalidate();
if (bIsEnabled)
EnableSetModified(bIsEnabled);
}
SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
: SfxObjectShell(i_nSfxCreationFlags)
, m_pMlElementTree(nullptr)
, mpPrinter(nullptr)
, mpTmpPrinter(nullptr)
, mnModifyCount(0)
, mbFormulaArranged(false)
, mnSmSyntaxVersion(SM_MOD()->GetConfig()->GetDefaultSmSyntaxVersion())
{
SvtLinguConfig().GetOptions(maLinguOptions);
SetPool(&SfxGetpApp()->GetPool());
SmModule *pp = SM_MOD();
maFormat = pp->GetConfig()->GetStandardFormat();
StartListening(maFormat);
StartListening(*pp->GetConfig());
SetBaseModel(new SmModel(this));
SetSmSyntaxVersion(mnSmSyntaxVersion);
SetMapUnit(SmMapUnit());
}
SmDocShell::~SmDocShell()
{
SmModule *pp = SM_MOD();
EndListening(maFormat);
EndListening(*pp->GetConfig());
mpCursor.reset();
mpEditEngine.reset();
mpEditEngineItemPool.clear();
mpPrinter.disposeAndClear();
mathml::SmMlIteratorFree(m_pMlElementTree);
}
bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
{
bool bSuccess = false;
const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
if ( rFltName == MATHML_XML )
{
if (mpTree)
{
mpTree.reset();
InvalidateCursor();
}
rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
SmXMLImportWrapper aEquation(xModel);
aEquation.useHTMLMLEntities(true);
bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
}
else
{
SvStream *pStream = rMedium.GetInStream();
if ( pStream )
{
if ( SotStorage::IsStorageFile( pStream ) )
{
rtl::Reference<SotStorage> aStorage = new SotStorage(pStream, false);
if ( aStorage->IsStream(u"Equation Native"_ustr) )
{
// is this a MathType Storage?
OUStringBuffer aBuffer;
MathType aEquation(aBuffer);
bSuccess = aEquation.Parse( aStorage.get() );
if ( bSuccess )
{
maText = aBuffer.makeStringAndClear();
Parse();
}
}
}
}
}
if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
{
SetFormulaArranged( false );
Repaint();
}
FinishedLoading();
return bSuccess;
}
bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
{
bool bRet = false;
if ( SfxObjectShell::InitNew( xStorage ) )
{
bRet = true;
SetVisArea(tools::Rectangle(Point(0, 0), Size(2000, 1000)));
}
return bRet;
}
bool SmDocShell::Load( SfxMedium& rMedium )
{
bool bRet = false;
if( SfxObjectShell::Load( rMedium ))
{
uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
if (xStorage->hasByName(u"content.xml"_ustr) && xStorage->isStreamElement(u"content.xml"_ustr))
{
// is this a fabulous math package ?
rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
SmXMLImportWrapper aEquation(xModel);
auto nError = aEquation.Import(rMedium);
bRet = ERRCODE_NONE == nError;
SetError(nError);
}
}
if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
{
SetFormulaArranged( false );
Repaint();
}
FinishedLoading();
return bRet;
}
bool SmDocShell::Save()
{
//! apply latest changes if necessary
UpdateText();
if ( SfxObjectShell::Save() )
{
if (!mpTree)
Parse();
if( mpTree )
ArrangeFormula();
SmXMLExportWrapper aEquation(GetModel());
aEquation.SetFlat(false);
return aEquation.Export(*GetMedium());
}
return false;
}
/*
* replace bad characters that can not be saved. (#i74144)
* */
void SmDocShell::ReplaceBadChars()
{
bool bReplace = false;
if (!mpEditEngine)
return;
OUStringBuffer aBuf( mpEditEngine->GetText() );
for (sal_Int32 i = 0; i < aBuf.getLength(); ++i)
{
if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
{
aBuf[i] = ' ';
bReplace = true;
}
}
if (bReplace)
maText = aBuf.makeStringAndClear();
}
void SmDocShell::UpdateText()
{
if (mpEditEngine && mpEditEngine->IsModified())
{
OUString aEngTxt( mpEditEngine->GetText() );
if (GetText() != aEngTxt)
SetText( aEngTxt );
}
}
bool SmDocShell::SaveAs( SfxMedium& rMedium )
{
bool bRet = false;
//! apply latest changes if necessary
UpdateText();
if ( SfxObjectShell::SaveAs( rMedium ) )
{
if (!mpTree)
Parse();
if( mpTree )
ArrangeFormula();
SmXMLExportWrapper aEquation(GetModel());
aEquation.SetFlat(false);
bRet = aEquation.Export(rMedium);
}
return bRet;
}
bool SmDocShell::ConvertTo( SfxMedium &rMedium )
{
bool bRet = false;
std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
if( pFlt )
{
if( !mpTree )
Parse();
if( mpTree )
ArrangeFormula();
const OUString& rFltName = pFlt->GetFilterName();
if(rFltName == STAROFFICE_XML)
{
SmXMLExportWrapper aEquation(GetModel());
aEquation.SetFlat(false);
bRet = aEquation.Export(rMedium);
}
else if(rFltName == MATHML_XML)
{
SmXMLExportWrapper aEquation(GetModel());
aEquation.SetFlat(true);
aEquation.SetUseHTMLMLEntities(true);
bRet = aEquation.Export(rMedium);
}
else if (pFlt->GetFilterName() == "MathType 3.x")
bRet = WriteAsMathType3( rMedium );
}
return bRet;
}
void SmDocShell::writeFormulaOoxml(
::sax_fastparser::FSHelperPtr const& pSerializer,
oox::core::OoxmlVersion const version,
oox::drawingml::DocumentType const documentType,
const sal_Int8 nAlign)
{
if( !mpTree )
Parse();
if( mpTree )
ArrangeFormula();
SmOoxmlExport aEquation(mpTree.get(), version, documentType);
if(documentType == oox::drawingml::DOCUMENT_DOCX)
aEquation.ConvertFromStarMath( pSerializer, nAlign);
else
aEquation.ConvertFromStarMath(pSerializer, oox::FormulaImExportBase::eFormulaAlign::INLINE);
}
void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
{
if (!mpTree)
Parse();
if (mpTree)
ArrangeFormula();
SmRtfExport aEquation(mpTree.get());
aEquation.ConvertFromStarMath(rBuffer, nEncoding);
}
void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
{
SmOoxmlImport aEquation( stream );
SetText( aEquation.ConvertToStarMath());
}
void SmDocShell::Execute(SfxRequest& rReq)
{
switch (rReq.GetSlot())
{
case SID_TEXTMODE:
{
SmFormat aOldFormat = GetFormat();
SmFormat aNewFormat( aOldFormat );
aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
SfxUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
break;
case SID_AUTO_REDRAW :
{
SmModule *pp = SM_MOD();
bool bRedraw = pp->GetConfig()->IsAutoRedraw();
pp->GetConfig()->SetAutoRedraw(!bRedraw);
}
break;
case SID_LOADSYMBOLS:
LoadSymbols();
break;
case SID_SAVESYMBOLS:
SaveSymbols();
break;
case SID_FONT:
{
// get device used to retrieve the FontList
OutputDevice *pDev = GetPrinter();
if (!pDev || pDev->GetFontFaceCollectionCount() == 0)
pDev = &SM_MOD()->GetDefaultVirtualDev();
OSL_ENSURE (pDev, "device for font list missing" );
SmFontTypeDialog aFontTypeDialog(rReq.GetFrameWeld(), pDev);
SmFormat aOldFormat = GetFormat();
aFontTypeDialog.ReadFrom( aOldFormat );
if (aFontTypeDialog.run() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
aFontTypeDialog.WriteTo(aNewFormat);
SfxUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
}
break;
case SID_FONTSIZE:
{
SmFontSizeDialog aFontSizeDialog(rReq.GetFrameWeld());
SmFormat aOldFormat = GetFormat();
aFontSizeDialog.ReadFrom( aOldFormat );
if (aFontSizeDialog.run() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
aFontSizeDialog.WriteTo(aNewFormat);
SfxUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
}
break;
case SID_DISTANCE:
{
SmDistanceDialog aDistanceDialog(rReq.GetFrameWeld());
SmFormat aOldFormat = GetFormat();
aDistanceDialog.ReadFrom( aOldFormat );
if (aDistanceDialog.run() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
aDistanceDialog.WriteTo(aNewFormat);
SfxUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
}
break;
case SID_ALIGN:
{
SmAlignDialog aAlignDialog(rReq.GetFrameWeld());
SmFormat aOldFormat = GetFormat();
aAlignDialog.ReadFrom( aOldFormat );
if (aAlignDialog.run() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
aAlignDialog.WriteTo(aNewFormat);
SmModule *pp = SM_MOD();
SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
aAlignDialog.WriteTo( aFmt );
pp->GetConfig()->SetStandardFormat( aFmt );
SfxUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
}
break;
case SID_TEXT:
{
const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_TEXT);
if (GetText() != rItem.GetValue())
SetText(rItem.GetValue());
}
break;
case SID_UNDO:
case SID_REDO:
{
SfxUndoManager* pTmpUndoMgr = GetUndoManager();
if( pTmpUndoMgr )
{
sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
const SfxItemSet* pArgs = rReq.GetArgs();
const SfxPoolItem* pItem;
if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
bool (SfxUndoManager::*fnDo)();
size_t nCount;
if( SID_UNDO == rReq.GetSlot() )
{
nCount = pTmpUndoMgr->GetUndoActionCount();
fnDo = &SfxUndoManager::Undo;
}
else
{
nCount = pTmpUndoMgr->GetRedoActionCount();
fnDo = &SfxUndoManager::Redo;
}
try
{
for( ; nCnt && nCount; --nCnt, --nCount )
(pTmpUndoMgr->*fnDo)();
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("starmath");
}
}
Repaint();
UpdateText();
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
while( pFrm )
{
SfxBindings& rBind = pFrm->GetBindings();
rBind.Invalidate(SID_UNDO);
rBind.Invalidate(SID_REDO);
rBind.Invalidate(SID_REPEAT);
rBind.Invalidate(SID_CLEARHISTORY);
pFrm = SfxViewFrame::GetNext( *pFrm, this );
}
}
break;
}
rReq.Done();
}
void SmDocShell::GetState(SfxItemSet &rSet)
{
SfxWhichIter aIter(rSet);
for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
{
switch (nWh)
{
case SID_TEXTMODE:
rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
break;
case SID_DOCTEMPLATE :
rSet.DisableItem(SID_DOCTEMPLATE);
break;
case SID_AUTO_REDRAW :
{
SmModule *pp = SM_MOD();
bool bRedraw = pp->GetConfig()->IsAutoRedraw();
rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
}
break;
case SID_MODIFYSTATUS:
{
sal_Unicode cMod = ' ';
if (IsModified())
cMod = '*';
rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
}
break;
case SID_TEXT:
rSet.Put(SfxStringItem(SID_TEXT, GetText()));
break;
case SID_GRAPHIC_SM:
//! very old (pre UNO) and ugly hack to invalidate the SmGraphicWidget.
//! If mnModifyCount gets changed then the call below will implicitly notify
//! SmGraphicController::StateChanged and there the window gets invalidated.
//! Thus all the 'mnModifyCount++' before invalidating this slot.
rSet.Put(SfxInt16Item(SID_GRAPHIC_SM, mnModifyCount));
break;
case SID_UNDO:
case SID_REDO:
{
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
if( pFrm )
pFrm->GetSlotState( nWh, nullptr, &rSet );
else
rSet.DisableItem( nWh );
}
break;
case SID_GETUNDOSTRINGS:
case SID_GETREDOSTRINGS:
{
SfxUndoManager* pTmpUndoMgr = GetUndoManager();
if( pTmpUndoMgr )
{
OUString(SfxUndoManager::*fnGetComment)( size_t, bool const ) const;
size_t nCount;
if( SID_GETUNDOSTRINGS == nWh )
{
nCount = pTmpUndoMgr->GetUndoActionCount();
fnGetComment = &SfxUndoManager::GetUndoActionComment;
}
else
{
nCount = pTmpUndoMgr->GetRedoActionCount();
fnGetComment = &SfxUndoManager::GetRedoActionComment;
}
if (nCount)
{
OUStringBuffer aBuf;
for (size_t n = 0; n < nCount; ++n)
{
aBuf.append((pTmpUndoMgr->*fnGetComment)( n, SfxUndoManager::TopLevel ));
aBuf.append('\n');
}
SfxStringListItem aItem( nWh );
aItem.SetString( aBuf.makeStringAndClear() );
rSet.Put( aItem );
}
}
else
rSet.DisableItem( nWh );
}
break;
}
}
}
SfxUndoManager *SmDocShell::GetUndoManager()
{
if (!mpEditEngine)
GetEditEngine();
return &mpEditEngine->GetUndoManager();
}
void SmDocShell::SaveSymbols()
{
SmModule *pp = SM_MOD();
pp->GetSymbolManager().Save();
}
void SmDocShell::Draw(OutputDevice *pDevice,
const JobSetup &,
sal_uInt16 /*nAspect*/,
bool /*bOutputForScreen*/)
{
pDevice->IntersectClipRegion(GetVisArea());
Point atmppoint;
DrawFormula(*pDevice, atmppoint);
}
SfxItemPool& SmDocShell::GetPool()
{
return SfxGetpApp()->GetPool();
}
void SmDocShell::SetVisArea(const tools::Rectangle & rVisArea)
{
tools::Rectangle aNewRect(rVisArea);
aNewRect.SetPos(Point());
if (aNewRect.IsWidthEmpty())
aNewRect.SetRight( 2000 );
if (aNewRect.IsHeightEmpty())
aNewRect.SetBottom( 1000 );
bool bIsEnabled = IsEnableSetModified();
if ( bIsEnabled )
EnableSetModified( false );
//TODO/LATER: it's unclear how this interacts with the SFX code
// If outplace editing, then don't resize the OutplaceWindow. But the
// ObjectShell has to resize.
bool bUnLockFrame;
if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
{
GetFrame()->LockAdjustPosSizePixel();
bUnLockFrame = true;
}
else
bUnLockFrame = false;
SfxObjectShell::SetVisArea( aNewRect );
if( bUnLockFrame )
GetFrame()->UnlockAdjustPosSizePixel();
if ( bIsEnabled )
EnableSetModified( bIsEnabled );
}
void SmDocShell::FillClass(SvGlobalName* pClassName,
SotClipboardFormatId* pFormat,
OUString* pFullTypeName,
sal_Int32 nFileFormat,
bool bTemplate /* = false */) const
{
if (nFileFormat == SOFFICE_FILEFORMAT_60 )
{
*pClassName = SvGlobalName(SO3_SM_CLASSID_60);
*pFormat = SotClipboardFormatId::STARMATH_60;
*pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
}
else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
{
*pClassName = SvGlobalName(SO3_SM_CLASSID_60);
*pFormat = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
*pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
}
}
void SmDocShell::SetModified(bool bModified)
{
if( IsEnableSetModified() )
{
SfxObjectShell::SetModified( bModified );
Broadcast(SfxHint(SfxHintId::DocChanged));
}
}
bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
{
OUStringBuffer aTextAsBuffer(maText);
MathType aEquation(aTextAsBuffer, mpTree.get());
return aEquation.ConvertFromStarMath( rMedium );
}
void SmDocShell::SetRightToLeft(bool bRTL)
{
SmFormat aOldFormat = GetFormat();
if (aOldFormat.IsRightToLeft() == bRTL)
return;
SmFormat aNewFormat(aOldFormat);
aNewFormat.SetRightToLeft(bRTL);
SfxUndoManager* pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
SetFormat(aNewFormat);
Repaint();
}
static Size GetTextLineSize(OutputDevice const& rDevice, const OUString& rLine)
{
Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight());
const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
if (nTabPos)
{
aSize.setWidth(0);
sal_Int32 nPos = 0;
do
{
if (nPos > 0)
aSize.setWidth(((aSize.Width() / nTabPos) + 1) * nTabPos);
const OUString aText = rLine.getToken(0, '\t', nPos);
aSize.AdjustWidth(rDevice.GetTextWidth(aText));
} while (nPos >= 0);
}
return aSize;
}
static Size GetTextSize(OutputDevice const& rDevice, std::u16string_view rText,
tools::Long MaxWidth)
{
Size aSize;
Size aTextSize;
if (rText.empty())
return aTextSize;
sal_Int32 nPos = 0;
do
{
OUString aLine(o3tl::getToken(rText, 0, '\n', nPos));
aLine = aLine.replaceAll("\r", "");
aSize = GetTextLineSize(rDevice, aLine);
if (aSize.Width() > MaxWidth)
{
do
{
OUString aText;
sal_Int32 m = aLine.getLength();
sal_Int32 nLen = m;
for (sal_Int32 n = 0; n < nLen; n++)
{
sal_Unicode cLineChar = aLine[n];
if ((cLineChar == ' ') || (cLineChar == '\t'))
{
aText = aLine.copy(0, n);
if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
m = n;
else
break;
}
}
aText = aLine.copy(0, m);
aLine = aLine.replaceAt(0, m, u"");
aSize = GetTextLineSize(rDevice, aText);
aTextSize.AdjustHeight(aSize.Height());
aTextSize.setWidth(std::clamp(aSize.Width(), aTextSize.Width(), MaxWidth));
aLine = comphelper::string::stripStart(aLine, ' ');
aLine = comphelper::string::stripStart(aLine, '\t');
aLine = comphelper::string::stripStart(aLine, ' ');
} while (!aLine.isEmpty());
}
else
{
aTextSize.AdjustHeight(aSize.Height());
aTextSize.setWidth(std::max(aTextSize.Width(), aSize.Width()));
}
} while (nPos >= 0);
return aTextSize;
}
static void DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine)
{
Point aPoint(rPosition);
const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
if (nTabPos)
{
sal_Int32 nPos = 0;
do
{
if (nPos > 0)
aPoint.setX(((aPoint.X() / nTabPos) + 1) * nTabPos);
OUString aText = rLine.getToken(0, '\t', nPos);
rDevice.DrawText(aPoint, aText);
aPoint.AdjustX(rDevice.GetTextWidth(aText));
} while (nPos >= 0);
}
else
rDevice.DrawText(aPoint, rLine);
}
static void DrawText(OutputDevice& rDevice, const Point& rPosition, std::u16string_view rText,
sal_uInt16 MaxWidth)
{
if (rText.empty())
return;
Point aPoint(rPosition);
Size aSize;
sal_Int32 nPos = 0;
do
{
OUString aLine(o3tl::getToken(rText, 0, '\n', nPos));
aLine = aLine.replaceAll("\r", "");
aSize = GetTextLineSize(rDevice, aLine);
if (aSize.Width() > MaxWidth)
{
do
{
OUString aText;
sal_Int32 m = aLine.getLength();
sal_Int32 nLen = m;
for (sal_Int32 n = 0; n < nLen; n++)
{
sal_Unicode cLineChar = aLine[n];
if ((cLineChar == ' ') || (cLineChar == '\t'))
{
aText = aLine.copy(0, n);
if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
m = n;
else
break;
}
}
aText = aLine.copy(0, m);
aLine = aLine.replaceAt(0, m, u"");
DrawTextLine(rDevice, aPoint, aText);
aPoint.AdjustY(aSize.Height());
aLine = comphelper::string::stripStart(aLine, ' ');
aLine = comphelper::string::stripStart(aLine, '\t');
aLine = comphelper::string::stripStart(aLine, ' ');
} while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth);
// print the remaining text
if (!aLine.isEmpty())
{
DrawTextLine(rDevice, aPoint, aLine);
aPoint.AdjustY(aSize.Height());
}
}
else
{
DrawTextLine(rDevice, aPoint, aLine);
aPoint.AdjustY(aSize.Height());
}
} while (nPos >= 0);
}
void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrintUIOptions,
tools::Rectangle aOutRect)
{
const bool bIsPrintTitle = rPrintUIOptions.getBoolValue(PRTUIOPT_TITLE_ROW, true);
const bool bIsPrintFrame = rPrintUIOptions.getBoolValue(PRTUIOPT_BORDER, true);
const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue(PRTUIOPT_FORMULA_TEXT, true);
SmPrintSize ePrintSize(static_cast<SmPrintSize>(
rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL)));
const sal_uInt16 nZoomFactor
= static_cast<sal_uInt16>(rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_SCALE, 100));
rOutDev.Push();
rOutDev.SetLineColor(COL_BLACK);
// output text on top
if (bIsPrintTitle)
{
Size aSize600(0, 600);
Size aSize650(0, 650);
vcl::Font aFont(FAMILY_DONTKNOW, aSize600);
aFont.SetAlignment(ALIGN_TOP);
aFont.SetWeight(WEIGHT_BOLD);
aFont.SetFontSize(aSize650);
aFont.SetColor(COL_BLACK);
rOutDev.SetFont(aFont);
Size aTitleSize(GetTextSize(rOutDev, GetTitle(), aOutRect.GetWidth() - 200));
aFont.SetWeight(WEIGHT_NORMAL);
aFont.SetFontSize(aSize600);
rOutDev.SetFont(aFont);
Size aDescSize(GetTextSize(rOutDev, GetComment(), aOutRect.GetWidth() - 200));
if (bIsPrintFrame)
rOutDev.DrawRect(tools::Rectangle(
aOutRect.TopLeft(), Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200
+ aDescSize.Height() + 100)));
aOutRect.AdjustTop(200);
// output title
aFont.SetWeight(WEIGHT_BOLD);
aFont.SetFontSize(aSize650);
rOutDev.SetFont(aFont);
Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2,
aOutRect.Top());
DrawText(rOutDev, aPoint, GetTitle(),
sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
aOutRect.AdjustTop(aTitleSize.Height() + 200);
// output description
aFont.SetWeight(WEIGHT_NORMAL);
aFont.SetFontSize(aSize600);
rOutDev.SetFont(aFont);
aPoint.setX(aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2);
aPoint.setY(aOutRect.Top());
DrawText(rOutDev, aPoint, GetComment(),
sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
aOutRect.AdjustTop(aDescSize.Height() + 300);
}
// output text on bottom
if (bIsPrintFormulaText)
{
vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600));
aFont.SetAlignment(ALIGN_TOP);
aFont.SetColor(COL_BLACK);
// get size
rOutDev.SetFont(aFont);
Size aSize(GetTextSize(rOutDev, GetText(), aOutRect.GetWidth() - 200));
aOutRect.AdjustBottom(-(aSize.Height() + 600));
if (bIsPrintFrame)
rOutDev.DrawRect(tools::Rectangle(
aOutRect.BottomLeft(), Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200)));
Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
aOutRect.Bottom() + 300);
DrawText(rOutDev, aPoint, GetText(),
sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
aOutRect.AdjustBottom(-200);
}
if (bIsPrintFrame)
rOutDev.DrawRect(aOutRect);
aOutRect.AdjustTop(100);
aOutRect.AdjustLeft(100);
aOutRect.AdjustBottom(-100);
aOutRect.AdjustRight(-100);
Size aSize(GetSize());
MapMode OutputMapMode;
switch (ePrintSize)
{
case PRINT_SIZE_NORMAL:
OutputMapMode = MapMode(SmMapUnit());
break;
case PRINT_SIZE_SCALED:
if (!aSize.IsEmpty())
{
sal_uInt16 nZ
= std::min(o3tl::convert(aOutRect.GetWidth(), 100, aSize.Width()),
o3tl::convert(aOutRect.GetHeight(), 100, aSize.Height()));
if (bIsPrintFrame && nZ > MINZOOM)
nZ -= 10;
Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100);
OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction);
}
else
OutputMapMode = MapMode(SmMapUnit());
break;
case PRINT_SIZE_ZOOMED:
{
Fraction aFraction(nZoomFactor, 100);
OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction);
break;
}
}
aSize = OutputDevice::LogicToLogic(aSize, OutputMapMode, MapMode(SmMapUnit()));
Point aPos(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2);
aPos = OutputDevice::LogicToLogic(aPos, MapMode(SmMapUnit()), OutputMapMode);
aOutRect = OutputDevice::LogicToLogic(aOutRect, MapMode(SmMapUnit()), OutputMapMode);
rOutDev.SetMapMode(OutputMapMode);
rOutDev.SetClipRegion(vcl::Region(aOutRect));
DrawFormula(rOutDev, aPos);
rOutDev.SetClipRegion();
rOutDev.Pop();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.