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"
35 void fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) {
38 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex );
39 aSuffixList.push_back(aToken.copy(1));
40 } while ( nIndex >= 0 );
46 #define CLASS_NAME "FilterEntry"
48 #pragma mark FilterEntry
50 FilterEntry::FilterEntry( const rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
52 ,m_aSubFilters( _rSubFilters )
54 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", _rTitle);
55 DBG_PRINT_EXIT(CLASS_NAME, __func__);
59 bool FilterEntry::hasSubFilters() const
61 // OSL_TRACE(">>> FilterEntry::%s", __func__);
62 bool bReturn = ( 0 < m_aSubFilters.getLength() );
63 // OSL_TRACE("<<< FilterEntry::%s retVal: %d", __func__, bReturn);
68 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
70 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
72 _rSubFilterList = m_aSubFilters;
73 sal_Int32 nReturn = m_aSubFilters.getLength();
75 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
82 isFilterString( const rtl::OUString& rFilterString, const char *pMatch )
86 bool bIsFilter = true;
88 rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch));
92 aToken = rFilterString.getToken( 0, ';', nIndex );
93 if( !aToken.match( aMatch ) )
107 shrinkFilterName( const rtl::OUString& aFilterName, bool bAllowNoStar = false )
109 // DBG_PRINT_ENTRY(CLASS_NAME, "shrinkFilterName", "filterName", aFilterName);
111 sal_Int32 nBracketEnd = -1;
112 rtl::OUString aRealName(aFilterName);
114 for( sal_Int32 i = aRealName.getLength() - 1; i > 0; i-- )
116 if( aFilterName[i] == ')' )
118 else if( aFilterName[i] == '(' )
120 sal_Int32 nBracketLen = nBracketEnd - i;
121 if( nBracketEnd <= 0 )
123 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
124 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
125 else if (bAllowNoStar)
127 if( isFilterString( aFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
128 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
139 struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
142 const rtl::OUString rTitle;
145 FilterTitleMatch( const rtl::OUString& _rTitle ) : rTitle( _rTitle ) { }
148 bool operator () ( const FilterEntry& _rEntry )
151 if( !_rEntry.hasSubFilters() ) {
152 //first try the complete filter name
153 rtl::OUString title = _rEntry.getTitle();
154 bMatch = title.equals(rTitle);
156 //we didn't find a match using the full name, let's give it another
157 //try using the shrunk version
158 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.getTitle() ).trim();
159 bMatch = aShrunkName.equals(rTitle);
163 // a filter group -> search the sub filters
165 _rEntry.endSubFilters() != ::std::find_if(
166 _rEntry.beginSubFilters(),
167 _rEntry.endSubFilters(),
174 bool operator () ( const UnoFilterEntry& _rEntry )
176 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.First );
177 bool retVal = aShrunkName.equals(rTitle);
184 #define CLASS_NAME "FilterHelper"
186 FilterHelper::FilterHelper()
187 : m_pFilterList(NULL)
188 , m_pFilterNames(NULL)
190 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
191 DBG_PRINT_EXIT(CLASS_NAME, __func__);
194 FilterHelper::~FilterHelper()
196 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
198 NSAutoreleasePool *pool = [NSAutoreleasePool new];
200 if (NULL != m_pFilterList) {
201 delete m_pFilterList;
204 if (NULL != m_pFilterNames) {
205 //we called retain when we added the strings to the list, so we should release them now
206 for (NSStringList::iterator iter = m_pFilterNames->begin(); iter != m_pFilterNames->end(); iter++) {
209 delete m_pFilterNames;
214 DBG_PRINT_EXIT(CLASS_NAME, __func__);
218 bool FilterHelper::FilterNameExists( const rtl::OUString& rTitle )
224 m_pFilterList->end() != ::std::find_if(
225 m_pFilterList->begin(),
226 m_pFilterList->end(),
227 FilterTitleMatch( rTitle )
234 bool FilterHelper::FilterNameExists( const UnoFilterList& _rGroupedFilters )
240 const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
241 const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
242 for( ; pStart != pEnd; ++pStart )
243 if( m_pFilterList->end() != ::std::find_if(
244 m_pFilterList->begin(),
245 m_pFilterList->end(),
246 FilterTitleMatch( pStart->First ) ) )
249 bRet = (pStart != pEnd);
256 void FilterHelper::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter )
258 //OSL_TRACE(">>> FilterHelper::%s", __func__);
259 if( NULL == m_pFilterList )
261 m_pFilterList = new FilterList;
263 // set the first filter to the current filter
264 m_aCurrentFilter = _rInitialCurrentFilter;
265 OSL_TRACE("ensureFilterList filter:%s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
267 //OSL_TRACE("<<< FilterHelper::%s", __func__);
270 void FilterHelper::SetCurFilter( const rtl::OUString& rFilter )
272 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "filter", rFilter);
274 SolarMutexGuard aGuard;
276 if(!m_aCurrentFilter.equals(rFilter))
278 m_aCurrentFilter = rFilter;
281 //only for output purposes
282 #if OSL_DEBUG_LEVEL > 1
283 FilterList::iterator aFilter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
284 if (aFilter != m_pFilterList->end()) {
285 OUStringList suffixes = aFilter->getFilterSuffixList();
286 if (!suffixes.empty()) {
287 OSL_TRACE("Current active suffixes: ");
288 OUStringList::iterator suffIter = suffixes.begin();
289 while(suffIter != suffixes.end()) {
290 OSL_TRACE("%s", OUStringToOString((*suffIter), RTL_TEXTENCODING_UTF8).getStr());
295 OSL_TRACE("No filter entry was found for that name!");
299 DBG_PRINT_EXIT(CLASS_NAME, __func__);
302 void FilterHelper::SetFilters()
304 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
306 // set the default filter
307 if( m_aCurrentFilter.getLength() > 0 )
309 OSL_TRACE( "Setting current filter to %s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
311 SetCurFilter( m_aCurrentFilter );
314 DBG_PRINT_EXIT(CLASS_NAME, __func__);
317 void FilterHelper::appendFilter(const ::rtl::OUString& aTitle, const ::rtl::OUString& aFilterString)
318 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
319 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString);
321 SolarMutexGuard aGuard;
323 if( FilterNameExists( aTitle ) ) {
324 throw com::sun::star::lang::IllegalArgumentException();
327 // ensure that we have a filter list
328 ensureFilterList( aTitle );
331 OUStringList suffixList;
332 fillSuffixList(suffixList, aFilterString);
333 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) );
335 DBG_PRINT_EXIT(CLASS_NAME, __func__);
338 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle )
339 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
340 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr());
342 SetCurFilter(aTitle);
344 DBG_PRINT_EXIT(CLASS_NAME, __func__);
347 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( )
348 throw( ::com::sun::star::uno::RuntimeException ) {
349 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
351 ::rtl::OUString sReturn = (m_aCurrentFilter);
353 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr());
358 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters )
359 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) {
361 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr());
363 SolarMutexGuard aGuard;
365 //add a separator if this is not the first group to be added
366 bool bPrependSeparator = m_pFilterList != NULL;
368 // ensure that we have a filter list
369 ::rtl::OUString sInitialCurrentFilter;
370 if( aFilters.getLength() > 0)
371 sInitialCurrentFilter = aFilters[0].First;
372 ensureFilterList( sInitialCurrentFilter );
375 if (bPrependSeparator) {
376 rtl::OUString dash("-");
377 OUStringList emptyList;
378 m_pFilterList->push_back(FilterEntry(dash, emptyList));
381 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray();
382 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
383 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) {
384 appendFilter(pSubFilters->First, pSubFilters->Second);
387 DBG_PRINT_EXIT(CLASS_NAME, __func__);
390 bool FilterHelper::filenameMatchesFilter(NSString* sFilename)
392 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
394 if (m_aCurrentFilter == NULL) {
395 OSL_TRACE("filter name is null");
399 NSFileManager *manager = [NSFileManager defaultManager];
400 NSDictionary* pAttribs = [manager attributesOfItemAtPath: sFilename error: nil];
403 NSObject* pType = [pAttribs objectForKey: NSFileType];
404 if( pType && [pType isKindOfClass: [NSString class]] )
406 NSString* pT = (NSString*)pType;
407 if( [pT isEqualToString: NSFileTypeDirectory] ||
408 [pT isEqualToString: NSFileTypeSymbolicLink] )
413 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
414 if (filter == m_pFilterList->end()) {
415 OSL_TRACE("filter not found in list");
419 OUStringList suffixList = filter->getFilterSuffixList();
422 rtl::OUString aName = [sFilename OUString];
423 rtl::OUString allMatcher(".*");
424 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) {
425 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) {
432 NSString* pResolved = resolveAlias( sFilename );
435 bool bResult = filenameMatchesFilter( pResolved );
436 [pResolved autorelease];
441 DBG_PRINT_EXIT(CLASS_NAME, __func__);
446 FilterList* FilterHelper::getFilterList() {
447 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
448 DBG_PRINT_EXIT(CLASS_NAME, __func__);
450 return m_pFilterList;
453 NSStringList* FilterHelper::getFilterNames() {
454 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
456 if (NULL == m_pFilterList)
458 if (NULL == m_pFilterNames) {
459 //build filter names list
460 m_pFilterNames = new NSStringList;
461 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
462 m_pFilterNames->push_back([[NSString stringWithOUString:iter->getTitle()] retain]);
466 DBG_PRINT_EXIT(CLASS_NAME, __func__);
468 return m_pFilterNames;
471 void FilterHelper::SetFilterAtIndex(unsigned index) {
472 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index);
474 if (m_pFilterList->size() <= index) {
477 FilterEntry entry = m_pFilterList->at(index);
478 SetCurFilter(entry.getTitle());
480 DBG_PRINT_EXIT(CLASS_NAME, __func__);
483 int FilterHelper::getCurrentFilterIndex() {
484 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
486 int result = 0;//default to first filter
487 if (m_aCurrentFilter.getLength() > 0) {
489 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++, i++) {
490 rtl::OUString aTitle = iter->getTitle();
491 if (m_aCurrentFilter.equals(aTitle)) {
495 aTitle = shrinkFilterName(aTitle).trim();
496 if (m_aCurrentFilter.equals(aTitle)) {
504 DBG_PRINT_EXIT(CLASS_NAME, __func__, result);
509 OUStringList FilterHelper::getCurrentFilterSuffixList() {
510 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
513 if (m_aCurrentFilter.getLength() > 0) {
514 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
515 rtl::OUString aTitle = iter->getTitle();
516 if (m_aCurrentFilter.equals(aTitle)) {
517 retVal = iter->getFilterSuffixList();
520 aTitle = shrinkFilterName(aTitle).trim();
521 if (m_aCurrentFilter.equals(aTitle)) {
522 retVal = iter->getFilterSuffixList();
529 DBG_PRINT_EXIT(CLASS_NAME, __func__);
534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */