1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 //------------------------------------------------------------------------
25 // includes
26 //------------------------------------------------------------------------
27 
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <cppuhelper/interfacecontainer.h>
31 #include <osl/diagnose.h>
32 #include <com/sun/star/uno/Any.hxx>
33 #include <FPServiceInfo.hxx>
34 #include <vos/mutex.hxx>
35 #include <vcl/svapp.hxx>
36 #ifndef _SALAQUAPICKER_HXX_
37 #include "SalAquaPicker.hxx"
38 #endif
39 #include <tools/urlobj.hxx>
40 #include <osl/file.hxx>
41 #include "CFStringUtilities.hxx"
42 #include "NSString_OOoAdditions.hxx"
43 
44 #ifndef _NSURL_OOOADDITIONS_HXX_
45 #include "NSURL_OOoAdditions.hxx"
46 #endif
47 
48 #include "SalAquaFilePicker.hxx"
49 
50 #include <stdio.h>
51 
52 #pragma mark DEFINES
53 #define CLASS_NAME "SalAquaPicker"
54 #define kSetHideExtensionStateKey @"NSNavLastUserSetHideExtensionButtonState"
55 
56 //------------------------------------------------------------------------
57 // namespace directives
58 //------------------------------------------------------------------------
59 
60 using namespace ::rtl;
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::uno;
64 
65 // constructor
SalAquaPicker()66 SalAquaPicker::SalAquaPicker()
67 : m_pDialog(NULL)
68 , m_pControlHelper(new ControlHelper())
69 {
70     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
71     DBG_PRINT_EXIT(CLASS_NAME, __func__);
72 }
73 
~SalAquaPicker()74 SalAquaPicker::~SalAquaPicker()
75 {
76     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
77 
78     ::vos::OGuard aGuard( Application::GetSolarMutex() );
79 
80     NSAutoreleasePool *pool = [NSAutoreleasePool new];
81 
82     if (NULL != m_pControlHelper)
83         delete m_pControlHelper;
84 
85     if (NULL != m_pDialog)
86         [m_pDialog release];
87 
88     [pool release];
89 
90     DBG_PRINT_EXIT(CLASS_NAME, __func__);
91 }
92 
implInitialize()93 void SAL_CALL SalAquaPicker::implInitialize()
94 {
95     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
96 
97     ::vos::OGuard aGuard( Application::GetSolarMutex() );
98 
99     if (m_pDialog != nil) {
100         return;
101     }
102 
103     switch (m_nDialogType)
104     {
105         case NAVIGATIONSERVICES_OPEN:
106             OSL_TRACE("NAVIGATIONSERVICES_OPEN");
107             m_pDialog = [NSOpenPanel openPanel];
108             [(NSOpenPanel*)m_pDialog setCanChooseDirectories:NO];
109             [(NSOpenPanel*)m_pDialog setCanChooseFiles:YES];
110             break;
111 
112         case NAVIGATIONSERVICES_SAVE: {
113             OSL_TRACE("NAVIGATIONSERVICES_SAVE");
114             m_pDialog = [NSSavePanel savePanel];
115             [(NSSavePanel*)m_pDialog setCanSelectHiddenExtension:NO]; //changed for issue #102102
116             /* I would have loved to use
117              * [(NSSavePanel*)m_pDialog setExtensionHidden:YES];
118              * here but unfortunately this
119              * a) only works when the dialog is already displayed because it seems to act on the corresponding checkbox (that we don't show but that doesn't matter)
120              * b) Mac OS X saves this setting on an application-based level which means that the last state is always being restored again when the app runs for the next time
121              *
122              * So the only reliable way seems to be using the NSUserDefaults object because that is where that value is stored and
123              * to just overwrite it if it has the wrong value.
124              */
125             NSUserDefaults *pDefaults = [NSUserDefaults standardUserDefaults];
126             NSNumber *pExtn = [pDefaults objectForKey:kSetHideExtensionStateKey];
127             if(pExtn == nil || [pExtn boolValue] == NO) {
128                 OSL_TRACE("Hiding extension");
129                 [pDefaults setBool:YES forKey:kSetHideExtensionStateKey];
130             }
131             } break;
132 
133         case NAVIGATIONSERVICES_DIRECTORY:
134             OSL_TRACE("NAVIGATIONSERVICES_DIRECTORY");
135             m_pDialog = [NSOpenPanel openPanel];
136             [(NSOpenPanel*)m_pDialog setCanChooseDirectories:YES];
137             [(NSOpenPanel*)m_pDialog setCanChooseFiles:NO];
138             break;
139 
140         default:
141             OSL_TRACE("m_nDialogType is UNKNOWN: %d", m_nDialogType);
142             break;
143     }
144 
145     if (m_pDialog == nil) {
146         OSL_TRACE("An error occurred while creating the dialog!");
147     }
148     else {
149         [(NSOpenPanel*)m_pDialog setCanCreateDirectories:YES];
150         //Retain the dialog instance or it will go away immediately
151         [m_pDialog retain];
152     }
153 
154     DBG_PRINT_EXIT(CLASS_NAME, __func__);
155 }
156 
run()157 int SalAquaPicker::run()
158 {
159     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
160 
161     ::vos::OGuard aGuard( Application::GetSolarMutex() );
162 
163     NSAutoreleasePool *pool = [NSAutoreleasePool new];
164 
165     if (m_pDialog == NULL) {
166         //this is the case e.g. for the folder picker at this stage
167         implInitialize();
168     }
169 
170     NSView *userPane = m_pControlHelper->getUserPane();
171     if (userPane != NULL) {
172         [m_pDialog setAccessoryView:userPane];
173     }
174 
175     int retVal = 0;
176 
177     NSString *startDirectory;
178     if (m_sDisplayDirectory.getLength() > 0) {
179         NSString *temp = [NSString stringWithOUString:m_sDisplayDirectory];
180         NSURL *url = [NSURL URLWithString:temp];
181         startDirectory = [url path];
182 
183         OSL_TRACE("start dir: %s", [startDirectory UTF8String]);
184         // NSLog(@"%@", startDirectory);
185     }
186     else {
187         startDirectory = NSHomeDirectory();
188     }
189 
190     switch(m_nDialogType) {
191         case NAVIGATIONSERVICES_DIRECTORY:
192         case NAVIGATIONSERVICES_OPEN:
193             retVal = [(NSOpenPanel*)m_pDialog runModalForDirectory:startDirectory file:nil types:nil];
194             break;
195         case NAVIGATIONSERVICES_SAVE:
196             retVal = [m_pDialog runModalForDirectory:startDirectory file:[NSString stringWithOUString:((SalAquaFilePicker*)this)->getSaveFileName()]/*[m_pDialog saveFilename]*/];
197             break;
198         // [m_pDialog beginSheetForDirectory:startDirectory file:[m_pDialog saveFilename] modalForWindow:[NSApp keyWindow] modalDelegate:((SalAquaFilePicker*)this)->getDelegate() didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
199         default:
200             break;
201     }
202 
203     if (retVal == NSFileHandlingPanelOKButton) {
204         NSString* pDir = [m_pDialog directory];
205         if (pDir) {
206             implsetDisplayDirectory([[NSURL fileURLWithPath:pDir] OUStringForInfo:FULLPATH]);
207         }
208     }
209 
210     DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
211 
212     [pool release];
213 
214     return retVal;
215 }
216 
runandwaitforresult()217 int SalAquaPicker::runandwaitforresult()
218 {
219     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
220 
221     ::vos::OGuard aGuard( Application::GetSolarMutex() );
222 
223     int status = this->run();
224 
225     DBG_PRINT_EXIT(CLASS_NAME, __func__, status);
226     return status;
227 }
228 
implsetDisplayDirectory(const rtl::OUString & aDirectory)229 void SAL_CALL SalAquaPicker::implsetDisplayDirectory( const rtl::OUString& aDirectory )
230     throw( lang::IllegalArgumentException, uno::RuntimeException )
231 {
232     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "directory", aDirectory);
233 
234     ::vos::OGuard aGuard( Application::GetSolarMutex() );
235 
236     if (aDirectory != m_sDisplayDirectory) {
237         m_sDisplayDirectory = aDirectory;
238     }
239 
240     DBG_PRINT_EXIT(CLASS_NAME, __func__);
241 }
242 
implgetDisplayDirectory()243 rtl::OUString SAL_CALL SalAquaPicker::implgetDisplayDirectory() throw( uno::RuntimeException )
244 {
245     DBG_PRINT_ENTRY(CLASS_NAME, __func__);
246     DBG_PRINT_EXIT(CLASS_NAME, __func__, m_sDisplayDirectory);
247 
248     return m_sDisplayDirectory;
249 }
250 
implsetTitle(const rtl::OUString & aTitle)251 void SAL_CALL SalAquaPicker::implsetTitle( const rtl::OUString& aTitle ) throw( uno::RuntimeException )
252 {
253     DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle);
254 
255     ::vos::OGuard aGuard( Application::GetSolarMutex() );
256 
257     if (m_pDialog != nil) {
258         [m_pDialog setTitle:[NSString stringWithOUString:aTitle]];
259     }
260 
261     DBG_PRINT_EXIT(CLASS_NAME, __func__);
262 }
263 
264