1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include "VistaFilePicker.hxx"
23 
24 #include "WinImplHelper.hxx"
25 #include "shared.hxx"
26 
27 #include <com/sun/star/awt/XWindow.hpp>
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
30 #include <com/sun/star/ui/dialogs/XFilePickerNotifier.hpp>
31 #include <com/sun/star/ui/dialogs/XFilePickerListener.hpp>
32 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
33 
34 #include <cppuhelper/interfacecontainer.h>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <osl/file.hxx>
38 #include <officecfg/Office/Common.hxx>
39 
40 #include <shlobj.h>
41 
42 namespace fpicker{
43 namespace win32{
44 namespace vista{
45 
46 VistaFilePicker::VistaFilePicker(bool bFolderPicker)
47     : TVistaFilePickerBase  (m_aMutex                 )
48     , m_bInitialized        (false                    )
49     , m_bFolderPicker       (bFolderPicker            )
50 {
51 }
52 
53 VistaFilePicker::~VistaFilePicker()
54 {
55 }
56 
57 void SAL_CALL VistaFilePicker::addFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener)
58 {
59     Request rRequest;
60     rRequest.setRequest (VistaFilePickerImpl::E_ADD_PICKER_LISTENER);
61     rRequest.setArgument(PROP_PICKER_LISTENER, xListener);
62 
63     m_rDialog.doRequest(rRequest);
64 }
65 
66 void SAL_CALL VistaFilePicker::removeFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener )
67 {
68     Request rRequest;
69     rRequest.setRequest (VistaFilePickerImpl::E_REMOVE_PICKER_LISTENER);
70     rRequest.setArgument(PROP_PICKER_LISTENER, xListener);
71 
72     m_rDialog.doRequest(rRequest);
73 }
74 
75 void VistaFilePicker::disposing(const css::lang::EventObject& /*aEvent*/)
76 {
77 }
78 
79 void SAL_CALL VistaFilePicker::setMultiSelectionMode(sal_Bool bMode)
80 {
81     ensureInit();
82 
83     Request rRequest;
84     rRequest.setRequest (VistaFilePickerImpl::E_SET_MULTISELECTION_MODE);
85     rRequest.setArgument(PROP_MULTISELECTION_MODE, bMode);
86 
87     m_rDialog.doRequest(rRequest);
88 }
89 
90 void SAL_CALL VistaFilePicker::setTitle(const OUString& sTitle)
91 {
92     ensureInit();
93 
94     Request rRequest;
95     rRequest.setRequest (VistaFilePickerImpl::E_SET_TITLE);
96     rRequest.setArgument(PROP_TITLE, sTitle);
97 
98     m_rDialog.doRequest(rRequest);
99 }
100 
101 void SAL_CALL VistaFilePicker::appendFilter(const OUString& sTitle ,
102                                             const OUString& sFilter)
103 {
104     Request rRequest;
105     rRequest.setRequest (VistaFilePickerImpl::E_APPEND_FILTER);
106     rRequest.setArgument(PROP_FILTER_TITLE, sTitle );
107     rRequest.setArgument(PROP_FILTER_VALUE, sFilter);
108 
109     m_rDialog.doRequest(rRequest);
110 }
111 
112 void SAL_CALL VistaFilePicker::setCurrentFilter(const OUString& sTitle)
113 {
114     Request rRequest;
115     rRequest.setRequest (VistaFilePickerImpl::E_SET_CURRENT_FILTER);
116     rRequest.setArgument(PROP_FILTER_TITLE, sTitle);
117 
118     m_rDialog.doRequest(rRequest);
119 }
120 
121 OUString SAL_CALL VistaFilePicker::getCurrentFilter()
122 {
123     Request rRequest;
124     rRequest.setRequest (VistaFilePickerImpl::E_GET_CURRENT_FILTER);
125 
126     m_rDialog.doRequest(rRequest);
127 
128     const  OUString sTitle = rRequest.getArgumentOrDefault(PROP_FILTER_TITLE, OUString());
129     return sTitle;
130 }
131 
132 void SAL_CALL VistaFilePicker::appendFilterGroup(const OUString&                              /*sGroupTitle*/,
133                                                  const css::uno::Sequence< css::beans::StringPair >& rFilters   )
134 {
135     Request rRequest;
136     rRequest.setRequest (VistaFilePickerImpl::E_APPEND_FILTERGROUP);
137     rRequest.setArgument(PROP_FILTER_GROUP, rFilters);
138 
139     m_rDialog.doRequest(rRequest);
140 }
141 
142 void SAL_CALL VistaFilePicker::setDefaultName(const OUString& sName )
143 {
144     ensureInit();
145 
146     Request rRequest;
147     rRequest.setRequest (VistaFilePickerImpl::E_SET_DEFAULT_NAME);
148     rRequest.setArgument(PROP_FILENAME, sName);
149 
150     m_rDialog.doRequest(rRequest);
151 }
152 
153 void SAL_CALL VistaFilePicker::setDisplayDirectory(const OUString& sDirectory)
154 {
155     ensureInit();
156 
157     Request rRequest;
158     rRequest.setRequest (VistaFilePickerImpl::E_SET_DIRECTORY);
159     rRequest.setArgument(PROP_DIRECTORY, sDirectory);
160 
161     m_rDialog.doRequest(rRequest);
162 }
163 
164 OUString SAL_CALL VistaFilePicker::getDisplayDirectory()
165 {
166     ensureInit();
167 
168     Request rRequest;
169     rRequest.setRequest (VistaFilePickerImpl::E_GET_DIRECTORY);
170     m_rDialog.doRequest(rRequest);
171     const OUString sDirectory = rRequest.getArgumentOrDefault(PROP_DIRECTORY, OUString());
172 
173     return sDirectory;
174 }
175 
176 // @deprecated can't be supported any longer ... see IDL description for further details
177 css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getFiles()
178 {
179     css::uno::Sequence< OUString > lFiles = getSelectedFiles();
180     // multiselection doesn't really work
181     // so just retrieve the first url
182     if (lFiles.getLength() > 1)
183         lFiles.realloc(1);
184     m_lLastFiles = lFiles;
185     return lFiles;
186 }
187 
188 css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getSelectedFiles()
189 {
190     Request rRequest;
191     rRequest.setRequest (VistaFilePickerImpl::E_GET_SELECTED_FILES);
192 
193     m_rDialog.doRequest(rRequest);
194 
195     const  css::uno::Sequence< OUString > lFiles = rRequest.getArgumentOrDefault(PROP_SELECTED_FILES, css::uno::Sequence< OUString >());
196     m_lLastFiles = lFiles;
197     return lFiles;
198 }
199 
200 void VistaFilePicker::ensureInit()
201 {
202     if ( !m_bInitialized )
203     {
204         if (m_bFolderPicker)
205         {
206             Request rRequest;
207             rRequest.setRequest (VistaFilePickerImpl::E_CREATE_FOLDER_PICKER);
208             m_rDialog.doRequest(rRequest);
209             m_bInitialized = true;
210         }
211         else
212         {
213             initialize( { css::uno::Any(css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE) });
214         }
215     }
216 }
217 
218 ::sal_Int16 SAL_CALL VistaFilePicker::execute()
219 {
220     ensureInit();
221 
222     Request rRequest;
223     rRequest.setRequest (VistaFilePickerImpl::E_SHOW_DIALOG_MODAL);
224 
225     // show a modal window
226     m_rDialog.doRequest(rRequest);
227 
228     const bool bOK          = rRequest.getArgumentOrDefault(PROP_DIALOG_SHOW_RESULT, false );
229     m_lLastFiles = rRequest.getArgumentOrDefault(PROP_SELECTED_FILES    , css::uno::Sequence< OUString >());
230 
231     ::sal_Int16 nResult = css::ui::dialogs::ExecutableDialogResults::CANCEL;
232     if (bOK)
233         nResult = css::ui::dialogs::ExecutableDialogResults::OK;
234     return nResult;
235 }
236 
237 // XFilePicker
238 
239 void SAL_CALL VistaFilePicker::setValue(      ::sal_Int16    nControlId    ,
240                                               ::sal_Int16    nControlAction,
241                                         const css::uno::Any& aValue        )
242 {
243     Request rRequest;
244     rRequest.setRequest (VistaFilePickerImpl::E_SET_CONTROL_VALUE);
245     rRequest.setArgument(PROP_CONTROL_ID    , nControlId    );
246     rRequest.setArgument(PROP_CONTROL_ACTION, nControlAction);
247     rRequest.setArgument(PROP_CONTROL_VALUE , aValue        );
248 
249     m_rDialog.doRequest(rRequest);
250 }
251 
252 css::uno::Any SAL_CALL VistaFilePicker::getValue(::sal_Int16 nControlId    ,
253                                                  ::sal_Int16 nControlAction)
254 {
255     Request rRequest;
256     rRequest.setRequest (VistaFilePickerImpl::E_GET_CONTROL_VALUE);
257     rRequest.setArgument(PROP_CONTROL_ID    , nControlId    );
258     rRequest.setArgument(PROP_CONTROL_ACTION, nControlAction);
259 
260     m_rDialog.doRequest(rRequest);
261     return rRequest.getValue(PROP_CONTROL_VALUE);
262 }
263 
264 void SAL_CALL VistaFilePicker::enableControl(::sal_Int16 nControlId,
265                                              sal_Bool  bEnable   )
266 {
267     Request rRequest;
268     rRequest.setRequest (VistaFilePickerImpl::E_ENABLE_CONTROL);
269     rRequest.setArgument(PROP_CONTROL_ID    , nControlId);
270     rRequest.setArgument(PROP_CONTROL_ENABLE, bEnable   );
271 
272     m_rDialog.doRequest(rRequest);
273 }
274 
275 void SAL_CALL VistaFilePicker::setLabel(      ::sal_Int16      nControlId,
276                                          const OUString& sLabel    )
277 {
278     Request rRequest;
279     rRequest.setRequest (VistaFilePickerImpl::E_SET_CONTROL_LABEL);
280     rRequest.setArgument(PROP_CONTROL_ID   , nControlId);
281     rRequest.setArgument(PROP_CONTROL_LABEL, sLabel    );
282 
283     m_rDialog.doRequest(rRequest);
284 }
285 
286 OUString SAL_CALL VistaFilePicker::getLabel(::sal_Int16 nControlId)
287 {
288     Request rRequest;
289     rRequest.setRequest (VistaFilePickerImpl::E_GET_CONTROL_LABEL);
290     rRequest.setArgument(PROP_CONTROL_ID, nControlId);
291 
292     m_rDialog.doRequest(rRequest);
293     const OUString sLabel = rRequest.getArgumentOrDefault(PROP_CONTROL_LABEL, OUString());
294     return sLabel;
295 }
296 
297 css::uno::Sequence< ::sal_Int16 > SAL_CALL VistaFilePicker::getSupportedImageFormats()
298 {
299     return css::uno::Sequence< sal_Int16 >();
300 }
301 
302 sal_Int32 SAL_CALL VistaFilePicker::getTargetColorDepth()
303 {
304     return 0;
305 }
306 
307 sal_Int32 SAL_CALL VistaFilePicker::getAvailableWidth()
308 {
309     return 0;
310 }
311 
312 sal_Int32 SAL_CALL VistaFilePicker::getAvailableHeight()
313 {
314     return 0;
315 }
316 
317 void SAL_CALL VistaFilePicker::setImage(      sal_Int16      /*nImageFormat*/,
318                                          const css::uno::Any& /*aImage      */)
319 {
320 }
321 
322 sal_Bool SAL_CALL VistaFilePicker::setShowState(sal_Bool /*bShowState*/)
323 {
324     return false;
325 }
326 
327 sal_Bool SAL_CALL VistaFilePicker::getShowState()
328 {
329     return false;
330 }
331 
332 void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
333 {
334     if (lArguments.getLength() < 1)
335         throw css::lang::IllegalArgumentException(
336                 "XInitialization::initialize() called without arguments.",
337                 static_cast< css::ui::dialogs::XFilePicker2* >( this ),
338                 1);
339 
340     sal_Int32         nTemplate = -1;
341     lArguments[0] >>= nTemplate;
342 
343     bool bFileOpenDialog = true;
344     ::sal_Int32 nFeatures       = 0;
345 
346     switch(nTemplate)
347     {
348         case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE :
349         {
350             bFileOpenDialog = true;
351         }
352         break;
353 
354         case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE :
355         {
356             bFileOpenDialog = false;
357         }
358         break;
359 
360         case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD :
361         {
362             bFileOpenDialog  = false;
363             nFeatures        |= FEATURE_AUTOEXTENSION;
364             nFeatures        |= FEATURE_PASSWORD;
365             nFeatures        |= FEATURE_GPGPASSWORD;
366         }
367         break;
368 
369         case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS :
370         {
371             bFileOpenDialog = false;
372             nFeatures        |= FEATURE_AUTOEXTENSION;
373             nFeatures        |= FEATURE_PASSWORD;
374             nFeatures        |= FEATURE_FILTEROPTIONS;
375             nFeatures        |= FEATURE_GPGPASSWORD;
376         }
377         break;
378 
379         case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION :
380         {
381             bFileOpenDialog  = false;
382             nFeatures        |= FEATURE_AUTOEXTENSION;
383             nFeatures        |= FEATURE_SELECTION;
384         }
385         break;
386 
387         case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE :
388         {
389             bFileOpenDialog  = false;
390             nFeatures        |= FEATURE_AUTOEXTENSION;
391             nFeatures        |= FEATURE_TEMPLATE;
392         }
393         break;
394 
395         case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE :
396         {
397             bFileOpenDialog  = true;
398             nFeatures        |= FEATURE_LINK;
399             nFeatures        |= FEATURE_PREVIEW;
400             nFeatures        |= FEATURE_IMAGETEMPLATE;
401         }
402         break;
403 
404         case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR :
405         {
406             bFileOpenDialog  = true;
407             nFeatures        |= FEATURE_LINK;
408             nFeatures        |= FEATURE_PREVIEW;
409             nFeatures        |= FEATURE_IMAGEANCHOR;
410         }
411         break;
412 
413         case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY :
414         {
415             bFileOpenDialog  = true;
416             nFeatures        |= FEATURE_PLAY;
417         }
418         break;
419 
420         case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY :
421         {
422             bFileOpenDialog  = true;
423             nFeatures        |= FEATURE_LINK;
424             nFeatures        |= FEATURE_PLAY;
425         }
426         break;
427 
428         case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION :
429         {
430             bFileOpenDialog  = true;
431             nFeatures        |= FEATURE_READONLY;
432             nFeatures        |= FEATURE_VERSION;
433         }
434         break;
435 
436         case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW :
437         {
438             bFileOpenDialog  = true;
439             nFeatures        |= FEATURE_LINK;
440             nFeatures        |= FEATURE_PREVIEW;
441         }
442         break;
443 
444         case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION :
445         {
446             bFileOpenDialog  = false;
447             nFeatures        |= FEATURE_AUTOEXTENSION;
448         }
449         break;
450 
451         case css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW :
452         {
453             bFileOpenDialog  = true;
454             nFeatures        |= FEATURE_PREVIEW;
455         }
456         break;
457     }
458     css::uno::Reference<css::awt::XWindow> xParentWindow;
459     if(lArguments.getLength() > 1)
460     {
461         lArguments[1] >>= xParentWindow;
462     }
463     Request rRequest;
464     if (bFileOpenDialog)
465         rRequest.setRequest (VistaFilePickerImpl::E_CREATE_OPEN_DIALOG);
466     else
467         rRequest.setRequest (VistaFilePickerImpl::E_CREATE_SAVE_DIALOG);
468     rRequest.setArgument(PROP_FEATURES, nFeatures);
469     rRequest.setArgument(PROP_TEMPLATE_DESCR, nTemplate);
470     if(xParentWindow.is())
471         rRequest.setArgument(PROP_PARENT_WINDOW, xParentWindow);
472     m_rDialog.doRequest(rRequest);
473 
474     m_bInitialized = true;
475 }
476 
477 void SAL_CALL VistaFilePicker::cancel()
478 {
479 }
480 
481 OUString SAL_CALL VistaFilePicker::getDirectory()
482 {
483     ensureInit();
484     css::uno::Sequence< OUString > aFileSeq = getSelectedFiles();
485     assert(aFileSeq.getLength() <= 1);
486     return aFileSeq.getLength() ? aFileSeq[0] : OUString();
487 }
488 
489 void SAL_CALL VistaFilePicker::setDescription( const OUString& aDescription )
490 {
491     setTitle(aDescription);
492 }
493 
494 // XServiceInfo
495 
496 OUString SAL_CALL VistaFilePicker::getImplementationName()
497 {
498     if (m_bFolderPicker)
499         return "com.sun.star.ui.dialogs.Win32FolderPicker";
500     else
501         return "com.sun.star.ui.dialogs.Win32FilePicker";
502 }
503 
504 sal_Bool SAL_CALL VistaFilePicker::supportsService(const OUString& sServiceName)
505 {
506     return cppu::supportsService(this, sServiceName);
507 }
508 
509 css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getSupportedServiceNames()
510 {
511         return {
512             "com.sun.star.ui.dialogs.FilePicker",
513             "com.sun.star.ui.dialogs.SystemFilePicker",
514             "com.sun.star.ui.dialogs.SystemFolderPicker" };
515 }
516 
517 } // namespace vista
518 } // namespace win32
519 } // namespace fpicker
520 
521 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
522 fpicker_win32_FilePicker_get_implementation(
523     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
524 {
525     return cppu::acquire(new ::fpicker::win32::vista::VistaFilePicker(false));
526 }
527 
528 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
529 fpicker_win32_FolderPicker_get_implementation(
530     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
531 {
532     return cppu::acquire(new ::fpicker::win32::vista::VistaFilePicker(true));
533 }
534 
535 
536 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
537