cURL: follow redirects
[LibreOffice.git] / starmath / source / document.cxx
blob142bc78f9f2817ac70fd093326e1e0b9eb5bb634
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/lang/Locale.hpp>
22 #include <com/sun/star/uno/Any.h>
24 #include <comphelper/accessibletexthelper.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/storagehelper.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <rtl/ustring.hxx>
29 #include <unotools/eventcfg.hxx>
30 #include <sfx2/event.hxx>
31 #include <sfx2/app.hxx>
32 #include <sfx2/dispatch.hxx>
33 #include <sfx2/docfile.hxx>
34 #include <sfx2/docfilt.hxx>
35 #include <sfx2/fcontnr.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/exchange.hxx>
43 #include <sot/formats.hxx>
44 #include <sot/storage.hxx>
45 #include <svl/eitem.hxx>
46 #include <svl/fstathelper.hxx>
47 #include <svl/intitem.hxx>
48 #include <svl/itempool.hxx>
49 #include <unotools/lingucfg.hxx>
50 #include <unotools/linguprops.hxx>
51 #include <unotools/pathoptions.hxx>
52 #include <svl/ptitem.hxx>
53 #include <svtools/sfxecode.hxx>
54 #include <svl/slstitm.hxx>
55 #include <svl/hint.hxx>
56 #include <svl/stritem.hxx>
57 #include <svtools/transfer.hxx>
58 #include <svl/undo.hxx>
59 #include <svl/urihelper.hxx>
60 #include <svl/whiter.hxx>
61 #include <editeng/editeng.hxx>
62 #include <editeng/editstat.hxx>
63 #include <editeng/eeitem.hxx>
64 #include <editeng/fhgtitem.hxx>
65 #include <editeng/fontitem.hxx>
66 #include <editeng/unolingu.hxx>
67 #include <ucbhelper/content.hxx>
68 #include <vcl/mapmod.hxx>
69 #include <tools/mapunit.hxx>
70 #include <vcl/msgbox.hxx>
71 #include <vcl/settings.hxx>
73 #include <sfx2/sfx.hrc>
74 #include <document.hxx>
75 #include <action.hxx>
76 #include <dialog.hxx>
77 #include <format.hxx>
78 #include <smdll.hxx>
79 #include <starmath.hrc>
80 #include <symbol.hxx>
81 #include <unomodel.hxx>
82 #include <utility.hxx>
83 #include <view.hxx>
84 #include "mathtype.hxx"
85 #include "ooxmlexport.hxx"
86 #include "ooxmlimport.hxx"
87 #include "rtfexport.hxx"
88 #include "mathmlimport.hxx"
89 #include "mathmlexport.hxx"
90 #include <sfx2/sfxsids.hrc>
91 #include <svx/svxids.hrc>
92 #include "cursor.hxx"
93 #include <tools/diagnose_ex.h>
94 #include "visitors.hxx"
95 #include "accessibility.hxx"
96 #include "cfgitem.hxx"
97 #include <memory>
99 using namespace ::com::sun::star;
100 using namespace ::com::sun::star::accessibility;
101 using namespace ::com::sun::star::uno;
103 #define SmDocShell
104 #include "smslots.hxx"
107 SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
109 void SmDocShell::InitInterface_Impl()
111 GetStaticInterface()->RegisterPopupMenu("view");
114 SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), SfxObjectShellFlags::STD_NORMAL, "smath" )
116 void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
118 switch (rHint.GetId())
120 case HINT_FORMATCHANGED:
121 SetFormulaArranged(false);
123 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
125 Repaint();
126 break;
130 void SmDocShell::LoadSymbols()
132 SmModule *pp = SM_MOD();
133 pp->GetSymbolManager().Load();
137 const OUString SmDocShell::GetComment() const
139 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
140 GetModel(), uno::UNO_QUERY_THROW);
141 uno::Reference<document::XDocumentProperties> xDocProps(
142 xDPS->getDocumentProperties());
143 return xDocProps->getDescription();
147 void SmDocShell::SetText(const OUString& rBuffer)
149 if (rBuffer != maText)
151 bool bIsEnabled = IsEnableSetModified();
152 if( bIsEnabled )
153 EnableSetModified( false );
155 maText = rBuffer;
156 SetFormulaArranged( false );
158 Parse();
160 SmViewShell *pViewSh = SmGetActiveView();
161 if( pViewSh )
163 pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_TEXT);
164 if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
166 // have SwOleClient::FormatChanged() to align the modified formula properly
167 // even if the vis area does not change (e.g. when formula text changes from
168 // "{a over b + c} over d" to "d over {a over b + c}"
169 SfxGetpApp()->NotifyEvent(SfxEventHint( SFX_EVENT_VISAREACHANGED, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
171 Repaint();
173 else
174 pViewSh->GetGraphicWindow().Invalidate();
177 if ( bIsEnabled )
178 EnableSetModified( bIsEnabled );
179 SetModified();
181 // launch accessible event if necessary
182 SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWindow().GetAccessible_Impl() : nullptr;
183 if (pAcc)
185 Any aOldValue, aNewValue;
186 if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
188 pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
189 aOldValue, aNewValue );
193 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
194 OnDocumentPrinterChanged(nullptr);
198 void SmDocShell::SetFormat(SmFormat& rFormat)
200 maFormat = rFormat;
201 SetFormulaArranged( false );
202 SetModified();
204 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
206 // don't use SmGetActiveView since the view shell might not be active (0 pointer)
207 // if for example the Basic Macro dialog currently has the focus. Thus:
208 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
209 while (pFrm)
211 pFrm->GetBindings().Invalidate(SID_GAPHIC_SM);
212 pFrm = SfxViewFrame::GetNext( *pFrm, this );
216 OUString const & SmDocShell::GetAccessibleText()
218 ArrangeFormula();
219 if (maAccText.isEmpty())
221 OSL_ENSURE( mpTree, "Tree missing" );
222 if (mpTree)
224 OUStringBuffer aBuf;
225 mpTree->GetAccessibleText(aBuf);
226 maAccText = aBuf.makeStringAndClear();
229 return maAccText;
232 void SmDocShell::Parse()
234 delete mpTree;
235 ReplaceBadChars();
236 mpTree = maParser.Parse(maText);
237 mnModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
238 SetFormulaArranged( false );
239 InvalidateCursor();
240 maUsedSymbols = maParser.GetUsedSymbols();
244 void SmDocShell::ArrangeFormula()
246 if (mbFormulaArranged)
247 return;
249 // Only for the duration of the existence of this object the correct settings
250 // at the printer are guaranteed!
251 SmPrinterAccess aPrtAcc(*this);
252 OutputDevice* pOutDev = aPrtAcc.GetRefDev();
254 SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
256 // if necessary get another OutputDevice for which we format
257 if (!pOutDev)
259 SmViewShell *pView = SmGetActiveView();
260 if (pView)
261 pOutDev = &pView->GetGraphicWindow();
262 else
264 pOutDev = &SM_MOD()->GetDefaultVirtualDev();
265 pOutDev->SetMapMode( MapMode(MapUnit::Map100thMM) );
268 OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM,
269 "Sm : falscher MapMode");
271 const SmFormat &rFormat = GetFormat();
272 mpTree->Prepare(rFormat, *this);
274 // format/draw formulas always from left to right,
275 // and numbers should not be converted
276 ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode();
277 pOutDev->SetLayoutMode( ComplexTextLayoutFlags::Default );
278 sal_Int16 nDigitLang = pOutDev->GetDigitLanguage();
279 pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
281 mpTree->Arrange(*pOutDev, rFormat);
283 pOutDev->SetLayoutMode( nLayoutMode );
284 pOutDev->SetDigitLanguage( nDigitLang );
286 SetFormulaArranged(true);
288 // invalidate accessible text
289 maAccText.clear();
293 void SetEditEngineDefaultFonts(SfxItemPool &rEditEngineItemPool)
296 // set fonts to be used
298 SvtLinguOptions aOpt;
299 SvtLinguConfig().GetOptions( aOpt );
301 struct FontDta {
302 sal_Int16 nFallbackLang;
303 sal_Int16 nLang;
304 DefaultFontType nFontType;
305 sal_uInt16 nFontInfoId;
306 } aTable[3] =
308 // info to get western font to be used
309 { LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
310 DefaultFontType::FIXED, EE_CHAR_FONTINFO },
311 // info to get CJK font to be used
312 { LANGUAGE_JAPANESE, LANGUAGE_NONE,
313 DefaultFontType::CJK_TEXT, EE_CHAR_FONTINFO_CJK },
314 // info to get CTL font to be used
315 { LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
316 DefaultFontType::CTL_TEXT, EE_CHAR_FONTINFO_CTL }
318 aTable[0].nLang = aOpt.nDefaultLanguage;
319 aTable[1].nLang = aOpt.nDefaultLanguage_CJK;
320 aTable[2].nLang = aOpt.nDefaultLanguage_CTL;
322 for (FontDta & rFntDta : aTable)
324 LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
325 rFntDta.nFallbackLang : rFntDta.nLang;
326 vcl::Font aFont = OutputDevice::GetDefaultFont(
327 rFntDta.nFontType, nLang, GetDefaultFontFlags::OnlyOne );
328 rEditEngineItemPool.SetPoolDefaultItem(
329 SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
330 aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(),
331 rFntDta.nFontInfoId ) );
334 // set font heights
335 SvxFontHeightItem aFontHeigt(
336 Application::GetDefaultDevice()->LogicToPixel(
337 Size( 0, 11 ), MapMode( MapUnit::MapPoint ) ).Height(), 100,
338 EE_CHAR_FONTHEIGHT );
339 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
340 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CJK );
341 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
342 aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CTL );
343 rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
347 EditEngine& SmDocShell::GetEditEngine()
349 if (!mpEditEngine)
352 //! see also SmEditWindow::DataChanged !
355 mpEditEngineItemPool = EditEngine::CreatePool();
357 SetEditEngineDefaultFonts(*mpEditEngineItemPool);
359 mpEditEngine = new EditEngine( mpEditEngineItemPool );
361 mpEditEngine->EnableUndo( true );
362 mpEditEngine->SetDefTab( sal_uInt16(
363 Application::GetDefaultDevice()->GetTextWidth("XXXX")) );
365 mpEditEngine->SetControlWord(
366 (mpEditEngine->GetControlWord() | EEControlBits::AUTOINDENTING) &
367 EEControlBits(~EEControlBits::UNDOATTRIBS) &
368 EEControlBits(~EEControlBits::PASTESPECIAL) );
370 mpEditEngine->SetWordDelimiters(" .=+-*/(){}[];\"");
371 mpEditEngine->SetRefMapMode( MapUnit::MapPixel );
373 mpEditEngine->SetPaperSize( Size( 800, 0 ) );
375 mpEditEngine->EraseVirtualDevice();
377 // set initial text if the document already has some...
378 // (may be the case when reloading a doc)
379 OUString aTxt( GetText() );
380 if (!aTxt.isEmpty())
381 mpEditEngine->SetText( aTxt );
383 mpEditEngine->ClearModifyFlag();
386 return *mpEditEngine;
390 SfxItemPool& SmDocShell::GetEditEngineItemPool()
392 if (!mpEditEngineItemPool)
393 GetEditEngine();
394 assert(mpEditEngineItemPool && "EditEngineItemPool missing");
395 return *mpEditEngineItemPool;
398 void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
400 if (!mpTree)
401 Parse();
402 OSL_ENSURE(mpTree, "Sm : NULL pointer");
404 ArrangeFormula();
406 // Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
407 // device and aren't aligned to that either. So now there can be a difference between the
408 // VisArea (i.e. the size within the client) and the current size.
409 // Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
411 rPosition.X() += maFormat.GetDistance( DIS_LEFTSPACE );
412 rPosition.Y() += maFormat.GetDistance( DIS_TOPSPACE );
414 //! in case of high contrast-mode (accessibility option!)
415 //! the draw mode needs to be set to default, because when imbedding
416 //! Math for example in Calc in "a over b" the fraction bar may not
417 //! be visible else. More generally: the FillColor may have been changed.
418 DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
419 bool bRestoreDrawMode = false;
420 if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
421 static_cast<vcl::Window &>(rDev).GetSettings().GetStyleSettings().GetHighContrastMode())
423 nOldDrawMode = rDev.GetDrawMode();
424 rDev.SetDrawMode( DrawModeFlags::Default );
425 bRestoreDrawMode = true;
428 // format/draw formulas always from left to right
429 // and numbers should not be converted
430 ComplexTextLayoutFlags nLayoutMode = rDev.GetLayoutMode();
431 rDev.SetLayoutMode( ComplexTextLayoutFlags::Default );
432 sal_Int16 nDigitLang = rDev.GetDigitLanguage();
433 rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
435 //Set selection if any
436 if(mpCursor && bDrawSelection){
437 mpCursor->AnnotateSelection();
438 SmSelectionDrawingVisitor(rDev, mpTree, rPosition);
441 //Drawing using visitor
442 SmDrawingVisitor(rDev, rPosition, mpTree);
445 rDev.SetLayoutMode( nLayoutMode );
446 rDev.SetDigitLanguage( nDigitLang );
448 if (bRestoreDrawMode)
449 rDev.SetDrawMode( nOldDrawMode );
452 Size SmDocShell::GetSize()
454 Size aRet;
456 if (!mpTree)
457 Parse();
459 if (mpTree)
461 ArrangeFormula();
462 aRet = mpTree->GetSize();
464 if ( !aRet.Width() )
465 aRet.Width() = 2000;
466 else
467 aRet.Width() += maFormat.GetDistance( DIS_LEFTSPACE ) +
468 maFormat.GetDistance( DIS_RIGHTSPACE );
469 if ( !aRet.Height() )
470 aRet.Height() = 1000;
471 else
472 aRet.Height() += maFormat.GetDistance( DIS_TOPSPACE ) +
473 maFormat.GetDistance( DIS_BOTTOMSPACE );
476 return aRet;
479 void SmDocShell::InvalidateCursor(){
480 mpCursor.reset();
483 SmCursor& SmDocShell::GetCursor(){
484 if(!mpCursor)
485 mpCursor.reset(new SmCursor(mpTree, this));
486 return *mpCursor;
489 bool SmDocShell::HasCursor()
491 return mpCursor.get() != nullptr;
494 SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
496 pPrinter = rDocShell.GetPrt();
497 if ( pPrinter )
499 pPrinter->Push( PushFlags::MAPMODE );
500 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
502 // if it is an embedded object (without it's own printer)
503 // we change the MapMode temporarily.
504 //!If it is a document with its own printer the MapMode should
505 //!be set correct (once) elsewhere(!), in order to avoid numerous
506 //!superfluous pushing and poping of the MapMode when using
507 //!this class.
509 const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
510 if ( MapUnit::Map100thMM != eOld )
512 MapMode aMap( pPrinter->GetMapMode() );
513 aMap.SetMapUnit( MapUnit::Map100thMM );
514 Point aTmp( aMap.GetOrigin() );
515 aTmp.X() = OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM );
516 aTmp.Y() = OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM );
517 aMap.SetOrigin( aTmp );
518 pPrinter->SetMapMode( aMap );
522 if ( !!(pRefDev = rDocShell.GetRefDev()) && pPrinter.get() != pRefDev.get() )
524 pRefDev->Push( PushFlags::MAPMODE );
525 if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
527 // if it is an embedded object (without it's own printer)
528 // we change the MapMode temporarily.
529 //!If it is a document with its own printer the MapMode should
530 //!be set correct (once) elsewhere(!), in order to avoid numerous
531 //!superfluous pushing and poping of the MapMode when using
532 //!this class.
534 const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
535 if ( MapUnit::Map100thMM != eOld )
537 MapMode aMap( pRefDev->GetMapMode() );
538 aMap.SetMapUnit( MapUnit::Map100thMM );
539 Point aTmp( aMap.GetOrigin() );
540 aTmp.X() = OutputDevice::LogicToLogic( aTmp.X(), eOld, MapUnit::Map100thMM );
541 aTmp.Y() = OutputDevice::LogicToLogic( aTmp.Y(), eOld, MapUnit::Map100thMM );
542 aMap.SetOrigin( aTmp );
543 pRefDev->SetMapMode( aMap );
549 SmPrinterAccess::~SmPrinterAccess()
551 if ( pPrinter )
552 pPrinter->Pop();
553 if ( pRefDev && pRefDev != pPrinter )
554 pRefDev->Pop();
557 Printer* SmDocShell::GetPrt()
559 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
561 // Normally the server provides the printer. But if it doesn't provide one (e.g. because
562 // there is no connection) it still can be the case that we know the printer because it
563 // has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
564 Printer* pPrt = GetDocumentPrinter();
565 if (!pPrt && mpTmpPrinter)
566 pPrt = mpTmpPrinter;
567 return pPrt;
569 else if (!mpPrinter)
571 SfxItemSet* pOptions = new SfxItemSet(GetPool(),
572 SID_PRINTSIZE, SID_PRINTSIZE,
573 SID_PRINTZOOM, SID_PRINTZOOM,
574 SID_PRINTTITLE, SID_PRINTTITLE,
575 SID_PRINTTEXT, SID_PRINTTEXT,
576 SID_PRINTFRAME, SID_PRINTFRAME,
577 SID_NO_RIGHT_SPACES, SID_NO_RIGHT_SPACES,
578 SID_SAVE_ONLY_USED_SYMBOLS, SID_SAVE_ONLY_USED_SYMBOLS,
579 SID_AUTO_CLOSE_BRACKETS, SID_AUTO_CLOSE_BRACKETS,
581 SmModule *pp = SM_MOD();
582 pp->GetConfig()->ConfigToItemSet(*pOptions);
583 mpPrinter = VclPtr<SfxPrinter>::Create(pOptions);
584 mpPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
586 return mpPrinter;
589 OutputDevice* SmDocShell::GetRefDev()
591 if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
593 OutputDevice* pOutDev = GetDocumentRefDev();
594 if (pOutDev)
595 return pOutDev;
598 return GetPrt();
601 void SmDocShell::SetPrinter( SfxPrinter *pNew )
603 mpPrinter.disposeAndClear();
604 mpPrinter = pNew; //Transfer ownership
605 mpPrinter->SetMapMode( MapMode(MapUnit::Map100thMM) );
606 SetFormulaArranged(false);
607 Repaint();
610 void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
612 mpTmpPrinter = pPrt;
613 SetFormulaArranged(false);
614 Size aOldSize = GetVisArea().GetSize();
615 Repaint();
616 if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
617 SetModified();
618 mpTmpPrinter = nullptr;
621 void SmDocShell::Repaint()
623 bool bIsEnabled = IsEnableSetModified();
624 if (bIsEnabled)
625 EnableSetModified( false );
627 SetFormulaArranged(false);
629 Size aVisSize = GetSize();
630 SetVisAreaSize(aVisSize);
631 SmViewShell* pViewSh = SmGetActiveView();
632 if (pViewSh)
633 pViewSh->GetGraphicWindow().Invalidate();
635 if (bIsEnabled)
636 EnableSetModified(bIsEnabled);
639 SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
640 : SfxObjectShell(i_nSfxCreationFlags)
641 , mpTree(nullptr)
642 , mpEditEngineItemPool(nullptr)
643 , mpEditEngine(nullptr)
644 , mpPrinter(nullptr)
645 , mpTmpPrinter(nullptr)
646 , mnModifyCount(0)
647 , mbFormulaArranged(false)
649 SetPool(&SfxGetpApp()->GetPool());
651 SmModule *pp = SM_MOD();
652 maFormat = pp->GetConfig()->GetStandardFormat();
654 StartListening(maFormat);
655 StartListening(*pp->GetConfig());
657 SetBaseModel(new SmModel(this));
660 SmDocShell::~SmDocShell()
662 SmModule *pp = SM_MOD();
664 EndListening(maFormat);
665 EndListening(*pp->GetConfig());
667 mpCursor.reset();
668 delete mpEditEngine;
669 SfxItemPool::Free(mpEditEngineItemPool);
670 delete mpTree;
671 mpPrinter.disposeAndClear();
674 bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
676 bool bSuccess = false;
677 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
679 OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
681 if ( rFltName == MATHML_XML )
683 if (mpTree)
685 delete mpTree;
686 mpTree = nullptr;
687 InvalidateCursor();
689 Reference<css::frame::XModel> xModel(GetModel());
690 SmXMLImportWrapper aEquation(xModel);
691 bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
693 else
695 SvStream *pStream = rMedium.GetInStream();
696 if ( pStream )
698 if ( SotStorage::IsStorageFile( pStream ) )
700 tools::SvRef<SotStorage> aStorage = new SotStorage( pStream, false );
701 if ( aStorage->IsStream("Equation Native") )
703 // is this a MathType Storage?
704 MathType aEquation( maText );
705 bSuccess = aEquation.Parse( aStorage.get() );
706 if ( bSuccess )
707 Parse();
713 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
715 SetFormulaArranged( false );
716 Repaint();
719 FinishedLoading();
720 return bSuccess;
724 bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
726 bool bRet = false;
727 if ( SfxObjectShell::InitNew( xStorage ) )
729 bRet = true;
730 SetVisArea(Rectangle(Point(0, 0), Size(2000, 1000)));
732 return bRet;
736 bool SmDocShell::Load( SfxMedium& rMedium )
738 bool bRet = false;
739 if( SfxObjectShell::Load( rMedium ))
741 uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
742 uno::Reference < container::XNameAccess > xAccess (xStorage, uno::UNO_QUERY);
743 if (
745 xAccess->hasByName( "content.xml" ) &&
746 xStorage->isStreamElement( "content.xml" )
747 ) ||
749 xAccess->hasByName( "Content.xml" ) &&
750 xStorage->isStreamElement( "Content.xml" )
754 // is this a fabulous math package ?
755 Reference<css::frame::XModel> xModel(GetModel());
756 SmXMLImportWrapper aEquation(xModel);
757 sal_uLong nError = aEquation.Import(rMedium);
758 bRet = 0 == nError;
759 SetError( nError, OSL_LOG_PREFIX );
763 if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
765 SetFormulaArranged( false );
766 Repaint();
769 FinishedLoading();
770 return bRet;
774 bool SmDocShell::Save()
776 //! apply latest changes if necessary
777 UpdateText();
779 if ( SfxObjectShell::Save() )
781 if (!mpTree)
782 Parse();
783 if( mpTree )
784 ArrangeFormula();
786 Reference<css::frame::XModel> xModel(GetModel());
787 SmXMLExportWrapper aEquation(xModel);
788 aEquation.SetFlat(false);
789 return aEquation.Export(*GetMedium());
792 return false;
796 * replace bad characters that can not be saved. (#i74144)
797 * */
798 void SmDocShell::ReplaceBadChars()
800 bool bReplace = false;
802 if (mpEditEngine)
804 OUStringBuffer aBuf( mpEditEngine->GetText() );
806 for (sal_Int32 i = 0; i < aBuf.getLength(); ++i)
808 if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
810 aBuf[i] = ' ';
811 bReplace = true;
815 if (bReplace)
816 maText = aBuf.makeStringAndClear();
821 void SmDocShell::UpdateText()
823 if (mpEditEngine && mpEditEngine->IsModified())
825 OUString aEngTxt( mpEditEngine->GetText() );
826 if (GetText() != aEngTxt)
827 SetText( aEngTxt );
832 bool SmDocShell::SaveAs( SfxMedium& rMedium )
834 bool bRet = false;
836 //! apply latest changes if necessary
837 UpdateText();
839 if ( SfxObjectShell::SaveAs( rMedium ) )
841 if (!mpTree)
842 Parse();
843 if( mpTree )
844 ArrangeFormula();
846 Reference<css::frame::XModel> xModel(GetModel());
847 SmXMLExportWrapper aEquation(xModel);
848 aEquation.SetFlat(false);
849 bRet = aEquation.Export(rMedium);
851 return bRet;
854 bool SmDocShell::ConvertTo( SfxMedium &rMedium )
856 bool bRet = false;
857 std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
858 if( pFlt )
860 if( !mpTree )
861 Parse();
862 if( mpTree )
863 ArrangeFormula();
865 const OUString& rFltName = pFlt->GetFilterName();
866 if(rFltName == STAROFFICE_XML)
868 Reference<css::frame::XModel> xModel(GetModel());
869 SmXMLExportWrapper aEquation(xModel);
870 aEquation.SetFlat(false);
871 bRet = aEquation.Export(rMedium);
873 else if(rFltName == MATHML_XML)
875 Reference<css::frame::XModel> xModel(GetModel());
876 SmXMLExportWrapper aEquation(xModel);
877 aEquation.SetFlat(true);
878 bRet = aEquation.Export(rMedium);
880 else if (pFlt->GetFilterName() == "MathType 3.x")
881 bRet = WriteAsMathType3( rMedium );
883 return bRet;
886 bool SmDocShell::writeFormulaOoxml(
887 ::sax_fastparser::FSHelperPtr const& pSerializer,
888 oox::core::OoxmlVersion const version,
889 oox::drawingml::DocumentType const documentType)
891 if( !mpTree )
892 Parse();
893 if( mpTree )
894 ArrangeFormula();
895 SmOoxmlExport aEquation(mpTree, version, documentType);
896 return aEquation.ConvertFromStarMath( pSerializer );
899 void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
901 if (!mpTree)
902 Parse();
903 if (mpTree)
904 ArrangeFormula();
905 SmRtfExport aEquation(mpTree);
906 aEquation.ConvertFromStarMath(rBuffer, nEncoding);
909 void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
911 SmOoxmlImport aEquation( stream );
912 SetText( aEquation.ConvertToStarMath());
915 void SmDocShell::Execute(SfxRequest& rReq)
917 switch (rReq.GetSlot())
919 case SID_TEXTMODE:
921 SmFormat aOldFormat = GetFormat();
922 SmFormat aNewFormat( aOldFormat );
923 aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
925 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
926 if (pTmpUndoMgr)
927 pTmpUndoMgr->AddUndoAction(
928 new SmFormatAction(this, aOldFormat, aNewFormat));
930 SetFormat( aNewFormat );
931 Repaint();
933 break;
935 case SID_AUTO_REDRAW :
937 SmModule *pp = SM_MOD();
938 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
939 pp->GetConfig()->SetAutoRedraw(!bRedraw);
941 break;
943 case SID_LOADSYMBOLS:
944 LoadSymbols();
945 break;
947 case SID_SAVESYMBOLS:
948 SaveSymbols();
949 break;
951 case SID_FONT:
953 // get device used to retrieve the FontList
954 OutputDevice *pDev = GetPrinter();
955 if (!pDev || pDev->GetDevFontCount() == 0)
956 pDev = &SM_MOD()->GetDefaultVirtualDev();
957 OSL_ENSURE (pDev, "device for font list missing" );
959 VclPtrInstance< SmFontTypeDialog > xFontTypeDialog( nullptr, pDev );
961 SmFormat aOldFormat = GetFormat();
962 xFontTypeDialog->ReadFrom( aOldFormat );
963 if (xFontTypeDialog->Execute() == RET_OK)
965 SmFormat aNewFormat( aOldFormat );
967 xFontTypeDialog->WriteTo(aNewFormat);
968 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
969 if (pTmpUndoMgr)
970 pTmpUndoMgr->AddUndoAction(
971 new SmFormatAction(this, aOldFormat, aNewFormat));
973 SetFormat( aNewFormat );
974 Repaint();
977 break;
979 case SID_FONTSIZE:
981 VclPtrInstance< SmFontSizeDialog > xFontSizeDialog(nullptr);
983 SmFormat aOldFormat = GetFormat();
984 xFontSizeDialog->ReadFrom( aOldFormat );
985 if (xFontSizeDialog->Execute() == RET_OK)
987 SmFormat aNewFormat( aOldFormat );
989 xFontSizeDialog->WriteTo(aNewFormat);
991 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
992 if (pTmpUndoMgr)
993 pTmpUndoMgr->AddUndoAction(
994 new SmFormatAction(this, aOldFormat, aNewFormat));
996 SetFormat( aNewFormat );
997 Repaint();
1000 break;
1002 case SID_DISTANCE:
1004 VclPtrInstance< SmDistanceDialog > xDistanceDialog(nullptr);
1006 SmFormat aOldFormat = GetFormat();
1007 xDistanceDialog->ReadFrom( aOldFormat );
1008 if (xDistanceDialog->Execute() == RET_OK)
1010 SmFormat aNewFormat( aOldFormat );
1012 xDistanceDialog->WriteTo(aNewFormat);
1014 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
1015 if (pTmpUndoMgr)
1016 pTmpUndoMgr->AddUndoAction(
1017 new SmFormatAction(this, aOldFormat, aNewFormat));
1019 SetFormat( aNewFormat );
1020 Repaint();
1023 break;
1025 case SID_ALIGN:
1027 VclPtrInstance< SmAlignDialog > xAlignDialog(nullptr);
1029 SmFormat aOldFormat = GetFormat();
1030 xAlignDialog->ReadFrom( aOldFormat );
1031 if (xAlignDialog->Execute() == RET_OK)
1033 SmFormat aNewFormat( aOldFormat );
1035 xAlignDialog->WriteTo(aNewFormat);
1037 SmModule *pp = SM_MOD();
1038 SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
1039 xAlignDialog->WriteTo( aFmt );
1040 pp->GetConfig()->SetStandardFormat( aFmt );
1042 ::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
1043 if (pTmpUndoMgr)
1044 pTmpUndoMgr->AddUndoAction(
1045 new SmFormatAction(this, aOldFormat, aNewFormat));
1047 SetFormat( aNewFormat );
1048 Repaint();
1051 break;
1053 case SID_TEXT:
1055 const SfxStringItem& rItem = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_TEXT));
1056 if (GetText() != OUString(rItem.GetValue()))
1057 SetText(rItem.GetValue());
1059 break;
1061 case SID_UNDO:
1062 case SID_REDO:
1064 ::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
1065 if( pTmpUndoMgr )
1067 sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
1068 const SfxItemSet* pArgs = rReq.GetArgs();
1069 const SfxPoolItem* pItem;
1070 if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
1071 nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
1073 bool (::svl::IUndoManager:: *fnDo)();
1075 std::size_t nCount;
1076 if( SID_UNDO == rReq.GetSlot() )
1078 nCount = pTmpUndoMgr->GetUndoActionCount();
1079 fnDo = &::svl::IUndoManager::Undo;
1081 else
1083 nCount = pTmpUndoMgr->GetRedoActionCount();
1084 fnDo = &::svl::IUndoManager::Redo;
1089 for( ; nCnt && nCount; --nCnt, --nCount )
1090 (pTmpUndoMgr->*fnDo)();
1092 catch( const Exception& )
1094 DBG_UNHANDLED_EXCEPTION();
1097 Repaint();
1098 UpdateText();
1099 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1100 while( pFrm )
1102 SfxBindings& rBind = pFrm->GetBindings();
1103 rBind.Invalidate(SID_UNDO);
1104 rBind.Invalidate(SID_REDO);
1105 rBind.Invalidate(SID_REPEAT);
1106 rBind.Invalidate(SID_CLEARHISTORY);
1107 pFrm = SfxViewFrame::GetNext( *pFrm, this );
1110 break;
1113 rReq.Done();
1117 void SmDocShell::GetState(SfxItemSet &rSet)
1119 SfxWhichIter aIter(rSet);
1121 for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
1123 switch (nWh)
1125 case SID_TEXTMODE:
1126 rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
1127 break;
1129 case SID_DOCTEMPLATE :
1130 rSet.DisableItem(SID_DOCTEMPLATE);
1131 break;
1133 case SID_AUTO_REDRAW :
1135 SmModule *pp = SM_MOD();
1136 bool bRedraw = pp->GetConfig()->IsAutoRedraw();
1138 rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
1140 break;
1142 case SID_MODIFYSTATUS:
1144 sal_Unicode cMod = ' ';
1145 if (IsModified())
1146 cMod = '*';
1147 rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
1149 break;
1151 case SID_TEXT:
1152 rSet.Put(SfxStringItem(SID_TEXT, GetText()));
1153 break;
1155 case SID_GAPHIC_SM:
1156 //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWindow.
1157 //! If mnModifyCount gets changed then the call below will implicitly notify
1158 //! SmGraphicController::StateChanged and there the window gets invalidated.
1159 //! Thus all the 'mnModifyCount++' before invalidating this slot.
1160 rSet.Put(SfxInt16Item(SID_GAPHIC_SM, mnModifyCount));
1161 break;
1163 case SID_UNDO:
1164 case SID_REDO:
1166 SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1167 if( pFrm )
1168 pFrm->GetSlotState( nWh, nullptr, &rSet );
1169 else
1170 rSet.DisableItem( nWh );
1172 break;
1174 case SID_GETUNDOSTRINGS:
1175 case SID_GETREDOSTRINGS:
1177 ::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
1178 if( pTmpUndoMgr )
1180 OUString(::svl::IUndoManager:: *fnGetComment)( size_t, bool const ) const;
1182 sal_uInt16 nCount;
1183 if( SID_GETUNDOSTRINGS == nWh )
1185 nCount = pTmpUndoMgr->GetUndoActionCount();
1186 fnGetComment = &::svl::IUndoManager::GetUndoActionComment;
1188 else
1190 nCount = pTmpUndoMgr->GetRedoActionCount();
1191 fnGetComment = &::svl::IUndoManager::GetRedoActionComment;
1193 if( nCount )
1195 OUStringBuffer aBuf;
1196 for( sal_uInt16 n = 0; n < nCount; ++n )
1198 aBuf.append((pTmpUndoMgr->*fnGetComment)( n, ::svl::IUndoManager::TopLevel ));
1199 aBuf.append('\n');
1202 SfxStringListItem aItem( nWh );
1203 aItem.SetString( aBuf.makeStringAndClear() );
1204 rSet.Put( aItem );
1207 else
1208 rSet.DisableItem( nWh );
1210 break;
1216 ::svl::IUndoManager *SmDocShell::GetUndoManager()
1218 if (!mpEditEngine)
1219 GetEditEngine();
1220 return &mpEditEngine->GetUndoManager();
1224 void SmDocShell::SaveSymbols()
1226 SmModule *pp = SM_MOD();
1227 pp->GetSymbolManager().Save();
1231 void SmDocShell::Draw(OutputDevice *pDevice,
1232 const JobSetup &,
1233 sal_uInt16 /*nAspect*/)
1235 pDevice->IntersectClipRegion(GetVisArea());
1236 Point atmppoint;
1237 DrawFormula(*pDevice, atmppoint);
1240 SfxItemPool& SmDocShell::GetPool()
1242 return SfxGetpApp()->GetPool();
1245 void SmDocShell::SetVisArea(const Rectangle & rVisArea)
1247 Rectangle aNewRect(rVisArea);
1249 aNewRect.SetPos(Point());
1251 if (! aNewRect.Right()) aNewRect.Right() = 2000;
1252 if (! aNewRect.Bottom()) aNewRect.Bottom() = 1000;
1254 bool bIsEnabled = IsEnableSetModified();
1255 if ( bIsEnabled )
1256 EnableSetModified( false );
1258 //TODO/LATER: it's unclear how this interacts with the SFX code
1259 // If outplace editing, then don't resize the OutplaceWindow. But the
1260 // ObjectShell has to resize. Bug 56470
1261 bool bUnLockFrame;
1262 if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
1264 GetFrame()->LockAdjustPosSizePixel();
1265 bUnLockFrame = true;
1267 else
1268 bUnLockFrame = false;
1270 SfxObjectShell::SetVisArea( aNewRect );
1272 if( bUnLockFrame )
1273 GetFrame()->UnlockAdjustPosSizePixel();
1275 if ( bIsEnabled )
1276 EnableSetModified( bIsEnabled );
1280 void SmDocShell::FillClass(SvGlobalName* pClassName,
1281 SotClipboardFormatId* pFormat,
1282 OUString* /*pAppName*/,
1283 OUString* pFullTypeName,
1284 OUString* pShortTypeName,
1285 sal_Int32 nFileFormat,
1286 bool bTemplate /* = false */) const
1288 if (nFileFormat == SOFFICE_FILEFORMAT_60 )
1290 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1291 *pFormat = SotClipboardFormatId::STARMATH_60;
1292 *pFullTypeName = SM_RESSTR(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1293 *pShortTypeName = SM_RESSTR(RID_DOCUMENTSTR);
1295 else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
1297 *pClassName = SvGlobalName(SO3_SM_CLASSID_60);
1298 *pFormat = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
1299 *pFullTypeName = SM_RESSTR(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1300 *pShortTypeName = SM_RESSTR(RID_DOCUMENTSTR);
1304 sal_uLong SmDocShell::GetMiscStatus() const
1306 return SfxObjectShell::GetMiscStatus() | SVOBJ_MISCSTATUS_NOTRESIZEABLE
1307 | SVOBJ_MISCSTATUS_RESIZEONPRINTERCHANGE;
1310 void SmDocShell::SetModified(bool bModified)
1312 if( IsEnableSetModified() )
1314 SfxObjectShell::SetModified( bModified );
1315 Broadcast(SfxHint(SFX_HINT_DOCCHANGED));
1319 bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
1321 MathType aEquation( maText, mpTree );
1322 return aEquation.ConvertFromStarMath( rMedium );
1325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */