/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "eventimp.hxx" using namespace ::cppu; using namespace ::com::sun::star; using namespace ::com::sun::star::xml; using namespace ::com::sun::star::xml::sax; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::document; using namespace ::com::sun::star::container; using namespace ::com::sun::star::presentation; using namespace ::xmloff::token; SvXMLEnumMapEntry const aXML_EventActions_EnumMap[] = { { XML_NONE, ClickAction_NONE }, { XML_PREVIOUS_PAGE, ClickAction_PREVPAGE }, { XML_NEXT_PAGE, ClickAction_NEXTPAGE }, { XML_FIRST_PAGE, ClickAction_FIRSTPAGE }, { XML_LAST_PAGE, ClickAction_LASTPAGE }, { XML_HIDE, ClickAction_INVISIBLE }, { XML_STOP, ClickAction_STOPPRESENTATION }, { XML_EXECUTE, ClickAction_PROGRAM }, { XML_SHOW, ClickAction_BOOKMARK }, { XML_SHOW, ClickAction_DOCUMENT }, { XML_EXECUTE_MACRO, ClickAction_MACRO }, { XML_VERB, ClickAction_VERB }, { XML_FADE_OUT, ClickAction_VANISH }, { XML_SOUND, ClickAction_SOUND }, { XML_TOKEN_INVALID, ClickAction(0) } }; SdXMLEventContextData::SdXMLEventContextData(const Reference< XShape >& rxShape) : mxShape(rxShape), mbValid(false), mbScript(false) , meClickAction(ClickAction_NONE), meEffect(EK_none) , meDirection(ED_none), mnStartScale(100), meSpeed(AnimationSpeed_MEDIUM) , mnVerb(0), mbPlayFull(false) { } namespace { class SdXMLEventContext : public SvXMLImportContext { public: SdXMLEventContextData maData; public: SdXMLEventContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList>& xAttrList, const Reference< XShape >& rxShape ); virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; }; class XMLEventSoundContext : public SvXMLImportContext { public: XMLEventSoundContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ); }; } XMLEventSoundContext::XMLEventSoundContext( SvXMLImport& rImp, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ) : SvXMLImportContext( rImp ) { for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) { switch( aIter.getToken() ) { case XML_ELEMENT(XLINK, XML_HREF): pParent->maData.msSoundURL = rImp.GetAbsoluteReference(aIter.toString()); break; case XML_ELEMENT(PRESENTATION, XML_PLAY_FULL): pParent->maData.mbPlayFull = IsXMLToken( aIter, XML_TRUE ); break; default: XMLOFF_WARN_UNKNOWN("xmloff", aIter); } } } SdXMLEventContext::SdXMLEventContext( SvXMLImport& rImp, sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList, const Reference< XShape >& rxShape ) : SvXMLImportContext(rImp) , maData(rxShape) { if( nElement == XML_ELEMENT(PRESENTATION, XML_EVENT_LISTENER) ) { maData.mbValid = true; } else if( nElement == XML_ELEMENT(SCRIPT, XML_EVENT_LISTENER) ) { maData.mbScript = true; maData.mbValid = true; } else { return; } // read attributes OUString sEventName; for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) { switch( aIter.getToken() ) { case XML_ELEMENT(PRESENTATION, XML_ACTION): SvXMLUnitConverter::convertEnum( maData.meClickAction, aIter.toView(), aXML_EventActions_EnumMap ); break; case XML_ELEMENT(PRESENTATION, XML_EFFECT): SvXMLUnitConverter::convertEnum( maData.meEffect, aIter.toView(), aXML_AnimationEffect_EnumMap ); break; case XML_ELEMENT(PRESENTATION, XML_DIRECTION): SvXMLUnitConverter::convertEnum( maData.meDirection, aIter.toView(), aXML_AnimationDirection_EnumMap ); break; case XML_ELEMENT(PRESENTATION, XML_START_SCALE): { sal_Int32 nScale; if (::sax::Converter::convertPercent( nScale, aIter.toView() )) maData.mnStartScale = static_cast(nScale); } break; case XML_ELEMENT(PRESENTATION, XML_SPEED): SvXMLUnitConverter::convertEnum( maData.meSpeed, aIter.toView(), aXML_AnimationSpeed_EnumMap ); break; case XML_ELEMENT(PRESENTATION, XML_VERB): ::sax::Converter::convertNumber( maData.mnVerb, aIter.toView() ); break; case XML_ELEMENT(SCRIPT, XML_EVENT_NAME): { sEventName = aIter.toString(); sal_uInt16 nScriptPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName(sEventName, &sEventName); maData.mbValid = XML_NAMESPACE_DOM == nScriptPrefix && sEventName == "click"; } break; case XML_ELEMENT(SCRIPT, XML_LANGUAGE): { // language is not evaluated! OUString aScriptLanguage; maData.msLanguage = aIter.toString(); sal_uInt16 nScriptPrefix = rImp.GetNamespaceMap(). GetKeyByAttrValueQName(maData.msLanguage, &aScriptLanguage); if( XML_NAMESPACE_OOO == nScriptPrefix ) maData.msLanguage = aScriptLanguage; } break; case XML_ELEMENT(SCRIPT, XML_MACRO_NAME): maData.msMacroName = aIter.toString(); break; case XML_ELEMENT(XLINK, XML_HREF): { if ( maData.mbScript ) { maData.msMacroName = aIter.toString(); } else { const OUString &rTmp = rImp.GetAbsoluteReference(aIter.toString()); INetURLObject::translateToInternal( rTmp, maData.msBookmark, INetURLObject::DecodeMechanism::Unambiguous ); } } break; } } if( maData.mbValid ) maData.mbValid = !sEventName.isEmpty(); if (!maData.msMacroName.isEmpty()) rImp.NotifyMacroEventRead(); } css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventContext::createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { if( nElement == XML_ELEMENT(PRESENTATION, XML_SOUND) ) return new XMLEventSoundContext( GetImport(), xAttrList, this ); else XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); return nullptr; } void SdXMLEventContext::endFastElement(sal_Int32 ) { GetImport().GetShapeImport()->addShapeEvents(maData); } void SdXMLEventContextData::ApplyProperties() { if( !mbValid ) return; do { Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); if( !xEventsSupplier.is() ) break; Reference< XNameReplace > xEvents( xEventsSupplier->getEvents() ); SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" ); if( !xEvents.is() ) break; OUString sAPIEventName; uno::Sequence< beans::PropertyValue > aProperties; sAPIEventName = "OnClick"; if( mbScript ) meClickAction = ClickAction_MACRO; sal_Int32 nPropertyCount = 2; switch( meClickAction ) { case ClickAction_NONE: case ClickAction_PREVPAGE: case ClickAction_NEXTPAGE: case ClickAction_FIRSTPAGE: case ClickAction_LASTPAGE: case ClickAction_INVISIBLE: case ClickAction_STOPPRESENTATION: break; case ClickAction_PROGRAM: case ClickAction_VERB: case ClickAction_BOOKMARK: case ClickAction_DOCUMENT: nPropertyCount += 1; break; case ClickAction_MACRO: if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) nPropertyCount += 1; break; case ClickAction_SOUND: nPropertyCount += 2; break; case ClickAction_VANISH: nPropertyCount += 4; break; default: break; } aProperties.realloc( nPropertyCount ); beans::PropertyValue* pProperties = aProperties.getArray(); if( ClickAction_MACRO == meClickAction ) { if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) { OUString sLibrary; const OUString& rApp = GetXMLToken( XML_APPLICATION ); const OUString& rDoc = GetXMLToken( XML_DOCUMENT ); if( msMacroName.getLength() > rApp.getLength()+1 && o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rApp.getLength()), rApp) && ':' == msMacroName[rApp.getLength()] ) { sLibrary = "StarOffice"; msMacroName = msMacroName.copy( rApp.getLength()+1 ); } else if( msMacroName.getLength() > rDoc.getLength()+1 && o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rDoc.getLength()), rDoc) && ':' == msMacroName[rDoc.getLength()] ) { sLibrary = rDoc; msMacroName = msMacroName.copy( rDoc.getLength()+1 ); } pProperties->Name = "EventType"; pProperties->Handle = -1; pProperties->Value <<= OUString( "StarBasic" ); pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; pProperties->Name = "MacroName"; pProperties->Handle = -1; pProperties->Value <<= msMacroName; pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; pProperties->Name = "Library"; pProperties->Handle = -1; pProperties->Value <<= sLibrary; pProperties->State = beans::PropertyState_DIRECT_VALUE; } else { pProperties->Name = "EventType"; pProperties->Handle = -1; pProperties->Value <<= OUString( "Script" ); pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; pProperties->Name = "Script"; pProperties->Handle = -1; pProperties->Value <<= msMacroName; pProperties->State = beans::PropertyState_DIRECT_VALUE; } } else { pProperties->Name = "EventType"; pProperties->Handle = -1; pProperties->Value <<= OUString( "Presentation" ); pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same xml event // so check here if it's really a bookmark or maybe a document if( meClickAction == ClickAction_BOOKMARK ) { if( !msBookmark.startsWith( "#" ) ) meClickAction = ClickAction_DOCUMENT; } pProperties->Name = "ClickAction"; pProperties->Handle = -1; pProperties->Value <<= meClickAction; pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; switch( meClickAction ) { case ClickAction_NONE: case ClickAction_PREVPAGE: case ClickAction_NEXTPAGE: case ClickAction_FIRSTPAGE: case ClickAction_LASTPAGE: case ClickAction_INVISIBLE: case ClickAction_STOPPRESENTATION: break; case ClickAction_BOOKMARK: msBookmark = msBookmark.copy(1); [[fallthrough]]; case ClickAction_DOCUMENT: case ClickAction_PROGRAM: pProperties->Name = "Bookmark"; pProperties->Handle = -1; pProperties->Value <<= msBookmark; pProperties->State = beans::PropertyState_DIRECT_VALUE; break; case ClickAction_VANISH: pProperties->Name = "Effect"; pProperties->Handle = -1; pProperties->Value <<= ImplSdXMLgetEffect( meEffect, meDirection, mnStartScale, true ); pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; pProperties->Name = "Speed"; pProperties->Handle = -1; pProperties->Value <<= meSpeed; pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; [[fallthrough]]; case ClickAction_SOUND: pProperties->Name = "SoundURL"; pProperties->Handle = -1; pProperties->Value <<= msSoundURL; pProperties->State = beans::PropertyState_DIRECT_VALUE; pProperties++; pProperties->Name = "PlayFull"; pProperties->Handle = -1; pProperties->Value <<= mbPlayFull; pProperties->State = beans::PropertyState_DIRECT_VALUE; break; case ClickAction_VERB: pProperties->Name = "Verb"; pProperties->Handle = -1; pProperties->Value <<= mnVerb; pProperties->State = beans::PropertyState_DIRECT_VALUE; break; case ClickAction_MACRO: OSL_FAIL("xmloff::SdXMLEventContext::EndElement(), ClickAction_MACRO must be handled in different if case"); break; default: break; } } xEvents->replaceByName( sAPIEventName, uno::Any( aProperties ) ); } while(false); } SdXMLEventsContext::SdXMLEventsContext( SvXMLImport& rImport, const Reference< XShape >& rxShape) : SvXMLImportContext(rImport), mxShape( rxShape ) { } SdXMLEventsContext::~SdXMLEventsContext() { } css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventsContext::createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { return new SdXMLEventContext( GetImport(), nElement, xAttrList, mxShape ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */