nss: upgrade to release 3.73
[LibreOffice.git] / filter / source / xsltdialog / xmlfiltersettingsdialog.cxx
blob256fb9a8c55148ea3f9f383995171af04d4ca949
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>
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>
41 #include <algorithm>
42 #include <memory>
44 #include <strings.hrc>
45 #include "xmlfiltersettingsdialog.hxx"
46 #include "xmlfiltertabdialog.hxx"
47 #include "xmlfiltertestdialog.hxx"
48 #include "xmlfilterjar.hxx"
49 #include <strings.hxx>
51 using namespace osl;
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;
59 using ::rtl::Uri;
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 ) );
98 try
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
120 incBusy();
122 if (m_xPBNew.get() == &rButton)
124 onNew();
126 else if (m_xPBEdit.get() == &rButton)
128 onEdit();
130 else if (m_xPBTest.get() == &rButton)
132 onTest();
134 else if (m_xPBDelete.get() == &rButton)
136 onDelete();
138 else if (m_xPBSave.get() == &rButton)
140 onSave();
142 else if (m_xPBOpen.get() == &rButton)
144 onOpen();
147 decBusy();
149 if (m_xPBClose.get() == &rButton)
150 m_xDialog->response(RET_CLOSE);
153 IMPL_LINK_NOARG(XMLFilterSettingsDialog, SelectionChangedHdl_Impl, weld::TreeView&, void)
155 updateStates();
158 IMPL_LINK_NOARG(XMLFilterSettingsDialog, DoubleClickHdl_Impl, weld::TreeView&, bool)
160 onEdit();
161 return true;
164 void XMLFilterSettingsDialog::UpdateWindow()
166 m_xFilterListBox->grab_focus();
167 disposeFilterList();
168 m_xFilterListBox->clear();
169 initFilterList();
170 updateStates();
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;
182 if (bHasSelection)
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 )
192 bIsDefault = true;
193 break;
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());
234 if (!pOldInfo)
235 return;
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) )
245 // change filter
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
256 int nExtensions = 0;
258 int nLength = rExtensions.getLength();
259 if( nLength )
261 // a non empty string has at least one extension
262 nExtensions++;
264 // now count the delimiters ';'
265 const sal_Unicode * pString = rExtensions.getStr();
266 int i;
267 for( i = 0; i < nLength; i++, pString++ )
269 if( *pString == ';' )
270 nExtensions++;
274 Sequence< OUString > aExtensions( nExtensions );
276 // extract the extensions from the source string and fill the sequence
278 int nLastIndex = 0;
279 int nCurrentIndex = 0;
280 int i;
282 for( i = 0; i < nExtensions; i++ )
284 nLastIndex = rExtensions.indexOf( ';', nLastIndex );
286 if( nLastIndex == -1 )
288 aExtensions[i] = rExtensions.copy( nCurrentIndex );
289 break;
291 else
293 aExtensions[i] = rExtensions.copy( nCurrentIndex, nLastIndex - nCurrentIndex );
294 nCurrentIndex = nLastIndex + 1;
295 nLastIndex = nCurrentIndex;
299 return aExtensions;
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 );
308 sal_Int32 nId = 2;
310 while( mxFilterContainer->hasByName( aFilterName ) )
312 aFilterName = rFilterName + " " + OUString::number( nId++ );
315 return aFilterName;
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 );
324 sal_Int32 nId = 2;
326 while( mxFilterContainer->hasByName( aTypeName ) )
328 aTypeName = rTypeName + " " + OUString::number( nId++ );
331 return aTypeName;
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) )
349 continue;
351 const sal_Int32 nValueCount( aValues.getLength() );
352 PropertyValue* pValues = aValues.getArray();
353 sal_Int32 nValue;
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 );
382 if( nDefaultNumber )
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 )
394 bool bOk = true;
396 if( 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", "");
421 bOk = false;
425 filter_info_impl* pFilterEntry( nullptr );
427 if( bOk )
429 // create or copy filter info
430 if( pOldInfo )
432 // change existing filter entry in filter list box
433 pFilterEntry = const_cast<filter_info_impl*>(pOldInfo);
434 *pFilterEntry = *pNewInfo;
436 else
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;
468 if( bOk )
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;
480 else
482 pFilterEntry->maFlags &= ~1;
485 if( !pFilterEntry->maExportXSLT.isEmpty() )
487 pFilterEntry->maFlags |= 2;
489 else
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 );
533 else
535 mxFilterContainer->insertByName( pFilterEntry->maFilterName, aAny );
538 catch( const Exception& )
540 TOOLS_WARN_EXCEPTION("filter.xslt", "");
541 bOk = false;
545 // 5. prepare type information
546 if( bOk )
548 Sequence< PropertyValue > aValues(4);
550 aValues[0].Name = "UIName";
551 aValues[0].Value <<= pFilterEntry->maInterfaceName;
552 aValues[1].Name = "ClipboardFormat";
553 OUString aDocType;
554 if( !pFilterEntry->maDocType.match( m_sDocTypePrefix ) )
556 aDocType = m_sDocTypePrefix + pFilterEntry->maDocType;
558 else
560 aDocType = pFilterEntry->maDocType;
562 if (aDocType == m_sDocTypePrefix)
563 aValues[1].Value <<= OUString();
564 else
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())
576 aValues.realloc(5);
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 );
591 else
593 mxTypeDetection->insertByName( pFilterEntry->maType, aAny );
596 catch( const Exception& )
598 TOOLS_WARN_EXCEPTION("filter.xslt", "");
599 bOk = false;
603 if( bOk )
607 Reference< XFlushable > xFlushable( mxTypeDetection, UNO_QUERY );
608 if( xFlushable.is() )
609 xFlushable->flush();
611 catch( const Exception& )
613 TOOLS_WARN_EXCEPTION("filter.xslt", "");
614 bOk = false;
618 if( !bOk )
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", "");
628 bOk = false;
631 else // bOk
635 Reference< XFlushable > xFlushable( mxFilterContainer, UNO_QUERY );
636 if( xFlushable.is() )
637 xFlushable->flush();
639 catch( const Exception& )
641 TOOLS_WARN_EXCEPTION("filter.xslt", "");
642 bOk = false;
645 if( !bOk )
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", "");
661 if( bOk )
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();
672 sal_Int32 nIndex;
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();
681 sal_Int32 nStr;
682 for( nStr = 0; nStr < nStrCount; nStr++ )
684 if( aTypes[nStr] == pFilterEntry->maType )
685 break;
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() )
699 xFlushable->flush();
703 break;
711 // update ui
712 if( bOk )
714 if( pOldInfo )
716 changeEntry( pFilterEntry );
718 else
720 addFilterEntry( pFilterEntry );
721 maFilterVector.push_back( std::unique_ptr<filter_info_impl>(pFilterEntry) );
725 return bOk;
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());
733 if (pInfo)
735 XMLFilterTestDialog aDlg(m_xDialog.get(), mxContext);
736 aDlg.test( *pInfo );
740 void XMLFilterSettingsDialog::onDelete()
742 int nIndex = m_xFilterListBox->get_selected_index();
743 if (nIndex == -1)
744 return;
745 filter_info_impl* pInfo = reinterpret_cast<filter_info_impl*>(m_xFilterListBox->get_id(nIndex).toInt64());
746 if (pInfo)
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,
753 aMessage));
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();
770 sal_Int32 nFilter;
771 Sequence< PropertyValue > aValues;
773 for( nFilter = 0; (nFilter < nCount) && !bTypeStillUsed; nFilter++, pFilterName++ )
775 Any aAny( mxFilterContainer->getByName( *pFilterName ) );
776 if( !(aAny >>= aValues) )
777 continue;
779 const sal_Int32 nValueCount( aValues.getLength() );
780 PropertyValue* pValues = aValues.getArray();
781 sal_Int32 nValue;
783 for (nValue = 0; nValue < nValueCount; nValue++, pValues++)
785 if ( pValues->Name == "Type" )
787 OUString aType;
788 pValues->Value >>= aType;
789 if( aType == pInfo->maType )
790 bTypeStillUsed = true;
792 break;
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() )
808 xFlushable->flush();
810 xFlushable.set( mxTypeDetection, UNO_QUERY );
811 if( xFlushable.is() )
812 xFlushable->flush();
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", "");
830 updateStates();
833 void XMLFilterSettingsDialog::onSave()
835 std::vector<filter_info_impl*> aFilters;
837 int nFilters = 0;
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);
842 ++nFilters;
843 return false;
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 )
858 return;
860 XMLFilterJarHelper aJarHelper( mxContext );
861 aJarHelper.savePackage( aDlg.GetPath(), aFilters );
863 INetURLObject aURL( aDlg.GetPath() );
865 OUString sPlaceholder( "%s" );
867 OUString aMsg;
868 if( nFilters > 0 )
870 aMsg = XsltResId(STR_FILTERS_HAVE_BEEN_SAVED);
871 aMsg = aMsg.replaceFirst( sPlaceholder, OUString::number( nFilters ) );
872 aMsg = aMsg.replaceFirst(sPlaceholder, aURL.GetLastName());
874 else
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,
883 aMsg));
884 xInfoBox->run();
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 )
903 return;
905 OUString aURL( aDlg.GetPath() );
907 XMLFilterJarHelper aJarHelper( mxContext );
908 aJarHelper.openPackage( aURL, aFilters );
910 int nFilters = 0;
911 for (auto& filter : aFilters)
913 if( insertOrEdit(filter.get()) )
915 aFilterName = filter->maFilterName;
916 nFilters++;
919 filter.reset();
922 disposeFilterList();
923 initFilterList();
925 OUString sPlaceholder( "%s" );
926 OUString aMsg;
927 if( nFilters == 0 )
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 );
939 else
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,
947 aMsg));
948 xInfoBox->run();
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) )
976 continue;
978 OUString aFilterService;
979 pTempFilter->maFilterName = filterName;
981 const sal_Int32 nValueCount( aValues.getLength() );
982 PropertyValue* pValues = aValues.getArray();
983 sal_Int32 nValue;
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" )
1027 continue;
1030 // if we don't have the needed user data, skip it
1031 if( aUserData.getLength() < 6 )
1032 continue;
1034 // if this is not an XSLTFilter entry, skip it
1035 if( aUserData[0] != "com.sun.star.documentconversion.XSLTFilter" )
1036 continue;
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();
1059 sal_Int32 nValue2;
1061 for( nValue2 = 0; nValue2 < nValueCount2; nValue2++, pValues2++ )
1063 if ( pValues2->Name == "ClipboardFormat" )
1065 OUString aDocType;
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();
1082 sal_Int32 n;
1083 for( n = 0; n < nCount3; n++ )
1085 if( n > 0 )
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
1098 bool bTemp = false;
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",
1151 STR_APPL_NAME_CALC,
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",
1161 STR_APPL_NAME_DRAW,
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" },
1187 return aInfos;
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)
1198 return &info;
1201 return nullptr;
1204 OUString getApplicationUIName( const OUString& rServiceName )
1206 const application_info_impl* pInfo = getApplicationInfo( rServiceName );
1207 if( pInfo )
1209 return pInfo->maDocumentUIName;
1211 else
1213 OUString aRet = XsltResId(STR_UNKNOWN_APPLICATION);
1214 if( !rServiceName.isEmpty() )
1216 aRet += " (" + rServiceName + ")";
1218 return aRet;
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);
1241 break;
1246 OUString XMLFilterSettingsDialog::getEntryString( const filter_info_impl* pInfo )
1248 OUString aEntryStr;
1249 if ( !pInfo->maExportService.isEmpty() )
1250 aEntryStr = getApplicationUIName( pInfo->maExportService );
1251 else
1252 aEntryStr = getApplicationUIName( pInfo->maImportService );
1253 aEntryStr += " - ";
1255 if( pInfo->maFlags & 1 )
1257 if( pInfo->maFlags & 2 )
1259 aEntryStr += XsltResId(STR_IMPORT_EXPORT);
1261 else
1263 aEntryStr += XsltResId(STR_IMPORT_ONLY);
1266 else if( pInfo->maFlags & 2 )
1268 aEntryStr += XsltResId(STR_EXPORT_ONLY);
1270 else
1272 aEntryStr += XsltResId(STR_UNDEFINED_FILTER);
1275 return aEntryStr;
1278 filter_info_impl::filter_info_impl()
1279 : maFlags(0x00080040)
1280 , maFileFormatVersion(0)
1281 , mnDocumentIconID(0)
1282 , mbReadonly(false)
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;
1319 return aUserData;
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);
1358 sal_Int32 nRead;
1361 nRead = xIS->readBytes( aDataBuffer, nBufferSize );
1363 if( nRead )
1365 if( nRead < nBufferSize )
1367 nBufferSize = nRead;
1368 aDataBuffer.realloc(nRead);
1371 xOS->writeBytes( aDataBuffer );
1374 while( nRead );
1376 xOS->flush();
1378 return true;
1380 catch(const Exception&)
1382 TOOLS_WARN_EXCEPTION("filter.xslt", "");
1385 return false;
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 )
1404 return false;
1409 return true;
1412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */