1502 lines
51 KiB
C++
1502 lines
51 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
/*
|
|
Warning: The SvXMLElementExport helper class creates the beginning and
|
|
closing tags of xml elements in its constructor and destructor, so theres
|
|
hidden stuff going on, on occasion the ordering of these classes declarations
|
|
may be significant
|
|
*/
|
|
|
|
|
|
#include <com/sun/star/xml/sax/XErrorHandler.hpp>
|
|
#include <com/sun/star/xml/sax/XEntityResolver.hpp>
|
|
#include <com/sun/star/xml/sax/InputSource.hpp>
|
|
#include <com/sun/star/xml/sax/XDTDHandler.hpp>
|
|
#include <com/sun/star/xml/sax/XParser.hpp>
|
|
#include <com/sun/star/io/XActiveDataSource.hpp>
|
|
#include <com/sun/star/io/XActiveDataControl.hpp>
|
|
#include <com/sun/star/document/XDocumentProperties.hpp>
|
|
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
|
|
#include <com/sun/star/packages/zip/ZipIOException.hpp>
|
|
#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
|
|
#include <com/sun/star/beans/PropertyAttribute.hpp>
|
|
#include <com/sun/star/container/XNameAccess.hpp>
|
|
#include <com/sun/star/embed/ElementModes.hpp>
|
|
#include <com/sun/star/util/MeasureUnit.hpp>
|
|
#include <com/sun/star/uno/Any.h>
|
|
|
|
#include <rtl/math.hxx>
|
|
#include <sfx2/frame.hxx>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <svtools/sfxecode.hxx>
|
|
#include <unotools/saveopt.hxx>
|
|
#include <svl/stritem.hxx>
|
|
#include <svl/itemprop.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <unotools/streamwrap.hxx>
|
|
#include <sax/tools/converter.hxx>
|
|
#include <xmloff/xmlnmspe.hxx>
|
|
#include <xmloff/xmltoken.hxx>
|
|
#include <xmloff/nmspmap.hxx>
|
|
#include <xmloff/attrlist.hxx>
|
|
#include <xmloff/xmlmetai.hxx>
|
|
#include <osl/mutex.hxx>
|
|
#include <comphelper/genericpropertyset.hxx>
|
|
#include <comphelper/servicehelper.hxx>
|
|
|
|
#include <memory>
|
|
|
|
#include "mathmlexport.hxx"
|
|
#include <starmath.hrc>
|
|
#include <unomodel.hxx>
|
|
#include <document.hxx>
|
|
#include <utility.hxx>
|
|
#include <config.hxx>
|
|
|
|
using namespace ::com::sun::star::beans;
|
|
using namespace ::com::sun::star::container;
|
|
using namespace ::com::sun::star::document;
|
|
using namespace ::com::sun::star::lang;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star;
|
|
using namespace ::xmloff::token;
|
|
|
|
using ::rtl::OUString;
|
|
using ::rtl::OUStringBuffer;
|
|
|
|
#define EXPORT_SVC_NAME "com.sun.star.xml.XMLExportFilter"
|
|
|
|
#undef WANTEXCEPT
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
sal_Bool SmXMLExportWrapper::Export(SfxMedium &rMedium)
|
|
{
|
|
sal_Bool bRet=sal_True;
|
|
uno::Reference<lang::XMultiServiceFactory>
|
|
xServiceFactory(comphelper::getProcessServiceFactory());
|
|
OSL_ENSURE(xServiceFactory.is(),"got no service manager");
|
|
|
|
//Get model
|
|
uno::Reference< lang::XComponent > xModelComp(xModel, uno::UNO_QUERY );
|
|
|
|
sal_Bool bEmbedded = sal_False;
|
|
uno::Reference <lang::XUnoTunnel> xTunnel;
|
|
xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
|
|
SmModel *pModel = reinterpret_cast<SmModel *>
|
|
(xTunnel->getSomething(SmModel::getUnoTunnelId()));
|
|
|
|
SmDocShell *pDocShell = pModel ?
|
|
static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
|
|
if ( pDocShell &&
|
|
SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() )
|
|
bEmbedded = sal_True;
|
|
|
|
uno::Reference<task::XStatusIndicator> xStatusIndicator;
|
|
if (!bEmbedded)
|
|
{
|
|
if (pDocShell /*&& pDocShell->GetMedium()*/)
|
|
{
|
|
OSL_ENSURE( pDocShell->GetMedium() == &rMedium,
|
|
"different SfxMedium found" );
|
|
|
|
SfxItemSet* pSet = rMedium.GetItemSet();
|
|
if (pSet)
|
|
{
|
|
const SfxUnoAnyItem* pItem = static_cast<const SfxUnoAnyItem*>(
|
|
pSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL) );
|
|
if (pItem)
|
|
pItem->GetValue() >>= xStatusIndicator;
|
|
}
|
|
}
|
|
|
|
// set progress range and start status indicator
|
|
if (xStatusIndicator.is())
|
|
{
|
|
sal_Int32 nProgressRange = bFlat ? 1 : 3;
|
|
xStatusIndicator->start(String(SmResId(STR_STATSTR_WRITING)),
|
|
nProgressRange);
|
|
}
|
|
}
|
|
|
|
|
|
// create XPropertySet with three properties for status indicator
|
|
comphelper::PropertyMapEntry aInfoMap[] =
|
|
{
|
|
{ "UsePrettyPrinting", sizeof("UsePrettyPrinting")-1, 0,
|
|
&::getBooleanCppuType(),
|
|
beans::PropertyAttribute::MAYBEVOID, 0},
|
|
{ "BaseURI", sizeof("BaseURI")-1, 0,
|
|
&::getCppuType( (OUString *)0 ),
|
|
beans::PropertyAttribute::MAYBEVOID, 0 },
|
|
{ "StreamRelPath", sizeof("StreamRelPath")-1, 0,
|
|
&::getCppuType( (OUString *)0 ),
|
|
beans::PropertyAttribute::MAYBEVOID, 0 },
|
|
{ "StreamName", sizeof("StreamName")-1, 0,
|
|
&::getCppuType( (OUString *)0 ),
|
|
beans::PropertyAttribute::MAYBEVOID, 0 },
|
|
{ NULL, 0, 0, NULL, 0, 0 }
|
|
};
|
|
uno::Reference< beans::XPropertySet > xInfoSet(
|
|
comphelper::GenericPropertySet_CreateInstance(
|
|
new comphelper::PropertySetInfo( aInfoMap ) ) );
|
|
|
|
SvtSaveOptions aSaveOpt;
|
|
OUString sUsePrettyPrinting("UsePrettyPrinting");
|
|
sal_Bool bUsePrettyPrinting( bFlat || aSaveOpt.IsPrettyPrinting() );
|
|
Any aAny;
|
|
aAny.setValue( &bUsePrettyPrinting, ::getBooleanCppuType() );
|
|
xInfoSet->setPropertyValue( sUsePrettyPrinting, aAny );
|
|
|
|
// Set base URI
|
|
OUString sPropName( "BaseURI" );
|
|
xInfoSet->setPropertyValue( sPropName, makeAny( rMedium.GetBaseURL( true ) ) );
|
|
|
|
sal_Int32 nSteps=0;
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->setValue(nSteps++);
|
|
if (!bFlat) //Storage (Package) of Stream
|
|
{
|
|
uno::Reference < embed::XStorage > xStg = rMedium.GetOutputStorage();
|
|
sal_Bool bOASIS = ( SotStorage::GetVersion( xStg ) > SOFFICE_FILEFORMAT_60 );
|
|
|
|
// TODO/LATER: handle the case of embedded links gracefully
|
|
if ( bEmbedded ) //&& !pStg->IsRoot() )
|
|
{
|
|
OUString aName;
|
|
if ( rMedium.GetItemSet() )
|
|
{
|
|
const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
|
|
rMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
|
|
if ( pDocHierarchItem )
|
|
aName = pDocHierarchItem->GetValue();
|
|
}
|
|
|
|
if ( !aName.isEmpty() )
|
|
{
|
|
sPropName = "StreamRelPath";
|
|
xInfoSet->setPropertyValue( sPropName, makeAny( aName ) );
|
|
}
|
|
}
|
|
|
|
if ( !bEmbedded )
|
|
{
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->setValue(nSteps++);
|
|
|
|
bRet = WriteThroughComponent(
|
|
xStg, xModelComp, "meta.xml", xServiceFactory, xInfoSet,
|
|
(bOASIS ? "com.sun.star.comp.Math.XMLOasisMetaExporter"
|
|
: "com.sun.star.comp.Math.XMLMetaExporter"),
|
|
sal_False);
|
|
}
|
|
if ( bRet )
|
|
{
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->setValue(nSteps++);
|
|
|
|
bRet = WriteThroughComponent(
|
|
xStg, xModelComp, "content.xml", xServiceFactory, xInfoSet,
|
|
"com.sun.star.comp.Math.XMLContentExporter");
|
|
}
|
|
|
|
if ( bRet )
|
|
{
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->setValue(nSteps++);
|
|
|
|
bRet = WriteThroughComponent(
|
|
xStg, xModelComp, "settings.xml", xServiceFactory, xInfoSet,
|
|
(bOASIS ? "com.sun.star.comp.Math.XMLOasisSettingsExporter"
|
|
: "com.sun.star.comp.Math.XMLSettingsExporter") );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SvStream *pStream = rMedium.GetOutStream();
|
|
uno::Reference<io::XOutputStream> xOut(
|
|
new utl::OOutputStreamWrapper(*pStream) );
|
|
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->setValue(nSteps++);
|
|
|
|
bRet = WriteThroughComponent(
|
|
xOut, xModelComp, xServiceFactory, xInfoSet,
|
|
"com.sun.star.comp.Math.XMLContentExporter");
|
|
}
|
|
|
|
if (xStatusIndicator.is())
|
|
xStatusIndicator->end();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/// export through an XML exporter component (output stream version)
|
|
sal_Bool SmXMLExportWrapper::WriteThroughComponent(
|
|
Reference<io::XOutputStream> xOutputStream,
|
|
Reference<XComponent> xComponent,
|
|
Reference<lang::XMultiServiceFactory> & rFactory,
|
|
Reference<beans::XPropertySet> & rPropSet,
|
|
const sal_Char* pComponentName )
|
|
{
|
|
OSL_ENSURE(xOutputStream.is(), "I really need an output stream!");
|
|
OSL_ENSURE(xComponent.is(), "Need component!");
|
|
OSL_ENSURE(NULL != pComponentName, "Need component name!");
|
|
|
|
// get component
|
|
Reference< io::XActiveDataSource > xSaxWriter(
|
|
rFactory->createInstance( "com.sun.star.xml.sax.Writer" ),
|
|
UNO_QUERY );
|
|
OSL_ENSURE( xSaxWriter.is(), "can't instantiate XML writer" );
|
|
if (!xSaxWriter.is())
|
|
return sal_False;
|
|
|
|
// connect XML writer to output stream
|
|
xSaxWriter->setOutputStream( xOutputStream );
|
|
|
|
// prepare arguments (prepend doc handler to given arguments)
|
|
Reference<xml::sax::XDocumentHandler> xDocHandler( xSaxWriter,UNO_QUERY);
|
|
|
|
Sequence<Any> aArgs( 2 );
|
|
aArgs[0] <<= xDocHandler;
|
|
aArgs[1] <<= rPropSet;
|
|
|
|
// get filter component
|
|
Reference< document::XExporter > xExporter(
|
|
rFactory->createInstanceWithArguments(
|
|
OUString::createFromAscii(pComponentName), aArgs), UNO_QUERY);
|
|
OSL_ENSURE( xExporter.is(),
|
|
"can't instantiate export filter component" );
|
|
if ( !xExporter.is() )
|
|
return sal_False;
|
|
|
|
|
|
// connect model and filter
|
|
xExporter->setSourceDocument( xComponent );
|
|
|
|
// filter!
|
|
Reference < XFilter > xFilter( xExporter, UNO_QUERY );
|
|
uno::Sequence< PropertyValue > aProps(0);
|
|
xFilter->filter( aProps );
|
|
|
|
uno::Reference<lang::XUnoTunnel> xFilterTunnel;
|
|
xFilterTunnel = uno::Reference<lang::XUnoTunnel>
|
|
( xFilter, uno::UNO_QUERY );
|
|
SmXMLExport *pFilter = reinterpret_cast< SmXMLExport * >(
|
|
sal::static_int_cast< sal_uIntPtr >(
|
|
xFilterTunnel->getSomething( SmXMLExport::getUnoTunnelId() )));
|
|
return pFilter ? pFilter->GetSuccess() : sal_True;
|
|
}
|
|
|
|
|
|
/// export through an XML exporter component (storage version)
|
|
sal_Bool SmXMLExportWrapper::WriteThroughComponent(
|
|
const Reference < embed::XStorage >& xStorage,
|
|
Reference<XComponent> xComponent,
|
|
const sal_Char* pStreamName,
|
|
Reference<lang::XMultiServiceFactory> & rFactory,
|
|
Reference<beans::XPropertySet> & rPropSet,
|
|
const sal_Char* pComponentName,
|
|
sal_Bool bCompress
|
|
)
|
|
{
|
|
OSL_ENSURE(xStorage.is(), "Need storage!");
|
|
OSL_ENSURE(NULL != pStreamName, "Need stream name!");
|
|
|
|
// open stream
|
|
Reference < io::XStream > xStream;
|
|
OUString sStreamName = OUString::createFromAscii(pStreamName);
|
|
try
|
|
{
|
|
xStream = xStorage->openStreamElement( sStreamName,
|
|
embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
|
|
}
|
|
catch ( uno::Exception& )
|
|
{
|
|
OSL_FAIL( "Can't create output stream in package!" );
|
|
return sal_False;
|
|
}
|
|
|
|
OUString aPropName( "MediaType" );
|
|
OUString aMime( "text/xml" );
|
|
uno::Any aAny;
|
|
aAny <<= aMime;
|
|
|
|
uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
|
|
xSet->setPropertyValue( aPropName, aAny );
|
|
|
|
if ( !bCompress )
|
|
{
|
|
aPropName = "Compressed";
|
|
sal_Bool bFalse = sal_False;
|
|
aAny.setValue( &bFalse, ::getBooleanCppuType() );
|
|
xSet->setPropertyValue( aPropName, aAny );
|
|
}
|
|
|
|
// even plain stream must be encrypted in encrypted document
|
|
OUString aTmpPropName( "UseCommonStoragePasswordEncryption" );
|
|
sal_Bool bTrue = sal_True;
|
|
aAny.setValue( &bTrue, ::getBooleanCppuType() );
|
|
xSet->setPropertyValue( aTmpPropName, aAny );
|
|
|
|
// set Base URL
|
|
if ( rPropSet.is() )
|
|
{
|
|
OUString sPropName( "StreamName" );
|
|
rPropSet->setPropertyValue( sPropName, makeAny( sStreamName ) );
|
|
}
|
|
|
|
// write the stuff
|
|
sal_Bool bRet = WriteThroughComponent( xStream->getOutputStream(), xComponent, rFactory,
|
|
rPropSet, pComponentName );
|
|
|
|
return bRet;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
SmXMLExport::SmXMLExport(
|
|
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
|
|
sal_uInt16 nExportFlags)
|
|
: SvXMLExport(util::MeasureUnit::INCH, xServiceFactory, XML_MATH,
|
|
nExportFlags)
|
|
, pTree(0) ,
|
|
bSuccess(sal_False)
|
|
{
|
|
}
|
|
|
|
sal_Int64 SAL_CALL SmXMLExport::getSomething(
|
|
const uno::Sequence< sal_Int8 >& rId )
|
|
throw(uno::RuntimeException)
|
|
{
|
|
if ( rId.getLength() == 16 &&
|
|
0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
|
|
rId.getConstArray(), 16 ) )
|
|
return sal::static_int_cast< sal_Int64 >(reinterpret_cast< sal_uIntPtr >(this));
|
|
|
|
return SvXMLExport::getSomething( rId );
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class theSmXMLExportUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSmXMLExportUnoTunnelId> {};
|
|
}
|
|
|
|
const uno::Sequence< sal_Int8 > & SmXMLExport::getUnoTunnelId() throw()
|
|
{
|
|
return theSmXMLExportUnoTunnelId::get().getSeq();
|
|
}
|
|
|
|
OUString SAL_CALL SmXMLExport_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExport_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExport_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
// EXPORT_OASIS is required here allthough there is no differrence between
|
|
// OOo and OASIS, because without the flag, a transformation to OOo would
|
|
// be chained in.
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_ALL );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
OUString SAL_CALL SmXMLExportMetaOOO_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLMetaExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExportMetaOOO_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMetaOOO_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_META );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
OUString SAL_CALL SmXMLExportMeta_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLOasisMetaExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExportMeta_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMeta_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_META );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
OUString SAL_CALL SmXMLExportSettingsOOO_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLSettingsExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExportSettingsOOO_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettingsOOO_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_SETTINGS );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
OUString SAL_CALL SmXMLExportSettings_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLOasisSettingsExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExportSettings_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettings_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_SETTINGS );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
OUString SAL_CALL SmXMLExportContent_getImplementationName() throw()
|
|
{
|
|
return OUString( "com.sun.star.comp.Math.XMLContentExporter" );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL SmXMLExportContent_getSupportedServiceNames()
|
|
throw()
|
|
{
|
|
const OUString aServiceName( EXPORT_SVC_NAME );
|
|
const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
|
|
return aSeq;
|
|
}
|
|
|
|
uno::Reference< uno::XInterface > SAL_CALL SmXMLExportContent_createInstance(
|
|
const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
|
|
throw( uno::Exception )
|
|
{
|
|
// The EXPORT_OASIS flag is only required to avoid that a transformer is
|
|
// chanied in
|
|
return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_CONTENT );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// XServiceInfo
|
|
// override empty method from parent class
|
|
rtl::OUString SAL_CALL SmXMLExport::getImplementationName()
|
|
throw(uno::RuntimeException)
|
|
{
|
|
OUString aTxt;
|
|
switch( getExportFlags() )
|
|
{
|
|
case EXPORT_META:
|
|
aTxt = SmXMLExportMeta_getImplementationName();
|
|
break;
|
|
case EXPORT_SETTINGS:
|
|
aTxt = SmXMLExportSettings_getImplementationName();
|
|
break;
|
|
case EXPORT_CONTENT:
|
|
aTxt = SmXMLExportContent_getImplementationName();
|
|
break;
|
|
case EXPORT_ALL:
|
|
default:
|
|
aTxt = SmXMLExport_getImplementationName();
|
|
break;
|
|
}
|
|
return aTxt;
|
|
}
|
|
|
|
sal_uInt32 SmXMLExport::exportDoc(enum XMLTokenEnum eClass)
|
|
{
|
|
if ( (getExportFlags() & EXPORT_CONTENT) == 0 )
|
|
{
|
|
SvXMLExport::exportDoc( eClass );
|
|
}
|
|
else
|
|
{
|
|
uno::Reference <frame::XModel> xModel = GetModel();
|
|
uno::Reference <lang::XUnoTunnel> xTunnel;
|
|
xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
|
|
SmModel *pModel = reinterpret_cast<SmModel *>
|
|
(xTunnel->getSomething(SmModel::getUnoTunnelId()));
|
|
|
|
if (pModel)
|
|
{
|
|
SmDocShell *pDocShell =
|
|
static_cast<SmDocShell*>(pModel->GetObjectShell());
|
|
pTree = pDocShell->GetFormulaTree();
|
|
aText = pDocShell->GetText();
|
|
}
|
|
|
|
GetDocHandler()->startDocument();
|
|
|
|
addChaffWhenEncryptedStorage();
|
|
|
|
/*Add xmlns line*/
|
|
SvXMLAttributeList &rList = GetAttrList();
|
|
|
|
// make use of a default namespace
|
|
ResetNamespaceMap(); // Math doesn't need namespaces from xmloff, since it now uses default namespaces (because that is common with current MathML usage in the web)
|
|
_GetNamespaceMap().Add( OUString(), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
|
|
|
|
rList.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX),
|
|
GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX));
|
|
|
|
//I think we need something like ImplExportEntities();
|
|
_ExportContent();
|
|
GetDocHandler()->endDocument();
|
|
}
|
|
|
|
bSuccess=sal_True;
|
|
return 0;
|
|
}
|
|
|
|
void SmXMLExport::_ExportContent()
|
|
{
|
|
SvXMLElementExport aEquation(*this, XML_NAMESPACE_MATH, XML_MATH, sal_True, sal_True);
|
|
SvXMLElementExport *pSemantics=0;
|
|
|
|
if (aText.Len())
|
|
{
|
|
pSemantics = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_SEMANTICS, sal_True, sal_True);
|
|
}
|
|
|
|
ExportNodes(pTree, 0);
|
|
|
|
if (aText.Len())
|
|
{
|
|
// Convert symbol names
|
|
uno::Reference <frame::XModel> xModel = GetModel();
|
|
uno::Reference <lang::XUnoTunnel> xTunnel;
|
|
xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
|
|
SmModel *pModel = reinterpret_cast<SmModel *>
|
|
(xTunnel->getSomething(SmModel::getUnoTunnelId()));
|
|
SmDocShell *pDocShell = pModel ?
|
|
static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
|
|
OSL_ENSURE( pDocShell, "doc shell missing" );
|
|
if (pDocShell)
|
|
{
|
|
SmParser &rParser = pDocShell->GetParser();
|
|
bool bVal = rParser.IsExportSymbolNames();
|
|
rParser.SetExportSymbolNames( true );
|
|
SmNode *pTmpTree = rParser.Parse( aText );
|
|
aText = rParser.GetText();
|
|
delete pTmpTree;
|
|
rParser.SetExportSymbolNames( bVal );
|
|
}
|
|
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_ENCODING,
|
|
OUString("StarMath 5.0"));
|
|
SvXMLElementExport aAnnotation(*this, XML_NAMESPACE_MATH,
|
|
XML_ANNOTATION, sal_True, sal_False);
|
|
GetDocHandler()->characters(OUString( aText ));
|
|
}
|
|
delete pSemantics;
|
|
}
|
|
|
|
void SmXMLExport::GetViewSettings( Sequence < PropertyValue >& aProps)
|
|
{
|
|
uno::Reference <frame::XModel> xModel = GetModel();
|
|
if ( !xModel.is() )
|
|
return;
|
|
|
|
uno::Reference <lang::XUnoTunnel> xTunnel;
|
|
xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
|
|
SmModel *pModel = reinterpret_cast<SmModel *>
|
|
(xTunnel->getSomething(SmModel::getUnoTunnelId()));
|
|
|
|
if ( !pModel )
|
|
return;
|
|
|
|
SmDocShell *pDocShell =
|
|
static_cast<SmDocShell*>(pModel->GetObjectShell());
|
|
if ( !pDocShell )
|
|
return;
|
|
|
|
aProps.realloc( 4 );
|
|
PropertyValue *pValue = aProps.getArray();
|
|
sal_Int32 nIndex = 0;
|
|
|
|
Rectangle aRect( pDocShell->GetVisArea() );
|
|
|
|
pValue[nIndex].Name = "ViewAreaTop";
|
|
pValue[nIndex++].Value <<= aRect.Top();
|
|
|
|
pValue[nIndex].Name = "ViewAreaLeft";
|
|
pValue[nIndex++].Value <<= aRect.Left();
|
|
|
|
pValue[nIndex++].Value <<= aRect.GetWidth();
|
|
|
|
pValue[nIndex].Name = "ViewAreaHeight";
|
|
pValue[nIndex++].Value <<= aRect.GetHeight();
|
|
}
|
|
|
|
void SmXMLExport::GetConfigurationSettings( Sequence < PropertyValue > & rProps)
|
|
{
|
|
Reference < XPropertySet > xProps ( GetModel(), UNO_QUERY );
|
|
if ( xProps.is() )
|
|
{
|
|
Reference< XPropertySetInfo > xPropertySetInfo = xProps->getPropertySetInfo();
|
|
if (xPropertySetInfo.is())
|
|
{
|
|
Sequence< Property > aProps = xPropertySetInfo->getProperties();
|
|
sal_Int32 nCount(aProps.getLength());
|
|
if (nCount > 0)
|
|
{
|
|
rProps.realloc(nCount);
|
|
PropertyValue* pProps = rProps.getArray();
|
|
if (pProps)
|
|
{
|
|
SmConfig *pConfig = SM_MOD()->GetConfig();
|
|
const bool bUsedSymbolsOnly = pConfig ? pConfig->IsSaveOnlyUsedSymbols() : false;
|
|
|
|
const OUString sFormula ( "Formula" );
|
|
const OUString sBasicLibraries ( "BasicLibraries" );
|
|
const OUString sDialogLibraries ( "DialogLibraries" );
|
|
const OUString sRuntimeUID ( "RuntimeUID" );
|
|
for (sal_Int32 i = 0; i < nCount; i++, pProps++)
|
|
{
|
|
const OUString &rPropName = aProps[i].Name;
|
|
if (rPropName != sFormula &&
|
|
rPropName != sBasicLibraries &&
|
|
rPropName != sDialogLibraries &&
|
|
rPropName != sRuntimeUID)
|
|
{
|
|
pProps->Name = rPropName;
|
|
|
|
rtl::OUString aActualName( rPropName );
|
|
|
|
// handle 'save used symbols only'
|
|
if (bUsedSymbolsOnly && rPropName == "Symbols" )
|
|
aActualName = "UserDefinedSymbolsInUse";
|
|
|
|
pProps->Value = xProps->getPropertyValue( aActualName );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmXMLExport::ExportLine(const SmNode *pNode, int nLevel)
|
|
{
|
|
ExportExpression(pNode, nLevel);
|
|
}
|
|
|
|
void SmXMLExport::ExportBinaryHorizontal(const SmNode *pNode, int nLevel)
|
|
{
|
|
ExportExpression(pNode, nLevel);
|
|
}
|
|
|
|
void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel)
|
|
{
|
|
ExportExpression(pNode, nLevel);
|
|
}
|
|
|
|
void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel)
|
|
{
|
|
SvXMLElementExport *pRow=0;
|
|
sal_uLong nSize = pNode->GetNumSubNodes();
|
|
|
|
// #i115443: nodes of type expression always need to be grouped with mrow statement
|
|
if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION))
|
|
pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True);
|
|
|
|
for (sal_uInt16 i = 0; i < nSize; i++)
|
|
if (const SmNode *pTemp = pNode->GetSubNode(i))
|
|
ExportNodes(pTemp, nLevel+1);
|
|
|
|
delete pRow;
|
|
}
|
|
|
|
void SmXMLExport::ExportBinaryVertical(const SmNode *pNode, int nLevel)
|
|
{
|
|
OSL_ENSURE(pNode->GetNumSubNodes()==3,"Bad Fraction");
|
|
SvXMLElementExport aFraction(*this, XML_NAMESPACE_MATH, XML_MFRAC, sal_True, sal_True);
|
|
ExportNodes(pNode->GetSubNode(0), nLevel);
|
|
ExportNodes(pNode->GetSubNode(2), nLevel);
|
|
}
|
|
|
|
void SmXMLExport::ExportTable(const SmNode *pNode, int nLevel)
|
|
{
|
|
SvXMLElementExport *pTable=0;
|
|
|
|
sal_uInt16 nSize = pNode->GetNumSubNodes();
|
|
|
|
//If the list ends in newline then the last entry has
|
|
//no subnodes, the newline is superfulous so we just drop
|
|
//the last node, inclusion would create a bad MathML
|
|
//table
|
|
if (nSize >= 1 && pNode->GetSubNode(nSize-1)->GetNumSubNodes() == 0)
|
|
--nSize;
|
|
|
|
// try to avoid creating a mtable element when the formula consists only
|
|
// of a single output line
|
|
if (nLevel || (nSize >1))
|
|
pTable = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
|
|
|
|
for (sal_uInt16 i = 0; i < nSize; i++)
|
|
if (const SmNode *pTemp = pNode->GetSubNode(i))
|
|
{
|
|
SvXMLElementExport *pRow=0;
|
|
SvXMLElementExport *pCell=0;
|
|
if (pTable)
|
|
{
|
|
pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
|
|
pCell = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
|
|
}
|
|
ExportNodes(pTemp, nLevel+1);
|
|
delete pCell;
|
|
delete pRow;
|
|
}
|
|
|
|
delete pTable;
|
|
}
|
|
|
|
void SmXMLExport::ExportMath(const SmNode *pNode, int /*nLevel*/)
|
|
{
|
|
const SmMathSymbolNode *pTemp = static_cast<const SmMathSymbolNode *>(pNode);
|
|
SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, sal_True, sal_False);
|
|
sal_Unicode nArse[2];
|
|
nArse[0] = pTemp->GetText().GetChar(0);
|
|
sal_Unicode cTmp = ConvertMathToMathML( nArse[0] );
|
|
if (cTmp != 0)
|
|
nArse[0] = cTmp;
|
|
OSL_ENSURE(nArse[0] != 0xffff,"Non existent symbol");
|
|
nArse[1] = 0;
|
|
GetDocHandler()->characters(nArse);
|
|
}
|
|
|
|
void SmXMLExport::ExportText(const SmNode *pNode, int /*nLevel*/)
|
|
{
|
|
SvXMLElementExport *pText;
|
|
const SmTextNode *pTemp = static_cast<const SmTextNode *>(pNode);
|
|
switch (pNode->GetToken().eType)
|
|
{
|
|
default:
|
|
case TIDENT:
|
|
{
|
|
//Note that we change the fontstyle to italic for strings that
|
|
//are italic and longer than a single character.
|
|
sal_Bool bIsItalic = IsItalic( pTemp->GetFont() );
|
|
if ((pTemp->GetText().Len() > 1) && bIsItalic)
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_ITALIC);
|
|
else if ((pTemp->GetText().Len() == 1) && !bIsItalic)
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_NORMAL);
|
|
pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI,sal_True,sal_False);
|
|
break;
|
|
}
|
|
case TNUMBER:
|
|
pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MN,sal_True,sal_False);
|
|
break;
|
|
case TTEXT:
|
|
pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTEXT,sal_True,sal_False);
|
|
break;
|
|
}
|
|
GetDocHandler()->characters(OUString(pTemp->GetText().GetBuffer()));
|
|
delete pText;
|
|
}
|
|
|
|
void SmXMLExport::ExportBlank(const SmNode * /*pNode*/, int /*nLevel*/)
|
|
{
|
|
//!! exports an empty <mi> tag since for example "~_~" is allowed in
|
|
//!! Math (so it has no sense at all) but must not result in an empty
|
|
//!! <msub> tag in MathML !!
|
|
|
|
SvXMLElementExport *pText;
|
|
|
|
pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
|
|
|
|
GetDocHandler()->characters( OUString() );
|
|
delete pText;
|
|
}
|
|
|
|
void SmXMLExport::ExportSubSupScript(const SmNode *pNode, int nLevel)
|
|
{
|
|
const SmNode *pSub = 0;
|
|
const SmNode *pSup = 0;
|
|
const SmNode *pCSub = 0;
|
|
const SmNode *pCSup = 0;
|
|
const SmNode *pLSub = 0;
|
|
const SmNode *pLSup = 0;
|
|
SvXMLElementExport *pThing = 0, *pThing2 = 0;
|
|
|
|
//if we have prescripts at all then we must use the tensor notation
|
|
|
|
//This is one of those excellent locations where scope is vital to
|
|
//arrange the construction and destruction of the element helper
|
|
//classes correctly
|
|
pLSub = pNode->GetSubNode(LSUB+1);
|
|
pLSup = pNode->GetSubNode(LSUP+1);
|
|
if (pLSub || pLSup)
|
|
{
|
|
SvXMLElementExport aMultiScripts(*this, XML_NAMESPACE_MATH,
|
|
XML_MMULTISCRIPTS, sal_True, sal_True);
|
|
|
|
|
|
if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
|
|
&& NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MUNDEROVER, sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MUNDER, sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MOVER, sal_True,sal_True);
|
|
}
|
|
|
|
ExportNodes(pNode->GetSubNode(0), nLevel+1); //Main Term
|
|
|
|
if (pCSub)
|
|
ExportNodes(pCSub, nLevel+1);
|
|
if (pCSup)
|
|
ExportNodes(pCSup, nLevel+1);
|
|
delete pThing2;
|
|
|
|
pSub = pNode->GetSubNode(RSUB+1);
|
|
pSup = pNode->GetSubNode(RSUP+1);
|
|
if (pSub || pSup)
|
|
{
|
|
if (pSub)
|
|
ExportNodes(pSub, nLevel+1);
|
|
else
|
|
{
|
|
SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
|
|
}
|
|
if (pSup)
|
|
ExportNodes(pSup, nLevel+1);
|
|
else
|
|
{
|
|
SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
|
|
}
|
|
}
|
|
|
|
//Seperator element between suffix and prefix sub/sup pairs
|
|
{
|
|
SvXMLElementExport aPrescripts(*this, XML_NAMESPACE_MATH,
|
|
XML_MPRESCRIPTS, sal_True,sal_True);
|
|
}
|
|
|
|
if (pLSub)
|
|
ExportNodes(pLSub, nLevel+1);
|
|
else
|
|
{
|
|
SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
|
|
sal_True,sal_True);
|
|
|
|
}
|
|
if (pLSup)
|
|
ExportNodes(pLSup, nLevel+1);
|
|
else
|
|
{
|
|
SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
|
|
sal_True,sal_True);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NULL != (pSub = pNode->GetSubNode(RSUB+1)) &&
|
|
NULL != (pSup = pNode->GetSubNode(RSUP+1)))
|
|
{
|
|
pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MSUBSUP, sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pSub = pNode->GetSubNode(RSUB+1)))
|
|
{
|
|
pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUB,
|
|
sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pSup = pNode->GetSubNode(RSUP+1)))
|
|
{
|
|
pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUP,
|
|
sal_True,sal_True);
|
|
}
|
|
|
|
if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
|
|
&& NULL != (pCSup=pNode->GetSubNode(CSUP+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MUNDEROVER, sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MUNDER, sal_True,sal_True);
|
|
}
|
|
else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
|
|
{
|
|
pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MOVER, sal_True,sal_True);
|
|
}
|
|
ExportNodes(pNode->GetSubNode(0), nLevel+1); //Main Term
|
|
|
|
if (pCSub)
|
|
ExportNodes(pCSub, nLevel+1);
|
|
if (pCSup)
|
|
ExportNodes(pCSup, nLevel+1);
|
|
delete pThing2;
|
|
|
|
if (pSub)
|
|
ExportNodes(pSub, nLevel+1);
|
|
if (pSup)
|
|
ExportNodes(pSup, nLevel+1);
|
|
delete pThing;
|
|
}
|
|
}
|
|
|
|
void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
|
|
{
|
|
const SmNode *pTemp;
|
|
const SmNode *pLeft=pNode->GetSubNode(0);
|
|
const SmNode *pRight=pNode->GetSubNode(2);
|
|
SvXMLElementExport *pFences=0,*pRow=0;
|
|
if ( ((pLeft) && (pLeft->GetToken().eType != TNONE)) &&
|
|
((pRight) && (pRight->GetToken().eType != TNONE)) &&
|
|
(pNode->GetScaleMode() == SCALE_HEIGHT))
|
|
{
|
|
sal_Unicode nArse[2];
|
|
nArse[1] = 0;
|
|
nArse[0] = static_cast<
|
|
const SmMathSymbolNode* >(pLeft)->GetText().GetChar(0);
|
|
OSL_ENSURE(nArse[0] != 0xffff,"Non existent symbol");
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_OPEN,nArse);
|
|
nArse[0] = static_cast<
|
|
const SmMathSymbolNode* >(pRight)->GetText().GetChar(0);
|
|
OSL_ENSURE(nArse[0] != 0xffff,"Non existent symbol");
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_CLOSE,nArse);
|
|
pFences = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MFENCED,
|
|
sal_True,sal_True);
|
|
}
|
|
else if (pLeft && (pLeft->GetToken().eType != TNONE))
|
|
{
|
|
pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
|
|
sal_True, sal_True);
|
|
if (pNode->GetScaleMode() == SCALE_HEIGHT)
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
|
|
else
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
|
|
ExportNodes(pLeft, nLevel+1);
|
|
}
|
|
else
|
|
pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
|
|
sal_True, sal_True);
|
|
|
|
if (NULL != (pTemp = pNode->GetSubNode(1)))
|
|
ExportNodes(pTemp, nLevel+1);
|
|
if (pFences)
|
|
delete pFences;
|
|
else if (pRight && (pRight->GetToken().eType != TNONE))
|
|
{
|
|
if (pNode->GetScaleMode() == SCALE_HEIGHT)
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
|
|
else
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
|
|
ExportNodes(pRight, nLevel+1);
|
|
}
|
|
delete pRow;
|
|
}
|
|
|
|
void SmXMLExport::ExportRoot(const SmNode *pNode, int nLevel)
|
|
{
|
|
if (pNode->GetSubNode(0))
|
|
{
|
|
SvXMLElementExport aRoot(*this, XML_NAMESPACE_MATH, XML_MROOT,sal_True,
|
|
sal_True);
|
|
ExportNodes(pNode->GetSubNode(2), nLevel+1);
|
|
ExportNodes(pNode->GetSubNode(0), nLevel+1);
|
|
}
|
|
else
|
|
{
|
|
SvXMLElementExport aSqrt(*this, XML_NAMESPACE_MATH, XML_MSQRT,sal_True,
|
|
sal_True);
|
|
ExportNodes(pNode->GetSubNode(2), nLevel+1);
|
|
}
|
|
}
|
|
|
|
void SmXMLExport::ExportOperator(const SmNode *pNode, int nLevel)
|
|
{
|
|
/*we need to either use content or font and size attributes
|
|
*here*/
|
|
SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MROW,
|
|
sal_True, sal_True);
|
|
ExportNodes(pNode->GetSubNode(0), nLevel+1);
|
|
ExportNodes(pNode->GetSubNode(1), nLevel+1);
|
|
}
|
|
|
|
void SmXMLExport::ExportAttributes(const SmNode *pNode, int nLevel)
|
|
{
|
|
SvXMLElementExport *pElement=0;
|
|
|
|
if (pNode->GetToken().eType == TUNDERLINE)
|
|
{
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_ACCENTUNDER,
|
|
XML_TRUE);
|
|
pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MUNDER,
|
|
sal_True,sal_True);
|
|
}
|
|
else if (pNode->GetToken().eType != TOVERSTRIKE)
|
|
{
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT,
|
|
XML_TRUE);
|
|
pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MOVER,
|
|
sal_True,sal_True);
|
|
}
|
|
|
|
ExportNodes(pNode->GetSubNode(1), nLevel+1);
|
|
switch (pNode->GetToken().eType)
|
|
{
|
|
case TOVERLINE:
|
|
{
|
|
//proper entity support required
|
|
SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
|
|
sal_True,sal_True);
|
|
sal_Unicode nArse[2] = {0xAF,0x00};
|
|
GetDocHandler()->characters(nArse);
|
|
}
|
|
break;
|
|
case TUNDERLINE:
|
|
{
|
|
//proper entity support required
|
|
SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
|
|
sal_True,sal_True);
|
|
sal_Unicode nArse[2] = {0x0332,0x00};
|
|
GetDocHandler()->characters(nArse);
|
|
}
|
|
break;
|
|
case TOVERSTRIKE:
|
|
break;
|
|
default:
|
|
ExportNodes(pNode->GetSubNode(0), nLevel+1);
|
|
break;
|
|
}
|
|
delete pElement;
|
|
}
|
|
|
|
static bool lcl_HasEffectOnMathvariant( const SmTokenType eType )
|
|
{
|
|
return eType == TBOLD || eType == TNBOLD ||
|
|
eType == TITALIC || eType == TNITALIC ||
|
|
eType == TSANS || eType == TSERIF || eType == TFIXED;
|
|
}
|
|
|
|
void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
|
|
{
|
|
SvXMLElementExport *pElement = 0;
|
|
|
|
//
|
|
// gather the mathvariant attribut relevant data from all
|
|
// successively following SmFontNodes...
|
|
//
|
|
int nBold = -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
|
|
int nItalic = -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
|
|
int nSansSerifFixed = -1;
|
|
SmTokenType eNodeType = TUNKNOWN;
|
|
while (lcl_HasEffectOnMathvariant( (eNodeType = pNode->GetToken().eType) ))
|
|
{
|
|
switch (eNodeType)
|
|
{
|
|
case TBOLD : nBold = 1; break;
|
|
case TNBOLD : nBold = 0; break;
|
|
case TITALIC : nItalic = 1; break;
|
|
case TNITALIC : nItalic = 0; break;
|
|
case TSANS : nSansSerifFixed = 0; break;
|
|
case TSERIF : nSansSerifFixed = 1; break;
|
|
case TFIXED : nSansSerifFixed = 2; break;
|
|
default:
|
|
OSL_FAIL( "unexpected case" );
|
|
}
|
|
// According to the parser every node that is to be evaluated heres
|
|
// has a single non-zero subnode at index 1!! Thus we only need to check
|
|
// that single node for follow-up nodes that have an effect on the attribute.
|
|
if (pNode->GetNumSubNodes() > 1 && pNode->GetSubNode(1) &&
|
|
lcl_HasEffectOnMathvariant( pNode->GetSubNode(1)->GetToken().eType))
|
|
{
|
|
pNode = pNode->GetSubNode(1);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
switch (pNode->GetToken().eType)
|
|
{
|
|
//wrap a phantom element around everything*/
|
|
case TPHANTOM:
|
|
pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
|
|
XML_MPHANTOM, sal_True,sal_True);
|
|
break;
|
|
case TBLACK:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK);
|
|
break;
|
|
case TWHITE:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_WHITE);
|
|
break;
|
|
case TRED:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_RED);
|
|
break;
|
|
case TGREEN:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GREEN);
|
|
break;
|
|
case TBLUE:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLUE);
|
|
break;
|
|
case TCYAN:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
|
|
break;
|
|
case TMAGENTA:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
|
|
break;
|
|
case TYELLOW:
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_YELLOW);
|
|
break;
|
|
case TSIZE:
|
|
{
|
|
const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode);
|
|
const Fraction &aFrac = pFontNode->GetSizeParameter();
|
|
|
|
OUStringBuffer sStrBuf;
|
|
switch(pFontNode->GetSizeType())
|
|
{
|
|
case FNTSIZ_MULTIPLY:
|
|
::sax::Converter::convertDouble(sStrBuf,
|
|
static_cast<double>(aFrac*Fraction(100.00)));
|
|
sStrBuf.append(static_cast<sal_Unicode>('%'));
|
|
break;
|
|
case FNTSIZ_DIVIDE:
|
|
::sax::Converter::convertDouble(sStrBuf,
|
|
static_cast<double>(Fraction(100.00)/aFrac));
|
|
sStrBuf.append(static_cast<sal_Unicode>('%'));
|
|
break;
|
|
case FNTSIZ_ABSOLUT:
|
|
::sax::Converter::convertDouble(sStrBuf,
|
|
static_cast<double>(aFrac));
|
|
sStrBuf.append(
|
|
GetXMLToken(XML_UNIT_PT));
|
|
break;
|
|
default:
|
|
{
|
|
//The problem here is that the wheels fall off because
|
|
//font size is stored in 100th's of a mm not pts, and
|
|
//rounding errors take their toll on the original
|
|
//value specified in points.
|
|
|
|
//Must fix StarMath to retain the original pt values
|
|
Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont().
|
|
GetSize().Height());
|
|
|
|
if (pFontNode->GetSizeType() == FNTSIZ_MINUS)
|
|
aTemp-=aFrac;
|
|
else
|
|
aTemp+=aFrac;
|
|
|
|
double mytest = static_cast<double>(aTemp);
|
|
|
|
mytest = ::rtl::math::round(mytest,1);
|
|
::sax::Converter::convertDouble(sStrBuf,mytest);
|
|
sStrBuf.append(GetXMLToken(XML_UNIT_PT));
|
|
}
|
|
break;
|
|
}
|
|
|
|
OUString sStr(sStrBuf.makeStringAndClear());
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr);
|
|
}
|
|
break;
|
|
case TBOLD:
|
|
case TITALIC:
|
|
case TNBOLD:
|
|
case TNITALIC:
|
|
case TFIXED:
|
|
case TSANS:
|
|
case TSERIF:
|
|
{
|
|
// nBold: -1 = yet undefined; 0 = false; 1 = true;
|
|
// nItalic: -1 = yet undefined; 0 = false; 1 = true;
|
|
// nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
|
|
const sal_Char *pText = "normal";
|
|
if (nSansSerifFixed == -1 || nSansSerifFixed == 1)
|
|
{
|
|
pText = "normal";
|
|
if (nBold == 1 && nItalic != 1)
|
|
pText = "bold";
|
|
else if (nBold != 1 && nItalic == 1)
|
|
pText = "italic";
|
|
else if (nBold == 1 && nItalic == 1)
|
|
pText = "bold-italic";
|
|
}
|
|
else if (nSansSerifFixed == 0)
|
|
{
|
|
pText = "sans-serif";
|
|
if (nBold == 1 && nItalic != 1)
|
|
pText = "bold-sans-serif";
|
|
else if (nBold != 1 && nItalic == 1)
|
|
pText = "sans-serif-italic";
|
|
else if (nBold == 1 && nItalic == 1)
|
|
pText = "sans-serif-bold-italic";
|
|
}
|
|
else if (nSansSerifFixed == 2)
|
|
pText = "monospace"; // no modifiers allowed for monospace ...
|
|
else
|
|
{
|
|
OSL_FAIL( "unexpected case" );
|
|
}
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, OUString::createFromAscii( pText ));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
}
|
|
//for now we will just always export with a style and not worry about
|
|
//anyone else for the moment.
|
|
{
|
|
//wrap a style around it
|
|
SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
|
|
ExportExpression(pNode, nLevel);
|
|
}
|
|
|
|
delete pElement;
|
|
}
|
|
|
|
|
|
void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel)
|
|
{
|
|
//Place the overbrace value OVER a vertical brace and then place that
|
|
//expression OVER the overbrace value, If someone can find a
|
|
//dedicated term in MathML to handle this overbrace/underbrace concept
|
|
//let me know. C.
|
|
XMLTokenEnum which;
|
|
|
|
switch (pNode->GetToken().eType)
|
|
{
|
|
case TOVERBRACE:
|
|
default:
|
|
which = XML_MOVER;
|
|
break;
|
|
case TUNDERBRACE:
|
|
which = XML_MUNDER;
|
|
break;
|
|
}
|
|
|
|
OSL_ENSURE(pNode->GetNumSubNodes()==3,"Bad Vertical Brace");
|
|
SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
|
|
{//Scoping
|
|
// using accents will draw the over-/underbraces too close to the base
|
|
// see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
|
|
// also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here!
|
|
SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
|
|
ExportNodes(pNode->GetSubNode(0), nLevel);
|
|
ExportNodes(pNode->GetSubNode(1), nLevel);
|
|
}
|
|
ExportNodes(pNode->GetSubNode(2), nLevel);
|
|
}
|
|
|
|
void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel)
|
|
{
|
|
SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
|
|
const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode);
|
|
sal_uInt16 i=0;
|
|
for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++)
|
|
{
|
|
SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
|
|
for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++)
|
|
if (const SmNode *pTemp = pNode->GetSubNode(i++))
|
|
{
|
|
SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
|
|
ExportNodes(pTemp, nLevel+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel)
|
|
{
|
|
if (!pNode)
|
|
return;
|
|
switch(pNode->GetType())
|
|
{
|
|
case NTABLE:
|
|
ExportTable(pNode, nLevel);
|
|
break;
|
|
case NALIGN:
|
|
case NBRACEBODY:
|
|
case NEXPRESSION:
|
|
ExportExpression(pNode, nLevel);
|
|
break;
|
|
case NLINE:
|
|
ExportLine(pNode, nLevel);
|
|
break;
|
|
case NTEXT:
|
|
ExportText(pNode, nLevel);
|
|
break;
|
|
case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine.
|
|
case NGLYPH_SPECIAL:
|
|
case NMATH:
|
|
{
|
|
sal_Unicode cTmp = 0;
|
|
const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode);
|
|
if (pTemp->GetText().Len() > 0)
|
|
cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) );
|
|
if (cTmp == 0)
|
|
{
|
|
// no conversion to MathML implemented -> export it as text
|
|
// thus at least it will not vanish into nothing
|
|
ExportText(pNode, nLevel);
|
|
}
|
|
else
|
|
{
|
|
//To fully handle generic MathML we need to implement the full
|
|
//operator dictionary, we will generate MathML with explicit
|
|
//stretchiness for now.
|
|
sal_Int16 nLength = GetAttrList().getLength();
|
|
sal_Bool bAddStretch=sal_True;
|
|
for ( sal_Int16 i = 0; i < nLength; i++ )
|
|
{
|
|
OUString sLocalName;
|
|
sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName(
|
|
GetAttrList().getNameByIndex(i), &sLocalName );
|
|
|
|
if ( ( XML_NAMESPACE_MATH == nPrefix ) &&
|
|
IsXMLToken(sLocalName, XML_STRETCHY) )
|
|
{
|
|
bAddStretch = sal_False;
|
|
break;
|
|
}
|
|
}
|
|
if (bAddStretch)
|
|
{
|
|
AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
|
|
}
|
|
ExportMath(pNode, nLevel);
|
|
}
|
|
}
|
|
break;
|
|
case NPLACE:
|
|
ExportMath(pNode, nLevel);
|
|
break;
|
|
case NBINHOR:
|
|
ExportBinaryHorizontal(pNode, nLevel);
|
|
break;
|
|
case NUNHOR:
|
|
ExportUnaryHorizontal(pNode, nLevel);
|
|
break;
|
|
case NBRACE:
|
|
ExportBrace(pNode, nLevel);
|
|
break;
|
|
case NBINVER:
|
|
ExportBinaryVertical(pNode, nLevel);
|
|
break;
|
|
case NSUBSUP:
|
|
ExportSubSupScript(pNode, nLevel);
|
|
break;
|
|
case NROOT:
|
|
ExportRoot(pNode, nLevel);
|
|
break;
|
|
case NOPER:
|
|
ExportOperator(pNode, nLevel);
|
|
break;
|
|
case NATTRIBUT:
|
|
ExportAttributes(pNode, nLevel);
|
|
break;
|
|
case NFONT:
|
|
ExportFont(pNode, nLevel);
|
|
break;
|
|
case NVERTICAL_BRACE:
|
|
ExportVerticalBrace(pNode, nLevel);
|
|
break;
|
|
case NMATRIX:
|
|
ExportMatrix(pNode, nLevel);
|
|
break;
|
|
case NBLANK:
|
|
ExportBlank(pNode, nLevel);
|
|
break;
|
|
default:
|
|
OSL_FAIL( "Warning: failed to export a node?" );
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|