bump product version to 7.6.3.2-android
[LibreOffice.git] / starmath / source / document.cxx
blob81187d376c4b846c279bd26394a085e7e165223b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 #include <com/sun/star/uno/Any.h>
25 #include <comphelper/fileformat.h>
26 #include <comphelper/accessibletexthelper.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <rtl/ustring.hxx>
29 #include <sal/log.hxx>
30 #include <unotools/eventcfg.hxx>
31 #include <sfx2/event.hxx>
32 #include <sfx2/app.hxx>
33 #include <sfx2/bindings.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <sfx2/docfilt.hxx>
36 #include <sfx2/msg.hxx>
37 #include <sfx2/objface.hxx>
38 #include <sfx2/printer.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/viewfrm.hxx>
41 #include <comphelper/classids.hxx>
42 #include <sot/formats.hxx>
43 #include <sot/storage.hxx>
44 #include <svl/eitem.hxx>
45 #include <svl/intitem.hxx>
46 #include <svl/itempool.hxx>
47 #include <svl/slstitm.hxx>
48 #include <svl/hint.hxx>
49 #include <svl/stritem.hxx>
50 #include <svl/undo.hxx>
51 #include <svl/whiter.hxx>
52 #include <vcl/mapmod.hxx>
53 #include <vcl/virdev.hxx>
54 #include <tools/mapunit.hxx>
55 #include <vcl/settings.hxx>
57 #include <document.hxx>
58 #include <action.hxx>
59 #include <dialog.hxx>
60 #include <format.hxx>
61 #include <parse.hxx>
62 #include <starmath.hrc>
63 #include <strings.hrc>
64 #include <smmod.hxx>
65 #include <symbol.hxx>
66 #include <unomodel.hxx>
67 #include <utility.hxx>
68 #include <view.hxx>
69 #include "mathtype.hxx"
70 #include "ooxmlexport.hxx"
71 #include "ooxmlimport.hxx"
72 #include "rtfexport.hxx"
73 #include <mathmlimport.hxx>
74 #include <mathmlexport.hxx>
75 #include <svx/svxids.hrc>
76 #include <cursor.hxx>
77 #include <comphelper/diagnose_ex.hxx>
78 #include <visitors.hxx>
79 #include "accessibility.hxx"
80 #include <cfgitem.hxx>
81 #include <utility>
82 #include <oox/mathml/imexport.hxx>
83 #include <ElementsDockingWindow.hxx>
84 #include <smediteng.hxx>
86 using namespace ::com::sun::star;
87 using namespace ::com::sun::star::accessibility;
88 using namespace ::com::sun::star::uno;
90 #define ShellClass_SmDocShell
91 #include <smslots.hxx>
94 SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
96 void SmDocShell::InitInterface_Impl()
98 GetStaticInterface()->RegisterPopupMenu("view");
101 void SmDocShell::SetSmSyntaxVersion(sal_uInt16 nSmSyntaxVersion)
103 mnSmSyntaxVersion = nSmSyntaxVersion;
104 maParser.reset(starmathdatabase::GetVersionSmParser(mnSmSyntaxVersion));
107 SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), "smath" )
109 void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
111 if (rHint.GetId() == SfxHintId::MathFormatChanged)
113 SetFormulaArranged(false);
115 mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
117 Repaint();
121 void SmDocShell::LoadSymbols()
123 SmModule *pp = SM_MOD();
124 pp->GetSymbolManager().Load();
128 OUString SmDocShell::GetComment() const
130 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
131 GetModel(), uno::UNO_QUERY_THROW);
132 uno::Reference<document::XDocumentProperties> xDocProps(
133 xDPS->getDocumentProperties());
134 return xDocProps->getDescription();
138 void SmDocShell::SetText(const OUString& rBuffer)
140 if (rBuffer == maText)
141 return;
143 bool bIsEnabled = IsEnableSetModified();
144 if( bIsEnabled )
145 EnableSetModified( false );
147 maText = rBuffer;
148 SetFormulaArranged( false );
150 Parse();
152 SmViewShell *pViewSh = SmGetActiveView();
153 if (pViewSh)
155 pViewSh->GetViewFrame().GetBindings().Invalidate(SID_TEXT);
156 if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
158 // have SwOleClient::FormatChanged() to align the modified formula properly
159 // even if the visible area does not change (e.g. when formula text changes from
160 // "{a over b + c} over d" to "d over {a over b + c}"
161 SfxGetpApp()->NotifyEvent(SfxEventHint( SfxEventHintId::VisAreaChanged, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
163 Repaint();
165 else
166 pViewSh->GetGraphicWidget().Invalidate();
169 if ( bIsEnabled )
170 EnableSetModified( bIsEnabled );
171 SetModified();
173 // launch accessible event if necessary
174 SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWidget().GetAccessible_Impl() : nullptr;
175 if (pAcc)
177 Any aOldValue, aNewValue;
178 if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
180 pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
181 aOldValue, aNewValue );
185 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
186 OnDocumentPrinterChanged(nullptr);
189 void SmDocShell::SetFormat(SmFormat const & rFormat)
191 maFormat = rFormat;
192 SetFormulaArranged( false );
193 SetModified();
195 mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
197 // don't use SmGetActiveView since the view shell might not be active (0 pointer)
198 // if for example the Basic Macro dialog currently has the focus. Thus:
199 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
200 while (pFrm)
202 pFrm->GetBindings().Invalidate(SID_GRAPHIC_SM);
203 pFrm = SfxViewFrame::GetNext( *pFrm, this );
207 OUString const & SmDocShell::GetAccessibleText()
209 ArrangeFormula();
210 if (maAccText.isEmpty())
212 OSL_ENSURE( mpTree, "Tree missing" );
213 if (mpTree)
215 OUStringBuffer aBuf;
216 mpTree->GetAccessibleText(aBuf);
217 maAccText = aBuf.makeStringAndClear();
220 return maAccText;
223 void SmDocShell::Parse()
225 mpTree.reset();
226 ReplaceBadChars();
227 mpTree = maParser->Parse(maText);
228 mnModifyCount++; //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
229 SetFormulaArranged( false );
230 InvalidateCursor();
231 maUsedSymbols = maParser->GetUsedSymbols();
235 void SmDocShell::ArrangeFormula()
237 if (mbFormulaArranged)
238 return;
240 // Only for the duration of the existence of this object the correct settings
241 // at the printer are guaranteed!
242 SmPrinterAccess aPrtAcc(*this);
243 OutputDevice* pOutDev = aPrtAcc.GetRefDev();
245 SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
247 // if necessary get another OutputDevice for which we format
248 if (!pOutDev)
250 if (SmViewShell *pView = SmGetActiveView())
251 pOutDev = &pView->GetGraphicWidget().GetDrawingArea()->get_ref_device();
252 else
254 pOutDev = &SM_MOD()->GetDefaultVirtualDev();
255 pOutDev->SetMapMode( MapMode(SmMapUnit()) );
258 OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == SmMapUnit(),
259 "Sm : wrong MapMode");
261 const SmFormat &rFormat = GetFormat();
262 mpTree->Prepare(rFormat, *this, 0);
264 // format/draw formulas always from left to right,
265 // and numbers should not be converted
266 vcl::text::ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode();
267 pOutDev->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default );
268 LanguageType nDigitLang = pOutDev->GetDigitLanguage();
269 pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
271 mpTree->Arrange(*pOutDev, rFormat);
273 pOutDev->SetLayoutMode( nLayoutMode );
274 pOutDev->SetDigitLanguage( nDigitLang );
276 SetFormulaArranged(true);
278 // invalidate accessible text
279 maAccText.clear();
282 void SmDocShell::UpdateEditEngineDefaultFonts()
284 SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
287 EditEngine& SmDocShell::GetEditEngine()
289 if (!mpEditEngine)
292 //! see also SmEditWindow::DataChanged !
294 mpEditEngineItemPool = EditEngine::CreatePool();
295 SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
296 mpEditEngine.reset( new SmEditEngine( mpEditEngineItemPool.get() ) );
297 mpEditEngine->EraseVirtualDevice();
299 // set initial text if the document already has some...
300 // (may be the case when reloading a doc)
301 OUString aTxt( GetText() );
302 if (!aTxt.isEmpty())
303 mpEditEngine->SetText( aTxt );
304 mpEditEngine->ClearModifyFlag();
306 return *mpEditEngine;
310 void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
312 if (!mpTree)
313 Parse();
314 OSL_ENSURE(mpTree, "Sm : NULL pointer");
316 ArrangeFormula();
318 // Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
319 // device and aren't aligned to that either. So now there can be a difference between the
320 // VisArea (i.e. the size within the client) and the current size.
321 // Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
323 rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
324 rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE ) );
326 //! in case of high contrast-mode (accessibility option!)
327 //! the draw mode needs to be set to default, because when embedding
328 //! Math for example in Calc in "a over b" the fraction bar may not
329 //! be visible else. More generally: the FillColor may have been changed.
330 DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
331 bool bRestoreDrawMode = false;
332 if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
333 rDev.GetOwnerWindow()->GetSettings().GetStyleSettings().GetHighContrastMode())
335 nOldDrawMode = rDev.GetDrawMode();
336 rDev.SetDrawMode( DrawModeFlags::Default );
337 bRestoreDrawMode = true;
340 // format/draw formulas always from left to right
341 // and numbers should not be converted
342 vcl::text::ComplexTextLayoutFlags nLayoutMode = rDev.GetLayoutMode();
343 rDev.SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default );
344 LanguageType nDigitLang = rDev.GetDigitLanguage();
345 rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
347 //Set selection if any
348 if(mpCursor && bDrawSelection){
349 mpCursor->AnnotateSelection();
350 SmSelectionDrawingVisitor(rDev, mpTree.get(), rPosition);
353 //Drawing using visitor
354 SmDrawingVisitor(rDev, rPosition, mpTree.get());
357 rDev.SetLayoutMode( nLayoutMode );
358 rDev.SetDigitLanguage( nDigitLang );
360 if (bRestoreDrawMode)
361 rDev.SetDrawMode( nOldDrawMode );
364 Size SmDocShell::GetSize()
366 Size aRet;
368 if (!mpTree)
369 Parse();
371 if (mpTree)
373 ArrangeFormula();
374 aRet = mpTree->GetSize();
376 if ( !aRet.Width() )
377 aRet.setWidth( 2000 );
378 else
379 aRet.AdjustWidth(maFormat.GetDistance( DIS_LEFTSPACE ) +
380 maFormat.GetDistance( DIS_RIGHTSPACE ) );
381 if ( !aRet.Height() )
382 aRet.setHeight( 1000 );
383 else
384 aRet.AdjustHeight(maFormat.GetDistance( DIS_TOPSPACE ) +
385 maFormat.GetDistance( DIS_BOTTOMSPACE ) );
388 return aRet;
391 void SmDocShell::InvalidateCursor(){
392 mpCursor.reset();
395 SmCursor& SmDocShell::GetCursor(){
396 if(!mpCursor)
397 mpCursor.reset(new SmCursor(mpTree.get(), this));
398 return *mpCursor;
401 bool SmDocShell::HasCursor() const { return mpCursor != nullptr; }
403 SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
405 pPrinter = rDocShell.GetPrt();
406 if ( pPrinter )
408 pPrinter->Push( vcl::PushFlags::MAPMODE );
409 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
411 // if it is an embedded object (without its own printer)
412 // we change the MapMode temporarily.
413 //!If it is a document with its own printer the MapMode should
414 //!be set correct (once) elsewhere(!), in order to avoid numerous
415 //!superfluous pushing and popping of the MapMode when using
416 //!this class.
418 const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
419 if ( SmMapUnit() != eOld )
421 MapMode aMap( pPrinter->GetMapMode() );
422 aMap.SetMapUnit( SmMapUnit() );
423 Point aTmp( aMap.GetOrigin() );
424 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
425 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
426 aMap.SetOrigin( aTmp );
427 pPrinter->SetMapMode( aMap );
431 pRefDev = rDocShell.GetRefDev();
432 if ( !pRefDev || pPrinter.get() == pRefDev.get() )
433 return;
435 pRefDev->Push( vcl::PushFlags::MAPMODE );
436 if ( SfxObjectCreateMode::EMBEDDED != rDocShell.GetCreateMode() )
437 return;
439 // if it is an embedded object (without its own printer)
440 // we change the MapMode temporarily.
441 //!If it is a document with its own printer the MapMode should
442 //!be set correct (once) elsewhere(!), in order to avoid numerous
443 //!superfluous pushing and popping of the MapMode when using
444 //!this class.
446 const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
447 if ( SmMapUnit() != eOld )
449 MapMode aMap( pRefDev->GetMapMode() );
450 aMap.SetMapUnit( SmMapUnit() );
451 Point aTmp( aMap.GetOrigin() );
452 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
453 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
454 aMap.SetOrigin( aTmp );
455 pRefDev->SetMapMode( aMap );
459 SmPrinterAccess::~SmPrinterAccess()
461 if ( pPrinter )
462 pPrinter->Pop();
463 if ( pRefDev && pRefDev != pPrinter )
464 pRefDev->Pop();
467 Printer* SmDocShell::GetPrt()
469 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
471 // Normally the server provides the printer. But if it doesn't provide one (e.g. because
472 // there is no connection) it still can be the case that we know the printer because it
473 // has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
474 Printer* pPrt = GetDocumentPrinter();
475 if (!pPrt && mpTmpPrinter)
476 pPrt = mpTmpPrinter;
477 return pPrt;
479 else if (!mpPrinter)
481 auto pOptions = std::make_unique<SfxItemSetFixed<
482 SID_PRINTTITLE, SID_PRINTZOOM,
483 SID_NO_RIGHT_SPACES, SID_SAVE_ONLY_USED_SYMBOLS,
484 SID_AUTO_CLOSE_BRACKETS, SID_SMEDITWINDOWZOOM>>(GetPool());
485 SmModule *pp = SM_MOD();
486 pp->GetConfig()->ConfigToItemSet(*pOptions);
487 mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pOptions));
488 mpPrinter->SetMapMode(MapMode(SmMapUnit()));
490 return mpPrinter;
493 OutputDevice* SmDocShell::GetRefDev()
495 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
497 OutputDevice* pOutDev = GetDocumentRefDev();
498 if (pOutDev)
499 return pOutDev;
502 return GetPrt();
505 void SmDocShell::SetPrinter( SfxPrinter *pNew )
507 mpPrinter.disposeAndClear();
508 mpPrinter = pNew; //Transfer ownership
509 mpPrinter->SetMapMode( MapMode(SmMapUnit()) );
510 SetFormulaArranged(false);
511 Repaint();
514 void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
516 mpTmpPrinter = pPrt;
517 SetFormulaArranged(false);
518 Size aOldSize = GetVisArea().GetSize();
519 Repaint();
520 if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
521 SetModified();
522 mpTmpPrinter = nullptr;
525 void SmDocShell::Repaint()
527 bool bIsEnabled = IsEnableSetModified();
528 if (bIsEnabled)
529 EnableSetModified( false );
531 SetFormulaArranged(false);
533 Size aVisSize = GetSize();
534 SetVisAreaSize(aVisSize);
535 if (SmViewShell* pViewSh = SmGetActiveView())
536 pViewSh->GetGraphicWidget().Invalidate();
538 if (bIsEnabled)
539 EnableSetModified(bIsEnabled);
542 SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
543 : SfxObjectShell(i_nSfxCreationFlags)
544 , m_pMlElementTree(nullptr)
545 , mpPrinter(nullptr)
546 , mpTmpPrinter(nullptr)
547 , mnModifyCount(0)
548 , mbFormulaArranged(false)
549 , mnSmSyntaxVersion(SM_MOD()->GetConfig()->GetDefaultSmSyntaxVersion())
551 SvtLinguConfig().GetOptions(maLinguOptions);
553 SetPool(&SfxGetpApp()->GetPool());
555 SmModule *pp = SM_MOD();
556 maFormat = pp->GetConfig()->GetStandardFormat();
558 StartListening(maFormat);
559 StartListening(*pp->GetConfig());
561 SetBaseModel(new SmModel(this));
562 SetSmSyntaxVersion(mnSmSyntaxVersion);
564 SetMapUnit(SmMapUnit());
567 SmDocShell::~SmDocShell()
569 SmModule *pp = SM_MOD();
571 EndListening(maFormat);
572 EndListening(*pp->GetConfig());
574 mpCursor.reset();
575 mpEditEngine.reset();
576 mpEditEngineItemPool.clear();
577 mpPrinter.disposeAndClear();
579 mathml::SmMlIteratorFree(m_pMlElementTree);
582 bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
584 bool bSuccess = false;
585 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
587 OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
589 if ( rFltName == MATHML_XML )
591 if (mpTree)
593 mpTree.reset();
594 InvalidateCursor();
596 rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
597 SmXMLImportWrapper aEquation(xModel);
598 aEquation.useHTMLMLEntities(true);
599 bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
601 else
603 SvStream *pStream = rMedium.GetInStream();
604 if ( pStream )
606 if ( SotStorage::IsStorageFile( pStream ) )
608 tools::SvRef<SotStorage> aStorage = new SotStorage( pStream, false );
609 if ( aStorage->IsStream("Equation Native") )
611 // is this a MathType Storage?
612 OUStringBuffer aBuffer;
613 MathType aEquation(aBuffer);
614 bSuccess = aEquation.Parse( aStorage.get() );
615 if ( bSuccess )
617 maText = aBuffer.makeStringAndClear();
618 Parse();
625 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
627 SetFormulaArranged( false );
628 Repaint();
631 FinishedLoading();
632 return bSuccess;
636 bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
638 bool bRet = false;
639 if ( SfxObjectShell::InitNew( xStorage ) )
641 bRet = true;
642 SetVisArea(tools::Rectangle(Point(0, 0), Size(2000, 1000)));
644 return bRet;
648 bool SmDocShell::Load( SfxMedium& rMedium )
650 bool bRet = false;
651 if( SfxObjectShell::Load( rMedium ))
653 uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
654 if (xStorage->hasByName("content.xml") && xStorage->isStreamElement("content.xml"))
656 // is this a fabulous math package ?
657 rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
658 SmXMLImportWrapper aEquation(xModel);
659 auto nError = aEquation.Import(rMedium);
660 bRet = ERRCODE_NONE == nError;
661 SetError(nError);
665 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
667 SetFormulaArranged( false );
668 Repaint();
671 FinishedLoading();
672 return bRet;
676 bool SmDocShell::Save()
678 //! apply latest changes if necessary
679 UpdateText();
681 if ( SfxObjectShell::Save() )
683 if (!mpTree)
684 Parse();
685 if( mpTree )
686 ArrangeFormula();
688 Reference<css::frame::XModel> xModel(GetModel());
689 SmXMLExportWrapper aEquation(xModel);
690 aEquation.SetFlat(false);
691 return aEquation.Export(*GetMedium());
694 return false;
698 * replace bad characters that can not be saved. (#i74144)
699 * */
700 void SmDocShell::ReplaceBadChars()
702 bool bReplace = false;
704 if (!mpEditEngine)
705 return;
707 OUStringBuffer aBuf( mpEditEngine->GetText() );
709 for (sal_Int32 i = 0; i < aBuf.getLength(); ++i)
711 if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
713 aBuf[i] = ' ';
714 bReplace = true;
718 if (bReplace)
719 maText = aBuf.makeStringAndClear();
723 void SmDocShell::UpdateText()
725 if (mpEditEngine && mpEditEngine->IsModified())
727 OUString aEngTxt( mpEditEngine->GetText() );
728 if (GetText() != aEngTxt)
729 SetText( aEngTxt );
734 bool SmDocShell::SaveAs( SfxMedium& rMedium )
736 bool bRet = false;
738 //! apply latest changes if necessary
739 UpdateText();
741 if ( SfxObjectShell::SaveAs( rMedium ) )
743 if (!mpTree)
744 Parse();
745 if( mpTree )
746 ArrangeFormula();
748 Reference<css::frame::XModel> xModel(GetModel());
749 SmXMLExportWrapper aEquation(xModel);
750 aEquation.SetFlat(false);
751 bRet = aEquation.Export(rMedium);
753 return bRet;
756 bool SmDocShell::ConvertTo( SfxMedium &rMedium )
758 bool bRet = false;
759 std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
760 if( pFlt )
762 if( !mpTree )
763 Parse();
764 if( mpTree )
765 ArrangeFormula();
767 const OUString& rFltName = pFlt->GetFilterName();
768 if(rFltName == STAROFFICE_XML)
770 Reference<css::frame::XModel> xModel(GetModel());
771 SmXMLExportWrapper aEquation(xModel);
772 aEquation.SetFlat(false);
773 bRet = aEquation.Export(rMedium);
775 else if(rFltName == MATHML_XML)
777 Reference<css::frame::XModel> xModel(GetModel());
778 SmXMLExportWrapper aEquation(xModel);
779 aEquation.SetFlat(true);
780 aEquation.SetUseHTMLMLEntities(true);
781 bRet = aEquation.Export(rMedium);
783 else if (pFlt->GetFilterName() == "MathType 3.x")
784 bRet = WriteAsMathType3( rMedium );
786 return bRet;
789 void SmDocShell::writeFormulaOoxml(
790 ::sax_fastparser::FSHelperPtr const& pSerializer,
791 oox::core::OoxmlVersion const version,
792 oox::drawingml::DocumentType const documentType,
793 const sal_Int8 nAlign)
795 if( !mpTree )
796 Parse();
797 if( mpTree )
798 ArrangeFormula();
799 SmOoxmlExport aEquation(mpTree.get(), version, documentType);
800 if(documentType == oox::drawingml::DOCUMENT_DOCX)
801 aEquation.ConvertFromStarMath( pSerializer, nAlign);
802 else
803 aEquation.ConvertFromStarMath(pSerializer, oox::FormulaImExportBase::eFormulaAlign::INLINE);
806 void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
808 if (!mpTree)
809 Parse();
810 if (mpTree)
811 ArrangeFormula();
812 SmRtfExport aEquation(mpTree.get());
813 aEquation.ConvertFromStarMath(rBuffer, nEncoding);
816 void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
818 SmOoxmlImport aEquation( stream );
819 SetText( aEquation.ConvertToStarMath());
822 void SmDocShell::Execute(SfxRequest& rReq)
824 switch (rReq.GetSlot())
826 case SID_TEXTMODE:
828 SmFormat aOldFormat = GetFormat();
829 SmFormat aNewFormat( aOldFormat );
830 aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
832 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
833 if (pTmpUndoMgr)
834 pTmpUndoMgr->AddUndoAction(
835 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
837 SetFormat( aNewFormat );
838 Repaint();
840 break;
842 case SID_AUTO_REDRAW :
844 SmModule *pp = SM_MOD();
845 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
846 pp->GetConfig()->SetAutoRedraw(!bRedraw);
848 break;
850 case SID_LOADSYMBOLS:
851 LoadSymbols();
852 break;
854 case SID_SAVESYMBOLS:
855 SaveSymbols();
856 break;
858 case SID_FONT:
860 // get device used to retrieve the FontList
861 OutputDevice *pDev = GetPrinter();
862 if (!pDev || pDev->GetFontFaceCollectionCount() == 0)
863 pDev = &SM_MOD()->GetDefaultVirtualDev();
864 OSL_ENSURE (pDev, "device for font list missing" );
866 SmFontTypeDialog aFontTypeDialog(rReq.GetFrameWeld(), pDev);
868 SmFormat aOldFormat = GetFormat();
869 aFontTypeDialog.ReadFrom( aOldFormat );
870 if (aFontTypeDialog.run() == RET_OK)
872 SmFormat aNewFormat( aOldFormat );
874 aFontTypeDialog.WriteTo(aNewFormat);
875 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
876 if (pTmpUndoMgr)
877 pTmpUndoMgr->AddUndoAction(
878 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
880 SetFormat( aNewFormat );
881 Repaint();
884 break;
886 case SID_FONTSIZE:
888 SmFontSizeDialog aFontSizeDialog(rReq.GetFrameWeld());
890 SmFormat aOldFormat = GetFormat();
891 aFontSizeDialog.ReadFrom( aOldFormat );
892 if (aFontSizeDialog.run() == RET_OK)
894 SmFormat aNewFormat( aOldFormat );
896 aFontSizeDialog.WriteTo(aNewFormat);
898 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
899 if (pTmpUndoMgr)
900 pTmpUndoMgr->AddUndoAction(
901 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
903 SetFormat( aNewFormat );
904 Repaint();
907 break;
909 case SID_DISTANCE:
911 SmDistanceDialog aDistanceDialog(rReq.GetFrameWeld());
913 SmFormat aOldFormat = GetFormat();
914 aDistanceDialog.ReadFrom( aOldFormat );
915 if (aDistanceDialog.run() == RET_OK)
917 SmFormat aNewFormat( aOldFormat );
919 aDistanceDialog.WriteTo(aNewFormat);
921 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
922 if (pTmpUndoMgr)
923 pTmpUndoMgr->AddUndoAction(
924 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
926 SetFormat( aNewFormat );
927 Repaint();
930 break;
932 case SID_ALIGN:
934 SmAlignDialog aAlignDialog(rReq.GetFrameWeld());
936 SmFormat aOldFormat = GetFormat();
937 aAlignDialog.ReadFrom( aOldFormat );
938 if (aAlignDialog.run() == RET_OK)
940 SmFormat aNewFormat( aOldFormat );
942 aAlignDialog.WriteTo(aNewFormat);
944 SmModule *pp = SM_MOD();
945 SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
946 aAlignDialog.WriteTo( aFmt );
947 pp->GetConfig()->SetStandardFormat( aFmt );
949 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
950 if (pTmpUndoMgr)
951 pTmpUndoMgr->AddUndoAction(
952 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
954 SetFormat( aNewFormat );
955 Repaint();
958 break;
960 case SID_TEXT:
962 const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_TEXT);
963 if (GetText() != rItem.GetValue())
964 SetText(rItem.GetValue());
966 break;
968 case SID_UNDO:
969 case SID_REDO:
971 SfxUndoManager* pTmpUndoMgr = GetUndoManager();
972 if( pTmpUndoMgr )
974 sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
975 const SfxItemSet* pArgs = rReq.GetArgs();
976 const SfxPoolItem* pItem;
977 if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
978 nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
980 bool (SfxUndoManager::*fnDo)();
982 size_t nCount;
983 if( SID_UNDO == rReq.GetSlot() )
985 nCount = pTmpUndoMgr->GetUndoActionCount();
986 fnDo = &SfxUndoManager::Undo;
988 else
990 nCount = pTmpUndoMgr->GetRedoActionCount();
991 fnDo = &SfxUndoManager::Redo;
996 for( ; nCnt && nCount; --nCnt, --nCount )
997 (pTmpUndoMgr->*fnDo)();
999 catch( const Exception& )
1001 DBG_UNHANDLED_EXCEPTION("starmath");
1004 Repaint();
1005 UpdateText();
1006 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1007 while( pFrm )
1009 SfxBindings& rBind = pFrm->GetBindings();
1010 rBind.Invalidate(SID_UNDO);
1011 rBind.Invalidate(SID_REDO);
1012 rBind.Invalidate(SID_REPEAT);
1013 rBind.Invalidate(SID_CLEARHISTORY);
1014 pFrm = SfxViewFrame::GetNext( *pFrm, this );
1017 break;
1020 rReq.Done();
1024 void SmDocShell::GetState(SfxItemSet &rSet)
1026 SfxWhichIter aIter(rSet);
1028 for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
1030 switch (nWh)
1032 case SID_TEXTMODE:
1033 rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
1034 break;
1036 case SID_DOCTEMPLATE :
1037 rSet.DisableItem(SID_DOCTEMPLATE);
1038 break;
1040 case SID_AUTO_REDRAW :
1042 SmModule *pp = SM_MOD();
1043 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
1045 rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
1047 break;
1049 case SID_MODIFYSTATUS:
1051 sal_Unicode cMod = ' ';
1052 if (IsModified())
1053 cMod = '*';
1054 rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
1056 break;
1058 case SID_TEXT:
1059 rSet.Put(SfxStringItem(SID_TEXT, GetText()));
1060 break;
1062 case SID_GRAPHIC_SM:
1063 //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWidget.
1064 //! If mnModifyCount gets changed then the call below will implicitly notify
1065 //! SmGraphicController::StateChanged and there the window gets invalidated.
1066 //! Thus all the 'mnModifyCount++' before invalidating this slot.
1067 rSet.Put(SfxInt16Item(SID_GRAPHIC_SM, mnModifyCount));
1068 break;
1070 case SID_UNDO:
1071 case SID_REDO:
1073 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1074 if( pFrm )
1075 pFrm->GetSlotState( nWh, nullptr, &rSet );
1076 else
1077 rSet.DisableItem( nWh );
1079 break;
1081 case SID_GETUNDOSTRINGS:
1082 case SID_GETREDOSTRINGS:
1084 SfxUndoManager* pTmpUndoMgr = GetUndoManager();
1085 if( pTmpUndoMgr )
1087 OUString(SfxUndoManager::*fnGetComment)( size_t, bool const ) const;
1089 size_t nCount;
1090 if( SID_GETUNDOSTRINGS == nWh )
1092 nCount = pTmpUndoMgr->GetUndoActionCount();
1093 fnGetComment = &SfxUndoManager::GetUndoActionComment;
1095 else
1097 nCount = pTmpUndoMgr->GetRedoActionCount();
1098 fnGetComment = &SfxUndoManager::GetRedoActionComment;
1100 if (nCount)
1102 OUStringBuffer aBuf;
1103 for (size_t n = 0; n < nCount; ++n)
1105 aBuf.append((pTmpUndoMgr->*fnGetComment)( n, SfxUndoManager::TopLevel ));
1106 aBuf.append('\n');
1109 SfxStringListItem aItem( nWh );
1110 aItem.SetString( aBuf.makeStringAndClear() );
1111 rSet.Put( aItem );
1114 else
1115 rSet.DisableItem( nWh );
1117 break;
1123 SfxUndoManager *SmDocShell::GetUndoManager()
1125 if (!mpEditEngine)
1126 GetEditEngine();
1127 return &mpEditEngine->GetUndoManager();
1131 void SmDocShell::SaveSymbols()
1133 SmModule *pp = SM_MOD();
1134 pp->GetSymbolManager().Save();
1138 void SmDocShell::Draw(OutputDevice *pDevice,
1139 const JobSetup &,
1140 sal_uInt16 /*nAspect*/,
1141 bool /*bOutputForScreen*/)
1143 pDevice->IntersectClipRegion(GetVisArea());
1144 Point atmppoint;
1145 DrawFormula(*pDevice, atmppoint);
1148 SfxItemPool& SmDocShell::GetPool()
1150 return SfxGetpApp()->GetPool();
1153 void SmDocShell::SetVisArea(const tools::Rectangle & rVisArea)
1155 tools::Rectangle aNewRect(rVisArea);
1157 aNewRect.SetPos(Point());
1159 if (aNewRect.IsWidthEmpty())
1160 aNewRect.SetRight( 2000 );
1161 if (aNewRect.IsHeightEmpty())
1162 aNewRect.SetBottom( 1000 );
1164 bool bIsEnabled = IsEnableSetModified();
1165 if ( bIsEnabled )
1166 EnableSetModified( false );
1168 //TODO/LATER: it's unclear how this interacts with the SFX code
1169 // If outplace editing, then don't resize the OutplaceWindow. But the
1170 // ObjectShell has to resize.
1171 bool bUnLockFrame;
1172 if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
1174 GetFrame()->LockAdjustPosSizePixel();
1175 bUnLockFrame = true;
1177 else
1178 bUnLockFrame = false;
1180 SfxObjectShell::SetVisArea( aNewRect );
1182 if( bUnLockFrame )
1183 GetFrame()->UnlockAdjustPosSizePixel();
1185 if ( bIsEnabled )
1186 EnableSetModified( bIsEnabled );
1190 void SmDocShell::FillClass(SvGlobalName* pClassName,
1191 SotClipboardFormatId* pFormat,
1192 OUString* pFullTypeName,
1193 sal_Int32 nFileFormat,
1194 bool bTemplate /* = false */) const
1196 if (nFileFormat == SOFFICE_FILEFORMAT_60 )
1198 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1199 *pFormat = SotClipboardFormatId::STARMATH_60;
1200 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1202 else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
1204 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1205 *pFormat = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
1206 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1210 void SmDocShell::SetModified(bool bModified)
1212 if( IsEnableSetModified() )
1214 SfxObjectShell::SetModified( bModified );
1215 Broadcast(SfxHint(SfxHintId::DocChanged));
1219 bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
1221 OUStringBuffer aTextAsBuffer(maText);
1222 MathType aEquation(aTextAsBuffer, mpTree.get());
1223 return aEquation.ConvertFromStarMath( rMedium );
1226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */