nss: upgrade to release 3.73
[LibreOffice.git] / starmath / source / document.cxx
blob07886b68f6a0061c361883bcf15a794a01dde679
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 <com/sun/star/accessibility/AccessibleEventId.hpp>
21 #include <com/sun/star/uno/Any.h>
23 #include <comphelper/fileformat.h>
24 #include <comphelper/accessibletexthelper.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
28 #include <unotools/eventcfg.hxx>
29 #include <sfx2/event.hxx>
30 #include <sfx2/app.hxx>
31 #include <sfx2/bindings.hxx>
32 #include <sfx2/docfile.hxx>
33 #include <sfx2/docfilt.hxx>
34 #include <sfx2/msg.hxx>
35 #include <sfx2/objface.hxx>
36 #include <sfx2/printer.hxx>
37 #include <sfx2/request.hxx>
38 #include <sfx2/viewfrm.hxx>
39 #include <comphelper/classids.hxx>
40 #include <sot/formats.hxx>
41 #include <sot/storage.hxx>
42 #include <svl/eitem.hxx>
43 #include <svl/intitem.hxx>
44 #include <svl/itempool.hxx>
45 #include <svl/slstitm.hxx>
46 #include <svl/hint.hxx>
47 #include <svl/stritem.hxx>
48 #include <svl/undo.hxx>
49 #include <svl/whiter.hxx>
50 #include <editeng/editeng.hxx>
51 #include <editeng/editstat.hxx>
52 #include <editeng/eeitem.hxx>
53 #include <editeng/fhgtitem.hxx>
54 #include <editeng/fontitem.hxx>
55 #include <vcl/mapmod.hxx>
56 #include <vcl/svapp.hxx>
57 #include <vcl/virdev.hxx>
58 #include <tools/mapunit.hxx>
59 #include <vcl/settings.hxx>
61 #include <document.hxx>
62 #include <action.hxx>
63 #include <dialog.hxx>
64 #include <format.hxx>
65 #include <starmath.hrc>
66 #include <strings.hrc>
67 #include <smmod.hxx>
68 #include <symbol.hxx>
69 #include <unomodel.hxx>
70 #include <utility.hxx>
71 #include <view.hxx>
72 #include "mathtype.hxx"
73 #include "ooxmlexport.hxx"
74 #include "ooxmlimport.hxx"
75 #include "rtfexport.hxx"
76 #include "mathmlimport.hxx"
77 #include "mathmlexport.hxx"
78 #include <svx/svxids.hrc>
79 #include <cursor.hxx>
80 #include <tools/diagnose_ex.h>
81 #include <visitors.hxx>
82 #include "accessibility.hxx"
83 #include "cfgitem.hxx"
84 #include <memory>
85 #include <utility>
86 #include <oox/mathml/export.hxx>
88 using namespace ::com::sun::star;
89 using namespace ::com::sun::star::accessibility;
90 using namespace ::com::sun::star::uno;
92 #define ShellClass_SmDocShell
93 #include <smslots.hxx>
96 SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
98 void SmDocShell::InitInterface_Impl()
100 GetStaticInterface()->RegisterPopupMenu("view");
103 SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), "smath" )
105 void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
107 if (rHint.GetId() == SfxHintId::MathFormatChanged)
109 SetFormulaArranged(false);
111 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
113 Repaint();
117 void SmDocShell::LoadSymbols()
119 SmModule *pp = SM_MOD();
120 pp->GetSymbolManager().Load();
124 OUString SmDocShell::GetComment() const
126 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
127 GetModel(), uno::UNO_QUERY_THROW);
128 uno::Reference<document::XDocumentProperties> xDocProps(
129 xDPS->getDocumentProperties());
130 return xDocProps->getDescription();
134 void SmDocShell::SetText(const OUString& rBuffer)
136 if (rBuffer == maText)
137 return;
139 bool bIsEnabled = IsEnableSetModified();
140 if( bIsEnabled )
141 EnableSetModified( false );
143 maText = rBuffer;
144 SetFormulaArranged( false );
146 Parse();
148 SmViewShell *pViewSh = SmGetActiveView();
149 if( pViewSh )
151 pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_TEXT);
152 if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
154 // have SwOleClient::FormatChanged() to align the modified formula properly
155 // even if the visible area does not change (e.g. when formula text changes from
156 // "{a over b + c} over d" to "d over {a over b + c}"
157 SfxGetpApp()->NotifyEvent(SfxEventHint( SfxEventHintId::VisAreaChanged, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
159 Repaint();
161 else
162 pViewSh->GetGraphicWindow().Invalidate();
165 if ( bIsEnabled )
166 EnableSetModified( bIsEnabled );
167 SetModified();
169 // launch accessible event if necessary
170 SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWindow().GetAccessible_Impl() : nullptr;
171 if (pAcc)
173 Any aOldValue, aNewValue;
174 if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
176 pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
177 aOldValue, aNewValue );
181 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
182 OnDocumentPrinterChanged(nullptr);
185 void SmDocShell::SetFormat(SmFormat const & rFormat)
187 maFormat = rFormat;
188 SetFormulaArranged( false );
189 SetModified();
191 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
193 // don't use SmGetActiveView since the view shell might not be active (0 pointer)
194 // if for example the Basic Macro dialog currently has the focus. Thus:
195 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
196 while (pFrm)
198 pFrm->GetBindings().Invalidate(SID_GAPHIC_SM);
199 pFrm = SfxViewFrame::GetNext( *pFrm, this );
203 OUString const & SmDocShell::GetAccessibleText()
205 ArrangeFormula();
206 if (maAccText.isEmpty())
208 OSL_ENSURE( mpTree, "Tree missing" );
209 if (mpTree)
211 OUStringBuffer aBuf;
212 mpTree->GetAccessibleText(aBuf);
213 maAccText = aBuf.makeStringAndClear();
216 return maAccText;
219 void SmDocShell::Parse()
221 mpTree.reset();
222 ReplaceBadChars();
223 mpTree = maParser.Parse(maText);
224 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
225 SetFormulaArranged( false );
226 InvalidateCursor();
227 maUsedSymbols = maParser.GetUsedSymbols();
231 void SmDocShell::ArrangeFormula()
233 if (mbFormulaArranged)
234 return;
236 // Only for the duration of the existence of this object the correct settings
237 // at the printer are guaranteed!
238 SmPrinterAccess aPrtAcc(*this);
239 OutputDevice* pOutDev = aPrtAcc.GetRefDev();
241 SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
243 // if necessary get another OutputDevice for which we format
244 if (!pOutDev)
246 SmViewShell *pView = SmGetActiveView();
247 if (pView)
248 pOutDev = &pView->GetGraphicWindow();
249 else
251 pOutDev = &SM_MOD()->GetDefaultVirtualDev();
252 pOutDev->SetMapMode( MapMode(MapUnit::Map100thMM) );
255 OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM,
256 "Sm : wrong MapMode");
258 const SmFormat &rFormat = GetFormat();
259 mpTree->Prepare(rFormat, *this, 0);
261 // format/draw formulas always from left to right,
262 // and numbers should not be converted
263 ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode();
264 pOutDev->SetLayoutMode( ComplexTextLayoutFlags::Default );
265 LanguageType nDigitLang = pOutDev->GetDigitLanguage();
266 pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
268 mpTree->Arrange(*pOutDev, rFormat);
270 pOutDev->SetLayoutMode( nLayoutMode );
271 pOutDev->SetDigitLanguage( nDigitLang );
273 SetFormulaArranged(true);
275 // invalidate accessible text
276 maAccText.clear();
279 void SmDocShell::UpdateEditEngineDefaultFonts(const Color& aTextColor)
281 assert(mpEditEngineItemPool);
282 if (!mpEditEngineItemPool)
283 return;
285 // set fonts to be used
286 struct FontDta {
287 LanguageType nFallbackLang;
288 LanguageType nLang;
289 DefaultFontType nFontType;
290 sal_uInt16 nFontInfoId;
291 } aTable[3] =
293 // info to get western font to be used
294 { LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
295 DefaultFontType::FIXED, EE_CHAR_FONTINFO },
296 // info to get CJK font to be used
297 { LANGUAGE_JAPANESE, LANGUAGE_NONE,
298 DefaultFontType::CJK_TEXT, EE_CHAR_FONTINFO_CJK },
299 // info to get CTL font to be used
300 { LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
301 DefaultFontType::CTL_TEXT, EE_CHAR_FONTINFO_CTL }
304 aTable[0].nLang = maLinguOptions.nDefaultLanguage;
305 aTable[1].nLang = maLinguOptions.nDefaultLanguage_CJK;
306 aTable[2].nLang = maLinguOptions.nDefaultLanguage_CTL;
308 for (const FontDta & rFntDta : aTable)
310 LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
311 rFntDta.nFallbackLang : rFntDta.nLang;
312 vcl::Font aFont = OutputDevice::GetDefaultFont(
313 rFntDta.nFontType, nLang, GetDefaultFontFlags::OnlyOne );
314 aFont.SetColor(aTextColor);
315 mpEditEngineItemPool->SetPoolDefaultItem(
316 SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
317 aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(),
318 rFntDta.nFontInfoId ) );
321 // set font heights
322 SvxFontHeightItem aFontHeigt(
323 Application::GetDefaultDevice()->LogicToPixel(
324 Size( 0, 11 ), MapMode( MapUnit::MapPoint ) ).Height(), 100,
325 EE_CHAR_FONTHEIGHT );
326 mpEditEngineItemPool->SetPoolDefaultItem( aFontHeigt );
327 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CJK );
328 mpEditEngineItemPool->SetPoolDefaultItem( aFontHeigt );
329 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CTL );
330 mpEditEngineItemPool->SetPoolDefaultItem( aFontHeigt );
333 EditEngine& SmDocShell::GetEditEngine()
335 if (!mpEditEngine)
338 //! see also SmEditWindow::DataChanged !
341 mpEditEngineItemPool = EditEngine::CreatePool();
343 const StyleSettings& rStyleSettings = Application::GetDefaultDevice()->GetSettings().GetStyleSettings();
344 UpdateEditEngineDefaultFonts(rStyleSettings.GetFieldTextColor());
346 mpEditEngine.reset( new EditEngine( mpEditEngineItemPool ) );
348 mpEditEngine->SetAddExtLeading(true);
350 mpEditEngine->EnableUndo( true );
351 mpEditEngine->SetDefTab( sal_uInt16(
352 Application::GetDefaultDevice()->GetTextWidth("XXXX")) );
354 mpEditEngine->SetBackgroundColor(rStyleSettings.GetFieldColor());
356 mpEditEngine->SetControlWord(
357 (mpEditEngine->GetControlWord() | EEControlBits::AUTOINDENTING) &
358 EEControlBits(~EEControlBits::UNDOATTRIBS) &
359 EEControlBits(~EEControlBits::PASTESPECIAL) );
361 mpEditEngine->SetWordDelimiters(" .=+-*/(){}[];\"");
362 mpEditEngine->SetRefMapMode(MapMode(MapUnit::MapPixel));
364 mpEditEngine->SetPaperSize( Size( 800, 0 ) );
366 mpEditEngine->EraseVirtualDevice();
368 // set initial text if the document already has some...
369 // (may be the case when reloading a doc)
370 OUString aTxt( GetText() );
371 if (!aTxt.isEmpty())
372 mpEditEngine->SetText( aTxt );
374 mpEditEngine->ClearModifyFlag();
377 return *mpEditEngine;
381 void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
383 if (!mpTree)
384 Parse();
385 OSL_ENSURE(mpTree, "Sm : NULL pointer");
387 ArrangeFormula();
389 // Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
390 // device and aren't aligned to that either. So now there can be a difference between the
391 // VisArea (i.e. the size within the client) and the current size.
392 // Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
394 rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
395 rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE ) );
397 //! in case of high contrast-mode (accessibility option!)
398 //! the draw mode needs to be set to default, because when embedding
399 //! Math for example in Calc in "a over b" the fraction bar may not
400 //! be visible else. More generally: the FillColor may have been changed.
401 DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
402 bool bRestoreDrawMode = false;
403 if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
404 static_cast<vcl::Window &>(rDev).GetSettings().GetStyleSettings().GetHighContrastMode())
406 nOldDrawMode = rDev.GetDrawMode();
407 rDev.SetDrawMode( DrawModeFlags::Default );
408 bRestoreDrawMode = true;
411 // format/draw formulas always from left to right
412 // and numbers should not be converted
413 ComplexTextLayoutFlags nLayoutMode = rDev.GetLayoutMode();
414 rDev.SetLayoutMode( ComplexTextLayoutFlags::Default );
415 LanguageType nDigitLang = rDev.GetDigitLanguage();
416 rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
418 //Set selection if any
419 if(mpCursor && bDrawSelection){
420 mpCursor->AnnotateSelection();
421 SmSelectionDrawingVisitor(rDev, mpTree.get(), rPosition);
424 //Drawing using visitor
425 SmDrawingVisitor(rDev, rPosition, mpTree.get());
428 rDev.SetLayoutMode( nLayoutMode );
429 rDev.SetDigitLanguage( nDigitLang );
431 if (bRestoreDrawMode)
432 rDev.SetDrawMode( nOldDrawMode );
435 Size SmDocShell::GetSize()
437 Size aRet;
439 if (!mpTree)
440 Parse();
442 if (mpTree)
444 ArrangeFormula();
445 aRet = mpTree->GetSize();
447 if ( !aRet.Width() )
448 aRet.setWidth( 2000 );
449 else
450 aRet.AdjustWidth(maFormat.GetDistance( DIS_LEFTSPACE ) +
451 maFormat.GetDistance( DIS_RIGHTSPACE ) );
452 if ( !aRet.Height() )
453 aRet.setHeight( 1000 );
454 else
455 aRet.AdjustHeight(maFormat.GetDistance( DIS_TOPSPACE ) +
456 maFormat.GetDistance( DIS_BOTTOMSPACE ) );
459 return aRet;
462 void SmDocShell::InvalidateCursor(){
463 mpCursor.reset();
466 SmCursor& SmDocShell::GetCursor(){
467 if(!mpCursor)
468 mpCursor.reset(new SmCursor(mpTree.get(), this));
469 return *mpCursor;
472 bool SmDocShell::HasCursor() const { return mpCursor != nullptr; }
474 SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
476 pPrinter = rDocShell.GetPrt();
477 if ( pPrinter )
479 pPrinter->Push( PushFlags::MAPMODE );
480 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
482 // if it is an embedded object (without its own printer)
483 // we change the MapMode temporarily.
484 //!If it is a document with its own printer the MapMode should
485 //!be set correct (once) elsewhere(!), in order to avoid numerous
486 //!superfluous pushing and popping of the MapMode when using
487 //!this class.
489 const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
490 if ( MapUnit::Map100thMM != eOld )
492 MapMode aMap( pPrinter->GetMapMode() );
493 aMap.SetMapUnit( MapUnit::Map100thMM );
494 Point aTmp( aMap.GetOrigin() );
495 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM ) );
496 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM ) );
497 aMap.SetOrigin( aTmp );
498 pPrinter->SetMapMode( aMap );
502 pRefDev = rDocShell.GetRefDev();
503 if ( !pRefDev || pPrinter.get() == pRefDev.get() )
504 return;
506 pRefDev->Push( PushFlags::MAPMODE );
507 if ( SfxObjectCreateMode::EMBEDDED != rDocShell.GetCreateMode() )
508 return;
510 // if it is an embedded object (without its own printer)
511 // we change the MapMode temporarily.
512 //!If it is a document with its own printer the MapMode should
513 //!be set correct (once) elsewhere(!), in order to avoid numerous
514 //!superfluous pushing and popping of the MapMode when using
515 //!this class.
517 const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
518 if ( MapUnit::Map100thMM != eOld )
520 MapMode aMap( pRefDev->GetMapMode() );
521 aMap.SetMapUnit( MapUnit::Map100thMM );
522 Point aTmp( aMap.GetOrigin() );
523 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM ) );
524 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM ) );
525 aMap.SetOrigin( aTmp );
526 pRefDev->SetMapMode( aMap );
530 SmPrinterAccess::~SmPrinterAccess()
532 if ( pPrinter )
533 pPrinter->Pop();
534 if ( pRefDev && pRefDev != pPrinter )
535 pRefDev->Pop();
538 Printer* SmDocShell::GetPrt()
540 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
542 // Normally the server provides the printer. But if it doesn't provide one (e.g. because
543 // there is no connection) it still can be the case that we know the printer because it
544 // has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
545 Printer* pPrt = GetDocumentPrinter();
546 if (!pPrt && mpTmpPrinter)
547 pPrt = mpTmpPrinter;
548 return pPrt;
550 else if (!mpPrinter)
552 auto pOptions = std::make_unique<SfxItemSet>(
553 GetPool(),
554 svl::Items<
555 SID_PRINTTITLE, SID_PRINTZOOM,
556 SID_NO_RIGHT_SPACES, SID_SAVE_ONLY_USED_SYMBOLS,
557 SID_AUTO_CLOSE_BRACKETS, SID_AUTO_CLOSE_BRACKETS>{});
558 SmModule *pp = SM_MOD();
559 pp->GetConfig()->ConfigToItemSet(*pOptions);
560 mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pOptions));
561 mpPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
563 return mpPrinter;
566 OutputDevice* SmDocShell::GetRefDev()
568 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
570 OutputDevice* pOutDev = GetDocumentRefDev();
571 if (pOutDev)
572 return pOutDev;
575 return GetPrt();
578 void SmDocShell::SetPrinter( SfxPrinter *pNew )
580 mpPrinter.disposeAndClear();
581 mpPrinter = pNew; //Transfer ownership
582 mpPrinter->SetMapMode( MapMode(MapUnit::Map100thMM) );
583 SetFormulaArranged(false);
584 Repaint();
587 void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
589 mpTmpPrinter = pPrt;
590 SetFormulaArranged(false);
591 Size aOldSize = GetVisArea().GetSize();
592 Repaint();
593 if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
594 SetModified();
595 mpTmpPrinter = nullptr;
598 void SmDocShell::Repaint()
600 bool bIsEnabled = IsEnableSetModified();
601 if (bIsEnabled)
602 EnableSetModified( false );
604 SetFormulaArranged(false);
606 Size aVisSize = GetSize();
607 SetVisAreaSize(aVisSize);
608 SmViewShell* pViewSh = SmGetActiveView();
609 if (pViewSh)
610 pViewSh->GetGraphicWindow().Invalidate();
612 if (bIsEnabled)
613 EnableSetModified(bIsEnabled);
616 SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
617 : SfxObjectShell(i_nSfxCreationFlags)
618 , mpEditEngineItemPool(nullptr)
619 , mpPrinter(nullptr)
620 , mpTmpPrinter(nullptr)
621 , mnModifyCount(0)
622 , mbFormulaArranged(false)
624 SvtLinguConfig().GetOptions(maLinguOptions);
626 SetPool(&SfxGetpApp()->GetPool());
628 SmModule *pp = SM_MOD();
629 maFormat = pp->GetConfig()->GetStandardFormat();
631 StartListening(maFormat);
632 StartListening(*pp->GetConfig());
634 SetBaseModel(new SmModel(this));
637 SmDocShell::~SmDocShell()
639 SmModule *pp = SM_MOD();
641 EndListening(maFormat);
642 EndListening(*pp->GetConfig());
644 mpCursor.reset();
645 mpEditEngine.reset();
646 SfxItemPool::Free(mpEditEngineItemPool);
647 mpPrinter.disposeAndClear();
650 bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
652 bool bSuccess = false;
653 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
655 OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
657 if ( rFltName == MATHML_XML )
659 if (mpTree)
661 mpTree.reset();
662 InvalidateCursor();
664 Reference<css::frame::XModel> xModel(GetModel());
665 SmXMLImportWrapper aEquation(xModel);
666 bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
668 else
670 SvStream *pStream = rMedium.GetInStream();
671 if ( pStream )
673 if ( SotStorage::IsStorageFile( pStream ) )
675 tools::SvRef<SotStorage> aStorage = new SotStorage( pStream, false );
676 if ( aStorage->IsStream("Equation Native") )
678 // is this a MathType Storage?
679 OUStringBuffer aBuffer;
680 MathType aEquation(aBuffer);
681 bSuccess = aEquation.Parse( aStorage.get() );
682 if ( bSuccess )
684 maText = aBuffer.makeStringAndClear();
685 Parse();
692 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
694 SetFormulaArranged( false );
695 Repaint();
698 FinishedLoading();
699 return bSuccess;
703 bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
705 bool bRet = false;
706 if ( SfxObjectShell::InitNew( xStorage ) )
708 bRet = true;
709 SetVisArea(tools::Rectangle(Point(0, 0), Size(2000, 1000)));
711 return bRet;
715 bool SmDocShell::Load( SfxMedium& rMedium )
717 bool bRet = false;
718 if( SfxObjectShell::Load( rMedium ))
720 uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
721 if (xStorage->hasByName("content.xml") && xStorage->isStreamElement("content.xml"))
723 // is this a fabulous math package ?
724 Reference<css::frame::XModel> xModel(GetModel());
725 SmXMLImportWrapper aEquation(xModel);
726 auto nError = aEquation.Import(rMedium);
727 bRet = ERRCODE_NONE == nError;
728 SetError(nError);
732 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
734 SetFormulaArranged( false );
735 Repaint();
738 FinishedLoading();
739 return bRet;
743 bool SmDocShell::Save()
745 //! apply latest changes if necessary
746 UpdateText();
748 if ( SfxObjectShell::Save() )
750 if (!mpTree)
751 Parse();
752 if( mpTree )
753 ArrangeFormula();
755 Reference<css::frame::XModel> xModel(GetModel());
756 SmXMLExportWrapper aEquation(xModel);
757 aEquation.SetFlat(false);
758 return aEquation.Export(*GetMedium());
761 return false;
765 * replace bad characters that can not be saved. (#i74144)
766 * */
767 void SmDocShell::ReplaceBadChars()
769 bool bReplace = false;
771 if (!mpEditEngine)
772 return;
774 OUStringBuffer aBuf( mpEditEngine->GetText() );
776 for (sal_Int32 i = 0; i < aBuf.getLength(); ++i)
778 if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
780 aBuf[i] = ' ';
781 bReplace = true;
785 if (bReplace)
786 maText = aBuf.makeStringAndClear();
790 void SmDocShell::UpdateText()
792 if (mpEditEngine && mpEditEngine->IsModified())
794 OUString aEngTxt( mpEditEngine->GetText() );
795 if (GetText() != aEngTxt)
796 SetText( aEngTxt );
801 bool SmDocShell::SaveAs( SfxMedium& rMedium )
803 bool bRet = false;
805 //! apply latest changes if necessary
806 UpdateText();
808 if ( SfxObjectShell::SaveAs( rMedium ) )
810 if (!mpTree)
811 Parse();
812 if( mpTree )
813 ArrangeFormula();
815 Reference<css::frame::XModel> xModel(GetModel());
816 SmXMLExportWrapper aEquation(xModel);
817 aEquation.SetFlat(false);
818 bRet = aEquation.Export(rMedium);
820 return bRet;
823 bool SmDocShell::ConvertTo( SfxMedium &rMedium )
825 bool bRet = false;
826 std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
827 if( pFlt )
829 if( !mpTree )
830 Parse();
831 if( mpTree )
832 ArrangeFormula();
834 const OUString& rFltName = pFlt->GetFilterName();
835 if(rFltName == STAROFFICE_XML)
837 Reference<css::frame::XModel> xModel(GetModel());
838 SmXMLExportWrapper aEquation(xModel);
839 aEquation.SetFlat(false);
840 bRet = aEquation.Export(rMedium);
842 else if(rFltName == MATHML_XML)
844 Reference<css::frame::XModel> xModel(GetModel());
845 SmXMLExportWrapper aEquation(xModel);
846 aEquation.SetFlat(true);
847 bRet = aEquation.Export(rMedium);
849 else if (pFlt->GetFilterName() == "MathType 3.x")
850 bRet = WriteAsMathType3( rMedium );
852 return bRet;
855 void SmDocShell::writeFormulaOoxml(
856 ::sax_fastparser::FSHelperPtr const& pSerializer,
857 oox::core::OoxmlVersion const version,
858 oox::drawingml::DocumentType const documentType,
859 const sal_Int8 nAlign)
861 if( !mpTree )
862 Parse();
863 if( mpTree )
864 ArrangeFormula();
865 SmOoxmlExport aEquation(mpTree.get(), version, documentType);
866 if(documentType == oox::drawingml::DOCUMENT_DOCX)
867 aEquation.ConvertFromStarMath( pSerializer, nAlign);
868 else
869 aEquation.ConvertFromStarMath(pSerializer, oox::FormulaExportBase::eFormulaAlign::INLINE);
872 void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
874 if (!mpTree)
875 Parse();
876 if (mpTree)
877 ArrangeFormula();
878 SmRtfExport aEquation(mpTree.get());
879 aEquation.ConvertFromStarMath(rBuffer, nEncoding);
882 void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
884 SmOoxmlImport aEquation( stream );
885 SetText( aEquation.ConvertToStarMath());
888 void SmDocShell::Execute(SfxRequest& rReq)
890 switch (rReq.GetSlot())
892 case SID_TEXTMODE:
894 SmFormat aOldFormat = GetFormat();
895 SmFormat aNewFormat( aOldFormat );
896 aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
898 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
899 if (pTmpUndoMgr)
900 pTmpUndoMgr->AddUndoAction(
901 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
903 SetFormat( aNewFormat );
904 Repaint();
906 break;
908 case SID_AUTO_REDRAW :
910 SmModule *pp = SM_MOD();
911 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
912 pp->GetConfig()->SetAutoRedraw(!bRedraw);
914 break;
916 case SID_LOADSYMBOLS:
917 LoadSymbols();
918 break;
920 case SID_SAVESYMBOLS:
921 SaveSymbols();
922 break;
924 case SID_FONT:
926 // get device used to retrieve the FontList
927 OutputDevice *pDev = GetPrinter();
928 if (!pDev || pDev->GetDevFontCount() == 0)
929 pDev = &SM_MOD()->GetDefaultVirtualDev();
930 OSL_ENSURE (pDev, "device for font list missing" );
932 SmFontTypeDialog aFontTypeDialog(rReq.GetFrameWeld(), pDev);
934 SmFormat aOldFormat = GetFormat();
935 aFontTypeDialog.ReadFrom( aOldFormat );
936 if (aFontTypeDialog.run() == RET_OK)
938 SmFormat aNewFormat( aOldFormat );
940 aFontTypeDialog.WriteTo(aNewFormat);
941 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
942 if (pTmpUndoMgr)
943 pTmpUndoMgr->AddUndoAction(
944 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
946 SetFormat( aNewFormat );
947 Repaint();
950 break;
952 case SID_FONTSIZE:
954 SmFontSizeDialog aFontSizeDialog(rReq.GetFrameWeld());
956 SmFormat aOldFormat = GetFormat();
957 aFontSizeDialog.ReadFrom( aOldFormat );
958 if (aFontSizeDialog.run() == RET_OK)
960 SmFormat aNewFormat( aOldFormat );
962 aFontSizeDialog.WriteTo(aNewFormat);
964 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
965 if (pTmpUndoMgr)
966 pTmpUndoMgr->AddUndoAction(
967 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
969 SetFormat( aNewFormat );
970 Repaint();
973 break;
975 case SID_DISTANCE:
977 SmDistanceDialog aDistanceDialog(rReq.GetFrameWeld());
979 SmFormat aOldFormat = GetFormat();
980 aDistanceDialog.ReadFrom( aOldFormat );
981 if (aDistanceDialog.run() == RET_OK)
983 SmFormat aNewFormat( aOldFormat );
985 aDistanceDialog.WriteTo(aNewFormat);
987 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
988 if (pTmpUndoMgr)
989 pTmpUndoMgr->AddUndoAction(
990 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
992 SetFormat( aNewFormat );
993 Repaint();
996 break;
998 case SID_ALIGN:
1000 SmAlignDialog aAlignDialog(rReq.GetFrameWeld());
1002 SmFormat aOldFormat = GetFormat();
1003 aAlignDialog.ReadFrom( aOldFormat );
1004 if (aAlignDialog.run() == RET_OK)
1006 SmFormat aNewFormat( aOldFormat );
1008 aAlignDialog.WriteTo(aNewFormat);
1010 SmModule *pp = SM_MOD();
1011 SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
1012 aAlignDialog.WriteTo( aFmt );
1013 pp->GetConfig()->SetStandardFormat( aFmt );
1015 SfxUndoManager *pTmpUndoMgr = GetUndoManager();
1016 if (pTmpUndoMgr)
1017 pTmpUndoMgr->AddUndoAction(
1018 std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
1020 SetFormat( aNewFormat );
1021 Repaint();
1024 break;
1026 case SID_TEXT:
1028 const SfxStringItem& rItem = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_TEXT));
1029 if (GetText() != rItem.GetValue())
1030 SetText(rItem.GetValue());
1032 break;
1034 case SID_UNDO:
1035 case SID_REDO:
1037 SfxUndoManager* pTmpUndoMgr = GetUndoManager();
1038 if( pTmpUndoMgr )
1040 sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
1041 const SfxItemSet* pArgs = rReq.GetArgs();
1042 const SfxPoolItem* pItem;
1043 if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
1044 nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
1046 bool (SfxUndoManager::*fnDo)();
1048 size_t nCount;
1049 if( SID_UNDO == rReq.GetSlot() )
1051 nCount = pTmpUndoMgr->GetUndoActionCount();
1052 fnDo = &SfxUndoManager::Undo;
1054 else
1056 nCount = pTmpUndoMgr->GetRedoActionCount();
1057 fnDo = &SfxUndoManager::Redo;
1062 for( ; nCnt && nCount; --nCnt, --nCount )
1063 (pTmpUndoMgr->*fnDo)();
1065 catch( const Exception& )
1067 DBG_UNHANDLED_EXCEPTION("starmath");
1070 Repaint();
1071 UpdateText();
1072 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1073 while( pFrm )
1075 SfxBindings& rBind = pFrm->GetBindings();
1076 rBind.Invalidate(SID_UNDO);
1077 rBind.Invalidate(SID_REDO);
1078 rBind.Invalidate(SID_REPEAT);
1079 rBind.Invalidate(SID_CLEARHISTORY);
1080 pFrm = SfxViewFrame::GetNext( *pFrm, this );
1083 break;
1086 rReq.Done();
1090 void SmDocShell::GetState(SfxItemSet &rSet)
1092 SfxWhichIter aIter(rSet);
1094 for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
1096 switch (nWh)
1098 case SID_TEXTMODE:
1099 rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
1100 break;
1102 case SID_DOCTEMPLATE :
1103 rSet.DisableItem(SID_DOCTEMPLATE);
1104 break;
1106 case SID_AUTO_REDRAW :
1108 SmModule *pp = SM_MOD();
1109 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
1111 rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
1113 break;
1115 case SID_MODIFYSTATUS:
1117 sal_Unicode cMod = ' ';
1118 if (IsModified())
1119 cMod = '*';
1120 rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
1122 break;
1124 case SID_TEXT:
1125 rSet.Put(SfxStringItem(SID_TEXT, GetText()));
1126 break;
1128 case SID_GAPHIC_SM:
1129 //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWindow.
1130 //! If mnModifyCount gets changed then the call below will implicitly notify
1131 //! SmGraphicController::StateChanged and there the window gets invalidated.
1132 //! Thus all the 'mnModifyCount++' before invalidating this slot.
1133 rSet.Put(SfxInt16Item(SID_GAPHIC_SM, mnModifyCount));
1134 break;
1136 case SID_UNDO:
1137 case SID_REDO:
1139 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1140 if( pFrm )
1141 pFrm->GetSlotState( nWh, nullptr, &rSet );
1142 else
1143 rSet.DisableItem( nWh );
1145 break;
1147 case SID_GETUNDOSTRINGS:
1148 case SID_GETREDOSTRINGS:
1150 SfxUndoManager* pTmpUndoMgr = GetUndoManager();
1151 if( pTmpUndoMgr )
1153 OUString(SfxUndoManager::*fnGetComment)( size_t, bool const ) const;
1155 size_t nCount;
1156 if( SID_GETUNDOSTRINGS == nWh )
1158 nCount = pTmpUndoMgr->GetUndoActionCount();
1159 fnGetComment = &SfxUndoManager::GetUndoActionComment;
1161 else
1163 nCount = pTmpUndoMgr->GetRedoActionCount();
1164 fnGetComment = &SfxUndoManager::GetRedoActionComment;
1166 if (nCount)
1168 OUStringBuffer aBuf;
1169 for (size_t n = 0; n < nCount; ++n)
1171 aBuf.append((pTmpUndoMgr->*fnGetComment)( n, SfxUndoManager::TopLevel ));
1172 aBuf.append('\n');
1175 SfxStringListItem aItem( nWh );
1176 aItem.SetString( aBuf.makeStringAndClear() );
1177 rSet.Put( aItem );
1180 else
1181 rSet.DisableItem( nWh );
1183 break;
1189 SfxUndoManager *SmDocShell::GetUndoManager()
1191 if (!mpEditEngine)
1192 GetEditEngine();
1193 return &mpEditEngine->GetUndoManager();
1197 void SmDocShell::SaveSymbols()
1199 SmModule *pp = SM_MOD();
1200 pp->GetSymbolManager().Save();
1204 void SmDocShell::Draw(OutputDevice *pDevice,
1205 const JobSetup &,
1206 sal_uInt16 /*nAspect*/)
1208 pDevice->IntersectClipRegion(GetVisArea());
1209 Point atmppoint;
1210 DrawFormula(*pDevice, atmppoint);
1213 SfxItemPool& SmDocShell::GetPool()
1215 return SfxGetpApp()->GetPool();
1218 void SmDocShell::SetVisArea(const tools::Rectangle & rVisArea)
1220 tools::Rectangle aNewRect(rVisArea);
1222 aNewRect.SetPos(Point());
1224 if (aNewRect.IsWidthEmpty())
1225 aNewRect.SetRight( 2000 );
1226 if (aNewRect.IsHeightEmpty())
1227 aNewRect.SetBottom( 1000 );
1229 bool bIsEnabled = IsEnableSetModified();
1230 if ( bIsEnabled )
1231 EnableSetModified( false );
1233 //TODO/LATER: it's unclear how this interacts with the SFX code
1234 // If outplace editing, then don't resize the OutplaceWindow. But the
1235 // ObjectShell has to resize.
1236 bool bUnLockFrame;
1237 if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
1239 GetFrame()->LockAdjustPosSizePixel();
1240 bUnLockFrame = true;
1242 else
1243 bUnLockFrame = false;
1245 SfxObjectShell::SetVisArea( aNewRect );
1247 if( bUnLockFrame )
1248 GetFrame()->UnlockAdjustPosSizePixel();
1250 if ( bIsEnabled )
1251 EnableSetModified( bIsEnabled );
1255 void SmDocShell::FillClass(SvGlobalName* pClassName,
1256 SotClipboardFormatId* pFormat,
1257 OUString* pFullTypeName,
1258 sal_Int32 nFileFormat,
1259 bool bTemplate /* = false */) const
1261 if (nFileFormat == SOFFICE_FILEFORMAT_60 )
1263 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1264 *pFormat = SotClipboardFormatId::STARMATH_60;
1265 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1267 else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
1269 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1270 *pFormat = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
1271 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1275 void SmDocShell::SetModified(bool bModified)
1277 if( IsEnableSetModified() )
1279 SfxObjectShell::SetModified( bModified );
1280 Broadcast(SfxHint(SfxHintId::DocChanged));
1284 bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
1286 OUStringBuffer aTextAsBuffer(maText);
1287 MathType aEquation(aTextAsBuffer, mpTree.get());
1288 return aEquation.ConvertFromStarMath( rMedium );
1291 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */