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 .
22 #include <osl/mutex.hxx>
23 #include <vcl/svapp.hxx>
25 #include "CFStringUtilities.hxx"
26 #include "NSString_OOoAdditions.hxx"
27 #include "NSURL_OOoAdditions.hxx"
29 #include "FilterHelper.hxx"
32 #define CLASS_NAME "FilterEntry"
34 #pragma mark FilterEntry
35 //---------------------------------------------------------------------
36 FilterEntry::FilterEntry( const rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
38 ,m_aSubFilters( _rSubFilters )
40 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", _rTitle);
41 DBG_PRINT_EXIT(CLASS_NAME, __func__);
44 //---------------------------------------------------------------------
45 sal_Bool FilterEntry::hasSubFilters() const
47 // OSL_TRACE(">>> FilterEntry::%s", __func__);
48 sal_Bool bReturn = ( 0 < m_aSubFilters.getLength() );
49 // OSL_TRACE("<<< FilterEntry::%s retVal: %d", __func__, bReturn);
53 //---------------------------------------------------------------------
54 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
56 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
58 _rSubFilterList = m_aSubFilters;
59 sal_Int32 nReturn = m_aSubFilters.getLength();
61 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
68 isFilterString( const rtl::OUString& rFilterString, const char *pMatch )
72 bool bIsFilter = true;
74 rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch));
78 aToken = rFilterString.getToken( 0, ';', nIndex );
79 if( !aToken.match( aMatch ) )
90 //=====================================================================
93 shrinkFilterName( const rtl::OUString aFilterName, bool bAllowNoStar = false )
95 // DBG_PRINT_ENTRY(CLASS_NAME, "shrinkFilterName", "filterName", aFilterName);
97 sal_Int32 nBracketEnd = -1;
98 rtl::OUString aRealName(aFilterName);
100 for( sal_Int32 i = aRealName.getLength() - 1; i > 0; i-- )
102 if( aFilterName[i] == ')' )
104 else if( aFilterName[i] == '(' )
106 sal_Int32 nBracketLen = nBracketEnd - i;
107 if( nBracketEnd <= 0 )
109 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
110 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
111 else if (bAllowNoStar)
113 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
114 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
122 //------------------------------------------------------------------------------------
124 //................................................................................
125 struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
128 const rtl::OUString rTitle;
131 FilterTitleMatch( const rtl::OUString _rTitle ) : rTitle( _rTitle ) { }
133 //............................................................................
134 bool operator () ( const FilterEntry& _rEntry )
137 if( !_rEntry.hasSubFilters() ) {
138 //first try the complete filter name
139 rtl::OUString title = _rEntry.getTitle();
140 bMatch = ( title.equals(rTitle) );
142 //we didn't find a match using the full name, let's give it another
143 //try using the shrunk version
144 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.getTitle() ).trim();
145 bMatch = ( aShrunkName.equals(rTitle) );
149 // a filter group -> search the sub filters
151 _rEntry.endSubFilters() != ::std::find_if(
152 _rEntry.beginSubFilters(),
153 _rEntry.endSubFilters(),
157 return bMatch ? true : false;
160 bool operator () ( const UnoFilterEntry& _rEntry )
162 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.First );
163 bool retVal = aShrunkName.equals(rTitle);
170 #define CLASS_NAME "FilterHelper"
172 FilterHelper::FilterHelper()
173 : m_pFilterList(NULL)
174 , m_pFilterNames(NULL)
176 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
177 DBG_PRINT_EXIT(CLASS_NAME, __func__);
180 FilterHelper::~FilterHelper()
182 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
184 NSAutoreleasePool *pool = [NSAutoreleasePool new];
186 if (NULL != m_pFilterList) {
187 delete m_pFilterList;
190 if (NULL != m_pFilterNames) {
191 //we called retain when we added the strings to the list, so we should release them now
192 for (NSStringList::iterator iter = m_pFilterNames->begin(); iter != m_pFilterNames->end(); iter++) {
195 delete m_pFilterNames;
200 DBG_PRINT_EXIT(CLASS_NAME, __func__);
203 //------------------------------------------------------------------------------------
204 sal_Bool FilterHelper::FilterNameExists( const rtl::OUString rTitle )
206 sal_Bool bRet = sal_False;
210 m_pFilterList->end() != ::std::find_if(
211 m_pFilterList->begin(),
212 m_pFilterList->end(),
213 FilterTitleMatch( rTitle )
219 //------------------------------------------------------------------------------------
220 sal_Bool FilterHelper::FilterNameExists( const UnoFilterList& _rGroupedFilters )
222 sal_Bool bRet = sal_False;
226 const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
227 const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
228 for( ; pStart != pEnd; ++pStart )
229 if( m_pFilterList->end() != ::std::find_if(
230 m_pFilterList->begin(),
231 m_pFilterList->end(),
232 FilterTitleMatch( pStart->First ) ) )
235 bRet = (pStart != pEnd);
241 //------------------------------------------------------------------------------------
242 void FilterHelper::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter )
244 //OSL_TRACE(">>> FilterHelper::%s", __func__);
245 if( NULL == m_pFilterList )
247 m_pFilterList = new FilterList;
249 // set the first filter to the current filter
250 m_aCurrentFilter = _rInitialCurrentFilter;
251 OSL_TRACE("ensureFilterList filter:%s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
253 //OSL_TRACE("<<< FilterHelper::%s", __func__);
256 void FilterHelper::SetCurFilter( const rtl::OUString& rFilter )
258 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "filter", rFilter);
260 SolarMutexGuard aGuard;
262 if(m_aCurrentFilter.equals(rFilter) == false)
264 m_aCurrentFilter = rFilter;
267 //only for output purposes
268 #if OSL_DEBUG_LEVEL > 1
269 FilterList::iterator aFilter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
270 if (aFilter != m_pFilterList->end()) {
271 OUStringList suffixes = aFilter->getFilterSuffixList();
272 if (!suffixes.empty()) {
273 OSL_TRACE("Current active suffixes: ");
274 OUStringList::iterator suffIter = suffixes.begin();
275 while(suffIter != suffixes.end()) {
276 OSL_TRACE("%s", OUStringToOString((*suffIter), RTL_TEXTENCODING_UTF8).getStr());
281 OSL_TRACE("No filter entry was found for that name!");
285 DBG_PRINT_EXIT(CLASS_NAME, __func__);
288 void FilterHelper::SetFilters()
290 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
292 // set the default filter
293 if( m_aCurrentFilter.getLength() > 0 )
295 OSL_TRACE( "Setting current filter to %s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
297 SetCurFilter( m_aCurrentFilter );
300 DBG_PRINT_EXIT(CLASS_NAME, __func__);
303 void FilterHelper::appendFilter(const ::rtl::OUString& aTitle, const ::rtl::OUString& aFilterString)
304 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
305 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString);
307 SolarMutexGuard aGuard;
309 if( FilterNameExists( aTitle ) ) {
310 throw com::sun::star::lang::IllegalArgumentException();
313 // ensure that we have a filter list
314 ensureFilterList( aTitle );
317 OUStringList suffixList;
318 fillSuffixList(suffixList, aFilterString);
319 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) );
321 DBG_PRINT_EXIT(CLASS_NAME, __func__);
324 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle )
325 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
326 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr());
328 SetCurFilter(aTitle);
330 DBG_PRINT_EXIT(CLASS_NAME, __func__);
333 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( )
334 throw( ::com::sun::star::uno::RuntimeException ) {
335 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
337 ::rtl::OUString sReturn = (m_aCurrentFilter);
339 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr());
344 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters )
345 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) {
347 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr());
349 SolarMutexGuard aGuard;
351 //add a separator if this is not the first group to be added
352 sal_Bool bPrependSeparator = m_pFilterList != NULL;
354 // ensure that we have a filter list
355 ::rtl::OUString sInitialCurrentFilter;
356 if( aFilters.getLength() > 0)
357 sInitialCurrentFilter = aFilters[0].First;
358 ensureFilterList( sInitialCurrentFilter );
361 if (bPrependSeparator) {
362 rtl::OUString dash(RTL_CONSTASCII_USTRINGPARAM("-"));
363 OUStringList emptyList;
364 m_pFilterList->push_back(FilterEntry(dash, emptyList));
367 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray();
368 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
369 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) {
370 appendFilter(pSubFilters->First, pSubFilters->Second);
373 DBG_PRINT_EXIT(CLASS_NAME, __func__);
376 // 'fileAttributesAtPath:traverseLink:' is deprecated
377 #if defined LIBO_WERROR && defined __GNUC__
378 #define GCC_VERSION (__GNUC__ * 10000 \
379 + __GNUC_MINOR__ * 100 \
380 + __GNUC_PATCHLEVEL__)
381 #if GCC_VERSION >= 40201
382 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
383 #define DID_TURN_OFF_DEPRECATED_DECLARATIONS_WARNING
387 sal_Bool FilterHelper::filenameMatchesFilter(NSString* sFilename)
389 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
391 if (m_aCurrentFilter == NULL) {
392 OSL_TRACE("filter name is null");
396 NSFileManager *manager = [NSFileManager defaultManager];
397 NSDictionary* pAttribs = [manager fileAttributesAtPath: sFilename traverseLink: NO];
400 NSObject* pType = [pAttribs objectForKey: NSFileType];
401 if( pType && [pType isKindOfClass: [NSString class]] )
403 NSString* pT = (NSString*)pType;
404 if( [pT isEqualToString: NSFileTypeDirectory] ||
405 [pT isEqualToString: NSFileTypeSymbolicLink] )
410 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
411 if (filter == m_pFilterList->end()) {
412 OSL_TRACE("filter not found in list");
416 OUStringList suffixList = filter->getFilterSuffixList();
419 rtl::OUString aName = [sFilename OUString];
420 rtl::OUString allMatcher(RTL_CONSTASCII_USTRINGPARAM(".*"));
421 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) {
422 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) {
429 NSString* pResolved = resolveAlias( sFilename );
432 sal_Bool bResult = filenameMatchesFilter( pResolved );
433 [pResolved autorelease];
438 DBG_PRINT_EXIT(CLASS_NAME, __func__);
443 #ifdef DID_TURN_OFF_DEPRECATED_DECLARATIONS_WARNING
444 #pragma GCC diagnostic error "-Wdeprecated-declarations"
447 FilterList* FilterHelper::getFilterList() {
448 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
449 DBG_PRINT_EXIT(CLASS_NAME, __func__);
451 return m_pFilterList;
454 NSStringList* FilterHelper::getFilterNames() {
455 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
457 if (NULL == m_pFilterList)
459 if (NULL == m_pFilterNames) {
460 //build filter names list
461 m_pFilterNames = new NSStringList;
462 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
463 m_pFilterNames->push_back([[NSString stringWithOUString:iter->getTitle()] retain]);
467 DBG_PRINT_EXIT(CLASS_NAME, __func__);
469 return m_pFilterNames;
472 void FilterHelper::SetFilterAtIndex(unsigned index) {
473 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index);
475 if (m_pFilterList->size() <= index) {
478 FilterEntry entry = m_pFilterList->at(index);
479 SetCurFilter(entry.getTitle());
481 DBG_PRINT_EXIT(CLASS_NAME, __func__);
484 void FilterHelper::fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) {
485 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aSuffixList", suffixString);
487 sal_Int32 nIndex = 0;
489 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex );
490 aSuffixList.push_back(aToken.copy(1));
491 } while ( nIndex >= 0 );
493 DBG_PRINT_EXIT(CLASS_NAME, __func__);
496 int FilterHelper::getCurrentFilterIndex() {
497 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
499 int result = 0;//default to first filter
500 if (m_aCurrentFilter.getLength() > 0) {
502 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++, i++) {
503 rtl::OUString aTitle = iter->getTitle();
504 if (m_aCurrentFilter.equals(aTitle)) {
508 aTitle = shrinkFilterName(aTitle).trim();
509 if (m_aCurrentFilter.equals(aTitle)) {
517 DBG_PRINT_EXIT(CLASS_NAME, __func__, result);
522 OUStringList FilterHelper::getCurrentFilterSuffixList() {
523 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
526 if (m_aCurrentFilter.getLength() > 0) {
527 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
528 rtl::OUString aTitle = iter->getTitle();
529 if (m_aCurrentFilter.equals(aTitle)) {
530 retVal = iter->getFilterSuffixList();
533 aTitle = shrinkFilterName(aTitle).trim();
534 if (m_aCurrentFilter.equals(aTitle)) {
535 retVal = iter->getFilterSuffixList();
542 DBG_PRINT_EXIT(CLASS_NAME, __func__);
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */