/* -*- 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/util/XFlushable.hpp>
 
#include <com/sun/star/beans/PropertyValue.hpp>
 
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <unotools/resmgr.hxx>
#include <tools/urlobj.hxx>
#include <svtools/headbar.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/pathoptions.hxx>
#include <osl/file.hxx>
#include <o3tl/enumrange.hxx>
#include <vcl/builderfactory.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <sfx2/filedlghelper.hxx>
#include <svtools/treelistentry.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(const char* pId)
{
    return Translate::get(pId, Translate::Create("flt"));
}
 
XMLFilterSettingsDialog::XMLFilterSettingsDialog(vcl::Window* pParent,
    const css::uno::Reference<css::uno::XComponentContext>& rxContext,
    Dialog::InitFlag eFlag)
    : ModelessDialog(pParent, "XMLFilterSettingsDialog", "filter/ui/xmlfiltersettings.ui", eFlag)
    , mxContext( rxContext )
    , m_bIsClosable(true)
    , m_sTemplatePath("$(user)/template/")
    , m_sDocTypePrefix("doctype:")
{
    get(m_pCtrlFilterList, "filterlist");
    get(m_pPBNew, "new");
    get(m_pPBEdit, "edit");
    get(m_pPBTest, "test");
    get(m_pPBDelete, "delete");
    get(m_pPBSave, "save");
    get(m_pPBOpen, "open");
    get(m_pPBClose, "close");
 
    m_pFilterListBox = m_pCtrlFilterList->getListBox();
    m_pFilterListBox->SetSelectHdl( LINK( this, XMLFilterSettingsDialog, SelectionChangedHdl_Impl ) );
    m_pFilterListBox->SetDeselectHdl( LINK( this, XMLFilterSettingsDialog, SelectionChangedHdl_Impl ) );
    m_pFilterListBox->SetDoubleClickHdl( LINK( this, XMLFilterSettingsDialog, DoubleClickHdl_Impl ) );
    m_pFilterListBox->SetAccessibleName(XsltResId(STR_XML_FILTER_LISTBOX));
    m_pFilterListBox->SetHelpId(m_pCtrlFilterList->GetHelpId());
 
    m_pPBNew->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBEdit->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBTest->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBDelete->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBSave->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBOpen->SetClickHdl(LINK( this, XMLFilterSettingsDialog, ClickHdl_Impl ) );
    m_pPBClose->SetClickHdl(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&)
    {
        OSL_FAIL( "XMLFilterSettingsDialog::XMLFilterSettingsDialog exception caught!" );
    }
}
 
XMLFilterSettingsDialog::~XMLFilterSettingsDialog()
{
    disposeOnce();
}
 
void XMLFilterSettingsDialog::dispose()
{
    m_pFilterListBox.clear();
    m_pCtrlFilterList.clear();
    m_pPBNew.clear();
    m_pPBEdit.clear();
    m_pPBTest.clear();
    m_pPBDelete.clear();
    m_pPBSave.clear();
    m_pPBOpen.clear();
    m_pPBClose.clear();
    ModelessDialog::dispose();
}
 
IMPL_LINK(XMLFilterSettingsDialog, ClickHdl_Impl, Button *, pButton, void )
{
    m_bIsClosable = false;
 
    if (m_pPBNew == pButton)
    {
        onNew();
    }
    else if (m_pPBEdit == pButton)
    {
        onEdit();
    }
    else if (m_pPBTest == pButton)
    {
        onTest();
    }
    else if (m_pPBDelete == pButton)
    {
        onDelete();
    }
    else if (m_pPBSave == pButton)
    {
        onSave();
    }
    else if (m_pPBOpen == pButton)
    {
        onOpen();
    }
    else if (m_pPBClose == pButton)
    {
        Close();
    }
 
    m_bIsClosable = true;
}
 
IMPL_LINK_NOARG(XMLFilterSettingsDialog, SelectionChangedHdl_Impl, SvTreeListBox*, void)
{
    updateStates();
}
 
IMPL_LINK_NOARG(XMLFilterSettingsDialog, DoubleClickHdl_Impl, SvTreeListBox*, bool)
{
    onEdit();
    return false;
}
 
short XMLFilterSettingsDialog::Execute()
{
    m_pCtrlFilterList->GrabFocus();
    disposeFilterList();
    m_pFilterListBox->Clear();
    initFilterList();
    updateStates();
 
    return ModelessDialog::Execute();
}
 
void XMLFilterSettingsDialog::updateStates()
{
    SvTreeListEntry* pSelectedEntry = m_pFilterListBox->FirstSelected();
 
    bool bHasSelection = pSelectedEntry != nullptr;
 
    bool bMultiSelection = bHasSelection && (m_pFilterListBox->NextSelected( pSelectedEntry ) != nullptr );
    bool bIsReadonly = false;
    bool bIsDefault = false;
    if(pSelectedEntry)
    {
        filter_info_impl* pInfo = static_cast<filter_info_impl*>(pSelectedEntry->GetUserData());
        bIsReadonly = pInfo->mbReadonly;
 
        for( auto nFact : o3tl::enumrange<SvtModuleOptions::EFactory>())
        {
            OUString sDefault = maModuleOpt.GetFactoryDefaultFilter(nFact);
            if( sDefault == pInfo->maFilterName )
            {
                bIsDefault = true;
                break;
            }
        }
    }
    m_pPBEdit->Enable( bHasSelection && !bMultiSelection && !bIsReadonly);
    m_pPBTest->Enable( bHasSelection && !bMultiSelection );
    m_pPBDelete->Enable( bHasSelection && !bMultiSelection && !bIsReadonly && !bIsDefault);
    m_pPBSave->Enable( 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(GetFrameWeld(), 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 entry
    SvTreeListEntry* pEntry = m_pFilterListBox->FirstSelected();
    if( pEntry )
    {
        // get its filter info
        filter_info_impl* pOldInfo = static_cast<filter_info_impl*>(pEntry->GetUserData());
 
        // execute XML Filter Dialog
        XMLFilterTabDialog aDlg(GetFrameWeld(), 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 );
 
    // 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 )
        {
            aExtensions[i] = rExtensions.copy( nCurrentIndex );
            break;
        }
        else
        {
            aExtensions[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
    {
        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 = aInterfaceName.copy( rInterfaceName.getLength() ).toInt32();
                        if( nNumber >= nDefaultNumber )
                            nDefaultNumber = nNumber + 1;
                    }
                }
            }
        }
    }
    catch( const Exception& )
    {
        OSL_FAIL( "XMLFilterSettingsDialog::createUniqueInterfaceName exception caught!" );
    }
 
    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& )
        {
            OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
            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.GetName().isEmpty() )
            {
                OUString aDestURL( m_sTemplatePath );
                aDestURL += pFilterEntry->maFilterName + "/";
                if( createDirectory( aDestURL ) )
                {
                    aDestURL += aSourceURL.GetName();
 
                    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( 8 );
 
        aFilterData[0].Name = "Type";
        aFilterData[0].Value <<= pFilterEntry->maType;
 
        aFilterData[1].Name = "UIName";
        aFilterData[1].Value <<= pFilterEntry->maInterfaceName;
 
        aFilterData[2].Name = "DocumentService";
        aFilterData[2].Value <<= pFilterEntry->maDocumentService;
 
        aFilterData[3].Name = "FilterService";
        aFilterData[3].Value <<= OUString( "com.sun.star.comp.Writer.XmlFilterAdaptor" );
 
        aFilterData[4].Name = "Flags";
        aFilterData[4].Value <<= pFilterEntry->maFlags;
 
        aFilterData[5].Name = "UserData";
        aFilterData[5].Value <<= aUserData;
 
        aFilterData[6].Name = "FileFormatVersion";
        aFilterData[6].Value <<= pFilterEntry->maFileFormatVersion;
 
        aFilterData[7].Name = "TemplateName";
        aFilterData[7].Value <<= pFilterEntry->maImportTemplate;
 
        // 4. insert new or replace existing filter
        try
        {
            Any aAny( makeAny( aFilterData ) );
            if( mxFilterContainer->hasByName( pFilterEntry->maFilterName ) )
            {
                mxFilterContainer->replaceByName( pFilterEntry->maFilterName, aAny );
            }
            else
            {
                mxFilterContainer->insertByName( pFilterEntry->maFilterName, aAny );
            }
        }
        catch( const Exception& )
        {
            OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
            bOk = false;
        }
    }
 
    // 5. prepare type information
    if( bOk )
    {
        Sequence< PropertyValue > aValues(4);
 
        aValues[0].Name = "UIName";
        aValues[0].Value <<= pFilterEntry->maInterfaceName;
        aValues[1].Name = "ClipboardFormat";
        OUString aDocType;
        if( !pFilterEntry->maDocType.match( m_sDocTypePrefix ) )
        {
            aDocType = m_sDocTypePrefix + pFilterEntry->maDocType;
        }
        else
        {
            aDocType = pFilterEntry->maDocType;
        }
        if (aDocType == m_sDocTypePrefix)
            aValues[1].Value <<= OUString();
        else
            aValues[1].Value <<= aDocType;
 
        aValues[2].Name = "DocumentIconID";
        aValues[2].Value <<= pFilterEntry->mnDocumentIconID;
 
        aValues[3].Name = "Extensions";
        aValues[3].Value <<= 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);
            aValues[4].Name = "DetectService";
            aValues[4].Value <<= OUString( "com.sun.star.comp.filters.XMLFilterDetect" );
        }
 
        // 6. insert new or replace existing type information
        if( mxTypeDetection.is() )
        {
            try
            {
                Any aAny( makeAny( aValues ) );
                if( mxTypeDetection->hasByName( pFilterEntry->maType ) )
                {
                    mxTypeDetection->replaceByName( pFilterEntry->maType, aAny );
                }
                else
                {
                    mxTypeDetection->insertByName( pFilterEntry->maType, aAny );
                }
            }
            catch( const Exception& )
            {
                OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
                bOk = false;
            }
        }
 
        if( bOk )
        {
            try
            {
                Reference< XFlushable > xFlushable( mxTypeDetection, UNO_QUERY );
                if( xFlushable.is() )
                    xFlushable->flush();
            }
            catch( const Exception& )
            {
                OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
                bOk = false;
            }
        }
 
        if( !bOk )
        {
            // we failed to add the type, so lets remove the filter
            try
            {
                mxFilterContainer->removeByName( pFilterEntry->maFilterName );
            }
            catch( const Exception& )
            {
                OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
                bOk = false;
            }
        }
        else
        {
            if( bOk )
            {
                try
                {
                    Reference< XFlushable > xFlushable( mxFilterContainer, UNO_QUERY );
                    if( xFlushable.is() )
                        xFlushable->flush();
                }
                catch( const Exception& )
                {
                    OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
                    bOk = false;
                }
 
                if( !bOk )
                {
                    // we failed to add the filter, so lets remove the type
                    try
                    {
                        mxTypeDetection->removeByName( pFilterEntry->maType );
                    }
                    catch( const Exception& )
                    {
                        OSL_FAIL( "XMLFilterSettingsDialog::insertOrEdit exception caught!" );
                    }
                }
 
            }
        }
    }
 
    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 )
                {
                    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[nStrCount] = pFilterEntry->maType;
 
                                    aSequence[nIndex].Value <<= aTypes;
 
                                    mxExtendedTypeDetection->replaceByName( sFilterDetectService, makeAny( aSequence ) );
 
                                    Reference< XFlushable > xFlushable( mxExtendedTypeDetection, UNO_QUERY );
                                    if( xFlushable.is() )
                                        xFlushable->flush();
                                }
                            }
 
                            break;
                        }
                    }
                }
            }
        }
    }
 
    // update ui
    if( bOk )
    {
        if( pOldInfo )
        {
            m_pFilterListBox->changeEntry( pFilterEntry );
        }
        else
        {
            m_pFilterListBox->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
    SvTreeListEntry* pEntry = m_pFilterListBox->FirstSelected();
    if( pEntry )
    {
        filter_info_impl* pInfo = static_cast<filter_info_impl*>(pEntry->GetUserData());
 
        XMLFilterTestDialog aDlg(GetFrameWeld(), mxContext);
        aDlg.test( *pInfo );
    }
}
 
void XMLFilterSettingsDialog::onDelete()
{
    SvTreeListEntry* pEntry = m_pFilterListBox->FirstSelected();
    if( pEntry )
    {
        filter_info_impl* pInfo = static_cast<filter_info_impl*>(pEntry->GetUserData());
 
        OUString aMessage(XsltResId(STR_WARN_DELETE));
        aMessage = aMessage.replaceFirst( "%s", pInfo->maFilterName );
 
        std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
                                                   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) && !bTypeStillUsed; 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_pFilterListBox->RemoveSelection();
 
                    // 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& )
            {
                OSL_FAIL( "XMLFilterSettingsDialog::onDelete exception caught!" );
            }
        }
    }
 
    updateStates();
}
 
void XMLFilterSettingsDialog::onSave()
{
    XMLFilterVector aFilters;
 
    int nFilters = 0;
 
    SvTreeListEntry* pEntry = m_pFilterListBox->FirstSelected();
    while( pEntry )
    {
        filter_info_impl* pInfo = static_cast<filter_info_impl*>(pEntry->GetUserData());
        aFilters.push_back( pInfo );
        pEntry = m_pFilterListBox->NextSelected( pEntry );
        nFilters++;
    }
 
    // Open Fileopen-Dialog
       ::sfx2::FileDialogHelper aDlg(
        css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
        FileDialogFlags::NONE, GetFrameWeld());
 
    OUString aExtensions( "*.jar" );
    OUString aFilterName(XsltResId(STR_FILTER_PACKAGE));
    aFilterName += " (" + aExtensions + ")";
 
    aDlg.AddFilter( aFilterName, aExtensions );
 
    if ( aDlg.Execute() == ERRCODE_NONE )
    {
        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.GetName() );
        }
        else
        {
            aMsg = XsltResId(STR_FILTER_HAS_BEEN_SAVED);
            aMsg = aMsg.replaceFirst( sPlaceholder, (*aFilters.begin())->maFilterName );
            aMsg = aMsg.replaceFirst( sPlaceholder, aURL.GetName() );
        }
 
        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                      VclMessageType::Info, VclButtonsType::Ok,
                                                      aMsg));
        xInfoBox->run();
    }
}
 
void XMLFilterSettingsDialog::onOpen()
{
    XMLFilterVector aFilters;
 
    // Open Fileopen-Dialog
       ::sfx2::FileDialogHelper aDlg(
        css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
        FileDialogFlags::NONE, GetFrameWeld());
 
    OUString aExtensions( "*.jar" );
    OUString aFilterName(XsltResId(STR_FILTER_PACKAGE));
    aFilterName += " (" + aExtensions + ")";
 
    aDlg.AddFilter( aFilterName, aExtensions );
 
    if ( aDlg.Execute() == ERRCODE_NONE )
    {
        OUString aURL( aDlg.GetPath() );
 
        XMLFilterJarHelper aJarHelper( mxContext );
        aJarHelper.openPackage( aURL, aFilters );
 
        int nFilters = 0;
        for (auto const& filter : aFilters)
        {
            if( insertOrEdit(filter) )
            {
                aFilterName = filter->maFilterName;
                nFilters++;
            }
 
            delete filter;
        }
 
        disposeFilterList();
        initFilterList();
 
        OUString sPlaceholder( "%s" );
        OUString aMsg;
        if( nFilters == 0 )
        {
            INetURLObject aURLObj( aURL );
            aMsg = XsltResId(STR_NO_FILTERS_FOUND);
            aMsg = aMsg.replaceFirst( sPlaceholder, aURLObj.GetName() );
        }
        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(GetFrameWeld(),
                                                      VclMessageType::Info, VclButtonsType::Ok,
                                                      aMsg));
        xInfoBox->run();
    }
}
 
bool XMLFilterSettingsDialog::EventNotify( NotifyEvent& rNEvt )
{
    // Because of tab control first call the base class.
    bool bRet = ModelessDialog::EventNotify(rNEvt);
    if ( !bRet )
    {
        if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
        {
            const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
            vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
            sal_uInt16 nKeyCode = aKeyCode.GetCode();
            bool bMod1 = pKEvt->GetKeyCode().IsMod1();
 
            if( nKeyCode == KEY_ESCAPE || (bMod1 && (nKeyCode == KEY_W)))
            {
                Close();
                return true;
            }
        }
    }
 
    return bRet;
}
 
void XMLFilterSettingsDialog::disposeFilterList()
{
    maFilterVector.clear();
    m_pFilterListBox->Clear();
}
 
void XMLFilterSettingsDialog::initFilterList()
{
    if( mxFilterContainer.is() )
    {
        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()) );
                m_pFilterListBox->addFilterEntry( pTempFilter.release() );
 
 
                pTempFilter.reset( new filter_info_impl );
            }
            catch( const Exception& )
            {
                OSL_FAIL( "XMLFilterSettingsDialog::initFilterList exception caught!" );
            }
 
        }
    }
 
    SvTreeListEntry* pEntry = m_pFilterListBox->GetEntry( 0 );
    if( pEntry )
        m_pFilterListBox->Select( pEntry );
}
 
application_info_impl::application_info_impl( const sal_Char * pDocumentService, const OUString& rUINameRes, const sal_Char * mpXMLImporter, const sal_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* >& getApplicationInfos()
{
    static std::vector< application_info_impl* > aInfos;
 
    if( aInfos.empty() )
    {
        aInfos.push_back( new application_info_impl(
            "com.sun.star.text.TextDocument",
            STR_APPL_NAME_WRITER,
            "com.sun.star.comp.Writer.XMLImporter",
            "com.sun.star.comp.Writer.XMLExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "com.sun.star.sheet.SpreadsheetDocument",
            STR_APPL_NAME_CALC,
            "com.sun.star.comp.Calc.XMLImporter",
            "com.sun.star.comp.Calc.XMLExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "com.sun.star.presentation.PresentationDocument",
            STR_APPL_NAME_IMPRESS,
            "com.sun.star.comp.Impress.XMLImporter",
            "com.sun.star.comp.Impress.XMLExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "com.sun.star.drawing.DrawingDocument",
            STR_APPL_NAME_DRAW,
            "com.sun.star.comp.Draw.XMLImporter",
            "com.sun.star.comp.Draw.XMLExporter" ) );
 
        // --- oasis file formats...
        aInfos.push_back( new application_info_impl(
            "com.sun.star.text.TextDocument",
            STR_APPL_NAME_OASIS_WRITER,
            "com.sun.star.comp.Writer.XMLOasisImporter",
            "com.sun.star.comp.Writer.XMLOasisExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "com.sun.star.sheet.SpreadsheetDocument",
            STR_APPL_NAME_OASIS_CALC,
            "com.sun.star.comp.Calc.XMLOasisImporter",
            "com.sun.star.comp.Calc.XMLOasisExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "com.sun.star.presentation.PresentationDocument",
            STR_APPL_NAME_OASIS_IMPRESS,
            "com.sun.star.comp.Impress.XMLOasisImporter",
            "com.sun.star.comp.Impress.XMLOasisExporter" ) );
 
        aInfos.push_back( new application_info_impl(
            "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( const OUString& rServiceName )
{
    std::vector< application_info_impl* >& rInfos = getApplicationInfos();
    for (auto const& info : rInfos)
    {
        if( rServiceName == info->maXMLExporter ||
            rServiceName == info->maXMLImporter)
        {
            return info;
        }
    }
    return nullptr;
}
 
OUString getApplicationUIName( const OUString& rServiceName )
{
    const application_info_impl* pInfo = getApplicationInfo( rServiceName );
    if( pInfo )
    {
        return pInfo->maDocumentUIName;
    }
    else
    {
        OUString aRet = XsltResId(STR_UNKNOWN_APPLICATION);
        if( !rServiceName.isEmpty() )
        {
            aRet += " (" + rServiceName + ")";
        }
        return aRet;
    }
}
 
SvxPathControl::SvxPathControl(vcl::Window* pParent)
    : Window(pParent, WB_HIDE | WB_CLIPCHILDREN | WB_TABSTOP | WB_DIALOGCONTROL | WB_BORDER)
    , bHasBeenShown(false)
{
    m_pVBox = VclPtr<VclVBox>::Create(this);
 
    m_pHeaderBar = VclPtr<HeaderBar>::Create(m_pVBox, WB_BOTTOMBORDER);
    m_pHeaderBar->set_height_request(GetTextHeight() + 6);
 
    m_pFocusCtrl = VclPtr<XMLFilterListBox>::Create(m_pVBox, this);
    m_pFocusCtrl->set_fill(true);
    m_pFocusCtrl->set_expand(true);
 
    m_pVBox->set_hexpand(true);
    m_pVBox->set_vexpand(true);
    m_pVBox->set_expand(true);
    m_pVBox->set_fill(true);
    m_pVBox->Show();
}
 
#define ITEMID_NAME     1
#define ITEMID_TYPE     2
 
void SvxPathControl::Resize()
{
    Window::Resize();
 
    if (!m_pVBox)
        return;
 
    m_pVBox->SetSizePixel(GetSizePixel());
 
    if (!bHasBeenShown)
        bHasBeenShown = IsReallyShown();
 
    if (!bHasBeenShown)
    {
        std::vector<long> aWidths;
        m_pFocusCtrl->getPreferredDimensions(aWidths);
        if (aWidths.empty())
        {
            bHasBeenShown = false;
            return;
        }
        long nFirstColumnWidth = aWidths[1];
        m_pHeaderBar->SetItemSize(ITEMID_NAME, nFirstColumnWidth);
        m_pHeaderBar->SetItemSize(ITEMID_TYPE, 0xFFFF);
        long nTabs[] = {0, nFirstColumnWidth};
        m_pFocusCtrl->SetTabs(SAL_N_ELEMENTS(nTabs), nTabs, MapUnit::MapPixel);
    }
}
 
Size SvxPathControl::GetOptimalSize() const
{
    Size aDefSize(LogicToPixel(Size(150, 0), MapMode(MapUnit::MapAppFont)));
    Size aOptSize(m_pVBox->GetOptimalSize());
    long nRowHeight(GetTextHeight());
    aOptSize.setHeight( nRowHeight * 10 );
    aOptSize.setWidth( std::max(aDefSize.Width(), aOptSize.Width()) );
    return aOptSize;
}
 
SvxPathControl::~SvxPathControl()
{
    disposeOnce();
}
 
void SvxPathControl::dispose()
{
    m_pFocusCtrl.disposeAndClear();
    m_pHeaderBar.disposeAndClear();
    m_pVBox.disposeAndClear();
    vcl::Window::dispose();
}
 
VCL_BUILDER_FACTORY(SvxPathControl)
 
bool SvxPathControl::EventNotify(NotifyEvent& rNEvt)
{
    bool bRet = Window::EventNotify(rNEvt);
 
    if ( m_pFocusCtrl && rNEvt.GetWindow() != m_pFocusCtrl && rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
        m_pFocusCtrl->GrabFocus();
 
    return bRet;
}
 
XMLFilterListBox::XMLFilterListBox(Window* pParent, SvxPathControl* pPathControl)
    : SvTabListBox(pParent, WB_SORT | WB_HSCROLL | WB_CLIPCHILDREN | WB_TABSTOP)
    , m_pHeaderBar(pPathControl->getHeaderBar())
{
    Size aBoxSize( pParent->GetOutputSizePixel() );
 
    m_pHeaderBar->SetEndDragHdl( LINK( this, XMLFilterListBox, HeaderEndDrag_Impl ) );
 
    OUString aStr1(XsltResId(STR_COLUMN_HEADER_NAME));
    OUString aStr2(XsltResId(STR_COLUMN_HEADER_TYPE));
 
    long nTabSize = aBoxSize.Width() / 2;
 
    m_pHeaderBar->InsertItem( ITEMID_NAME, aStr1, nTabSize,
                            HeaderBarItemBits::LEFT | HeaderBarItemBits::VCENTER );
    m_pHeaderBar->InsertItem( ITEMID_TYPE, aStr2, nTabSize,
                            HeaderBarItemBits::LEFT | HeaderBarItemBits::VCENTER );
 
    static long nTabs[] = {0, nTabSize };
 
    SetSelectionMode( SelectionMode::Multiple );
    SetTabs( SAL_N_ELEMENTS(nTabs), nTabs, MapUnit::MapPixel );
    SetScrolledHdl( LINK( this, XMLFilterListBox, TabBoxScrollHdl_Impl ) );
    SetHighlightRange();
    Show();
    m_pHeaderBar->Show();
}
 
XMLFilterListBox::~XMLFilterListBox()
{
    disposeOnce();
}
 
void XMLFilterListBox::dispose()
{
    m_pHeaderBar.clear();
    SvTabListBox::dispose();
}
 
IMPL_LINK_NOARG( XMLFilterListBox, TabBoxScrollHdl_Impl, SvTreeListBox*, void )
{
    m_pHeaderBar->SetOffset( -GetXOffset() );
}
 
IMPL_LINK( XMLFilterListBox, HeaderEndDrag_Impl, HeaderBar*, pBar, void )
{
    if ( pBar && !pBar->GetCurItemId() )
        return;
 
    if ( !m_pHeaderBar->IsItemMode() )
    {
        Size aSz;
        sal_uInt16 nTabs = m_pHeaderBar->GetItemCount();
        long nTmpSz = 0;
        long nWidth = m_pHeaderBar->GetItemSize(ITEMID_NAME);
        long nBarWidth = m_pHeaderBar->GetSizePixel().Width();
 
        if(nWidth < 30)
            m_pHeaderBar->SetItemSize( ITEMID_TYPE, 30);
        else if ( ( nBarWidth - nWidth ) < 30 )
            m_pHeaderBar->SetItemSize( ITEMID_TYPE, nBarWidth - 30 );
 
        for ( sal_uInt16 i = 1; i <= nTabs; ++i )
        {
            long nW = m_pHeaderBar->GetItemSize(i);
            aSz.setWidth(  nW + nTmpSz );
            nTmpSz += nW;
            SetTab( i, PixelToLogic( aSz, MapMode(MapUnit::MapAppFont) ).Width() );
        }
    }
}
 
/** adds a new filter info entry to the ui filter list */
void XMLFilterListBox::addFilterEntry( const filter_info_impl* pInfo )
{
    const OUString aEntryStr( getEntryString( pInfo ) );
    InsertEntryToColumn( aEntryStr, TREELIST_APPEND, 0xffff, const_cast<filter_info_impl *>(pInfo) );
}
 
void XMLFilterListBox::changeEntry( const filter_info_impl* pInfo )
{
    const sal_uLong nCount = GetEntryCount();
    sal_uLong nPos;
    for( nPos = 0; nPos < nCount; nPos++ )
    {
        SvTreeListEntry* pEntry = GetEntry( nPos );
        if( static_cast<filter_info_impl*>(pEntry->GetUserData()) == pInfo )
        {
            OUString aEntryText( getEntryString( pInfo ) );
            SetEntryText( aEntryText, pEntry );
            break;
        }
    }
}
 
OUString XMLFilterListBox::getEntryString( const filter_info_impl* pInfo )
{
    OUString aEntryStr( pInfo->maFilterName + "\t");
    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
{
    Sequence< OUString > aUserData(8);
 
    aUserData[0] = "com.sun.star.documentconversion.XSLTFilter";
    aUserData[1] = OUString::boolean( mbNeedsXSLT2 );
    aUserData[2] = maImportService;
    aUserData[3] = maExportService;
    aUserData[4] = maImportXSLT;
    aUserData[5] = maExportXSLT;
    aUserData[7] = maComment;
 
    return aUserData;
}
 
OUString string_encode( const OUString & rText )
{
    static sal_Bool const uricNoSlash[] = {
        false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false,
        false,  true, false, false,  true, false,  true,  true,  //  !"#$%&'
         true,  true,  true,  true, false,  true,  true, false,  // ()*+,-./
         true,  true,  true,  true,  true,  true,  true,  true,  // 01234567
         true,  true,  true, false, false,  true, false,  true,  // 89:;<=>?
         true,  true,  true,  true,  true,  true,  true,  true,  // @ABCDEFG
         true,  true,  true,  true,  true,  true,  true,  true,  // HIJKLMNO
         true,  true,  true,  true,  true,  true,  true,  true,  // PQRSTUVW
         true,  true,  true, false, false, false, false,  true,  // XYZ[\]^_
        false,  true,  true,  true,  true,  true,  true,  true,  // `abcdefg
         true,  true,  true,  true,  true,  true,  true,  true,  // hijklmno
         true,  true,  true,  true,  true,  true,  true,  true,  // pqrstuvw
         true,  true,  true, false, false, false,  true, false}; // xyz{|}~
 
 
    return Uri::encode( rText, uricNoSlash, 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&)
    {
        OSL_FAIL( "copyStreams() exception caught!" );
    }
 
    return false;
}
 
bool createDirectory( OUString const & rURL )
{
    sal_Int32 nLastIndex = sizeof( "file:///" ) - 2;
    while( nLastIndex != -1 )
    {
        nLastIndex = rURL.indexOf( '/', nLastIndex + 1);
        if( nLastIndex != -1 )
        {
            OUString aDirURL( rURL.copy( 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: */

V547 Expression 'bOk' is always true.

V560 A part of conditional expression is always true: !bTypeStillUsed.