/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xmlfiltersettingsdialog.hxx" #include "xmlfiltertabdialog.hxx" #include "xmlfiltertestdialog.hxx" #include "xmlfilterjar.hxx" #include 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& 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(pSelectedEntry->GetUserData()); bIsReadonly = pInfo->mbReadonly; for( auto nFact : o3tl::enumrange()) { 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(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(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(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(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(pEntry->GetUserData()); OUString aMessage(XsltResId(STR_WARN_DELETE)); aMessage = aMessage.replaceFirst( "%s", pInfo->maFilterName ); std::unique_ptr 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 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(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 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 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 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(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::Create(this); m_pHeaderBar = VclPtr::Create(m_pVBox, WB_BOTTOMBORDER); m_pHeaderBar->set_height_request(GetTextHeight() + 6); m_pFocusCtrl = VclPtr::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 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(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(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: */