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
, u
"filter/ui/xmlfiltersettings.ui"_ustr
, u
"XMLFilterSettingsDialog"_ustr
)
66 , mxContext( rxContext
)
67 , m_sTemplatePath(u
"$(user)/template/"_ustr
)
68 , m_sDocTypePrefix(u
"doctype:"_ustr
)
69 , m_xPBNew(m_xBuilder
->weld_button(u
"new"_ustr
))
70 , m_xPBEdit(m_xBuilder
->weld_button(u
"edit"_ustr
))
71 , m_xPBTest(m_xBuilder
->weld_button(u
"test"_ustr
))
72 , m_xPBDelete(m_xBuilder
->weld_button(u
"delete"_ustr
))
73 , m_xPBSave(m_xBuilder
->weld_button(u
"save"_ustr
))
74 , m_xPBOpen(m_xBuilder
->weld_button(u
"open"_ustr
))
75 , m_xPBClose(m_xBuilder
->weld_button(u
"close"_ustr
))
76 , m_xFilterListBox(m_xBuilder
->weld_tree_view(u
"filterlist"_ustr
))
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_selection_changed(
84 LINK(this, XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
));
85 m_xFilterListBox
->connect_row_activated( LINK( this, XMLFilterSettingsDialog
, DoubleClickHdl_Impl
) );
86 m_xFilterListBox
->set_accessible_name(FilterResId(STR_XML_FILTER_LISTBOX
));
88 m_xPBNew
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
89 m_xPBEdit
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
90 m_xPBTest
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
91 m_xPBDelete
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
92 m_xPBSave
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
93 m_xPBOpen
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
94 m_xPBClose
->connect_clicked(LINK( this, XMLFilterSettingsDialog
, ClickHdl_Impl
) );
98 mxFilterContainer
.set( rxContext
->getServiceManager()->createInstanceWithContext( u
"com.sun.star.document.FilterFactory"_ustr
, rxContext
), UNO_QUERY
);
99 mxTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( u
"com.sun.star.document.TypeDetection"_ustr
, rxContext
), UNO_QUERY
);
100 mxExtendedTypeDetection
.set( rxContext
->getServiceManager()->createInstanceWithContext( u
"com.sun.star.document.ExtendedTypeDetectionFactory"_ustr
, rxContext
), UNO_QUERY
);
102 SvtPathOptions aOptions
;
103 m_sTemplatePath
= aOptions
.SubstituteVariable( m_sTemplatePath
);
105 catch(const Exception
&)
107 TOOLS_WARN_EXCEPTION("filter.xslt", "");
111 XMLFilterSettingsDialog::~XMLFilterSettingsDialog()
115 IMPL_LINK(XMLFilterSettingsDialog
, ClickHdl_Impl
, weld::Button
&, rButton
, void)
117 // tdf#122171 block closing libreoffice until the following dialog is dismissed
120 if (m_xPBNew
.get() == &rButton
)
124 else if (m_xPBEdit
.get() == &rButton
)
128 else if (m_xPBTest
.get() == &rButton
)
132 else if (m_xPBDelete
.get() == &rButton
)
136 else if (m_xPBSave
.get() == &rButton
)
140 else if (m_xPBOpen
.get() == &rButton
)
147 if (m_xPBClose
.get() == &rButton
)
148 m_xDialog
->response(RET_CLOSE
);
151 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, SelectionChangedHdl_Impl
, weld::TreeView
&, void)
156 IMPL_LINK_NOARG(XMLFilterSettingsDialog
, DoubleClickHdl_Impl
, weld::TreeView
&, bool)
162 void XMLFilterSettingsDialog::UpdateWindow()
164 m_xFilterListBox
->grab_focus();
166 m_xFilterListBox
->clear();
171 void XMLFilterSettingsDialog::updateStates()
173 std::vector
<int> aRows
= m_xFilterListBox
->get_selected_rows();
175 bool bHasSelection
= !aRows
.empty();
177 bool bMultiSelection
= aRows
.size() > 1;
178 bool bIsReadonly
= false;
179 bool bIsDefault
= false;
182 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(aRows
[0]));
183 bIsReadonly
= pInfo
->mbReadonly
;
185 for( auto nFact
: o3tl::enumrange
<SvtModuleOptions::EFactory
>())
187 OUString sDefault
= maModuleOpt
.GetFactoryDefaultFilter(nFact
);
188 if( sDefault
== pInfo
->maFilterName
)
195 m_xPBEdit
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
);
196 m_xPBTest
->set_sensitive( bHasSelection
&& !bMultiSelection
);
197 m_xPBDelete
->set_sensitive( bHasSelection
&& !bMultiSelection
&& !bIsReadonly
&& !bIsDefault
);
198 m_xPBSave
->set_sensitive( bHasSelection
);
201 /** is called when the user clicks on the "New" button */
202 void XMLFilterSettingsDialog::onNew()
204 filter_info_impl aTempInfo
;
206 // create a unique filter name
207 aTempInfo
.maFilterName
= createUniqueFilterName(FilterResId(STR_DEFAULT_FILTER_NAME
));
209 // init default extension
210 aTempInfo
.maExtension
= STR_DEFAULT_EXTENSION
;
212 // set default ui name
213 aTempInfo
.maInterfaceName
= createUniqueInterfaceName(FilterResId(STR_DEFAULT_UI_NAME
));
215 // set default application
216 aTempInfo
.maDocumentService
= "com.sun.star.text.TextDocument";
218 // execute XML Filter Dialog
219 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, &aTempInfo
);
220 if (aDlg
.run() == RET_OK
)
222 // insert the new filter
223 insertOrEdit( aDlg
.getNewFilterInfo() );
227 /** is called when the user clicks on the "Edit" Button */
228 void XMLFilterSettingsDialog::onEdit()
230 // get selected filter info
231 filter_info_impl
* pOldInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_selected_id());
235 // execute XML Filter Dialog
236 XMLFilterTabDialog
aDlg(m_xDialog
.get(), mxContext
, pOldInfo
);
237 if (aDlg
.run() == RET_OK
)
239 filter_info_impl
* pNewInfo
= aDlg
.getNewFilterInfo();
241 if( !(*pOldInfo
== *pNewInfo
) )
244 insertOrEdit( pNewInfo
, pOldInfo
);
249 /** helper to create a sequence of strings from an extensions strings
250 "ext1;ext2;ext3" will become { "ext1", "ext2", "ext3" } */
251 static Sequence
< OUString
> createExtensionsSequence( const OUString
& rExtensions
)
253 // first count how many extensions we have inside the string
256 int nLength
= rExtensions
.getLength();
259 // a non empty string has at least one extension
262 // now count the delimiters ';'
263 const sal_Unicode
* pString
= rExtensions
.getStr();
265 for( i
= 0; i
< nLength
; i
++, pString
++ )
267 if( *pString
== ';' )
272 Sequence
< OUString
> aExtensions( nExtensions
);
273 auto aExtensionsRange
= asNonConstRange(aExtensions
);
275 // extract the extensions from the source string and fill the sequence
278 int nCurrentIndex
= 0;
281 for( i
= 0; i
< nExtensions
; i
++ )
283 nLastIndex
= rExtensions
.indexOf( ';', nLastIndex
);
285 if( nLastIndex
== -1 )
287 aExtensionsRange
[i
] = rExtensions
.copy( nCurrentIndex
);
292 aExtensionsRange
[i
] = rExtensions
.copy( nCurrentIndex
, nLastIndex
- nCurrentIndex
);
293 nCurrentIndex
= nLastIndex
+ 1;
294 nLastIndex
= nCurrentIndex
;
301 /** checks if the given name is unique inside the filter factory. If not,
302 numbers are added until the returned name is unique */
303 OUString
XMLFilterSettingsDialog::createUniqueFilterName( const OUString
& rFilterName
)
305 OUString
aFilterName( rFilterName
);
309 while( mxFilterContainer
->hasByName( aFilterName
) )
311 aFilterName
= rFilterName
+ " " + OUString::number( nId
++ );
317 /** checks if the given name is unique inside the type detection. If not,
318 numbers are added until the returned name is unique */
319 OUString
XMLFilterSettingsDialog::createUniqueTypeName( const OUString
& rTypeName
)
321 OUString
aTypeName( rTypeName
);
325 while( mxFilterContainer
->hasByName( aTypeName
) )
327 aTypeName
= rTypeName
+ " " + OUString::number( nId
++ );
333 /** checks if the given name is a unique ui name inside the filter factory. If not,
334 numbers are added until the returned name is unique */
335 OUString
XMLFilterSettingsDialog::createUniqueInterfaceName( const OUString
& rInterfaceName
)
337 sal_Int32 nDefaultNumber
= 0;
341 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
343 Sequence
< PropertyValue
> aValues
;
344 for( OUString
const & filterName
: aFilterNames
)
346 Any
aAny( mxFilterContainer
->getByName( filterName
) );
347 if( !(aAny
>>= aValues
) )
350 const sal_Int32
nValueCount( aValues
.getLength() );
351 PropertyValue
* pValues
= aValues
.getArray();
354 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
356 if ( pValues
->Name
== "UIName" )
358 OUString aInterfaceName
;
359 pValues
->Value
>>= aInterfaceName
;
362 // see if this filter matches our default filter name
363 if( aInterfaceName
.match( rInterfaceName
) )
365 // if yes, make sure we generate a unique name with a higher number
366 // this is dump but fast
367 sal_Int32 nNumber
= o3tl::toInt32(aInterfaceName
.subView( rInterfaceName
.getLength() ));
368 if( nNumber
>= nDefaultNumber
)
369 nDefaultNumber
= nNumber
+ 1;
375 catch( const Exception
& )
377 TOOLS_WARN_EXCEPTION("filter.xslt", "");
380 OUString
aInterfaceName( rInterfaceName
);
383 aInterfaceName
+= " " + OUString::number( nDefaultNumber
);
386 return aInterfaceName
;
389 /** inserts a new filter into the ui and configuration if pOldInfo is NULL.
390 If pOldInfo is not null, the old filter will be replaced with the new settings */
391 bool XMLFilterSettingsDialog::insertOrEdit( filter_info_impl
* pNewInfo
, const filter_info_impl
* pOldInfo
)
397 // see if we need to update the type name
398 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
400 if( pOldInfo
->maType
== pOldInfo
->maFilterName
)
402 pNewInfo
->maType
.clear();
406 // see if we need to clean up old stuff first
409 // if filter name changed, we need to remove the old filter first
410 if( pOldInfo
->maFilterName
!= pNewInfo
->maFilterName
)
411 mxFilterContainer
->removeByName( pOldInfo
->maFilterName
);
413 // if type name changed, we need to remove the old type first
414 if( pOldInfo
->maType
!= pNewInfo
->maType
)
415 mxTypeDetection
->removeByName( pOldInfo
->maType
);
417 catch( const Exception
& )
419 TOOLS_WARN_EXCEPTION("filter.xslt", "");
424 filter_info_impl
* pFilterEntry( nullptr );
428 // create or copy filter info
431 // change existing filter entry in filter list box
432 pFilterEntry
= const_cast<filter_info_impl
*>(pOldInfo
);
433 *pFilterEntry
= *pNewInfo
;
437 // add new entry to filter list box
438 pFilterEntry
= new filter_info_impl( *pNewInfo
);
442 // check if we need to copy the template
443 if( bOk
&& !pFilterEntry
->maImportTemplate
.isEmpty() )
445 if( !pFilterEntry
->maImportTemplate
.matchIgnoreAsciiCase( m_sTemplatePath
) )
447 INetURLObject
aSourceURL( pFilterEntry
->maImportTemplate
);
448 if (!aSourceURL
.GetLastName().isEmpty())
450 OUString aDestURL
= m_sTemplatePath
+ pFilterEntry
->maFilterName
+ "/";
451 if( createDirectory( aDestURL
) )
453 aDestURL
+= aSourceURL
.GetLastName();
455 SvFileStream
aInputStream(pFilterEntry
->maImportTemplate
, StreamMode::READ
);
456 Reference
< XInputStream
> xIS( new utl::OInputStreamWrapper( aInputStream
) );
457 SvFileStream
aOutputStream(aDestURL
, StreamMode::WRITE
);
458 Reference
< XOutputStream
> xOS( new utl::OOutputStreamWrapper( aOutputStream
) );
460 if( copyStreams( xIS
, xOS
) )
461 pFilterEntry
->maImportTemplate
= aDestURL
;
469 if( pFilterEntry
->maType
.isEmpty() )
471 pFilterEntry
->maType
= createUniqueTypeName( pNewInfo
->maFilterName
);
474 // update import/export flags
475 if( !pFilterEntry
->maImportXSLT
.isEmpty() )
477 pFilterEntry
->maFlags
|= 1;
481 pFilterEntry
->maFlags
&= ~1;
484 if( !pFilterEntry
->maExportXSLT
.isEmpty() )
486 pFilterEntry
->maFlags
|= 2;
490 pFilterEntry
->maFlags
&= ~2;
492 pFilterEntry
->maFlags
|= 0x80040;
494 // 2. create user data for filter entry
495 Sequence
< OUString
> aUserData( pFilterEntry
->getFilterUserData());
497 // 3. create property values for filter entry
498 Sequence
< PropertyValue
> aFilterData
{
499 comphelper::makePropertyValue(u
"Type"_ustr
, pFilterEntry
->maType
),
500 comphelper::makePropertyValue(u
"UIName"_ustr
, pFilterEntry
->maInterfaceName
),
501 comphelper::makePropertyValue(u
"DocumentService"_ustr
, pFilterEntry
->maDocumentService
),
502 comphelper::makePropertyValue(u
"FilterService"_ustr
, u
"com.sun.star.comp.Writer.XmlFilterAdaptor"_ustr
),
503 comphelper::makePropertyValue(u
"Flags"_ustr
, pFilterEntry
->maFlags
),
504 comphelper::makePropertyValue(u
"UserData"_ustr
, aUserData
),
505 comphelper::makePropertyValue(u
"FileFormatVersion"_ustr
, pFilterEntry
->maFileFormatVersion
),
506 comphelper::makePropertyValue(u
"TemplateName"_ustr
, pFilterEntry
->maImportTemplate
)
509 // 4. insert new or replace existing filter
512 Any
aAny( aFilterData
);
513 if( mxFilterContainer
->hasByName( pFilterEntry
->maFilterName
) )
515 mxFilterContainer
->replaceByName( pFilterEntry
->maFilterName
, aAny
);
519 mxFilterContainer
->insertByName( pFilterEntry
->maFilterName
, aAny
);
522 catch( const Exception
& )
524 TOOLS_WARN_EXCEPTION("filter.xslt", "");
529 // 5. prepare type information
533 if( !pFilterEntry
->maDocType
.match( m_sDocTypePrefix
) )
535 aDocType
= m_sDocTypePrefix
+ pFilterEntry
->maDocType
;
539 aDocType
= pFilterEntry
->maDocType
;
541 if (aDocType
== m_sDocTypePrefix
)
544 Sequence
< PropertyValue
> aValues
{
545 comphelper::makePropertyValue(u
"UIName"_ustr
, pFilterEntry
->maInterfaceName
),
546 comphelper::makePropertyValue(u
"ClipboardFormat"_ustr
, aDocType
),
547 comphelper::makePropertyValue(u
"DocumentIconID"_ustr
, pFilterEntry
->mnDocumentIconID
),
548 comphelper::makePropertyValue(u
"Extensions"_ustr
, createExtensionsSequence( pFilterEntry
->maExtension
))
551 // the detect service will only be registered, if a doctype/search token was specified
552 if (aDocType
.getLength() > m_sDocTypePrefix
.getLength())
555 auto pValues
= aValues
.getArray();
556 pValues
[4].Name
= "DetectService";
557 pValues
[4].Value
<<= u
"com.sun.star.comp.filters.XMLFilterDetect"_ustr
;
560 // 6. insert new or replace existing type information
561 if( mxTypeDetection
.is() )
566 if( mxTypeDetection
->hasByName( pFilterEntry
->maType
) )
568 mxTypeDetection
->replaceByName( pFilterEntry
->maType
, aAny
);
572 mxTypeDetection
->insertByName( pFilterEntry
->maType
, aAny
);
575 catch( const Exception
& )
577 TOOLS_WARN_EXCEPTION("filter.xslt", "");
586 Reference
< XFlushable
> xFlushable( mxTypeDetection
, UNO_QUERY
);
587 if( xFlushable
.is() )
590 catch( const Exception
& )
592 TOOLS_WARN_EXCEPTION("filter.xslt", "");
599 // we failed to add the type, so let's remove the filter
602 mxFilterContainer
->removeByName( pFilterEntry
->maFilterName
);
604 catch( const Exception
& )
606 TOOLS_WARN_EXCEPTION("filter.xslt", "");
614 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
615 if( xFlushable
.is() )
618 catch( const Exception
& )
620 TOOLS_WARN_EXCEPTION("filter.xslt", "");
626 // we failed to add the filter, so let's remove the type
629 mxTypeDetection
->removeByName( pFilterEntry
->maType
);
631 catch( const Exception
& )
633 TOOLS_WARN_EXCEPTION("filter.xslt", "");
642 if( mxExtendedTypeDetection
.is() )
644 OUString
sFilterDetectService( u
"com.sun.star.comp.filters.XMLFilterDetect"_ustr
);
645 if( mxExtendedTypeDetection
->hasByName( sFilterDetectService
) )
647 Sequence
< PropertyValue
> aSequence
;
648 if( mxExtendedTypeDetection
->getByName( sFilterDetectService
) >>= aSequence
)
650 auto aSequenceRange
= asNonConstRange(aSequence
);
651 sal_Int32 nCount
= aSequence
.getLength();
653 for( nIndex
= 0; nIndex
< nCount
; nIndex
++ )
655 if ( aSequence
[nIndex
].Name
== "Types" )
657 Sequence
< OUString
> aTypes
;
658 if( aSequence
[nIndex
].Value
>>= aTypes
)
660 sal_Int32 nStrCount
= aTypes
.getLength();
662 for( nStr
= 0; nStr
< nStrCount
; nStr
++ )
664 if( aTypes
[nStr
] == pFilterEntry
->maType
)
668 if( nStr
== nStrCount
)
670 aTypes
.realloc( nStrCount
+ 1 );
671 aTypes
.getArray()[nStrCount
] = pFilterEntry
->maType
;
673 aSequenceRange
[nIndex
].Value
<<= aTypes
;
675 mxExtendedTypeDetection
->replaceByName( sFilterDetectService
, Any( aSequence
) );
677 Reference
< XFlushable
> xFlushable( mxExtendedTypeDetection
, UNO_QUERY
);
678 if( xFlushable
.is() )
696 changeEntry( pFilterEntry
);
700 addFilterEntry( pFilterEntry
);
701 maFilterVector
.push_back( std::unique_ptr
<filter_info_impl
>(pFilterEntry
) );
708 /** is called when the user clicks the "Test" button */
709 void XMLFilterSettingsDialog::onTest()
711 // get the first selected filter
712 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_selected_id());
715 XMLFilterTestDialog
aDlg(m_xDialog
.get(), mxContext
);
720 void XMLFilterSettingsDialog::onDelete()
722 int nIndex
= m_xFilterListBox
->get_selected_index();
725 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(nIndex
));
728 OUString
aMessage(FilterResId(STR_WARN_DELETE
));
729 aMessage
= aMessage
.replaceFirst( "%s", pInfo
->maFilterName
);
731 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(m_xDialog
.get(),
732 VclMessageType::Warning
, VclButtonsType::YesNo
,
734 xWarn
->set_default_response(RET_YES
);
735 if (xWarn
->run() == RET_YES
)
739 if( mxFilterContainer
->hasByName( pInfo
->maFilterName
) )
741 mxFilterContainer
->removeByName( pInfo
->maFilterName
);
743 bool bTypeStillUsed
= false;
745 // now loop over all filter and see if someone else uses the same type
746 Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
747 OUString
* pFilterName
= aFilterNames
.getArray();
749 const sal_Int32 nCount
= aFilterNames
.getLength();
751 Sequence
< PropertyValue
> aValues
;
753 for( nFilter
= 0; (nFilter
< nCount
) && !bTypeStillUsed
; nFilter
++, pFilterName
++ )
755 Any
aAny( mxFilterContainer
->getByName( *pFilterName
) );
756 if( !(aAny
>>= aValues
) )
759 const sal_Int32
nValueCount( aValues
.getLength() );
760 PropertyValue
* pValues
= aValues
.getArray();
763 for (nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++)
765 if ( pValues
->Name
== "Type" )
768 pValues
->Value
>>= aType
;
769 if( aType
== pInfo
->maType
)
770 bTypeStillUsed
= true;
777 // if the type is not used anymore, remove it also
778 if( !bTypeStillUsed
)
780 if( mxTypeDetection
->hasByName( pInfo
->maType
) )
782 mxTypeDetection
->removeByName( pInfo
->maType
);
786 Reference
< XFlushable
> xFlushable( mxFilterContainer
, UNO_QUERY
);
787 if( xFlushable
.is() )
790 xFlushable
.set( mxTypeDetection
, UNO_QUERY
);
791 if( xFlushable
.is() )
794 // now remove entry from ui
795 m_xFilterListBox
->remove(nIndex
);
797 // and delete the filter entry
798 maFilterVector
.erase(std::find_if( maFilterVector
.begin(), maFilterVector
.end(),
799 [&] (std::unique_ptr
<filter_info_impl
> const & p
)
800 { return p
.get() == pInfo
; }));
803 catch( const Exception
& )
805 TOOLS_WARN_EXCEPTION("filter.xslt", "");
813 void XMLFilterSettingsDialog::onSave()
815 std::vector
<filter_info_impl
*> aFilters
;
819 m_xFilterListBox
->selected_foreach([&](weld::TreeIter
& rEntry
){
820 filter_info_impl
* pInfo
= weld::fromId
<filter_info_impl
*>(m_xFilterListBox
->get_id(rEntry
));
821 aFilters
.push_back(pInfo
);
826 // Open Fileopen-Dialog
827 ::sfx2::FileDialogHelper
aDlg(
828 css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
,
829 FileDialogFlags::NONE
, m_xDialog
.get());
830 aDlg
.SetContext(sfx2::FileDialogHelper::XMLFilterSettings
);
832 OUString
aExtensions( u
"*.jar"_ustr
);
833 OUString aFilterName
= FilterResId(STR_FILTER_PACKAGE
) +
834 " (" + aExtensions
+ ")";
836 aDlg
.AddFilter( aFilterName
, aExtensions
);
838 if ( aDlg
.Execute() != ERRCODE_NONE
)
841 XMLFilterJarHelper
aJarHelper( mxContext
);
842 aJarHelper
.savePackage( aDlg
.GetPath(), aFilters
);
844 INetURLObject
aURL( aDlg
.GetPath() );
846 OUString
sPlaceholder( u
"%s"_ustr
);
851 aMsg
= FilterResId(STR_FILTERS_HAVE_BEEN_SAVED
);
852 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
853 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
857 aMsg
= FilterResId(STR_FILTER_HAS_BEEN_SAVED
);
858 aMsg
= aMsg
.replaceFirst( sPlaceholder
, (*aFilters
.begin())->maFilterName
);
859 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURL
.GetLastName());
862 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
863 VclMessageType::Info
, VclButtonsType::Ok
,
868 void XMLFilterSettingsDialog::onOpen()
870 std::vector
< std::unique_ptr
<filter_info_impl
> > aFilters
;
872 // Open Fileopen-Dialog
873 ::sfx2::FileDialogHelper
aDlg(
874 css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
875 FileDialogFlags::NONE
, m_xDialog
.get());
876 aDlg
.SetContext(sfx2::FileDialogHelper::XMLFilterSettings
);
878 OUString
aExtensions( u
"*.jar"_ustr
);
879 OUString aFilterName
= FilterResId(STR_FILTER_PACKAGE
) +
880 " (" + aExtensions
+ ")";
882 aDlg
.AddFilter( aFilterName
, aExtensions
);
884 if ( aDlg
.Execute() != ERRCODE_NONE
)
887 OUString
aURL( aDlg
.GetPath() );
889 XMLFilterJarHelper
aJarHelper( mxContext
);
890 aJarHelper
.openPackage( aURL
, aFilters
);
893 for (auto& filter
: aFilters
)
895 if( insertOrEdit(filter
.get()) )
897 aFilterName
= filter
->maFilterName
;
907 OUString
sPlaceholder( u
"%s"_ustr
);
911 INetURLObject
aURLObj( aURL
);
912 aMsg
= FilterResId(STR_NO_FILTERS_FOUND
);
913 aMsg
= aMsg
.replaceFirst(sPlaceholder
, aURLObj
.GetLastName());
915 else if( nFilters
== 1 )
917 aMsg
= FilterResId(STR_FILTER_INSTALLED
);
918 aMsg
= aMsg
.replaceFirst( sPlaceholder
, aFilterName
);
923 aMsg
= FilterResId(STR_FILTERS_INSTALLED
);
924 aMsg
= aMsg
.replaceFirst( sPlaceholder
, OUString::number( nFilters
) );
927 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xDialog
.get(),
928 VclMessageType::Info
, VclButtonsType::Ok
,
933 void XMLFilterSettingsDialog::disposeFilterList()
935 maFilterVector
.clear();
936 m_xFilterListBox
->clear();
939 void XMLFilterSettingsDialog::initFilterList()
941 if( mxFilterContainer
.is() )
943 const Sequence
< OUString
> aFilterNames( mxFilterContainer
->getElementNames() );
945 Sequence
< PropertyValue
> aValues
;
947 std::unique_ptr
<filter_info_impl
> pTempFilter( new filter_info_impl
);
948 Sequence
< OUString
> aUserData
;
950 for( OUString
const & filterName
: aFilterNames
)
952 aUserData
.realloc(0);
956 Any
aAny( mxFilterContainer
->getByName( filterName
) );
957 if( !(aAny
>>= aValues
) )
960 OUString aFilterService
;
961 pTempFilter
->maFilterName
= filterName
;
963 const sal_Int32
nValueCount( aValues
.getLength() );
964 PropertyValue
* pValues
= aValues
.getArray();
967 for( nValue
= 0; nValue
< nValueCount
; nValue
++, pValues
++ )
969 if ( pValues
->Name
== "Type" )
971 pValues
->Value
>>= pTempFilter
->maType
;
973 else if ( pValues
->Name
== "UIName" )
975 pValues
->Value
>>= pTempFilter
->maInterfaceName
;
977 else if ( pValues
->Name
== "DocumentService" )
979 pValues
->Value
>>= pTempFilter
->maDocumentService
;
981 else if ( pValues
->Name
== "FilterService" )
983 pValues
->Value
>>= aFilterService
;
985 else if ( pValues
->Name
== "Flags" )
987 pValues
->Value
>>= pTempFilter
->maFlags
;
989 else if ( pValues
->Name
== "UserData" )
991 pValues
->Value
>>= aUserData
;
993 else if ( pValues
->Name
== "FileFormatVersion" )
995 pValues
->Value
>>= pTempFilter
->maFileFormatVersion
;
997 else if ( pValues
->Name
== "TemplateName" )
999 pValues
->Value
>>= pTempFilter
->maImportTemplate
;
1001 else if ( pValues
->Name
== "Finalized" )
1003 pValues
->Value
>>= pTempFilter
->mbReadonly
;
1007 // if this is not a XmlFilterAdaptor entry, skip it
1008 if( aFilterService
!= "com.sun.star.comp.Writer.XmlFilterAdaptor" )
1012 // if we don't have the needed user data, skip it
1013 if( aUserData
.getLength() < 6 )
1016 // if this is not an XSLTFilter entry, skip it
1017 if( aUserData
[0] != "com.sun.star.documentconversion.XSLTFilter" )
1020 // get filter information from userdata
1021 pTempFilter
->mbNeedsXSLT2
= aUserData
[1].toBoolean();
1022 pTempFilter
->maImportService
= aUserData
[2];
1023 pTempFilter
->maExportService
= aUserData
[3];
1024 pTempFilter
->maImportXSLT
= aUserData
[4];
1025 pTempFilter
->maExportXSLT
= aUserData
[5];
1026 if( aUserData
.getLength() >= 8 )
1027 pTempFilter
->maComment
= aUserData
[7];
1029 // get type information
1030 if( mxTypeDetection
.is() )
1034 aAny
= mxTypeDetection
->getByName( pTempFilter
->maType
);
1035 Sequence
< PropertyValue
> aValues2
;
1037 if( aAny
>>= aValues2
)
1039 const sal_Int32
nValueCount2( aValues2
.getLength() );
1040 PropertyValue
* pValues2
= aValues2
.getArray();
1043 for( nValue2
= 0; nValue2
< nValueCount2
; nValue2
++, pValues2
++ )
1045 if ( pValues2
->Name
== "ClipboardFormat" )
1048 pValues2
->Value
>>= aDocType
;
1050 if( aDocType
.match( m_sDocTypePrefix
) )
1051 aDocType
= aDocType
.copy( m_sDocTypePrefix
.getLength() );
1053 pTempFilter
->maDocType
= aDocType
;
1055 else if ( pValues2
->Name
== "Extensions" )
1057 Sequence
< OUString
> aExtensions
;
1058 if( pValues2
->Value
>>= aExtensions
)
1060 pTempFilter
->maExtension
.clear();
1062 sal_Int32
nCount3( aExtensions
.getLength() );
1063 OUString
* pExtensions
= aExtensions
.getArray();
1065 for( n
= 0; n
< nCount3
; n
++ )
1068 pTempFilter
->maExtension
+= ";";
1069 pTempFilter
->maExtension
+= *pExtensions
++;
1073 else if ( pValues2
->Name
== "DocumentIconID" )
1075 pValues2
->Value
>>= pTempFilter
->mnDocumentIconID
;
1077 else if ( pValues2
->Name
== "Finalized" )
1079 // both the filter and the type may be finalized
1081 pValues2
->Value
>>= bTemp
;
1082 pTempFilter
->mbReadonly
|= bTemp
;
1087 catch( const css::container::NoSuchElementException
& )
1089 OSL_FAIL( "Type not found, user error?" ); // TODO: error?
1093 // add entry to internal container and to ui filter list box
1094 maFilterVector
.push_back(std::move(pTempFilter
));
1095 addFilterEntry(maFilterVector
.back().get());
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 OUString
& rDocumentService
, const OUString
& rUINameRes
, const OUString
& rXMLImporter
, const OUString
& rXMLExporter
)
1115 : maDocumentService( rDocumentService
),
1116 maDocumentUIName(Translate::ExpandVariables(rUINameRes
)),
1117 maXMLImporter( rXMLImporter
),
1118 maXMLExporter( rXMLExporter
)
1122 std::vector
< application_info_impl
> const & getApplicationInfos()
1124 static std::vector
< application_info_impl
> const aInfos
1126 { u
"com.sun.star.text.TextDocument"_ustr
,
1127 STR_APPL_NAME_WRITER
,
1128 u
"com.sun.star.comp.Writer.XMLImporter"_ustr
,
1129 u
"com.sun.star.comp.Writer.XMLExporter"_ustr
},
1131 { u
"com.sun.star.sheet.SpreadsheetDocument"_ustr
,
1133 u
"com.sun.star.comp.Calc.XMLImporter"_ustr
,
1134 u
"com.sun.star.comp.Calc.XMLExporter"_ustr
},
1136 { u
"com.sun.star.presentation.PresentationDocument"_ustr
,
1137 STR_APPL_NAME_IMPRESS
,
1138 u
"com.sun.star.comp.Impress.XMLImporter"_ustr
,
1139 u
"com.sun.star.comp.Impress.XMLExporter"_ustr
},
1141 { u
"com.sun.star.drawing.DrawingDocument"_ustr
,
1143 u
"com.sun.star.comp.Draw.XMLImporter"_ustr
,
1144 u
"com.sun.star.comp.Draw.XMLExporter"_ustr
},
1146 // --- oasis file formats...
1147 { u
"com.sun.star.text.TextDocument"_ustr
,
1148 STR_APPL_NAME_OASIS_WRITER
,
1149 u
"com.sun.star.comp.Writer.XMLOasisImporter"_ustr
,
1150 u
"com.sun.star.comp.Writer.XMLOasisExporter"_ustr
},
1152 { u
"com.sun.star.sheet.SpreadsheetDocument"_ustr
,
1153 STR_APPL_NAME_OASIS_CALC
,
1154 u
"com.sun.star.comp.Calc.XMLOasisImporter"_ustr
,
1155 u
"com.sun.star.comp.Calc.XMLOasisExporter"_ustr
},
1157 { u
"com.sun.star.presentation.PresentationDocument"_ustr
,
1158 STR_APPL_NAME_OASIS_IMPRESS
,
1159 u
"com.sun.star.comp.Impress.XMLOasisImporter"_ustr
,
1160 u
"com.sun.star.comp.Impress.XMLOasisExporter"_ustr
},
1162 { u
"com.sun.star.drawing.DrawingDocument"_ustr
,
1163 STR_APPL_NAME_OASIS_DRAW
,
1164 u
"com.sun.star.comp.Draw.XMLOasisImporter"_ustr
,
1165 u
"com.sun.star.comp.Draw.XMLOasisExporter"_ustr
},
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 u
"com.sun.star.documentconversion.XSLTFilter"_ustr
,
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: */