diff options
Diffstat (limited to '')
19 files changed, 4488 insertions, 0 deletions
diff --git a/filter/source/xsltdialog/typedetectionexport.cxx b/filter/source/xsltdialog/typedetectionexport.cxx new file mode 100644 index 000000000..30c4f894b --- /dev/null +++ b/filter/source/xsltdialog/typedetectionexport.cxx @@ -0,0 +1,264 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> + +#include "typedetectionexport.hxx" +#include "xmlfiltercommon.hxx" + +#include <comphelper/attributelist.hxx> +#include <rtl/ref.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::xml::sax; + + +TypeDetectionExporter::TypeDetectionExporter( Reference< XComponentContext > const & xContext ) +: mxContext( xContext ) +{ +} + +static OUString createRelativeURL( std::u16string_view rFilterName, const OUString& rURL ) +{ + if( !rURL.isEmpty() && + !rURL.startsWith("http:") && + !rURL.startsWith("https:") && + !rURL.startsWith("jar:") && + !rURL.startsWith("ftp:") ) + { + INetURLObject aURL( rURL ); + OUString aName(aURL.GetLastName()); + if( aName.isEmpty() ) + { + sal_Int32 nPos = rURL.lastIndexOf( '/' ); + if( nPos == -1 ) + { + aName = rURL; + } + else + { + aName = rURL.copy( nPos + 1 ); + } + } + + return OUString( OUString::Concat("vnd.sun.star.Package:") + rFilterName + "/" + aName ); + } + else + { + return rURL; + } +} + +void TypeDetectionExporter::doExport( const Reference< XOutputStream >& xOS, const std::vector<filter_info_impl*>& rFilters ) +{ + try + { + static const OUStringLiteral sComponentData ( u"oor:component-data" ); + static const OUStringLiteral sNode ( u"node" ); + static const OUStringLiteral sName ( u"oor:name" ); + static const OUStringLiteral sWhiteSpace ( u" " ); + static const OUStringLiteral sUIName ( u"UIName" ); + static const OUStringLiteral sComma ( u"," ); + static const OUStringLiteral sDelim ( u";" ); + static const OUStringLiteral sData ( u"Data" ); + static const OUStringLiteral sDocTypePrefix ( u"doctype:" ); + static const OUStringLiteral sFilterAdaptorService( u"com.sun.star.comp.Writer.XmlFilterAdaptor" ); + static const OUStringLiteral sXSLTFilterService ( u"com.sun.star.documentconversion.XSLTFilter" ); + static const OUStringLiteral sCdataAttribute ( u"CDATA" ); + + + // set up sax writer and connect to given output stream + Reference< XWriter > xHandler = Writer::create( mxContext ); + xHandler->setOutputStream( xOS ); + + rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( "xmlns:oor", sCdataAttribute, "http://openoffice.org/2001/registry" ); + pAttrList->AddAttribute ( "xmlns:xs", sCdataAttribute, "http://www.w3.org/2001/XMLSchema" ); + pAttrList->AddAttribute ( sName, sCdataAttribute, "TypeDetection" ); + pAttrList->AddAttribute ( "oor:package", sCdataAttribute, "org.openoffice.Office" ); + + xHandler->startDocument(); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sComponentData, pAttrList ); + + // export types + { + pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( sName, sCdataAttribute, "Types" ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sNode, pAttrList ); + + for (auto const& filter : rFilters) + { + pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute( sName, sCdataAttribute, filter->maType ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sNode, pAttrList ); + OUString sValue = "0" + sComma + sComma; + if( !filter->maDocType.isEmpty() ) + { + sValue += sDocTypePrefix + filter->maDocType; + } + sValue += sComma + sComma + filter->maExtension + sComma + + OUString::number( filter->mnDocumentIconID ) + sComma; + + addProperty( xHandler, sData, sValue ); + addLocaleProperty( xHandler, sUIName, filter->maInterfaceName ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sNode ); + } + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sNode ); + } + + // export filters + { + pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( sName, sCdataAttribute, "Filters" ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sNode, pAttrList ); + + for (auto const& filter : rFilters) + { + pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute( sName, sCdataAttribute, filter->maFilterName ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sNode, pAttrList ); + addLocaleProperty( xHandler, sUIName, filter->maInterfaceName ); + + const application_info_impl* pAppInfo = getApplicationInfo( filter->maExportService ); + OUString sValue = + "0" + + sComma + + filter->maType + + sComma + + filter->maDocumentService + + sComma + + sFilterAdaptorService + + sComma + + OUString::number( filter->maFlags ) + + sComma + + sXSLTFilterService + + sDelim + + OUString::boolean( filter->mbNeedsXSLT2 ) + + sDelim + + pAppInfo->maXMLImporter + + sDelim + + pAppInfo->maXMLExporter + + sDelim + + createRelativeURL( filter->maFilterName, filter->maImportXSLT ) + + sDelim + + createRelativeURL( filter->maFilterName, filter->maExportXSLT ) + + sDelim + + // entry DTD obsolete and removed, but delimiter kept + sDelim + + filter->maComment + + sComma + + "0" + + sComma + + createRelativeURL( filter->maFilterName, filter->maImportTemplate ); + addProperty( xHandler, sData, sValue ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sNode ); + } + + xHandler->endElement( sNode ); + } + + // finish + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sComponentData ); + xHandler->endDocument(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +void TypeDetectionExporter::addProperty( const Reference< XWriter >& xHandler, const OUString& rName, const OUString& rValue ) +{ + try + { + static const OUStringLiteral sCdataAttribute( u"CDATA" ); + static const OUStringLiteral sProp( u"prop" ); + static const OUStringLiteral sValue( u"value" ); + static const OUStringLiteral sWhiteSpace ( u" " ); + + rtl::Reference<::comphelper::AttributeList>pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( "oor:name", sCdataAttribute, rName ); + pAttrList->AddAttribute ( "oor:type", sCdataAttribute, "xs:string" ); + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sProp, pAttrList ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sValue, pAttrList ); + xHandler->characters( rValue ); + xHandler->endElement( sValue ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sProp ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +void TypeDetectionExporter::addLocaleProperty( const Reference< XWriter >& xHandler, const OUString& rName, const OUString& rValue ) +{ + try + { + static const OUStringLiteral sCdataAttribute( u"CDATA" ); + static const OUStringLiteral sProp( u"prop" ); + static const OUStringLiteral sValue( u"value" ); + static const OUStringLiteral sWhiteSpace ( u" " ); + + rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( "oor:name", sCdataAttribute, rName ); + pAttrList->AddAttribute ( "oor:type", sCdataAttribute, "xs:string" ); + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sProp, pAttrList ); + pAttrList = new ::comphelper::AttributeList; + pAttrList->AddAttribute ( "xml:lang", sCdataAttribute, "en-US" ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sValue, pAttrList ); + xHandler->characters( rValue ); + xHandler->endElement( sValue ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sProp ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/typedetectionexport.hxx b/filter/source/xsltdialog/typedetectionexport.hxx new file mode 100644 index 000000000..a253540bb --- /dev/null +++ b/filter/source/xsltdialog/typedetectionexport.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/xml/sax/XWriter.hpp> +#include <com/sun/star/io/XOutputStream.hpp> + +#include "xmlfilterjar.hxx" + +class TypeDetectionExporter +{ +public: + explicit TypeDetectionExporter( css::uno::Reference< css::uno::XComponentContext > const & mxContext ); + + void doExport(const css::uno::Reference < css::io::XOutputStream >& xOS, const std::vector<filter_info_impl*>& rFilters ); + +private: + static void addProperty( const css::uno::Reference< css::xml::sax::XWriter >& xWriter, const OUString& rName, const OUString& rValue ); + static void addLocaleProperty( const css::uno::Reference< css::xml::sax::XWriter >& xWriter, const OUString& rName, const OUString& rValue ); + + css::uno::Reference< css::uno::XComponentContext > mxContext; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/typedetectionimport.cxx b/filter/source/xsltdialog/typedetectionimport.cxx new file mode 100644 index 000000000..be5766927 --- /dev/null +++ b/filter/source/xsltdialog/typedetectionimport.cxx @@ -0,0 +1,316 @@ +/* -*- 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 <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/xml/sax/Parser.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <tools/diagnose_ex.h> +#include <rtl/ref.hxx> +#include <o3tl/string_view.hxx> + +#include "typedetectionimport.hxx" +#include "xmlfiltercommon.hxx" + +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace com::sun::star::beans; +using namespace com::sun::star::xml::sax; +using namespace com::sun::star; + +TypeDetectionImporter::TypeDetectionImporter() +{ +} + +TypeDetectionImporter::~TypeDetectionImporter() +{ +} + +void TypeDetectionImporter::doImport( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& xIS, + std::vector< std::unique_ptr<filter_info_impl> >& rFilters ) +{ + try + { + Reference< XParser > xParser = xml::sax::Parser::create( rxContext ); + + rtl::Reference<TypeDetectionImporter> pImporter = new TypeDetectionImporter; + xParser->setDocumentHandler( pImporter ); + + InputSource source; + source.aInputStream = xIS; + + // start parsing + xParser->parseStream( source ); + + pImporter->fillFilterVector( rFilters ); + } + catch( const Exception& /* e */ ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +void TypeDetectionImporter::fillFilterVector( std::vector< std::unique_ptr<filter_info_impl> >& rFilters ) +{ + // create filter infos from imported filter nodes + for (auto const& filterNode : maFilterNodes) + { + std::unique_ptr<filter_info_impl> pFilter = createFilterForNode(filterNode.get()); + if( pFilter ) + rFilters.push_back( std::move(pFilter) ); + } + maFilterNodes.clear(); + + // now delete type nodes + maTypeNodes.clear(); +} + +static std::u16string_view getSubdata( int index, sal_Unicode delimiter, std::u16string_view rData ) +{ + sal_Int32 nLastIndex = 0; + + size_t nNextIndex = rData.find( delimiter ); + + std::u16string_view aSubdata; + + while( index ) + { + nLastIndex = nNextIndex == std::u16string_view::npos ? 0 : nNextIndex + 1; + nNextIndex = rData.find( delimiter, nLastIndex ); + + index--; + + if( (index > 0) && (nLastIndex == 0) ) + return aSubdata; + } + + if( nNextIndex == std::u16string_view::npos ) + { + aSubdata = rData.substr( nLastIndex ); + } + else + { + aSubdata = rData.substr( nLastIndex, nNextIndex - nLastIndex ); + } + + return aSubdata; +} + +Node* TypeDetectionImporter::findTypeNode( const OUString& rType ) +{ + auto aIter = std::find_if(maTypeNodes.begin(), maTypeNodes.end(), + [&rType](const std::unique_ptr<Node>& rxNode) { return rxNode->maName == rType; }); + if (aIter != maTypeNodes.end()) + return aIter->get(); + + return nullptr; +} + +std::unique_ptr<filter_info_impl> TypeDetectionImporter::createFilterForNode( Node * pNode ) +{ + std::unique_ptr<filter_info_impl> pFilter(new filter_info_impl); + + pFilter->maFilterName = pNode->maName; + pFilter->maInterfaceName = pNode->maPropertyMap["UIName"]; + + OUString aData = pNode->maPropertyMap["Data"]; + + sal_Unicode aComma(','); + + pFilter->maType = getSubdata( 1, aComma, aData ); + pFilter->maDocumentService = getSubdata( 2, aComma, aData ); + + std::u16string_view aFilterService( getSubdata( 3, aComma, aData ) ); + pFilter->maFlags = o3tl::toInt32(getSubdata( 4, aComma, aData )); + + // parse filter user data + sal_Unicode aDelim(';'); + std::u16string_view aFilterUserData( getSubdata( 5, aComma, aData ) ); + + std::u16string_view aAdapterService( getSubdata( 0, aDelim, aFilterUserData ) ); + //Import/ExportService + pFilter->mbNeedsXSLT2 = OUString(getSubdata( 1, aDelim, aFilterUserData )).toBoolean(); + pFilter->maImportService = getSubdata( 2, aDelim, aFilterUserData ); + pFilter->maExportService = getSubdata( 3, aDelim, aFilterUserData ); + pFilter->maImportXSLT = getSubdata( 4, aDelim, aFilterUserData ); + pFilter->maExportXSLT = getSubdata( 5, aDelim, aFilterUserData ); + pFilter->maComment = getSubdata( 7, aDelim, aFilterUserData ); + + + pFilter->maImportTemplate = getSubdata( 7, aComma, aData ); + + Node* pTypeNode = findTypeNode( pFilter->maType ); + if( pTypeNode ) + { + OUString aTypeUserData( pTypeNode->maPropertyMap["Data"] ); + + pFilter->maDocType = getSubdata( 2, aComma, aTypeUserData ); + pFilter->maExtension = getSubdata( 4, aComma, aTypeUserData ); + pFilter->mnDocumentIconID = o3tl::toInt32(getSubdata( 5, aComma, aTypeUserData )); + } + + bool bOk = true; + + if( pTypeNode == nullptr ) + bOk = false; + + if( pFilter->maFilterName.isEmpty() ) + bOk = false; + + if( pFilter->maInterfaceName.isEmpty() ) + bOk = false; + + if( pFilter->maType.isEmpty() ) + bOk = false; + + if( pFilter->maFlags == 0 ) + bOk = false; + + if( aFilterService != u"com.sun.star.comp.Writer.XmlFilterAdaptor" ) + bOk = false; + + if( aAdapterService != u"com.sun.star.documentconversion.XSLTFilter" ) + bOk = false; + + if( pFilter->maExtension.isEmpty() ) + bOk = false; + + if( !bOk ) + return nullptr; + + return pFilter; +} + +void SAL_CALL TypeDetectionImporter::startDocument( ) +{ +} + +void SAL_CALL TypeDetectionImporter::endDocument( ) +{ +} + +void SAL_CALL TypeDetectionImporter::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) +{ + ImportState eNewState = e_Unknown; + + if( maStack.empty() ) + { + // #109668# support legacy name as well on import + if( aName == "oor:component-data" || aName == "oor:node" ) + { + eNewState = e_Root; + } + } + else if( maStack.top() == e_Root ) + { + if( aName == "node" ) + { + OUString aNodeName( xAttribs->getValueByName( "oor:name" ) ); + + if( aNodeName == "Filters" ) + { + eNewState = e_Filters; + } + else if( aNodeName == "Types" ) + { + eNewState = e_Types; + } + } + } + else if( (maStack.top() == e_Filters) || (maStack.top() == e_Types) ) + { + if( aName == "node" ) + { + maNodeName = xAttribs->getValueByName( "oor:name" ); + + eNewState = (maStack.top() == e_Filters) ? e_Filter : e_Type; + } + } + else if( (maStack.top() == e_Filter) || (maStack.top() == e_Type)) + { + if( aName == "prop" ) + { + maPropertyName = xAttribs->getValueByName( "oor:name" ); + eNewState = e_Property; + } + } + else if( maStack.top() == e_Property ) + { + if( aName == "value" ) + { + eNewState = e_Value; + maValue.clear(); + } + } + + maStack.push( eNewState ); +} +void SAL_CALL TypeDetectionImporter::endElement( const OUString& /* aName */ ) +{ + if( maStack.empty() ) + return; + + ImportState eCurrentState = maStack.top(); + switch( eCurrentState ) + { + case e_Filter: + case e_Type: + { + std::unique_ptr<Node> pNode(new Node); + pNode->maName = maNodeName; + pNode->maPropertyMap = maPropertyMap; + maPropertyMap.clear(); + + if( eCurrentState == e_Filter ) + { + maFilterNodes.push_back( std::move(pNode) ); + } + else + { + maTypeNodes.push_back( std::move(pNode) ); + } + } + break; + + case e_Property: + maPropertyMap[ maPropertyName ] = maValue; + break; + default: break; + } + + maStack.pop(); +} +void SAL_CALL TypeDetectionImporter::characters( const OUString& aChars ) +{ + if( !maStack.empty() && maStack.top() == e_Value ) + { + maValue += aChars; + } +} +void SAL_CALL TypeDetectionImporter::ignorableWhitespace( const OUString& /* aWhitespaces */ ) +{ +} +void SAL_CALL TypeDetectionImporter::processingInstruction( const OUString& /* aTarget */, const OUString& /* aData */ ) +{ +} +void SAL_CALL TypeDetectionImporter::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /* xLocator */ ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/typedetectionimport.hxx b/filter/source/xsltdialog/typedetectionimport.hxx new file mode 100644 index 000000000..3b69ef9af --- /dev/null +++ b/filter/source/xsltdialog/typedetectionimport.hxx @@ -0,0 +1,92 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> + +#include "xmlfilterjar.hxx" + +#include <map> +#include <memory> +#include <vector> +#include <stack> + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { struct PropertyValue; } +} + +enum ImportState +{ + e_Root, + e_Filters, + e_Types, + e_Filter, + e_Type, + e_Property, + e_Value, + e_Unknown +}; + +typedef std::map<OUString, OUString> PropertyMap; + +struct Node +{ + OUString maName; + PropertyMap maPropertyMap; +}; + +class TypeDetectionImporter : public cppu::WeakImplHelper < css::xml::sax::XDocumentHandler > +{ +public: + TypeDetectionImporter(); + virtual ~TypeDetectionImporter() override; + + static void doImport( const css::uno::Reference< css::uno::XComponentContext >& rxContext, const css::uno::Reference < css::io::XInputStream >& xOS, + std::vector< std::unique_ptr<filter_info_impl> >& rFilters ); + + virtual void SAL_CALL startDocument( ) override; + virtual void SAL_CALL endDocument( ) override; + virtual void SAL_CALL startElement( const OUString& aName, const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs ) override; + virtual void SAL_CALL endElement( const OUString& aName ) override; + virtual void SAL_CALL characters( const OUString& aChars ) override; + virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override; + virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override; + virtual void SAL_CALL setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >& xLocator ) override; + +private: + void fillFilterVector( std::vector< std::unique_ptr<filter_info_impl> >& rFilters ); + std::unique_ptr<filter_info_impl> createFilterForNode( Node * pNode ); + Node* findTypeNode( const OUString& rType ); + + std::stack< ImportState > maStack; + PropertyMap maPropertyMap; + + std::vector< std::unique_ptr<Node> > maFilterNodes; + std::vector< std::unique_ptr<Node> > maTypeNodes; + + OUString maValue; + OUString maNodeName; + OUString maPropertyName; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltercommon.hxx b/filter/source/xsltdialog/xmlfiltercommon.hxx new file mode 100644 index 000000000..4ac225183 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltercommon.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <unotools/resmgr.hxx> + +#include <string_view> +#include <vector> + + +extern OUString string_encode( const OUString & rText ); +extern OUString string_decode( const OUString & rText ); + +bool copyStreams( const css::uno::Reference< css::io::XInputStream >& xIS, const css::uno::Reference< css::io::XOutputStream >& xOS ); +bool createDirectory( std::u16string_view rURL ); + + +class filter_info_impl +{ +public: + OUString maFilterName; + OUString maType; + OUString maDocumentService; + OUString maInterfaceName; + OUString maComment; + OUString maExtension; + OUString maExportXSLT; + OUString maImportXSLT; + OUString maImportTemplate; + OUString maDocType; + OUString maImportService; + OUString maExportService; + + sal_Int32 maFlags; + sal_Int32 maFileFormatVersion; + sal_Int32 mnDocumentIconID; + + bool mbReadonly; + + bool mbNeedsXSLT2; + + filter_info_impl(); + bool operator==( const filter_info_impl& ) const; + + css::uno::Sequence< OUString > getFilterUserData() const; +}; + + +struct application_info_impl +{ + OUString maDocumentService; + OUString maDocumentUIName; + OUString maXMLImporter; + OUString maXMLExporter; + + application_info_impl(const char * pDocumentService, const OUString& rUINameRes, const char * mpXMLImporter, const char * mpXMLExporter); +}; + + +extern std::vector< application_info_impl > const & getApplicationInfos(); +extern OUString getApplicationUIName( std::u16string_view rServiceName ); +extern const application_info_impl* getApplicationInfo( std::u16string_view rServiceName ); +OUString XsltResId(TranslateId pId); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfilterdialogcomponent.cxx b/filter/source/xsltdialog/xmlfilterdialogcomponent.cxx new file mode 100644 index 000000000..6f4b1db34 --- /dev/null +++ b/filter/source/xsltdialog/xmlfilterdialogcomponent.cxx @@ -0,0 +1,285 @@ +/* -*- 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 <osl/mutex.hxx> + +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/component.hxx> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/svapp.hxx> + +#include "xmlfiltersettingsdialog.hxx" + +using namespace ::cppu; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::frame; + +namespace { + +class XMLFilterDialogComponentBase +{ +protected: + ::osl::Mutex maMutex; +}; + + +class XMLFilterDialogComponent : public XMLFilterDialogComponentBase, + public OComponentHelper, + public css::ui::dialogs::XExecutableDialog, + public XServiceInfo, + public XInitialization, + public XTerminateListener +{ +public: + explicit XMLFilterDialogComponent( const Reference< XComponentContext >& rxContext ); + + // XInterface + virtual Any SAL_CALL queryInterface( const Type& aType ) override; + virtual Any SAL_CALL queryAggregation( Type const & rType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + +protected: + // XTypeProvider + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual Sequence< Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XExecutableDialog + virtual void SAL_CALL setTitle( const OUString& aTitle ) override; + virtual sal_Int16 SAL_CALL execute( ) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const EventObject& Event ) override; + virtual void SAL_CALL disposing( const EventObject& Source ) override; + + /** Called in dispose method after the listeners were notified. + */ + virtual void SAL_CALL disposing() override; + +private: + css::uno::Reference<css::awt::XWindow> mxParent; /// parent window + css::uno::Reference< XComponentContext > mxContext; + + std::shared_ptr<XMLFilterSettingsDialog> mxDialog; +}; + +} + +XMLFilterDialogComponent::XMLFilterDialogComponent(const css::uno::Reference< XComponentContext >& rxContext) + : OComponentHelper(maMutex) + , mxContext(rxContext) +{ + Reference< XDesktop2 > xDesktop = Desktop::create( rxContext ); + Reference< XTerminateListener > xListener( this ); + xDesktop->addTerminateListener( xListener ); +} + +// XInterface +Any SAL_CALL XMLFilterDialogComponent::queryInterface( const Type& aType ) +{ + return OComponentHelper::queryInterface( aType ); +} + + +Any SAL_CALL XMLFilterDialogComponent::queryAggregation( Type const & rType ) +{ + if (rType == cppu::UnoType<css::ui::dialogs::XExecutableDialog>::get()) + { + void * p = static_cast< css::ui::dialogs::XExecutableDialog * >( this ); + return Any( &p, rType ); + } + else if (rType == cppu::UnoType<XServiceInfo>::get()) + { + void * p = static_cast< XServiceInfo * >( this ); + return Any( &p, rType ); + } + else if (rType == cppu::UnoType<XInitialization>::get()) + { + void * p = static_cast< XInitialization * >( this ); + return Any( &p, rType ); + } + else if (rType == cppu::UnoType<XTerminateListener>::get()) + { + void * p = static_cast< XTerminateListener * >( this ); + return Any( &p, rType ); + } + return OComponentHelper::queryAggregation( rType ); +} + + +void SAL_CALL XMLFilterDialogComponent::acquire() noexcept +{ + OComponentHelper::acquire(); +} + + +void SAL_CALL XMLFilterDialogComponent::release() noexcept +{ + OComponentHelper::release(); +} + + +OUString SAL_CALL XMLFilterDialogComponent::getImplementationName() +{ + return "com.sun.star.comp.ui.XSLTFilterDialog"; +} + +Sequence< sal_Int8 > SAL_CALL XMLFilterDialogComponent::getImplementationId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + + +Sequence< Type > XMLFilterDialogComponent::getTypes() +{ + return { cppu::UnoType<XComponent>::get(), + cppu::UnoType<XTypeProvider>::get(), + cppu::UnoType<XAggregation>::get(), + cppu::UnoType<XWeak>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XInitialization>::get(), + cppu::UnoType<XTerminateListener>::get(), + cppu::UnoType<css::ui::dialogs::XExecutableDialog>::get() }; +} + +Sequence< OUString > SAL_CALL XMLFilterDialogComponent::getSupportedServiceNames() +{ + return { "com.sun.star.ui.dialogs.XSLTFilterDialog" }; +} + +sal_Bool SAL_CALL XMLFilterDialogComponent::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService( this, ServiceName ); +} + +/** Called in dispose method after the listeners were notified. +*/ +void SAL_CALL XMLFilterDialogComponent::disposing() +{ + ::SolarMutexGuard aGuard; + + if (mxDialog) + mxDialog->response(RET_CLOSE); +} + + +// XTerminateListener +void SAL_CALL XMLFilterDialogComponent::queryTermination( const EventObject& /* Event */ ) +{ + ::SolarMutexGuard aGuard; + if (!mxDialog) + return; + mxDialog->present(); +} + +void SAL_CALL XMLFilterDialogComponent::notifyTermination( const EventObject& /* Event */ ) +{ + { + ::SolarMutexGuard aGuard; + if (mxDialog) + mxDialog->response(RET_CLOSE); + } + + // we are going down, so dispose us! + dispose(); +} + +void SAL_CALL XMLFilterDialogComponent::disposing( const EventObject& /* Source */ ) +{ +} + +void SAL_CALL XMLFilterDialogComponent::setTitle( const OUString& /* _rTitle */ ) +{ +} + +sal_Int16 SAL_CALL XMLFilterDialogComponent::execute() +{ + ::SolarMutexGuard aGuard; + + bool bLaunch = false; + if (!mxDialog) + { + Reference< XComponent > xKeepAlive( this ); + mxDialog = std::make_shared<XMLFilterSettingsDialog>(Application::GetFrameWeld(mxParent), mxContext); + bLaunch = true; + } + + mxDialog->UpdateWindow(); + + if (!bLaunch) + { + mxDialog->present(); + return 0; + } + + weld::DialogController::runAsync(mxDialog, [this](sal_Int32) + { + mxDialog.reset(); + }); + + return 0; +} + +void SAL_CALL XMLFilterDialogComponent::initialize( const Sequence< Any >& aArguments ) +{ + for(const Any& rArgument : aArguments) + { + PropertyValue aProperty; + if(rArgument >>= aProperty) + { + if( aProperty.Name == "ParentWindow" ) + { + aProperty.Value >>= mxParent; + } + } + } +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_XSLTFilterDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XMLFilterDialogComponent(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfilterjar.cxx b/filter/source/xsltdialog/xmlfilterjar.cxx new file mode 100644 index 000000000..2366aa80e --- /dev/null +++ b/filter/source/xsltdialog/xmlfilterjar.cxx @@ -0,0 +1,361 @@ +/* -*- 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 <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + + +#include <comphelper/oslfile2streamwrap.hxx> +#include <comphelper/storagehelper.hxx> +#include <osl/file.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/streamwrap.hxx> +#include <unotools/tempfile.hxx> +#include <svl/urihelper.hxx> +#include <tools/diagnose_ex.h> +#include <tools/stream.hxx> +#include <tools/urlobj.hxx> + +#include <rtl/uri.hxx> + +#include "xmlfiltercommon.hxx" +#include "xmlfilterjar.hxx" +#include "typedetectionexport.hxx" +#include "typedetectionimport.hxx" + +using namespace osl; +using namespace comphelper; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::io; + +using ::rtl::Uri; + +constexpr OUStringLiteral sVndSunStarPackage(u"vnd.sun.star.Package:"); + +XMLFilterJarHelper::XMLFilterJarHelper( const Reference< XComponentContext >& rxContext ) +: mxContext( rxContext ), + sXSLTPath( "$(user)/xslt/" ), + sTemplatePath( "$(user)/template/" ), + sProgPath( "$(prog)/" ) +{ + SvtPathOptions aOptions; + sProgPath = aOptions.SubstituteVariable( sProgPath ); + sXSLTPath = aOptions.SubstituteVariable( sXSLTPath ); + sTemplatePath = aOptions.SubstituteVariable( sTemplatePath ); +} + +static OUString encodeZipUri( const OUString& rURI ) +{ + return Uri::encode( rURI, rtl_UriCharClassUric, rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8 ); +} + +/// @throws Exception +static Reference< XInterface > addFolder( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, const OUString& rName ) +{ + if ( rName == ".." || rName == "." ) + throw lang::IllegalArgumentException(); + + Sequence< Any > aArgs{ Any(true) }; + + Reference< XInterface > xFolder( xFactory->createInstanceWithArguments(aArgs) ); + Reference< XNamed > xNamed( xFolder, UNO_QUERY ); + Reference< XChild > xChild( xFolder, UNO_QUERY ); + + if( xNamed.is() && xChild.is() ) + { + OUString aName( encodeZipUri( rName ) ); + xNamed->setName( aName ); + xChild->setParent( xRootFolder ); + } + + return xFolder; +} + +/// @throws Exception +static void addFile_( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, Reference< XInputStream > const & xInput, const OUString& aName ) +{ + Reference< XActiveDataSink > xSink( xFactory->createInstance(), UNO_QUERY ); + Reference< XUnoTunnel > xTunnel( xSink, UNO_QUERY ); + if( xSink.is() && xTunnel.is()) + { + Reference< XNameContainer > xNameContainer(xRootFolder, UNO_QUERY ); + xNameContainer->insertByName(encodeZipUri( aName ), Any(xTunnel)); + xSink->setInputStream( xInput ); + } +} + +void XMLFilterJarHelper::addFile( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, const OUString& rSourceFile ) +{ + if( rSourceFile.isEmpty() || + rSourceFile.startsWith("http:") || + rSourceFile.startsWith("https:") || + rSourceFile.startsWith("jar:") || + rSourceFile.startsWith("ftp:") ) + return; + + OUString aFileURL( rSourceFile ); + + if( !aFileURL.matchIgnoreAsciiCase("file://") ) + { + aFileURL = URIHelper::SmartRel2Abs( INetURLObject(sProgPath), aFileURL, Link<OUString *, bool>(), false ); + } + + INetURLObject aURL( aFileURL ); + OUString aName( aURL.getName() ); + + SvFileStream* pStream = new SvFileStream(aFileURL, StreamMode::READ ); + Reference< XInputStream > xInput( new utl::OSeekableInputStreamWrapper( pStream, true ) ); + addFile_( xRootFolder, xFactory, xInput, aName ); +} + +bool XMLFilterJarHelper::savePackage( const OUString& rPackageURL, const std::vector<filter_info_impl*>& rFilters ) +{ + try + { + osl::File::remove( rPackageURL ); + + // create the package jar file + + Sequence< Any > aArguments{ Any(rPackageURL), + // let ZipPackage be used ( no manifest.xml is required ) + Any(beans::NamedValue( + "StorageFormat", Any(OUString(ZIP_STORAGE_FORMAT_STRING)))) }; + + Reference< XHierarchicalNameAccess > xIfc( + mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.packages.comp.ZipPackage", + aArguments, mxContext ), UNO_QUERY ); + + if( xIfc.is() ) + { + Reference< XSingleServiceFactory > xFactory( xIfc, UNO_QUERY ); + + // get root zip folder + Reference< XInterface > xRootFolder; + xIfc->getByHierarchicalName( "/" ) >>= xRootFolder; + + // export filters files + for (auto const& filter : rFilters) + { + Reference< XInterface > xFilterRoot( addFolder( xRootFolder, xFactory, filter->maFilterName ) ); + + if( xFilterRoot.is() ) + { + if( !filter->maExportXSLT.isEmpty() ) + addFile( xFilterRoot, xFactory, filter->maExportXSLT ); + try + { + if( !filter->maImportXSLT.isEmpty() ) + addFile( xFilterRoot, xFactory, filter->maImportXSLT ); + } + catch(const css::container::ElementExistException&) + { + // in case of same named import / export XSLT the latter + // is ignored + TOOLS_WARN_EXCEPTION("filter.xslt", "same named xslt filter exception!"); + } + + if( !filter->maImportTemplate.isEmpty() ) + addFile( xFilterRoot, xFactory, filter->maImportTemplate ); + } + } + + // create TypeDetection.xcu + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + OUString aTempFileURL( aTempFile.GetURL() ); + + { + osl::File aOutputFile( aTempFileURL ); + (void)aOutputFile.open(osl_File_OpenFlag_Write); + Reference< XOutputStream > xOS( new OSLOutputStreamWrapper( aOutputFile ) ); + + TypeDetectionExporter aExporter( mxContext ); + aExporter.doExport(xOS,rFilters); + } + + Reference< XInputStream > XIS( new utl::OSeekableInputStreamWrapper( new SvFileStream(aTempFileURL, StreamMode::READ ), true ) ); + addFile_( xRootFolder, xFactory, XIS, "TypeDetection.xcu" ); + + Reference< XChangesBatch > xBatch( xIfc, UNO_QUERY ); + if( xBatch.is() ) + xBatch->commitChanges(); + + return true; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + osl::File::remove( rPackageURL ); + + return false; +} + + +void XMLFilterJarHelper::openPackage( const OUString& rPackageURL, + std::vector< std::unique_ptr<filter_info_impl> >& rFilters ) +{ + try + { + // create the package jar file + + // let ZipPackage be used ( no manifest.xml is required ) + beans::NamedValue aArg; + aArg.Name = "StorageFormat"; + aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING); + Sequence< Any > aArguments{ Any(rPackageURL), Any(aArg) }; + + Reference< XHierarchicalNameAccess > xIfc( + mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.packages.comp.ZipPackage", + aArguments, mxContext ), UNO_QUERY ); + + if( xIfc.is() ) + { + // get root zip folder + Reference< XInterface > xRootFolder; + xIfc->getByHierarchicalName( "/" ) >>= xRootFolder; + + OUString szTypeDetection("TypeDetection.xcu"); + if( xIfc->hasByHierarchicalName( szTypeDetection ) ) + { + Reference< XActiveDataSink > xTypeDetection; + xIfc->getByHierarchicalName( szTypeDetection ) >>= xTypeDetection; + + if( xTypeDetection.is() ) + { + Reference< XInputStream > xIS( xTypeDetection->getInputStream() ); + + std::vector< std::unique_ptr<filter_info_impl> > aFilters; + TypeDetectionImporter::doImport( mxContext, xIS, aFilters ); + + // copy all files used by the filters imported from the + // typedetection to office/user/xslt + for (auto& filter : aFilters) + { + if( copyFiles( xIfc, filter.get() ) ) + { + rFilters.push_back(std::move(filter)); + } + else + { + // failed to copy all files + filter.reset(); + } + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +bool XMLFilterJarHelper::copyFiles( const Reference< XHierarchicalNameAccess >& xIfc, filter_info_impl* pFilter ) +{ + bool bOk = copyFile( xIfc, pFilter->maExportXSLT, sXSLTPath ); + + if( bOk ) + bOk = copyFile( xIfc, pFilter->maImportXSLT, sXSLTPath ); + + if( bOk ) + bOk = copyFile( xIfc, pFilter->maImportTemplate, sTemplatePath ); + + return bOk; +} + +bool XMLFilterJarHelper::copyFile( const Reference< XHierarchicalNameAccess >& xIfc, OUString& rURL, std::u16string_view rTargetURL ) +{ + if( !rURL.matchIgnoreAsciiCase( sVndSunStarPackage ) ) + return true; + + try + { + OUString szPackagePath( encodeZipUri( rURL.copy( sVndSunStarPackage.getLength() ) ) ); + + if ( ::comphelper::OStorageHelper::PathHasSegment( szPackagePath, u".." ) + || ::comphelper::OStorageHelper::PathHasSegment( szPackagePath, u"." ) ) + throw lang::IllegalArgumentException(); + + if( xIfc->hasByHierarchicalName( szPackagePath ) ) + { + Reference< XActiveDataSink > xFileEntry; + xIfc->getByHierarchicalName( szPackagePath ) >>= xFileEntry; + + if( xFileEntry.is() ) + { + Reference< XInputStream > xIS( xFileEntry->getInputStream() ); + + INetURLObject aBaseURL( rTargetURL ); + + rURL = URIHelper::SmartRel2Abs( aBaseURL, szPackagePath, Link<OUString *, bool>(), false ); + + if( !rURL.isEmpty() ) + { + // create output directory if needed + if( !createDirectory( rURL ) ) + return false; + + ::osl::File file(rURL); + ::osl::FileBase::RC rc = + file.open(osl_File_OpenFlag_Write|osl_File_OpenFlag_Create); + if (::osl::FileBase::E_EXIST == rc) { + rc = file.open(osl_File_OpenFlag_Write); + if (::osl::FileBase::E_None == rc) { + file.setSize(0); // #i97170# truncate + } + } + if (::osl::FileBase::E_None != rc) { + throw RuntimeException(); + } + Reference< XOutputStream > const xOS( + new comphelper::OSLOutputStreamWrapper(file)); + + return copyStreams( xIS, xOS ); + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfilterjar.hxx b/filter/source/xsltdialog/xmlfilterjar.hxx new file mode 100644 index 000000000..d634bb6c4 --- /dev/null +++ b/filter/source/xsltdialog/xmlfilterjar.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <memory> +#include <vector> + +class filter_info_impl; + +class XMLFilterJarHelper +{ +public: + explicit XMLFilterJarHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + bool savePackage( const OUString& rPackageURL, const std::vector<filter_info_impl*>& rFilters ); + void openPackage( const OUString& rPackageURL, std::vector< std::unique_ptr<filter_info_impl> >& rFilters ); + +private: + /// @throws css::uno::Exception + void addFile( css::uno::Reference< css::uno::XInterface > const & xRootFolder, css::uno::Reference< css::lang::XSingleServiceFactory > const & xFactory, const OUString& rSourceFile ); + + static bool copyFile( const css::uno::Reference< css::container::XHierarchicalNameAccess >& xIfc, OUString& rURL, std::u16string_view rTargetURL ); + bool copyFiles( const css::uno::Reference< css::container::XHierarchicalNameAccess >& xIfc, filter_info_impl* pFilter ); + + css::uno::Reference< css::uno::XComponentContext > mxContext; + + OUString sXSLTPath; + OUString sTemplatePath; + OUString sProgPath; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx b/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx new file mode 100644 index 000000000..62a8513d7 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx @@ -0,0 +1,1384 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <o3tl/string_view.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/resmgr.hxx> +#include <unotools/streamwrap.hxx> +#include <osl/file.hxx> +#include <o3tl/enumrange.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/filedlghelper.hxx> +#include <tools/stream.hxx> + +#include <rtl/uri.hxx> + +#include <algorithm> +#include <memory> + +#include <strings.hrc> +#include "xmlfiltersettingsdialog.hxx" +#include "xmlfiltertabdialog.hxx" +#include "xmlfiltertestdialog.hxx" +#include "xmlfilterjar.hxx" +#include <strings.hxx> + +using namespace osl; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::util; + +using ::rtl::Uri; + +OUString XsltResId(TranslateId aId) +{ + return Translate::get(aId, Translate::Create("flt")); +} + +XMLFilterSettingsDialog::XMLFilterSettingsDialog(weld::Window* pParent, + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : GenericDialogController(pParent, "filter/ui/xmlfiltersettings.ui", "XMLFilterSettingsDialog") + , mxContext( rxContext ) + , m_sTemplatePath("$(user)/template/") + , m_sDocTypePrefix("doctype:") + , m_xPBNew(m_xBuilder->weld_button("new")) + , m_xPBEdit(m_xBuilder->weld_button("edit")) + , m_xPBTest(m_xBuilder->weld_button("test")) + , m_xPBDelete(m_xBuilder->weld_button("delete")) + , m_xPBSave(m_xBuilder->weld_button("save")) + , m_xPBOpen(m_xBuilder->weld_button("open")) + , m_xPBClose(m_xBuilder->weld_button("close")) + , m_xFilterListBox(m_xBuilder->weld_tree_view("filterlist")) +{ + m_xFilterListBox->set_selection_mode(SelectionMode::Multiple); + + m_xFilterListBox->set_size_request(m_xFilterListBox->get_approximate_digit_width() * 65, + m_xFilterListBox->get_height_rows(12)); + + m_xFilterListBox->connect_changed( LINK( this, XMLFilterSettingsDialog, SelectionChangedHdl_Impl ) ); + m_xFilterListBox->connect_row_activated( LINK( this, XMLFilterSettingsDialog, DoubleClickHdl_Impl ) ); + m_xFilterListBox->set_accessible_name(XsltResId(STR_XML_FILTER_LISTBOX)); + + m_xPBNew->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBEdit->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBTest->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBDelete->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBSave->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBOpen->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + m_xPBClose->connect_clicked(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) ); + + try + { + mxFilterContainer.set( rxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", rxContext ), UNO_QUERY ); + mxTypeDetection.set( rxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", rxContext ), UNO_QUERY ); + mxExtendedTypeDetection.set( rxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.ExtendedTypeDetectionFactory", rxContext ), UNO_QUERY ); + + SvtPathOptions aOptions; + m_sTemplatePath = aOptions.SubstituteVariable( m_sTemplatePath ); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +XMLFilterSettingsDialog::~XMLFilterSettingsDialog() +{ +} + +IMPL_LINK(XMLFilterSettingsDialog, ClickHdl_Impl, weld::Button&, rButton, void) +{ + // tdf#122171 block closing libreoffice until the following dialog is dismissed + incBusy(); + + if (m_xPBNew.get() == &rButton) + { + onNew(); + } + else if (m_xPBEdit.get() == &rButton) + { + onEdit(); + } + else if (m_xPBTest.get() == &rButton) + { + onTest(); + } + else if (m_xPBDelete.get() == &rButton) + { + onDelete(); + } + else if (m_xPBSave.get() == &rButton) + { + onSave(); + } + else if (m_xPBOpen.get() == &rButton) + { + onOpen(); + } + + decBusy(); + + if (m_xPBClose.get() == &rButton) + m_xDialog->response(RET_CLOSE); +} + +IMPL_LINK_NOARG(XMLFilterSettingsDialog, SelectionChangedHdl_Impl, weld::TreeView&, void) +{ + updateStates(); +} + +IMPL_LINK_NOARG(XMLFilterSettingsDialog, DoubleClickHdl_Impl, weld::TreeView&, bool) +{ + onEdit(); + return true; +} + +void XMLFilterSettingsDialog::UpdateWindow() +{ + m_xFilterListBox->grab_focus(); + disposeFilterList(); + m_xFilterListBox->clear(); + initFilterList(); + updateStates(); +} + +void XMLFilterSettingsDialog::updateStates() +{ + std::vector<int> aRows = m_xFilterListBox->get_selected_rows(); + + bool bHasSelection = !aRows.empty(); + + bool bMultiSelection = aRows.size() > 1; + bool bIsReadonly = false; + bool bIsDefault = false; + if (bHasSelection) + { + filter_info_impl* pInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_id(aRows[0])); + bIsReadonly = pInfo->mbReadonly; + + for( auto nFact : o3tl::enumrange<SvtModuleOptions::EFactory>()) + { + OUString sDefault = maModuleOpt.GetFactoryDefaultFilter(nFact); + if( sDefault == pInfo->maFilterName ) + { + bIsDefault = true; + break; + } + } + } + m_xPBEdit->set_sensitive( bHasSelection && !bMultiSelection && !bIsReadonly); + m_xPBTest->set_sensitive( bHasSelection && !bMultiSelection ); + m_xPBDelete->set_sensitive( bHasSelection && !bMultiSelection && !bIsReadonly && !bIsDefault); + m_xPBSave->set_sensitive( bHasSelection ); +} + +/** is called when the user clicks on the "New" button */ +void XMLFilterSettingsDialog::onNew() +{ + filter_info_impl aTempInfo; + + // create a unique filter name + aTempInfo.maFilterName = createUniqueFilterName(XsltResId(STR_DEFAULT_FILTER_NAME)); + + // init default extension + aTempInfo.maExtension = STR_DEFAULT_EXTENSION; + + // set default ui name + aTempInfo.maInterfaceName = createUniqueInterfaceName(XsltResId(STR_DEFAULT_UI_NAME)); + + // set default application + aTempInfo.maDocumentService = "com.sun.star.text.TextDocument"; + + // execute XML Filter Dialog + XMLFilterTabDialog aDlg(m_xDialog.get(), mxContext, &aTempInfo); + if (aDlg.run() == RET_OK) + { + // insert the new filter + insertOrEdit( aDlg.getNewFilterInfo() ); + } +} + +/** is called when the user clicks on the "Edit" Button */ +void XMLFilterSettingsDialog::onEdit() +{ + // get selected filter info + filter_info_impl* pOldInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_selected_id()); + if (!pOldInfo) + return; + + // execute XML Filter Dialog + XMLFilterTabDialog aDlg(m_xDialog.get(), mxContext, pOldInfo); + if (aDlg.run() == RET_OK) + { + filter_info_impl* pNewInfo = aDlg.getNewFilterInfo(); + + if( !(*pOldInfo == *pNewInfo) ) + { + // change filter + insertOrEdit( pNewInfo, pOldInfo ); + } + } +} + +/** helper to create a sequence of strings from an extensions strings + "ext1;ext2;ext3" will become { "ext1", "ext2", "ext3" } */ +static Sequence< OUString > createExtensionsSequence( const OUString& rExtensions ) +{ + // first count how many extensions we have inside the string + int nExtensions = 0; + + int nLength = rExtensions.getLength(); + if( nLength ) + { + // a non empty string has at least one extension + nExtensions++; + + // now count the delimiters ';' + const sal_Unicode * pString = rExtensions.getStr(); + int i; + for( i = 0; i < nLength; i++, pString++ ) + { + if( *pString == ';' ) + nExtensions++; + } + } + + Sequence< OUString > aExtensions( nExtensions ); + auto aExtensionsRange = asNonConstRange(aExtensions); + + // extract the extensions from the source string and fill the sequence + + int nLastIndex = 0; + int nCurrentIndex = 0; + int i; + + for( i = 0; i < nExtensions; i++ ) + { + nLastIndex = rExtensions.indexOf( ';', nLastIndex ); + + if( nLastIndex == -1 ) + { + aExtensionsRange[i] = rExtensions.copy( nCurrentIndex ); + break; + } + else + { + aExtensionsRange[i] = rExtensions.copy( nCurrentIndex, nLastIndex - nCurrentIndex ); + nCurrentIndex = nLastIndex + 1; + nLastIndex = nCurrentIndex; + } + } + + return aExtensions; +} + +/** checks if the given name is unique inside the filter factory. If not, + numbers are added until the returned name is unique */ +OUString XMLFilterSettingsDialog::createUniqueFilterName( const OUString& rFilterName ) +{ + OUString aFilterName( rFilterName ); + + sal_Int32 nId = 2; + + while( mxFilterContainer->hasByName( aFilterName ) ) + { + aFilterName = rFilterName + " " + OUString::number( nId++ ); + } + + return aFilterName; +} + +/** checks if the given name is unique inside the type detection. If not, + numbers are added until the returned name is unique */ +OUString XMLFilterSettingsDialog::createUniqueTypeName( const OUString& rTypeName ) +{ + OUString aTypeName( rTypeName ); + + sal_Int32 nId = 2; + + while( mxFilterContainer->hasByName( aTypeName ) ) + { + aTypeName = rTypeName + " " + OUString::number( nId++ ); + } + + return aTypeName; +} + +/** checks if the given name is a unique ui name inside the filter factory. If not, + numbers are added until the returned name is unique */ +OUString XMLFilterSettingsDialog::createUniqueInterfaceName( const OUString& rInterfaceName ) +{ + sal_Int32 nDefaultNumber = 0; + + try + { + const Sequence< OUString > aFilterNames( mxFilterContainer->getElementNames() ); + + Sequence< PropertyValue > aValues; + for( OUString const & filterName : aFilterNames) + { + Any aAny( mxFilterContainer->getByName( filterName ) ); + if( !(aAny >>= aValues) ) + continue; + + const sal_Int32 nValueCount( aValues.getLength() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 nValue; + + for( nValue = 0; nValue < nValueCount; nValue++, pValues++ ) + { + if ( pValues->Name == "UIName" ) + { + OUString aInterfaceName; + pValues->Value >>= aInterfaceName; + + + // see if this filter matches our default filter name + if( aInterfaceName.match( rInterfaceName ) ) + { + // if yes, make sure we generate a unique name with a higher number + // this is dump but fast + sal_Int32 nNumber = o3tl::toInt32(aInterfaceName.subView( rInterfaceName.getLength() )); + if( nNumber >= nDefaultNumber ) + nDefaultNumber = nNumber + 1; + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + OUString aInterfaceName( rInterfaceName ); + if( nDefaultNumber ) + { + aInterfaceName += " " + OUString::number( nDefaultNumber ); + } + + return aInterfaceName; +} + +/** inserts a new filter into the ui and configuration if pOldInfo is NULL. + If pOldInfo is not null, the old filter will be replaced with the new settings */ +bool XMLFilterSettingsDialog::insertOrEdit( filter_info_impl* pNewInfo, const filter_info_impl* pOldInfo ) +{ + bool bOk = true; + + if( pOldInfo ) + { + // see if we need to update the type name + if( pOldInfo->maFilterName != pNewInfo->maFilterName ) + { + if( pOldInfo->maType == pOldInfo->maFilterName ) + { + pNewInfo->maType.clear(); + } + } + + // see if we need to clean up old stuff first + try + { + // if filter name changed, we need to remove the old filter first + if( pOldInfo->maFilterName != pNewInfo->maFilterName ) + mxFilterContainer->removeByName( pOldInfo->maFilterName ); + + // if type name changed, we need to remove the old type first + if( pOldInfo->maType != pNewInfo->maType ) + mxTypeDetection->removeByName( pOldInfo->maType ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + } + + filter_info_impl* pFilterEntry( nullptr ); + + if( bOk ) + { + // create or copy filter info + if( pOldInfo ) + { + // change existing filter entry in filter list box + pFilterEntry = const_cast<filter_info_impl*>(pOldInfo); + *pFilterEntry = *pNewInfo; + } + else + { + // add new entry to filter list box + pFilterEntry = new filter_info_impl( *pNewInfo ); + } + } + + // check if we need to copy the template + if( bOk && !pFilterEntry->maImportTemplate.isEmpty() ) + { + if( !pFilterEntry->maImportTemplate.matchIgnoreAsciiCase( m_sTemplatePath ) ) + { + INetURLObject aSourceURL( pFilterEntry->maImportTemplate ); + if (!aSourceURL.GetLastName().isEmpty()) + { + OUString aDestURL = m_sTemplatePath + pFilterEntry->maFilterName + "/"; + if( createDirectory( aDestURL ) ) + { + aDestURL += aSourceURL.GetLastName(); + + SvFileStream aInputStream(pFilterEntry->maImportTemplate, StreamMode::READ ); + Reference< XInputStream > xIS( new utl::OInputStreamWrapper( aInputStream ) ); + SvFileStream aOutputStream(aDestURL, StreamMode::WRITE ); + Reference< XOutputStream > xOS( new utl::OOutputStreamWrapper( aOutputStream ) ); + + if( copyStreams( xIS, xOS ) ) + pFilterEntry->maImportTemplate = aDestURL; + } + } + } + } + + if( bOk ) + { + if( pFilterEntry->maType.isEmpty() ) + { + pFilterEntry->maType = createUniqueTypeName( pNewInfo->maFilterName ); + } + + // update import/export flags + if( !pFilterEntry->maImportXSLT.isEmpty() ) + { + pFilterEntry->maFlags |= 1; + } + else + { + pFilterEntry->maFlags &= ~1; + } + + if( !pFilterEntry->maExportXSLT.isEmpty() ) + { + pFilterEntry->maFlags |= 2; + } + else + { + pFilterEntry->maFlags &= ~2; + } + pFilterEntry->maFlags |= 0x80040; + + // 2. create user data for filter entry + Sequence< OUString > aUserData( pFilterEntry->getFilterUserData()); + + // 3. create property values for filter entry + Sequence< PropertyValue > aFilterData{ + comphelper::makePropertyValue("Type", pFilterEntry->maType), + comphelper::makePropertyValue("UIName", pFilterEntry->maInterfaceName), + comphelper::makePropertyValue("DocumentService", pFilterEntry->maDocumentService), + comphelper::makePropertyValue("FilterService", OUString( "com.sun.star.comp.Writer.XmlFilterAdaptor" )), + comphelper::makePropertyValue("Flags", pFilterEntry->maFlags), + comphelper::makePropertyValue("UserData", aUserData), + comphelper::makePropertyValue("FileFormatVersion", pFilterEntry->maFileFormatVersion), + comphelper::makePropertyValue("TemplateName", pFilterEntry->maImportTemplate) + }; + + // 4. insert new or replace existing filter + try + { + Any aAny( aFilterData ); + if( mxFilterContainer->hasByName( pFilterEntry->maFilterName ) ) + { + mxFilterContainer->replaceByName( pFilterEntry->maFilterName, aAny ); + } + else + { + mxFilterContainer->insertByName( pFilterEntry->maFilterName, aAny ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + } + + // 5. prepare type information + if( bOk ) + { + OUString aDocType; + if( !pFilterEntry->maDocType.match( m_sDocTypePrefix ) ) + { + aDocType = m_sDocTypePrefix + pFilterEntry->maDocType; + } + else + { + aDocType = pFilterEntry->maDocType; + } + if (aDocType == m_sDocTypePrefix) + aDocType.clear(); + + Sequence< PropertyValue > aValues{ + comphelper::makePropertyValue("UIName", pFilterEntry->maInterfaceName), + comphelper::makePropertyValue("ClipboardFormat", aDocType), + comphelper::makePropertyValue("DocumentIconID", pFilterEntry->mnDocumentIconID), + comphelper::makePropertyValue("Extensions", createExtensionsSequence( pFilterEntry->maExtension )) + }; + + // the detect service will only be registered, if a doctype/search token was specified + if (aDocType.getLength() > m_sDocTypePrefix.getLength()) + { + aValues.realloc(5); + auto pValues = aValues.getArray(); + pValues[4].Name = "DetectService"; + pValues[4].Value <<= OUString( "com.sun.star.comp.filters.XMLFilterDetect" ); + } + + // 6. insert new or replace existing type information + if( mxTypeDetection.is() ) + { + try + { + Any aAny( aValues ); + if( mxTypeDetection->hasByName( pFilterEntry->maType ) ) + { + mxTypeDetection->replaceByName( pFilterEntry->maType, aAny ); + } + else + { + mxTypeDetection->insertByName( pFilterEntry->maType, aAny ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + } + + if( bOk ) + { + try + { + Reference< XFlushable > xFlushable( mxTypeDetection, UNO_QUERY ); + if( xFlushable.is() ) + xFlushable->flush(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + } + + if( !bOk ) + { + // we failed to add the type, so lets remove the filter + try + { + mxFilterContainer->removeByName( pFilterEntry->maFilterName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + } + else // bOk + { + try + { + Reference< XFlushable > xFlushable( mxFilterContainer, UNO_QUERY ); + if( xFlushable.is() ) + xFlushable->flush(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + bOk = false; + } + + if( !bOk ) + { + // we failed to add the filter, so lets remove the type + try + { + mxTypeDetection->removeByName( pFilterEntry->maType ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + } + } + } + + if( bOk ) + { + if( mxExtendedTypeDetection.is() ) + { + OUString sFilterDetectService( "com.sun.star.comp.filters.XMLFilterDetect" ); + if( mxExtendedTypeDetection->hasByName( sFilterDetectService ) ) + { + Sequence< PropertyValue > aSequence; + if( mxExtendedTypeDetection->getByName( sFilterDetectService ) >>= aSequence ) + { + auto aSequenceRange = asNonConstRange(aSequence); + sal_Int32 nCount = aSequence.getLength(); + sal_Int32 nIndex; + for( nIndex = 0; nIndex < nCount; nIndex++ ) + { + if ( aSequence[nIndex].Name == "Types" ) + { + Sequence< OUString > aTypes; + if( aSequence[nIndex].Value >>= aTypes ) + { + sal_Int32 nStrCount = aTypes.getLength(); + sal_Int32 nStr; + for( nStr = 0; nStr < nStrCount; nStr++ ) + { + if( aTypes[nStr] == pFilterEntry->maType ) + break; + } + + if( nStr == nStrCount ) + { + aTypes.realloc( nStrCount + 1 ); + aTypes.getArray()[nStrCount] = pFilterEntry->maType; + + aSequenceRange[nIndex].Value <<= aTypes; + + mxExtendedTypeDetection->replaceByName( sFilterDetectService, Any( aSequence ) ); + + Reference< XFlushable > xFlushable( mxExtendedTypeDetection, UNO_QUERY ); + if( xFlushable.is() ) + xFlushable->flush(); + } + } + + break; + } + } + } + } + } + } + + // update ui + if( bOk ) + { + if( pOldInfo ) + { + changeEntry( pFilterEntry ); + } + else + { + addFilterEntry( pFilterEntry ); + maFilterVector.push_back( std::unique_ptr<filter_info_impl>(pFilterEntry) ); + } + } + + return bOk; +} + +/** is called when the user clicks the "Test" button */ +void XMLFilterSettingsDialog::onTest() +{ + // get the first selected filter + filter_info_impl* pInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_selected_id()); + if (pInfo) + { + XMLFilterTestDialog aDlg(m_xDialog.get(), mxContext); + aDlg.test( *pInfo ); + } +} + +void XMLFilterSettingsDialog::onDelete() +{ + int nIndex = m_xFilterListBox->get_selected_index(); + if (nIndex == -1) + return; + filter_info_impl* pInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_id(nIndex)); + if (pInfo) + { + OUString aMessage(XsltResId(STR_WARN_DELETE)); + aMessage = aMessage.replaceFirst( "%s", pInfo->maFilterName ); + + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::YesNo, + aMessage)); + xWarn->set_default_response(RET_YES); + if (xWarn->run() == RET_YES) + { + try + { + if( mxFilterContainer->hasByName( pInfo->maFilterName ) ) + { + mxFilterContainer->removeByName( pInfo->maFilterName ); + + bool bTypeStillUsed = false; + + // now loop over all filter and see if someone else uses the same type + Sequence< OUString > aFilterNames( mxFilterContainer->getElementNames() ); + OUString* pFilterName = aFilterNames.getArray(); + + const sal_Int32 nCount = aFilterNames.getLength(); + sal_Int32 nFilter; + Sequence< PropertyValue > aValues; + + for( nFilter = 0; (nFilter < nCount) && !bTypeStillUsed; nFilter++, pFilterName++ ) + { + Any aAny( mxFilterContainer->getByName( *pFilterName ) ); + if( !(aAny >>= aValues) ) + continue; + + const sal_Int32 nValueCount( aValues.getLength() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 nValue; + + for (nValue = 0; nValue < nValueCount; nValue++, pValues++) + { + if ( pValues->Name == "Type" ) + { + OUString aType; + pValues->Value >>= aType; + if( aType == pInfo->maType ) + bTypeStillUsed = true; + + break; + } + } + } + + // if the type is not used anymore, remove it also + if( !bTypeStillUsed ) + { + if( mxTypeDetection->hasByName( pInfo->maType ) ) + { + mxTypeDetection->removeByName( pInfo->maType ); + } + } + + Reference< XFlushable > xFlushable( mxFilterContainer, UNO_QUERY ); + if( xFlushable.is() ) + xFlushable->flush(); + + xFlushable.set( mxTypeDetection, UNO_QUERY ); + if( xFlushable.is() ) + xFlushable->flush(); + + // now remove entry from ui + m_xFilterListBox->remove(nIndex); + + // and delete the filter entry + maFilterVector.erase(std::find_if( maFilterVector.begin(), maFilterVector.end(), + [&] (std::unique_ptr<filter_info_impl> const & p) + { return p.get() == pInfo; })); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + } + } + + updateStates(); +} + +void XMLFilterSettingsDialog::onSave() +{ + std::vector<filter_info_impl*> aFilters; + + int nFilters = 0; + + m_xFilterListBox->selected_foreach([&](weld::TreeIter& rEntry){ + filter_info_impl* pInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_id(rEntry)); + aFilters.push_back(pInfo); + ++nFilters; + return false; + }); + + // Open Fileopen-Dialog + ::sfx2::FileDialogHelper aDlg( + css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, m_xDialog.get()); + aDlg.SetContext(sfx2::FileDialogHelper::XMLFilterSettings); + + OUString aExtensions( "*.jar" ); + OUString aFilterName = XsltResId(STR_FILTER_PACKAGE) + + " (" + aExtensions + ")"; + + aDlg.AddFilter( aFilterName, aExtensions ); + + if ( aDlg.Execute() != ERRCODE_NONE ) + return; + + XMLFilterJarHelper aJarHelper( mxContext ); + aJarHelper.savePackage( aDlg.GetPath(), aFilters ); + + INetURLObject aURL( aDlg.GetPath() ); + + OUString sPlaceholder( "%s" ); + + OUString aMsg; + if( nFilters > 0 ) + { + aMsg = XsltResId(STR_FILTERS_HAVE_BEEN_SAVED); + aMsg = aMsg.replaceFirst( sPlaceholder, OUString::number( nFilters ) ); + aMsg = aMsg.replaceFirst(sPlaceholder, aURL.GetLastName()); + } + else + { + aMsg = XsltResId(STR_FILTER_HAS_BEEN_SAVED); + aMsg = aMsg.replaceFirst( sPlaceholder, (*aFilters.begin())->maFilterName ); + aMsg = aMsg.replaceFirst(sPlaceholder, aURL.GetLastName()); + } + + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + aMsg)); + xInfoBox->run(); +} + +void XMLFilterSettingsDialog::onOpen() +{ + std::vector< std::unique_ptr<filter_info_impl> > aFilters; + + // Open Fileopen-Dialog + ::sfx2::FileDialogHelper aDlg( + css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_xDialog.get()); + aDlg.SetContext(sfx2::FileDialogHelper::XMLFilterSettings); + + OUString aExtensions( "*.jar" ); + OUString aFilterName = XsltResId(STR_FILTER_PACKAGE) + + " (" + aExtensions + ")"; + + aDlg.AddFilter( aFilterName, aExtensions ); + + if ( aDlg.Execute() != ERRCODE_NONE ) + return; + + OUString aURL( aDlg.GetPath() ); + + XMLFilterJarHelper aJarHelper( mxContext ); + aJarHelper.openPackage( aURL, aFilters ); + + int nFilters = 0; + for (auto& filter : aFilters) + { + if( insertOrEdit(filter.get()) ) + { + aFilterName = filter->maFilterName; + nFilters++; + } + + filter.reset(); + } + + disposeFilterList(); + initFilterList(); + + OUString sPlaceholder( "%s" ); + OUString aMsg; + if( nFilters == 0 ) + { + INetURLObject aURLObj( aURL ); + aMsg = XsltResId(STR_NO_FILTERS_FOUND); + aMsg = aMsg.replaceFirst(sPlaceholder, aURLObj.GetLastName()); + } + else if( nFilters == 1 ) + { + aMsg = XsltResId(STR_FILTER_INSTALLED); + aMsg = aMsg.replaceFirst( sPlaceholder, aFilterName ); + + } + else + { + aMsg = XsltResId(STR_FILTERS_INSTALLED); + aMsg = aMsg.replaceFirst( sPlaceholder, OUString::number( nFilters ) ); + } + + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + aMsg)); + xInfoBox->run(); +} + +void XMLFilterSettingsDialog::disposeFilterList() +{ + maFilterVector.clear(); + m_xFilterListBox->clear(); +} + +void XMLFilterSettingsDialog::initFilterList() +{ + if( mxFilterContainer.is() ) + { + const Sequence< OUString > aFilterNames( mxFilterContainer->getElementNames() ); + + Sequence< PropertyValue > aValues; + + std::unique_ptr<filter_info_impl> pTempFilter( new filter_info_impl ); + Sequence< OUString > aUserData; + + for( OUString const & filterName : aFilterNames ) + { + aUserData.realloc(0); + + try + { + Any aAny( mxFilterContainer->getByName( filterName ) ); + if( !(aAny >>= aValues) ) + continue; + + OUString aFilterService; + pTempFilter->maFilterName = filterName; + + const sal_Int32 nValueCount( aValues.getLength() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 nValue; + + for( nValue = 0; nValue < nValueCount; nValue++, pValues++ ) + { + if ( pValues->Name == "Type" ) + { + pValues->Value >>= pTempFilter->maType; + } + else if ( pValues->Name == "UIName" ) + { + pValues->Value >>= pTempFilter->maInterfaceName; + } + else if ( pValues->Name == "DocumentService" ) + { + pValues->Value >>= pTempFilter->maDocumentService; + } + else if ( pValues->Name == "FilterService" ) + { + pValues->Value >>= aFilterService; + } + else if ( pValues->Name == "Flags" ) + { + pValues->Value >>= pTempFilter->maFlags; + } + else if ( pValues->Name == "UserData" ) + { + pValues->Value >>= aUserData; + } + else if ( pValues->Name == "FileFormatVersion" ) + { + pValues->Value >>= pTempFilter->maFileFormatVersion; + } + else if ( pValues->Name == "TemplateName" ) + { + pValues->Value >>= pTempFilter->maImportTemplate; + } + else if ( pValues->Name == "Finalized" ) + { + pValues->Value >>= pTempFilter->mbReadonly; + } + } + + // if this is not a XmlFilterAdaptor entry, skip it + if( aFilterService != "com.sun.star.comp.Writer.XmlFilterAdaptor" ) + continue; + + + // if we don't have the needed user data, skip it + if( aUserData.getLength() < 6 ) + continue; + + // if this is not an XSLTFilter entry, skip it + if( aUserData[0] != "com.sun.star.documentconversion.XSLTFilter" ) + continue; + + // get filter information from userdata + pTempFilter->mbNeedsXSLT2 = aUserData[1].toBoolean(); + pTempFilter->maImportService = aUserData[2]; + pTempFilter->maExportService = aUserData[3]; + pTempFilter->maImportXSLT = aUserData[4]; + pTempFilter->maExportXSLT = aUserData[5]; + if( aUserData.getLength() >= 8 ) + pTempFilter->maComment = aUserData[7]; + + // get type information + if( mxTypeDetection.is() ) + { + try + { + aAny = mxTypeDetection->getByName( pTempFilter->maType ); + Sequence< PropertyValue > aValues2; + + if( aAny >>= aValues2 ) + { + const sal_Int32 nValueCount2( aValues2.getLength() ); + PropertyValue* pValues2 = aValues2.getArray(); + sal_Int32 nValue2; + + for( nValue2 = 0; nValue2 < nValueCount2; nValue2++, pValues2++ ) + { + if ( pValues2->Name == "ClipboardFormat" ) + { + OUString aDocType; + pValues2->Value >>= aDocType; + + if( aDocType.match( m_sDocTypePrefix ) ) + aDocType = aDocType.copy( m_sDocTypePrefix.getLength() ); + + pTempFilter->maDocType = aDocType; + } + else if ( pValues2->Name == "Extensions" ) + { + Sequence< OUString > aExtensions; + if( pValues2->Value >>= aExtensions ) + { + pTempFilter->maExtension.clear(); + + sal_Int32 nCount3( aExtensions.getLength() ); + OUString* pExtensions = aExtensions.getArray(); + sal_Int32 n; + for( n = 0; n < nCount3; n++ ) + { + if( n > 0 ) + pTempFilter->maExtension += ";"; + pTempFilter->maExtension += *pExtensions++; + } + } + } + else if ( pValues2->Name == "DocumentIconID" ) + { + pValues2->Value >>= pTempFilter->mnDocumentIconID; + } + else if ( pValues2->Name == "Finalized" ) + { + // both the filter and the type may be finalized + bool bTemp = false; + pValues2->Value >>= bTemp; + pTempFilter->mbReadonly |= bTemp; + } + } + } + } + catch( const css::container::NoSuchElementException& ) + { + OSL_FAIL( "Type not found, user error?" ); // TODO: error? + } + } + + // add entry to internal container and to ui filter list box + maFilterVector.push_back( std::unique_ptr<filter_info_impl>(pTempFilter.get()) ); + addFilterEntry( pTempFilter.release() ); + + + pTempFilter.reset( new filter_info_impl ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + } + } + + if (m_xFilterListBox->n_children()) + { + m_xFilterListBox->columns_autosize(); + m_xFilterListBox->select(0); + } +} + +application_info_impl::application_info_impl( const char * pDocumentService, const OUString& rUINameRes, const char * mpXMLImporter, const char * mpXMLExporter ) +: maDocumentService( pDocumentService, strlen( pDocumentService ), RTL_TEXTENCODING_ASCII_US ), + maDocumentUIName(Translate::ExpandVariables(rUINameRes)), + maXMLImporter( mpXMLImporter, strlen( mpXMLImporter ), RTL_TEXTENCODING_ASCII_US ), + maXMLExporter( mpXMLExporter, strlen( mpXMLExporter ), RTL_TEXTENCODING_ASCII_US ) +{ +} + +std::vector< application_info_impl > const & getApplicationInfos() +{ + static std::vector< application_info_impl > const aInfos + { + { "com.sun.star.text.TextDocument", + STR_APPL_NAME_WRITER, + "com.sun.star.comp.Writer.XMLImporter", + "com.sun.star.comp.Writer.XMLExporter" }, + + { "com.sun.star.sheet.SpreadsheetDocument", + STR_APPL_NAME_CALC, + "com.sun.star.comp.Calc.XMLImporter", + "com.sun.star.comp.Calc.XMLExporter" }, + + { "com.sun.star.presentation.PresentationDocument", + STR_APPL_NAME_IMPRESS, + "com.sun.star.comp.Impress.XMLImporter", + "com.sun.star.comp.Impress.XMLExporter" }, + + { "com.sun.star.drawing.DrawingDocument", + STR_APPL_NAME_DRAW, + "com.sun.star.comp.Draw.XMLImporter", + "com.sun.star.comp.Draw.XMLExporter" }, + + // --- oasis file formats... + { "com.sun.star.text.TextDocument", + STR_APPL_NAME_OASIS_WRITER, + "com.sun.star.comp.Writer.XMLOasisImporter", + "com.sun.star.comp.Writer.XMLOasisExporter" }, + + { "com.sun.star.sheet.SpreadsheetDocument", + STR_APPL_NAME_OASIS_CALC, + "com.sun.star.comp.Calc.XMLOasisImporter", + "com.sun.star.comp.Calc.XMLOasisExporter" }, + + { "com.sun.star.presentation.PresentationDocument", + STR_APPL_NAME_OASIS_IMPRESS, + "com.sun.star.comp.Impress.XMLOasisImporter", + "com.sun.star.comp.Impress.XMLOasisExporter" }, + + { "com.sun.star.drawing.DrawingDocument", + STR_APPL_NAME_OASIS_DRAW, + "com.sun.star.comp.Draw.XMLOasisImporter", + "com.sun.star.comp.Draw.XMLOasisExporter" }, + }; + + return aInfos; +} + +const application_info_impl* getApplicationInfo( std::u16string_view rServiceName ) +{ + std::vector< application_info_impl > const & rInfos = getApplicationInfos(); + for (auto const& info : rInfos) + { + if( rServiceName == info.maXMLExporter || + rServiceName == info.maXMLImporter) + { + return &info; + } + } + return nullptr; +} + +OUString getApplicationUIName( std::u16string_view rServiceName ) +{ + const application_info_impl* pInfo = getApplicationInfo( rServiceName ); + if( pInfo ) + { + return pInfo->maDocumentUIName; + } + else + { + OUString aRet = XsltResId(STR_UNKNOWN_APPLICATION); + if( !rServiceName.empty() ) + { + aRet += OUString::Concat(" (") + rServiceName + ")"; + } + return aRet; + } +} + +/** adds a new filter info entry to the ui filter list */ +void XMLFilterSettingsDialog::addFilterEntry( const filter_info_impl* pInfo ) +{ + int nRow = m_xFilterListBox->n_children(); + OUString sId(weld::toId(pInfo)); + m_xFilterListBox->append(sId, pInfo->maFilterName); + m_xFilterListBox->set_text(nRow, getEntryString(pInfo), 1); +} + +void XMLFilterSettingsDialog::changeEntry( const filter_info_impl* pInfo ) +{ + const int nCount = m_xFilterListBox->n_children(); + for(int nPos = 0; nPos < nCount; ++nPos) + { + filter_info_impl* pEntry = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_id(nPos)); + if (pEntry == pInfo) + { + m_xFilterListBox->set_text(nPos, pInfo->maFilterName, 0); + m_xFilterListBox->set_text(nPos, getEntryString(pInfo), 1); + break; + } + } +} + +OUString XMLFilterSettingsDialog::getEntryString( const filter_info_impl* pInfo ) +{ + OUString aEntryStr; + if ( !pInfo->maExportService.isEmpty() ) + aEntryStr = getApplicationUIName( pInfo->maExportService ); + else + aEntryStr = getApplicationUIName( pInfo->maImportService ); + aEntryStr += " - "; + + if( pInfo->maFlags & 1 ) + { + if( pInfo->maFlags & 2 ) + { + aEntryStr += XsltResId(STR_IMPORT_EXPORT); + } + else + { + aEntryStr += XsltResId(STR_IMPORT_ONLY); + } + } + else if( pInfo->maFlags & 2 ) + { + aEntryStr += XsltResId(STR_EXPORT_ONLY); + } + else + { + aEntryStr += XsltResId(STR_UNDEFINED_FILTER); + } + + return aEntryStr; +} + +filter_info_impl::filter_info_impl() + : maFlags(0x00080040) + , maFileFormatVersion(0) + , mnDocumentIconID(0) + , mbReadonly(false) + , mbNeedsXSLT2(false) +{ +} + +bool filter_info_impl::operator==( const filter_info_impl& r ) const +{ + return maFilterName == r.maFilterName && + maType == r.maType && + maDocumentService == r.maDocumentService && + maInterfaceName == r.maInterfaceName && + maComment == r.maComment && + maExtension == r.maExtension && + maDocType == r.maDocType && + maExportXSLT == r.maExportXSLT && + maImportXSLT == r.maImportXSLT && + maExportService == r.maExportService && + maImportService == r.maImportService && + maImportTemplate == r.maImportTemplate && + maFlags == r.maFlags && + maFileFormatVersion == r.maFileFormatVersion && + mbNeedsXSLT2 == r.mbNeedsXSLT2; +} + + +Sequence< OUString > filter_info_impl::getFilterUserData() const +{ + return + { + "com.sun.star.documentconversion.XSLTFilter", + OUString::boolean( mbNeedsXSLT2 ), + maImportService, + maExportService, + maImportXSLT, + maExportXSLT, + maComment + }; +} + +OUString string_encode( const OUString & rText ) +{ + static constexpr auto uricNoSlash = rtl::createUriCharClass( + u8"!$&'()*+-.0123456789:=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"); + + + return + Uri::encode( rText, uricNoSlash.data(), rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8 ); +} + +OUString string_decode( const OUString & rText ) +{ + return Uri::decode( rText, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); +} + +bool copyStreams( const Reference< XInputStream >& xIS, const Reference< XOutputStream >& xOS ) +{ + try + { + sal_Int32 nBufferSize = 512; + Sequence< sal_Int8 > aDataBuffer(nBufferSize); + + sal_Int32 nRead; + do + { + nRead = xIS->readBytes( aDataBuffer, nBufferSize ); + + if( nRead ) + { + if( nRead < nBufferSize ) + { + nBufferSize = nRead; + aDataBuffer.realloc(nRead); + } + + xOS->writeBytes( aDataBuffer ); + } + } + while( nRead ); + + xOS->flush(); + + return true; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + return false; +} + +bool createDirectory( std::u16string_view rURL ) +{ + size_t nLastIndex = sizeof( "file:///" ) - 2; + while( nLastIndex != std::u16string_view::npos ) + { + nLastIndex = rURL.find( '/', nLastIndex + 1); + if( nLastIndex != std::u16string_view::npos ) + { + OUString aDirURL( rURL.substr( 0, nLastIndex ) ); + Directory aDir( aDirURL ); + Directory::RC rc = aDir.open(); + if( rc == Directory::E_NOENT ) + rc = osl::Directory::create( aDirURL ); + + if( rc != Directory::E_None ) + { + return false; + } + } + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx b/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx new file mode 100644 index 000000000..c555e8b16 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx @@ -0,0 +1,97 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <vcl/weld.hxx> +#include <vcl/locktoplevels.hxx> +#include <unotools/moduleoptions.hxx> + +#include "xmlfiltercommon.hxx" + +class XMLFilterSettingsDialog : public weld::GenericDialogController +{ +public: + XMLFilterSettingsDialog(weld::Window* pParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext); + virtual ~XMLFilterSettingsDialog() override; + + DECL_LINK(ClickHdl_Impl, weld::Button&, void ); + DECL_LINK(SelectionChangedHdl_Impl, weld::TreeView&, void); + DECL_LINK(DoubleClickHdl_Impl, weld::TreeView&, bool); + + void UpdateWindow(); + + void present() { m_xDialog->present(); } + + void onNew(); + void onEdit(); + void onTest(); + void onDelete(); + void onSave(); + void onOpen(); + + void updateStates(); +private: + void initFilterList(); + void disposeFilterList(); + + void incBusy() { maBusy.incBusy(m_xDialog.get()); } + void decBusy() { maBusy.decBusy(); } + + bool insertOrEdit( filter_info_impl* pNewInfo, const filter_info_impl* pOldInfo = nullptr ); + + OUString createUniqueFilterName( const OUString& rUIName ); + OUString createUniqueTypeName( const OUString& rTypeName ); + OUString createUniqueInterfaceName( const OUString& rInterfaceName ); + + /** adds a new filter info entry to the ui filter list */ + void addFilterEntry( const filter_info_impl* pInfo ); + + void changeEntry( const filter_info_impl* pInfo ); + + static OUString getEntryString( const filter_info_impl* pInfo ); + +private: + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::container::XNameContainer > mxFilterContainer; + css::uno::Reference< css::container::XNameContainer > mxTypeDetection; + css::uno::Reference< css::container::XNameContainer > mxExtendedTypeDetection; + + std::vector< std::unique_ptr<filter_info_impl> > maFilterVector; + + TopLevelWindowLocker maBusy; + + OUString m_sTemplatePath; + OUString m_sDocTypePrefix; + + SvtModuleOptions maModuleOpt; + + std::unique_ptr<weld::Button> m_xPBNew; + std::unique_ptr<weld::Button> m_xPBEdit; + std::unique_ptr<weld::Button> m_xPBTest; + std::unique_ptr<weld::Button> m_xPBDelete; + std::unique_ptr<weld::Button> m_xPBSave; + std::unique_ptr<weld::Button> m_xPBOpen; + std::unique_ptr<weld::Button> m_xPBClose; + std::unique_ptr<weld::TreeView> m_xFilterListBox; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabdialog.cxx b/filter/source/xsltdialog/xmlfiltertabdialog.cxx new file mode 100644 index 000000000..ea73c486a --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabdialog.cxx @@ -0,0 +1,263 @@ +/* -*- 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 <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/fileurl.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <osl/file.hxx> +#include <unotools/resmgr.hxx> + +#include <strings.hrc> +#include "xmlfiltertabdialog.hxx" +#include "xmlfiltertabpagebasic.hxx" +#include "xmlfiltertabpagexslt.hxx" +#include "xmlfiltercommon.hxx" + +using namespace com::sun::star::uno; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; + +XMLFilterTabDialog::XMLFilterTabDialog(weld::Window *pParent, + const Reference< XComponentContext >& rxContext, const filter_info_impl* pInfo) + : GenericDialogController(pParent, "filter/ui/xsltfilterdialog.ui", "XSLTFilterDialog") + , mxContext(rxContext) + , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) + , mpBasicPage(new XMLFilterTabPageBasic(m_xTabCtrl->get_page("general"))) + , mpXSLTPage(new XMLFilterTabPageXSLT(m_xTabCtrl->get_page("transformation"), m_xDialog.get())) +{ + mpOldInfo = pInfo; + mpNewInfo.reset( new filter_info_impl( *mpOldInfo ) ); + + OUString aTitle(m_xDialog->get_title()); + aTitle = aTitle.replaceAll("%s", mpNewInfo->maFilterName); + m_xDialog->set_title(aTitle); + + m_xOKBtn->connect_clicked( LINK( this, XMLFilterTabDialog, OkHdl ) ); + + mpBasicPage->SetInfo( mpNewInfo.get() ); + mpXSLTPage->SetInfo( mpNewInfo.get() ); +} + +XMLFilterTabDialog::~XMLFilterTabDialog() +{ +} + +bool XMLFilterTabDialog::onOk() +{ + mpXSLTPage->FillInfo( mpNewInfo.get() ); + mpBasicPage->FillInfo( mpNewInfo.get() ); + + OString sErrorPage; + TranslateId pErrorId; + weld::Widget* pFocusWindow = nullptr; + OUString aReplace1; + OUString aReplace2; + + // 1. see if the filter name is ok + if( (mpNewInfo->maFilterName.isEmpty()) || (mpNewInfo->maFilterName != mpOldInfo->maFilterName) ) + { + // if the user deleted the filter name, we reset the original filter name + if( mpNewInfo->maFilterName.isEmpty() ) + { + mpNewInfo->maFilterName = mpOldInfo->maFilterName; + } + else + { + try + { + Reference< XNameAccess > xFilterContainer( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", mxContext ), UNO_QUERY ); + if( xFilterContainer.is() ) + { + if( xFilterContainer->hasByName( mpNewInfo->maFilterName ) ) + { + sErrorPage = "general"; + pErrorId = STR_ERROR_FILTER_NAME_EXISTS; + pFocusWindow = mpBasicPage->m_xEDFilterName.get(); + aReplace1 = mpNewInfo->maFilterName; + } + + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + } + } + + // 2. see if the interface name is ok + if( (mpNewInfo->maInterfaceName.isEmpty()) || (mpNewInfo->maInterfaceName != mpOldInfo->maInterfaceName) ) + { + // if the user deleted the interface name, we reset the original filter name + if( mpNewInfo->maInterfaceName.isEmpty() ) + { + mpNewInfo->maInterfaceName = mpOldInfo->maInterfaceName; + } + else + { + try + { + Reference< XNameAccess > xFilterContainer( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", mxContext ), UNO_QUERY ); + if( xFilterContainer.is() ) + { + Sequence< OUString > aFilterNames( xFilterContainer->getElementNames() ); + OUString* pFilterName = aFilterNames.getArray(); + + const sal_Int32 nCount = aFilterNames.getLength(); + sal_Int32 nFilter; + + Sequence< PropertyValue > aValues; + for( nFilter = 0; (nFilter < nCount) && !pErrorId; nFilter++, pFilterName++ ) + { + Any aAny( xFilterContainer->getByName( *pFilterName ) ); + if( !(aAny >>= aValues) ) + continue; + + const sal_Int32 nValueCount( aValues.getLength() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 nValue; + + for( nValue = 0; (nValue < nValueCount) && !pErrorId; nValue++, pValues++ ) + { + if ( pValues->Name == "UIName" ) + { + OUString aInterfaceName; + pValues->Value >>= aInterfaceName; + if( aInterfaceName == mpNewInfo->maInterfaceName ) + { + sErrorPage = "general"; + pErrorId = STR_ERROR_TYPE_NAME_EXISTS; + pFocusWindow = mpBasicPage->m_xEDInterfaceName.get(); + aReplace1 = mpNewInfo->maInterfaceName; + aReplace2 = *pFilterName; + } + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + } + } + + if (!pErrorId) + { + // 4. see if the export xslt is valid + if( (mpNewInfo->maExportXSLT != mpOldInfo->maExportXSLT) && comphelper::isFileUrl( mpNewInfo->maExportXSLT ) ) + { + osl::File aFile( mpNewInfo->maExportXSLT ); + osl::File::RC aRC = aFile.open( osl_File_OpenFlag_Read ); + if( aRC != osl::File::E_None ) + { + pErrorId = STR_ERROR_EXPORT_XSLT_NOT_FOUND; + sErrorPage = "transformation"; + pFocusWindow = mpXSLTPage->m_xEDExportXSLT->getWidget(); + } + } + } + + if (!pErrorId) + { + // 5. see if the import xslt is valid + if( (mpNewInfo->maImportXSLT != mpOldInfo->maImportXSLT) && comphelper::isFileUrl( mpNewInfo->maImportXSLT ) ) + { + osl::File aFile( mpNewInfo->maImportXSLT ); + osl::File::RC aRC = aFile.open( osl_File_OpenFlag_Read ); + if( aRC != osl::File::E_None ) + { + pErrorId = STR_ERROR_IMPORT_XSLT_NOT_FOUND; + sErrorPage = "transformation"; + pFocusWindow = mpXSLTPage->m_xEDImportTemplate->getWidget(); + } + } + } + + // see if we have at least an import or an export xslt + if((mpNewInfo->maImportXSLT.isEmpty()) && (mpNewInfo->maExportXSLT.isEmpty()) ) + { + pErrorId = STR_ERROR_EXPORT_XSLT_NOT_FOUND; + sErrorPage = "transformation"; + pFocusWindow = mpXSLTPage->m_xEDExportXSLT->getWidget(); + } + + if (!pErrorId) + { + // 6. see if the import template is valid + if( (mpNewInfo->maImportTemplate != mpOldInfo->maImportTemplate) && comphelper::isFileUrl( mpNewInfo->maImportTemplate ) ) + { + osl::File aFile( mpNewInfo->maImportTemplate ); + osl::File::RC aRC = aFile.open( osl_File_OpenFlag_Read ); + if( aRC != osl::File::E_None ) + { + pErrorId = STR_ERROR_IMPORT_TEMPLATE_NOT_FOUND; + sErrorPage = "transformation"; + pFocusWindow = mpXSLTPage->m_xEDImportTemplate->getWidget(); + } + } + } + + if (pErrorId) + { + m_xTabCtrl->set_current_page(sErrorPage); + + OUString aMessage(XsltResId(pErrorId)); + + if( aReplace2.getLength() ) + { + aMessage = aMessage.replaceAll( "%s1", aReplace1 ); + aMessage = aMessage.replaceAll( "%s2", aReplace2 ); + } + else if( aReplace1.getLength() ) + { + aMessage = aMessage.replaceAll( "%s", aReplace1 ); + } + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + aMessage)); + xBox->run(); + + if( pFocusWindow ) + pFocusWindow->grab_focus(); + + return false; + } + else + { + return true; + } +} + +IMPL_LINK_NOARG(XMLFilterTabDialog, OkHdl, weld::Button&, void) +{ + if( onOk() ) + m_xDialog->response(RET_OK); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabdialog.hxx b/filter/source/xsltdialog/xmlfiltertabdialog.hxx new file mode 100644 index 000000000..e764102b0 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabdialog.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <vcl/weld.hxx> + +class filter_info_impl; +class XMLFilterTabPageBasic; +class XMLFilterTabPageXSLT; + +class XMLFilterTabDialog : public weld::GenericDialogController +{ +public: + XMLFilterTabDialog(weld::Window *pParent, const css::uno::Reference< css::uno::XComponentContext >& rxContext, const filter_info_impl* pInfo); + virtual ~XMLFilterTabDialog() override; + + bool onOk(); + + filter_info_impl* getNewFilterInfo() const { return mpNewInfo.get(); } + +private: + css::uno::Reference< css::uno::XComponentContext > mxContext; + + DECL_LINK(OkHdl, weld::Button&, void); + + const filter_info_impl* mpOldInfo; + std::unique_ptr<filter_info_impl> mpNewInfo; + + std::unique_ptr<weld::Notebook> m_xTabCtrl; + std::unique_ptr<weld::Button> m_xOKBtn; + + std::unique_ptr<XMLFilterTabPageBasic> mpBasicPage; + std::unique_ptr<XMLFilterTabPageXSLT> mpXSLTPage; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabpagebasic.cxx b/filter/source/xsltdialog/xmlfiltertabpagebasic.cxx new file mode 100644 index 000000000..63b969a2f --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabpagebasic.cxx @@ -0,0 +1,128 @@ +/* -*- 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 <rtl/ustrbuf.hxx> +#include <vcl/svapp.hxx> +#include "xmlfiltercommon.hxx" +#include "xmlfiltertabpagebasic.hxx" + +XMLFilterTabPageBasic::XMLFilterTabPageBasic(weld::Widget* pPage) + : m_xBuilder(Application::CreateBuilder(pPage, "filter/ui/xmlfiltertabpagegeneral.ui")) + , m_xContainer(m_xBuilder->weld_widget("XmlFilterTabPageGeneral")) + , m_xEDFilterName(m_xBuilder->weld_entry("filtername")) + , m_xCBApplication(m_xBuilder->weld_combo_box("application")) + , m_xEDInterfaceName(m_xBuilder->weld_entry("interfacename")) + , m_xEDExtension(m_xBuilder->weld_entry("extension")) + , m_xEDDescription(m_xBuilder->weld_text_view("description")) +{ + m_xEDDescription->set_size_request(-1, m_xEDDescription->get_height_rows(4)); + + std::vector< application_info_impl > const & rInfos = getApplicationInfos(); + for (auto const& info : rInfos) + { + OUString aEntry( info.maDocumentUIName ); + m_xCBApplication->append_text( aEntry ); + } +} + +XMLFilterTabPageBasic::~XMLFilterTabPageBasic() +{ +} + +static OUString checkExtensions( const OUString& rExtensions ) +{ + const sal_Unicode* pSource = rExtensions.getStr(); + sal_Int32 nCount = rExtensions.getLength(); + + OUStringBuffer aRet; + while( nCount-- ) + { + switch(*pSource) + { + case u',': + aRet.append(";"); + break; + case u'.': + case u'*': + break; + default: + aRet.append( *pSource ); + } + + pSource++; + } + + return aRet.makeStringAndClear(); +} + +void XMLFilterTabPageBasic::FillInfo( filter_info_impl* pInfo ) +{ + if( !pInfo ) + return; + + if( !m_xEDFilterName->get_text().isEmpty() ) + pInfo->maFilterName = m_xEDFilterName->get_text(); + + if( !m_xCBApplication->get_active_text().isEmpty() ) + pInfo->maDocumentService = m_xCBApplication->get_active_text(); + + if( !m_xEDInterfaceName->get_text().isEmpty() ) + pInfo->maInterfaceName = m_xEDInterfaceName->get_text(); + + if( !m_xEDExtension->get_text().isEmpty() ) + pInfo->maExtension = checkExtensions( m_xEDExtension->get_text() ); + + pInfo->maComment = string_encode( m_xEDDescription->get_text() ); + + if( pInfo->maDocumentService.isEmpty() ) + return; + + std::vector< application_info_impl > const & rInfos = getApplicationInfos(); + for (auto const& info : rInfos) + { + if( pInfo->maDocumentService == info.maDocumentUIName ) + { + pInfo->maDocumentService = info.maDocumentService; + pInfo->maExportService = info.maXMLExporter; + pInfo->maImportService = info.maXMLImporter; + break; + } + } +} + +void XMLFilterTabPageBasic::SetInfo(const filter_info_impl* pInfo) +{ + if( !pInfo ) + return; + + m_xEDFilterName->set_text( string_decode(pInfo->maFilterName) ); + /* + if( pInfo->maDocumentService.getLength() ) + maCBApplication.set_text( getApplicationUIName( pInfo->maDocumentService ) ); + */ + if( !pInfo->maExportService.isEmpty() ) + m_xCBApplication->set_entry_text( getApplicationUIName( pInfo->maExportService ) ); + else + m_xCBApplication->set_entry_text( getApplicationUIName( pInfo->maImportService ) ); + m_xEDInterfaceName->set_text( string_decode(pInfo->maInterfaceName) ); + m_xEDExtension->set_text( pInfo->maExtension ); + m_xEDDescription->set_text( string_decode( pInfo->maComment ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabpagebasic.hxx b/filter/source/xsltdialog/xmlfiltertabpagebasic.hxx new file mode 100644 index 000000000..c11a4c69e --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabpagebasic.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ +#pragma once + +#include <vcl/weld.hxx> + +class filter_info_impl; + +class XMLFilterTabPageBasic +{ +public: + explicit XMLFilterTabPageBasic(weld::Widget* pPage); + ~XMLFilterTabPageBasic(); + + void FillInfo( filter_info_impl* pInfo ); + void SetInfo(const filter_info_impl* pInfo); + + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Widget> m_xContainer; + std::unique_ptr<weld::Entry> m_xEDFilterName; + std::unique_ptr<weld::ComboBox> m_xCBApplication; + std::unique_ptr<weld::Entry> m_xEDInterfaceName; + std::unique_ptr<weld::Entry> m_xEDExtension; + std::unique_ptr<weld::TextView> m_xEDDescription; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabpagexslt.cxx b/filter/source/xsltdialog/xmlfiltertabpagexslt.cxx new file mode 100644 index 000000000..4d758da28 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabpagexslt.cxx @@ -0,0 +1,165 @@ +/* -*- 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 <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <sfx2/filedlghelper.hxx> +#include <unotools/pathoptions.hxx> +#include <osl/file.hxx> +#include <svl/urihelper.hxx> +#include <vcl/svapp.hxx> + +#include "xmlfiltercommon.hxx" +#include "xmlfiltertabpagexslt.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +XMLFilterTabPageXSLT::XMLFilterTabPageXSLT(weld::Widget* pPage, weld::Dialog* pDialog) + : sInstPath( "$(prog)/" ) + , m_pDialog(pDialog) + , m_xBuilder(Application::CreateBuilder(pPage, "filter/ui/xmlfiltertabpagetransformation.ui")) + , m_xContainer(m_xBuilder->weld_widget("XmlFilterTabPageTransformation")) + , m_xEDDocType(m_xBuilder->weld_entry("doc")) + , m_xEDExportXSLT(new SvtURLBox(m_xBuilder->weld_combo_box("xsltexport"))) + , m_xPBExprotXSLT(m_xBuilder->weld_button("browseexport")) + , m_xEDImportXSLT(new SvtURLBox(m_xBuilder->weld_combo_box("xsltimport"))) + , m_xPBImportXSLT(m_xBuilder->weld_button("browseimport")) + , m_xEDImportTemplate(new SvtURLBox(m_xBuilder->weld_combo_box("tempimport"))) + , m_xPBImportTemplate(m_xBuilder->weld_button("browsetemp")) + , m_xCBNeedsXSLT2(m_xBuilder->weld_check_button("filtercb")) +{ + SvtPathOptions aOptions; + sInstPath = aOptions.SubstituteVariable( sInstPath ); + + m_xPBExprotXSLT->connect_clicked( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) ); + m_xPBImportXSLT->connect_clicked( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) ); + m_xPBImportTemplate->connect_clicked( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) ); +} + +XMLFilterTabPageXSLT::~XMLFilterTabPageXSLT() +{ +} + +void XMLFilterTabPageXSLT::FillInfo( filter_info_impl* pInfo ) +{ + if( pInfo ) + { + pInfo->maDocType = m_xEDDocType->get_text(); + pInfo->maExportXSLT = GetURL(*m_xEDExportXSLT); + pInfo->maImportXSLT = GetURL(*m_xEDImportXSLT); + pInfo->maImportTemplate = GetURL(*m_xEDImportTemplate); + pInfo->mbNeedsXSLT2 = m_xCBNeedsXSLT2->get_active(); + } +} + +void XMLFilterTabPageXSLT::SetInfo(const filter_info_impl* pInfo) +{ + if( pInfo ) + { + m_xEDDocType->set_text( pInfo->maDocType ); + + SetURL( *m_xEDExportXSLT, pInfo->maExportXSLT ); + SetURL( *m_xEDImportXSLT, pInfo->maImportXSLT ); + SetURL( *m_xEDImportTemplate, pInfo->maImportTemplate ); + m_xCBNeedsXSLT2->set_active(pInfo->mbNeedsXSLT2); + } +} + +void XMLFilterTabPageXSLT::SetURL( SvtURLBox& rURLBox, const OUString& rURL ) +{ + OUString aPath; + + if( rURL.matchIgnoreAsciiCase( "file://" ) ) + { + osl::FileBase::getSystemPathFromFileURL( rURL, aPath ); + + rURLBox.SetBaseURL( rURL ); + rURLBox.set_entry_text( aPath ); + } + else if( rURL.matchIgnoreAsciiCase( "http://" ) || + rURL.matchIgnoreAsciiCase( "https://" ) || + rURL.matchIgnoreAsciiCase( "ftp://" ) ) + { + rURLBox.SetBaseURL( rURL ); + rURLBox.set_entry_text( rURL ); + } + else if( !rURL.isEmpty() ) + { + OUString aURL = URIHelper::SmartRel2Abs( INetURLObject(sInstPath), rURL, Link<OUString *, bool>(), false ); + osl::FileBase::getSystemPathFromFileURL( aURL, aPath ); + + rURLBox.SetBaseURL( aURL ); + rURLBox.set_entry_text( aPath ); + } + else + { + rURLBox.SetBaseURL( sInstPath ); + rURLBox.set_entry_text( "" ); + } +} + +OUString XMLFilterTabPageXSLT::GetURL(const SvtURLBox& rURLBox) +{ + OUString aURL; + OUString aStrPath(rURLBox.get_active_text()); + if( aStrPath.matchIgnoreAsciiCase( "http://" ) || + aStrPath.matchIgnoreAsciiCase( "https://" ) || + aStrPath.matchIgnoreAsciiCase( "ftp://" ) ) + { + return aStrPath; + } + else + { + osl::FileBase::getFileURLFromSystemPath( aStrPath, aURL ); + } + + return aURL; +} + +IMPL_LINK ( XMLFilterTabPageXSLT, ClickBrowseHdl_Impl, weld::Button&, rButton, void ) +{ + SvtURLBox* pURLBox; + + if( &rButton == m_xPBExprotXSLT.get() ) + { + pURLBox = m_xEDExportXSLT.get(); + } + else if( &rButton == m_xPBImportXSLT.get() ) + { + pURLBox = m_xEDImportXSLT.get(); + } + else + { + pURLBox = m_xEDImportTemplate.get(); + } + + // Open Fileopen-Dialog + ::sfx2::FileDialogHelper aDlg(css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_pDialog); + + aDlg.SetDisplayDirectory(GetURL(*pURLBox)); + + if (aDlg.Execute() == ERRCODE_NONE) + { + OUString aURL(aDlg.GetPath()); + SetURL(*pURLBox, aURL); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertabpagexslt.hxx b/filter/source/xsltdialog/xmlfiltertabpagexslt.hxx new file mode 100644 index 000000000..52538a834 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertabpagexslt.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#pragma once + +#include <vcl/weld.hxx> +#include <svtools/inettbc.hxx> + +class filter_info_impl; + +class XMLFilterTabPageXSLT +{ +private: + void SetURL(SvtURLBox& rURLBox, const OUString& rURL); + static OUString GetURL(const SvtURLBox& rURLBox); + + OUString sInstPath; + +public: + explicit XMLFilterTabPageXSLT(weld::Widget* pPage, weld::Dialog* pDialog); + ~XMLFilterTabPageXSLT(); + + void FillInfo( filter_info_impl* pInfo ); + void SetInfo(const filter_info_impl* pInfo); + + DECL_LINK( ClickBrowseHdl_Impl, weld::Button&, void ); + + weld::Dialog* m_pDialog; + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Widget> m_xContainer; + std::unique_ptr<weld::Entry> m_xEDDocType; + std::unique_ptr<SvtURLBox> m_xEDExportXSLT; + std::unique_ptr<weld::Button> m_xPBExprotXSLT; + std::unique_ptr<SvtURLBox> m_xEDImportXSLT; + std::unique_ptr<weld::Button> m_xPBImportXSLT; + std::unique_ptr<SvtURLBox> m_xEDImportTemplate; + std::unique_ptr<weld::Button> m_xPBImportTemplate; + std::unique_ptr<weld::CheckButton> m_xCBNeedsXSLT2; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertestdialog.cxx b/filter/source/xsltdialog/xmlfiltertestdialog.cxx new file mode 100644 index 000000000..ca38ab547 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertestdialog.cxx @@ -0,0 +1,697 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XGraphicStorageHandler.hpp> +#include <com/sun/star/document/XEmbeddedObjectResolver.hpp> +#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/system/SystemShellExecute.hpp> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/xml/XImportFilter.hpp> +#include <com/sun/star/xml/XExportFilter.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> + +#include <comphelper/oslfile2streamwrap.hxx> +#include <comphelper/propertyvalue.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/filedlghelper.hxx> +#include <osl/file.hxx> +#include <unotools/tempfile.hxx> +#include <tools/diagnose_ex.h> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/processfactory.hxx> + +#include "xmlfiltercommon.hxx" +#include "xmlfiltertestdialog.hxx" + + +using namespace utl; +using namespace osl; +using namespace comphelper; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::document; +using namespace com::sun::star::frame; +using namespace com::sun::star::task; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace com::sun::star::system; +using namespace com::sun::star::xml; +using namespace com::sun::star::xml::sax; + +namespace { + +class GlobalEventListenerImpl : public ::cppu::WeakImplHelper< css::document::XDocumentEventListener > +{ +public: + explicit GlobalEventListenerImpl( XMLFilterTestDialog* pDialog ); + + // XDocumentEventListener + virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override; + + // lang::XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; +private: + XMLFilterTestDialog* mpDialog; +}; + +} + +GlobalEventListenerImpl::GlobalEventListenerImpl( XMLFilterTestDialog* pDialog ) +: mpDialog( pDialog ) +{ +} + +void SAL_CALL GlobalEventListenerImpl::documentEventOccured( const css::document::DocumentEvent& Event ) +{ + ::SolarMutexGuard aGuard; + if( Event.EventName == "OnFocus" || Event.EventName == "OnUnload" ) + { + Reference< XComponent > xComp( Event.Source, UNO_QUERY ); + mpDialog->updateCurrentDocumentButtonState( &xComp ); + } +} + +void SAL_CALL GlobalEventListenerImpl::disposing( const css::lang::EventObject& /* Source */ ) +{ +} + +/** returns true if the given component supports the given service */ +static bool checkComponent( Reference< XComponent > const & rxComponent, const OUString& rServiceName ) +{ + try + { + Reference< XServiceInfo > xInfo( rxComponent, UNO_QUERY ); + if( xInfo.is() ) + { + if( xInfo->supportsService( rServiceName ) ) + { + // special case for impress documents which supports same service as draw documents + if ( rServiceName == "com.sun.star.drawing.DrawingDocument" ) + { + // so if we want a draw we need to check if it's not an impress + if( !xInfo->supportsService("com.sun.star.presentation.PresentationDocument") ) + return true; + } + else + { + return true; + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + return false; +} + +XMLFilterTestDialog::XMLFilterTestDialog(weld::Window* pParent, + const Reference<XComponentContext>& rxContext) + : GenericDialogController(pParent, "filter/ui/testxmlfilter.ui", "TestXMLFilterDialog") + , mxContext(rxContext) + , m_xExport(m_xBuilder->weld_widget("export")) + , m_xFTExportXSLTFile(m_xBuilder->weld_label("exportxsltfile")) + , m_xPBExportBrowse(m_xBuilder->weld_button("exportbrowse")) + , m_xPBCurrentDocument(m_xBuilder->weld_button("currentdocument")) + , m_xFTNameOfCurrentFile(m_xBuilder->weld_label("currentfilename")) + , m_xImport(m_xBuilder->weld_widget("import")) + , m_xFTImportXSLTFile(m_xBuilder->weld_label("importxsltfile")) + , m_xFTImportTemplate(m_xBuilder->weld_label("templateimport")) + , m_xFTImportTemplateFile(m_xBuilder->weld_label("importxslttemplate")) + , m_xCBXDisplaySource(m_xBuilder->weld_check_button("displaysource")) + , m_xPBImportBrowse(m_xBuilder->weld_button("importbrowse")) + , m_xPBRecentFile(m_xBuilder->weld_button("recentfile")) + , m_xFTNameOfRecentFile(m_xBuilder->weld_label("recentfilename")) + , m_xPBClose(m_xBuilder->weld_button("close")) +{ + m_xPBExportBrowse->connect_clicked(LINK( this, XMLFilterTestDialog, ClickHdl_Impl ) ); + m_xPBCurrentDocument->connect_clicked(LINK( this, XMLFilterTestDialog, ClickHdl_Impl ) ); + m_xPBImportBrowse->connect_clicked(LINK( this, XMLFilterTestDialog, ClickHdl_Impl ) ); + m_xPBRecentFile->connect_clicked(LINK( this, XMLFilterTestDialog, ClickHdl_Impl ) ); + m_xPBClose->connect_clicked(LINK( this, XMLFilterTestDialog, ClickHdl_Impl ) ); + + m_sDialogTitle = m_xDialog->get_title(); + + try + { + mxGlobalBroadcaster = theGlobalEventBroadcaster::get(mxContext); + mxGlobalEventListener = new GlobalEventListenerImpl( this ); + mxGlobalBroadcaster->addDocumentEventListener( mxGlobalEventListener ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +XMLFilterTestDialog::~XMLFilterTestDialog() +{ + try + { + if( mxGlobalBroadcaster.is() ) + mxGlobalBroadcaster->removeDocumentEventListener( mxGlobalEventListener ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +void XMLFilterTestDialog::test( const filter_info_impl& rFilterInfo ) +{ + m_xFilterInfo.reset(new filter_info_impl( rFilterInfo )); + + m_sImportRecentFile.clear(); + + initDialog(); + + m_xDialog->run(); +} + +static OUString getFileNameFromURL( std::u16string_view rURL ) +{ + INetURLObject aURL( rURL ); + OUString aName( aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset) ); + return aName; +} + +void XMLFilterTestDialog::updateCurrentDocumentButtonState( Reference< XComponent > const * pRef /* = NULL */ ) +{ + if( pRef && pRef->is() ) + { + if( checkComponent( *pRef, m_xFilterInfo->maDocumentService ) ) + mxLastFocusModel = *pRef; + } + + bool bExport = (m_xFilterInfo->maFlags & 2) == 2; + Reference< XComponent > xCurrentDocument; + if( bExport ) + xCurrentDocument = getFrontMostDocument( m_xFilterInfo->maDocumentService ); + m_xPBCurrentDocument->set_sensitive( bExport && xCurrentDocument.is() ); + m_xFTNameOfCurrentFile->set_sensitive( bExport && xCurrentDocument.is() ); + + if( !xCurrentDocument.is() ) + return; + + OUString aTitle; + Reference< XDocumentPropertiesSupplier > xDPS( xCurrentDocument, UNO_QUERY ); + if( xDPS.is() ) + { + Reference< XDocumentProperties > xProps( xDPS->getDocumentProperties() ); + if( xProps.is() ) + { + aTitle = xProps->getTitle(); + } + } + + if( aTitle.isEmpty() ) + { + Reference< XStorable > xStorable( xCurrentDocument, UNO_QUERY ); + if( xStorable.is() ) + { + if( xStorable->hasLocation() ) + { + OUString aURL( xStorable->getLocation() ); + aTitle = getFileNameFromURL( aURL ); + } + } + } + + m_xFTNameOfCurrentFile->set_label( aTitle ); +} + +void XMLFilterTestDialog::initDialog() +{ + DBG_ASSERT( m_xFilterInfo, "i need a filter I can test!" ); + if( nullptr == m_xFilterInfo ) + return; + + OUString aTitle( m_sDialogTitle ); + aTitle = aTitle.replaceFirst( "%s", m_xFilterInfo->maFilterName ); + m_xDialog->set_title( aTitle ); + + bool bImport = (m_xFilterInfo->maFlags & 1) == 1; + bool bExport = (m_xFilterInfo->maFlags & 2) == 2; + + updateCurrentDocumentButtonState(); + + m_xExport->set_sensitive(bExport); + m_xFTExportXSLTFile->set_label( getFileNameFromURL( m_xFilterInfo->maExportXSLT ) ); + + + m_xImport->set_sensitive(bImport); + m_xFTImportTemplate->set_sensitive(bImport && !m_xFilterInfo->maImportTemplate.isEmpty()); + m_xFTImportTemplateFile->set_sensitive(bImport && !m_xFilterInfo->maImportTemplate.isEmpty()); + m_xPBRecentFile->set_sensitive(bImport && !m_sImportRecentFile.isEmpty()); + m_xFTNameOfRecentFile->set_sensitive(bImport && !m_sImportRecentFile.isEmpty()); + + m_xFTImportXSLTFile->set_label( getFileNameFromURL( m_xFilterInfo->maImportXSLT ) ); + m_xFTImportTemplateFile->set_label( getFileNameFromURL( m_xFilterInfo->maImportTemplate ) ); + m_xFTNameOfRecentFile->set_label( getFileNameFromURL( m_sImportRecentFile ) ); +} + +void XMLFilterTestDialog::onExportBrowse() +{ + try + { + // Open Fileopen-Dialog + ::sfx2::FileDialogHelper aDlg( + css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_xDialog.get()); + + Reference< XNameAccess > xFilterContainer( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", mxContext ), UNO_QUERY ); + Reference< XNameAccess > xTypeDetection( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", mxContext ), UNO_QUERY ); + if( xFilterContainer.is() && xTypeDetection.is() ) + { + const Sequence< OUString > aFilterNames( xFilterContainer->getElementNames() ); + + for( OUString const & filterName : aFilterNames ) + { + Sequence< PropertyValue > aValues; + + Any aAny( xFilterContainer->getByName( filterName ) ); + if( !(aAny >>= aValues) ) + continue; + + OUString aInterfaceName; + OUString aType, aService; + sal_Int32 nFlags( 0 ); + + int nFound = 0; + + for( const PropertyValue& rValue : std::as_const(aValues) ) + { + if ( rValue.Name == "Type" ) + { + rValue.Value >>= aType; + nFound |= 1; + } + else if ( rValue.Name == "DocumentService" ) + { + rValue.Value >>= aService; + nFound |= 2; + } + else if ( rValue.Name == "Flags" ) + { + rValue.Value >>= nFlags; + nFound |= 4; + } + else if ( rValue.Name == "UIName" ) + { + rValue.Value >>= aInterfaceName; + nFound |= 8; + } + + if (nFound == 15) + break; + } + + if( (nFound == 15) && (!aType.isEmpty() && aService == m_xFilterInfo->maDocumentService) ) + { + // see if this filter is not suppressed in dialog + if( (nFlags & 0x1000) == 0 ) + { + aAny = xTypeDetection->getByName( aType ); + Sequence< PropertyValue > aValues2; + + if( aAny >>= aValues2 ) + { + OUString aExtension; + for( const PropertyValue& rProp : std::as_const(aValues2) ) + { + if ( rProp.Name == "Extensions" ) + { + Sequence< OUString > aExtensions; + if( rProp.Value >>= aExtensions ) + { + const sal_Int32 nCount( aExtensions.getLength() ); + OUString* pExtensions = aExtensions.getArray(); + sal_Int32 n; + for( n = 0; n < nCount; n++ ) + { + if( n > 0 ) + aExtension += ";"; + aExtension += "*." + *pExtensions++; + } + } + } + } + + OUString aFilterName( aInterfaceName + " (" + aExtension + ")" ); + + aDlg.AddFilter( aFilterName, aExtension ); + + if( (nFlags & 0x100) == 0x100 ) + aDlg.SetCurrentFilter( aFilterName ); + } + } + } + + } + } + + aDlg.SetDisplayDirectory( m_sExportRecentFile ); + + if ( aDlg.Execute() == ERRCODE_NONE ) + { + m_sExportRecentFile = aDlg.GetPath(); + + Reference< XDesktop2 > xLoader = Desktop::create( mxContext ); + Reference< XInteractionHandler2 > xInter = InteractionHandler::createWithParent(mxContext, nullptr); + Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue("InteractionHandler", + xInter) }; + Reference< XComponent > xComp( xLoader->loadComponentFromURL( m_sExportRecentFile, "_default", 0, aArguments ) ); + if( xComp.is() ) + { + doExport( xComp ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + initDialog(); +} + +void XMLFilterTestDialog::onExportCurrentDocument() +{ + doExport( getFrontMostDocument( m_xFilterInfo->maDocumentService ) ); +} + +void XMLFilterTestDialog::doExport( const Reference< XComponent >& xComp ) +{ + try + { + Reference< XStorable > xStorable( xComp, UNO_QUERY ); + if( xStorable.is() ) + { + OUString const ext(".xml"); + utl::TempFile aTempFile(u"", true, &ext); + OUString aTempFileURL( aTempFile.GetURL() ); + + const application_info_impl* pAppInfo = getApplicationInfo( m_xFilterInfo->maExportService ); + if( pAppInfo ) + { + File aOutputFile( aTempFileURL ); + (void)aOutputFile.open( osl_File_OpenFlag_Write ); + + // create xslt exporter + Reference< XOutputStream > xIS( new comphelper::OSLOutputStreamWrapper( aOutputFile ) ); + int bUseDocType = m_xFilterInfo->maDocType.isEmpty() ? 0 : 1; + Sequence< PropertyValue > aSourceData( 2 + bUseDocType ); + auto pSourceData = aSourceData.getArray(); + int i = 0; + + + pSourceData[i ].Name = "OutputStream"; + pSourceData[i++].Value <<= xIS; + + pSourceData[i].Name = "Indent"; + pSourceData[i++].Value <<= true; + + if( bUseDocType ) + { + pSourceData[i ].Name = "DocType_Public"; + pSourceData[i++].Value <<= m_xFilterInfo->maDocType; + } + + Reference< XExportFilter > xExporter( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.documentconversion.XSLTFilter", mxContext ), UNO_QUERY ); + Reference< XDocumentHandler > xHandler( xExporter, UNO_QUERY ); + if( xHandler.is() ) + { + Sequence< OUString > aFilterUserData( m_xFilterInfo->getFilterUserData() ); + xExporter->exporter( aSourceData, aFilterUserData ); + + Reference< XMultiServiceFactory > xDocFac( xComp, UNO_QUERY ); + + Reference< XEmbeddedObjectResolver > xObjectResolver; + Reference<XGraphicStorageHandler> xGraphicStorageHandler; + + if( xDocFac.is() ) + { + try + { + xGraphicStorageHandler.set(xDocFac->createInstance("com.sun.star.document.ExportGraphicStorageHandler"), UNO_QUERY); + xObjectResolver.set( xDocFac->createInstance("com.sun.star.document.ExportEmbeddedObjectResolver"), UNO_QUERY ); + } + catch( const Exception& ) + { + } + } + + Sequence< Any > aArgs( 1 + ( xGraphicStorageHandler.is() ? 1 : 0 ) + ( xObjectResolver.is() ? 1 : 0 ) ); + Any* pArgs = aArgs.getArray(); + if (xGraphicStorageHandler.is()) + *pArgs++ <<= xGraphicStorageHandler; + + if (xObjectResolver.is()) + *pArgs++ <<= xObjectResolver; + + // *pArgs++ <<= xInfoSet; + *pArgs <<= xHandler; + + Reference< XFilter > xFilter( mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( pAppInfo->maXMLExporter, aArgs, mxContext ), UNO_QUERY ); + if( xFilter.is() ) + { + Reference< XExporter > xExporter2( xFilter, UNO_QUERY ); + if( xExporter2.is() ) + { + xExporter2->setSourceDocument( xComp ); + + Sequence< PropertyValue > aDescriptor{comphelper::makePropertyValue( + "FileName", aTempFileURL) }; + + if( xFilter->filter( aDescriptor ) ) + displayXMLFile( aTempFileURL ); + } + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +void XMLFilterTestDialog::displayXMLFile( const OUString& rURL ) +{ + Reference< XSystemShellExecute > xSystemShellExecute( + SystemShellExecute::create(comphelper::getProcessComponentContext()) ); + xSystemShellExecute->execute( rURL, OUString(), SystemShellExecuteFlags::URIS_ONLY ); +} + +void XMLFilterTestDialog::onImportBrowse() +{ + // Open Fileopen-Dialog + ::sfx2::FileDialogHelper aDlg( + css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, m_xDialog.get()); + OUString aFilterName( m_xFilterInfo->maInterfaceName ); + OUString aExtensions; + + int nLastIndex = 0; + int nCurrentIndex = 0; + for( int i = 0; nLastIndex != -1; i++ ) + { + nLastIndex = m_xFilterInfo->maExtension.indexOf( ';', nLastIndex ); + + if( i > 0 ) + aExtensions += ";"; + + aExtensions += "*."; + + if( nLastIndex == -1 ) + { + + aExtensions += m_xFilterInfo->maExtension.subView( nCurrentIndex ); + } + else + { + aExtensions += m_xFilterInfo->maExtension.subView( nCurrentIndex, nLastIndex - nCurrentIndex ); + nCurrentIndex = nLastIndex + 1; + nLastIndex = nCurrentIndex; + } + } + + aFilterName += " (" + aExtensions + ")"; + + aDlg.AddFilter( aFilterName, aExtensions ); + aDlg.SetDisplayDirectory( m_sImportRecentFile ); + + if ( aDlg.Execute() == ERRCODE_NONE ) + { + m_sImportRecentFile = aDlg.GetPath(); + import( m_sImportRecentFile ); + } + + initDialog(); +} + +void XMLFilterTestDialog::import( const OUString& rURL ) +{ + try + { + Reference< XDesktop2 > xLoader = Desktop::create( mxContext ); + Reference< XInteractionHandler2 > xInter = InteractionHandler::createWithParent(mxContext, nullptr); + + Sequence< PropertyValue > aArguments{ + comphelper::makePropertyValue("FilterName", m_xFilterInfo->maFilterName), + comphelper::makePropertyValue("InteractionHandler", xInter) + }; + + xLoader->loadComponentFromURL( rURL, "_default", 0, aArguments ); + + if( m_xCBXDisplaySource->get_active() ) + { + OUString const ext(".xml"); + TempFile aTempFile(u"", true, &ext); + OUString aTempFileURL( aTempFile.GetURL() ); + + Reference< XImportFilter > xImporter( mxContext->getServiceManager()->createInstanceWithContext( "com.sun.star.documentconversion.XSLTFilter", mxContext ), UNO_QUERY ); + if( xImporter.is() ) + { + osl::File aInputFile( rURL ); + (void)aInputFile.open( osl_File_OpenFlag_Read ); + + Reference< XInputStream > xIS( new comphelper::OSLInputStreamWrapper( aInputFile ) ); + + Sequence< PropertyValue > aSourceData{ + comphelper::makePropertyValue("InputStream", xIS), + comphelper::makePropertyValue("FileName", rURL), + comphelper::makePropertyValue("Indent", true) + }; + + Reference< XWriter > xWriter = Writer::create( mxContext ); + + File aOutputFile( aTempFileURL ); + (void)aOutputFile.open( osl_File_OpenFlag_Write ); + + Reference< XOutputStream > xOS( new OSLOutputStreamWrapper( aOutputFile ) ); + xWriter->setOutputStream( xOS ); + + Sequence< OUString > aFilterUserData( m_xFilterInfo->getFilterUserData() ); + xImporter->importer( aSourceData, xWriter, aFilterUserData ); + } + + displayXMLFile( aTempFileURL ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } +} + +IMPL_LINK(XMLFilterTestDialog, ClickHdl_Impl, weld::Button&, rButton, void ) +{ + if (m_xPBExportBrowse.get() == &rButton) + { + onExportBrowse(); + } + else if (m_xPBCurrentDocument.get() == &rButton) + { + onExportCurrentDocument(); + } + else if (m_xPBImportBrowse.get() == &rButton) + { + onImportBrowse(); + } + else if (m_xPBRecentFile.get() == &rButton) + { + import( m_sImportRecentFile ); + } + else if (m_xPBClose.get() == &rButton) + { + m_xDialog->response(RET_CLOSE); + } +} + +/** returns the front most open component that supports the given service */ +Reference< XComponent > XMLFilterTestDialog::getFrontMostDocument( const OUString& rServiceName ) +{ + Reference< XComponent > xRet; + + try + { + Reference< XDesktop2 > xDesktop = Desktop::create( mxContext ); + Reference< XComponent > xTest( mxLastFocusModel ); + if( checkComponent( xTest, rServiceName ) ) + { + xRet = xTest; + } + else + { + xTest = xDesktop->getCurrentComponent(); + + if( checkComponent( xTest, rServiceName ) ) + { + xRet = xTest; + } + else + { + Reference< XEnumerationAccess > xAccess( xDesktop->getComponents() ); + if( xAccess.is() ) + { + Reference< XEnumeration > xEnum( xAccess->createEnumeration() ); + if( xEnum.is() ) + { + while( xEnum->hasMoreElements() ) + { + if( (xEnum->nextElement() >>= xTest) && xTest.is() ) + { + if( checkComponent( xTest, rServiceName ) ) + { + xRet = xTest; + break; + } + } + } + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("filter.xslt", ""); + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xmlfiltertestdialog.hxx b/filter/source/xsltdialog/xmlfiltertestdialog.hxx new file mode 100644 index 000000000..bce1e19e1 --- /dev/null +++ b/filter/source/xsltdialog/xmlfiltertestdialog.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <cppuhelper/weakref.hxx> +#include <vcl/weld.hxx> + +class filter_info_impl; + +class XMLFilterTestDialog : public weld::GenericDialogController +{ +public: + XMLFilterTestDialog(weld::Window* pParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext); + virtual ~XMLFilterTestDialog() override; + + void test( const filter_info_impl& rFilterInfo ); + + void updateCurrentDocumentButtonState( css::uno::Reference< css::lang::XComponent > const * pRef = nullptr ); + +private: + DECL_LINK(ClickHdl_Impl, weld::Button&, void); + + void onExportBrowse(); + void onExportCurrentDocument(); + void onImportBrowse(); + void initDialog(); + + css::uno::Reference< css::lang::XComponent > getFrontMostDocument( const OUString& rServiceName ); + void import( const OUString& rURL ); + static void displayXMLFile( const OUString& rURL ); + void doExport( const css::uno::Reference< css::lang::XComponent >& xComp ); + +private: + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::document::XDocumentEventBroadcaster > mxGlobalBroadcaster; + css::uno::Reference< css::document::XDocumentEventListener > mxGlobalEventListener; + css::uno::WeakReference< css::lang::XComponent > mxLastFocusModel; + + OUString m_sImportRecentFile; + OUString m_sExportRecentFile; + std::unique_ptr<filter_info_impl> m_xFilterInfo; + OUString m_sDialogTitle; + + std::unique_ptr<weld::Widget> m_xExport; + std::unique_ptr<weld::Label> m_xFTExportXSLTFile; + std::unique_ptr<weld::Button> m_xPBExportBrowse; + std::unique_ptr<weld::Button> m_xPBCurrentDocument; + std::unique_ptr<weld::Label> m_xFTNameOfCurrentFile; + std::unique_ptr<weld::Widget> m_xImport; + std::unique_ptr<weld::Label> m_xFTImportXSLTFile; + std::unique_ptr<weld::Label> m_xFTImportTemplate; + std::unique_ptr<weld::Label> m_xFTImportTemplateFile; + std::unique_ptr<weld::CheckButton> m_xCBXDisplaySource; + std::unique_ptr<weld::Button> m_xPBImportBrowse; + std::unique_ptr<weld::Button> m_xPBRecentFile; + std::unique_ptr<weld::Label> m_xFTNameOfRecentFile; + std::unique_ptr<weld::Button> m_xPBClose; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/xsltdialog/xsltdlg.component b/filter/source/xsltdialog/xsltdlg.component new file mode 100644 index 000000000..6d4a693f3 --- /dev/null +++ b/filter/source/xsltdialog/xsltdlg.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.ui.XSLTFilterDialog" + constructor="filter_XSLTFilterDialog_get_implementation"> + <service name="com.sun.star.ui.dialogs.XSLTFilterDialog"/> + </implementation> +</component> |