Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / starmath / source / document.cxx
blob8668fa061e2fcd7f5758e509a47a15f3f7852a01
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 <o3tl/make_unique.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/ustring.hxx>
28 #include <unotools/eventcfg.hxx>
29 #include <sfx2/event.hxx>
30 #include <sfx2/app.hxx>
31 #include <sfx2/docfile.hxx>
32 #include <sfx2/docfilt.hxx>
33 #include <sfx2/msg.hxx>
34 #include <sfx2/objface.hxx>
35 #include <sfx2/printer.hxx>
36 #include <sfx2/request.hxx>
37 #include <sfx2/viewfrm.hxx>
38 #include <comphelper/classids.hxx>
39 #include <sot/formats.hxx>
40 #include <sot/storage.hxx>
41 #include <svl/eitem.hxx>
42 #include <svl/intitem.hxx>
43 #include <svl/itempool.hxx>
44 #include <svl/slstitm.hxx>
45 #include <svl/hint.hxx>
46 #include <svl/stritem.hxx>
47 #include <svl/undo.hxx>
48 #include <svl/whiter.hxx>
49 #include <editeng/editeng.hxx>
50 #include <editeng/editstat.hxx>
51 #include <editeng/eeitem.hxx>
52 #include <editeng/fhgtitem.hxx>
53 #include <editeng/fontitem.hxx>
54 #include <vcl/mapmod.hxx>
55 #include <tools/mapunit.hxx>
56 #include <vcl/settings.hxx>
58 #include <document.hxx>
59 #include <action.hxx>
60 #include <dialog.hxx>
61 #include <format.hxx>
62 #include <starmath.hrc>
63 #include <strings.hrc>
64 #include <symbol.hxx>
65 #include <unomodel.hxx>
66 #include <utility.hxx>
67 #include <view.hxx>
68 #include "mathtype.hxx"
69 #include "ooxmlexport.hxx"
70 #include "ooxmlimport.hxx"
71 #include "rtfexport.hxx"
72 #include "mathmlimport.hxx"
73 #include "mathmlexport.hxx"
74 #include <svx/svxids.hrc>
75 #include <cursor.hxx>
76 #include <tools/diagnose_ex.h>
77 #include <visitors.hxx>
78 #include "accessibility.hxx"
79 #include "cfgitem.hxx"
80 #include <memory>
81 #include <utility>
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::accessibility;
85 using namespace ::com::sun::star::uno;
87 #define ShellClass_SmDocShell
88 #include <smslots.hxx>
91 SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
93 void SmDocShell::InitInterface_Impl()
95 GetStaticInterface()->RegisterPopupMenu("view");
98 SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), SfxObjectShellFlags::STD_NORMAL, "smath" )
100 void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
102 if (rHint.GetId() == SfxHintId::MathFormatChanged)
104 SetFormulaArranged(false);
106 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
108 Repaint();
112 void SmDocShell::LoadSymbols()
114 SmModule *pp = SM_MOD();
115 pp->GetSymbolManager().Load();
119 const OUString SmDocShell::GetComment() const
121 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
122 GetModel(), uno::UNO_QUERY_THROW);
123 uno::Reference<document::XDocumentProperties> xDocProps(
124 xDPS->getDocumentProperties());
125 return xDocProps->getDescription();
129 void SmDocShell::SetText(const OUString& rBuffer)
131 if (rBuffer != maText)
133 bool bIsEnabled = IsEnableSetModified();
134 if( bIsEnabled )
135 EnableSetModified( false );
137 maText = rBuffer;
138 SetFormulaArranged( false );
140 Parse();
142 SmViewShell *pViewSh = SmGetActiveView();
143 if( pViewSh )
145 pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_TEXT);
146 if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
148 // have SwOleClient::FormatChanged() to align the modified formula properly
149 // even if the visible area does not change (e.g. when formula text changes from
150 // "{a over b + c} over d" to "d over {a over b + c}"
151 SfxGetpApp()->NotifyEvent(SfxEventHint( SfxEventHintId::VisAreaChanged, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
153 Repaint();
155 else
156 pViewSh->GetGraphicWindow().Invalidate();
159 if ( bIsEnabled )
160 EnableSetModified( bIsEnabled );
161 SetModified();
163 // launch accessible event if necessary
164 SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWindow().GetAccessible_Impl() : nullptr;
165 if (pAcc)
167 Any aOldValue, aNewValue;
168 if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
170 pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
171 aOldValue, aNewValue );
175 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
176 OnDocumentPrinterChanged(nullptr);
180 void SmDocShell::SetFormat(SmFormat const & rFormat)
182 maFormat = rFormat;
183 SetFormulaArranged( false );
184 SetModified();
186 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
188 // don't use SmGetActiveView since the view shell might not be active (0 pointer)
189 // if for example the Basic Macro dialog currently has the focus. Thus:
190 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
191 while (pFrm)
193 pFrm->GetBindings().Invalidate(SID_GAPHIC_SM);
194 pFrm = SfxViewFrame::GetNext( *pFrm, this );
198 OUString const & SmDocShell::GetAccessibleText()
200 ArrangeFormula();
201 if (maAccText.isEmpty())
203 OSL_ENSURE( mpTree, "Tree missing" );
204 if (mpTree)
206 OUStringBuffer aBuf;
207 mpTree->GetAccessibleText(aBuf);
208 maAccText = aBuf.makeStringAndClear();
211 return maAccText;
214 void SmDocShell::Parse()
216 mpTree.reset();
217 ReplaceBadChars();
218 mpTree = maParser.Parse(maText);
219 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
220 SetFormulaArranged( false );
221 InvalidateCursor();
222 maUsedSymbols = maParser.GetUsedSymbols();
226 void SmDocShell::ArrangeFormula()
228 if (mbFormulaArranged)
229 return;
231 // Only for the duration of the existence of this object the correct settings
232 // at the printer are guaranteed!
233 SmPrinterAccess aPrtAcc(*this);
234 OutputDevice* pOutDev = aPrtAcc.GetRefDev();
236 SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
238 // if necessary get another OutputDevice for which we format
239 if (!pOutDev)
241 SmViewShell *pView = SmGetActiveView();
242 if (pView)
243 pOutDev = &pView->GetGraphicWindow();
244 else
246 pOutDev = &SM_MOD()->GetDefaultVirtualDev();
247 pOutDev->SetMapMode( MapMode(MapUnit::Map100thMM) );
250 OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM,
251 "Sm : wrong MapMode");
253 const SmFormat &rFormat = GetFormat();
254 mpTree->Prepare(rFormat, *this, 0);
256 // format/draw formulas always from left to right,
257 // and numbers should not be converted
258 ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode();
259 pOutDev->SetLayoutMode( ComplexTextLayoutFlags::Default );
260 LanguageType nDigitLang = pOutDev->GetDigitLanguage();
261 pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
263 mpTree->Arrange(*pOutDev, rFormat);
265 pOutDev->SetLayoutMode( nLayoutMode );
266 pOutDev->SetDigitLanguage( nDigitLang );
268 SetFormulaArranged(true);
270 // invalidate accessible text
271 maAccText.clear();
274 void SetEditEngineDefaultFonts(SfxItemPool &rEditEngineItemPool, const SvtLinguOptions &rOpt)
276 // set fonts to be used
277 struct FontDta {
278 LanguageType nFallbackLang;
279 LanguageType nLang;
280 DefaultFontType nFontType;
281 sal_uInt16 nFontInfoId;
282 } aTable[3] =
284 // info to get western font to be used
285 { LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
286 DefaultFontType::FIXED, EE_CHAR_FONTINFO },
287 // info to get CJK font to be used
288 { LANGUAGE_JAPANESE, LANGUAGE_NONE,
289 DefaultFontType::CJK_TEXT, EE_CHAR_FONTINFO_CJK },
290 // info to get CTL font to be used
291 { LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
292 DefaultFontType::CTL_TEXT, EE_CHAR_FONTINFO_CTL }
294 aTable[0].nLang = rOpt.nDefaultLanguage;
295 aTable[1].nLang = rOpt.nDefaultLanguage_CJK;
296 aTable[2].nLang = rOpt.nDefaultLanguage_CTL;
298 for (FontDta & rFntDta : aTable)
300 LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
301 rFntDta.nFallbackLang : rFntDta.nLang;
302 vcl::Font aFont = OutputDevice::GetDefaultFont(
303 rFntDta.nFontType, nLang, GetDefaultFontFlags::OnlyOne );
304 rEditEngineItemPool.SetPoolDefaultItem(
305 SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
306 aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(),
307 rFntDta.nFontInfoId ) );
310 // set font heights
311 SvxFontHeightItem aFontHeigt(
312 Application::GetDefaultDevice()->LogicToPixel(
313 Size( 0, 11 ), MapMode( MapUnit::MapPoint ) ).Height(), 100,
314 EE_CHAR_FONTHEIGHT );
315 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
316 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CJK );
317 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
318 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CTL );
319 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
322 EditEngine& SmDocShell::GetEditEngine()
324 if (!mpEditEngine)
327 //! see also SmEditWindow::DataChanged !
330 mpEditEngineItemPool = EditEngine::CreatePool();
332 SetEditEngineDefaultFonts(*mpEditEngineItemPool, maLinguOptions);
334 mpEditEngine.reset( new EditEngine( mpEditEngineItemPool ) );
336 mpEditEngine->SetAddExtLeading(true);
338 mpEditEngine->EnableUndo( true );
339 mpEditEngine->SetDefTab( sal_uInt16(
340 Application::GetDefaultDevice()->GetTextWidth("XXXX")) );
342 mpEditEngine->SetControlWord(
343 (mpEditEngine->GetControlWord() | EEControlBits::AUTOINDENTING) &
344 EEControlBits(~EEControlBits::UNDOATTRIBS) &
345 EEControlBits(~EEControlBits::PASTESPECIAL) );
347 mpEditEngine->SetWordDelimiters(" .=+-*/(){}[];\"");
348 mpEditEngine->SetRefMapMode(MapMode(MapUnit::MapPixel));
350 mpEditEngine->SetPaperSize( Size( 800, 0 ) );
352 mpEditEngine->EraseVirtualDevice();
354 // set initial text if the document already has some...
355 // (may be the case when reloading a doc)
356 OUString aTxt( GetText() );
357 if (!aTxt.isEmpty())
358 mpEditEngine->SetText( aTxt );
360 mpEditEngine->ClearModifyFlag();
363 return *mpEditEngine;
367 SfxItemPool& SmDocShell::GetEditEngineItemPool()
369 if (!mpEditEngineItemPool)
370 GetEditEngine();
371 assert(mpEditEngineItemPool && "EditEngineItemPool missing");
372 return *mpEditEngineItemPool;
375 void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
377 if (!mpTree)
378 Parse();
379 OSL_ENSURE(mpTree, "Sm : NULL pointer");
381 ArrangeFormula();
383 // Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
384 // device and aren't aligned to that either. So now there can be a difference between the
385 // VisArea (i.e. the size within the client) and the current size.
386 // Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
388 rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
389 rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE ) );
391 //! in case of high contrast-mode (accessibility option!)
392 //! the draw mode needs to be set to default, because when imbedding
393 //! Math for example in Calc in "a over b" the fraction bar may not
394 //! be visible else. More generally: the FillColor may have been changed.
395 DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
396 bool bRestoreDrawMode = false;
397 if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
398 static_cast<vcl::Window &>(rDev).GetSettings().GetStyleSettings().GetHighContrastMode())
400 nOldDrawMode = rDev.GetDrawMode();
401 rDev.SetDrawMode( DrawModeFlags::Default );
402 bRestoreDrawMode = true;
405 // format/draw formulas always from left to right
406 // and numbers should not be converted
407 ComplexTextLayoutFlags nLayoutMode = rDev.GetLayoutMode();
408 rDev.SetLayoutMode( ComplexTextLayoutFlags::Default );
409 LanguageType nDigitLang = rDev.GetDigitLanguage();
410 rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
412 //Set selection if any
413 if(mpCursor && bDrawSelection){
414 mpCursor->AnnotateSelection();
415 SmSelectionDrawingVisitor(rDev, mpTree.get(), rPosition);
418 //Drawing using visitor
419 SmDrawingVisitor(rDev, rPosition, mpTree.get());
422 rDev.SetLayoutMode( nLayoutMode );
423 rDev.SetDigitLanguage( nDigitLang );
425 if (bRestoreDrawMode)
426 rDev.SetDrawMode( nOldDrawMode );
429 Size SmDocShell::GetSize()
431 Size aRet;
433 if (!mpTree)
434 Parse();
436 if (mpTree)
438 ArrangeFormula();
439 aRet = mpTree->GetSize();
441 if ( !aRet.Width() )
442 aRet.setWidth( 2000 );
443 else
444 aRet.AdjustWidth(maFormat.GetDistance( DIS_LEFTSPACE ) +
445 maFormat.GetDistance( DIS_RIGHTSPACE ) );
446 if ( !aRet.Height() )
447 aRet.setHeight( 1000 );
448 else
449 aRet.AdjustHeight(maFormat.GetDistance( DIS_TOPSPACE ) +
450 maFormat.GetDistance( DIS_BOTTOMSPACE ) );
453 return aRet;
456 void SmDocShell::InvalidateCursor(){
457 mpCursor.reset();
460 SmCursor& SmDocShell::GetCursor(){
461 if(!mpCursor)
462 mpCursor.reset(new SmCursor(mpTree.get(), this));
463 return *mpCursor;
466 bool SmDocShell::HasCursor()
468 return mpCursor.get() != nullptr;
471 SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
473 pPrinter = rDocShell.GetPrt();
474 if ( pPrinter )
476 pPrinter->Push( PushFlags::MAPMODE );
477 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
479 // if it is an embedded object (without its own printer)
480 // we change the MapMode temporarily.
481 //!If it is a document with its own printer the MapMode should
482 //!be set correct (once) elsewhere(!), in order to avoid numerous
483 //!superfluous pushing and popping of the MapMode when using
484 //!this class.
486 const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
487 if ( MapUnit::Map100thMM != eOld )
489 MapMode aMap( pPrinter->GetMapMode() );
490 aMap.SetMapUnit( MapUnit::Map100thMM );
491 Point aTmp( aMap.GetOrigin() );
492 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM ) );
493 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM ) );
494 aMap.SetOrigin( aTmp );
495 pPrinter->SetMapMode( aMap );
499 if ( (pRefDev = rDocShell.GetRefDev()) && pPrinter.get() != pRefDev.get() )
501 pRefDev->Push( PushFlags::MAPMODE );
502 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
504 // if it is an embedded object (without its own printer)
505 // we change the MapMode temporarily.
506 //!If it is a document with its own printer the MapMode should
507 //!be set correct (once) elsewhere(!), in order to avoid numerous
508 //!superfluous pushing and popping of the MapMode when using
509 //!this class.
511 const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
512 if ( MapUnit::Map100thMM != eOld )
514 MapMode aMap( pRefDev->GetMapMode() );
515 aMap.SetMapUnit( MapUnit::Map100thMM );
516 Point aTmp( aMap.GetOrigin() );
517 aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM ) );
518 aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM ) );
519 aMap.SetOrigin( aTmp );
520 pRefDev->SetMapMode( aMap );
526 SmPrinterAccess::~SmPrinterAccess()
528 if ( pPrinter )
529 pPrinter->Pop();
530 if ( pRefDev && pRefDev != pPrinter )
531 pRefDev->Pop();
534 Printer* SmDocShell::GetPrt()
536 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
538 // Normally the server provides the printer. But if it doesn't provide one (e.g. because
539 // there is no connection) it still can be the case that we know the printer because it
540 // has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
541 Printer* pPrt = GetDocumentPrinter();
542 if (!pPrt && mpTmpPrinter)
543 pPrt = mpTmpPrinter;
544 return pPrt;
546 else if (!mpPrinter)
548 auto pOptions = o3tl::make_unique<SfxItemSet>(
549 GetPool(),
550 svl::Items<
551 SID_PRINTTITLE, SID_PRINTZOOM,
552 SID_NO_RIGHT_SPACES, SID_SAVE_ONLY_USED_SYMBOLS,
553 SID_AUTO_CLOSE_BRACKETS, SID_AUTO_CLOSE_BRACKETS>{});
554 SmModule *pp = SM_MOD();
555 pp->GetConfig()->ConfigToItemSet(*pOptions);
556 mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pOptions));
557 mpPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
559 return mpPrinter;
562 OutputDevice* SmDocShell::GetRefDev()
564 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
566 OutputDevice* pOutDev = GetDocumentRefDev();
567 if (pOutDev)
568 return pOutDev;
571 return GetPrt();
574 void SmDocShell::SetPrinter( SfxPrinter *pNew )
576 mpPrinter.disposeAndClear();
577 mpPrinter = pNew; //Transfer ownership
578 mpPrinter->SetMapMode( MapMode(MapUnit::Map100thMM) );
579 SetFormulaArranged(false);
580 Repaint();
583 void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
585 mpTmpPrinter = pPrt;
586 SetFormulaArranged(false);
587 Size aOldSize = GetVisArea().GetSize();
588 Repaint();
589 if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
590 SetModified();
591 mpTmpPrinter = nullptr;
594 void SmDocShell::Repaint()
596 bool bIsEnabled = IsEnableSetModified();
597 if (bIsEnabled)
598 EnableSetModified( false );
600 SetFormulaArranged(false);
602 Size aVisSize = GetSize();
603 SetVisAreaSize(aVisSize);
604 SmViewShell* pViewSh = SmGetActiveView();
605 if (pViewSh)
606 pViewSh->GetGraphicWindow().Invalidate();
608 if (bIsEnabled)
609 EnableSetModified(bIsEnabled);
612 SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
613 : SfxObjectShell(i_nSfxCreationFlags)
614 , mpEditEngineItemPool(nullptr)
615 , mpEditEngine(nullptr)
616 , mpPrinter(nullptr)
617 , mpTmpPrinter(nullptr)
618 , mnModifyCount(0)
619 , mbFormulaArranged(false)
621 SvtLinguConfig().GetOptions(maLinguOptions);
623 SetPool(&SfxGetpApp()->GetPool());
625 SmModule *pp = SM_MOD();
626 maFormat = pp->GetConfig()->GetStandardFormat();
628 StartListening(maFormat);
629 StartListening(*pp->GetConfig());
631 SetBaseModel(new SmModel(this));
634 SmDocShell::~SmDocShell()
636 SmModule *pp = SM_MOD();
638 EndListening(maFormat);
639 EndListening(*pp->GetConfig());
641 mpCursor.reset();
642 mpEditEngine.reset();
643 SfxItemPool::Free(mpEditEngineItemPool);
644 mpPrinter.disposeAndClear();
647 bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
649 bool bSuccess = false;
650 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
652 OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
654 if ( rFltName == MATHML_XML )
656 if (mpTree)
658 mpTree.reset();
659 InvalidateCursor();
661 Reference<css::frame::XModel> xModel(GetModel());
662 SmXMLImportWrapper aEquation(xModel);
663 bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
665 else
667 SvStream *pStream = rMedium.GetInStream();
668 if ( pStream )
670 if ( SotStorage::IsStorageFile( pStream ) )
672 tools::SvRef<SotStorage> aStorage = new SotStorage( pStream, false );
673 if ( aStorage->IsStream("Equation Native") )
675 // is this a MathType Storage?
676 OUStringBuffer aBuffer;
677 MathType aEquation(aBuffer);
678 bSuccess = aEquation.Parse( aStorage.get() );
679 if ( bSuccess )
681 maText = aBuffer.makeStringAndClear();
682 Parse();
689 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
691 SetFormulaArranged( false );
692 Repaint();
695 FinishedLoading();
696 return bSuccess;
700 bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
702 bool bRet = false;
703 if ( SfxObjectShell::InitNew( xStorage ) )
705 bRet = true;
706 SetVisArea(tools::Rectangle(Point(0, 0), Size(2000, 1000)));
708 return bRet;
712 bool SmDocShell::Load( SfxMedium& rMedium )
714 bool bRet = false;
715 if( SfxObjectShell::Load( rMedium ))
717 uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
718 uno::Reference < container::XNameAccess > xAccess (xStorage, uno::UNO_QUERY);
719 if (
721 xAccess->hasByName( "content.xml" ) &&
722 xStorage->isStreamElement( "content.xml" )
723 ) ||
725 xAccess->hasByName( "Content.xml" ) &&
726 xStorage->isStreamElement( "Content.xml" )
730 // is this a fabulous math package ?
731 Reference<css::frame::XModel> xModel(GetModel());
732 SmXMLImportWrapper aEquation(xModel);
733 auto nError = aEquation.Import(rMedium);
734 bRet = ERRCODE_NONE == nError;
735 SetError(nError);
739 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
741 SetFormulaArranged( false );
742 Repaint();
745 FinishedLoading();
746 return bRet;
750 bool SmDocShell::Save()
752 //! apply latest changes if necessary
753 UpdateText();
755 if ( SfxObjectShell::Save() )
757 if (!mpTree)
758 Parse();
759 if( mpTree )
760 ArrangeFormula();
762 Reference<css::frame::XModel> xModel(GetModel());
763 SmXMLExportWrapper aEquation(xModel);
764 aEquation.SetFlat(false);
765 return aEquation.Export(*GetMedium());
768 return false;
772 * replace bad characters that can not be saved. (#i74144)
773 * */
774 void SmDocShell::ReplaceBadChars()
776 bool bReplace = false;
778 if (mpEditEngine)
780 OUStringBuffer aBuf( mpEditEngine->GetText() );
782 for (sal_Int32 i = 0; i < aBuf.getLength(); ++i)
784 if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
786 aBuf[i] = ' ';
787 bReplace = true;
791 if (bReplace)
792 maText = aBuf.makeStringAndClear();
797 void SmDocShell::UpdateText()
799 if (mpEditEngine && mpEditEngine->IsModified())
801 OUString aEngTxt( mpEditEngine->GetText() );
802 if (GetText() != aEngTxt)
803 SetText( aEngTxt );
808 bool SmDocShell::SaveAs( SfxMedium& rMedium )
810 bool bRet = false;
812 //! apply latest changes if necessary
813 UpdateText();
815 if ( SfxObjectShell::SaveAs( rMedium ) )
817 if (!mpTree)
818 Parse();
819 if( mpTree )
820 ArrangeFormula();
822 Reference<css::frame::XModel> xModel(GetModel());
823 SmXMLExportWrapper aEquation(xModel);
824 aEquation.SetFlat(false);
825 bRet = aEquation.Export(rMedium);
827 return bRet;
830 bool SmDocShell::ConvertTo( SfxMedium &rMedium )
832 bool bRet = false;
833 std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
834 if( pFlt )
836 if( !mpTree )
837 Parse();
838 if( mpTree )
839 ArrangeFormula();
841 const OUString& rFltName = pFlt->GetFilterName();
842 if(rFltName == STAROFFICE_XML)
844 Reference<css::frame::XModel> xModel(GetModel());
845 SmXMLExportWrapper aEquation(xModel);
846 aEquation.SetFlat(false);
847 bRet = aEquation.Export(rMedium);
849 else if(rFltName == MATHML_XML)
851 Reference<css::frame::XModel> xModel(GetModel());
852 SmXMLExportWrapper aEquation(xModel);
853 aEquation.SetFlat(true);
854 bRet = aEquation.Export(rMedium);
856 else if (pFlt->GetFilterName() == "MathType 3.x")
857 bRet = WriteAsMathType3( rMedium );
859 return bRet;
862 void SmDocShell::writeFormulaOoxml(
863 ::sax_fastparser::FSHelperPtr const& pSerializer,
864 oox::core::OoxmlVersion const version,
865 oox::drawingml::DocumentType const documentType)
867 if( !mpTree )
868 Parse();
869 if( mpTree )
870 ArrangeFormula();
871 SmOoxmlExport aEquation(mpTree.get(), version, documentType);
872 aEquation.ConvertFromStarMath( pSerializer );
875 void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
877 if (!mpTree)
878 Parse();
879 if (mpTree)
880 ArrangeFormula();
881 SmRtfExport aEquation(mpTree.get());
882 aEquation.ConvertFromStarMath(rBuffer, nEncoding);
885 void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
887 SmOoxmlImport aEquation( stream );
888 SetText( aEquation.ConvertToStarMath());
891 void SmDocShell::Execute(SfxRequest& rReq)
893 switch (rReq.GetSlot())
895 case SID_TEXTMODE:
897 SmFormat aOldFormat = GetFormat();
898 SmFormat aNewFormat( aOldFormat );
899 aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
901 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
902 if (pTmpUndoMgr)
903 pTmpUndoMgr->AddUndoAction(
904 new SmFormatAction(this, aOldFormat, aNewFormat));
906 SetFormat( aNewFormat );
907 Repaint();
909 break;
911 case SID_AUTO_REDRAW :
913 SmModule *pp = SM_MOD();
914 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
915 pp->GetConfig()->SetAutoRedraw(!bRedraw);
917 break;
919 case SID_LOADSYMBOLS:
920 LoadSymbols();
921 break;
923 case SID_SAVESYMBOLS:
924 SaveSymbols();
925 break;
927 case SID_FONT:
929 // get device used to retrieve the FontList
930 OutputDevice *pDev = GetPrinter();
931 if (!pDev || pDev->GetDevFontCount() == 0)
932 pDev = &SM_MOD()->GetDefaultVirtualDev();
933 OSL_ENSURE (pDev, "device for font list missing" );
935 SmFontTypeDialog aFontTypeDialog(rReq.GetFrameWeld(), pDev);
937 SmFormat aOldFormat = GetFormat();
938 aFontTypeDialog.ReadFrom( aOldFormat );
939 if (aFontTypeDialog.run() == RET_OK)
941 SmFormat aNewFormat( aOldFormat );
943 aFontTypeDialog.WriteTo(aNewFormat);
944 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
945 if (pTmpUndoMgr)
946 pTmpUndoMgr->AddUndoAction(
947 new SmFormatAction(this, aOldFormat, aNewFormat));
949 SetFormat( aNewFormat );
950 Repaint();
953 break;
955 case SID_FONTSIZE:
957 SmFontSizeDialog aFontSizeDialog(rReq.GetFrameWeld());
959 SmFormat aOldFormat = GetFormat();
960 aFontSizeDialog.ReadFrom( aOldFormat );
961 if (aFontSizeDialog.run() == RET_OK)
963 SmFormat aNewFormat( aOldFormat );
965 aFontSizeDialog.WriteTo(aNewFormat);
967 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
968 if (pTmpUndoMgr)
969 pTmpUndoMgr->AddUndoAction(
970 new SmFormatAction(this, aOldFormat, aNewFormat));
972 SetFormat( aNewFormat );
973 Repaint();
976 break;
978 case SID_DISTANCE:
980 SmDistanceDialog aDistanceDialog(rReq.GetFrameWeld());
982 SmFormat aOldFormat = GetFormat();
983 aDistanceDialog.ReadFrom( aOldFormat );
984 if (aDistanceDialog.run() == RET_OK)
986 SmFormat aNewFormat( aOldFormat );
988 aDistanceDialog.WriteTo(aNewFormat);
990 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
991 if (pTmpUndoMgr)
992 pTmpUndoMgr->AddUndoAction(
993 new SmFormatAction(this, aOldFormat, aNewFormat));
995 SetFormat( aNewFormat );
996 Repaint();
999 break;
1001 case SID_ALIGN:
1003 SmAlignDialog aAlignDialog(rReq.GetFrameWeld());
1005 SmFormat aOldFormat = GetFormat();
1006 aAlignDialog.ReadFrom( aOldFormat );
1007 if (aAlignDialog.run() == RET_OK)
1009 SmFormat aNewFormat( aOldFormat );
1011 aAlignDialog.WriteTo(aNewFormat);
1013 SmModule *pp = SM_MOD();
1014 SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
1015 aAlignDialog.WriteTo( aFmt );
1016 pp->GetConfig()->SetStandardFormat( aFmt );
1018 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
1019 if (pTmpUndoMgr)
1020 pTmpUndoMgr->AddUndoAction(
1021 new SmFormatAction(this, aOldFormat, aNewFormat));
1023 SetFormat( aNewFormat );
1024 Repaint();
1027 break;
1029 case SID_TEXT:
1031 const SfxStringItem& rItem = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_TEXT));
1032 if (GetText() != rItem.GetValue())
1033 SetText(rItem.GetValue());
1035 break;
1037 case SID_UNDO:
1038 case SID_REDO:
1040 ::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
1041 if( pTmpUndoMgr )
1043 sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
1044 const SfxItemSet* pArgs = rReq.GetArgs();
1045 const SfxPoolItem* pItem;
1046 if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
1047 nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
1049 bool (::svl::IUndoManager:: *fnDo)();
1051 size_t nCount;
1052 if( SID_UNDO == rReq.GetSlot() )
1054 nCount = pTmpUndoMgr->GetUndoActionCount();
1055 fnDo = &::svl::IUndoManager::Undo;
1057 else
1059 nCount = pTmpUndoMgr->GetRedoActionCount();
1060 fnDo = &::svl::IUndoManager::Redo;
1065 for( ; nCnt && nCount; --nCnt, --nCount )
1066 (pTmpUndoMgr->*fnDo)();
1068 catch( const Exception& )
1070 DBG_UNHANDLED_EXCEPTION("starmath");
1073 Repaint();
1074 UpdateText();
1075 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1076 while( pFrm )
1078 SfxBindings& rBind = pFrm->GetBindings();
1079 rBind.Invalidate(SID_UNDO);
1080 rBind.Invalidate(SID_REDO);
1081 rBind.Invalidate(SID_REPEAT);
1082 rBind.Invalidate(SID_CLEARHISTORY);
1083 pFrm = SfxViewFrame::GetNext( *pFrm, this );
1086 break;
1089 rReq.Done();
1093 void SmDocShell::GetState(SfxItemSet &rSet)
1095 SfxWhichIter aIter(rSet);
1097 for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
1099 switch (nWh)
1101 case SID_TEXTMODE:
1102 rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
1103 break;
1105 case SID_DOCTEMPLATE :
1106 rSet.DisableItem(SID_DOCTEMPLATE);
1107 break;
1109 case SID_AUTO_REDRAW :
1111 SmModule *pp = SM_MOD();
1112 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
1114 rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
1116 break;
1118 case SID_MODIFYSTATUS:
1120 sal_Unicode cMod = ' ';
1121 if (IsModified())
1122 cMod = '*';
1123 rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
1125 break;
1127 case SID_TEXT:
1128 rSet.Put(SfxStringItem(SID_TEXT, GetText()));
1129 break;
1131 case SID_GAPHIC_SM:
1132 //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWindow.
1133 //! If mnModifyCount gets changed then the call below will implicitly notify
1134 //! SmGraphicController::StateChanged and there the window gets invalidated.
1135 //! Thus all the 'mnModifyCount++' before invalidating this slot.
1136 rSet.Put(SfxInt16Item(SID_GAPHIC_SM, mnModifyCount));
1137 break;
1139 case SID_UNDO:
1140 case SID_REDO:
1142 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1143 if( pFrm )
1144 pFrm->GetSlotState( nWh, nullptr, &rSet );
1145 else
1146 rSet.DisableItem( nWh );
1148 break;
1150 case SID_GETUNDOSTRINGS:
1151 case SID_GETREDOSTRINGS:
1153 ::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
1154 if( pTmpUndoMgr )
1156 OUString(::svl::IUndoManager:: *fnGetComment)( size_t, bool const ) const;
1158 size_t nCount;
1159 if( SID_GETUNDOSTRINGS == nWh )
1161 nCount = pTmpUndoMgr->GetUndoActionCount();
1162 fnGetComment = &::svl::IUndoManager::GetUndoActionComment;
1164 else
1166 nCount = pTmpUndoMgr->GetRedoActionCount();
1167 fnGetComment = &::svl::IUndoManager::GetRedoActionComment;
1169 if (nCount)
1171 OUStringBuffer aBuf;
1172 for (size_t n = 0; n < nCount; ++n)
1174 aBuf.append((pTmpUndoMgr->*fnGetComment)( n, ::svl::IUndoManager::TopLevel ));
1175 aBuf.append('\n');
1178 SfxStringListItem aItem( nWh );
1179 aItem.SetString( aBuf.makeStringAndClear() );
1180 rSet.Put( aItem );
1183 else
1184 rSet.DisableItem( nWh );
1186 break;
1192 ::svl::IUndoManager *SmDocShell::GetUndoManager()
1194 if (!mpEditEngine)
1195 GetEditEngine();
1196 return &mpEditEngine->GetUndoManager();
1200 void SmDocShell::SaveSymbols()
1202 SmModule *pp = SM_MOD();
1203 pp->GetSymbolManager().Save();
1207 void SmDocShell::Draw(OutputDevice *pDevice,
1208 const JobSetup &,
1209 sal_uInt16 /*nAspect*/)
1211 pDevice->IntersectClipRegion(GetVisArea());
1212 Point atmppoint;
1213 DrawFormula(*pDevice, atmppoint);
1216 SfxItemPool& SmDocShell::GetPool()
1218 return SfxGetpApp()->GetPool();
1221 void SmDocShell::SetVisArea(const tools::Rectangle & rVisArea)
1223 tools::Rectangle aNewRect(rVisArea);
1225 aNewRect.SetPos(Point());
1227 if (! aNewRect.Right()) aNewRect.SetRight( 2000 );
1228 if (! aNewRect.Bottom()) aNewRect.SetBottom( 1000 );
1230 bool bIsEnabled = IsEnableSetModified();
1231 if ( bIsEnabled )
1232 EnableSetModified( false );
1234 //TODO/LATER: it's unclear how this interacts with the SFX code
1235 // If outplace editing, then don't resize the OutplaceWindow. But the
1236 // ObjectShell has to resize.
1237 bool bUnLockFrame;
1238 if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
1240 GetFrame()->LockAdjustPosSizePixel();
1241 bUnLockFrame = true;
1243 else
1244 bUnLockFrame = false;
1246 SfxObjectShell::SetVisArea( aNewRect );
1248 if( bUnLockFrame )
1249 GetFrame()->UnlockAdjustPosSizePixel();
1251 if ( bIsEnabled )
1252 EnableSetModified( bIsEnabled );
1256 void SmDocShell::FillClass(SvGlobalName* pClassName,
1257 SotClipboardFormatId* pFormat,
1258 OUString* /*pAppName*/,
1259 OUString* pFullTypeName,
1260 OUString* pShortTypeName,
1261 sal_Int32 nFileFormat,
1262 bool bTemplate /* = false */) const
1264 if (nFileFormat == SOFFICE_FILEFORMAT_60 )
1266 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1267 *pFormat = SotClipboardFormatId::STARMATH_60;
1268 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1269 *pShortTypeName = SmResId(RID_DOCUMENTSTR);
1271 else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
1273 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1274 *pFormat = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
1275 *pFullTypeName = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1276 *pShortTypeName = SmResId(RID_DOCUMENTSTR);
1280 void SmDocShell::SetModified(bool bModified)
1282 if( IsEnableSetModified() )
1284 SfxObjectShell::SetModified( bModified );
1285 Broadcast(SfxHint(SfxHintId::DocChanged));
1289 bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
1291 OUStringBuffer aTextAsBuffer(maText);
1292 MathType aEquation(aTextAsBuffer, mpTree.get());
1293 return aEquation.ConvertFromStarMath( rMedium );
1296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */