blob: c4f88126f0194c2b76ed355b160650680fa4e7c9 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_starmath.hxx"
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/uno/Any.h>
#include <comphelper/accessibletexthelper.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/storagehelper.hxx>
#include <rtl/logfile.hxx>
#include <rtl/ustring.hxx>
#include <unotools/eventcfg.hxx>
#include <sfx2/event.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/fcontnr.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/printer.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <sot/clsids.hxx>
#include <sot/exchange.hxx>
#include <sot/formats.hxx>
#include <sot/storage.hxx>
#include <svl/eitem.hxx>
#include <svl/fstathelper.hxx>
#include <svl/intitem.hxx>
#include <svl/itempool.hxx>
#include <unotools/lingucfg.hxx>
#include <unotools/linguprops.hxx>
#include <unotools/pathoptions.hxx>
#include <svl/ptitem.hxx>
#include <svtools/sfxecode.hxx>
#include <svl/slstitm.hxx>
#include <svl/smplhint.hxx>
#include <svl/stritem.hxx>
#include <svtools/transfer.hxx>
#include <svl/undo.hxx>
#include <svl/urihelper.hxx>
#include <svl/whiter.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editstat.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/unolingu.hxx>
#include <ucbhelper/content.hxx>
#include <vcl/mapmod.hxx>
#include <tools/mapunit.hxx>
#include <vcl/msgbox.hxx>
#include <sfx2/sfx.hrc>
#include <document.hxx>
#include <action.hxx>
#include <config.hxx>
#include <dialog.hxx>
#include <format.hxx>
#include <smdll.hxx>
#include <starmath.hrc>
#include <symbol.hxx>
#include <toolbox.hxx>
#include <unomodel.hxx>
#include <utility.hxx>
#include <view.hxx>
#include "mathtype.hxx"
#include "mathmlimport.hxx"
#include "mathmlexport.hxx"
#include <sfx2/sfxsids.hrc>
#include <svx/svxids.hrc>
#include <tools/diagnose_ex.h>
using namespace ::com::sun::star;
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::uno;
#define DOCUMENT_BUFFER_SIZE (sal_uInt16)32768
static const char __FAR_DATA pStarMathDoc[] = "StarMathDocument";
#define SmDocShell
#include "smslots.hxx"
////////////////////////////////////////////////////////////
TYPEINIT1( SmDocShell, SfxObjectShell );
SFX_IMPL_INTERFACE(SmDocShell, SfxObjectShell, SmResId(0))
{
SFX_POPUPMENU_REGISTRATION(SmResId(RID_VIEWMENU));
SFX_POPUPMENU_REGISTRATION(SmResId(RID_COMMANDMENU));
}
SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), SFXOBJECTSHELL_STD_NORMAL, "smath" )
void SmDocShell::SFX_NOTIFY(SfxBroadcaster&, const TypeId&,
const SfxHint& rHint, const TypeId&)
{
switch (((SfxSimpleHint&)rHint).GetId())
{
case HINT_FORMATCHANGED:
SetFormulaArranged(sal_False);
nModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
Repaint();
break;
}
}
void SmDocShell::LoadSymbols()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::LoadSymbols" );
SmModule *pp = SM_MOD();
pp->GetSymbolManager().Load();
}
const String SmDocShell::GetComment() const
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetComment" );
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
const_cast<SmDocShell*>(this)->GetModel(), uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties> xDocProps(
xDPS->getDocumentProperties());
return xDocProps->getDescription();
}
void SmDocShell::SetText(const String& rBuffer)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetText" );
if (rBuffer != aText)
{
sal_Bool bIsEnabled = IsEnableSetModified();
if( bIsEnabled )
EnableSetModified( sal_False );
aText = rBuffer;
SetFormulaArranged( sal_False );
Parse();
//Repaint();
SmViewShell *pViewSh = SmGetActiveView();
if( pViewSh )
{
pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_TEXT);
if ( SFX_CREATE_MODE_EMBEDDED == GetCreateMode() )
{
// have SwOleClient::FormatChanged() to align the modified formula properly
// even if the vis area does not change (e.g. when formula text changes from
// "{a over b + c} over d" to "d over {a over b + c}"
SFX_APP()->NotifyEvent(SfxEventHint( SFX_EVENT_VISAREACHANGED, GlobalEventConfig::GetEventName(STR_EVENT_VISAREACHANGED), this));
Repaint();
}
else
pViewSh->GetGraphicWindow().Invalidate();
}
if ( bIsEnabled )
EnableSetModified( bIsEnabled );
SetModified(sal_True);
// launch accessible event if necessary
SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWindow().GetAccessible_Impl() : 0;
if (pAcc)
{
Any aOldValue, aNewValue;
if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( aText, rBuffer, aOldValue, aNewValue ) )
{
pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
aOldValue, aNewValue );
}
}
if ( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED )
OnDocumentPrinterChanged(0);
}
}
void SmDocShell::SetFormat(SmFormat& rFormat)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetFormat" );
aFormat = rFormat;
SetFormulaArranged( sal_False );
SetModified( sal_True );
nModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
// don't use SmGetActiveView since the view shell might not be active (0 pointer)
// if for example the Basic Macro dialog currently has the focus. Thus:
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
while (pFrm)
{
pFrm->GetBindings().Invalidate(SID_GAPHIC_SM);
pFrm = SfxViewFrame::GetNext( *pFrm, this );
}
}
String SmDocShell::GetAccessibleText()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetAccessibleText" );
if (!IsFormulaArranged())
ArrangeFormula();
if (0 == aAccText.Len())
{
DBG_ASSERT( pTree, "Tree missing" );
if (pTree)
pTree->GetAccessibleText( aAccText );
}
return aAccText;
}
void SmDocShell::Parse()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Parse" );
if (pTree)
delete pTree;
ReplaceBadChars();
pTree = aInterpreter.Parse(aText);
nModifyCount++; //! see comment for SID_GAPHIC_SM in SmDocShell::GetState
SetFormulaArranged( sal_False );
aUsedSymbols = aInterpreter.GetUsedSymbols();
}
void SmDocShell::ArrangeFormula()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::ArrangeFormula" );
if (IsFormulaArranged())
return;
//! Nur f�r die Dauer der Existenz dieses Objekts sind am Drucker die
//! richtigen Einstellungen garantiert.
SmPrinterAccess aPrtAcc(*this);
// OutputDevice *pOutDev = aPrtAcc.GetPrinter();
OutputDevice* pOutDev = aPrtAcc.GetRefDev();
if (!pOutDev)
{
#if OSL_DEBUG_LEVEL > 1
DBG_ERROR("!! SmDocShell::ArrangeFormula: reference device missing !!");
#endif
}
// falls n�tig ein anderes OutputDevice holen f�r das formatiert wird
if (!pOutDev)
{
SmViewShell *pView = SmGetActiveView();
if (pView)
pOutDev = &pView->GetGraphicWindow();
else
{
pOutDev = &SM_MOD()->GetDefaultVirtualDev();
pOutDev->SetMapMode( MapMode(MAP_100TH_MM) );
}
}
DBG_ASSERT(pOutDev->GetMapMode().GetMapUnit() == MAP_100TH_MM,
"Sm : falscher MapMode");
const SmFormat &rFormat = GetFormat();
pTree->Prepare(rFormat, *this);
// format/draw formulas always from left to right,
// and numbers should not be converted
sal_uLong nLayoutMode = pOutDev->GetLayoutMode();
pOutDev->SetLayoutMode( TEXT_LAYOUT_BIDI_LTR );
sal_Int16 nDigitLang = pOutDev->GetDigitLanguage();
pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
//
pTree->Arrange(*pOutDev, rFormat);
//
pOutDev->SetLayoutMode( nLayoutMode );
pOutDev->SetDigitLanguage( nDigitLang );
SetFormulaArranged(sal_True);
// invalidate accessible text
aAccText = String();
}
void SetEditEngineDefaultFonts(
EditEngine &/*rEditEngine*/,
SfxItemPool &rEditEngineItemPool )
{
//
// set fonts to be used
//
SvtLinguOptions aOpt;
SvtLinguConfig().GetOptions( aOpt );
//
struct FontDta {
sal_Int16 nFallbackLang;
sal_Int16 nLang;
sal_uInt16 nFontType;
sal_uInt16 nFontInfoId;
} aTable[3] =
{
// info to get western font to be used
{ LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
DEFAULTFONT_FIXED, EE_CHAR_FONTINFO },
// info to get CJK font to be used
{ LANGUAGE_JAPANESE, LANGUAGE_NONE,
DEFAULTFONT_CJK_TEXT, EE_CHAR_FONTINFO_CJK },
// info to get CTL font to be used
{ LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
DEFAULTFONT_CTL_TEXT, EE_CHAR_FONTINFO_CTL }
};
aTable[0].nLang = aOpt.nDefaultLanguage;
aTable[1].nLang = aOpt.nDefaultLanguage_CJK;
aTable[2].nLang = aOpt.nDefaultLanguage_CTL;
//
for (int i = 0; i < 3; ++i)
{
const FontDta &rFntDta = aTable[i];
LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
rFntDta.nFallbackLang : rFntDta.nLang;
Font aFont = Application::GetDefaultDevice()->GetDefaultFont(
rFntDta.nFontType, nLang, DEFAULTFONT_FLAGS_ONLYONE );
#ifdef DEBUG_TL
ByteString aFntName( aFont.GetName(), 1 );
int eFntFamily = aFont.GetFamily();
ByteString aFntStyleName( aFont.GetStyleName(), 1 );
int ePitch = aFont.GetPitch();
int eCharSet = aFont.GetCharSet();
fprintf(stderr, "\nFontName %s \n", aFntName.GetBuffer() );
fprintf(stderr, "StyleName %s \n", aFntStyleName.GetBuffer() );
fprintf(stderr, "eFntFamily %d \n", eFntFamily );
fprintf(stderr, "ePitch %d \n", ePitch );
fprintf(stderr, "eCharSet %d \n", eCharSet );
#endif
rEditEngineItemPool.SetPoolDefaultItem(
SvxFontItem( aFont.GetFamily(), aFont.GetName(),
aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(),
rFntDta.nFontInfoId ) );
}
// set font heights
SvxFontHeightItem aFontHeigt(
Application::GetDefaultDevice()->LogicToPixel(
Size( 0, 11 ), MapMode( MAP_POINT ) ).Height(), 100,
EE_CHAR_FONTHEIGHT );
rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CJK );
rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
aFontHeigt.SetWhich( EE_CHAR_FONTHEIGHT_CTL );
rEditEngineItemPool.SetPoolDefaultItem( aFontHeigt );
}
EditEngine& SmDocShell::GetEditEngine()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetEditEngine" );
if (!pEditEngine)
{
//!
//! see also SmEditWindow::DataChanged !
//!
pEditEngineItemPool = EditEngine::CreatePool();
SetEditEngineDefaultFonts( *pEditEngine, *pEditEngineItemPool );
pEditEngine = new EditEngine( pEditEngineItemPool );
pEditEngine->EnableUndo( sal_True );
pEditEngine->SetDefTab( sal_uInt16(
Application::GetDefaultDevice()->GetTextWidth( C2S("XXXX") ) ) );
pEditEngine->SetControlWord(
(pEditEngine->GetControlWord() | EE_CNTRL_AUTOINDENTING) &
(~EE_CNTRL_UNDOATTRIBS) &
(~EE_CNTRL_PASTESPECIAL) );
pEditEngine->SetWordDelimiters( C2S(" .=+-*/(){}[];\"" ) );
pEditEngine->SetRefMapMode( MAP_PIXEL );
pEditEngine->SetPaperSize( Size( 800, 0 ) );
pEditEngine->EraseVirtualDevice();
// set initial text if the document already has some...
// (may be the case when reloading a doc)
String aTxt( GetText() );
if (aTxt.Len())
pEditEngine->SetText( aTxt );
pEditEngine->ClearModifyFlag();
// forces new settings to be used if the itempool was modified
// after cthe creation of the EditEngine
//pEditEngine->Clear(); //#77957 incorrect font size
}
return *pEditEngine;
}
SfxItemPool& SmDocShell::GetEditEngineItemPool()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetEditEngineItemPool" );
if (!pEditEngineItemPool)
GetEditEngine();
DBG_ASSERT( pEditEngineItemPool, "EditEngineItemPool missing" );
return *pEditEngineItemPool;
}
void SmDocShell::Draw(OutputDevice &rDev, Point &rPosition)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Draw" );
if (!pTree)
Parse();
DBG_ASSERT(pTree, "Sm : NULL pointer");
if (!IsFormulaArranged())
ArrangeFormula();
//Problem: Was passiert mit dem WYSIWYG? Wir haben waehrend wir inplace aktiv
//sind kein Referenzdevice und sind auch nicht darauf ausgerichtet. Es kann
//also jetzt eine Differenz zwischen der VisArea (spricht die Groesse im Client)
//und der jetzt vorliegenden Groese geben.
//Idee: Die Differenz koennte, zumindest behelfsmaessig, mit SmNod::SetSize
//angepasst werden.
rPosition.X() += aFormat.GetDistance( DIS_LEFTSPACE );
rPosition.Y() += aFormat.GetDistance( DIS_TOPSPACE );
//! in case of high contrast-mode (accessibility option!)
//! the draw mode needs to be set to default, because when imbedding
//! Math for example in Calc in "a over b" the fraction bar may not
//! be visible else. More generally: the FillColor may have been changed.
sal_uLong nOldDrawMode = DRAWMODE_DEFAULT;
sal_Bool bRestoreDrawMode = sal_False;
if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
((Window &) rDev).GetSettings().GetStyleSettings().GetHighContrastMode())
{
nOldDrawMode = rDev.GetDrawMode();
rDev.SetDrawMode( DRAWMODE_DEFAULT );
bRestoreDrawMode = sal_True;
}
// format/draw formulas always from left to right
// and numbers should not be converted
sal_uLong nLayoutMode = rDev.GetLayoutMode();
rDev.SetLayoutMode( TEXT_LAYOUT_BIDI_LTR );
sal_Int16 nDigitLang = rDev.GetDigitLanguage();
rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
//
pTree->Draw(rDev, rPosition);
//
rDev.SetLayoutMode( nLayoutMode );
rDev.SetDigitLanguage( nDigitLang );
if (bRestoreDrawMode)
rDev.SetDrawMode( nOldDrawMode );
}
Size SmDocShell::GetSize()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetSize" );
Size aRet;
if (!pTree)
Parse();
if (pTree)
{
if (!IsFormulaArranged())
ArrangeFormula();
aRet = pTree->GetSize();
if ( !aRet.Width() )
aRet.Width() = 2000;
else
aRet.Width() += aFormat.GetDistance( DIS_LEFTSPACE ) +
aFormat.GetDistance( DIS_RIGHTSPACE );
if ( !aRet.Height() )
aRet.Height() = 1000;
else
aRet.Height() += aFormat.GetDistance( DIS_TOPSPACE ) +
aFormat.GetDistance( DIS_BOTTOMSPACE );
}
return aRet;
}
////////////////////////////////////////
SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
{
if ( 0 != (pPrinter = rDocShell.GetPrt()) )
{
pPrinter->Push( PUSH_MAPMODE );
if ( SFX_CREATE_MODE_EMBEDDED == rDocShell.GetCreateMode() )
{
// if it is an embedded object (without it's own printer)
// we change the MapMode temporarily.
//!If it is a document with it's own printer the MapMode should
//!be set correct (once) elsewhere(!), in order to avoid numerous
//!superfluous pushing and poping of the MapMode when using
//!this class.
const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
if ( MAP_100TH_MM != eOld )
{
MapMode aMap( pPrinter->GetMapMode() );
aMap.SetMapUnit( MAP_100TH_MM );
Point aTmp( aMap.GetOrigin() );
aTmp.X() = OutputDevice::LogicToLogic( aTmp.X(), eOld, MAP_100TH_MM );
aTmp.Y() = OutputDevice::LogicToLogic( aTmp.Y(), eOld, MAP_100TH_MM );
aMap.SetOrigin( aTmp );
pPrinter->SetMapMode( aMap );
}
}
}
if ( 0 != (pRefDev = rDocShell.GetRefDev()) && pPrinter != pRefDev )
{
pRefDev->Push( PUSH_MAPMODE );
if ( SFX_CREATE_MODE_EMBEDDED == rDocShell.GetCreateMode() )
{
// if it is an embedded object (without it's own printer)
// we change the MapMode temporarily.
//!If it is a document with it's own printer the MapMode should
//!be set correct (once) elsewhere(!), in order to avoid numerous
//!superfluous pushing and poping of the MapMode when using
//!this class.
const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
if ( MAP_100TH_MM != eOld )
{
MapMode aMap( pRefDev->GetMapMode() );
aMap.SetMapUnit( MAP_100TH_MM );
Point aTmp( aMap.GetOrigin() );
aTmp.X() = OutputDevice::LogicToLogic( aTmp.X(), eOld, MAP_100TH_MM );
aTmp.Y() = OutputDevice::LogicToLogic( aTmp.Y(), eOld, MAP_100TH_MM );
aMap.SetOrigin( aTmp );
pRefDev->SetMapMode( aMap );
}
}
}
}
SmPrinterAccess::~SmPrinterAccess()
{
if ( pPrinter )
pPrinter->Pop();
if ( pRefDev && pRefDev != pPrinter )
pRefDev->Pop();
}
////////////////////////////////////////
Printer* SmDocShell::GetPrt()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetPrt" );
if ( SFX_CREATE_MODE_EMBEDDED == GetCreateMode() )
{
//Normalerweise wird der Printer vom Server besorgt. Wenn dieser aber
//keinen liefert (weil etwa noch keine connection da ist), kann es
//dennoch sein, dass wir den Printer kennen, denn dieser wird in
//OnDocumentPrinterChanged vom Server durchgereicht und dann temporaer
//festgehalten.
Printer *pPrt = GetDocumentPrinter();
if ( !pPrt && pTmpPrinter )
pPrt = pTmpPrinter;
return pPrt;
}
else if ( !pPrinter )
{
SfxItemSet *pOptions =
new SfxItemSet(GetPool(),
SID_PRINTSIZE, SID_PRINTSIZE,
SID_PRINTZOOM, SID_PRINTZOOM,
SID_PRINTTITLE, SID_PRINTTITLE,
SID_PRINTTEXT, SID_PRINTTEXT,
SID_PRINTFRAME, SID_PRINTFRAME,
SID_NO_RIGHT_SPACES, SID_NO_RIGHT_SPACES,
SID_SAVE_ONLY_USED_SYMBOLS, SID_SAVE_ONLY_USED_SYMBOLS,
0);
SmModule *pp = SM_MOD();
pp->GetConfig()->ConfigToItemSet(*pOptions);
pPrinter = new SfxPrinter(pOptions);
pPrinter->SetMapMode( MapMode(MAP_100TH_MM) );
}
return pPrinter;
}
OutputDevice* SmDocShell::GetRefDev()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetRefDev" );
if ( SFX_CREATE_MODE_EMBEDDED == GetCreateMode() )
{
OutputDevice* pOutDev = GetDocumentRefDev();
if ( pOutDev )
return pOutDev;
}
return GetPrt();
}
void SmDocShell::SetPrinter( SfxPrinter *pNew )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetPrinter" );
delete pPrinter;
pPrinter = pNew; //Eigentumsuebergang!
pPrinter->SetMapMode( MapMode(MAP_100TH_MM) );
SetFormulaArranged(sal_False);
Repaint();
}
void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::OnDocumentPrinterChanged" );
pTmpPrinter = pPrt;
SetFormulaArranged(sal_False);
Size aOldSize = GetVisArea().GetSize();
Repaint();
if( aOldSize != GetVisArea().GetSize() && aText.Len() )
SetModified( sal_True );
pTmpPrinter = 0;
}
void SmDocShell::Repaint()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Repaint" );
sal_Bool bIsEnabled = IsEnableSetModified();
if ( bIsEnabled )
EnableSetModified( sal_False );
SetFormulaArranged( sal_False );
Size aVisSize = GetSize();
SetVisAreaSize( aVisSize );
SmViewShell *pViewSh = SmGetActiveView();
if (pViewSh)
pViewSh->GetGraphicWindow().Invalidate();
if ( bIsEnabled )
EnableSetModified( bIsEnabled );
}
SmDocShell::SmDocShell( const sal_uInt64 i_nSfxCreationFlags ) :
SfxObjectShell( i_nSfxCreationFlags ),
pTree ( 0 ),
pEditEngineItemPool ( 0 ),
pEditEngine ( 0 ),
pPrinter ( 0 ),
pTmpPrinter ( 0 ),
nModifyCount ( 0 ),
bIsFormulaArranged ( sal_False )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SmDocShell" );
SetPool(&SFX_APP()->GetPool());
SmModule *pp = SM_MOD();
aFormat = pp->GetConfig()->GetStandardFormat();
StartListening(aFormat);
StartListening(*pp->GetConfig());
SetBaseModel( new SmModel(this) );
}
SmDocShell::~SmDocShell()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::~SmDocShell" );
SmModule *pp = SM_MOD();
EndListening(aFormat);
EndListening(*pp->GetConfig());
delete pEditEngine;
SfxItemPool::Free(pEditEngineItemPool);
delete pTree;
delete pPrinter;
}
sal_Bool SmDocShell::SetData( const String& rData )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetData" );
SetText( rData );
return sal_True;
}
sal_Bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::ConvertFrom" );
sal_Bool bSuccess = sal_False;
const String& rFltName = rMedium.GetFilter()->GetFilterName();
DBG_ASSERT( !rFltName.EqualsAscii( STAROFFICE_XML ), "Wrong filter!");
if ( rFltName.EqualsAscii( MATHML_XML ) )
{
if (pTree)
{
delete pTree;
pTree = 0;
}
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLImportWrapper aEquation(xModel);
bSuccess = 0 == aEquation.Import(rMedium);
}
else
{
SvStream *pStream = rMedium.GetInStream();
if ( pStream )
{
if ( SotStorage::IsStorageFile( pStream ) )
{
SvStorageRef aStorage = new SotStorage( pStream, sal_False );
if ( aStorage->IsStream( C2S( "Equation Native" ) ) )
{
// is this a MathType Storage?
MathType aEquation( aText );
if ( sal_True == (bSuccess = (1 == aEquation.Parse( aStorage )) ))
Parse();
}
}
else
{
//bSuccess = ImportSM20File( pStream );
}
}
}
if ( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED )
{
//???OnDocumentPrinterChanged(0);
SetFormulaArranged( sal_False );
Repaint();
}
FinishedLoading( SFX_LOADED_ALL );
return bSuccess;
}
sal_Bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::InitNew" );
sal_Bool bRet = sal_False;
if ( SfxObjectShell::InitNew( xStorage ) )
{
bRet = sal_True;
SetVisArea(Rectangle(Point(0, 0), Size(2000, 1000)));
}
return bRet;
}
sal_Bool SmDocShell::Load( SfxMedium& rMedium )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Load" );
sal_Bool bRet = sal_False;
if( SfxObjectShell::Load( rMedium ))
{
uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
uno::Reference < container::XNameAccess > xAccess (xStorage, uno::UNO_QUERY);
if (
(
xAccess->hasByName( C2S( "content.xml" ) ) &&
xStorage->isStreamElement( C2S( "content.xml" ) )
) ||
(
xAccess->hasByName( C2S( "Content.xml" ) ) &&
xStorage->isStreamElement( C2S( "Content.xml" ) )
)
)
{
// is this a fabulous math package ?
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLImportWrapper aEquation(xModel);
sal_uLong nError = aEquation.Import(rMedium);
bRet = 0 == nError;
SetError( nError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
}
}
if ( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED )
{
//???OnDocumentPrinterChanged(0);
SetFormulaArranged( sal_False );
Repaint();
}
FinishedLoading( SFX_LOADED_ALL );
return bRet;
}
//------------------------------------------------------------------
sal_Bool SmDocShell::Save()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Save" );
//! apply latest changes if necessary
UpdateText();
if ( SfxObjectShell::Save() )
{
if (!pTree)
Parse();
if( pTree && !IsFormulaArranged() )
ArrangeFormula();
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLExportWrapper aEquation(xModel);
aEquation.SetFlat(sal_False);
return aEquation.Export(*GetMedium());
}
return sal_False;
}
/*
* replace bad characters that can not be saved. (#i74144)
* */
sal_Bool SmDocShell::ReplaceBadChars()
{
sal_Bool bReplace = sal_False;
if (pEditEngine)
{
String aEngTxt( pEditEngine->GetText( LINEEND_LF ) );
const sal_Unicode *pEngTxt = aEngTxt.GetBuffer();
xub_StrLen nLen = aEngTxt.Len();
for (xub_StrLen i = 0; i < nLen && !bReplace; ++i)
{
const sal_Unicode c = *pEngTxt++;
if (c < ' ' && c != '\r' && c != '\n' && c != '\t')
bReplace = sal_True;
}
if (bReplace)
{
sal_Unicode *pChgTxt = aEngTxt.GetBufferAccess();
for (xub_StrLen i = 0; i < nLen; ++i)
{
sal_Unicode &rc = *pChgTxt++;
if (rc < ' ' && rc != '\r' && rc != '\n' && rc != '\t')
rc = ' ';
}
aEngTxt.ReleaseBufferAccess( nLen );
aText = aEngTxt;
}
}
return bReplace;
}
void SmDocShell::UpdateText()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::UpdateText" );
if (pEditEngine && pEditEngine->IsModified())
{
String aEngTxt( pEditEngine->GetText( LINEEND_LF ) );
if (GetText() != aEngTxt)
SetText( aEngTxt );
}
}
sal_Bool SmDocShell::SaveAs( SfxMedium& rMedium )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SaveAs" );
sal_Bool bRet = sal_False;
//! apply latest changes if necessary
UpdateText();
if ( SfxObjectShell::SaveAs( rMedium ) )
{
if (!pTree)
Parse();
if( pTree && !IsFormulaArranged() )
ArrangeFormula();
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLExportWrapper aEquation(xModel);
aEquation.SetFlat(sal_False);
bRet = aEquation.Export(rMedium);
}
return bRet;
}
sal_Bool SmDocShell::ConvertTo( SfxMedium &rMedium )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::ConvertTo" );
sal_Bool bRet = sal_False;
const SfxFilter* pFlt = rMedium.GetFilter();
if( pFlt )
{
if( !pTree )
Parse();
if( pTree && !IsFormulaArranged() )
ArrangeFormula();
const String& rFltName = pFlt->GetFilterName();
if(rFltName.EqualsAscii( STAROFFICE_XML ))
{
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLExportWrapper aEquation(xModel);
aEquation.SetFlat(sal_False);
bRet = aEquation.Export(rMedium);
}
else if(rFltName.EqualsAscii( MATHML_XML ))
{
Reference<com::sun::star::frame::XModel> xModel(GetModel());
SmXMLExportWrapper aEquation(xModel);
aEquation.SetFlat(sal_True);
bRet = aEquation.Export(rMedium);
}
else if( pFlt->GetFilterName().EqualsAscii("MathType 3.x"))
bRet = WriteAsMathType3( rMedium );
}
return bRet;
}
sal_Bool SmDocShell::SaveCompleted( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SaveCompleted" );
if( SfxObjectShell::SaveCompleted( xStorage ))
return sal_True;
return sal_False;
}
void SmDocShell::Execute(SfxRequest& rReq)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Execute" );
switch (rReq.GetSlot())
{
case SID_TEXTMODE:
{
SmFormat aOldFormat = GetFormat();
SmFormat aNewFormat( aOldFormat );
aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
new SmFormatAction(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
break;
case SID_AUTO_REDRAW :
{
SmModule *pp = SM_MOD();
sal_Bool bRedraw = pp->GetConfig()->IsAutoRedraw();
pp->GetConfig()->SetAutoRedraw(!bRedraw);
}
break;
case SID_LOADSYMBOLS:
LoadSymbols();
break;
case SID_SAVESYMBOLS:
SaveSymbols();
break;
case SID_FONT:
{
// get device used to retrieve the FontList
OutputDevice *pDev = GetPrinter();
if (!pDev || pDev->GetDevFontCount() == 0)
pDev = &SM_MOD()->GetDefaultVirtualDev();
DBG_ASSERT (pDev, "device for font list missing" );
SmFontTypeDialog *pFontTypeDialog = new SmFontTypeDialog( NULL, pDev );
SmFormat aOldFormat = GetFormat();
pFontTypeDialog->ReadFrom( aOldFormat );
if (pFontTypeDialog->Execute() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
pFontTypeDialog->WriteTo(aNewFormat);
::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
new SmFormatAction(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
delete pFontTypeDialog;
}
break;
case SID_FONTSIZE:
{
SmFontSizeDialog *pFontSizeDialog = new SmFontSizeDialog(NULL);
SmFormat aOldFormat = GetFormat();
pFontSizeDialog->ReadFrom( aOldFormat );
if (pFontSizeDialog->Execute() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
pFontSizeDialog->WriteTo(aNewFormat);
::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
new SmFormatAction(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
delete pFontSizeDialog;
}
break;
case SID_DISTANCE:
{
SmDistanceDialog *pDistanceDialog = new SmDistanceDialog(NULL);
SmFormat aOldFormat = GetFormat();
pDistanceDialog->ReadFrom( aOldFormat );
if (pDistanceDialog->Execute() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
pDistanceDialog->WriteTo(aNewFormat);
::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
new SmFormatAction(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
delete pDistanceDialog;
}
break;
case SID_ALIGN:
{
SmAlignDialog *pAlignDialog = new SmAlignDialog(NULL);
SmFormat aOldFormat = GetFormat();
pAlignDialog->ReadFrom( aOldFormat );
if (pAlignDialog->Execute() == RET_OK)
{
SmFormat aNewFormat( aOldFormat );
pAlignDialog->WriteTo(aNewFormat);
SmModule *pp = SM_MOD();
SmFormat aFmt( pp->GetConfig()->GetStandardFormat() );
pAlignDialog->WriteTo( aFmt );
pp->GetConfig()->SetStandardFormat( aFmt );
::svl::IUndoManager *pTmpUndoMgr = GetUndoManager();
if (pTmpUndoMgr)
pTmpUndoMgr->AddUndoAction(
new SmFormatAction(this, aOldFormat, aNewFormat));
SetFormat( aNewFormat );
Repaint();
}
delete pAlignDialog;
}
break;
case SID_TEXT:
{
const SfxStringItem& rItem = (const SfxStringItem&)rReq.GetArgs()->Get(SID_TEXT);
if (GetText() != rItem.GetValue())
SetText(rItem.GetValue());
}
break;
case SID_UNDO:
case SID_REDO:
{
::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
if( pTmpUndoMgr )
{
sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
const SfxItemSet* pArgs = rReq.GetArgs();
const SfxPoolItem* pItem;
if( pArgs && SFX_ITEM_SET == pArgs->GetItemState( nId, sal_False, &pItem ))
nCnt = ((SfxUInt16Item*)pItem)->GetValue();
sal_Bool (::svl::IUndoManager:: *fnDo)();
sal_uInt16 nCount;
if( SID_UNDO == rReq.GetSlot() )
{
nCount = pTmpUndoMgr->GetUndoActionCount();
fnDo = &::svl::IUndoManager::Undo;
}
else
{
nCount = pTmpUndoMgr->GetRedoActionCount();
fnDo = &::svl::IUndoManager::Redo;
}
try
{
for( ; nCnt && nCount; --nCnt, --nCount )
(pTmpUndoMgr->*fnDo)();
}
catch( const Exception& e )
{
DBG_UNHANDLED_EXCEPTION();
}
}
SmModule *pModule = SM_MOD();
if ( pModule && pModule->GetConfig()->IsAutoRedraw() )
UpdateText();
Repaint();
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
while( pFrm )
{
SfxBindings& rBind = pFrm->GetBindings();
rBind.Invalidate(SID_UNDO);
rBind.Invalidate(SID_REDO);
rBind.Invalidate(SID_REPEAT);
rBind.Invalidate(SID_CLEARHISTORY);
pFrm = SfxViewFrame::GetNext( *pFrm, this );
}
}
break;
}
rReq.Done();
}
void SmDocShell::GetState(SfxItemSet &rSet)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetState" );
SfxWhichIter aIter(rSet);
for (sal_uInt16 nWh = aIter.FirstWhich(); 0 != nWh; nWh = aIter.NextWhich())
{
switch (nWh)
{
case SID_TEXTMODE:
rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
break;
case SID_DOCTEMPLATE :
rSet.DisableItem(SID_DOCTEMPLATE);
break;
case SID_AUTO_REDRAW :
{
SmModule *pp = SM_MOD();
sal_Bool bRedraw = pp->GetConfig()->IsAutoRedraw();
rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, bRedraw));
}
break;
case SID_MODIFYSTATUS:
{
sal_Unicode cMod = ' ';
if (IsModified())
cMod = '*';
rSet.Put(SfxStringItem(SID_MODIFYSTATUS, String(cMod)));
}
break;
case SID_TEXT:
rSet.Put(SfxStringItem(SID_TEXT, GetText()));
break;
case SID_GAPHIC_SM:
//! very old (pre UNO) and ugly hack to invalidate the SmGraphicWindow.
//! If nModifyCount gets changed then the call below will implicitly notify
//! SmGraphicController::StateChanged and there the window gets invalidated.
//! Thus all the 'nModifyCount++' before invalidating this slot.
rSet.Put(SfxInt16Item(SID_GAPHIC_SM, nModifyCount));
break;
case SID_UNDO:
case SID_REDO:
{
SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
if( pFrm )
pFrm->GetSlotState( nWh, NULL, &rSet );
else
rSet.DisableItem( nWh );
}
break;
case SID_GETUNDOSTRINGS:
case SID_GETREDOSTRINGS:
{
::svl::IUndoManager* pTmpUndoMgr = GetUndoManager();
if( pTmpUndoMgr )
{
UniString(::svl::IUndoManager:: *fnGetComment)( size_t, bool const ) const;
sal_uInt16 nCount;
if( SID_GETUNDOSTRINGS == nWh )
{
nCount = pTmpUndoMgr->GetUndoActionCount();
fnGetComment = &::svl::IUndoManager::GetUndoActionComment;
}
else
{
nCount = pTmpUndoMgr->GetRedoActionCount();
fnGetComment = &::svl::IUndoManager::GetRedoActionComment;
}
if( nCount )
{
String sList;
for( sal_uInt16 n = 0; n < nCount; ++n )
( sList += (pTmpUndoMgr->*fnGetComment)( n, ::svl::IUndoManager::TopLevel ) )
+= '\n';
SfxStringListItem aItem( nWh );
aItem.SetString( sList );
rSet.Put( aItem );
}
}
else
rSet.DisableItem( nWh );
}
break;
}
}
}
::svl::IUndoManager *SmDocShell::GetUndoManager()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::GetUndoManager" );
if (!pEditEngine)
GetEditEngine();
return &pEditEngine->GetUndoManager();
}
void SmDocShell::SaveSymbols()
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SaveSymbols" );
SmModule *pp = SM_MOD();
pp->GetSymbolManager().Save();
}
void SmDocShell::Draw(OutputDevice *pDevice,
const JobSetup &,
sal_uInt16 /*nAspect*/)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Draw" );
pDevice->IntersectClipRegion(GetVisArea());
Point atmppoint;
Draw(*pDevice, atmppoint);
}
SfxItemPool& SmDocShell::GetPool() const
{
return SFX_APP()->GetPool();
}
void SmDocShell::SetVisArea(const Rectangle & rVisArea)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetVisArea" );
Rectangle aNewRect(rVisArea);
aNewRect.SetPos(Point());
if (! aNewRect.Right()) aNewRect.Right() = 2000;
if (! aNewRect.Bottom()) aNewRect.Bottom() = 1000;
sal_Bool bIsEnabled = IsEnableSetModified();
if ( bIsEnabled )
EnableSetModified( sal_False );
//TODO/LATER: it's unclear how this interacts with the SFX code
// If outplace editing, then dont resize the OutplaceWindow. But the
// ObjectShell has to resize. Bug 56470
sal_Bool bUnLockFrame;
if( GetCreateMode() == SFX_CREATE_MODE_EMBEDDED && !IsInPlaceActive() && GetFrame() )
{
GetFrame()->LockAdjustPosSizePixel();
bUnLockFrame = sal_True;
}
else
bUnLockFrame = sal_False;
SfxObjectShell::SetVisArea( aNewRect );
if( bUnLockFrame )
GetFrame()->UnlockAdjustPosSizePixel();
if ( bIsEnabled )
EnableSetModified( bIsEnabled );
}
void SmDocShell::FillClass(SvGlobalName* pClassName,
sal_uInt32* pFormat,
String* /*pAppName*/,
String* pFullTypeName,
String* pShortTypeName,
sal_Int32 nFileFormat,
sal_Bool bTemplate /* = sal_False */) const
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::FillClass" );
if (nFileFormat == SOFFICE_FILEFORMAT_60 )
{
*pClassName = SvGlobalName(SO3_SM_CLASSID_60);
*pFormat = SOT_FORMATSTR_ID_STARMATH_60;
*pFullTypeName = String(SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT));
*pShortTypeName = String(SmResId(RID_DOCUMENTSTR));
}
else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
{
*pClassName = SvGlobalName(SO3_SM_CLASSID_60);
*pFormat = bTemplate ? SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE : SOT_FORMATSTR_ID_STARMATH_8;
*pFullTypeName = String(SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT));
*pShortTypeName = String(SmResId(RID_DOCUMENTSTR));
}
}
sal_uLong SmDocShell::GetMiscStatus() const
{
return SfxObjectShell::GetMiscStatus() | SVOBJ_MISCSTATUS_NOTRESIZEABLE
| SVOBJ_MISCSTATUS_RESIZEONPRINTERCHANGE;
}
void SmDocShell::SetModified(sal_Bool bModified)
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SetModified" );
if( IsEnableSetModified() )
{
SfxObjectShell::SetModified( bModified );
Broadcast(SfxSimpleHint(SFX_HINT_DOCCHANGED));
}
}
sal_Bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
{
RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::WriteAsMathType3" );
MathType aEquation( aText, pTree );
sal_Bool bRet = 0 != aEquation.ConvertFromStarMath( rMedium );
return bRet;
}