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>
27 #include <tools/diagnose_ex.h>
28 #include <tools/urlobj.hxx>
29 #include <unotools/pathoptions.hxx>
30 #include <unotools/resmgr.hxx>
31 #include <unotools/streamwrap.hxx>
32 #include <osl/file.hxx>
33 #include <o3tl/enumrange.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/weld.hxx>
36 #include <sfx2/filedlghelper.hxx>
37 #include <tools/stream.hxx>
39 #include <rtl/uri.hxx>
44 #include <strings.hrc>
45 #include "xmlfiltersettingsdialog.hxx"
46 #include "xmlfiltertabdialog.hxx"
47 #include "xmlfiltertestdialog.hxx"
48 #include "xmlfilterjar.hxx"
49 #include <strings.hxx>
52 using namespace com::sun::star::lang
;
53 using namespace com::sun::star::uno
;
54 using namespace com::sun::star::io
;
55 using namespace com::sun::star::container
;
56 using namespace com::sun::star::beans
;
57 using namespace com::sun::star::util
;
61 OUString
XsltResId(const char* pId
)
63 return Translate::get(pId
, Translate::Create("flt"));
66 XMLFilterSettingsDialog::XMLFilterSettingsDialog(weld::Window
* pParent
,
67 const css::uno::Reference
<css::uno::XComponentContext
>& rxContext
)
68 : GenericDialogController(pParent
, "filter/ui/xmlfiltersettings.ui", "XMLFilterSettingsDialog")
69 , mxContext( rxContext
)
70 , m_sTemplatePath("$(user)/template/")
71 , m_sDocTypePrefix("doctype:")
72 , m_xPBNew(m_xBuilder
->weld_button("new"))
73 , m_xPBEdit(m_xBuilder
->weld_button("edit"))
74 , m_xPBTest(m_xBuilder
->weld_button("test"))
75 , m_xPBDelete(m_xBuilder
->weld_button("delete"))
76 , m_xPBSave(m_xBuilder
->weld_button("save"))
77 , m_xPBOpen(m_xBuilder
->weld_button("open"))
78 , m_xPBClose(m_xBuilder
->weld_button("close"))
79 , m_xFilterListBox(m_xBuilder
->weld_tree_view("filterlist"))
81 m_xFilterListBox
->set_selection_mode(SelectionMode::Multiple
);
83 m_xFilterListBox
->set_size_request(m_xFilterListBox
->get_approximate_digit_width() * 65,
84 m_xFilterListBox
->get_height_rows(12));
86 m_xFilterListBox
->connect_changed( LINK( this, XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
) );
87 m_xFilterListBox
->connect_row_activated( LINK( this, XMLFilterSettingsDialog
, DoubleClickHdl_Impl
) );
88 m_xFilterListBox
->set_accessible_name(XsltResId(STR_XML_FILTER_LISTBOX
));
90 m_xPBNew
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
91 m_xPBEdit
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
92 m_xPBTest
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
93 m_xPBDelete
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
94 m_xPBSave
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
95 m_xPBOpen
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
96 m_xPBClose
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
100 mxFilterContainer
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", rxContext
), UNO_QUERY
);
101 mxTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", rxContext
), UNO_QUERY
);
102 mxExtendedTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.document.ExtendedTypeDetectionFactory", rxContext
), UNO_QUERY
);
104 SvtPathOptions aOptions
;
105 m_sTemplatePath
= aOptions
.SubstituteVariable( m_sTemplatePath
);
107 catch(const Exception
&)
109 TOOLS_WARN_EXCEPTION("filter.xslt", "");
113 XMLFilterSettingsDialog::~XMLFilterSettingsDialog()
117 IMPL_LINK(XMLFilterSettingsDialog
, ClickHdl_Impl
, weld::Button
&, rButton
, void)
119 // tdf#122171 block closing libreoffice until the following dialog is dismissed
122 if (m_xPBNew
.get() == &rButton
)
126 else if (m_xPBEdit
.get() == &rButton
)
130 else if (m_xPBTest
.get() == &rButton
)
134 else if (m_xPBDelete
.get() == &rButton
)
138 else if (m_xPBSave
.get() == &rButton
)
142 else if (m_xPBOpen
.get() == &rButton
)
149 if (m_xPBClose
.get() == &rButton
)
150 m_xDialog
->response(RET_CLOSE
);
153 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
, weld::TreeView
&, void)
158 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, DoubleClickHdl_Impl
, weld::TreeView
&, bool)
164 void XMLFilterSettingsDialog::UpdateWindow()
166 m_xFilterListBox
->grab_focus();
168 m_xFilterListBox
->clear();
173 void XMLFilterSettingsDialog::updateStates()
175 std::vector
<int> aRows
= m_xFilterListBox
->get_selected_rows();
177 bool bHasSelection
= !aRows
.empty();
179 bool bMultiSelection
= aRows
.size() > 1;
180 bool bIsReadonly
= false;
181 bool bIsDefault
= false;
184 filter_info_impl
* pInfo
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_id(aRows
[0]).toInt64());
185 bIsReadonly
= pInfo
->mbReadonly
;
187 for( auto nFact
: o3tl::enumrange
<SvtModuleOptions::EFactory
>())
189 OUString sDefault
= maModuleOpt
.GetFactoryDefaultFilter(nFact
);
190 if( sDefault
== pInfo
->maFilterName
)
197 m_xPBEdit
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
);
198 m_xPBTest
->set_sensitive( bHasSelection
&& !bMultiSelection
);
199 m_xPBDelete
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
&& !bIsDefault
);
200 m_xPBSave
->set_sensitive( bHasSelection
);
203 /** is called when the user clicks on the "New" button */
204 void XMLFilterSettingsDialog::onNew()
206 filter_info_impl aTempInfo
;
208 // create a unique filter name
209 aTempInfo
.maFilterName
= createUniqueFilterName(XsltResId(STR_DEFAULT_FILTER_NAME
));
211 // init default extension
212 aTempInfo
.maExtension
= STR_DEFAULT_EXTENSION
;
214 // set default ui name
215 aTempInfo
.maInterfaceName
= createUniqueInterfaceName(XsltResId(STR_DEFAULT_UI_NAME
));
217 // set default application
218 aTempInfo
.maDocumentService
= "com.sun.star.text.TextDocument";
220 // execute XML Filter Dialog
221 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, &aTempInfo
);
222 if (aDlg
.run() == RET_OK
)
224 // insert the new filter
225 insertOrEdit( aDlg
.getNewFilterInfo() );
229 /** is called when the user clicks on the "Edit" Button */
230 void XMLFilterSettingsDialog::onEdit()
232 // get selected filter info
233 filter_info_impl
* pOldInfo
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_selected_id().toInt64());
237 // execute XML Filter Dialog
238 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, pOldInfo
);
239 if (aDlg
.run() == RET_OK
)
241 filter_info_impl
* pNewInfo
= aDlg
.getNewFilterInfo();
243 if( !(*pOldInfo
== *pNewInfo
) )
246 insertOrEdit( pNewInfo
, pOldInfo
);
251 /** helper to create a sequence of strings from an extensions strings
252 "ext1;ext2;ext3" will become { "ext1", "ext2", "ext3" } */
253 static Sequence
< OUString
> createExtensionsSequence( const OUString
& rExtensions
)
255 // first count how many extensions we have inside the string
258 int nLength
= rExtensions
.getLength();
261 // a non empty string has at least one extension
264 // now count the delimiters ';'
265 const sal_Unicode
* pString
= rExtensions
.getStr();
267 for( i
= 0; i
< nLength
; i
++, pString
++ )
269 if( *pString
== ';' )
274 Sequence
< OUString
> aExtensions( nExtensions
);
276 // extract the extensions from the source string and fill the sequence
279 int nCurrentIndex
= 0;
282 for( i
= 0; i
< nExtensions
; i
++ )
284 nLastIndex
= rExtensions
.indexOf( ';', nLastIndex
);
286 if( nLastIndex
== -1 )
288 aExtensions
[i
] = rExtensions
.copy( nCurrentIndex
);
293 aExtensions
[i
] = rExtensions
.copy( nCurrentIndex
, nLastIndex
- nCurrentIndex
);
294 nCurrentIndex
= nLastIndex
+ 1;
295 nLastIndex
= nCurrentIndex
;
302 /** checks if the given name is unique inside the filter factory. If not,
303 numbers are added until the returned name is unique */
304 OUString
XMLFilterSettingsDialog::createUniqueFilterName( const OUString
& rFilterName
)
306 OUString
aFilterName( rFilterName
);
310 while( mxFilterContainer
->hasByName( aFilterName
) )
312 aFilterName
= rFilterName
+ " " + OUString::number( nId
++ );
318 /** checks if the given name is unique inside the type detection. If not,
319 numbers are added until the returned name is unique */
320 OUString
XMLFilterSettingsDialog::createUniqueTypeName( const OUString
& rTypeName
)
322 OUString
aTypeName( rTypeName
);
326 while( mxFilterContainer
->hasByName( aTypeName
) )
328 aTypeName
= rTypeName
+ " " + OUString::number( nId
++ );
334 /** checks if the given name is a unique ui name inside the filter factory. If not,
335 numbers are added until the returned name is unique */
336 OUString
XMLFilterSettingsDialog::createUniqueInterfaceName( const OUString
& rInterfaceName
)
338 sal_Int32 nDefaultNumber
= 0;
342 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
344 Sequence
< PropertyValue
> aValues
;
345 for( OUString
const & filterName
: aFilterNames
)
347 Any
aAny( mxFilterContainer
->getByName( filterName
) );
348 if( !(aAny
>>= aValues
) )
351 const sal_Int32
nValueCount( aValues
.getLength() );
352 PropertyValue
* pValues
= aValues
.getArray();
355 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
357 if ( pValues
->Name
== "UIName" )
359 OUString aInterfaceName
;
360 pValues
->Value
>>= aInterfaceName
;
363 // see if this filter matches our default filter name
364 if( aInterfaceName
.match( rInterfaceName
) )
366 // if yes, make sure we generate a unique name with a higher number
367 // this is dump but fast
368 sal_Int32 nNumber
= aInterfaceName
.copy( rInterfaceName
.getLength() ).toInt32();
369 if( nNumber
>= nDefaultNumber
)
370 nDefaultNumber
= nNumber
+ 1;
376 catch( const Exception
& )
378 TOOLS_WARN_EXCEPTION("filter.xslt", "");
381 OUString
aInterfaceName( rInterfaceName
);
384 aInterfaceName
+= " " + OUString::number( nDefaultNumber
);
387 return aInterfaceName
;
390 /** inserts a new filter into the ui and configuration if pOldInfo is NULL.
391 If pOldInfo is not null, the old filter will be replaced with the new settings */
392 bool XMLFilterSettingsDialog::insertOrEdit( filter_info_impl
* pNewInfo
, const filter_info_impl
* pOldInfo
)
398 // see if we need to update the type name
399 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
401 if( pOldInfo
->maType
== pOldInfo
->maFilterName
)
403 pNewInfo
->maType
.clear();
407 // see if we need to clean up old stuff first
410 // if filter name changed, we need to remove the old filter first
411 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
412 mxFilterContainer
->removeByName( pOldInfo
->maFilterName
);
414 // if type name changed, we need to remove the old type first
415 if( pOldInfo
->maType
!= pNewInfo
->maType
)
416 mxTypeDetection
->removeByName( pOldInfo
->maType
);
418 catch( const Exception
& )
420 TOOLS_WARN_EXCEPTION("filter.xslt", "");
425 filter_info_impl
* pFilterEntry( nullptr );
429 // create or copy filter info
432 // change existing filter entry in filter list box
433 pFilterEntry
= const_cast<filter_info_impl
*>(pOldInfo
);
434 *pFilterEntry
= *pNewInfo
;
438 // add new entry to filter list box
439 pFilterEntry
= new filter_info_impl( *pNewInfo
);
443 // check if we need to copy the template
444 if( bOk
&& !pFilterEntry
->maImportTemplate
.isEmpty() )
446 if( !pFilterEntry
->maImportTemplate
.matchIgnoreAsciiCase( m_sTemplatePath
) )
448 INetURLObject
aSourceURL( pFilterEntry
->maImportTemplate
);
449 if (!aSourceURL
.GetLastName().isEmpty())
451 OUString aDestURL
= m_sTemplatePath
+ pFilterEntry
->maFilterName
+ "/";
452 if( createDirectory( aDestURL
) )
454 aDestURL
+= aSourceURL
.GetLastName();
456 SvFileStream
aInputStream(pFilterEntry
->maImportTemplate
, StreamMode::READ
);
457 Reference
< XInputStream
> xIS( new utl::OInputStreamWrapper( aInputStream
) );
458 SvFileStream
aOutputStream(aDestURL
, StreamMode::WRITE
);
459 Reference
< XOutputStream
> xOS( new utl::OOutputStreamWrapper( aOutputStream
) );
461 if( copyStreams( xIS
, xOS
) )
462 pFilterEntry
->maImportTemplate
= aDestURL
;
470 if( pFilterEntry
->maType
.isEmpty() )
472 pFilterEntry
->maType
= createUniqueTypeName( pNewInfo
->maFilterName
);
475 // update import/export flags
476 if( !pFilterEntry
->maImportXSLT
.isEmpty() )
478 pFilterEntry
->maFlags
|= 1;
482 pFilterEntry
->maFlags
&= ~1;
485 if( !pFilterEntry
->maExportXSLT
.isEmpty() )
487 pFilterEntry
->maFlags
|= 2;
491 pFilterEntry
->maFlags
&= ~2;
493 pFilterEntry
->maFlags
|= 0x80040;
495 // 2. create user data for filter entry
496 Sequence
< OUString
> aUserData( pFilterEntry
->getFilterUserData());
498 // 3. create property values for filter entry
499 Sequence
< PropertyValue
> aFilterData( 8 );
501 aFilterData
[0].Name
= "Type";
502 aFilterData
[0].Value
<<= pFilterEntry
->maType
;
504 aFilterData
[1].Name
= "UIName";
505 aFilterData
[1].Value
<<= pFilterEntry
->maInterfaceName
;
507 aFilterData
[2].Name
= "DocumentService";
508 aFilterData
[2].Value
<<= pFilterEntry
->maDocumentService
;
510 aFilterData
[3].Name
= "FilterService";
511 aFilterData
[3].Value
<<= OUString( "com.sun.star.comp.Writer.XmlFilterAdaptor" );
513 aFilterData
[4].Name
= "Flags";
514 aFilterData
[4].Value
<<= pFilterEntry
->maFlags
;
516 aFilterData
[5].Name
= "UserData";
517 aFilterData
[5].Value
<<= aUserData
;
519 aFilterData
[6].Name
= "FileFormatVersion";
520 aFilterData
[6].Value
<<= pFilterEntry
->maFileFormatVersion
;
522 aFilterData
[7].Name
= "TemplateName";
523 aFilterData
[7].Value
<<= pFilterEntry
->maImportTemplate
;
525 // 4. insert new or replace existing filter
528 Any
aAny( makeAny( aFilterData
) );
529 if( mxFilterContainer
->hasByName( pFilterEntry
->maFilterName
) )
531 mxFilterContainer
->replaceByName( pFilterEntry
->maFilterName
, aAny
);
535 mxFilterContainer
->insertByName( pFilterEntry
->maFilterName
, aAny
);
538 catch( const Exception
& )
540 TOOLS_WARN_EXCEPTION("filter.xslt", "");
545 // 5. prepare type information
548 Sequence
< PropertyValue
> aValues(4);
550 aValues
[0].Name
= "UIName";
551 aValues
[0].Value
<<= pFilterEntry
->maInterfaceName
;
552 aValues
[1].Name
= "ClipboardFormat";
554 if( !pFilterEntry
->maDocType
.match( m_sDocTypePrefix
) )
556 aDocType
= m_sDocTypePrefix
+ pFilterEntry
->maDocType
;
560 aDocType
= pFilterEntry
->maDocType
;
562 if (aDocType
== m_sDocTypePrefix
)
563 aValues
[1].Value
<<= OUString();
565 aValues
[1].Value
<<= aDocType
;
567 aValues
[2].Name
= "DocumentIconID";
568 aValues
[2].Value
<<= pFilterEntry
->mnDocumentIconID
;
570 aValues
[3].Name
= "Extensions";
571 aValues
[3].Value
<<= createExtensionsSequence( pFilterEntry
->maExtension
);
573 // the detect service will only be registered, if a doctype/search token was specified
574 if (aDocType
.getLength() > m_sDocTypePrefix
.getLength())
577 aValues
[4].Name
= "DetectService";
578 aValues
[4].Value
<<= OUString( "com.sun.star.comp.filters.XMLFilterDetect" );
581 // 6. insert new or replace existing type information
582 if( mxTypeDetection
.is() )
586 Any
aAny( makeAny( aValues
) );
587 if( mxTypeDetection
->hasByName( pFilterEntry
->maType
) )
589 mxTypeDetection
->replaceByName( pFilterEntry
->maType
, aAny
);
593 mxTypeDetection
->insertByName( pFilterEntry
->maType
, aAny
);
596 catch( const Exception
& )
598 TOOLS_WARN_EXCEPTION("filter.xslt", "");
607 Reference
< XFlushable
> xFlushable( mxTypeDetection
, UNO_QUERY
);
608 if( xFlushable
.is() )
611 catch( const Exception
& )
613 TOOLS_WARN_EXCEPTION("filter.xslt", "");
620 // we failed to add the type, so lets remove the filter
623 mxFilterContainer
->removeByName( pFilterEntry
->maFilterName
);
625 catch( const Exception
& )
627 TOOLS_WARN_EXCEPTION("filter.xslt", "");
635 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
636 if( xFlushable
.is() )
639 catch( const Exception
& )
641 TOOLS_WARN_EXCEPTION("filter.xslt", "");
647 // we failed to add the filter, so lets remove the type
650 mxTypeDetection
->removeByName( pFilterEntry
->maType
);
652 catch( const Exception
& )
654 TOOLS_WARN_EXCEPTION("filter.xslt", "");
663 if( mxExtendedTypeDetection
.is() )
665 OUString
sFilterDetectService( "com.sun.star.comp.filters.XMLFilterDetect" );
666 if( mxExtendedTypeDetection
->hasByName( sFilterDetectService
) )
668 Sequence
< PropertyValue
> aSequence
;
669 if( mxExtendedTypeDetection
->getByName( sFilterDetectService
) >>= aSequence
)
671 sal_Int32 nCount
= aSequence
.getLength();
673 for( nIndex
= 0; nIndex
< nCount
; nIndex
++ )
675 if ( aSequence
[nIndex
].Name
== "Types" )
677 Sequence
< OUString
> aTypes
;
678 if( aSequence
[nIndex
].Value
>>= aTypes
)
680 sal_Int32 nStrCount
= aTypes
.getLength();
682 for( nStr
= 0; nStr
< nStrCount
; nStr
++ )
684 if( aTypes
[nStr
] == pFilterEntry
->maType
)
688 if( nStr
== nStrCount
)
690 aTypes
.realloc( nStrCount
+ 1 );
691 aTypes
[nStrCount
] = pFilterEntry
->maType
;
693 aSequence
[nIndex
].Value
<<= aTypes
;
695 mxExtendedTypeDetection
->replaceByName( sFilterDetectService
, makeAny( aSequence
) );
697 Reference
< XFlushable
> xFlushable( mxExtendedTypeDetection
, UNO_QUERY
);
698 if( xFlushable
.is() )
716 changeEntry( pFilterEntry
);
720 addFilterEntry( pFilterEntry
);
721 maFilterVector
.push_back( std::unique_ptr
<filter_info_impl
>(pFilterEntry
) );
728 /** is called when the user clicks the "Test" button */
729 void XMLFilterSettingsDialog::onTest()
731 // get the first selected filter
732 filter_info_impl
* pInfo
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_selected_id().toInt64());
735 XMLFilterTestDialog
aDlg(m_xDialog
.get(), mxContext
);
740 void XMLFilterSettingsDialog::onDelete()
742 int nIndex
= m_xFilterListBox
->get_selected_index();
745 filter_info_impl
* pInfo
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_id(nIndex
).toInt64());
748 OUString
aMessage(XsltResId(STR_WARN_DELETE
));
749 aMessage
= aMessage
.replaceFirst( "%s", pInfo
->maFilterName
);
751 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(m_xDialog
.get(),
752 VclMessageType::Warning
, VclButtonsType::YesNo
,
754 xWarn
->set_default_response(RET_YES
);
755 if (xWarn
->run() == RET_YES
)
759 if( mxFilterContainer
->hasByName( pInfo
->maFilterName
) )
761 mxFilterContainer
->removeByName( pInfo
->maFilterName
);
763 bool bTypeStillUsed
= false;
765 // now loop over all filter and see if someone else uses the same type
766 Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
767 OUString
* pFilterName
= aFilterNames
.getArray();
769 const sal_Int32 nCount
= aFilterNames
.getLength();
771 Sequence
< PropertyValue
> aValues
;
773 for( nFilter
= 0; (nFilter
< nCount
) && !bTypeStillUsed
; nFilter
++, pFilterName
++ )
775 Any
aAny( mxFilterContainer
->getByName( *pFilterName
) );
776 if( !(aAny
>>= aValues
) )
779 const sal_Int32
nValueCount( aValues
.getLength() );
780 PropertyValue
* pValues
= aValues
.getArray();
783 for (nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++)
785 if ( pValues
->Name
== "Type" )
788 pValues
->Value
>>= aType
;
789 if( aType
== pInfo
->maType
)
790 bTypeStillUsed
= true;
797 // if the type is not used anymore, remove it also
798 if( !bTypeStillUsed
)
800 if( mxTypeDetection
->hasByName( pInfo
->maType
) )
802 mxTypeDetection
->removeByName( pInfo
->maType
);
806 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
807 if( xFlushable
.is() )
810 xFlushable
.set( mxTypeDetection
, UNO_QUERY
);
811 if( xFlushable
.is() )
814 // now remove entry from ui
815 m_xFilterListBox
->remove(nIndex
);
817 // and delete the filter entry
818 maFilterVector
.erase(std::find_if( maFilterVector
.begin(), maFilterVector
.end(),
819 [&] (std::unique_ptr
<filter_info_impl
> const & p
)
820 { return p
.get() == pInfo
; }));
823 catch( const Exception
& )
825 TOOLS_WARN_EXCEPTION("filter.xslt", "");
833 void XMLFilterSettingsDialog::onSave()
835 std::vector
<filter_info_impl
*> aFilters
;
839 m_xFilterListBox
->selected_foreach([&](weld::TreeIter
& rEntry
){
840 filter_info_impl
* pInfo
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_id(rEntry
).toInt64());
841 aFilters
.push_back(pInfo
);
846 // Open Fileopen-Dialog
847 ::sfx2::FileDialogHelper
aDlg(
848 css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
,
849 FileDialogFlags::NONE
, m_xDialog
.get());
851 OUString
aExtensions( "*.jar" );
852 OUString aFilterName
= XsltResId(STR_FILTER_PACKAGE
) +
853 " (" + aExtensions
+ ")";
855 aDlg
.AddFilter( aFilterName
, aExtensions
);
857 if ( aDlg
.Execute() != ERRCODE_NONE
)
860 XMLFilterJarHelper
aJarHelper( mxContext
);
861 aJarHelper
.savePackage( aDlg
.GetPath(), aFilters
);
863 INetURLObject
aURL( aDlg
.GetPath() );
865 OUString
sPlaceholder( "%s" );
870 aMsg
= XsltResId(STR_FILTERS_HAVE_BEEN_SAVED
);
871 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
872 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
876 aMsg
= XsltResId(STR_FILTER_HAS_BEEN_SAVED
);
877 aMsg
= aMsg
.replaceFirst( sPlaceholder
, (*aFilters
.begin())->maFilterName
);
878 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
881 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
882 VclMessageType::Info
, VclButtonsType::Ok
,
887 void XMLFilterSettingsDialog::onOpen()
889 std::vector
< std::unique_ptr
<filter_info_impl
> > aFilters
;
891 // Open Fileopen-Dialog
892 ::sfx2::FileDialogHelper
aDlg(
893 css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
894 FileDialogFlags::NONE
, m_xDialog
.get());
896 OUString
aExtensions( "*.jar" );
897 OUString aFilterName
= XsltResId(STR_FILTER_PACKAGE
) +
898 " (" + aExtensions
+ ")";
900 aDlg
.AddFilter( aFilterName
, aExtensions
);
902 if ( aDlg
.Execute() != ERRCODE_NONE
)
905 OUString
aURL( aDlg
.GetPath() );
907 XMLFilterJarHelper
aJarHelper( mxContext
);
908 aJarHelper
.openPackage( aURL
, aFilters
);
911 for (auto& filter
: aFilters
)
913 if( insertOrEdit(filter
.get()) )
915 aFilterName
= filter
->maFilterName
;
925 OUString
sPlaceholder( "%s" );
929 INetURLObject
aURLObj( aURL
);
930 aMsg
= XsltResId(STR_NO_FILTERS_FOUND
);
931 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURLObj
.GetLastName());
933 else if( nFilters
== 1 )
935 aMsg
= XsltResId(STR_FILTER_INSTALLED
);
936 aMsg
= aMsg
.replaceFirst( sPlaceholder
, aFilterName
);
941 aMsg
= XsltResId(STR_FILTERS_INSTALLED
);
942 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
945 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
946 VclMessageType::Info
, VclButtonsType::Ok
,
951 void XMLFilterSettingsDialog::disposeFilterList()
953 maFilterVector
.clear();
954 m_xFilterListBox
->clear();
957 void XMLFilterSettingsDialog::initFilterList()
959 if( mxFilterContainer
.is() )
961 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
963 Sequence
< PropertyValue
> aValues
;
965 std::unique_ptr
<filter_info_impl
> pTempFilter( new filter_info_impl
);
966 Sequence
< OUString
> aUserData
;
968 for( OUString
const & filterName
: aFilterNames
)
970 aUserData
.realloc(0);
974 Any
aAny( mxFilterContainer
->getByName( filterName
) );
975 if( !(aAny
>>= aValues
) )
978 OUString aFilterService
;
979 pTempFilter
->maFilterName
= filterName
;
981 const sal_Int32
nValueCount( aValues
.getLength() );
982 PropertyValue
* pValues
= aValues
.getArray();
985 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
987 if ( pValues
->Name
== "Type" )
989 pValues
->Value
>>= pTempFilter
->maType
;
991 else if ( pValues
->Name
== "UIName" )
993 pValues
->Value
>>= pTempFilter
->maInterfaceName
;
995 else if ( pValues
->Name
== "DocumentService" )
997 pValues
->Value
>>= pTempFilter
->maDocumentService
;
999 else if ( pValues
->Name
== "FilterService" )
1001 pValues
->Value
>>= aFilterService
;
1003 else if ( pValues
->Name
== "Flags" )
1005 pValues
->Value
>>= pTempFilter
->maFlags
;
1007 else if ( pValues
->Name
== "UserData" )
1009 pValues
->Value
>>= aUserData
;
1011 else if ( pValues
->Name
== "FileFormatVersion" )
1013 pValues
->Value
>>= pTempFilter
->maFileFormatVersion
;
1015 else if ( pValues
->Name
== "TemplateName" )
1017 pValues
->Value
>>= pTempFilter
->maImportTemplate
;
1019 else if ( pValues
->Name
== "Finalized" )
1021 pValues
->Value
>>= pTempFilter
->mbReadonly
;
1025 // if this is not a XmlFilterAdaptor entry, skip it
1026 if( aFilterService
!= "com.sun.star.comp.Writer.XmlFilterAdaptor" )
1030 // if we don't have the needed user data, skip it
1031 if( aUserData
.getLength() < 6 )
1034 // if this is not an XSLTFilter entry, skip it
1035 if( aUserData
[0] != "com.sun.star.documentconversion.XSLTFilter" )
1038 // get filter information from userdata
1039 pTempFilter
->mbNeedsXSLT2
= aUserData
[1].toBoolean();
1040 pTempFilter
->maImportService
= aUserData
[2];
1041 pTempFilter
->maExportService
= aUserData
[3];
1042 pTempFilter
->maImportXSLT
= aUserData
[4];
1043 pTempFilter
->maExportXSLT
= aUserData
[5];
1044 if( aUserData
.getLength() >= 8 )
1045 pTempFilter
->maComment
= aUserData
[7];
1047 // get type information
1048 if( mxTypeDetection
.is() )
1052 aAny
= mxTypeDetection
->getByName( pTempFilter
->maType
);
1053 Sequence
< PropertyValue
> aValues2
;
1055 if( aAny
>>= aValues2
)
1057 const sal_Int32
nValueCount2( aValues2
.getLength() );
1058 PropertyValue
* pValues2
= aValues2
.getArray();
1061 for( nValue2
= 0; nValue2
< nValueCount2
; nValue2
++, pValues2
++ )
1063 if ( pValues2
->Name
== "ClipboardFormat" )
1066 pValues2
->Value
>>= aDocType
;
1068 if( aDocType
.match( m_sDocTypePrefix
) )
1069 aDocType
= aDocType
.copy( m_sDocTypePrefix
.getLength() );
1071 pTempFilter
->maDocType
= aDocType
;
1073 else if ( pValues2
->Name
== "Extensions" )
1075 Sequence
< OUString
> aExtensions
;
1076 if( pValues2
->Value
>>= aExtensions
)
1078 pTempFilter
->maExtension
.clear();
1080 sal_Int32
nCount3( aExtensions
.getLength() );
1081 OUString
* pExtensions
= aExtensions
.getArray();
1083 for( n
= 0; n
< nCount3
; n
++ )
1086 pTempFilter
->maExtension
+= ";";
1087 pTempFilter
->maExtension
+= *pExtensions
++;
1091 else if ( pValues2
->Name
== "DocumentIconID" )
1093 pValues2
->Value
>>= pTempFilter
->mnDocumentIconID
;
1095 else if ( pValues2
->Name
== "Finalized" )
1097 // both the filter and the type may be finalized
1099 pValues2
->Value
>>= bTemp
;
1100 pTempFilter
->mbReadonly
|= bTemp
;
1105 catch( const css::container::NoSuchElementException
& )
1107 OSL_FAIL( "Type not found, user error?" ); // TODO: error?
1111 // add entry to internal container and to ui filter list box
1112 maFilterVector
.push_back( std::unique_ptr
<filter_info_impl
>(pTempFilter
.get()) );
1113 addFilterEntry( pTempFilter
.release() );
1116 pTempFilter
.reset( new filter_info_impl
);
1118 catch( const Exception
& )
1120 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1126 if (m_xFilterListBox
->n_children())
1128 m_xFilterListBox
->columns_autosize();
1129 m_xFilterListBox
->select(0);
1133 application_info_impl::application_info_impl( const char * pDocumentService
, const OUString
& rUINameRes
, const char * mpXMLImporter
, const char * mpXMLExporter
)
1134 : maDocumentService( pDocumentService
, strlen( pDocumentService
), RTL_TEXTENCODING_ASCII_US
),
1135 maDocumentUIName(Translate::ExpandVariables(rUINameRes
)),
1136 maXMLImporter( mpXMLImporter
, strlen( mpXMLImporter
), RTL_TEXTENCODING_ASCII_US
),
1137 maXMLExporter( mpXMLExporter
, strlen( mpXMLExporter
), RTL_TEXTENCODING_ASCII_US
)
1141 std::vector
< application_info_impl
> const & getApplicationInfos()
1143 static std::vector
< application_info_impl
> const aInfos
1145 { "com.sun.star.text.TextDocument",
1146 STR_APPL_NAME_WRITER
,
1147 "com.sun.star.comp.Writer.XMLImporter",
1148 "com.sun.star.comp.Writer.XMLExporter" },
1150 { "com.sun.star.sheet.SpreadsheetDocument",
1152 "com.sun.star.comp.Calc.XMLImporter",
1153 "com.sun.star.comp.Calc.XMLExporter" },
1155 { "com.sun.star.presentation.PresentationDocument",
1156 STR_APPL_NAME_IMPRESS
,
1157 "com.sun.star.comp.Impress.XMLImporter",
1158 "com.sun.star.comp.Impress.XMLExporter" },
1160 { "com.sun.star.drawing.DrawingDocument",
1162 "com.sun.star.comp.Draw.XMLImporter",
1163 "com.sun.star.comp.Draw.XMLExporter" },
1165 // --- oasis file formats...
1166 { "com.sun.star.text.TextDocument",
1167 STR_APPL_NAME_OASIS_WRITER
,
1168 "com.sun.star.comp.Writer.XMLOasisImporter",
1169 "com.sun.star.comp.Writer.XMLOasisExporter" },
1171 { "com.sun.star.sheet.SpreadsheetDocument",
1172 STR_APPL_NAME_OASIS_CALC
,
1173 "com.sun.star.comp.Calc.XMLOasisImporter",
1174 "com.sun.star.comp.Calc.XMLOasisExporter" },
1176 { "com.sun.star.presentation.PresentationDocument",
1177 STR_APPL_NAME_OASIS_IMPRESS
,
1178 "com.sun.star.comp.Impress.XMLOasisImporter",
1179 "com.sun.star.comp.Impress.XMLOasisExporter" },
1181 { "com.sun.star.drawing.DrawingDocument",
1182 STR_APPL_NAME_OASIS_DRAW
,
1183 "com.sun.star.comp.Draw.XMLOasisImporter",
1184 "com.sun.star.comp.Draw.XMLOasisExporter" },
1190 const application_info_impl
* getApplicationInfo( const OUString
& rServiceName
)
1192 std::vector
< application_info_impl
> const & rInfos
= getApplicationInfos();
1193 for (auto const& info
: rInfos
)
1195 if( rServiceName
== info
.maXMLExporter
||
1196 rServiceName
== info
.maXMLImporter
)
1204 OUString
getApplicationUIName( const OUString
& rServiceName
)
1206 const application_info_impl
* pInfo
= getApplicationInfo( rServiceName
);
1209 return pInfo
->maDocumentUIName
;
1213 OUString aRet
= XsltResId(STR_UNKNOWN_APPLICATION
);
1214 if( !rServiceName
.isEmpty() )
1216 aRet
+= " (" + rServiceName
+ ")";
1222 /** adds a new filter info entry to the ui filter list */
1223 void XMLFilterSettingsDialog::addFilterEntry( const filter_info_impl
* pInfo
)
1225 int nRow
= m_xFilterListBox
->n_children();
1226 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(pInfo
)));
1227 m_xFilterListBox
->append(sId
, pInfo
->maFilterName
);
1228 m_xFilterListBox
->set_text(nRow
, getEntryString(pInfo
), 1);
1231 void XMLFilterSettingsDialog::changeEntry( const filter_info_impl
* pInfo
)
1233 const int nCount
= m_xFilterListBox
->n_children();
1234 for(int nPos
= 0; nPos
< nCount
; ++nPos
)
1236 filter_info_impl
* pEntry
= reinterpret_cast<filter_info_impl
*>(m_xFilterListBox
->get_id(nPos
).toInt64());
1237 if (pEntry
== pInfo
)
1239 m_xFilterListBox
->set_text(nPos
, pInfo
->maFilterName
, 0);
1240 m_xFilterListBox
->set_text(nPos
, getEntryString(pInfo
), 1);
1246 OUString
XMLFilterSettingsDialog::getEntryString( const filter_info_impl
* pInfo
)
1249 if ( !pInfo
->maExportService
.isEmpty() )
1250 aEntryStr
= getApplicationUIName( pInfo
->maExportService
);
1252 aEntryStr
= getApplicationUIName( pInfo
->maImportService
);
1255 if( pInfo
->maFlags
& 1 )
1257 if( pInfo
->maFlags
& 2 )
1259 aEntryStr
+= XsltResId(STR_IMPORT_EXPORT
);
1263 aEntryStr
+= XsltResId(STR_IMPORT_ONLY
);
1266 else if( pInfo
->maFlags
& 2 )
1268 aEntryStr
+= XsltResId(STR_EXPORT_ONLY
);
1272 aEntryStr
+= XsltResId(STR_UNDEFINED_FILTER
);
1278 filter_info_impl::filter_info_impl()
1279 : maFlags(0x00080040)
1280 , maFileFormatVersion(0)
1281 , mnDocumentIconID(0)
1283 , mbNeedsXSLT2(false)
1287 bool filter_info_impl::operator==( const filter_info_impl
& r
) const
1289 return maFilterName
== r
.maFilterName
&&
1290 maType
== r
.maType
&&
1291 maDocumentService
== r
.maDocumentService
&&
1292 maInterfaceName
== r
.maInterfaceName
&&
1293 maComment
== r
.maComment
&&
1294 maExtension
== r
.maExtension
&&
1295 maDocType
== r
.maDocType
&&
1296 maExportXSLT
== r
.maExportXSLT
&&
1297 maImportXSLT
== r
.maImportXSLT
&&
1298 maExportService
== r
.maExportService
&&
1299 maImportService
== r
.maImportService
&&
1300 maImportTemplate
== r
.maImportTemplate
&&
1301 maFlags
== r
.maFlags
&&
1302 maFileFormatVersion
== r
.maFileFormatVersion
&&
1303 mbNeedsXSLT2
== r
.mbNeedsXSLT2
;
1307 Sequence
< OUString
> filter_info_impl::getFilterUserData() const
1309 Sequence
< OUString
> aUserData(8);
1311 aUserData
[0] = "com.sun.star.documentconversion.XSLTFilter";
1312 aUserData
[1] = OUString::boolean( mbNeedsXSLT2
);
1313 aUserData
[2] = maImportService
;
1314 aUserData
[3] = maExportService
;
1315 aUserData
[4] = maImportXSLT
;
1316 aUserData
[5] = maExportXSLT
;
1317 aUserData
[7] = maComment
;
1322 OUString
string_encode( const OUString
& rText
)
1324 static sal_Bool
const uricNoSlash
[] = {
1325 false, false, false, false, false, false, false, false,
1326 false, false, false, false, false, false, false, false,
1327 false, false, false, false, false, false, false, false,
1328 false, false, false, false, false, false, false, false,
1329 false, true, false, false, true, false, true, true, // !"#$%&'
1330 true, true, true, true, false, true, true, false, // ()*+,-./
1331 true, true, true, true, true, true, true, true, // 01234567
1332 true, true, true, false, false, true, false, true, // 89:;<=>?
1333 true, true, true, true, true, true, true, true, // @ABCDEFG
1334 true, true, true, true, true, true, true, true, // HIJKLMNO
1335 true, true, true, true, true, true, true, true, // PQRSTUVW
1336 true, true, true, false, false, false, false, true, // XYZ[\]^_
1337 false, true, true, true, true, true, true, true, // `abcdefg
1338 true, true, true, true, true, true, true, true, // hijklmno
1339 true, true, true, true, true, true, true, true, // pqrstuvw
1340 true, true, true, false, false, false, true, false}; // xyz{|}~
1343 return Uri::encode( rText
, uricNoSlash
, rtl_UriEncodeCheckEscapes
, RTL_TEXTENCODING_UTF8
);
1346 OUString
string_decode( const OUString
& rText
)
1348 return Uri::decode( rText
, rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
);
1351 bool copyStreams( const Reference
< XInputStream
>& xIS
, const Reference
< XOutputStream
>& xOS
)
1355 sal_Int32 nBufferSize
= 512;
1356 Sequence
< sal_Int8
> aDataBuffer(nBufferSize
);
1361 nRead
= xIS
->readBytes( aDataBuffer
, nBufferSize
);
1365 if( nRead
< nBufferSize
)
1367 nBufferSize
= nRead
;
1368 aDataBuffer
.realloc(nRead
);
1371 xOS
->writeBytes( aDataBuffer
);
1380 catch(const Exception
&)
1382 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1388 bool createDirectory( OUString
const & rURL
)
1390 sal_Int32 nLastIndex
= sizeof( "file:///" ) - 2;
1391 while( nLastIndex
!= -1 )
1393 nLastIndex
= rURL
.indexOf( '/', nLastIndex
+ 1);
1394 if( nLastIndex
!= -1 )
1396 OUString
aDirURL( rURL
.copy( 0, nLastIndex
) );
1397 Directory
aDir( aDirURL
);
1398 Directory::RC rc
= aDir
.open();
1399 if( rc
== Directory::E_NOENT
)
1400 rc
= osl::Directory::create( aDirURL
);
1402 if( rc
!= Directory::E_None
)
1412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */