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 "sal/config.h"
24 #include <osl/mutex.hxx>
25 #include <vcl/svapp.hxx>
27 #include "CFStringUtilities.hxx"
28 #include "NSString_OOoAdditions.hxx"
29 #include "NSURL_OOoAdditions.hxx"
31 #include "FilterHelper.hxx"
34 #define CLASS_NAME "FilterEntry"
36 #pragma mark FilterEntry
37 //---------------------------------------------------------------------
38 FilterEntry::FilterEntry( const rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
40 ,m_aSubFilters( _rSubFilters )
42 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", _rTitle);
43 DBG_PRINT_EXIT(CLASS_NAME, __func__);
46 //---------------------------------------------------------------------
47 sal_Bool FilterEntry::hasSubFilters() const
49 // OSL_TRACE(">>> FilterEntry::%s", __func__);
50 sal_Bool bReturn = ( 0 < m_aSubFilters.getLength() );
51 // OSL_TRACE("<<< FilterEntry::%s retVal: %d", __func__, bReturn);
55 //---------------------------------------------------------------------
56 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
58 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
60 _rSubFilterList = m_aSubFilters;
61 sal_Int32 nReturn = m_aSubFilters.getLength();
63 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
70 isFilterString( const rtl::OUString& rFilterString, const char *pMatch )
74 bool bIsFilter = true;
76 rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch));
80 aToken = rFilterString.getToken( 0, ';', nIndex );
81 if( !aToken.match( aMatch ) )
92 //=====================================================================
95 shrinkFilterName( const rtl::OUString aFilterName, bool bAllowNoStar = false )
97 // DBG_PRINT_ENTRY(CLASS_NAME, "shrinkFilterName", "filterName", aFilterName);
99 sal_Int32 nBracketEnd = -1;
100 rtl::OUString aRealName(aFilterName);
102 for( sal_Int32 i = aRealName.getLength() - 1; i > 0; i-- )
104 if( aFilterName[i] == ')' )
106 else if( aFilterName[i] == '(' )
108 sal_Int32 nBracketLen = nBracketEnd - i;
109 if( nBracketEnd <= 0 )
111 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
112 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
113 else if (bAllowNoStar)
115 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
116 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
124 //------------------------------------------------------------------------------------
126 //................................................................................
127 struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
130 const rtl::OUString rTitle;
133 FilterTitleMatch( const rtl::OUString _rTitle ) : rTitle( _rTitle ) { }
135 //............................................................................
136 bool operator () ( const FilterEntry& _rEntry )
139 if( !_rEntry.hasSubFilters() ) {
140 //first try the complete filter name
141 rtl::OUString title = _rEntry.getTitle();
142 bMatch = ( title.equals(rTitle) );
144 //we didn't find a match using the full name, let's give it another
145 //try using the shrunk version
146 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.getTitle() ).trim();
147 bMatch = ( aShrunkName.equals(rTitle) );
151 // a filter group -> search the sub filters
153 _rEntry.endSubFilters() != ::std::find_if(
154 _rEntry.beginSubFilters(),
155 _rEntry.endSubFilters(),
159 return bMatch ? true : false;
162 bool operator () ( const UnoFilterEntry& _rEntry )
164 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.First );
165 bool retVal = aShrunkName.equals(rTitle);
172 #define CLASS_NAME "FilterHelper"
174 FilterHelper::FilterHelper()
175 : m_pFilterList(NULL)
176 , m_pFilterNames(NULL)
178 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
179 DBG_PRINT_EXIT(CLASS_NAME, __func__);
182 FilterHelper::~FilterHelper()
184 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
186 NSAutoreleasePool *pool = [NSAutoreleasePool new];
188 if (NULL != m_pFilterList) {
189 delete m_pFilterList;
192 if (NULL != m_pFilterNames) {
193 //we called retain when we added the strings to the list, so we should release them now
194 for (NSStringList::iterator iter = m_pFilterNames->begin(); iter != m_pFilterNames->end(); iter++) {
197 delete m_pFilterNames;
202 DBG_PRINT_EXIT(CLASS_NAME, __func__);
205 //------------------------------------------------------------------------------------
206 sal_Bool FilterHelper::FilterNameExists( const rtl::OUString rTitle )
208 sal_Bool bRet = sal_False;
212 m_pFilterList->end() != ::std::find_if(
213 m_pFilterList->begin(),
214 m_pFilterList->end(),
215 FilterTitleMatch( rTitle )
221 //------------------------------------------------------------------------------------
222 sal_Bool FilterHelper::FilterNameExists( const UnoFilterList& _rGroupedFilters )
224 sal_Bool bRet = sal_False;
228 const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
229 const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
230 for( ; pStart != pEnd; ++pStart )
231 if( m_pFilterList->end() != ::std::find_if(
232 m_pFilterList->begin(),
233 m_pFilterList->end(),
234 FilterTitleMatch( pStart->First ) ) )
237 bRet = (pStart != pEnd);
243 //------------------------------------------------------------------------------------
244 void FilterHelper::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter )
246 //OSL_TRACE(">>> FilterHelper::%s", __func__);
247 if( NULL == m_pFilterList )
249 m_pFilterList = new FilterList;
251 // set the first filter to the current filter
252 m_aCurrentFilter = _rInitialCurrentFilter;
253 OSL_TRACE("ensureFilterList filter:%s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
255 //OSL_TRACE("<<< FilterHelper::%s", __func__);
258 void FilterHelper::SetCurFilter( const rtl::OUString& rFilter )
260 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "filter", rFilter);
262 SolarMutexGuard aGuard;
264 if(m_aCurrentFilter.equals(rFilter) == false)
266 m_aCurrentFilter = rFilter;
269 //only for output purposes
270 #if OSL_DEBUG_LEVEL > 1
271 FilterList::iterator aFilter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
272 if (aFilter != m_pFilterList->end()) {
273 OUStringList suffixes = aFilter->getFilterSuffixList();
274 if (!suffixes.empty()) {
275 OSL_TRACE("Current active suffixes: ");
276 OUStringList::iterator suffIter = suffixes.begin();
277 while(suffIter != suffixes.end()) {
278 OSL_TRACE("%s", OUStringToOString((*suffIter), RTL_TEXTENCODING_UTF8).getStr());
283 OSL_TRACE("No filter entry was found for that name!");
287 DBG_PRINT_EXIT(CLASS_NAME, __func__);
290 void FilterHelper::SetFilters()
292 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
294 // set the default filter
295 if( m_aCurrentFilter.getLength() > 0 )
297 OSL_TRACE( "Setting current filter to %s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
299 SetCurFilter( m_aCurrentFilter );
302 DBG_PRINT_EXIT(CLASS_NAME, __func__);
305 void FilterHelper::appendFilter(const ::rtl::OUString& aTitle, const ::rtl::OUString& aFilterString)
306 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
307 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString);
309 SolarMutexGuard aGuard;
311 if( FilterNameExists( aTitle ) ) {
312 throw com::sun::star::lang::IllegalArgumentException();
315 // ensure that we have a filter list
316 ensureFilterList( aTitle );
319 OUStringList suffixList;
320 fillSuffixList(suffixList, aFilterString);
321 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) );
323 DBG_PRINT_EXIT(CLASS_NAME, __func__);
326 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle )
327 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
328 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr());
330 SetCurFilter(aTitle);
332 DBG_PRINT_EXIT(CLASS_NAME, __func__);
335 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( )
336 throw( ::com::sun::star::uno::RuntimeException ) {
337 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
339 ::rtl::OUString sReturn = (m_aCurrentFilter);
341 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr());
346 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters )
347 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) {
349 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr());
351 SolarMutexGuard aGuard;
353 //add a separator if this is not the first group to be added
354 sal_Bool bPrependSeparator = m_pFilterList != NULL;
356 // ensure that we have a filter list
357 ::rtl::OUString sInitialCurrentFilter;
358 if( aFilters.getLength() > 0)
359 sInitialCurrentFilter = aFilters[0].First;
360 ensureFilterList( sInitialCurrentFilter );
363 if (bPrependSeparator) {
364 rtl::OUString dash("-");
365 OUStringList emptyList;
366 m_pFilterList->push_back(FilterEntry(dash, emptyList));
369 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray();
370 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
371 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) {
372 appendFilter(pSubFilters->First, pSubFilters->Second);
375 DBG_PRINT_EXIT(CLASS_NAME, __func__);
378 // 'fileAttributesAtPath:traverseLink:' is deprecated
379 #if HAVE_GCC_PRAGMA_DIAGNOSTIC_MODIFY
380 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
383 sal_Bool FilterHelper::filenameMatchesFilter(NSString* sFilename)
385 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
387 if (m_aCurrentFilter == NULL) {
388 OSL_TRACE("filter name is null");
392 NSFileManager *manager = [NSFileManager defaultManager];
393 NSDictionary* pAttribs = [manager fileAttributesAtPath: sFilename traverseLink: NO];
396 NSObject* pType = [pAttribs objectForKey: NSFileType];
397 if( pType && [pType isKindOfClass: [NSString class]] )
399 NSString* pT = (NSString*)pType;
400 if( [pT isEqualToString: NSFileTypeDirectory] ||
401 [pT isEqualToString: NSFileTypeSymbolicLink] )
406 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
407 if (filter == m_pFilterList->end()) {
408 OSL_TRACE("filter not found in list");
412 OUStringList suffixList = filter->getFilterSuffixList();
415 rtl::OUString aName = [sFilename OUString];
416 rtl::OUString allMatcher(".*");
417 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) {
418 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) {
425 NSString* pResolved = resolveAlias( sFilename );
428 sal_Bool bResult = filenameMatchesFilter( pResolved );
429 [pResolved autorelease];
434 DBG_PRINT_EXIT(CLASS_NAME, __func__);
439 #if HAVE_GCC_PRAGMA_DIAGNOSTIC_MODIFY
440 #pragma GCC diagnostic error "-Wdeprecated-declarations"
443 FilterList* FilterHelper::getFilterList() {
444 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
445 DBG_PRINT_EXIT(CLASS_NAME, __func__);
447 return m_pFilterList;
450 NSStringList* FilterHelper::getFilterNames() {
451 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
453 if (NULL == m_pFilterList)
455 if (NULL == m_pFilterNames) {
456 //build filter names list
457 m_pFilterNames = new NSStringList;
458 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
459 m_pFilterNames->push_back([[NSString stringWithOUString:iter->getTitle()] retain]);
463 DBG_PRINT_EXIT(CLASS_NAME, __func__);
465 return m_pFilterNames;
468 void FilterHelper::SetFilterAtIndex(unsigned index) {
469 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index);
471 if (m_pFilterList->size() <= index) {
474 FilterEntry entry = m_pFilterList->at(index);
475 SetCurFilter(entry.getTitle());
477 DBG_PRINT_EXIT(CLASS_NAME, __func__);
480 void FilterHelper::fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) {
481 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aSuffixList", suffixString);
483 sal_Int32 nIndex = 0;
485 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex );
486 aSuffixList.push_back(aToken.copy(1));
487 } while ( nIndex >= 0 );
489 DBG_PRINT_EXIT(CLASS_NAME, __func__);
492 int FilterHelper::getCurrentFilterIndex() {
493 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
495 int result = 0;//default to first filter
496 if (m_aCurrentFilter.getLength() > 0) {
498 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++, i++) {
499 rtl::OUString aTitle = iter->getTitle();
500 if (m_aCurrentFilter.equals(aTitle)) {
504 aTitle = shrinkFilterName(aTitle).trim();
505 if (m_aCurrentFilter.equals(aTitle)) {
513 DBG_PRINT_EXIT(CLASS_NAME, __func__, result);
518 OUStringList FilterHelper::getCurrentFilterSuffixList() {
519 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
522 if (m_aCurrentFilter.getLength() > 0) {
523 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
524 rtl::OUString aTitle = iter->getTitle();
525 if (m_aCurrentFilter.equals(aTitle)) {
526 retVal = iter->getFilterSuffixList();
529 aTitle = shrinkFilterName(aTitle).trim();
530 if (m_aCurrentFilter.equals(aTitle)) {
531 retVal = iter->getFilterSuffixList();
538 DBG_PRINT_EXIT(CLASS_NAME, __func__);
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */