tdf#164627 docx export: consolidate getWordCompatibilityMode()
[LibreOffice.git] / filter / source / xsltdialog / xmlfiltersettingsdialog.cxx
blob6490d0dcf535ae72c470f1e4997cbce5468febba
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
43 #include <algorithm>
44 #include <memory>
46 #include <strings.hrc>
47 #include "xmlfiltersettingsdialog.hxx"
48 #include "xmlfiltertabdialog.hxx"
49 #include "xmlfiltertestdialog.hxx"
50 #include "xmlfilterjar.hxx"
51 #include <strings.hxx>
53 using namespace osl;
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;
61 using ::rtl::Uri;
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 ) );
96 try
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
118 incBusy();
120 if (m_xPBNew.get() == &rButton)
122 onNew();
124 else if (m_xPBEdit.get() == &rButton)
126 onEdit();
128 else if (m_xPBTest.get() == &rButton)
130 onTest();
132 else if (m_xPBDelete.get() == &rButton)
134 onDelete();
136 else if (m_xPBSave.get() == &rButton)
138 onSave();
140 else if (m_xPBOpen.get() == &rButton)
142 onOpen();
145 decBusy();
147 if (m_xPBClose.get() == &rButton)
148 m_xDialog->response(RET_CLOSE);
151 IMPL_LINK_NOARG(XMLFilterSettingsDialog, SelectionChangedHdl_Impl, weld::TreeView&, void)
153 updateStates();
156 IMPL_LINK_NOARG(XMLFilterSettingsDialog, DoubleClickHdl_Impl, weld::TreeView&, bool)
158 onEdit();
159 return true;
162 void XMLFilterSettingsDialog::UpdateWindow()
164 m_xFilterListBox->grab_focus();
165 disposeFilterList();
166 m_xFilterListBox->clear();
167 initFilterList();
168 updateStates();
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;
180 if (bHasSelection)
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 )
190 bIsDefault = true;
191 break;
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());
232 if (!pOldInfo)
233 return;
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) )
243 // change filter
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
254 int nExtensions = 0;
256 int nLength = rExtensions.getLength();
257 if( nLength )
259 // a non empty string has at least one extension
260 nExtensions++;
262 // now count the delimiters ';'
263 const sal_Unicode * pString = rExtensions.getStr();
264 int i;
265 for( i = 0; i < nLength; i++, pString++ )
267 if( *pString == ';' )
268 nExtensions++;
272 Sequence< OUString > aExtensions( nExtensions );
273 auto aExtensionsRange = asNonConstRange(aExtensions);
275 // extract the extensions from the source string and fill the sequence
277 int nLastIndex = 0;
278 int nCurrentIndex = 0;
279 int i;
281 for( i = 0; i < nExtensions; i++ )
283 nLastIndex = rExtensions.indexOf( ';', nLastIndex );
285 if( nLastIndex == -1 )
287 aExtensionsRange[i] = rExtensions.copy( nCurrentIndex );
288 break;
290 else
292 aExtensionsRange[i] = rExtensions.copy( nCurrentIndex, nLastIndex - nCurrentIndex );
293 nCurrentIndex = nLastIndex + 1;
294 nLastIndex = nCurrentIndex;
298 return aExtensions;
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 );
307 sal_Int32 nId = 2;
309 while( mxFilterContainer->hasByName( aFilterName ) )
311 aFilterName = rFilterName + " " + OUString::number( nId++ );
314 return aFilterName;
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 );
323 sal_Int32 nId = 2;
325 while( mxFilterContainer->hasByName( aTypeName ) )
327 aTypeName = rTypeName + " " + OUString::number( nId++ );
330 return aTypeName;
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) )
348 continue;
350 const sal_Int32 nValueCount( aValues.getLength() );
351 PropertyValue* pValues = aValues.getArray();
352 sal_Int32 nValue;
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 );
381 if( nDefaultNumber )
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 )
393 bool bOk = true;
395 if( 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", "");
420 bOk = false;
424 filter_info_impl* pFilterEntry( nullptr );
426 if( bOk )
428 // create or copy filter info
429 if( pOldInfo )
431 // change existing filter entry in filter list box
432 pFilterEntry = const_cast<filter_info_impl*>(pOldInfo);
433 *pFilterEntry = *pNewInfo;
435 else
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;
467 if( bOk )
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;
479 else
481 pFilterEntry->maFlags &= ~1;
484 if( !pFilterEntry->maExportXSLT.isEmpty() )
486 pFilterEntry->maFlags |= 2;
488 else
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 );
517 else
519 mxFilterContainer->insertByName( pFilterEntry->maFilterName, aAny );
522 catch( const Exception& )
524 TOOLS_WARN_EXCEPTION("filter.xslt", "");
525 bOk = false;
529 // 5. prepare type information
530 if( bOk )
532 OUString aDocType;
533 if( !pFilterEntry->maDocType.match( m_sDocTypePrefix ) )
535 aDocType = m_sDocTypePrefix + pFilterEntry->maDocType;
537 else
539 aDocType = pFilterEntry->maDocType;
541 if (aDocType == m_sDocTypePrefix)
542 aDocType.clear();
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())
554 aValues.realloc(5);
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() )
565 Any aAny( aValues );
566 if( mxTypeDetection->hasByName( pFilterEntry->maType ) )
568 mxTypeDetection->replaceByName( pFilterEntry->maType, aAny );
570 else
572 mxTypeDetection->insertByName( pFilterEntry->maType, aAny );
575 catch( const Exception& )
577 TOOLS_WARN_EXCEPTION("filter.xslt", "");
578 bOk = false;
582 if( bOk )
586 Reference< XFlushable > xFlushable( mxTypeDetection, UNO_QUERY );
587 if( xFlushable.is() )
588 xFlushable->flush();
590 catch( const Exception& )
592 TOOLS_WARN_EXCEPTION("filter.xslt", "");
593 bOk = false;
597 if( !bOk )
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", "");
607 bOk = false;
610 else // bOk
614 Reference< XFlushable > xFlushable( mxFilterContainer, UNO_QUERY );
615 if( xFlushable.is() )
616 xFlushable->flush();
618 catch( const Exception& )
620 TOOLS_WARN_EXCEPTION("filter.xslt", "");
621 bOk = false;
624 if( !bOk )
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", "");
640 if( bOk )
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();
652 sal_Int32 nIndex;
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();
661 sal_Int32 nStr;
662 for( nStr = 0; nStr < nStrCount; nStr++ )
664 if( aTypes[nStr] == pFilterEntry->maType )
665 break;
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() )
679 xFlushable->flush();
683 break;
691 // update ui
692 if( bOk )
694 if( pOldInfo )
696 changeEntry( pFilterEntry );
698 else
700 addFilterEntry( pFilterEntry );
701 maFilterVector.push_back( std::unique_ptr<filter_info_impl>(pFilterEntry) );
705 return bOk;
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());
713 if (pInfo)
715 XMLFilterTestDialog aDlg(m_xDialog.get(), mxContext);
716 aDlg.test( *pInfo );
720 void XMLFilterSettingsDialog::onDelete()
722 int nIndex = m_xFilterListBox->get_selected_index();
723 if (nIndex == -1)
724 return;
725 filter_info_impl* pInfo = weld::fromId<filter_info_impl*>(m_xFilterListBox->get_id(nIndex));
726 if (pInfo)
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,
733 aMessage));
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();
750 sal_Int32 nFilter;
751 Sequence< PropertyValue > aValues;
753 for( nFilter = 0; (nFilter < nCount) && !bTypeStillUsed; nFilter++, pFilterName++ )
755 Any aAny( mxFilterContainer->getByName( *pFilterName ) );
756 if( !(aAny >>= aValues) )
757 continue;
759 const sal_Int32 nValueCount( aValues.getLength() );
760 PropertyValue* pValues = aValues.getArray();
761 sal_Int32 nValue;
763 for (nValue = 0; nValue < nValueCount; nValue++, pValues++)
765 if ( pValues->Name == "Type" )
767 OUString aType;
768 pValues->Value >>= aType;
769 if( aType == pInfo->maType )
770 bTypeStillUsed = true;
772 break;
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() )
788 xFlushable->flush();
790 xFlushable.set( mxTypeDetection, UNO_QUERY );
791 if( xFlushable.is() )
792 xFlushable->flush();
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", "");
810 updateStates();
813 void XMLFilterSettingsDialog::onSave()
815 std::vector<filter_info_impl*> aFilters;
817 int nFilters = 0;
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);
822 ++nFilters;
823 return false;
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 )
839 return;
841 XMLFilterJarHelper aJarHelper( mxContext );
842 aJarHelper.savePackage( aDlg.GetPath(), aFilters );
844 INetURLObject aURL( aDlg.GetPath() );
846 OUString sPlaceholder( u"%s"_ustr );
848 OUString aMsg;
849 if( nFilters > 0 )
851 aMsg = FilterResId(STR_FILTERS_HAVE_BEEN_SAVED);
852 aMsg = aMsg.replaceFirst( sPlaceholder, OUString::number( nFilters ) );
853 aMsg = aMsg.replaceFirst(sPlaceholder, aURL.GetLastName());
855 else
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,
864 aMsg));
865 xInfoBox->run();
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 )
885 return;
887 OUString aURL( aDlg.GetPath() );
889 XMLFilterJarHelper aJarHelper( mxContext );
890 aJarHelper.openPackage( aURL, aFilters );
892 int nFilters = 0;
893 for (auto& filter : aFilters)
895 if( insertOrEdit(filter.get()) )
897 aFilterName = filter->maFilterName;
898 nFilters++;
901 filter.reset();
904 disposeFilterList();
905 initFilterList();
907 OUString sPlaceholder( u"%s"_ustr );
908 OUString aMsg;
909 if( nFilters == 0 )
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 );
921 else
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,
929 aMsg));
930 xInfoBox->run();
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) )
958 continue;
960 OUString aFilterService;
961 pTempFilter->maFilterName = filterName;
963 const sal_Int32 nValueCount( aValues.getLength() );
964 PropertyValue* pValues = aValues.getArray();
965 sal_Int32 nValue;
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" )
1009 continue;
1012 // if we don't have the needed user data, skip it
1013 if( aUserData.getLength() < 6 )
1014 continue;
1016 // if this is not an XSLTFilter entry, skip it
1017 if( aUserData[0] != "com.sun.star.documentconversion.XSLTFilter" )
1018 continue;
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();
1041 sal_Int32 nValue2;
1043 for( nValue2 = 0; nValue2 < nValueCount2; nValue2++, pValues2++ )
1045 if ( pValues2->Name == "ClipboardFormat" )
1047 OUString aDocType;
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();
1064 sal_Int32 n;
1065 for( n = 0; n < nCount3; n++ )
1067 if( n > 0 )
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
1080 bool bTemp = false;
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,
1132 STR_APPL_NAME_CALC,
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,
1142 STR_APPL_NAME_DRAW,
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 },
1168 return aInfos;
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)
1179 return &info;
1182 return nullptr;
1185 OUString getApplicationUIName( std::u16string_view rServiceName )
1187 const application_info_impl* pInfo = getApplicationInfo( rServiceName );
1188 if( pInfo )
1190 return pInfo->maDocumentUIName;
1192 else
1194 OUString aRet = FilterResId(STR_UNKNOWN_APPLICATION);
1195 if( !rServiceName.empty() )
1197 aRet += OUString::Concat(" (") + rServiceName + ")";
1199 return aRet;
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);
1222 break;
1227 OUString XMLFilterSettingsDialog::getEntryString( const filter_info_impl* pInfo )
1229 OUString aEntryStr;
1230 if ( !pInfo->maExportService.isEmpty() )
1231 aEntryStr = getApplicationUIName( pInfo->maExportService );
1232 else
1233 aEntryStr = getApplicationUIName( pInfo->maImportService );
1234 aEntryStr += " - ";
1236 if( pInfo->maFlags & 1 )
1238 if( pInfo->maFlags & 2 )
1240 aEntryStr += FilterResId(STR_IMPORT_EXPORT);
1242 else
1244 aEntryStr += FilterResId(STR_IMPORT_ONLY);
1247 else if( pInfo->maFlags & 2 )
1249 aEntryStr += FilterResId(STR_EXPORT_ONLY);
1251 else
1253 aEntryStr += FilterResId(STR_UNDEFINED_FILTER);
1256 return aEntryStr;
1259 filter_info_impl::filter_info_impl()
1260 : maFlags(0x00080040)
1261 , maFileFormatVersion(0)
1262 , mnDocumentIconID(0)
1263 , mbReadonly(false)
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
1290 return
1292 u"com.sun.star.documentconversion.XSLTFilter"_ustr,
1293 OUString::boolean( mbNeedsXSLT2 ),
1294 maImportService,
1295 maExportService,
1296 maImportXSLT,
1297 maExportXSLT,
1298 maComment
1302 OUString string_encode( const OUString & rText )
1304 static constexpr auto uricNoSlash = rtl::createUriCharClass(
1305 u8"!$&'()*+-.0123456789:=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~");
1308 return
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);
1324 sal_Int32 nRead;
1327 nRead = xIS->readBytes( aDataBuffer, nBufferSize );
1329 if( nRead )
1331 if( nRead < nBufferSize )
1333 nBufferSize = nRead;
1334 aDataBuffer.realloc(nRead);
1337 xOS->writeBytes( aDataBuffer );
1340 while( nRead );
1342 xOS->flush();
1344 return true;
1346 catch(const Exception&)
1348 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1351 return false;
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 )
1370 return false;
1375 return true;
1378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */