eecdaa02b6
Change-Id: I39cfbe43e7f27ada9999daf93aa6ccfd38fb0c52 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176561 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
1570 lines
47 KiB
C++
1570 lines
47 KiB
C++
/* -*- 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::get()->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 = &SmModule::get()->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::get()->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)
|
|
{
|
|
SvtLinguConfig().GetOptions(maLinguOptions);
|
|
|
|
SetPool(&SfxGetpApp()->GetPool());
|
|
|
|
auto* config = SmModule::get()->GetConfig();
|
|
mnSmSyntaxVersion = config->GetDefaultSmSyntaxVersion();
|
|
maFormat = config->GetStandardFormat();
|
|
|
|
StartListening(maFormat);
|
|
StartListening(*config);
|
|
|
|
SetBaseModel(new SmModel(this));
|
|
SetSmSyntaxVersion(mnSmSyntaxVersion);
|
|
|
|
SetMapUnit(SmMapUnit());
|
|
}
|
|
|
|
SmDocShell::~SmDocShell()
|
|
{
|
|
EndListening(maFormat);
|
|
EndListening(*SmModule::get()->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 :
|
|
{
|
|
auto* config = SmModule::get()->GetConfig();
|
|
config->SetAutoRedraw(!config->IsAutoRedraw());
|
|
}
|
|
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 = &SmModule::get()->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);
|
|
|
|
auto* config = SmModule::get()->GetConfig();
|
|
SmFormat aFmt(config->GetStandardFormat());
|
|
aAlignDialog.WriteTo( aFmt );
|
|
config->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 :
|
|
rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, SmModule::get()->GetConfig()->IsAutoRedraw()));
|
|
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::get()->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: */
|