1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/XPropertySet.hpp>
21 #include <com/sun/star/util/XFlushable.hpp>
22 #include <com/sun/star/uno/XComponentContext.hpp>
24 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
28 #include <comphelper/propertyvalue.hxx>
29 #include <o3tl/string_view.hxx>
30 #include <comphelper/diagnose_ex.hxx>
31 #include <tools/urlobj.hxx>
32 #include <unotools/pathoptions.hxx>
33 #include <unotools/streamwrap.hxx>
34 #include <osl/file.hxx>
35 #include <o3tl/enumrange.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/weld.hxx>
38 #include <sfx2/filedlghelper.hxx>
39 #include <tools/stream.hxx>
41 #include <rtl/uri.hxx>
46 #include <strings.hrc>
47 #include "xmlfiltersettingsdialog.hxx"
48 #include "xmlfiltertabdialog.hxx"
49 #include "xmlfiltertestdialog.hxx"
50 #include "xmlfilterjar.hxx"
51 #include <strings.hxx>
54 using namespace com::sun::star::lang
;
55 using namespace com::sun::star::uno
;
56 using namespace com::sun::star::io
;
57 using namespace com::sun::star::container
;
58 using namespace com::sun::star::beans
;
59 using namespace com::sun::star::util
;
63 XMLFilterSettingsDialog::XMLFilterSettingsDialog(weld::Window
* pParent
,
64 const css::uno::Reference
<css::uno::XComponentContext
>& rxContext
)
65 : GenericDialogController(pParent
, "filter/ui/xmlfiltersettings.ui", "XMLFilterSettingsDialog")
66 , mxContext( rxContext
)
67 , m_sTemplatePath("$(user)/template/")
68 , m_sDocTypePrefix("doctype:")
69 , m_xPBNew(m_xBuilder
->weld_button("new"))
70 , m_xPBEdit(m_xBuilder
->weld_button("edit"))
71 , m_xPBTest(m_xBuilder
->weld_button("test"))
72 , m_xPBDelete(m_xBuilder
->weld_button("delete"))
73 , m_xPBSave(m_xBuilder
->weld_button("save"))
74 , m_xPBOpen(m_xBuilder
->weld_button("open"))
75 , m_xPBClose(m_xBuilder
->weld_button("close"))
76 , m_xFilterListBox(m_xBuilder
->weld_tree_view("filterlist"))
78 m_xFilterListBox
->set_selection_mode(SelectionMode::Multiple
);
80 m_xFilterListBox
->set_size_request(m_xFilterListBox
->get_approximate_digit_width() * 65,
81 m_xFilterListBox
->get_height_rows(12));
83 m_xFilterListBox
->connect_changed( LINK( this, XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
) );
84 m_xFilterListBox
->connect_row_activated( LINK( this, XMLFilterSettingsDialog
, DoubleClickHdl_Impl
) );
85 m_xFilterListBox
->set_accessible_name(FilterResId(STR_XML_FILTER_LISTBOX
));
87 m_xPBNew
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
88 m_xPBEdit
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
89 m_xPBTest
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
90 m_xPBDelete
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
91 m_xPBSave
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
92 m_xPBOpen
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
93 m_xPBClose
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
97 mxFilterContainer
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", rxContext
), UNO_QUERY
);
98 mxTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", rxContext
), UNO_QUERY
);
99 mxExtendedTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.ExtendedTypeDetectionFactory", rxContext
), UNO_QUERY
);
101 SvtPathOptions aOptions
;
102 m_sTemplatePath
= aOptions
.SubstituteVariable( m_sTemplatePath
);
104 catch(const Exception
&)
106 TOOLS_WARN_EXCEPTION("filter.xslt", "");
110 XMLFilterSettingsDialog::~XMLFilterSettingsDialog()
114 IMPL_LINK(XMLFilterSettingsDialog
, ClickHdl_Impl
, weld::Button
&, rButton
, void)
116 // tdf#122171 block closing libreoffice until the following dialog is dismissed
119 if (m_xPBNew
.get() == &rButton
)
123 else if (m_xPBEdit
.get() == &rButton
)
127 else if (m_xPBTest
.get() == &rButton
)
131 else if (m_xPBDelete
.get() == &rButton
)
135 else if (m_xPBSave
.get() == &rButton
)
139 else if (m_xPBOpen
.get() == &rButton
)
146 if (m_xPBClose
.get() == &rButton
)
147 m_xDialog
->response(RET_CLOSE
);
150 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
, weld::TreeView
&, void)
155 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, DoubleClickHdl_Impl
, weld::TreeView
&, bool)
161 void XMLFilterSettingsDialog::UpdateWindow()
163 m_xFilterListBox
->grab_focus();
165 m_xFilterListBox
->clear();
170 void XMLFilterSettingsDialog::updateStates()
172 std::vector
<int> aRows
= m_xFilterListBox
->get_selected_rows();
174 bool bHasSelection
= !aRows
.empty();
176 bool bMultiSelection
= aRows
.size() > 1;
177 bool bIsReadonly
= false;
178 bool bIsDefault
= false;
181 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(aRows
[0]));
182 bIsReadonly
= pInfo
->mbReadonly
;
184 for( auto nFact
: o3tl::enumrange
<SvtModuleOptions::EFactory
>())
186 OUString sDefault
= maModuleOpt
.GetFactoryDefaultFilter(nFact
);
187 if( sDefault
== pInfo
->maFilterName
)
194 m_xPBEdit
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
);
195 m_xPBTest
->set_sensitive( bHasSelection
&& !bMultiSelection
);
196 m_xPBDelete
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
&& !bIsDefault
);
197 m_xPBSave
->set_sensitive( bHasSelection
);
200 /** is called when the user clicks on the "New" button */
201 void XMLFilterSettingsDialog::onNew()
203 filter_info_impl aTempInfo
;
205 // create a unique filter name
206 aTempInfo
.maFilterName
= createUniqueFilterName(FilterResId(STR_DEFAULT_FILTER_NAME
));
208 // init default extension
209 aTempInfo
.maExtension
= STR_DEFAULT_EXTENSION
;
211 // set default ui name
212 aTempInfo
.maInterfaceName
= createUniqueInterfaceName(FilterResId(STR_DEFAULT_UI_NAME
));
214 // set default application
215 aTempInfo
.maDocumentService
= "com.sun.star.text.TextDocument";
217 // execute XML Filter Dialog
218 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, &aTempInfo
);
219 if (aDlg
.run() == RET_OK
)
221 // insert the new filter
222 insertOrEdit( aDlg
.getNewFilterInfo() );
226 /** is called when the user clicks on the "Edit" Button */
227 void XMLFilterSettingsDialog::onEdit()
229 // get selected filter info
230 filter_info_impl
* pOldInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_selected_id());
234 // execute XML Filter Dialog
235 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, pOldInfo
);
236 if (aDlg
.run() == RET_OK
)
238 filter_info_impl
* pNewInfo
= aDlg
.getNewFilterInfo();
240 if( !(*pOldInfo
== *pNewInfo
) )
243 insertOrEdit( pNewInfo
, pOldInfo
);
248 /** helper to create a sequence of strings from an extensions strings
249 "ext1;ext2;ext3" will become { "ext1", "ext2", "ext3" } */
250 static Sequence
< OUString
> createExtensionsSequence( const OUString
& rExtensions
)
252 // first count how many extensions we have inside the string
255 int nLength
= rExtensions
.getLength();
258 // a non empty string has at least one extension
261 // now count the delimiters ';'
262 const sal_Unicode
* pString
= rExtensions
.getStr();
264 for( i
= 0; i
< nLength
; i
++, pString
++ )
266 if( *pString
== ';' )
271 Sequence
< OUString
> aExtensions( nExtensions
);
272 auto aExtensionsRange
= asNonConstRange(aExtensions
);
274 // extract the extensions from the source string and fill the sequence
277 int nCurrentIndex
= 0;
280 for( i
= 0; i
< nExtensions
; i
++ )
282 nLastIndex
= rExtensions
.indexOf( ';', nLastIndex
);
284 if( nLastIndex
== -1 )
286 aExtensionsRange
[i
] = rExtensions
.copy( nCurrentIndex
);
291 aExtensionsRange
[i
] = rExtensions
.copy( nCurrentIndex
, nLastIndex
- nCurrentIndex
);
292 nCurrentIndex
= nLastIndex
+ 1;
293 nLastIndex
= nCurrentIndex
;
300 /** checks if the given name is unique inside the filter factory. If not,
301 numbers are added until the returned name is unique */
302 OUString
XMLFilterSettingsDialog::createUniqueFilterName( const OUString
& rFilterName
)
304 OUString
aFilterName( rFilterName
);
308 while( mxFilterContainer
->hasByName( aFilterName
) )
310 aFilterName
= rFilterName
+ " " + OUString::number( nId
++ );
316 /** checks if the given name is unique inside the type detection. If not,
317 numbers are added until the returned name is unique */
318 OUString
XMLFilterSettingsDialog::createUniqueTypeName( const OUString
& rTypeName
)
320 OUString
aTypeName( rTypeName
);
324 while( mxFilterContainer
->hasByName( aTypeName
) )
326 aTypeName
= rTypeName
+ " " + OUString::number( nId
++ );
332 /** checks if the given name is a unique ui name inside the filter factory. If not,
333 numbers are added until the returned name is unique */
334 OUString
XMLFilterSettingsDialog::createUniqueInterfaceName( const OUString
& rInterfaceName
)
336 sal_Int32 nDefaultNumber
= 0;
340 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
342 Sequence
< PropertyValue
> aValues
;
343 for( OUString
const & filterName
: aFilterNames
)
345 Any
aAny( mxFilterContainer
->getByName( filterName
) );
346 if( !(aAny
>>= aValues
) )
349 const sal_Int32
nValueCount( aValues
.getLength() );
350 PropertyValue
* pValues
= aValues
.getArray();
353 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
355 if ( pValues
->Name
== "UIName" )
357 OUString aInterfaceName
;
358 pValues
->Value
>>= aInterfaceName
;
361 // see if this filter matches our default filter name
362 if( aInterfaceName
.match( rInterfaceName
) )
364 // if yes, make sure we generate a unique name with a higher number
365 // this is dump but fast
366 sal_Int32 nNumber
= o3tl::toInt32(aInterfaceName
.subView( rInterfaceName
.getLength() ));
367 if( nNumber
>= nDefaultNumber
)
368 nDefaultNumber
= nNumber
+ 1;
374 catch( const Exception
& )
376 TOOLS_WARN_EXCEPTION("filter.xslt", "");
379 OUString
aInterfaceName( rInterfaceName
);
382 aInterfaceName
+= " " + OUString::number( nDefaultNumber
);
385 return aInterfaceName
;
388 /** inserts a new filter into the ui and configuration if pOldInfo is NULL.
389 If pOldInfo is not null, the old filter will be replaced with the new settings */
390 bool XMLFilterSettingsDialog::insertOrEdit( filter_info_impl
* pNewInfo
, const filter_info_impl
* pOldInfo
)
396 // see if we need to update the type name
397 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
399 if( pOldInfo
->maType
== pOldInfo
->maFilterName
)
401 pNewInfo
->maType
.clear();
405 // see if we need to clean up old stuff first
408 // if filter name changed, we need to remove the old filter first
409 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
410 mxFilterContainer
->removeByName( pOldInfo
->maFilterName
);
412 // if type name changed, we need to remove the old type first
413 if( pOldInfo
->maType
!= pNewInfo
->maType
)
414 mxTypeDetection
->removeByName( pOldInfo
->maType
);
416 catch( const Exception
& )
418 TOOLS_WARN_EXCEPTION("filter.xslt", "");
423 filter_info_impl
* pFilterEntry( nullptr );
427 // create or copy filter info
430 // change existing filter entry in filter list box
431 pFilterEntry
= const_cast<filter_info_impl
*>(pOldInfo
);
432 *pFilterEntry
= *pNewInfo
;
436 // add new entry to filter list box
437 pFilterEntry
= new filter_info_impl( *pNewInfo
);
441 // check if we need to copy the template
442 if( bOk
&& !pFilterEntry
->maImportTemplate
.isEmpty() )
444 if( !pFilterEntry
->maImportTemplate
.matchIgnoreAsciiCase( m_sTemplatePath
) )
446 INetURLObject
aSourceURL( pFilterEntry
->maImportTemplate
);
447 if (!aSourceURL
.GetLastName().isEmpty())
449 OUString aDestURL
= m_sTemplatePath
+ pFilterEntry
->maFilterName
+ "/";
450 if( createDirectory( aDestURL
) )
452 aDestURL
+= aSourceURL
.GetLastName();
454 SvFileStream
aInputStream(pFilterEntry
->maImportTemplate
, StreamMode::READ
);
455 Reference
< XInputStream
> xIS( new utl::OInputStreamWrapper( aInputStream
) );
456 SvFileStream
aOutputStream(aDestURL
, StreamMode::WRITE
);
457 Reference
< XOutputStream
> xOS( new utl::OOutputStreamWrapper( aOutputStream
) );
459 if( copyStreams( xIS
, xOS
) )
460 pFilterEntry
->maImportTemplate
= aDestURL
;
468 if( pFilterEntry
->maType
.isEmpty() )
470 pFilterEntry
->maType
= createUniqueTypeName( pNewInfo
->maFilterName
);
473 // update import/export flags
474 if( !pFilterEntry
->maImportXSLT
.isEmpty() )
476 pFilterEntry
->maFlags
|= 1;
480 pFilterEntry
->maFlags
&= ~1;
483 if( !pFilterEntry
->maExportXSLT
.isEmpty() )
485 pFilterEntry
->maFlags
|= 2;
489 pFilterEntry
->maFlags
&= ~2;
491 pFilterEntry
->maFlags
|= 0x80040;
493 // 2. create user data for filter entry
494 Sequence
< OUString
> aUserData( pFilterEntry
->getFilterUserData());
496 // 3. create property values for filter entry
497 Sequence
< PropertyValue
> aFilterData
{
498 comphelper::makePropertyValue("Type", pFilterEntry
->maType
),
499 comphelper::makePropertyValue("UIName", pFilterEntry
->maInterfaceName
),
500 comphelper::makePropertyValue("DocumentService", pFilterEntry
->maDocumentService
),
501 comphelper::makePropertyValue("FilterService", OUString( "com.sun.star.comp.Writer.XmlFilterAdaptor" )),
502 comphelper::makePropertyValue("Flags", pFilterEntry
->maFlags
),
503 comphelper::makePropertyValue("UserData", aUserData
),
504 comphelper::makePropertyValue("FileFormatVersion", pFilterEntry
->maFileFormatVersion
),
505 comphelper::makePropertyValue("TemplateName", pFilterEntry
->maImportTemplate
)
508 // 4. insert new or replace existing filter
511 Any
aAny( aFilterData
);
512 if( mxFilterContainer
->hasByName( pFilterEntry
->maFilterName
) )
514 mxFilterContainer
->replaceByName( pFilterEntry
->maFilterName
, aAny
);
518 mxFilterContainer
->insertByName( pFilterEntry
->maFilterName
, aAny
);
521 catch( const Exception
& )
523 TOOLS_WARN_EXCEPTION("filter.xslt", "");
528 // 5. prepare type information
532 if( !pFilterEntry
->maDocType
.match( m_sDocTypePrefix
) )
534 aDocType
= m_sDocTypePrefix
+ pFilterEntry
->maDocType
;
538 aDocType
= pFilterEntry
->maDocType
;
540 if (aDocType
== m_sDocTypePrefix
)
543 Sequence
< PropertyValue
> aValues
{
544 comphelper::makePropertyValue("UIName", pFilterEntry
->maInterfaceName
),
545 comphelper::makePropertyValue("ClipboardFormat", aDocType
),
546 comphelper::makePropertyValue("DocumentIconID", pFilterEntry
->mnDocumentIconID
),
547 comphelper::makePropertyValue("Extensions", createExtensionsSequence( pFilterEntry
->maExtension
))
550 // the detect service will only be registered, if a doctype/search token was specified
551 if (aDocType
.getLength() > m_sDocTypePrefix
.getLength())
554 auto pValues
= aValues
.getArray();
555 pValues
[4].Name
= "DetectService";
556 pValues
[4].Value
<<= OUString( "com.sun.star.comp.filters.XMLFilterDetect" );
559 // 6. insert new or replace existing type information
560 if( mxTypeDetection
.is() )
565 if( mxTypeDetection
->hasByName( pFilterEntry
->maType
) )
567 mxTypeDetection
->replaceByName( pFilterEntry
->maType
, aAny
);
571 mxTypeDetection
->insertByName( pFilterEntry
->maType
, aAny
);
574 catch( const Exception
& )
576 TOOLS_WARN_EXCEPTION("filter.xslt", "");
585 Reference
< XFlushable
> xFlushable( mxTypeDetection
, UNO_QUERY
);
586 if( xFlushable
.is() )
589 catch( const Exception
& )
591 TOOLS_WARN_EXCEPTION("filter.xslt", "");
598 // we failed to add the type, so lets remove the filter
601 mxFilterContainer
->removeByName( pFilterEntry
->maFilterName
);
603 catch( const Exception
& )
605 TOOLS_WARN_EXCEPTION("filter.xslt", "");
613 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
614 if( xFlushable
.is() )
617 catch( const Exception
& )
619 TOOLS_WARN_EXCEPTION("filter.xslt", "");
625 // we failed to add the filter, so lets remove the type
628 mxTypeDetection
->removeByName( pFilterEntry
->maType
);
630 catch( const Exception
& )
632 TOOLS_WARN_EXCEPTION("filter.xslt", "");
641 if( mxExtendedTypeDetection
.is() )
643 OUString
sFilterDetectService( "com.sun.star.comp.filters.XMLFilterDetect" );
644 if( mxExtendedTypeDetection
->hasByName( sFilterDetectService
) )
646 Sequence
< PropertyValue
> aSequence
;
647 if( mxExtendedTypeDetection
->getByName( sFilterDetectService
) >>= aSequence
)
649 auto aSequenceRange
= asNonConstRange(aSequence
);
650 sal_Int32 nCount
= aSequence
.getLength();
652 for( nIndex
= 0; nIndex
< nCount
; nIndex
++ )
654 if ( aSequence
[nIndex
].Name
== "Types" )
656 Sequence
< OUString
> aTypes
;
657 if( aSequence
[nIndex
].Value
>>= aTypes
)
659 sal_Int32 nStrCount
= aTypes
.getLength();
661 for( nStr
= 0; nStr
< nStrCount
; nStr
++ )
663 if( aTypes
[nStr
] == pFilterEntry
->maType
)
667 if( nStr
== nStrCount
)
669 aTypes
.realloc( nStrCount
+ 1 );
670 aTypes
.getArray()[nStrCount
] = pFilterEntry
->maType
;
672 aSequenceRange
[nIndex
].Value
<<= aTypes
;
674 mxExtendedTypeDetection
->replaceByName( sFilterDetectService
, Any( aSequence
) );
676 Reference
< XFlushable
> xFlushable( mxExtendedTypeDetection
, UNO_QUERY
);
677 if( xFlushable
.is() )
695 changeEntry( pFilterEntry
);
699 addFilterEntry( pFilterEntry
);
700 maFilterVector
.push_back( std::unique_ptr
<filter_info_impl
>(pFilterEntry
) );
707 /** is called when the user clicks the "Test" button */
708 void XMLFilterSettingsDialog::onTest()
710 // get the first selected filter
711 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_selected_id());
714 XMLFilterTestDialog
aDlg(m_xDialog
.get(), mxContext
);
719 void XMLFilterSettingsDialog::onDelete()
721 int nIndex
= m_xFilterListBox
->get_selected_index();
724 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(nIndex
));
727 OUString
aMessage(FilterResId(STR_WARN_DELETE
));
728 aMessage
= aMessage
.replaceFirst( "%s", pInfo
->maFilterName
);
730 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(m_xDialog
.get(),
731 VclMessageType::Warning
, VclButtonsType::YesNo
,
733 xWarn
->set_default_response(RET_YES
);
734 if (xWarn
->run() == RET_YES
)
738 if( mxFilterContainer
->hasByName( pInfo
->maFilterName
) )
740 mxFilterContainer
->removeByName( pInfo
->maFilterName
);
742 bool bTypeStillUsed
= false;
744 // now loop over all filter and see if someone else uses the same type
745 Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
746 OUString
* pFilterName
= aFilterNames
.getArray();
748 const sal_Int32 nCount
= aFilterNames
.getLength();
750 Sequence
< PropertyValue
> aValues
;
752 for( nFilter
= 0; (nFilter
< nCount
) && !bTypeStillUsed
; nFilter
++, pFilterName
++ )
754 Any
aAny( mxFilterContainer
->getByName( *pFilterName
) );
755 if( !(aAny
>>= aValues
) )
758 const sal_Int32
nValueCount( aValues
.getLength() );
759 PropertyValue
* pValues
= aValues
.getArray();
762 for (nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++)
764 if ( pValues
->Name
== "Type" )
767 pValues
->Value
>>= aType
;
768 if( aType
== pInfo
->maType
)
769 bTypeStillUsed
= true;
776 // if the type is not used anymore, remove it also
777 if( !bTypeStillUsed
)
779 if( mxTypeDetection
->hasByName( pInfo
->maType
) )
781 mxTypeDetection
->removeByName( pInfo
->maType
);
785 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
786 if( xFlushable
.is() )
789 xFlushable
.set( mxTypeDetection
, UNO_QUERY
);
790 if( xFlushable
.is() )
793 // now remove entry from ui
794 m_xFilterListBox
->remove(nIndex
);
796 // and delete the filter entry
797 maFilterVector
.erase(std::find_if( maFilterVector
.begin(), maFilterVector
.end(),
798 [&] (std::unique_ptr
<filter_info_impl
> const & p
)
799 { return p
.get() == pInfo
; }));
802 catch( const Exception
& )
804 TOOLS_WARN_EXCEPTION("filter.xslt", "");
812 void XMLFilterSettingsDialog::onSave()
814 std::vector
<filter_info_impl
*> aFilters
;
818 m_xFilterListBox
->selected_foreach([&](weld::TreeIter
& rEntry
){
819 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(rEntry
));
820 aFilters
.push_back(pInfo
);
825 // Open Fileopen-Dialog
826 ::sfx2::FileDialogHelper
aDlg(
827 css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
,
828 FileDialogFlags::NONE
, m_xDialog
.get());
829 aDlg
.SetContext(sfx2::FileDialogHelper::XMLFilterSettings
);
831 OUString
aExtensions( "*.jar" );
832 OUString aFilterName
= FilterResId(STR_FILTER_PACKAGE
) +
833 " (" + aExtensions
+ ")";
835 aDlg
.AddFilter( aFilterName
, aExtensions
);
837 if ( aDlg
.Execute() != ERRCODE_NONE
)
840 XMLFilterJarHelper
aJarHelper( mxContext
);
841 aJarHelper
.savePackage( aDlg
.GetPath(), aFilters
);
843 INetURLObject
aURL( aDlg
.GetPath() );
845 OUString
sPlaceholder( "%s" );
850 aMsg
= FilterResId(STR_FILTERS_HAVE_BEEN_SAVED
);
851 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
852 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
856 aMsg
= FilterResId(STR_FILTER_HAS_BEEN_SAVED
);
857 aMsg
= aMsg
.replaceFirst( sPlaceholder
, (*aFilters
.begin())->maFilterName
);
858 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
861 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
862 VclMessageType::Info
, VclButtonsType::Ok
,
867 void XMLFilterSettingsDialog::onOpen()
869 std::vector
< std::unique_ptr
<filter_info_impl
> > aFilters
;
871 // Open Fileopen-Dialog
872 ::sfx2::FileDialogHelper
aDlg(
873 css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
874 FileDialogFlags::NONE
, m_xDialog
.get());
875 aDlg
.SetContext(sfx2::FileDialogHelper::XMLFilterSettings
);
877 OUString
aExtensions( "*.jar" );
878 OUString aFilterName
= FilterResId(STR_FILTER_PACKAGE
) +
879 " (" + aExtensions
+ ")";
881 aDlg
.AddFilter( aFilterName
, aExtensions
);
883 if ( aDlg
.Execute() != ERRCODE_NONE
)
886 OUString
aURL( aDlg
.GetPath() );
888 XMLFilterJarHelper
aJarHelper( mxContext
);
889 aJarHelper
.openPackage( aURL
, aFilters
);
892 for (auto& filter
: aFilters
)
894 if( insertOrEdit(filter
.get()) )
896 aFilterName
= filter
->maFilterName
;
906 OUString
sPlaceholder( "%s" );
910 INetURLObject
aURLObj( aURL
);
911 aMsg
= FilterResId(STR_NO_FILTERS_FOUND
);
912 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURLObj
.GetLastName());
914 else if( nFilters
== 1 )
916 aMsg
= FilterResId(STR_FILTER_INSTALLED
);
917 aMsg
= aMsg
.replaceFirst( sPlaceholder
, aFilterName
);
922 aMsg
= FilterResId(STR_FILTERS_INSTALLED
);
923 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
926 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
927 VclMessageType::Info
, VclButtonsType::Ok
,
932 void XMLFilterSettingsDialog::disposeFilterList()
934 maFilterVector
.clear();
935 m_xFilterListBox
->clear();
938 void XMLFilterSettingsDialog::initFilterList()
940 if( mxFilterContainer
.is() )
942 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
944 Sequence
< PropertyValue
> aValues
;
946 std::unique_ptr
<filter_info_impl
> pTempFilter( new filter_info_impl
);
947 Sequence
< OUString
> aUserData
;
949 for( OUString
const & filterName
: aFilterNames
)
951 aUserData
.realloc(0);
955 Any
aAny( mxFilterContainer
->getByName( filterName
) );
956 if( !(aAny
>>= aValues
) )
959 OUString aFilterService
;
960 pTempFilter
->maFilterName
= filterName
;
962 const sal_Int32
nValueCount( aValues
.getLength() );
963 PropertyValue
* pValues
= aValues
.getArray();
966 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
968 if ( pValues
->Name
== "Type" )
970 pValues
->Value
>>= pTempFilter
->maType
;
972 else if ( pValues
->Name
== "UIName" )
974 pValues
->Value
>>= pTempFilter
->maInterfaceName
;
976 else if ( pValues
->Name
== "DocumentService" )
978 pValues
->Value
>>= pTempFilter
->maDocumentService
;
980 else if ( pValues
->Name
== "FilterService" )
982 pValues
->Value
>>= aFilterService
;
984 else if ( pValues
->Name
== "Flags" )
986 pValues
->Value
>>= pTempFilter
->maFlags
;
988 else if ( pValues
->Name
== "UserData" )
990 pValues
->Value
>>= aUserData
;
992 else if ( pValues
->Name
== "FileFormatVersion" )
994 pValues
->Value
>>= pTempFilter
->maFileFormatVersion
;
996 else if ( pValues
->Name
== "TemplateName" )
998 pValues
->Value
>>= pTempFilter
->maImportTemplate
;
1000 else if ( pValues
->Name
== "Finalized" )
1002 pValues
->Value
>>= pTempFilter
->mbReadonly
;
1006 // if this is not a XmlFilterAdaptor entry, skip it
1007 if( aFilterService
!= "com.sun.star.comp.Writer.XmlFilterAdaptor" )
1011 // if we don't have the needed user data, skip it
1012 if( aUserData
.getLength() < 6 )
1015 // if this is not an XSLTFilter entry, skip it
1016 if( aUserData
[0] != "com.sun.star.documentconversion.XSLTFilter" )
1019 // get filter information from userdata
1020 pTempFilter
->mbNeedsXSLT2
= aUserData
[1].toBoolean();
1021 pTempFilter
->maImportService
= aUserData
[2];
1022 pTempFilter
->maExportService
= aUserData
[3];
1023 pTempFilter
->maImportXSLT
= aUserData
[4];
1024 pTempFilter
->maExportXSLT
= aUserData
[5];
1025 if( aUserData
.getLength() >= 8 )
1026 pTempFilter
->maComment
= aUserData
[7];
1028 // get type information
1029 if( mxTypeDetection
.is() )
1033 aAny
= mxTypeDetection
->getByName( pTempFilter
->maType
);
1034 Sequence
< PropertyValue
> aValues2
;
1036 if( aAny
>>= aValues2
)
1038 const sal_Int32
nValueCount2( aValues2
.getLength() );
1039 PropertyValue
* pValues2
= aValues2
.getArray();
1042 for( nValue2
= 0; nValue2
< nValueCount2
; nValue2
++, pValues2
++ )
1044 if ( pValues2
->Name
== "ClipboardFormat" )
1047 pValues2
->Value
>>= aDocType
;
1049 if( aDocType
.match( m_sDocTypePrefix
) )
1050 aDocType
= aDocType
.copy( m_sDocTypePrefix
.getLength() );
1052 pTempFilter
->maDocType
= aDocType
;
1054 else if ( pValues2
->Name
== "Extensions" )
1056 Sequence
< OUString
> aExtensions
;
1057 if( pValues2
->Value
>>= aExtensions
)
1059 pTempFilter
->maExtension
.clear();
1061 sal_Int32
nCount3( aExtensions
.getLength() );
1062 OUString
* pExtensions
= aExtensions
.getArray();
1064 for( n
= 0; n
< nCount3
; n
++ )
1067 pTempFilter
->maExtension
+= ";";
1068 pTempFilter
->maExtension
+= *pExtensions
++;
1072 else if ( pValues2
->Name
== "DocumentIconID" )
1074 pValues2
->Value
>>= pTempFilter
->mnDocumentIconID
;
1076 else if ( pValues2
->Name
== "Finalized" )
1078 // both the filter and the type may be finalized
1080 pValues2
->Value
>>= bTemp
;
1081 pTempFilter
->mbReadonly
|= bTemp
;
1086 catch( const css::container::NoSuchElementException
& )
1088 OSL_FAIL( "Type not found, user error?" ); // TODO: error?
1092 // add entry to internal container and to ui filter list box
1093 maFilterVector
.push_back( std::unique_ptr
<filter_info_impl
>(pTempFilter
.get()) );
1094 addFilterEntry( pTempFilter
.release() );
1097 pTempFilter
.reset( new filter_info_impl
);
1099 catch( const Exception
& )
1101 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1107 if (m_xFilterListBox
->n_children())
1109 m_xFilterListBox
->columns_autosize();
1110 m_xFilterListBox
->select(0);
1114 application_info_impl::application_info_impl( const char * pDocumentService
, const OUString
& rUINameRes
, const char * mpXMLImporter
, const char * mpXMLExporter
)
1115 : maDocumentService( pDocumentService
, strlen( pDocumentService
), RTL_TEXTENCODING_ASCII_US
),
1116 maDocumentUIName(Translate::ExpandVariables(rUINameRes
)),
1117 maXMLImporter( mpXMLImporter
, strlen( mpXMLImporter
), RTL_TEXTENCODING_ASCII_US
),
1118 maXMLExporter( mpXMLExporter
, strlen( mpXMLExporter
), RTL_TEXTENCODING_ASCII_US
)
1122 std::vector
< application_info_impl
> const & getApplicationInfos()
1124 static std::vector
< application_info_impl
> const aInfos
1126 { "com.sun.star.text.TextDocument",
1127 STR_APPL_NAME_WRITER
,
1128 "com.sun.star.comp.Writer.XMLImporter",
1129 "com.sun.star.comp.Writer.XMLExporter" },
1131 { "com.sun.star.sheet.SpreadsheetDocument",
1133 "com.sun.star.comp.Calc.XMLImporter",
1134 "com.sun.star.comp.Calc.XMLExporter" },
1136 { "com.sun.star.presentation.PresentationDocument",
1137 STR_APPL_NAME_IMPRESS
,
1138 "com.sun.star.comp.Impress.XMLImporter",
1139 "com.sun.star.comp.Impress.XMLExporter" },
1141 { "com.sun.star.drawing.DrawingDocument",
1143 "com.sun.star.comp.Draw.XMLImporter",
1144 "com.sun.star.comp.Draw.XMLExporter" },
1146 // --- oasis file formats...
1147 { "com.sun.star.text.TextDocument",
1148 STR_APPL_NAME_OASIS_WRITER
,
1149 "com.sun.star.comp.Writer.XMLOasisImporter",
1150 "com.sun.star.comp.Writer.XMLOasisExporter" },
1152 { "com.sun.star.sheet.SpreadsheetDocument",
1153 STR_APPL_NAME_OASIS_CALC
,
1154 "com.sun.star.comp.Calc.XMLOasisImporter",
1155 "com.sun.star.comp.Calc.XMLOasisExporter" },
1157 { "com.sun.star.presentation.PresentationDocument",
1158 STR_APPL_NAME_OASIS_IMPRESS
,
1159 "com.sun.star.comp.Impress.XMLOasisImporter",
1160 "com.sun.star.comp.Impress.XMLOasisExporter" },
1162 { "com.sun.star.drawing.DrawingDocument",
1163 STR_APPL_NAME_OASIS_DRAW
,
1164 "com.sun.star.comp.Draw.XMLOasisImporter",
1165 "com.sun.star.comp.Draw.XMLOasisExporter" },
1171 const application_info_impl
* getApplicationInfo( std::u16string_view rServiceName
)
1173 std::vector
< application_info_impl
> const & rInfos
= getApplicationInfos();
1174 for (auto const& info
: rInfos
)
1176 if( rServiceName
== info
.maXMLExporter
||
1177 rServiceName
== info
.maXMLImporter
)
1185 OUString
getApplicationUIName( std::u16string_view rServiceName
)
1187 const application_info_impl
* pInfo
= getApplicationInfo( rServiceName
);
1190 return pInfo
->maDocumentUIName
;
1194 OUString aRet
= FilterResId(STR_UNKNOWN_APPLICATION
);
1195 if( !rServiceName
.empty() )
1197 aRet
+= OUString::Concat(" (") + rServiceName
+ ")";
1203 /** adds a new filter info entry to the ui filter list */
1204 void XMLFilterSettingsDialog::addFilterEntry( const filter_info_impl
* pInfo
)
1206 int nRow
= m_xFilterListBox
->n_children();
1207 OUString
sId(weld::toId(pInfo
));
1208 m_xFilterListBox
->append(sId
, pInfo
->maFilterName
);
1209 m_xFilterListBox
->set_text(nRow
, getEntryString(pInfo
), 1);
1212 void XMLFilterSettingsDialog::changeEntry( const filter_info_impl
* pInfo
)
1214 const int nCount
= m_xFilterListBox
->n_children();
1215 for(int nPos
= 0; nPos
< nCount
; ++nPos
)
1217 filter_info_impl
* pEntry
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(nPos
));
1218 if (pEntry
== pInfo
)
1220 m_xFilterListBox
->set_text(nPos
, pInfo
->maFilterName
, 0);
1221 m_xFilterListBox
->set_text(nPos
, getEntryString(pInfo
), 1);
1227 OUString
XMLFilterSettingsDialog::getEntryString( const filter_info_impl
* pInfo
)
1230 if ( !pInfo
->maExportService
.isEmpty() )
1231 aEntryStr
= getApplicationUIName( pInfo
->maExportService
);
1233 aEntryStr
= getApplicationUIName( pInfo
->maImportService
);
1236 if( pInfo
->maFlags
& 1 )
1238 if( pInfo
->maFlags
& 2 )
1240 aEntryStr
+= FilterResId(STR_IMPORT_EXPORT
);
1244 aEntryStr
+= FilterResId(STR_IMPORT_ONLY
);
1247 else if( pInfo
->maFlags
& 2 )
1249 aEntryStr
+= FilterResId(STR_EXPORT_ONLY
);
1253 aEntryStr
+= FilterResId(STR_UNDEFINED_FILTER
);
1259 filter_info_impl::filter_info_impl()
1260 : maFlags(0x00080040)
1261 , maFileFormatVersion(0)
1262 , mnDocumentIconID(0)
1264 , mbNeedsXSLT2(false)
1268 bool filter_info_impl::operator==( const filter_info_impl
& r
) const
1270 return maFilterName
== r
.maFilterName
&&
1271 maType
== r
.maType
&&
1272 maDocumentService
== r
.maDocumentService
&&
1273 maInterfaceName
== r
.maInterfaceName
&&
1274 maComment
== r
.maComment
&&
1275 maExtension
== r
.maExtension
&&
1276 maDocType
== r
.maDocType
&&
1277 maExportXSLT
== r
.maExportXSLT
&&
1278 maImportXSLT
== r
.maImportXSLT
&&
1279 maExportService
== r
.maExportService
&&
1280 maImportService
== r
.maImportService
&&
1281 maImportTemplate
== r
.maImportTemplate
&&
1282 maFlags
== r
.maFlags
&&
1283 maFileFormatVersion
== r
.maFileFormatVersion
&&
1284 mbNeedsXSLT2
== r
.mbNeedsXSLT2
;
1288 Sequence
< OUString
> filter_info_impl::getFilterUserData() const
1292 "com.sun.star.documentconversion.XSLTFilter",
1293 OUString::boolean( mbNeedsXSLT2
),
1302 OUString
string_encode( const OUString
& rText
)
1304 static constexpr auto uricNoSlash
= rtl::createUriCharClass(
1305 u8
"!$&'()*+-.0123456789:=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~");
1309 Uri::encode( rText
, uricNoSlash
.data(), rtl_UriEncodeCheckEscapes
, RTL_TEXTENCODING_UTF8
);
1312 OUString
string_decode( const OUString
& rText
)
1314 return Uri::decode( rText
, rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
);
1317 bool copyStreams( const Reference
< XInputStream
>& xIS
, const Reference
< XOutputStream
>& xOS
)
1321 sal_Int32 nBufferSize
= 512;
1322 Sequence
< sal_Int8
> aDataBuffer(nBufferSize
);
1327 nRead
= xIS
->readBytes( aDataBuffer
, nBufferSize
);
1331 if( nRead
< nBufferSize
)
1333 nBufferSize
= nRead
;
1334 aDataBuffer
.realloc(nRead
);
1337 xOS
->writeBytes( aDataBuffer
);
1346 catch(const Exception
&)
1348 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1354 bool createDirectory( std::u16string_view rURL
)
1356 size_t nLastIndex
= sizeof( "file:///" ) - 2;
1357 while( nLastIndex
!= std::u16string_view::npos
)
1359 nLastIndex
= rURL
.find( '/', nLastIndex
+ 1);
1360 if( nLastIndex
!= std::u16string_view::npos
)
1362 OUString
aDirURL( rURL
.substr( 0, nLastIndex
) );
1363 Directory
aDir( aDirURL
);
1364 Directory::RC rc
= aDir
.open();
1365 if( rc
== Directory::E_NOENT
)
1366 rc
= osl::Directory::create( aDirURL
);
1368 if( rc
!= Directory::E_None
)
1378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */