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 //------------------------------------------------------------------------
29 // includes
30 //------------------------------------------------------------------------
31 
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
35 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
36 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
37 #include <cppuhelper/interfacecontainer.h>
38 #include <osl/diagnose.h>
39 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
40 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
41 #include <com/sun/star/uno/Any.hxx>
42 #include <FPServiceInfo.hxx>
43 #include <vos/mutex.hxx>
44 #include <vcl/svapp.hxx>
45 
46 #ifndef _TOOLS_URLOBJ_HXX
47 #include <tools/urlobj.hxx>
48 #endif
49 #include "resourceprovider.hxx"
50 
51 #ifndef _SV_RC_H
52 #include <tools/rc.hxx>
53 #endif
54 #include <osl/file.hxx>
55 #include "CFStringUtilities.hxx"
56 #include "NSString_OOoAdditions.hxx"
57 #include "NSURL_OOoAdditions.hxx"
58 
59 #include <iostream>
60 
61 #include "SalAquaFilePicker.hxx"
62 
63 
64 #pragma mark DEFINES
65 
66 #define LABEL_TOGGLE( elem ) \
67 case elem : \
68 aLabel = aResProvider.getResString( CHECKBOX_##elem ); \
69     setLabel( CHECKBOX_##elem, aLabel ); \
70     break
71 
72 #define CLASS_NAME "SalAquaFilePicker"
73 
74 //------------------------------------------------------------------------
75 // namespace directives
76 //------------------------------------------------------------------------
77 
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::ui::dialogs;
80 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
81 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
82 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
83 using namespace ::com::sun::star::lang;
84 using namespace ::com::sun::star::beans;
85 using namespace ::com::sun::star::uno;
86 
87 //------------------------------------------------------------------------
88 // helper functions
89 //------------------------------------------------------------------------
90 
91 namespace
92 {
93     // controling event notifications
94     const bool STARTUP_SUSPENDED = true;
95     const bool STARTUP_ALIVE     = false;
96 
97     uno::Sequence<rtl::OUString> SAL_CALL FilePicker_getSupportedServiceNames()
98     {
99         uno::Sequence<rtl::OUString> aRet(3);
100         aRet[0] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.FilePicker" );
101         aRet[1] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.SystemFilePicker" );
102         aRet[2] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.AquaFilePicker" );
103         return aRet;
104     }
105 }
106 
107 #pragma mark Constructor
108 //-----------------------------------------------------------------------------------------
109 // constructor
110 //-----------------------------------------------------------------------------------------
111 
112 SalAquaFilePicker::SalAquaFilePicker( const uno::Reference<lang::XMultiServiceFactory>& xServiceMgr ) :
113 cppu::WeakComponentImplHelper8<XFilterManager, XFilterGroupManager, XFilePickerControlAccess, XFilePickerNotifier,
114  lang::XInitialization, util::XCancellable, lang::XEventListener, lang::XServiceInfo>( m_rbHelperMtx )
115 , m_xServiceMgr( xServiceMgr )
116 , m_pFilterHelper( NULL )
117 {
118     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
119 
120     m_pDelegate = [[AquaFilePickerDelegate alloc] initWithFilePicker:this];
121     m_pControlHelper->setFilePickerDelegate(m_pDelegate);
122 
123     DBG_PRINT_EXIT(CLASS_NAME, __func__);
124 }
125 
126 SalAquaFilePicker::~SalAquaFilePicker()
127 {
128     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
129 
130     if (NULL != m_pFilterHelper)
131         delete m_pFilterHelper;
132 
133     [m_pDelegate release];
134 
135     DBG_PRINT_EXIT(CLASS_NAME, __func__);
136 }
137 
138 
139 #pragma mark XFilePickerNotifier
140 //------------------------------------------------------------------------------------
141 // XFilePickerNotifier
142 //------------------------------------------------------------------------------------
143 
144 void SAL_CALL SalAquaFilePicker::addFilePickerListener( const uno::Reference<XFilePickerListener>& xListener )
145     throw( uno::RuntimeException )
146 {
147     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
148 
149     ::vos::OGuard aGuard( Application::GetSolarMutex() );
150     m_xListener = xListener;
151 
152     DBG_PRINT_EXIT(CLASS_NAME, __func__);
153 }
154 
155 void SAL_CALL SalAquaFilePicker::removeFilePickerListener( const uno::Reference<XFilePickerListener>& )
156     throw( uno::RuntimeException )
157 {
158     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
159 
160     ::vos::OGuard aGuard( Application::GetSolarMutex() );
161     m_xListener.clear();
162 
163     DBG_PRINT_EXIT(CLASS_NAME, __func__);
164 }
165 
166 #pragma mark XAsynchronousExecutableDialog
167 //-----------------------------------------------------------------------------------------
168 // XExecutableDialog functions
169 //-----------------------------------------------------------------------------------------
170 void SAL_CALL SalAquaFilePicker::setTitle( const rtl::OUString& aTitle ) throw( uno::RuntimeException )
171 {
172     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle);
173 
174     ::vos::OGuard aGuard( Application::GetSolarMutex() );
175     implsetTitle(aTitle);
176 
177     DBG_PRINT_EXIT(CLASS_NAME, __func__);
178 }
179 
180 sal_Int16 SAL_CALL SalAquaFilePicker::execute() throw( uno::RuntimeException )
181 {
182     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
183 
184     ::vos::OGuard aGuard( Application::GetSolarMutex() );
185 
186     sal_Int16 retVal = 0;
187 
188     implInitialize();
189 
190     // if m_pDialog is nil after initialization, something must have gone wrong before
191     // or there was no initialization (see issue http://www.openoffice.org/issues/show_bug.cgi?id=100214)
192     if (m_pDialog == nil) {
193         //throw uno::RuntimeException(rtl::OUString::createFromAscii("The dialog was not properly initialized!"), static_cast< XFilePicker* >( this ));
194         m_nDialogType = NAVIGATIONSERVICES_OPEN;
195     }
196 
197     if (m_pFilterHelper) {
198         m_pFilterHelper->SetFilters();
199     }
200 
201     if (m_nDialogType == NAVIGATIONSERVICES_SAVE) {
202         if (m_sSaveFileName.getLength() == 0) {
203             //if no filename is set, NavigationServices will set the name to "untitled". We don't want this!
204             //So let's try to get the window title to get the real untitled name
205             NSWindow *frontWindow = [NSApp keyWindow];
206             if (NULL != frontWindow) {
207                 NSString *windowTitle = [frontWindow title];
208                 if (windowTitle != nil) {
209                     rtl::OUString ouName = [windowTitle OUString];
210                     //a window title will typically be something like "Untitled1 - OpenOffice.org Writer"
211                     //but we only want the "Untitled1" part of it
212                     sal_Int32 indexOfDash = ouName.indexOf(rtl::OUString::createFromAscii(" - "));
213                     if (indexOfDash > -1) {
214                         m_sSaveFileName = ouName.copy(0,indexOfDash);
215                         if (m_sSaveFileName.getLength() > 0) {
216                             setDefaultName(m_sSaveFileName);
217                         }
218                     } else {
219                         OSL_TRACE("no dash present in window title");
220                     }
221                 } else {
222                     OSL_TRACE("couldn't get window title");
223                 }
224             } else {
225                 OSL_TRACE("no front window found");
226             }
227         }
228     }
229 
230     //Set the delegate to be notified of certain events
231     [m_pDialog setDelegate:m_pDelegate];
232 
233     int nStatus = runandwaitforresult();
234 
235     [m_pDialog setDelegate:nil];
236 
237     switch( nStatus )
238     {
239         case NSOKButton:
240             OSL_TRACE("The dialog returned OK");
241             retVal = ExecutableDialogResults::OK;
242             break;
243 
244         case NSCancelButton:
245             OSL_TRACE("The dialog was cancelled by the user!");
246             retVal = ExecutableDialogResults::CANCEL;
247             break;
248 
249         default:
250             throw uno::RuntimeException(rtl::OUString::createFromAscii("The dialog returned with an unknown result!"), static_cast< XFilePicker* >( this ));
251             break;
252     }
253 
254     DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
255 
256     return retVal;
257 }
258 
259 
260 #pragma mark XFilePicker
261 //-----------------------------------------------------------------------------------------
262 // XFilePicker functions
263 //-----------------------------------------------------------------------------------------
264 
265 void SAL_CALL SalAquaFilePicker::setMultiSelectionMode( sal_Bool bMode ) throw( uno::RuntimeException )
266 {
267     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "multiSelectable?", bMode);
268 
269     ::vos::OGuard aGuard( Application::GetSolarMutex() );
270 
271     if (m_nDialogType == NAVIGATIONSERVICES_OPEN) {
272         [(NSOpenPanel*)m_pDialog setAllowsMultipleSelection:YES];
273         OSL_TRACE("dialog allows multi-selection? %d", [(NSOpenPanel*)m_pDialog allowsMultipleSelection]);
274     }
275 
276     DBG_PRINT_EXIT(CLASS_NAME, __func__);
277 }
278 
279 void SAL_CALL SalAquaFilePicker::setDefaultName( const rtl::OUString& aName )
280 throw( uno::RuntimeException )
281 {
282     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "name", aName);
283 
284     ::vos::OGuard aGuard( Application::GetSolarMutex() );
285 
286     m_sSaveFileName = aName;
287 
288     DBG_PRINT_EXIT(CLASS_NAME, __func__);
289 }
290 
291 void SAL_CALL SalAquaFilePicker::setDisplayDirectory( const rtl::OUString& rDirectory )
292 throw( lang::IllegalArgumentException, uno::RuntimeException )
293 {
294     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "directory", rDirectory);
295 
296     ::vos::OGuard aGuard( Application::GetSolarMutex() );
297 
298     implsetDisplayDirectory(rDirectory);
299 
300     DBG_PRINT_EXIT(CLASS_NAME, __func__);
301 }
302 
303 rtl::OUString SAL_CALL SalAquaFilePicker::getDisplayDirectory() throw( uno::RuntimeException )
304 {
305     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
306 
307     rtl::OUString retVal = implgetDisplayDirectory();
308 
309     DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
310     return retVal;
311 }
312 
313 uno::Sequence<rtl::OUString> SAL_CALL SalAquaFilePicker::getFiles() throw( uno::RuntimeException )
314 {
315     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
316 
317     ::vos::OGuard aGuard( Application::GetSolarMutex() );
318 
319     // OSL_TRACE("starting work");
320     /*
321      * If more than one file is selected in an OpenDialog, then the first result
322      * is the directory and the remaining results contain just the files' names
323      * without the basedir path.
324      */
325     NSArray *files = nil;
326     if (m_nDialogType == NAVIGATIONSERVICES_OPEN) {
327         files = [(NSOpenPanel*)m_pDialog URLs];
328     }
329     else if (m_nDialogType == NAVIGATIONSERVICES_SAVE) {
330         files = [NSArray arrayWithObjects:[m_pDialog URL], nil];
331     }
332 
333     long nFiles = [files count];
334     OSL_TRACE("# of items: %d", nFiles);
335 
336     uno::Sequence< rtl::OUString > aSelectedFiles(nFiles > 1 ? nFiles + 1 : nFiles);
337 
338     for(int nIndex = 0; nIndex < nFiles; nIndex += 1)
339     {
340         NSURL *url = [files objectAtIndex:nIndex];
341         OSL_TRACE("handling %s", [[url description] UTF8String]);
342         InfoType info = FULLPATH;
343         if (nFiles > 1) {
344             //just get the file's name (only in OpenDialog)
345             info = FILENAME;
346         }
347         OUString sFileOrDirURL = [url OUStringForInfo:info];
348 
349         //get the directory information, only on the first file processed
350         if (nIndex == 0) {
351             OUString sDirectoryURL = [url OUStringForInfo:PATHWITHOUTLASTCOMPONENT];
352 
353             if (nFiles > 1) {
354                 aSelectedFiles[0] = OUString(sDirectoryURL);
355             }
356         }
357 
358         short nSequenceIndex = nFiles > 1 ? nIndex + 1 : nIndex;
359         aSelectedFiles[nSequenceIndex] = sFileOrDirURL;
360 
361         OSL_TRACE("Returned file in getFiles: \"%s\".", OUStringToOString(sFileOrDirURL, RTL_TEXTENCODING_UTF8).getStr());
362     }
363 
364     DBG_PRINT_EXIT(CLASS_NAME, __func__);
365     return aSelectedFiles;
366 }
367 
368 #pragma mark XFilterManager
369 //-----------------------------------------------------------------------------------------
370 // XFilterManager functions
371 //-----------------------------------------------------------------------------------------
372 
373 void SAL_CALL SalAquaFilePicker::appendFilter( const rtl::OUString& aTitle, const rtl::OUString& aFilter )
374 throw( lang::IllegalArgumentException, uno::RuntimeException )
375 {
376     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
377 
378     ::vos::OGuard aGuard( Application::GetSolarMutex() );
379 
380     ensureFilterHelper();
381     m_pFilterHelper->appendFilter( aTitle, aFilter );
382     m_pControlHelper->setFilterControlNeeded(YES);
383 
384     DBG_PRINT_EXIT(CLASS_NAME, __func__);
385 }
386 
387 void SAL_CALL SalAquaFilePicker::setCurrentFilter( const rtl::OUString& aTitle )
388 throw( lang::IllegalArgumentException, uno::RuntimeException )
389 {
390     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
391     OSL_TRACE( "Setting current filter to %s",
392                OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
393 
394     ::vos::OGuard aGuard( Application::GetSolarMutex() );
395 
396     ensureFilterHelper();
397     m_pFilterHelper->setCurrentFilter(aTitle);
398     updateFilterUI();
399 
400     updateSaveFileNameExtension();
401 
402     DBG_PRINT_EXIT(CLASS_NAME, __func__);
403 }
404 
405 rtl::OUString SAL_CALL SalAquaFilePicker::getCurrentFilter() throw( uno::RuntimeException )
406 {
407     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
408     ::vos::OGuard aGuard( Application::GetSolarMutex() );
409 
410     ensureFilterHelper();
411 
412     DBG_PRINT_EXIT(CLASS_NAME, __func__);
413     return m_pFilterHelper->getCurrentFilter();
414 }
415 
416 #pragma mark XFilterGroupManager
417 //-----------------------------------------------------------------------------------------
418 // XFilterGroupManager functions
419 //-----------------------------------------------------------------------------------------
420 
421 void SAL_CALL SalAquaFilePicker::appendFilterGroup( const rtl::OUString& sGroupTitle, const uno::Sequence<beans::StringPair>& aFilters )
422 throw( lang::IllegalArgumentException, uno::RuntimeException )
423 {
424     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
425     ::vos::OGuard aGuard( Application::GetSolarMutex() );
426 
427     ensureFilterHelper();
428     m_pFilterHelper->appendFilterGroup(sGroupTitle, aFilters);
429     m_pControlHelper->setFilterControlNeeded(YES);
430     DBG_PRINT_EXIT(CLASS_NAME, __func__);
431 }
432 
433 #pragma mark XFilePickerControlAccess
434 //------------------------------------------------------------------------------------
435 // XFilePickerControlAccess functions
436 //------------------------------------------------------------------------------------
437 
438 void SAL_CALL SalAquaFilePicker::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
439 throw( uno::RuntimeException )
440 {
441     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
442 
443     ::vos::OGuard aGuard( Application::GetSolarMutex() );
444 
445     m_pControlHelper->setValue(nControlId, nControlAction, rValue);
446 
447     if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION && m_nDialogType == NAVIGATIONSERVICES_SAVE) {
448         updateSaveFileNameExtension();
449     }
450 
451     DBG_PRINT_EXIT(CLASS_NAME, __func__);
452 }
453 
454 uno::Any SAL_CALL SalAquaFilePicker::getValue( sal_Int16 nControlId, sal_Int16 nControlAction )
455 throw( uno::RuntimeException )
456 {
457     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
458 
459     uno::Any aValue = m_pControlHelper->getValue(nControlId, nControlAction);
460 
461     DBG_PRINT_EXIT(CLASS_NAME, __func__);
462     return aValue;
463 }
464 
465 void SAL_CALL SalAquaFilePicker::enableControl( sal_Int16 nControlId, sal_Bool bEnable )
466 throw( uno::RuntimeException )
467 {
468     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
469 
470     m_pControlHelper->enableControl(nControlId, bEnable);
471 
472     DBG_PRINT_EXIT(CLASS_NAME, __func__);
473 }
474 
475 void SAL_CALL SalAquaFilePicker::setLabel( sal_Int16 nControlId, const ::rtl::OUString& aLabel )
476 throw( uno::RuntimeException )
477 {
478     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
479 
480     ::vos::OGuard aGuard( Application::GetSolarMutex() );
481 
482     NSString* sLabel = [NSString stringWithOUString:aLabel];
483     m_pControlHelper->setLabel( nControlId, sLabel ) ;
484 
485     DBG_PRINT_EXIT(CLASS_NAME, __func__);
486 }
487 
488 rtl::OUString SAL_CALL SalAquaFilePicker::getLabel( sal_Int16 nControlId )
489 throw( uno::RuntimeException )
490 {
491     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
492     DBG_PRINT_EXIT(CLASS_NAME, __func__);
493 
494     return m_pControlHelper->getLabel(nControlId);
495 }
496 
497 #pragma mark XInitialization
498 //------------------------------------------------------------------------------------
499 // XInitialization
500 //------------------------------------------------------------------------------------
501 
502 void SAL_CALL SalAquaFilePicker::initialize( const uno::Sequence<uno::Any>& aArguments )
503 throw( uno::Exception, uno::RuntimeException )
504 {
505     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "arguments size", aArguments.getLength());
506 
507     ::vos::OGuard aGuard( Application::GetSolarMutex() );
508 
509     // parameter checking
510     uno::Any aAny;
511     if( 0 == aArguments.getLength() )
512         throw lang::IllegalArgumentException(rtl::OUString::createFromAscii( "no arguments" ),
513                                              static_cast<XFilePicker*>( this ), 1 );
514 
515     aAny = aArguments[0];
516 
517     if( ( aAny.getValueType() != ::getCppuType( ( sal_Int16* )0 ) ) &&
518         (aAny.getValueType() != ::getCppuType( ( sal_Int8* )0 ) ) )
519         throw lang::IllegalArgumentException(rtl::OUString::createFromAscii( "invalid argument type" ),
520                                              static_cast<XFilePicker*>( this ), 1 );
521 
522     sal_Int16 templateId = -1;
523     aAny >>= templateId;
524 
525     switch( templateId )
526     {
527         case FILEOPEN_SIMPLE:
528             m_nDialogType = NAVIGATIONSERVICES_OPEN;
529             OSL_TRACE( "Template: FILEOPEN_SIMPLE" );
530             break;
531         case FILESAVE_SIMPLE:
532             m_nDialogType = NAVIGATIONSERVICES_SAVE;
533             OSL_TRACE( "Template: FILESAVE_SIMPLE" );
534             break;
535         case FILESAVE_AUTOEXTENSION_PASSWORD:
536             m_nDialogType = NAVIGATIONSERVICES_SAVE;
537             OSL_TRACE( "Template: FILESAVE_AUTOEXTENSION_PASSWORD" );
538             break;
539         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
540             m_nDialogType = NAVIGATIONSERVICES_SAVE;
541             OSL_TRACE( "Template: FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS" );
542             break;
543         case FILESAVE_AUTOEXTENSION_SELECTION:
544             m_nDialogType = NAVIGATIONSERVICES_SAVE;
545             OSL_TRACE( "Template: FILESAVE_AUTOEXTENSION_SELECTION" );
546             break;
547         case FILESAVE_AUTOEXTENSION_TEMPLATE:
548             m_nDialogType = NAVIGATIONSERVICES_SAVE;
549             OSL_TRACE( "Template: FILESAVE_AUTOEXTENSION_TEMPLATE" );
550             break;
551         case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
552             m_nDialogType = NAVIGATIONSERVICES_OPEN;
553             OSL_TRACE( "Template: FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE" );
554             break;
555         case FILEOPEN_PLAY:
556             m_nDialogType = NAVIGATIONSERVICES_OPEN;
557             OSL_TRACE( "Template: FILEOPEN_PLAY" );
558             break;
559         case FILEOPEN_READONLY_VERSION:
560             m_nDialogType = NAVIGATIONSERVICES_OPEN;
561             OSL_TRACE( "Template: FILEOPEN_READONLY_VERSION" );
562             break;
563         case FILEOPEN_LINK_PREVIEW:
564             m_nDialogType = NAVIGATIONSERVICES_OPEN;
565             OSL_TRACE( "Template: FILEOPEN_LINK_PREVIEW" );
566             break;
567         case FILESAVE_AUTOEXTENSION:
568             m_nDialogType = NAVIGATIONSERVICES_SAVE;
569             OSL_TRACE( "Template: FILESAVE_AUTOEXTENSION" );
570             break;
571         default:
572             throw lang::IllegalArgumentException(rtl::OUString::createFromAscii( "Unknown template" ),
573                                                  static_cast< XFilePicker* >( this ),
574                                                  1 );
575     }
576 
577     m_pControlHelper->initialize(templateId);
578 
579     implInitialize();
580 
581     DBG_PRINT_EXIT(CLASS_NAME, __func__);
582 }
583 
584 #pragma mark XCancellable
585 //------------------------------------------------------------------------------------
586 // XCancellable
587 //------------------------------------------------------------------------------------
588 
589 void SAL_CALL SalAquaFilePicker::cancel() throw( uno::RuntimeException )
590 {
591     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
592 
593     ::vos::OGuard aGuard( Application::GetSolarMutex() );
594 
595     if (m_pDialog != nil) {
596         [m_pDialog cancel:nil];
597     }
598 
599     DBG_PRINT_EXIT(CLASS_NAME, __func__);
600 }
601 
602 #pragma mark XEventListener
603 //------------------------------------------------
604 // XEventListener
605 //------------------------------------------------
606 
607 void SAL_CALL SalAquaFilePicker::disposing( const lang::EventObject& aEvent ) throw( uno::RuntimeException )
608 {
609     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
610 
611     ::vos::OGuard aGuard( Application::GetSolarMutex() );
612 
613     uno::Reference<XFilePickerListener> xFilePickerListener( aEvent.Source, ::com::sun::star::uno::UNO_QUERY );
614 
615     if( xFilePickerListener.is() )
616         removeFilePickerListener( xFilePickerListener );
617 
618     DBG_PRINT_EXIT(CLASS_NAME, __func__);
619 }
620 
621 #pragma mark XServiceInfo
622 // -------------------------------------------------
623 // XServiceInfo
624 // -------------------------------------------------
625 
626 rtl::OUString SAL_CALL SalAquaFilePicker::getImplementationName()
627 throw( uno::RuntimeException )
628 {
629     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
630 
631     rtl::OUString retVal = rtl::OUString::createFromAscii( FILE_PICKER_IMPL_NAME );
632 
633     DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
634 
635     return retVal;
636 }
637 
638 sal_Bool SAL_CALL SalAquaFilePicker::supportsService( const rtl::OUString& sServiceName )
639 throw( uno::RuntimeException )
640 {
641     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "service name", sServiceName);
642 
643     sal_Bool retVal = sal_False;
644 
645     uno::Sequence <rtl::OUString> supportedServicesNames = FilePicker_getSupportedServiceNames();
646 
647     for( sal_Int32 n = supportedServicesNames.getLength(); n--; ) {
648         if( supportedServicesNames[n].compareTo( sServiceName ) == 0) {
649             retVal = sal_True;
650             break;
651         }
652     }
653 
654     DBG_PRINT_EXIT(CLASS_NAME, __func__);
655 
656     return retVal;
657 }
658 
659 uno::Sequence<rtl::OUString> SAL_CALL SalAquaFilePicker::getSupportedServiceNames()
660 throw( uno::RuntimeException )
661 {
662     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
663     DBG_PRINT_EXIT(CLASS_NAME, __func__);
664 
665     return FilePicker_getSupportedServiceNames();
666 }
667 
668 #pragma mark Misc/Private
669 //-----------------------------------------------------------------------------------------
670 // FilePicker Event functions
671 //-----------------------------------------------------------------------------------------
672 
673 void SAL_CALL SalAquaFilePicker::fileSelectionChanged( FilePickerEvent aEvent )
674 {
675     OSL_TRACE( "file selection changed");
676     if (m_xListener.is())
677         m_xListener->fileSelectionChanged( aEvent );
678 }
679 
680 void SAL_CALL SalAquaFilePicker::directoryChanged( FilePickerEvent aEvent )
681 {
682     OSL_TRACE("directory changed");
683     if (m_xListener.is())
684         m_xListener->directoryChanged( aEvent );
685 }
686 
687 void SAL_CALL SalAquaFilePicker::controlStateChanged( FilePickerEvent aEvent )
688 {
689     OSL_TRACE("control state changed");
690     if (m_xListener.is())
691         m_xListener->controlStateChanged( aEvent );
692 }
693 
694 void SAL_CALL SalAquaFilePicker::dialogSizeChanged()
695 {
696     OSL_TRACE("dialog size changed");
697     if (m_xListener.is())
698         m_xListener->dialogSizeChanged();
699 }
700 
701 //------------------------------------------------------------------------------------
702 
703 #define MAP_TOGGLE( elem ) \
704 case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
705     pWidget = m_pToggles[elem]; \
706     break
707 
708 #define MAP_BUTTON( elem ) \
709 case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
710     pWidget = m_pButtons[elem]; \
711     break
712 #undef MAP_LIST
713 #define MAP_LIST( elem ) \
714 case ExtendedFilePickerElementIds::LISTBOX_##elem: \
715     pWidget = m_pListControls[elem]; if (isAList != NULL) *isAList = sal_True; \
716     break
717 
718 #define MAP_LIST_LABEL( elem ) \
719 case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
720     pWidget = m_pListControls[elem]; \
721     break
722 
723 //--------------------------------------------------
724 // Misc
725 //-------------------------------------------------
726 void SalAquaFilePicker::ensureFilterHelper() {
727     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
728 
729     ::vos::OGuard aGuard( Application::GetSolarMutex() );
730 
731     if (NULL == m_pFilterHelper) {
732         m_pFilterHelper = new FilterHelper;
733         m_pControlHelper->setFilterHelper(m_pFilterHelper);
734         [m_pDelegate setFilterHelper:m_pFilterHelper];
735     }
736 
737     DBG_PRINT_EXIT(CLASS_NAME, __func__);
738 }
739 
740 void SalAquaFilePicker::implInitialize()
741 {
742     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
743 
744     //call super
745     SalAquaPicker::implInitialize();
746 
747     DBG_PRINT_EXIT(CLASS_NAME, __func__);
748 }
749 
750 void SalAquaFilePicker::updateFilterUI() {
751     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
752 
753     m_pControlHelper->updateFilterUI();
754 
755     DBG_PRINT_EXIT(CLASS_NAME, __func__);
756 }
757 
758 void SalAquaFilePicker::updateSaveFileNameExtension() {
759     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
760 
761     if (m_nDialogType != NAVIGATIONSERVICES_SAVE) {
762         return;
763     }
764 
765     // we need to set this here again because initial setting does
766     //[m_pDialog setExtensionHidden:YES];
767 
768     ::vos::OGuard aGuard( Application::GetSolarMutex() );
769 
770     if (m_pControlHelper->isAutoExtensionEnabled() == false) {
771         OSL_TRACE("allowing other file types");
772         [m_pDialog setAllowedFileTypes:nil];
773         [m_pDialog setAllowsOtherFileTypes:YES];
774     } else {
775         ensureFilterHelper();
776 
777         OUStringList aStringList = m_pFilterHelper->getCurrentFilterSuffixList();
778         if( aStringList.empty()) // #i9328#
779             return;
780 
781         rtl::OUString suffix = (*(aStringList.begin())).copy(1);
782         NSString *requiredFileType = [NSString stringWithOUString:suffix];
783 
784         [m_pDialog setRequiredFileType:requiredFileType];
785 
786         OSL_TRACE("disallowing other file types");
787         [m_pDialog setAllowsOtherFileTypes:NO];
788     }
789 
790     DBG_PRINT_EXIT(CLASS_NAME, __func__);
791 }
792 
793 void SalAquaFilePicker::filterControlChanged() {
794     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
795 
796     if (m_pDialog == nil) {
797         return;
798     }
799 
800     ::vos::OGuard aGuard( Application::GetSolarMutex() );
801 
802     updateSaveFileNameExtension();
803 
804     [m_pDialog validateVisibleColumns];
805 
806     FilePickerEvent evt;
807     evt.ElementId = LISTBOX_FILTER;
808     controlStateChanged( evt );
809 
810     DBG_PRINT_EXIT(CLASS_NAME, __func__);
811 }
812 
813