diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /framework/source/fwe/xml | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream/1%7.0.4.tar.xz libreoffice-upstream/1%7.0.4.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | framework/source/fwe/xml/menuconfiguration.cxx | 156 | ||||
-rw-r--r-- | framework/source/fwe/xml/menudocumenthandler.cxx | 903 | ||||
-rw-r--r-- | framework/source/fwe/xml/saxnamespacefilter.cxx | 171 | ||||
-rw-r--r-- | framework/source/fwe/xml/statusbarconfiguration.cxx | 105 | ||||
-rw-r--r-- | framework/source/fwe/xml/statusbardocumenthandler.cxx | 658 | ||||
-rw-r--r-- | framework/source/fwe/xml/toolboxconfiguration.cxx | 108 | ||||
-rw-r--r-- | framework/source/fwe/xml/toolboxdocumenthandler.cxx | 759 | ||||
-rw-r--r-- | framework/source/fwe/xml/xmlnamespaces.cxx | 152 |
8 files changed, 3012 insertions, 0 deletions
diff --git a/framework/source/fwe/xml/menuconfiguration.cxx b/framework/source/fwe/xml/menuconfiguration.cxx new file mode 100644 index 000000000..e5a548640 --- /dev/null +++ b/framework/source/fwe/xml/menuconfiguration.cxx @@ -0,0 +1,156 @@ +/* -*- 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 <menuconfiguration.hxx> + +#include <addonmenu.hxx> +#include <xml/menudocumenthandler.hxx> +#include <xml/saxnamespacefilter.hxx> + +#include <uielement/rootitemcontainer.hxx> + +#include <com/sun/star/xml/sax/Parser.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <cppuhelper/exc_hlp.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::io; + +namespace framework +{ + +MenuConfiguration::MenuConfiguration( + const css::uno::Reference< css::uno::XComponentContext >& rxContext ) +: m_xContext( rxContext ) +{ +} + +MenuConfiguration::~MenuConfiguration() +{ +} + +Reference< XIndexAccess > MenuConfiguration::CreateMenuBarConfigurationFromXML( + Reference< XInputStream > const & rInputStream ) +{ + Reference< XParser > xParser = Parser::create( m_xContext ); + + // connect stream to input stream to the parser + InputSource aInputSource; + + aInputSource.aInputStream = rInputStream; + + // create menu bar + Reference< XIndexContainer > xItemContainer( static_cast< cppu::OWeakObject *>( new RootItemContainer()), UNO_QUERY ); + + // create namespace filter and set menudocument handler inside to support xml namespaces + + Reference< XDocumentHandler > xDocHandler( new OReadMenuDocumentHandler( xItemContainer )); + + Reference< XDocumentHandler > xFilter( new SaxNamespaceFilter( xDocHandler )); + + // connect parser and filter + xParser->setDocumentHandler( xFilter ); + + try + { + xParser->parseStream( aInputSource ); + return xItemContainer; + } + catch ( const RuntimeException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + } + catch( const SAXException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + SAXException aWrappedSAXException; + + if ( !( e.WrappedException >>= aWrappedSAXException )) + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + else + throw WrappedTargetException( aWrappedSAXException.Message, Reference< XInterface >(), e.WrappedException ); + } + catch( const css::io::IOException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + } +} + +void MenuConfiguration::StoreMenuBarConfigurationToXML( + Reference< XIndexAccess > const & rMenuBarConfiguration, + Reference< XOutputStream > const & rOutputStream, bool bIsMenuBar ) +{ + Reference< XWriter > xWriter = Writer::create(m_xContext); + xWriter->setOutputStream( rOutputStream ); + + try + { + OWriteMenuDocumentHandler aWriteMenuDocumentHandler( rMenuBarConfiguration, xWriter, bIsMenuBar ); + aWriteMenuDocumentHandler.WriteMenuDocument(); + } + catch ( const RuntimeException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + } + catch ( const SAXException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + } + catch ( const css::io::IOException& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw WrappedTargetException( e.Message, Reference< XInterface >(), anyEx ); + } +} + +void* MenuAttributes::CreateAttribute(const OUString& rFrame, const OUString& rImageIdStr) +{ + MenuAttributes* pAttributes = new MenuAttributes(rFrame, rImageIdStr); + pAttributes->acquire(); + return pAttributes; +} + +void* MenuAttributes::CreateAttribute(const css::uno::WeakReference<css::frame::XDispatchProvider>& rDispatchProvider) +{ + MenuAttributes* pAttributes = new MenuAttributes(rDispatchProvider); + pAttributes->acquire(); + return pAttributes; +} + +void MenuAttributes::ReleaseAttribute(void* nAttributePtr) +{ + if (!nAttributePtr) + return; + MenuAttributes* pAttributes = static_cast<MenuAttributes*>(nAttributePtr); + pAttributes->release(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/menudocumenthandler.cxx b/framework/source/fwe/xml/menudocumenthandler.cxx new file mode 100644 index 000000000..84de0f40b --- /dev/null +++ b/framework/source/fwe/xml/menudocumenthandler.cxx @@ -0,0 +1,903 @@ +/* -*- 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 <stdio.h> +#include <sal/macros.h> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <xml/menudocumenthandler.hxx> + +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/ui/ItemType.hpp> +#include <com/sun/star/ui/ItemStyle.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/attributelist.hxx> + +#ifdef ATTRIBUTE_HELPID +#undef ATTRIBUTE_HELPID +#endif + +#define XMLNS_MENU "http://openoffice.org/2001/menu" + +#define ELEMENT_MENUBAR "http://openoffice.org/2001/menu^menubar" +#define ELEMENT_MENU "http://openoffice.org/2001/menu^menu" +#define ELEMENT_MENUPOPUP "http://openoffice.org/2001/menu^menupopup" +#define ELEMENT_MENUITEM "http://openoffice.org/2001/menu^menuitem" +#define ELEMENT_MENUSEPARATOR "http://openoffice.org/2001/menu^menuseparator" + +#define ELEMENT_NS_MENUBAR "menu:menubar" +#define ELEMENT_NS_MENU "menu:menu" +#define ELEMENT_NS_MENUPOPUP "menu:menupopup" +#define ELEMENT_NS_MENUITEM "menu:menuitem" +#define ELEMENT_NS_MENUSEPARATOR "menu:menuseparator" + +#define ATTRIBUTE_ID "http://openoffice.org/2001/menu^id" +#define ATTRIBUTE_LABEL "http://openoffice.org/2001/menu^label" +#define ATTRIBUTE_HELPID "http://openoffice.org/2001/menu^helpid" +#define ATTRIBUTE_STYLE "http://openoffice.org/2001/menu^style" + +#define ATTRIBUTE_NS_ID "menu:id" +#define ATTRIBUTE_NS_LABEL "menu:label" +#define ATTRIBUTE_NS_HELPID "menu:helpid" +#define ATTRIBUTE_NS_STYLE "menu:style" + +#define ATTRIBUTE_XMLNS_MENU "xmlns:menu" + +#define ATTRIBUTE_TYPE_CDATA "CDATA" + +#define MENUBAR_DOCTYPE "<!DOCTYPE menu:menubar PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\" \"menubar.dtd\">" + +#define ATTRIBUTE_ITEMSTYLE_TEXT "text" +#define ATTRIBUTE_ITEMSTYLE_IMAGE "image" +#define ATTRIBUTE_ITEMSTYLE_RADIO "radio" + +// Property names of a menu/menu item ItemDescriptor +static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL"; +static const char ITEM_DESCRIPTOR_HELPURL[] = "HelpURL"; +static const char ITEM_DESCRIPTOR_CONTAINER[] = "ItemDescriptorContainer"; +static const char ITEM_DESCRIPTOR_LABEL[] = "Label"; +static const char ITEM_DESCRIPTOR_TYPE[] = "Type"; +static const char ITEM_DESCRIPTOR_STYLE[] = "Style"; + +// using namespaces + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::ui; + +namespace framework +{ + +namespace { + +struct MenuStyleItem +{ + sal_Int16 nBit; + const char* attrName; +}; + +} + +const MenuStyleItem MenuItemStyles[ ] = { + { css::ui::ItemStyle::ICON, ATTRIBUTE_ITEMSTYLE_IMAGE }, + { css::ui::ItemStyle::TEXT, ATTRIBUTE_ITEMSTYLE_TEXT }, + { css::ui::ItemStyle::RADIO_CHECK, ATTRIBUTE_ITEMSTYLE_RADIO } +}; + +sal_Int32 const nMenuStyleItemEntries = SAL_N_ELEMENTS(MenuItemStyles); + +static void ExtractMenuParameters( const Sequence< PropertyValue >& rProp, + OUString& rCommandURL, + OUString& rLabel, + OUString& rHelpURL, + Reference< XIndexAccess >& rSubMenu, + sal_Int16& rType, + sal_Int16& rStyle ) +{ + for ( const PropertyValue& p : rProp ) + { + if ( p.Name == ITEM_DESCRIPTOR_COMMANDURL ) + { + p.Value >>= rCommandURL; + rCommandURL = rCommandURL.intern(); + } + else if ( p.Name == ITEM_DESCRIPTOR_HELPURL ) + { + p.Value >>= rHelpURL; + } + else if ( p.Name == ITEM_DESCRIPTOR_CONTAINER ) + { + p.Value >>= rSubMenu; + } + else if ( p.Name == ITEM_DESCRIPTOR_LABEL ) + { + p.Value >>= rLabel; + } + else if ( p.Name == ITEM_DESCRIPTOR_TYPE ) + { + p.Value >>= rType; + } + else if ( p.Name == ITEM_DESCRIPTOR_STYLE ) + { + p.Value >>= rStyle; + } + } +} + +// Base class implementation + +ReadMenuDocumentHandlerBase::ReadMenuDocumentHandlerBase() : + m_aType( ITEM_DESCRIPTOR_TYPE ), + m_aLabel( ITEM_DESCRIPTOR_LABEL ), + m_aContainer( ITEM_DESCRIPTOR_CONTAINER ), + m_aHelpURL( ITEM_DESCRIPTOR_HELPURL ), + m_aCommandURL( ITEM_DESCRIPTOR_COMMANDURL ), + m_aStyle( ITEM_DESCRIPTOR_STYLE ) +{ +} + +ReadMenuDocumentHandlerBase::~ReadMenuDocumentHandlerBase() +{ +} + +void SAL_CALL ReadMenuDocumentHandlerBase::ignorableWhitespace( + const OUString& ) +{ +} + +void SAL_CALL ReadMenuDocumentHandlerBase::processingInstruction( + const OUString& /*aTarget*/, const OUString& /*aData*/ ) +{ +} + +void SAL_CALL ReadMenuDocumentHandlerBase::setDocumentLocator( + const Reference< XLocator > &xLocator) +{ + m_xLocator = xLocator; +} + +OUString ReadMenuDocumentHandlerBase::getErrorLineString() +{ + if ( m_xLocator.is() ) + { + char buffer[32]; + snprintf( buffer, sizeof(buffer), "Line: %ld - ", static_cast<long>( m_xLocator->getLineNumber() )); + return OUString::createFromAscii( buffer ); + } + else + return OUString(); +} + +void ReadMenuDocumentHandlerBase::initPropertyCommon( + Sequence< PropertyValue > &rProps, const OUString &rCommandURL, + const OUString &rHelpId, const OUString &rLabel, sal_Int16 nItemStyleBits ) +{ + rProps[0].Name = m_aCommandURL; + rProps[1].Name = m_aHelpURL; + rProps[2].Name = m_aContainer; + rProps[3].Name = m_aLabel; + rProps[4].Name = m_aStyle; + rProps[5].Name = m_aType; + + // Common values + rProps[0].Value <<= rCommandURL.intern(); + rProps[1].Value <<= rHelpId; + rProps[2].Value <<= Reference< XIndexContainer >(); + rProps[3].Value <<= rLabel; + rProps[4].Value <<= nItemStyleBits; + rProps[5].Value <<= css::ui::ItemType::DEFAULT; +} + +OReadMenuDocumentHandler::OReadMenuDocumentHandler( + const Reference< XIndexContainer >& rMenuBarContainer ) +: m_nElementDepth( 0 ), + m_eReaderMode( ReaderMode::None ), + m_xMenuBarContainer( rMenuBarContainer ), + m_xContainerFactory( rMenuBarContainer, UNO_QUERY ) +{ +} + +OReadMenuDocumentHandler::~OReadMenuDocumentHandler() +{ +} + +void SAL_CALL OReadMenuDocumentHandler::startDocument() +{ +} + +void SAL_CALL OReadMenuDocumentHandler::endDocument() +{ + if ( m_nElementDepth > 0 ) + { + OUString aErrorMessage = getErrorLineString() + + "A closing element is missing!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadMenuDocumentHandler::startElement( + const OUString& aName, const Reference< XAttributeList > &xAttrList ) +{ + if ( m_eReaderMode != ReaderMode::None ) + { + ++m_nElementDepth; + m_xReader->startElement( aName, xAttrList ); + } + else + { + if ( aName == ELEMENT_MENUBAR ) + { + m_eReaderMode = ReaderMode::MenuBar; + m_xReader.set( new OReadMenuBarHandler( m_xMenuBarContainer, m_xContainerFactory )); + } + else if ( aName == ELEMENT_MENUPOPUP ) + { + m_eReaderMode = ReaderMode::MenuPopup; + m_xReader.set( new OReadMenuPopupHandler( m_xMenuBarContainer, m_xContainerFactory )); + } + ++m_nElementDepth; + m_xReader->startDocument(); + } +} + +void SAL_CALL OReadMenuDocumentHandler::characters(const OUString&) +{ +} + +void SAL_CALL OReadMenuDocumentHandler::endElement( const OUString& aName ) +{ + if ( m_eReaderMode == ReaderMode::None ) + return; + + --m_nElementDepth; + m_xReader->endElement( aName ); + if ( 0 != m_nElementDepth ) + return; + + m_xReader->endDocument(); + m_xReader.clear(); + if ( m_eReaderMode == ReaderMode::MenuBar && aName != ELEMENT_MENUBAR ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menubar expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + else if ( m_eReaderMode == ReaderMode::MenuPopup && aName != ELEMENT_MENUPOPUP ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menupopup expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + m_eReaderMode = ReaderMode::None; +} + +OReadMenuBarHandler::OReadMenuBarHandler( + const Reference< XIndexContainer >& rMenuBarContainer, + const Reference< XSingleComponentFactory >& rFactory ) +: m_nElementDepth( 0 ), + m_bMenuMode( false ), + m_xMenuBarContainer( rMenuBarContainer ), + m_xContainerFactory( rFactory ) +{ +} + +OReadMenuBarHandler::~OReadMenuBarHandler() +{ +} + +void SAL_CALL OReadMenuBarHandler::startDocument() +{ +} + +void SAL_CALL OReadMenuBarHandler::endDocument() +{ +} + +void SAL_CALL OReadMenuBarHandler::startElement( + const OUString& rName, const Reference< XAttributeList > &xAttrList ) +{ + if ( m_bMenuMode ) + { + ++m_nElementDepth; + m_xReader->startElement( rName, xAttrList ); + } + else if ( rName == ELEMENT_MENU ) + { + ++m_nElementDepth; + + OUString aHelpId; + OUString aCommandId; + OUString aLabel; + sal_Int16 nItemBits(0); + + m_bMenuMode = true; + + // Container must be factory to create sub container + Reference< XComponentContext > xComponentContext( + comphelper::getProcessComponentContext() ); + + Reference< XIndexContainer > xSubItemContainer; + if ( m_xContainerFactory.is() ) + xSubItemContainer.set( m_xContainerFactory->createInstanceWithContext( xComponentContext ), UNO_QUERY ); + + if ( xSubItemContainer.is() ) + { + // read attributes for menu + for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ ) + { + OUString aName = xAttrList->getNameByIndex( i ); + const OUString aValue = xAttrList->getValueByIndex( i ); + if ( aName == ATTRIBUTE_ID ) + aCommandId = aValue; + else if ( aName == ATTRIBUTE_LABEL ) + aLabel = aValue; + else if ( aName == ATTRIBUTE_HELPID ) + aHelpId = aValue; + else if ( aName == ATTRIBUTE_STYLE ) + { + sal_Int32 nIndex = 0; + do + { + OUString aToken = aValue.getToken( 0, '+', nIndex ); + if ( !aToken.isEmpty() ) + { + if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT ) + nItemBits |= css::ui::ItemStyle::TEXT; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE ) + nItemBits |= css::ui::ItemStyle::ICON; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO ) + nItemBits |= css::ui::ItemStyle::RADIO_CHECK; + } + } + while ( nIndex >= 0 ); + } + } + + if ( !aCommandId.isEmpty() ) + { + Sequence< PropertyValue > aSubMenuProp( 6 ); + initPropertyCommon( aSubMenuProp, aCommandId, aHelpId, aLabel, nItemBits ); + aSubMenuProp[2].Value <<= xSubItemContainer; + + m_xMenuBarContainer->insertByIndex( m_xMenuBarContainer->getCount(), makeAny( aSubMenuProp ) ); + } + else + { + OUString aErrorMessage = getErrorLineString() + + "attribute id for element menu required!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_xReader.set( new OReadMenuHandler( xSubItemContainer, m_xContainerFactory )); + m_xReader->startDocument(); + } + } + else + { + OUString aErrorMessage = getErrorLineString() + + "element menu expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadMenuBarHandler::characters(const OUString&) +{ +} + +void OReadMenuBarHandler::endElement( const OUString& aName ) +{ + if ( !m_bMenuMode ) + return; + + --m_nElementDepth; + if ( 0 == m_nElementDepth ) + { + m_xReader->endDocument(); + m_xReader.clear(); + m_bMenuMode = false; + if ( aName != ELEMENT_MENU ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menu expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + else + m_xReader->endElement( aName ); +} + +OReadMenuHandler::OReadMenuHandler( + const Reference< XIndexContainer >& rMenuContainer, + const Reference< XSingleComponentFactory >& rFactory ) : + m_nElementDepth( 0 ), + m_bMenuPopupMode( false ), + m_xMenuContainer( rMenuContainer ), + m_xContainerFactory( rFactory ) +{ +} + +OReadMenuHandler::~OReadMenuHandler() +{ +} + +void SAL_CALL OReadMenuHandler::startDocument() +{ +} + +void SAL_CALL OReadMenuHandler::endDocument() +{ +} + +void SAL_CALL OReadMenuHandler::startElement( + const OUString& aName, const Reference< XAttributeList > &xAttrList ) +{ + if ( m_bMenuPopupMode ) + { + ++m_nElementDepth; + m_xReader->startElement( aName, xAttrList ); + } + else if ( aName == ELEMENT_MENUPOPUP ) + { + ++m_nElementDepth; + m_bMenuPopupMode = true; + m_xReader.set( new OReadMenuPopupHandler( m_xMenuContainer, m_xContainerFactory )); + m_xReader->startDocument(); + } + else + { + OUString aErrorMessage = getErrorLineString() + + "unknown element found!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadMenuHandler::characters(const OUString&) +{ +} + +void SAL_CALL OReadMenuHandler::endElement( const OUString& aName ) +{ + if ( !m_bMenuPopupMode ) + return; + + --m_nElementDepth; + if ( 0 == m_nElementDepth ) + { + m_xReader->endDocument(); + m_xReader.clear(); + m_bMenuPopupMode = false; + if ( aName != ELEMENT_MENUPOPUP ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menupopup expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + else + m_xReader->endElement( aName ); +} + +OReadMenuPopupHandler::OReadMenuPopupHandler( + const Reference< XIndexContainer >& rMenuContainer, + const Reference< XSingleComponentFactory >& rFactory ) : + m_nElementDepth( 0 ), + m_bMenuMode( false ), + m_xMenuContainer( rMenuContainer ), + m_xContainerFactory( rFactory ), + m_xComponentContext( comphelper::getProcessComponentContext() ), + m_nNextElementExpected( ELEM_CLOSE_NONE ) +{ +} + +OReadMenuPopupHandler::~OReadMenuPopupHandler() +{ +} + +void SAL_CALL OReadMenuPopupHandler::startDocument() +{ +} + +void SAL_CALL OReadMenuPopupHandler::endDocument() +{ +} + +void SAL_CALL OReadMenuPopupHandler::startElement( + const OUString& rName, const Reference< XAttributeList > &xAttrList ) +{ + ++m_nElementDepth; + + if ( m_bMenuMode ) + m_xReader->startElement( rName, xAttrList ); + else if ( rName == ELEMENT_MENU ) + { + OUString aHelpId; + OUString aCommandId; + OUString aLabel; + sal_Int16 nItemBits(0); + + m_bMenuMode = true; + + // Container must be factory to create sub container + Reference< XIndexContainer > xSubItemContainer; + if ( m_xContainerFactory.is() ) + xSubItemContainer.set( m_xContainerFactory->createInstanceWithContext( m_xComponentContext ), UNO_QUERY ); + + // read attributes for menu + for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ ) + { + OUString aName = xAttrList->getNameByIndex( i ); + const OUString aValue = xAttrList->getValueByIndex( i ); + if ( aName == ATTRIBUTE_ID ) + aCommandId = aValue; + else if ( aName == ATTRIBUTE_LABEL ) + aLabel = aValue; + else if ( aName == ATTRIBUTE_HELPID ) + aHelpId = aValue; + else if ( aName == ATTRIBUTE_STYLE ) + { + sal_Int32 nIndex = 0; + do + { + OUString aToken = aValue.getToken( 0, '+', nIndex ); + if ( !aToken.isEmpty() ) + { + if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT ) + nItemBits |= css::ui::ItemStyle::TEXT; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE ) + nItemBits |= css::ui::ItemStyle::ICON; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO ) + nItemBits |= css::ui::ItemStyle::RADIO_CHECK; + } + } + while ( nIndex >= 0 ); + } + + } + + if ( !aCommandId.isEmpty() ) + { + Sequence< PropertyValue > aSubMenuProp( 6 ); + initPropertyCommon( aSubMenuProp, aCommandId, aHelpId, aLabel, nItemBits ); + aSubMenuProp[2].Value <<= xSubItemContainer; + + m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aSubMenuProp ) ); + } + else + { + OUString aErrorMessage = getErrorLineString() + + "attribute id for element menu required!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_xReader.set( new OReadMenuHandler( xSubItemContainer, m_xContainerFactory )); + m_xReader->startDocument(); + } + else if ( rName == ELEMENT_MENUITEM ) + { + OUString aHelpId; + OUString aCommandId; + OUString aLabel; + sal_Int16 nItemBits(0); + // read attributes for menu item + for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ ) + { + OUString aName = xAttrList->getNameByIndex( i ); + const OUString aValue = xAttrList->getValueByIndex( i ); + if ( aName == ATTRIBUTE_ID ) + aCommandId = aValue; + else if ( aName == ATTRIBUTE_LABEL ) + aLabel = aValue; + else if ( aName == ATTRIBUTE_HELPID ) + aHelpId = aValue; + else if ( aName == ATTRIBUTE_STYLE ) + { + sal_Int32 nIndex = 0; + do + { + OUString aToken = aValue.getToken( 0, '+', nIndex ); + if ( !aToken.isEmpty() ) + { + if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT ) + nItemBits |= css::ui::ItemStyle::TEXT; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE ) + nItemBits |= css::ui::ItemStyle::ICON; + else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO ) + nItemBits |= css::ui::ItemStyle::RADIO_CHECK; + } + } + while ( nIndex >= 0 ); + } + + } + + if ( !aCommandId.isEmpty() ) + { + Sequence< PropertyValue > aMenuItem( 6 ); + initPropertyCommon( aMenuItem, aCommandId, aHelpId, aLabel, nItemBits ); + aMenuItem[2].Value <<= Reference< XIndexContainer >(); + + m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aMenuItem ) ); + } + + m_nNextElementExpected = ELEM_CLOSE_MENUITEM; + } + else if ( rName == ELEMENT_MENUSEPARATOR ) + { + Sequence< PropertyValue > aMenuSeparator( 1 ); + aMenuSeparator[0].Name = ITEM_DESCRIPTOR_TYPE; + aMenuSeparator[0].Value <<= css::ui::ItemType::SEPARATOR_LINE; + + m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aMenuSeparator ) ); + + m_nNextElementExpected = ELEM_CLOSE_MENUSEPARATOR; + } + else + { + OUString aErrorMessage = getErrorLineString() + + "unknown element found!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadMenuPopupHandler::characters(const OUString&) +{ +} + +void SAL_CALL OReadMenuPopupHandler::endElement( const OUString& aName ) +{ + --m_nElementDepth; + if ( m_bMenuMode ) + { + if ( 0 == m_nElementDepth ) + { + m_xReader->endDocument(); + m_xReader.clear(); + m_bMenuMode = false; + if ( aName != ELEMENT_MENU ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menu expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + else + m_xReader->endElement( aName ); + } + else + { + if ( m_nNextElementExpected == ELEM_CLOSE_MENUITEM ) + { + if ( aName != ELEMENT_MENUITEM ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menuitem expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + else if ( m_nNextElementExpected == ELEM_CLOSE_MENUSEPARATOR ) + { + if ( aName != ELEMENT_MENUSEPARATOR ) + { + OUString aErrorMessage = getErrorLineString() + + "closing element menuseparator expected!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + + m_nNextElementExpected = ELEM_CLOSE_NONE; + } +} + +// --------------------------------- Write XML --------------------------------- + +OWriteMenuDocumentHandler::OWriteMenuDocumentHandler( + const Reference< XIndexAccess >& rMenuBarContainer, + const Reference< XDocumentHandler >& rDocumentHandler, + bool bIsMenuBar ) : + m_xMenuBarContainer( rMenuBarContainer ), + m_xWriteDocumentHandler( rDocumentHandler ), + m_bIsMenuBar( bIsMenuBar ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + m_xEmptyList.set( static_cast<XAttributeList *>(pList), UNO_QUERY ); + m_aAttributeType = ATTRIBUTE_TYPE_CDATA; +} + +OWriteMenuDocumentHandler::~OWriteMenuDocumentHandler() +{ +} + +void OWriteMenuDocumentHandler::WriteMenuDocument() +{ + rtl::Reference<::comphelper::AttributeList> pList = new ::comphelper::AttributeList; + + m_xWriteDocumentHandler->startDocument(); + + // write DOCTYPE line! + Reference< XExtendedDocumentHandler > xExtendedDocHandler( m_xWriteDocumentHandler, UNO_QUERY ); + if ( m_bIsMenuBar /*FIXME*/ && xExtendedDocHandler.is() ) + { + xExtendedDocHandler->unknown( MENUBAR_DOCTYPE ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + } + + pList->AddAttribute( ATTRIBUTE_XMLNS_MENU, + m_aAttributeType, + XMLNS_MENU ); + + if ( m_bIsMenuBar ) //FIXME + pList->AddAttribute( ATTRIBUTE_NS_ID, + m_aAttributeType, + "menubar" ); + + OUString aRootElement; + if ( m_bIsMenuBar ) + aRootElement = ELEMENT_NS_MENUBAR; + else + aRootElement = ELEMENT_NS_MENUPOPUP; + m_xWriteDocumentHandler->startElement( aRootElement, pList.get() ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + + WriteMenu( m_xMenuBarContainer ); + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( aRootElement ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endDocument(); +} + +void OWriteMenuDocumentHandler::WriteMenu( const Reference< XIndexAccess >& rMenuContainer ) +{ + sal_Int32 nItemCount = rMenuContainer->getCount(); + bool bSeparator = false; + Any aAny; + + for ( sal_Int32 nItemPos = 0; nItemPos < nItemCount; nItemPos++ ) + { + Sequence< PropertyValue > aProps; + aAny = rMenuContainer->getByIndex( nItemPos ); + if ( aAny >>= aProps ) + { + OUString aCommandURL; + OUString aLabel; + OUString aHelpURL; + sal_Int16 nType( css::ui::ItemType::DEFAULT ); + sal_Int16 nItemBits( 0 ); + Reference< XIndexAccess > xSubMenu; + + ExtractMenuParameters( aProps, aCommandURL, aLabel, aHelpURL, xSubMenu, nType, nItemBits ); + if ( xSubMenu.is() ) + { + if ( !aCommandURL.isEmpty() ) + { + ::comphelper::AttributeList* pListMenu = new ::comphelper::AttributeList; + Reference< XAttributeList > xListMenu( static_cast<XAttributeList *>(pListMenu) , UNO_QUERY ); + + pListMenu->AddAttribute( ATTRIBUTE_NS_ID, + m_aAttributeType, + aCommandURL ); + + if ( !aLabel.isEmpty() ) + pListMenu->AddAttribute( ATTRIBUTE_NS_LABEL, + m_aAttributeType, + aLabel ); + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENU, xListMenu ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUPOPUP, m_xEmptyList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + + WriteMenu( xSubMenu ); + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUPOPUP ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENU ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + bSeparator = false; + } + } + else + { + if ( nType == css::ui::ItemType::DEFAULT ) + { + if ( !aCommandURL.isEmpty() ) + { + bSeparator = false; + WriteMenuItem( aCommandURL, aLabel, aHelpURL, nItemBits ); + } + } + else if ( !bSeparator ) + { + // Don't write two separators together + WriteMenuSeparator(); + bSeparator = true; + } + } + } + } +} + +void OWriteMenuDocumentHandler::WriteMenuItem( const OUString& aCommandURL, const OUString& aLabel, const OUString& aHelpURL, sal_Int16 nStyle ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + Reference< XAttributeList > xList( static_cast<XAttributeList *>(pList) , UNO_QUERY ); + + pList->AddAttribute( ATTRIBUTE_NS_ID, + m_aAttributeType, + aCommandURL ); + + if ( !aHelpURL.isEmpty() ) + { + pList->AddAttribute( ATTRIBUTE_NS_HELPID, + m_aAttributeType, + aHelpURL ); + } + + if ( !aLabel.isEmpty() ) + { + pList->AddAttribute( ATTRIBUTE_NS_LABEL, + m_aAttributeType, + aLabel ); + } + if ( nStyle > 0 ) + { + OUStringBuffer aValue; + const MenuStyleItem* pStyle = MenuItemStyles; + + for ( sal_Int32 nIndex = 0; nIndex < nMenuStyleItemEntries; ++nIndex, ++pStyle ) + { + if ( nStyle & pStyle->nBit ) + { + if ( !aValue.isEmpty() ) + aValue.append("+"); + aValue.appendAscii( pStyle->attrName ); + } + } + pList->AddAttribute( ATTRIBUTE_NS_STYLE, + m_aAttributeType, + aValue.makeStringAndClear() ); + } + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUITEM, xList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUITEM ); +} + +void OWriteMenuDocumentHandler::WriteMenuSeparator() +{ + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUSEPARATOR, m_xEmptyList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUSEPARATOR ); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/saxnamespacefilter.cxx b/framework/source/fwe/xml/saxnamespacefilter.cxx new file mode 100644 index 000000000..bf464c663 --- /dev/null +++ b/framework/source/fwe/xml/saxnamespacefilter.cxx @@ -0,0 +1,171 @@ +/* -*- 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 . + */ + +/** Attention: stl headers must(!) be included at first. Otherwise it can make trouble + with solaris headers ... +*/ +#include <vector> + +#include <stdio.h> + +#include <com/sun/star/xml/sax/SAXException.hpp> + +#include <xml/saxnamespacefilter.hxx> + +#include <comphelper/attributelist.hxx> + +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; + +namespace framework{ + +SaxNamespaceFilter::SaxNamespaceFilter( Reference< XDocumentHandler > const & rSax1DocumentHandler ) : + xDocumentHandler( rSax1DocumentHandler ), + m_aXMLAttributeNamespace( "xmlns" ), + m_aXMLAttributeType( "CDATA" ) +{ +} + +SaxNamespaceFilter::~SaxNamespaceFilter() +{ +} + +// XDocumentHandler +void SAL_CALL SaxNamespaceFilter::startDocument() +{ +} + +void SAL_CALL SaxNamespaceFilter::endDocument() +{ +} + +void SAL_CALL SaxNamespaceFilter::startElement( + const OUString& rName, const Reference< XAttributeList > &xAttribs ) +{ + XMLNamespaces aXMLNamespaces; + if ( !m_aNamespaceStack.empty() ) + aXMLNamespaces = m_aNamespaceStack.top(); + + ::comphelper::AttributeList* pNewList = new ::comphelper::AttributeList(); + + // examine all namespaces for this level + ::std::vector< sal_Int16 > aAttributeIndexes; + { + for ( sal_Int16 i=0; i< xAttribs->getLength(); i++ ) + { + OUString aName = xAttribs->getNameByIndex( i ); + if ( aName.startsWith( m_aXMLAttributeNamespace ) ) + aXMLNamespaces.addNamespace( aName, xAttribs->getValueByIndex( i )); + else + aAttributeIndexes.push_back( i ); + } + } + + // current namespaces for this level + m_aNamespaceStack.push( aXMLNamespaces ); + + try + { + // apply namespaces to all remaining attributes + for (auto const& attributeIndex : aAttributeIndexes) + { + OUString aAttributeName = xAttribs->getNameByIndex(attributeIndex); + OUString aValue = xAttribs->getValueByIndex(attributeIndex); + OUString aNamespaceAttributeName = aXMLNamespaces.applyNSToAttributeName( aAttributeName ); + pNewList->AddAttribute( aNamespaceAttributeName, m_aXMLAttributeType, aValue ); + } + } + catch ( SAXException& e ) + { + e.Message = getErrorLineString() + e.Message; + throw; + } + + OUString aNamespaceElementName; + + try + { + aNamespaceElementName = aXMLNamespaces.applyNSToElementName( rName ); + } + catch ( SAXException& e ) + { + e.Message = getErrorLineString() + e.Message; + throw; + } + + xDocumentHandler->startElement( aNamespaceElementName, pNewList ); +} + +void SAL_CALL SaxNamespaceFilter::endElement(const OUString& aName) +{ + XMLNamespaces& aXMLNamespaces = m_aNamespaceStack.top(); + OUString aNamespaceElementName; + + try + { + aNamespaceElementName = aXMLNamespaces.applyNSToElementName( aName ); + } + catch ( SAXException& e ) + { + e.Message = getErrorLineString() + e.Message; + throw; + } + + xDocumentHandler->endElement( aNamespaceElementName ); + m_aNamespaceStack.pop(); +} + +void SAL_CALL SaxNamespaceFilter::characters(const OUString& aChars) +{ + xDocumentHandler->characters( aChars ); +} + +void SAL_CALL SaxNamespaceFilter::ignorableWhitespace(const OUString& aWhitespaces) +{ + xDocumentHandler->ignorableWhitespace( aWhitespaces ); +} + +void SAL_CALL SaxNamespaceFilter::processingInstruction( + const OUString& aTarget, const OUString& aData) +{ + xDocumentHandler->processingInstruction( aTarget, aData ); +} + +void SAL_CALL SaxNamespaceFilter::setDocumentLocator( + const Reference< XLocator > &xLocator) +{ + m_xLocator = xLocator; + xDocumentHandler->setDocumentLocator( xLocator ); +} + +OUString SaxNamespaceFilter::getErrorLineString() +{ + if ( m_xLocator.is() ) + { + char buffer[32]; + snprintf( buffer, sizeof(buffer), "Line: %ld - ", static_cast<long>( m_xLocator->getLineNumber() )); + return OUString::createFromAscii( buffer ); + } + else + return OUString(); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/statusbarconfiguration.cxx b/framework/source/fwe/xml/statusbarconfiguration.cxx new file mode 100644 index 000000000..ce974237b --- /dev/null +++ b/framework/source/fwe/xml/statusbarconfiguration.cxx @@ -0,0 +1,105 @@ +/* -*- 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 <statusbarconfiguration.hxx> +#include <xml/statusbardocumenthandler.hxx> +#include <xml/saxnamespacefilter.hxx> + +#include <com/sun/star/xml/sax/Parser.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/XInputStream.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; + +namespace framework +{ + +bool StatusBarConfiguration::LoadStatusBar( + const Reference< XComponentContext >& rxContext, + const Reference< XInputStream >& xInputStream, + const Reference< XIndexContainer >& rStatusbarConfiguration ) +{ + Reference< XParser > xParser = Parser::create(rxContext); + + // connect stream to input stream to the parser + InputSource aInputSource; + aInputSource.aInputStream = xInputStream; + + // create namespace filter and set menudocument handler inside to support xml namespaces + Reference< XDocumentHandler > xDocHandler( new OReadStatusBarDocumentHandler( rStatusbarConfiguration )); + Reference< XDocumentHandler > xFilter( new SaxNamespaceFilter( xDocHandler )); + + // connect parser and filter + xParser->setDocumentHandler( xFilter ); + + try + { + xParser->parseStream( aInputSource ); + return true; + } + catch ( const RuntimeException& ) + { + return false; + } + catch( const SAXException& ) + { + return false; + } + catch( const css::io::IOException& ) + { + return false; + } +} + +bool StatusBarConfiguration::StoreStatusBar( + const Reference< XComponentContext >& rxContext, + const Reference< XOutputStream >& xOutputStream, + const Reference< XIndexAccess >& rStatusbarConfiguration ) +{ + Reference< XWriter > xWriter = Writer::create( rxContext ); + xWriter->setOutputStream( xOutputStream ); + + try + { + OWriteStatusBarDocumentHandler aWriteStatusBarDocumentHandler( rStatusbarConfiguration, xWriter ); + aWriteStatusBarDocumentHandler.WriteStatusBarDocument(); + return true; + } + catch ( const RuntimeException& ) + { + return false; + } + catch ( const SAXException& ) + { + return false; + } + catch ( const css::io::IOException& ) + { + return false; + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/statusbardocumenthandler.cxx b/framework/source/fwe/xml/statusbardocumenthandler.cxx new file mode 100644 index 000000000..b0e836600 --- /dev/null +++ b/framework/source/fwe/xml/statusbardocumenthandler.cxx @@ -0,0 +1,658 @@ +/* -*- 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 <stdio.h> + +#include <xml/statusbardocumenthandler.hxx> + +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#include <com/sun/star/ui/ItemStyle.hpp> +#include <com/sun/star/ui/ItemType.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> + +#include <vcl/svapp.hxx> +#include <vcl/status.hxx> + +#include <comphelper/attributelist.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::container; + +#define XMLNS_STATUSBAR "http://openoffice.org/2001/statusbar" +#define XMLNS_XLINK "http://www.w3.org/1999/xlink" +#define XMLNS_STATUSBAR_PREFIX "statusbar:" +#define XMLNS_XLINK_PREFIX "xlink:" + +#define XMLNS_FILTER_SEPARATOR "^" + +#define ELEMENT_STATUSBAR "statusbar" +#define ELEMENT_STATUSBARITEM "statusbaritem" + +#define ATTRIBUTE_ALIGN "align" +#define ATTRIBUTE_STYLE "style" +#define ATTRIBUTE_URL "href" +#define ATTRIBUTE_WIDTH "width" +#define ATTRIBUTE_OFFSET "offset" +#define ATTRIBUTE_AUTOSIZE "autosize" +#define ATTRIBUTE_OWNERDRAW "ownerdraw" +#define ATTRIBUTE_HELPURL "helpid" +#define ATTRIBUTE_MANDATORY "mandatory" + +#define ELEMENT_NS_STATUSBAR "statusbar:statusbar" +#define ELEMENT_NS_STATUSBARITEM "statusbar:statusbaritem" + +#define ATTRIBUTE_XMLNS_STATUSBAR "xmlns:statusbar" +#define ATTRIBUTE_XMLNS_XLINK "xmlns:xlink" + +#define ATTRIBUTE_TYPE_CDATA "CDATA" + +#define ATTRIBUTE_BOOLEAN_TRUE "true" +#define ATTRIBUTE_BOOLEAN_FALSE "false" + +#define ATTRIBUTE_ALIGN_LEFT "left" +#define ATTRIBUTE_ALIGN_RIGHT "right" +#define ATTRIBUTE_ALIGN_CENTER "center" + +#define ATTRIBUTE_STYLE_IN "in" +#define ATTRIBUTE_STYLE_OUT "out" +#define ATTRIBUTE_STYLE_FLAT "flat" + +#define STATUSBAR_DOCTYPE "<!DOCTYPE statusbar:statusbar PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\" \"statusbar.dtd\">" + +namespace framework +{ + +// Property names of a menu/menu item ItemDescriptor +static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL"; +static const char ITEM_DESCRIPTOR_HELPURL[] = "HelpURL"; +static const char ITEM_DESCRIPTOR_OFFSET[] = "Offset"; +static const char ITEM_DESCRIPTOR_STYLE[] = "Style"; +static const char ITEM_DESCRIPTOR_WIDTH[] = "Width"; +static const char ITEM_DESCRIPTOR_TYPE[] = "Type"; + +static void ExtractStatusbarItemParameters( + const Sequence< PropertyValue >& rProp, + OUString& rCommandURL, + OUString& rHelpURL, + sal_Int16& rOffset, + sal_Int16& rStyle, + sal_Int16& rWidth ) +{ + for ( const PropertyValue& rEntry : rProp ) + { + if ( rEntry.Name == ITEM_DESCRIPTOR_COMMANDURL ) + { + rEntry.Value >>= rCommandURL; + rCommandURL = rCommandURL.intern(); + } + else if ( rEntry.Name == ITEM_DESCRIPTOR_HELPURL ) + { + rEntry.Value >>= rHelpURL; + } + else if ( rEntry.Name == ITEM_DESCRIPTOR_OFFSET ) + { + rEntry.Value >>= rOffset; + } + else if ( rEntry.Name == ITEM_DESCRIPTOR_STYLE ) + { + rEntry.Value >>= rStyle; + } + else if ( rEntry.Name == ITEM_DESCRIPTOR_WIDTH ) + { + rEntry.Value >>= rWidth; + } + } +} + +namespace { + +struct StatusBarEntryProperty +{ + OReadStatusBarDocumentHandler::StatusBar_XML_Namespace nNamespace; + char aEntryName[20]; +}; + +} + +StatusBarEntryProperty const StatusBarEntries[OReadStatusBarDocumentHandler::SB_XML_ENTRY_COUNT] = +{ + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ELEMENT_STATUSBAR }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ELEMENT_STATUSBARITEM }, + { OReadStatusBarDocumentHandler::SB_NS_XLINK, ATTRIBUTE_URL }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_ALIGN }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_STYLE }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_AUTOSIZE }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_OWNERDRAW }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_WIDTH }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_OFFSET }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_HELPURL }, + { OReadStatusBarDocumentHandler::SB_NS_STATUSBAR, ATTRIBUTE_MANDATORY } +}; + +OReadStatusBarDocumentHandler::OReadStatusBarDocumentHandler( + const Reference< XIndexContainer >& rStatusBarItems ) : + m_aStatusBarItems( rStatusBarItems ) +{ + // create hash map + for ( int i = 0; i < int(SB_XML_ENTRY_COUNT); i++ ) + { + if ( StatusBarEntries[i].nNamespace == SB_NS_STATUSBAR ) + { + OUString temp = XMLNS_STATUSBAR XMLNS_FILTER_SEPARATOR + + OUString::createFromAscii( StatusBarEntries[i].aEntryName ); + m_aStatusBarMap.emplace( temp, static_cast<StatusBar_XML_Entry>(i) ); + } + else + { + OUString temp = XMLNS_XLINK XMLNS_FILTER_SEPARATOR + + OUString::createFromAscii( StatusBarEntries[i].aEntryName ); + m_aStatusBarMap.emplace( temp, static_cast<StatusBar_XML_Entry>(i) ); + } + } + + m_bStatusBarStartFound = false; + m_bStatusBarItemStartFound = false; +} + +OReadStatusBarDocumentHandler::~OReadStatusBarDocumentHandler() +{ +} + +// XDocumentHandler +void SAL_CALL OReadStatusBarDocumentHandler::startDocument() +{ +} + +void SAL_CALL OReadStatusBarDocumentHandler::endDocument() +{ + SolarMutexGuard g; + + if ( m_bStatusBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "No matching start or end element 'statusbar' found!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadStatusBarDocumentHandler::startElement( + const OUString& aName, const Reference< XAttributeList > &xAttribs ) +{ + SolarMutexGuard g; + + StatusBarHashMap::const_iterator pStatusBarEntry = m_aStatusBarMap.find( aName ); + if ( pStatusBarEntry == m_aStatusBarMap.end() ) + return; + + switch ( pStatusBarEntry->second ) + { + case SB_ELEMENT_STATUSBAR: + { + if ( m_bStatusBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element 'statusbar:statusbar' cannot be embedded into 'statusbar:statusbar'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bStatusBarStartFound = true; + } + break; + + case SB_ELEMENT_STATUSBARITEM: + { + if ( !m_bStatusBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element 'statusbar:statusbaritem' must be embedded into element 'statusbar:statusbar'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + if ( m_bStatusBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element statusbar:statusbaritem is not a container!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + OUString aCommandURL; + OUString aHelpURL; + sal_Int16 nItemBits( ItemStyle::ALIGN_CENTER|ItemStyle::DRAW_IN3D|ItemStyle::MANDATORY ); + sal_Int16 nWidth( 0 ); + sal_Int16 nOffset( STATUSBAR_OFFSET ); + bool bCommandURL( false ); + + m_bStatusBarItemStartFound = true; + for ( sal_Int16 n = 0; n < xAttribs->getLength(); n++ ) + { + pStatusBarEntry = m_aStatusBarMap.find( xAttribs->getNameByIndex( n ) ); + if ( pStatusBarEntry != m_aStatusBarMap.end() ) + { + switch ( pStatusBarEntry->second ) + { + case SB_ATTRIBUTE_URL: + { + bCommandURL = true; + aCommandURL = xAttribs->getValueByIndex( n ); + } + break; + + case SB_ATTRIBUTE_ALIGN: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_ALIGN_LEFT ) + { + nItemBits |= ItemStyle::ALIGN_LEFT; + nItemBits &= ~ItemStyle::ALIGN_CENTER; + } + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_ALIGN_CENTER ) + { + nItemBits |= ItemStyle::ALIGN_CENTER; + nItemBits &= ~ItemStyle::ALIGN_LEFT; + } + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_ALIGN_RIGHT ) + { + nItemBits |= ItemStyle::ALIGN_RIGHT; + } + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute statusbar:align must have one value of 'left','right' or 'center'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + case SB_ATTRIBUTE_STYLE: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_STYLE_IN ) + { + nItemBits |= ItemStyle::DRAW_IN3D; + nItemBits &= ~ItemStyle::DRAW_OUT3D; + } + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_STYLE_OUT ) + { + nItemBits |= ItemStyle::DRAW_OUT3D; + nItemBits &= ~ItemStyle::DRAW_IN3D; + } + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_STYLE_FLAT ) + { + nItemBits |= ItemStyle::DRAW_FLAT; + } + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute statusbar:autosize must have value 'true' or 'false'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + case SB_ATTRIBUTE_AUTOSIZE: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_TRUE ) + nItemBits |= ItemStyle::AUTO_SIZE; + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_FALSE ) + nItemBits &= ~ItemStyle::AUTO_SIZE; + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute statusbar:autosize must have value 'true' or 'false'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + case SB_ATTRIBUTE_OWNERDRAW: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_TRUE ) + nItemBits |= ItemStyle::OWNER_DRAW; + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_FALSE ) + nItemBits &= ~ItemStyle::OWNER_DRAW; + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute statusbar:ownerdraw must have value 'true' or 'false'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + case SB_ATTRIBUTE_WIDTH: + { + nWidth = static_cast<sal_Int16>(xAttribs->getValueByIndex( n ).toInt32()); + } + break; + + case SB_ATTRIBUTE_OFFSET: + { + nOffset = static_cast<sal_Int16>(xAttribs->getValueByIndex( n ).toInt32()); + } + break; + + case SB_ATTRIBUTE_HELPURL: + { + aHelpURL = xAttribs->getValueByIndex( n ); + } + break; + + case SB_ATTRIBUTE_MANDATORY: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_TRUE ) + nItemBits |= ItemStyle::MANDATORY; + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_FALSE ) + nItemBits &= ~ItemStyle::MANDATORY; + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute statusbar:mandatory must have value 'true' or 'false'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + default: + break; + } + } + } // for + + if ( !bCommandURL ) + { + OUString aErrorMessage = getErrorLineString() + "Required attribute statusbar:url must have a value!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + else + { + Sequence< PropertyValue > aStatusbarItemProp( 6 ); + aStatusbarItemProp[0].Name = ITEM_DESCRIPTOR_COMMANDURL; + aStatusbarItemProp[1].Name = ITEM_DESCRIPTOR_HELPURL; + aStatusbarItemProp[2].Name = ITEM_DESCRIPTOR_OFFSET; + aStatusbarItemProp[3].Name = ITEM_DESCRIPTOR_STYLE; + aStatusbarItemProp[4].Name = ITEM_DESCRIPTOR_WIDTH; + aStatusbarItemProp[5].Name = ITEM_DESCRIPTOR_TYPE; + + aStatusbarItemProp[0].Value <<= aCommandURL; + aStatusbarItemProp[1].Value <<= aHelpURL; + aStatusbarItemProp[2].Value <<= nOffset; + aStatusbarItemProp[3].Value <<= nItemBits; + aStatusbarItemProp[4].Value <<= nWidth; + aStatusbarItemProp[5].Value <<= css::ui::ItemType::DEFAULT; + + m_aStatusBarItems->insertByIndex( m_aStatusBarItems->getCount(), makeAny( aStatusbarItemProp ) ); + } + } + break; + + default: + break; + } +} + +void SAL_CALL OReadStatusBarDocumentHandler::endElement(const OUString& aName) +{ + SolarMutexGuard g; + + StatusBarHashMap::const_iterator pStatusBarEntry = m_aStatusBarMap.find( aName ); + if ( pStatusBarEntry == m_aStatusBarMap.end() ) + return; + + switch ( pStatusBarEntry->second ) + { + case SB_ELEMENT_STATUSBAR: + { + if ( !m_bStatusBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'statusbar' found, but no start element 'statusbar'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bStatusBarStartFound = false; + } + break; + + case SB_ELEMENT_STATUSBARITEM: + { + if ( !m_bStatusBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'statusbar:statusbaritem' found, but no start element 'statusbar:statusbaritem'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bStatusBarItemStartFound = false; + } + break; + + default: break; + } +} + +void SAL_CALL OReadStatusBarDocumentHandler::characters(const OUString&) +{ +} + +void SAL_CALL OReadStatusBarDocumentHandler::ignorableWhitespace(const OUString&) +{ +} + +void SAL_CALL OReadStatusBarDocumentHandler::processingInstruction( + const OUString& /*aTarget*/, const OUString& /*aData*/ ) +{ +} + +void SAL_CALL OReadStatusBarDocumentHandler::setDocumentLocator( + const Reference< XLocator > &xLocator) +{ + SolarMutexGuard g; + + m_xLocator = xLocator; +} + +OUString OReadStatusBarDocumentHandler::getErrorLineString() +{ + SolarMutexGuard g; + + if ( m_xLocator.is() ) + { + char buffer[32]; + snprintf( buffer, sizeof(buffer), "Line: %ld - ", static_cast<long>( m_xLocator->getLineNumber() )); + return OUString::createFromAscii( buffer ); + } + else + return OUString(); +} + +// OWriteStatusBarDocumentHandler + +OWriteStatusBarDocumentHandler::OWriteStatusBarDocumentHandler( + const Reference< XIndexAccess >& aStatusBarItems, + const Reference< XDocumentHandler >& rWriteDocumentHandler ) : + m_aStatusBarItems( aStatusBarItems ), + m_xWriteDocumentHandler( rWriteDocumentHandler ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + m_xEmptyList.set( static_cast<XAttributeList *>(pList), UNO_QUERY ); + m_aAttributeType = ATTRIBUTE_TYPE_CDATA; + m_aXMLXlinkNS = XMLNS_XLINK_PREFIX; + m_aXMLStatusBarNS = XMLNS_STATUSBAR_PREFIX; +} + +OWriteStatusBarDocumentHandler::~OWriteStatusBarDocumentHandler() +{ +} + +void OWriteStatusBarDocumentHandler::WriteStatusBarDocument() +{ + SolarMutexGuard g; + + m_xWriteDocumentHandler->startDocument(); + + // write DOCTYPE line! + Reference< XExtendedDocumentHandler > xExtendedDocHandler( m_xWriteDocumentHandler, UNO_QUERY ); + if ( xExtendedDocHandler.is() ) + { + xExtendedDocHandler->unknown( STATUSBAR_DOCTYPE ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + } + + rtl::Reference<::comphelper::AttributeList> pList = new ::comphelper::AttributeList; + + pList->AddAttribute( ATTRIBUTE_XMLNS_STATUSBAR, + m_aAttributeType, + XMLNS_STATUSBAR ); + + pList->AddAttribute( ATTRIBUTE_XMLNS_XLINK, + m_aAttributeType, + XMLNS_XLINK ); + + m_xWriteDocumentHandler->startElement( ELEMENT_NS_STATUSBAR, pList.get() ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + + sal_Int32 nItemCount = m_aStatusBarItems->getCount(); + Any aAny; + + for ( sal_Int32 nItemPos = 0; nItemPos < nItemCount; nItemPos++ ) + { + Sequence< PropertyValue > aProps; + aAny = m_aStatusBarItems->getByIndex( nItemPos ); + if ( aAny >>= aProps ) + { + OUString aCommandURL; + OUString aHelpURL; + sal_Int16 nStyle( ItemStyle::ALIGN_CENTER|ItemStyle::DRAW_IN3D ); + sal_Int16 nWidth( 0 ); + sal_Int16 nOffset( STATUSBAR_OFFSET ); + + ExtractStatusbarItemParameters( + aProps, + aCommandURL, + aHelpURL, + nOffset, + nStyle, + nWidth ); + + if ( !aCommandURL.isEmpty() ) + WriteStatusBarItem( aCommandURL, nOffset, nStyle, nWidth ); + } + } + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_STATUSBAR ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endDocument(); +} + +// protected member functions + +void OWriteStatusBarDocumentHandler::WriteStatusBarItem( + const OUString& rCommandURL, + sal_Int16 nOffset, + sal_Int16 nStyle, + sal_Int16 nWidth ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + Reference< XAttributeList > xList( static_cast<XAttributeList *>(pList) , UNO_QUERY ); + + if (m_aAttributeURL.isEmpty() ) + { + m_aAttributeURL = m_aXMLXlinkNS + ATTRIBUTE_URL; + } + + // save required attribute (URL) + pList->AddAttribute( m_aAttributeURL, m_aAttributeType, rCommandURL ); + + // alignment + if ( nStyle & ItemStyle::ALIGN_RIGHT ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_ALIGN, + m_aAttributeType, + ATTRIBUTE_ALIGN_RIGHT ); + } + else if ( nStyle & ItemStyle::ALIGN_CENTER ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_ALIGN, + m_aAttributeType, + ATTRIBUTE_ALIGN_CENTER ); + } + else + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_ALIGN, + m_aAttributeType, + ATTRIBUTE_ALIGN_LEFT ); + } + + // style ( StatusBarItemBits::In is default ) + if ( nStyle & ItemStyle::DRAW_FLAT ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_STYLE, + m_aAttributeType, + ATTRIBUTE_STYLE_FLAT ); + } + else if ( nStyle & ItemStyle::DRAW_OUT3D ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_STYLE, + m_aAttributeType, + ATTRIBUTE_STYLE_OUT ); + } + + // autosize (default sal_False) + if ( nStyle & ItemStyle::AUTO_SIZE ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_AUTOSIZE, + m_aAttributeType, + ATTRIBUTE_BOOLEAN_TRUE ); + } + + // ownerdraw (default sal_False) + if ( nStyle & ItemStyle::OWNER_DRAW ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_OWNERDRAW, + m_aAttributeType, + ATTRIBUTE_BOOLEAN_TRUE ); + } + + // width (default 0) + if ( nWidth > 0 ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_WIDTH, + m_aAttributeType, + OUString::number( nWidth ) ); + } + + // offset (default STATUSBAR_OFFSET) + if ( nOffset != STATUSBAR_OFFSET ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_OFFSET, + m_aAttributeType, + OUString::number( nOffset ) ); + } + + // mandatory (default sal_True) + if ( !( nStyle & ItemStyle::MANDATORY ) ) + { + pList->AddAttribute( m_aXMLStatusBarNS + ATTRIBUTE_MANDATORY, + m_aAttributeType, + ATTRIBUTE_BOOLEAN_FALSE ); + } + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_STATUSBARITEM, xList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_STATUSBARITEM ); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/toolboxconfiguration.cxx b/framework/source/fwe/xml/toolboxconfiguration.cxx new file mode 100644 index 000000000..7eb068357 --- /dev/null +++ b/framework/source/fwe/xml/toolboxconfiguration.cxx @@ -0,0 +1,108 @@ +/* -*- 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 <toolboxconfiguration.hxx> +#include <xml/toolboxdocumenthandler.hxx> +#include <xml/saxnamespacefilter.hxx> + +#include <com/sun/star/xml/sax/Parser.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/XInputStream.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; + +namespace framework +{ + +bool ToolBoxConfiguration::LoadToolBox( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::io::XInputStream >& rInputStream, + const css::uno::Reference< css::container::XIndexContainer >& rToolbarConfiguration ) +{ + Reference< XParser > xParser = Parser::create(rxContext); + + // connect stream to input stream to the parser + InputSource aInputSource; + + aInputSource.aInputStream = rInputStream; + + // create namespace filter and set menudocument handler inside to support xml namespaces + Reference< XDocumentHandler > xDocHandler( new OReadToolBoxDocumentHandler( rToolbarConfiguration )); + Reference< XDocumentHandler > xFilter( new SaxNamespaceFilter( xDocHandler )); + + // connect parser and filter + xParser->setDocumentHandler( xFilter ); + + try + { + xParser->parseStream( aInputSource ); + return true; + } + catch ( const RuntimeException& ) + { + return false; + } + catch( const SAXException& ) + { + return false; + } + catch( const css::io::IOException& ) + { + return false; + } +} + +bool ToolBoxConfiguration::StoreToolBox( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::io::XOutputStream >& rOutputStream, + const css::uno::Reference< css::container::XIndexAccess >& rToolbarConfiguration ) +{ + Reference< XWriter > xWriter = Writer::create(rxContext); + xWriter->setOutputStream( rOutputStream ); + + try + { + Reference< XDocumentHandler > xHandler( xWriter, UNO_QUERY_THROW ); + OWriteToolBoxDocumentHandler aWriteToolBoxDocumentHandler( rToolbarConfiguration, xHandler ); + aWriteToolBoxDocumentHandler.WriteToolBoxDocument(); + return true; + } + catch ( const RuntimeException& ) + { + return false; + } + catch ( const SAXException& ) + { + return false; + } + catch ( const css::io::IOException& ) + { + return false; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/toolboxdocumenthandler.cxx b/framework/source/fwe/xml/toolboxdocumenthandler.cxx new file mode 100644 index 000000000..ea5facd72 --- /dev/null +++ b/framework/source/fwe/xml/toolboxdocumenthandler.cxx @@ -0,0 +1,759 @@ +/* -*- 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 <stdio.h> + +#include <xml/toolboxdocumenthandler.hxx> +#include <xml/toolboxconfigurationdefines.hxx> + +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#include <com/sun/star/ui/ItemType.hpp> +#include <com/sun/star/ui/ItemStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> + +#include <sal/config.h> +#include <sal/macros.h> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <rtl/ustrbuf.hxx> + +#include <comphelper/attributelist.hxx> +#include <comphelper/propertysequence.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml::sax; + +#define TOOLBAR_DOCTYPE "<!DOCTYPE toolbar:toolbar PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\" \"toolbar.dtd\">" + +namespace framework +{ + +// Property names of a menu/menu item ItemDescriptor +static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL"; +static const char ITEM_DESCRIPTOR_LABEL[] = "Label"; +static const char ITEM_DESCRIPTOR_TYPE[] = "Type"; +static const char ITEM_DESCRIPTOR_STYLE[] = "Style"; +static const char ITEM_DESCRIPTOR_VISIBLE[] = "IsVisible"; + +static void ExtractToolbarParameters( const Sequence< PropertyValue >& rProp, + OUString& rCommandURL, + OUString& rLabel, + sal_Int16& rStyle, + bool& rVisible, + sal_Int16& rType ) +{ + for ( const PropertyValue& rEntry : rProp ) + { + if ( rEntry.Name == ITEM_DESCRIPTOR_COMMANDURL ) + { + rEntry.Value >>= rCommandURL; + rCommandURL = rCommandURL.intern(); + } + else if ( rEntry.Name == ITEM_DESCRIPTOR_LABEL ) + rEntry.Value >>= rLabel; + else if ( rEntry.Name == ITEM_DESCRIPTOR_TYPE ) + rEntry.Value >>= rType; + else if ( rEntry.Name == ITEM_DESCRIPTOR_VISIBLE ) + rEntry.Value >>= rVisible; + else if ( rEntry.Name == ITEM_DESCRIPTOR_STYLE ) + rEntry.Value >>= rStyle; + } +} + +namespace { + +struct ToolboxStyleItem +{ + sal_Int16 nBit; + const char* attrName; +}; + +} + +const ToolboxStyleItem Styles[ ] = { + { css::ui::ItemStyle::RADIO_CHECK, ATTRIBUTE_ITEMSTYLE_RADIO }, + { css::ui::ItemStyle::ALIGN_LEFT, ATTRIBUTE_ITEMSTYLE_LEFT }, + { css::ui::ItemStyle::AUTO_SIZE, ATTRIBUTE_ITEMSTYLE_AUTO }, + { css::ui::ItemStyle::REPEAT, ATTRIBUTE_ITEMSTYLE_REPEAT }, + { css::ui::ItemStyle::DROPDOWN_ONLY, ATTRIBUTE_ITEMSTYLE_DROPDOWNONLY }, + { css::ui::ItemStyle::DROP_DOWN, ATTRIBUTE_ITEMSTYLE_DROPDOWN }, + { css::ui::ItemStyle::ICON, ATTRIBUTE_ITEMSTYLE_IMAGE }, + { css::ui::ItemStyle::TEXT, ATTRIBUTE_ITEMSTYLE_TEXT }, +}; + +sal_Int32 const nStyleItemEntries = SAL_N_ELEMENTS(Styles); + +namespace { + +struct ToolBarEntryProperty +{ + OReadToolBoxDocumentHandler::ToolBox_XML_Namespace nNamespace; + char aEntryName[20]; +}; + +} + +ToolBarEntryProperty const ToolBoxEntries[OReadToolBoxDocumentHandler::TB_XML_ENTRY_COUNT] = +{ + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ELEMENT_TOOLBAR }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ELEMENT_TOOLBARITEM }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ELEMENT_TOOLBARSPACE }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ELEMENT_TOOLBARBREAK }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ELEMENT_TOOLBARSEPARATOR }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ATTRIBUTE_TEXT }, + { OReadToolBoxDocumentHandler::TB_NS_XLINK, ATTRIBUTE_URL }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ATTRIBUTE_VISIBLE }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ATTRIBUTE_ITEMSTYLE }, + { OReadToolBoxDocumentHandler::TB_NS_TOOLBAR, ATTRIBUTE_UINAME }, +}; + +OReadToolBoxDocumentHandler::OReadToolBoxDocumentHandler( const Reference< XIndexContainer >& rItemContainer ) : + m_rItemContainer( rItemContainer ), + m_aType( ITEM_DESCRIPTOR_TYPE ), + m_aLabel( ITEM_DESCRIPTOR_LABEL ), + m_aStyle( ITEM_DESCRIPTOR_STYLE ), + m_aIsVisible( ITEM_DESCRIPTOR_VISIBLE ), + m_aCommandURL( ITEM_DESCRIPTOR_COMMANDURL ) + { + // create hash map + for ( int i = 0; i < int(TB_XML_ENTRY_COUNT); i++ ) + { + if ( ToolBoxEntries[i].nNamespace == TB_NS_TOOLBAR ) + { + OUString temp = XMLNS_TOOLBAR XMLNS_FILTER_SEPARATOR + + OUString::createFromAscii( ToolBoxEntries[i].aEntryName ); + m_aToolBoxMap.emplace( temp, static_cast<ToolBox_XML_Entry>(i) ); + } + else + { + OUString temp = XMLNS_XLINK XMLNS_FILTER_SEPARATOR + + OUString::createFromAscii( ToolBoxEntries[i].aEntryName ); + m_aToolBoxMap.emplace( temp, static_cast<ToolBox_XML_Entry>(i) ); + } + } + + // pre-calculate a hash code for all style strings to speed up xml read process + m_nHashCode_Style_Radio = OUString( ATTRIBUTE_ITEMSTYLE_RADIO ).hashCode(); + m_nHashCode_Style_Left = OUString( ATTRIBUTE_ITEMSTYLE_LEFT ).hashCode(); + m_nHashCode_Style_AutoSize = OUString( ATTRIBUTE_ITEMSTYLE_AUTOSIZE ).hashCode(); + m_nHashCode_Style_DropDown = OUString( ATTRIBUTE_ITEMSTYLE_DROPDOWN ).hashCode(); + m_nHashCode_Style_Repeat = OUString( ATTRIBUTE_ITEMSTYLE_REPEAT ).hashCode(); + m_nHashCode_Style_DropDownOnly = OUString( ATTRIBUTE_ITEMSTYLE_DROPDOWNONLY ).hashCode(); + m_nHashCode_Style_Text = OUString( ATTRIBUTE_ITEMSTYLE_TEXT ).hashCode(); + m_nHashCode_Style_Image = OUString( ATTRIBUTE_ITEMSTYLE_IMAGE ).hashCode(); + + m_bToolBarStartFound = false; + m_bToolBarItemStartFound = false; + m_bToolBarSpaceStartFound = false; + m_bToolBarBreakStartFound = false; + m_bToolBarSeparatorStartFound = false; +} + +OReadToolBoxDocumentHandler::~OReadToolBoxDocumentHandler() +{ +} + +// XDocumentHandler +void SAL_CALL OReadToolBoxDocumentHandler::startDocument() +{ +} + +void SAL_CALL OReadToolBoxDocumentHandler::endDocument() +{ + SolarMutexGuard g; + + if ( m_bToolBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "No matching start or end element 'toolbar' found!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } +} + +void SAL_CALL OReadToolBoxDocumentHandler::startElement( + const OUString& aName, const Reference< XAttributeList > &xAttribs ) +{ + SolarMutexGuard g; + + ToolBoxHashMap::const_iterator pToolBoxEntry = m_aToolBoxMap.find( aName ); + if ( pToolBoxEntry == m_aToolBoxMap.end() ) + return; + + switch ( pToolBoxEntry->second ) + { + case TB_ELEMENT_TOOLBAR: + { + if ( m_bToolBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element 'toolbar:toolbar' cannot be embedded into 'toolbar:toolbar'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + else + { + // Check if we have a UI name set in our XML file + OUString aUIName; + for ( sal_Int16 n = 0; n < xAttribs->getLength(); n++ ) + { + pToolBoxEntry = m_aToolBoxMap.find( xAttribs->getNameByIndex( n ) ); + if ( pToolBoxEntry != m_aToolBoxMap.end() ) + { + switch ( pToolBoxEntry->second ) + { + case TB_ATTRIBUTE_UINAME: + aUIName = xAttribs->getValueByIndex( n ); + break; + default: + break; + } + } + } + if ( !aUIName.isEmpty() ) + { + // Try to set UI name as a container property + Reference< XPropertySet > xPropSet( m_rItemContainer, UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + xPropSet->setPropertyValue("UIName", makeAny( aUIName ) ); + } + catch ( const UnknownPropertyException& ) + { + } + } + + } + } + m_bToolBarStartFound = true; + } + break; + + case TB_ELEMENT_TOOLBARITEM: + { + if ( !m_bToolBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element 'toolbar:toolbaritem' must be embedded into element 'toolbar:toolbar'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + if ( m_bToolBarSeparatorStartFound || + m_bToolBarBreakStartFound || + m_bToolBarSpaceStartFound || + m_bToolBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element toolbar:toolbaritem is not a container!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + bool bAttributeURL = false; + + m_bToolBarItemStartFound = true; + OUString aLabel; + OUString aCommandURL; + sal_uInt16 nItemBits( 0 ); + bool bVisible( true ); + + for ( sal_Int16 n = 0; n < xAttribs->getLength(); n++ ) + { + pToolBoxEntry = m_aToolBoxMap.find( xAttribs->getNameByIndex( n ) ); + if ( pToolBoxEntry != m_aToolBoxMap.end() ) + { + switch ( pToolBoxEntry->second ) + { + case TB_ATTRIBUTE_TEXT: + { + aLabel = xAttribs->getValueByIndex( n ); + } + break; + + case TB_ATTRIBUTE_URL: + { + bAttributeURL = true; + aCommandURL = xAttribs->getValueByIndex( n ).intern(); + } + break; + + case TB_ATTRIBUTE_VISIBLE: + { + if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_TRUE ) + bVisible = true; + else if ( xAttribs->getValueByIndex( n ) == ATTRIBUTE_BOOLEAN_FALSE ) + bVisible = false; + else + { + OUString aErrorMessage = getErrorLineString() + "Attribute toolbar:visible must have value 'true' or 'false'!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + } + break; + + case TB_ATTRIBUTE_STYLE: + { + // read space separated item style list + OUString aTemp = xAttribs->getValueByIndex( n ); + sal_Int32 nIndex = 0; + + do + { + OUString aToken = aTemp.getToken( 0, ' ', nIndex ); + if ( !aToken.isEmpty() ) + { + sal_Int32 nHashCode = aToken.hashCode(); + if ( nHashCode == m_nHashCode_Style_Radio ) + nItemBits |= css::ui::ItemStyle::RADIO_CHECK; + else if ( nHashCode == m_nHashCode_Style_Left ) + nItemBits |= css::ui::ItemStyle::ALIGN_LEFT; + else if ( nHashCode == m_nHashCode_Style_AutoSize ) + nItemBits |= css::ui::ItemStyle::AUTO_SIZE; + else if ( nHashCode == m_nHashCode_Style_Repeat ) + nItemBits |= css::ui::ItemStyle::REPEAT; + else if ( nHashCode == m_nHashCode_Style_DropDownOnly ) + nItemBits |= css::ui::ItemStyle::DROPDOWN_ONLY; + else if ( nHashCode == m_nHashCode_Style_DropDown ) + nItemBits |= css::ui::ItemStyle::DROP_DOWN; + else if ( nHashCode == m_nHashCode_Style_Text ) + nItemBits |= css::ui::ItemStyle::TEXT; + else if ( nHashCode == m_nHashCode_Style_Image ) + nItemBits |= css::ui::ItemStyle::ICON; + } + } + while ( nIndex >= 0 ); + } + break; + + default: + break; + } + } + } // for + + if ( !bAttributeURL ) + { + OUString aErrorMessage = getErrorLineString() + "Required attribute toolbar:url must have a value!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + if ( !aCommandURL.isEmpty() ) + { + //fix for fdo#39370 + /// check whether RTL interface or not + if(AllSettings::GetLayoutRTL()){ + if (aCommandURL == ".uno:ParaLeftToRight") + aCommandURL = ".uno:ParaRightToLeft"; + else if (aCommandURL == ".uno:ParaRightToLeft") + aCommandURL = ".uno:ParaLeftToRight"; + else if (aCommandURL == ".uno:LeftPara") + aCommandURL = ".uno:RightPara"; + else if (aCommandURL == ".uno:RightPara") + aCommandURL = ".uno:LeftPara"; + else if (aCommandURL == ".uno:AlignLeft") + aCommandURL = ".uno:AlignRight"; + else if (aCommandURL == ".uno:AlignRight") + aCommandURL = ".uno:AlignLeft"; + else if (aCommandURL == ".uno:WrapLeft") + aCommandURL = ".uno:WrapRight"; + else if (aCommandURL == ".uno:WrapRight") + aCommandURL = ".uno:WrapLeft"; + } + + auto aToolbarItemProp( comphelper::InitPropertySequence( { + { m_aCommandURL, css::uno::makeAny( aCommandURL ) }, + { m_aLabel, css::uno::makeAny( aLabel ) }, + { m_aType, css::uno::makeAny( css::ui::ItemType::DEFAULT ) }, + { m_aStyle, css::uno::makeAny( nItemBits ) }, + { m_aIsVisible, css::uno::makeAny( bVisible ) }, + } ) ); + + m_rItemContainer->insertByIndex( m_rItemContainer->getCount(), makeAny( aToolbarItemProp ) ); + } + } + break; + + case TB_ELEMENT_TOOLBARSPACE: + { + if ( m_bToolBarSeparatorStartFound || + m_bToolBarBreakStartFound || + m_bToolBarSpaceStartFound || + m_bToolBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element toolbar:toolbarspace is not a container!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarSpaceStartFound = true; + + Sequence< PropertyValue > aToolbarItemProp( 2 ); + aToolbarItemProp[0].Name = m_aCommandURL; + aToolbarItemProp[1].Name = m_aType; + + aToolbarItemProp[0].Value <<= OUString(); + aToolbarItemProp[1].Value <<= css::ui::ItemType::SEPARATOR_SPACE; + + m_rItemContainer->insertByIndex( m_rItemContainer->getCount(), makeAny( aToolbarItemProp ) ); + } + break; + + case TB_ELEMENT_TOOLBARBREAK: + { + if ( m_bToolBarSeparatorStartFound || + m_bToolBarBreakStartFound || + m_bToolBarSpaceStartFound || + m_bToolBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element toolbar:toolbarbreak is not a container!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarBreakStartFound = true; + + Sequence< PropertyValue > aToolbarItemProp( 2 ); + aToolbarItemProp[0].Name = m_aCommandURL; + aToolbarItemProp[1].Name = m_aType; + + aToolbarItemProp[0].Value <<= OUString(); + aToolbarItemProp[1].Value <<= css::ui::ItemType::SEPARATOR_LINEBREAK; + + m_rItemContainer->insertByIndex( m_rItemContainer->getCount(), makeAny( aToolbarItemProp ) ); + } + break; + + case TB_ELEMENT_TOOLBARSEPARATOR: + { + if ( m_bToolBarSeparatorStartFound || + m_bToolBarBreakStartFound || + m_bToolBarSpaceStartFound || + m_bToolBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "Element toolbar:toolbarseparator is not a container!"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarSeparatorStartFound = true; + + Sequence< PropertyValue > aToolbarItemProp( 2 ); + aToolbarItemProp[0].Name = m_aCommandURL; + aToolbarItemProp[1].Name = m_aType; + + aToolbarItemProp[0].Value <<= OUString(); + aToolbarItemProp[1].Value <<= css::ui::ItemType::SEPARATOR_LINE; + + m_rItemContainer->insertByIndex( m_rItemContainer->getCount(), makeAny( aToolbarItemProp ) ); + } + break; + + default: + break; + } +} + +void SAL_CALL OReadToolBoxDocumentHandler::endElement(const OUString& aName) +{ + SolarMutexGuard g; + + ToolBoxHashMap::const_iterator pToolBoxEntry = m_aToolBoxMap.find( aName ); + if ( pToolBoxEntry == m_aToolBoxMap.end() ) + return; + + switch ( pToolBoxEntry->second ) + { + case TB_ELEMENT_TOOLBAR: + { + if ( !m_bToolBarStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'toolbar' found, but no start element 'toolbar'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarStartFound = false; + } + break; + + case TB_ELEMENT_TOOLBARITEM: + { + if ( !m_bToolBarItemStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'toolbar:toolbaritem' found, but no start element 'toolbar:toolbaritem'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarItemStartFound = false; + } + break; + + case TB_ELEMENT_TOOLBARBREAK: + { + if ( !m_bToolBarBreakStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'toolbar:toolbarbreak' found, but no start element 'toolbar:toolbarbreak'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarBreakStartFound = false; + } + break; + + case TB_ELEMENT_TOOLBARSPACE: + { + if ( !m_bToolBarSpaceStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'toolbar:toolbarspace' found, but no start element 'toolbar:toolbarspace'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarSpaceStartFound = false; + } + break; + + case TB_ELEMENT_TOOLBARSEPARATOR: + { + if ( !m_bToolBarSeparatorStartFound ) + { + OUString aErrorMessage = getErrorLineString() + "End element 'toolbar:toolbarseparator' found, but no start element 'toolbar:toolbarseparator'"; + throw SAXException( aErrorMessage, Reference< XInterface >(), Any() ); + } + + m_bToolBarSeparatorStartFound = false; + } + break; + + default: break; + } +} + +void SAL_CALL OReadToolBoxDocumentHandler::characters(const OUString&) +{ +} + +void SAL_CALL OReadToolBoxDocumentHandler::ignorableWhitespace(const OUString&) +{ +} + +void SAL_CALL OReadToolBoxDocumentHandler::processingInstruction( + const OUString& /*aTarget*/, const OUString& /*aData*/ ) +{ +} + +void SAL_CALL OReadToolBoxDocumentHandler::setDocumentLocator( + const Reference< XLocator > &xLocator) +{ + SolarMutexGuard g; + + m_xLocator = xLocator; +} + +OUString OReadToolBoxDocumentHandler::getErrorLineString() +{ + SolarMutexGuard g; + + if ( m_xLocator.is() ) + { + char buffer[32]; + snprintf( buffer, sizeof(buffer), "Line: %ld - ", static_cast<long>( m_xLocator->getLineNumber() )); + return OUString::createFromAscii( buffer ); + } + else + return OUString(); +} + +// OWriteToolBoxDocumentHandler + +OWriteToolBoxDocumentHandler::OWriteToolBoxDocumentHandler( + const Reference< XIndexAccess >& rItemAccess, + Reference< XDocumentHandler > const & rWriteDocumentHandler ) : + m_xWriteDocumentHandler( rWriteDocumentHandler ), + m_rItemAccess( rItemAccess ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + m_xEmptyList.set( static_cast<XAttributeList *>(pList), UNO_QUERY ); + m_aAttributeType = ATTRIBUTE_TYPE_CDATA; + m_aXMLXlinkNS = XMLNS_XLINK_PREFIX; + m_aXMLToolbarNS = XMLNS_TOOLBAR_PREFIX; +} + +OWriteToolBoxDocumentHandler::~OWriteToolBoxDocumentHandler() +{ +} + +void OWriteToolBoxDocumentHandler::WriteToolBoxDocument() +{ + SolarMutexGuard g; + + m_xWriteDocumentHandler->startDocument(); + + // write DOCTYPE line! + Reference< XExtendedDocumentHandler > xExtendedDocHandler( m_xWriteDocumentHandler, UNO_QUERY ); + if ( xExtendedDocHandler.is() ) + { + xExtendedDocHandler->unknown( TOOLBAR_DOCTYPE ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + } + + OUString aUIName; + Reference< XPropertySet > xPropSet( m_rItemAccess, UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + xPropSet->getPropertyValue("UIName") >>= aUIName; + } + catch ( const UnknownPropertyException& ) + { + } + } + + rtl::Reference<::comphelper::AttributeList> pList = new ::comphelper::AttributeList; + + pList->AddAttribute( ATTRIBUTE_XMLNS_TOOLBAR, + m_aAttributeType, + XMLNS_TOOLBAR ); + + pList->AddAttribute( ATTRIBUTE_XMLNS_XLINK, + m_aAttributeType, + XMLNS_XLINK ); + + if ( !aUIName.isEmpty() ) + pList->AddAttribute( m_aXMLToolbarNS + ATTRIBUTE_UINAME, + m_aAttributeType, + aUIName ); + + m_xWriteDocumentHandler->startElement( ELEMENT_NS_TOOLBAR, pList.get() ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + + sal_Int32 nItemCount = m_rItemAccess->getCount(); + Any aAny; + + for ( sal_Int32 nItemPos = 0; nItemPos < nItemCount; nItemPos++ ) + { + Sequence< PropertyValue > aProps; + aAny = m_rItemAccess->getByIndex( nItemPos ); + if ( aAny >>= aProps ) + { + OUString aCommandURL; + OUString aLabel; + bool bVisible( true ); + sal_Int16 nType( css::ui::ItemType::DEFAULT ); + sal_Int16 nStyle( 0 ); + + ExtractToolbarParameters( aProps, aCommandURL, aLabel, nStyle, bVisible, nType ); + if ( nType == css::ui::ItemType::DEFAULT ) + WriteToolBoxItem( aCommandURL, aLabel, nStyle, bVisible ); + else if ( nType == css::ui::ItemType::SEPARATOR_SPACE ) + WriteToolBoxSpace(); + else if ( nType == css::ui::ItemType::SEPARATOR_LINE ) + WriteToolBoxSeparator(); + else if ( nType == css::ui::ItemType::SEPARATOR_LINEBREAK ) + WriteToolBoxBreak(); + } + } + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_TOOLBAR ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endDocument(); +} + +// protected member functions + +void OWriteToolBoxDocumentHandler::WriteToolBoxItem( + const OUString& rCommandURL, + const OUString& rLabel, + sal_Int16 nStyle, + bool bVisible ) +{ + ::comphelper::AttributeList* pList = new ::comphelper::AttributeList; + Reference< XAttributeList > xList( static_cast<XAttributeList *>(pList) , UNO_QUERY ); + + if ( m_aAttributeURL.isEmpty() ) + { + m_aAttributeURL = m_aXMLXlinkNS + ATTRIBUTE_URL; + } + + // save required attribute (URL) + pList->AddAttribute( m_aAttributeURL, m_aAttributeType, rCommandURL ); + + if ( !rLabel.isEmpty() ) + { + pList->AddAttribute( m_aXMLToolbarNS + ATTRIBUTE_TEXT, + m_aAttributeType, + rLabel ); + } + + if ( !bVisible ) + { + pList->AddAttribute( m_aXMLToolbarNS + ATTRIBUTE_VISIBLE, + m_aAttributeType, + ATTRIBUTE_BOOLEAN_FALSE ); + } + + if ( nStyle > 0 ) + { + OUStringBuffer aValue; + const ToolboxStyleItem* pStyle = Styles; + + for ( sal_Int32 nIndex = 0; nIndex < nStyleItemEntries; ++nIndex, ++pStyle ) + { + if ( nStyle & pStyle->nBit ) + { + if ( !aValue.isEmpty() ) + aValue.append(" "); + aValue.appendAscii( pStyle->attrName ); + } + } + pList->AddAttribute( m_aXMLToolbarNS + ATTRIBUTE_ITEMSTYLE, + m_aAttributeType, + aValue.makeStringAndClear() ); + } + + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_TOOLBARITEM, xList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_TOOLBARITEM ); +} + +void OWriteToolBoxDocumentHandler::WriteToolBoxSpace() +{ + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_TOOLBARSPACE, m_xEmptyList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_TOOLBARSPACE ); +} + +void OWriteToolBoxDocumentHandler::WriteToolBoxBreak() +{ + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_TOOLBARBREAK, m_xEmptyList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_TOOLBARBREAK ); +} + +void OWriteToolBoxDocumentHandler::WriteToolBoxSeparator() +{ + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->startElement( ELEMENT_NS_TOOLBARSEPARATOR, m_xEmptyList ); + m_xWriteDocumentHandler->ignorableWhitespace( OUString() ); + m_xWriteDocumentHandler->endElement( ELEMENT_NS_TOOLBARSEPARATOR ); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/fwe/xml/xmlnamespaces.cxx b/framework/source/fwe/xml/xmlnamespaces.cxx new file mode 100644 index 000000000..dfd79edde --- /dev/null +++ b/framework/source/fwe/xml/xmlnamespaces.cxx @@ -0,0 +1,152 @@ +/* -*- 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 <xml/xmlnamespaces.hxx> + +#include <com/sun/star/xml/sax/SAXException.hpp> + +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; + +namespace framework +{ + +void XMLNamespaces::addNamespace( const OUString& aName, const OUString& aValue ) +{ + NamespaceMap::iterator p; + OUString aNamespaceName( aName ); + + // delete preceding "xmlns" + constexpr char aXMLAttributeNamespace[] = "xmlns"; + if ( aNamespaceName.startsWith( aXMLAttributeNamespace ) ) + { + constexpr sal_Int32 nXMLNamespaceLength = RTL_CONSTASCII_LENGTH(aXMLAttributeNamespace); + if ( aNamespaceName.getLength() == nXMLNamespaceLength ) + { + aNamespaceName.clear(); + } + else if ( aNamespaceName.getLength() >= nXMLNamespaceLength+2 ) + { + aNamespaceName = aNamespaceName.copy( nXMLNamespaceLength+1 ); + } + else + { + // a xml namespace without name is not allowed (e.g. "xmlns:" ) + throw SAXException( "A xml namespace without name is not allowed!", Reference< XInterface >(), Any() ); + } + } + + if ( aValue.isEmpty() && !aNamespaceName.isEmpty() ) + { + // namespace should be reset - as xml draft states this is only allowed + // for the default namespace - check and throw exception if check fails + throw SAXException( "Clearing xml namespace only allowed for default namespace!", Reference< XInterface >(), Any() ); + } + + if ( aNamespaceName.isEmpty() ) + m_aDefaultNamespace = aValue; + else + { + p = m_aNamespaceMap.find( aNamespaceName ); + if ( p != m_aNamespaceMap.end() ) + { + // replace current namespace definition + m_aNamespaceMap.erase( p ); + m_aNamespaceMap.emplace( aNamespaceName, aValue ); + } + else + { + m_aNamespaceMap.emplace( aNamespaceName, aValue ); + } + } +} + +OUString XMLNamespaces::applyNSToAttributeName( const OUString& aName ) const +{ + // xml draft: there is no default namespace for attributes! + + int index; + if (( index = aName.indexOf( ':' )) > 0 ) + { + if ( aName.getLength() <= index+1 ) + { + // attribute with namespace but without name "namespace:" is not allowed!! + throw SAXException( "Attribute has no name only preceding namespace!", Reference< XInterface >(), Any() ); + } + OUString aAttributeName = getNamespaceValue( aName.copy( 0, index )) + "^" + aName.copy( index+1); + return aAttributeName; + } + + return aName; +} + +OUString XMLNamespaces::applyNSToElementName( const OUString& aName ) const +{ + // xml draft: element names can have a default namespace + + int index = aName.indexOf( ':' ); + OUString aNamespace; + OUString aElementName = aName; + + if ( index > 0 ) + aNamespace = getNamespaceValue( aName.copy( 0, index ) ); + else + aNamespace = m_aDefaultNamespace; + + if ( !aNamespace.isEmpty() ) + { + aElementName = aNamespace + "^"; + } + else + return aName; + + if ( index > 0 ) + { + if ( aName.getLength() <= index+1 ) + { + // attribute with namespace but without a name is not allowed (e.g. "cfg:" ) + throw SAXException( "Attribute has no name only preceding namespace!", Reference< XInterface >(), Any() ); + } + aElementName += aName.copy( index+1 ); + } + else + aElementName += aName; + + return aElementName; +} + +OUString const & XMLNamespaces::getNamespaceValue( const OUString& aNamespace ) const +{ + if ( aNamespace.isEmpty() ) + return m_aDefaultNamespace; + else + { + NamespaceMap::const_iterator p = m_aNamespaceMap.find( aNamespace ); + if ( p == m_aNamespaceMap.end() ) + { + // namespace not defined => throw exception! + throw SAXException( "XML namespace used but not defined!", Reference< XInterface >(), Any() ); + } + return p->second; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |