/* -*- 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 <comphelper/diagnose_ex.hxx>
#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;
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(u"com.sun.star.presentation.PresentationDocument"_ustr) )
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, u"filter/ui/testxmlfilter.ui"_ustr, u"TestXMLFilterDialog"_ustr)
, mxContext(rxContext)
, m_xExport(m_xBuilder->weld_widget(u"export"_ustr))
, m_xFTExportXSLTFile(m_xBuilder->weld_label(u"exportxsltfile"_ustr))
, m_xPBExportBrowse(m_xBuilder->weld_button(u"exportbrowse"_ustr))
, m_xPBCurrentDocument(m_xBuilder->weld_button(u"currentdocument"_ustr))
, m_xFTNameOfCurrentFile(m_xBuilder->weld_label(u"currentfilename"_ustr))
, m_xImport(m_xBuilder->weld_widget(u"import"_ustr))
, m_xFTImportXSLTFile(m_xBuilder->weld_label(u"importxsltfile"_ustr))
, m_xFTImportTemplate(m_xBuilder->weld_label(u"templateimport"_ustr))
, m_xFTImportTemplateFile(m_xBuilder->weld_label(u"importxslttemplate"_ustr))
, m_xCBXDisplaySource(m_xBuilder->weld_check_button(u"displaysource"_ustr))
, m_xPBImportBrowse(m_xBuilder->weld_button(u"importbrowse"_ustr))
, m_xPBRecentFile(m_xBuilder->weld_button(u"recentfile"_ustr))
, m_xFTNameOfRecentFile(m_xBuilder->weld_label(u"recentfilename"_ustr))
, m_xPBClose(m_xBuilder->weld_button(u"close"_ustr))
{
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( u"com.sun.star.document.FilterFactory"_ustr, mxContext ), UNO_QUERY );
Reference< XNameAccess > xTypeDetection( mxContext->getServiceManager()->createInstanceWithContext( u"com.sun.star.document.TypeDetection"_ustr, 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 : 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 : 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(u"InteractionHandler"_ustr,
xInter) };
Reference< XComponent > xComp( xLoader->loadComponentFromURL( m_sExportRecentFile, u"_default"_ustr, 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() )
{
utl::TempFileNamed aTempFile(u"", true, u".xml");
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( u"com.sun.star.documentconversion.XSLTFilter"_ustr, 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(u"com.sun.star.document.ExportGraphicStorageHandler"_ustr), UNO_QUERY);
xObjectResolver.set( xDocFac->createInstance(u"com.sun.star.document.ExportEmbeddedObjectResolver"_ustr), 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(
u"FileName"_ustr, 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(u"FilterName"_ustr, m_xFilterInfo->maFilterName),
comphelper::makePropertyValue(u"InteractionHandler"_ustr, xInter)
};
xLoader->loadComponentFromURL( rURL, u"_default"_ustr, 0, aArguments );
if( m_xCBXDisplaySource->get_active() )
{
TempFileNamed aTempFile(u"", true, u".xml");
const OUString& aTempFileURL( aTempFile.GetURL() );
Reference< XImportFilter > xImporter( mxContext->getServiceManager()->createInstanceWithContext( u"com.sun.star.documentconversion.XSLTFilter"_ustr, 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(u"InputStream"_ustr, xIS),
comphelper::makePropertyValue(u"FileName"_ustr, rURL),
comphelper::makePropertyValue(u"Indent"_ustr, 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 = std::move(xTest);
}
else
{
xTest = xDesktop->getCurrentComponent();
if( checkComponent( xTest, rServiceName ) )
{
xRet = std::move(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: */
↑ V547 Expression '(nFlags & 0x1000) == 0' is always true.
↑ V547 Expression '(nFlags & 0x100) == 0x100' is always false.