1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <functional> 29 #include <algorithm> 30 #include <vos/mutex.hxx> 31 #include <vcl/svapp.hxx> 32 33 // #ifndef _OSL_DIAGNOSE_H_ 34 // #include <osl/diagnose.h> 35 // #endif 36 #include "CFStringUtilities.hxx" 37 #include "NSString_OOoAdditions.hxx" 38 #include "NSURL_OOoAdditions.hxx" 39 40 #include "FilterHelper.hxx" 41 42 #pragma mark DEFINES 43 #define CLASS_NAME "FilterEntry" 44 45 #pragma mark FilterEntry 46 //--------------------------------------------------------------------- 47 FilterEntry::FilterEntry( const rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters ) 48 :m_sTitle( _rTitle ) 49 ,m_aSubFilters( _rSubFilters ) 50 { 51 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", _rTitle); 52 DBG_PRINT_EXIT(CLASS_NAME, __func__); 53 } 54 55 //--------------------------------------------------------------------- 56 sal_Bool FilterEntry::hasSubFilters() const 57 { 58 // OSL_TRACE(">>> FilterEntry::%s", __func__); 59 sal_Bool bReturn = ( 0 < m_aSubFilters.getLength() ); 60 // OSL_TRACE("<<< FilterEntry::%s retVal: %d", __func__, bReturn); 61 return bReturn; 62 } 63 64 //--------------------------------------------------------------------- 65 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList ) 66 { 67 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 68 69 _rSubFilterList = m_aSubFilters; 70 sal_Int32 nReturn = m_aSubFilters.getLength(); 71 72 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); 73 74 return nReturn; 75 } 76 77 #pragma mark statics 78 static bool 79 isFilterString( const rtl::OUString& rFilterString, const char *pMatch ) 80 { 81 sal_Int32 nIndex = 0; 82 rtl::OUString aToken; 83 bool bIsFilter = true; 84 85 rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch)); 86 87 do 88 { 89 aToken = rFilterString.getToken( 0, ';', nIndex ); 90 if( !aToken.match( aMatch ) ) 91 { 92 bIsFilter = false; 93 break; 94 } 95 } 96 while( nIndex >= 0 ); 97 98 return bIsFilter; 99 } 100 101 //===================================================================== 102 103 static rtl::OUString 104 shrinkFilterName( const rtl::OUString aFilterName, bool bAllowNoStar = false ) 105 { 106 // DBG_PRINT_ENTRY(CLASS_NAME, "shrinkFilterName", "filterName", aFilterName); 107 108 int i; 109 int nBracketLen = -1; 110 int nBracketEnd = -1; 111 rtl::OUString rFilterName = aFilterName; 112 const sal_Unicode *pStr = rFilterName; 113 rtl::OUString aRealName = rFilterName; 114 115 for( i = aRealName.getLength() - 1; i > 0; i-- ) 116 { 117 if( pStr[i] == ')' ) 118 nBracketEnd = i; 119 else if( pStr[i] == '(' ) 120 { 121 nBracketLen = nBracketEnd - i; 122 if( nBracketEnd <= 0 ) 123 continue; 124 if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) ) 125 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() ); 126 else if (bAllowNoStar) 127 { 128 if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), ".") ) 129 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() ); 130 } 131 } 132 } 133 134 return aRealName; 135 } 136 137 //------------------------------------------------------------------------------------ 138 namespace { 139 //................................................................................ 140 struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool > 141 { 142 protected: 143 const rtl::OUString rTitle; 144 145 public: 146 FilterTitleMatch( const rtl::OUString _rTitle ) : rTitle( _rTitle ) { } 147 148 //............................................................................ 149 bool operator () ( const FilterEntry& _rEntry ) 150 { 151 sal_Bool bMatch; 152 if( !_rEntry.hasSubFilters() ) { 153 //first try the complete filter name 154 rtl::OUString title = _rEntry.getTitle(); 155 bMatch = ( title.equals(rTitle) ); 156 if (!bMatch) { 157 //we didn't find a match using the full name, let's give it another 158 //try using the shrunk version 159 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.getTitle() ).trim(); 160 bMatch = ( aShrunkName.equals(rTitle) ); 161 } 162 } 163 else 164 // a filter group -> search the sub filters 165 bMatch = 166 _rEntry.endSubFilters() != ::std::find_if( 167 _rEntry.beginSubFilters(), 168 _rEntry.endSubFilters(), 169 *this 170 ); 171 172 return bMatch ? true : false; 173 } 174 175 bool operator () ( const UnoFilterEntry& _rEntry ) 176 { 177 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.First ); 178 bool retVal = aShrunkName.equals(rTitle); 179 return retVal; 180 } 181 }; 182 } 183 184 #undef CLASS_NAME 185 #define CLASS_NAME "FilterHelper" 186 187 FilterHelper::FilterHelper() 188 : m_pFilterList(NULL) 189 , m_pFilterNames(NULL) 190 { 191 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 192 DBG_PRINT_EXIT(CLASS_NAME, __func__); 193 } 194 195 FilterHelper::~FilterHelper() 196 { 197 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 198 199 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 200 201 if (NULL != m_pFilterList) { 202 delete m_pFilterList; 203 } 204 205 if (NULL != m_pFilterNames) { 206 //we called retain when we added the strings to the list, so we should release them now 207 for (NSStringList::iterator iter = m_pFilterNames->begin(); iter != m_pFilterNames->end(); iter++) { 208 [*iter release]; 209 } 210 delete m_pFilterNames; 211 } 212 213 [pool release]; 214 215 DBG_PRINT_EXIT(CLASS_NAME, __func__); 216 } 217 218 //------------------------------------------------------------------------------------ 219 sal_Bool FilterHelper::FilterNameExists( const rtl::OUString rTitle ) 220 { 221 sal_Bool bRet = sal_False; 222 223 if( m_pFilterList ) 224 bRet = 225 m_pFilterList->end() != ::std::find_if( 226 m_pFilterList->begin(), 227 m_pFilterList->end(), 228 FilterTitleMatch( rTitle ) 229 ); 230 231 return bRet; 232 } 233 234 //------------------------------------------------------------------------------------ 235 sal_Bool FilterHelper::FilterNameExists( const UnoFilterList& _rGroupedFilters ) 236 { 237 sal_Bool bRet = sal_False; 238 239 if( m_pFilterList ) 240 { 241 const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray(); 242 const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength(); 243 for( ; pStart != pEnd; ++pStart ) 244 if( m_pFilterList->end() != ::std::find_if( 245 m_pFilterList->begin(), 246 m_pFilterList->end(), 247 FilterTitleMatch( pStart->First ) ) ) 248 break; 249 250 bRet = (pStart != pEnd); 251 } 252 253 return bRet; 254 } 255 256 //------------------------------------------------------------------------------------ 257 void FilterHelper::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter ) 258 { 259 //OSL_TRACE(">>> FilterHelper::%s", __func__); 260 if( NULL == m_pFilterList ) 261 { 262 m_pFilterList = new FilterList; 263 264 // set the first filter to the current filter 265 m_aCurrentFilter = _rInitialCurrentFilter; 266 OSL_TRACE("ensureFilterList filter:%s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr()); 267 } 268 //OSL_TRACE("<<< FilterHelper::%s", __func__); 269 } 270 271 void FilterHelper::SetCurFilter( const rtl::OUString& rFilter ) 272 { 273 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "filter", rFilter); 274 275 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 276 277 if(m_aCurrentFilter.equals(rFilter) == false) 278 { 279 m_aCurrentFilter = rFilter; 280 } 281 282 //only for output purposes 283 #if OSL_DEBUG_LEVEL > 1 284 FilterList::iterator aFilter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter)); 285 if (aFilter != m_pFilterList->end()) { 286 OUStringList suffixes = aFilter->getFilterSuffixList(); 287 if (!suffixes.empty()) { 288 OSL_TRACE("Current active suffixes: "); 289 OUStringList::iterator suffIter = suffixes.begin(); 290 while(suffIter != suffixes.end()) { 291 OSL_TRACE("%s", OUStringToOString((*suffIter), RTL_TEXTENCODING_UTF8).getStr()); 292 suffIter++; 293 } 294 } 295 } else { 296 OSL_TRACE("No filter entry was found for that name!"); 297 } 298 #endif 299 300 DBG_PRINT_EXIT(CLASS_NAME, __func__); 301 } 302 303 void FilterHelper::SetFilters() 304 { 305 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 306 307 // set the default filter 308 if( m_aCurrentFilter.getLength() > 0 ) 309 { 310 OSL_TRACE( "Setting current filter to %s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr()); 311 312 SetCurFilter( m_aCurrentFilter ); 313 } 314 315 DBG_PRINT_EXIT(CLASS_NAME, __func__); 316 } 317 318 void FilterHelper::appendFilter(const ::rtl::OUString& aTitle, const ::rtl::OUString& aFilterString) 319 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) { 320 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString); 321 322 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 323 324 if( FilterNameExists( aTitle ) ) { 325 throw com::sun::star::lang::IllegalArgumentException(); 326 } 327 328 // ensure that we have a filter list 329 ensureFilterList( aTitle ); 330 331 // append the filter 332 OUStringList suffixList; 333 fillSuffixList(suffixList, aFilterString); 334 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) ); 335 336 DBG_PRINT_EXIT(CLASS_NAME, __func__); 337 } 338 339 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle ) 340 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) { 341 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr()); 342 343 SetCurFilter(aTitle); 344 345 DBG_PRINT_EXIT(CLASS_NAME, __func__); 346 } 347 348 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( ) 349 throw( ::com::sun::star::uno::RuntimeException ) { 350 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 351 352 ::rtl::OUString sReturn = (m_aCurrentFilter); 353 354 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr()); 355 356 return sReturn; 357 } 358 359 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters ) 360 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) { 361 362 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr()); 363 364 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 365 366 //add a separator if this is not the first group to be added 367 sal_Bool bPrependSeparator = m_pFilterList != NULL; 368 369 // ensure that we have a filter list 370 ::rtl::OUString sInitialCurrentFilter; 371 if( aFilters.getLength() > 0) 372 sInitialCurrentFilter = aFilters[0].First; 373 ensureFilterList( sInitialCurrentFilter ); 374 375 // append the filter 376 if (bPrependSeparator) { 377 rtl::OUString dash = rtl::OUString::createFromAscii("-"); 378 OUStringList emptyList; 379 m_pFilterList->push_back(FilterEntry(dash, emptyList)); 380 } 381 382 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray(); 383 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength(); 384 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) { 385 appendFilter(pSubFilters->First, pSubFilters->Second); 386 } 387 388 DBG_PRINT_EXIT(CLASS_NAME, __func__); 389 } 390 391 sal_Bool FilterHelper::filenameMatchesFilter(NSString* sFilename) 392 { 393 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 394 395 if (m_aCurrentFilter == NULL) { 396 OSL_TRACE("filter name is null"); 397 return sal_True; 398 } 399 400 NSFileManager *manager = [NSFileManager defaultManager]; 401 NSDictionary* pAttribs = [manager fileAttributesAtPath: sFilename traverseLink: NO]; 402 if( pAttribs ) 403 { 404 NSObject* pType = [pAttribs objectForKey: NSFileType]; 405 if( pType && [pType isKindOfClass: [NSString class]] ) 406 { 407 NSString* pT = (NSString*)pType; 408 if( [pT isEqualToString: NSFileTypeDirectory] || 409 [pT isEqualToString: NSFileTypeSymbolicLink] ) 410 return sal_True; 411 } 412 } 413 414 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter)); 415 if (filter == m_pFilterList->end()) { 416 OSL_TRACE("filter not found in list"); 417 return sal_True; 418 } 419 420 OUStringList suffixList = filter->getFilterSuffixList(); 421 422 { 423 rtl::OUString aName = [sFilename OUString]; 424 rtl::OUString allMatcher = rtl::OUString::createFromAscii(".*"); 425 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) { 426 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) { 427 return sal_True; 428 } 429 } 430 } 431 432 // might be an alias 433 NSString* pResolved = resolveAlias( sFilename ); 434 if( pResolved ) 435 { 436 sal_Bool bResult = filenameMatchesFilter( pResolved ); 437 [pResolved autorelease]; 438 if( bResult ) 439 return sal_True; 440 } 441 442 DBG_PRINT_EXIT(CLASS_NAME, __func__); 443 444 return sal_False; 445 } 446 447 FilterList* FilterHelper::getFilterList() { 448 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 449 DBG_PRINT_EXIT(CLASS_NAME, __func__); 450 451 return m_pFilterList; 452 } 453 454 NSStringList* FilterHelper::getFilterNames() { 455 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 456 457 if (NULL == m_pFilterList) 458 return NULL; 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]); 464 } 465 } 466 467 DBG_PRINT_EXIT(CLASS_NAME, __func__); 468 469 return m_pFilterNames; 470 } 471 472 void FilterHelper::SetFilterAtIndex(unsigned index) { 473 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index); 474 475 if (m_pFilterList->size() <= index) { 476 index = 0; 477 } 478 FilterEntry entry = m_pFilterList->at(index); 479 SetCurFilter(entry.getTitle()); 480 481 DBG_PRINT_EXIT(CLASS_NAME, __func__); 482 } 483 484 void FilterHelper::fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) { 485 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aSuffixList", suffixString); 486 487 sal_Int32 nIndex = 0; 488 do { 489 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex ); 490 aSuffixList.push_back(aToken.copy(1)); 491 } while ( nIndex >= 0 ); 492 493 DBG_PRINT_EXIT(CLASS_NAME, __func__); 494 } 495 496 int FilterHelper::getCurrentFilterIndex() { 497 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 498 499 int result = 0;//default to first filter 500 if (m_aCurrentFilter.getLength() > 0) { 501 int i = 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)) { 505 result = i; 506 break; 507 } else { 508 aTitle = shrinkFilterName(aTitle).trim(); 509 if (m_aCurrentFilter.equals(aTitle)) { 510 result = i; 511 break; 512 } 513 } 514 } 515 } 516 517 DBG_PRINT_EXIT(CLASS_NAME, __func__, result); 518 519 return result; 520 } 521 522 OUStringList FilterHelper::getCurrentFilterSuffixList() { 523 DBG_PRINT_ENTRY(CLASS_NAME, __func__); 524 525 OUStringList retVal; 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(); 531 break; 532 } else { 533 aTitle = shrinkFilterName(aTitle).trim(); 534 if (m_aCurrentFilter.equals(aTitle)) { 535 retVal = iter->getFilterSuffixList(); 536 break; 537 } 538 } 539 } 540 } 541 542 DBG_PRINT_EXIT(CLASS_NAME, __func__); 543 544 return retVal; 545 } 546