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