1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "VistaFilePickerImpl.hxx"
22 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
23 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
24 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
25 #include <com/sun/star/beans/StringPair.hpp>
26 #include <com/sun/star/awt/XWindow.hpp>
27 #include <com/sun/star/awt/XSystemDependentWindowPeer.hpp>
28 #include <com/sun/star/lang/SystemDependent.hpp>
29 #include <comphelper/sequence.hxx>
30 #include <fpicker/strings.hrc>
31 #include <fpsofficeResMgr.hxx>
32 #include <osl/file.hxx>
33 #include <osl/mutex.hxx>
34 #include <rtl/process.h>
35 #include <o3tl/char16_t2wchar_t.hxx>
36 #include "../misc/WinImplHelper.hxx"
40 inline bool is_current_process_window(HWND hwnd
)
43 GetWindowThreadProcessId(hwnd
, &pid
);
44 return (pid
== GetCurrentProcessId());
47 HWND
choose_parent_window()
49 HWND hwnd_parent
= GetForegroundWindow();
50 if (!is_current_process_window(hwnd_parent
))
51 hwnd_parent
= GetDesktopWindow();
57 bool createFolderItem(OUString
const & url
, ComPtr
<IShellItem
> & folder
) {
59 if (osl::FileBase::getSystemPathFromFileURL(url
, path
)
60 != osl::FileBase::E_None
)
64 HRESULT res
= SHCreateItemFromParsingName(
65 o3tl::toW(path
.getStr()), nullptr,
66 IID_PPV_ARGS(&folder
));
67 return SUCCEEDED(res
);
77 // types, const etcpp.
80 static const ::sal_Int16 INVALID_CONTROL_ID
= -1;
81 static const ::sal_Int16 INVALID_CONTROL_ACTION
= -1;
83 // Guids used for IFileDialog::SetClientGuid
84 static const GUID CLIENTID_FILEDIALOG_SIMPLE
= {0xB8628FD3, 0xA3F5, 0x4845, 0x9B, 0x62, 0xD5, 0x1E, 0xDF, 0x97, 0xC4, 0x83};
85 static const GUID CLIENTID_FILEDIALOG_OPTIONS
= {0x93ED486F, 0x0D04, 0x4807, 0x8C, 0x44, 0xAC, 0x26, 0xCB, 0x6C, 0x5D, 0x36};
86 static const GUID CLIENTID_FILESAVE_PASSWORD
= {0xC12D4F4C, 0x4D41, 0x4D4F, 0x97, 0xEF, 0x87, 0xF9, 0x8D, 0xB6, 0x1E, 0xA6};
87 static const GUID CLIENTID_FILESAVE_SELECTION
= {0x5B2482B3, 0x0358, 0x4E09, 0xAA, 0x64, 0x2B, 0x76, 0xB2, 0xA0, 0xDD, 0xFE};
88 static const GUID CLIENTID_FILESAVE_TEMPLATE
= {0x9996D877, 0x20D5, 0x424B, 0x9C, 0x2E, 0xD3, 0xB6, 0x31, 0xEC, 0xF7, 0xCE};
89 static const GUID CLIENTID_FILEOPEN_LINK_TEMPLATE
= {0x32237796, 0x1509, 0x49D1, 0xBB, 0x7E, 0x63, 0xAD, 0x36, 0xAE, 0x86, 0x8C};
90 static const GUID CLIENTID_FILEOPEN_LINK_ANCHOR
= {0xBE3188CB, 0x399A, 0x45AE, 0x8F, 0x78, 0x75, 0x17, 0xAF, 0x26, 0x81, 0xEA};
91 static const GUID CLIENTID_FILEOPEN_PLAY
= {0x32CFB147, 0xF5AE, 0x4F90, 0xA1, 0xF1, 0x81, 0x20, 0x72, 0xBB, 0x2F, 0xC5};
92 static const GUID CLIENTID_FILEOPEN_LINK
= {0x39AC4BAE, 0x7D2D, 0x46BC, 0xBE, 0x2E, 0xF8, 0x8C, 0xB5, 0x65, 0x5E, 0x6A};
95 OUString
lcl_getURLFromShellItem (IShellItem
* pItem
)
97 LPOLESTR pStr
= nullptr;
100 SIGDN eConversion
= SIGDN_FILESYSPATH
;
101 HRESULT hr
= pItem
->GetDisplayName ( eConversion
, &pStr
);
105 eConversion
= SIGDN_URL
;
106 hr
= pItem
->GetDisplayName ( eConversion
, &pStr
);
111 sURL
= o3tl::toU(pStr
);
115 ::osl::FileBase::getFileURLFromSystemPath( o3tl::toU(pStr
), sURL
);
118 CoTaskMemFree (pStr
);
123 ::std::vector
< COMDLG_FILTERSPEC
> lcl_buildFilterList(CFilterContainer
& rContainer
)
125 ::std::vector
< COMDLG_FILTERSPEC
> lList
;
126 CFilterContainer::FILTER_ENTRY_T aFilter
;
128 rContainer
.beginEnumFilter( );
129 while( rContainer
.getNextFilter(aFilter
) )
131 COMDLG_FILTERSPEC aSpec
;
133 aSpec
.pszName
= o3tl::toW(aFilter
.first
.getStr()) ;
134 aSpec
.pszSpec
= o3tl::toW(aFilter
.second
.getStr());
136 lList
.push_back(aSpec
);
143 VistaFilePickerImpl::VistaFilePickerImpl()
148 , m_iEventHandler(new VistaFilePickerEventHandler(this))
149 , m_bInExecute (false)
150 , m_bWasExecuted (false)
154 m_hParentWindow
= choose_parent_window();
158 VistaFilePickerImpl::~VistaFilePickerImpl()
163 void VistaFilePickerImpl::before()
166 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
169 // osl::Thread class initializes COm already in MTA mode because it's needed
170 // by VCL and UNO so. There is no way to change that from outside...
171 // but we need a STA environment...
172 // So we make it by try-and-error...
173 // If first CoInitialize will fail... we uninitialize COM initialize it new .-)
175 m_hLastResult
= CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED
);
176 if ( FAILED(m_hLastResult
) )
179 m_hLastResult
= CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED
);
184 void VistaFilePickerImpl::doRequest(const RequestRef
& rRequest
)
188 switch(rRequest
->getRequest())
190 case E_ADD_PICKER_LISTENER
:
191 impl_sta_addFilePickerListener(rRequest
);
194 case E_REMOVE_PICKER_LISTENER
:
195 impl_sta_removeFilePickerListener(rRequest
);
198 case E_APPEND_FILTER
:
199 impl_sta_appendFilter(rRequest
);
202 case E_APPEND_FILTERGROUP
:
203 impl_sta_appendFilterGroup(rRequest
);
206 case E_SET_CURRENT_FILTER
:
207 impl_sta_setCurrentFilter(rRequest
);
210 case E_GET_CURRENT_FILTER
:
211 impl_sta_getCurrentFilter(rRequest
);
214 case E_CREATE_OPEN_DIALOG
:
215 impl_sta_CreateOpenDialog(rRequest
);
218 case E_CREATE_SAVE_DIALOG
:
219 impl_sta_CreateSaveDialog(rRequest
);
222 case E_SET_MULTISELECTION_MODE
:
223 impl_sta_SetMultiSelectionMode(rRequest
);
227 impl_sta_SetTitle(rRequest
);
231 impl_sta_SetFileName(rRequest
);
234 case E_SET_DIRECTORY
:
235 impl_sta_SetDirectory(rRequest
);
238 case E_GET_DIRECTORY
:
239 impl_sta_GetDirectory(rRequest
);
242 case E_SET_DEFAULT_NAME
:
243 impl_sta_SetDefaultName(rRequest
);
246 case E_GET_SELECTED_FILES
:
247 impl_sta_getSelectedFiles(rRequest
);
250 case E_SHOW_DIALOG_MODAL
:
251 impl_sta_ShowDialogModal(rRequest
);
254 case E_SET_CONTROL_VALUE
:
255 impl_sta_SetControlValue(rRequest
);
258 case E_GET_CONTROL_VALUE
:
259 impl_sta_GetControlValue(rRequest
);
262 case E_SET_CONTROL_LABEL
:
263 impl_sta_SetControlLabel(rRequest
);
266 case E_GET_CONTROL_LABEL
:
267 impl_sta_GetControlLabel(rRequest
);
270 case E_ENABLE_CONTROL
:
271 impl_sta_EnableControl(rRequest
);
274 // no default: let the compiler detect changes on enum ERequest !
282 void VistaFilePickerImpl::after()
288 void VistaFilePickerImpl::impl_sta_addFilePickerListener(const RequestRef
& rRequest
)
290 // SYNCHRONIZED outside !
291 const css::uno::Reference
< css::ui::dialogs::XFilePickerListener
> xListener
= rRequest
->getArgumentOrDefault(PROP_PICKER_LISTENER
, css::uno::Reference
< css::ui::dialogs::XFilePickerListener
>());
292 if ( ! xListener
.is())
296 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
297 TFileDialogEvents iHandler
= m_iEventHandler
;
301 VistaFilePickerEventHandler
* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(iHandler
.get());
303 pHandlerImpl
->addFilePickerListener(xListener
);
307 void VistaFilePickerImpl::impl_sta_removeFilePickerListener(const RequestRef
& rRequest
)
309 // SYNCHRONIZED outside !
310 const css::uno::Reference
< css::ui::dialogs::XFilePickerListener
> xListener
= rRequest
->getArgumentOrDefault(PROP_PICKER_LISTENER
, css::uno::Reference
< css::ui::dialogs::XFilePickerListener
>());
311 if ( ! xListener
.is())
315 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
316 TFileDialogEvents iHandler
= m_iEventHandler
;
320 VistaFilePickerEventHandler
* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(iHandler
.get());
322 pHandlerImpl
->removeFilePickerListener(xListener
);
326 void VistaFilePickerImpl::impl_sta_appendFilter(const RequestRef
& rRequest
)
328 const OUString sTitle
= rRequest
->getArgumentOrDefault(PROP_FILTER_TITLE
, OUString());
329 const OUString sFilter
= rRequest
->getArgumentOrDefault(PROP_FILTER_VALUE
, OUString());
332 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
334 m_lFilters
.addFilter(sTitle
, sFilter
);
338 void VistaFilePickerImpl::impl_sta_appendFilterGroup(const RequestRef
& rRequest
)
340 const css::uno::Sequence
< css::beans::StringPair
> aFilterGroup
=
341 rRequest
->getArgumentOrDefault(PROP_FILTER_GROUP
, css::uno::Sequence
< css::beans::StringPair
>());
344 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
346 if ( m_lFilters
.numFilter() > 0 && aFilterGroup
.getLength() > 0 )
347 m_lFilters
.addFilter( STRING_SEPARATOR
, "", true );
349 ::sal_Int32 c
= aFilterGroup
.getLength();
353 const css::beans::StringPair
& rFilter
= aFilterGroup
[i
];
354 m_lFilters
.addFilter(rFilter
.First
, rFilter
.Second
);
359 void VistaFilePickerImpl::impl_sta_setCurrentFilter(const RequestRef
& rRequest
)
361 const OUString sTitle
= rRequest
->getArgumentOrDefault(PROP_FILTER_TITLE
, OUString());
364 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
366 m_lFilters
.setCurrentFilter(sTitle
);
370 void VistaFilePickerImpl::impl_sta_getCurrentFilter(const RequestRef
& rRequest
)
372 TFileDialog iDialog
= impl_getBaseDialogInterface();
373 UINT nIndex
= UINT_MAX
;
374 HRESULT hResult
= iDialog
->GetFileTypeIndex(&nIndex
);
376 ( FAILED(hResult
) ) ||
377 ( nIndex
== UINT_MAX
) // COM dialog sometimes return S_OK for empty filter lists .-(
382 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
385 ::sal_Int32 nRealIndex
= (nIndex
-1); // COM dialog base on 1 ... filter container on 0 .-)
387 (nRealIndex
>= 0 ) &&
388 (m_lFilters
.getFilter(nRealIndex
, sTitle
))
390 rRequest
->setArgument(PROP_FILTER_TITLE
, sTitle
);
391 else if ( nRealIndex
== -1 ) // Dialog not visible yet
393 sTitle
= m_lFilters
.getCurrentFilter();
394 rRequest
->setArgument(PROP_FILTER_TITLE
, sTitle
);
402 void VistaFilePickerImpl::impl_sta_CreateOpenDialog(const RequestRef
& rRequest
)
405 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
407 m_hLastResult
= m_iDialogOpen
.create();
408 if (FAILED(m_hLastResult
))
412 m_iDialogOpen
.query(&iDialog
);
414 TFileDialogEvents iHandler
= m_iEventHandler
;
420 iDialog
->GetOptions ( &nFlags
);
422 nFlags
&= ~FOS_FORCESHOWHIDDEN
;
423 nFlags
|= FOS_PATHMUSTEXIST
;
424 nFlags
|= FOS_FILEMUSTEXIST
;
425 nFlags
|= FOS_OVERWRITEPROMPT
;
426 nFlags
|= FOS_DONTADDTORECENT
;
428 iDialog
->SetOptions ( nFlags
);
430 ::sal_Int32 nFeatures
= rRequest
->getArgumentOrDefault(PROP_FEATURES
, ::sal_Int32(0));
431 ::sal_Int32 nTemplate
= rRequest
->getArgumentOrDefault(PROP_TEMPLATE_DESCR
, ::sal_Int32(0));
432 impl_sta_enableFeatures(nFeatures
, nTemplate
);
434 VistaFilePickerEventHandler
* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(iHandler
.get());
436 pHandlerImpl
->startListening(iDialog
);
440 void VistaFilePickerImpl::impl_sta_CreateSaveDialog(const RequestRef
& rRequest
)
443 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
445 m_hLastResult
= m_iDialogSave
.create();
446 if (FAILED(m_hLastResult
))
449 TFileDialogEvents iHandler
= m_iEventHandler
;
451 m_iDialogSave
.query(&iDialog
);
457 iDialog
->GetOptions ( &nFlags
);
459 nFlags
&= ~FOS_FORCESHOWHIDDEN
;
460 nFlags
|= FOS_PATHMUSTEXIST
;
461 nFlags
|= FOS_FILEMUSTEXIST
;
462 nFlags
|= FOS_OVERWRITEPROMPT
;
463 nFlags
|= FOS_DONTADDTORECENT
;
465 iDialog
->SetOptions ( nFlags
);
467 ::sal_Int32 nFeatures
= rRequest
->getArgumentOrDefault(PROP_FEATURES
, ::sal_Int32(0));
468 ::sal_Int32 nTemplate
= rRequest
->getArgumentOrDefault(PROP_TEMPLATE_DESCR
, ::sal_Int32(0));
469 css::uno::Reference
<css::awt::XWindow
> xWindow
= rRequest
->getArgumentOrDefault(PROP_PARENT_WINDOW
, css::uno::Reference
<css::awt::XWindow
>());
472 css::uno::Reference
<css::awt::XSystemDependentWindowPeer
> xSysDepWin(xWindow
,css::uno::UNO_QUERY
);
473 if(xSysDepWin
.is()) {
474 css::uno::Sequence
<sal_Int8
> aProcessIdent(16);
475 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8
*>(aProcessIdent
.getArray()));
476 css::uno::Any aAny
= xSysDepWin
->getWindowHandle(aProcessIdent
,css::lang::SystemDependent::SYSTEM_WIN32
);
480 m_hParentWindow
= reinterpret_cast<HWND
>(tmp
);
484 impl_sta_enableFeatures(nFeatures
, nTemplate
);
486 VistaFilePickerEventHandler
* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(iHandler
.get());
488 pHandlerImpl
->startListening(iDialog
);
492 static const ::sal_Int32 GROUP_VERSION
= 1;
493 static const ::sal_Int32 GROUP_TEMPLATE
= 2;
494 static const ::sal_Int32 GROUP_IMAGETEMPLATE
= 3;
495 static const ::sal_Int32 GROUP_CHECKBOXES
= 4;
496 static const ::sal_Int32 GROUP_IMAGEANCHOR
= 5;
499 static void setLabelToControl(TFileDialogCustomize iCustom
, sal_uInt16 nControlId
)
501 OUString aLabel
= CResourceProvider::getResString(nControlId
);
502 aLabel
= SOfficeToWindowsLabel(aLabel
);
503 iCustom
->SetControlLabel(nControlId
, o3tl::toW(aLabel
.getStr()) );
507 void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures
, ::sal_Int32 nTemplate
)
512 case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
:
513 case css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW
:
514 case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE
:
515 aGUID
= CLIENTID_FILEDIALOG_SIMPLE
;
518 case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION
:
519 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
:
520 aGUID
= CLIENTID_FILEDIALOG_OPTIONS
;
523 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD
:
524 aGUID
= CLIENTID_FILESAVE_PASSWORD
;
527 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
:
528 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION
:
529 aGUID
= CLIENTID_FILESAVE_SELECTION
;
532 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE
:
533 aGUID
= CLIENTID_FILESAVE_TEMPLATE
;
536 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
:
537 aGUID
= CLIENTID_FILEOPEN_LINK_TEMPLATE
;
540 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
:
541 aGUID
= CLIENTID_FILEOPEN_LINK_ANCHOR
;
544 case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY
:
545 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY
:
546 aGUID
= CLIENTID_FILEOPEN_PLAY
;
549 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW
:
550 aGUID
= CLIENTID_FILEOPEN_LINK
;
553 TFileDialog iDialog
= impl_getBaseDialogInterface();
554 iDialog
->SetClientGuid ( aGUID
);
556 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
558 if ((nFeatures
& FEATURE_VERSION
) == FEATURE_VERSION
)
560 iCustom
->StartVisualGroup (GROUP_VERSION
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_VERSION
).replaceFirst("~","").getStr()));
561 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
);
562 iCustom
->EndVisualGroup ();
563 iCustom
->MakeProminent (GROUP_VERSION
);
566 if ((nFeatures
& FEATURE_TEMPLATE
) == FEATURE_TEMPLATE
)
568 iCustom
->StartVisualGroup (GROUP_TEMPLATE
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_TEMPLATES
).replaceFirst("~","").getStr()));
569 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
);
570 iCustom
->EndVisualGroup ();
571 iCustom
->MakeProminent (GROUP_TEMPLATE
);
574 if ((nFeatures
& FEATURE_IMAGETEMPLATE
) == FEATURE_IMAGETEMPLATE
)
576 iCustom
->StartVisualGroup (GROUP_IMAGETEMPLATE
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_TEMPLATE
).replaceFirst("~","").getStr()));
577 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
);
578 iCustom
->EndVisualGroup ();
579 iCustom
->MakeProminent (GROUP_IMAGETEMPLATE
);
582 if ((nFeatures
& FEATURE_IMAGEANCHOR
) == FEATURE_IMAGEANCHOR
)
584 iCustom
->StartVisualGroup (GROUP_IMAGEANCHOR
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_ANCHOR
).replaceFirst("~","").getStr()));
585 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
);
586 iCustom
->EndVisualGroup ();
587 iCustom
->MakeProminent (GROUP_IMAGEANCHOR
);
590 iCustom
->StartVisualGroup (GROUP_CHECKBOXES
, L
"");
592 sal_uInt16
nControlId(0);
593 if ((nFeatures
& FEATURE_AUTOEXTENSION
) == FEATURE_AUTOEXTENSION
)
595 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
;
596 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_AUTO_EXTENSION
).replaceFirst("~","").getStr()), true);
597 setLabelToControl(iCustom
, nControlId
);
600 if ((nFeatures
& FEATURE_PASSWORD
) == FEATURE_PASSWORD
)
602 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
;
603 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PASSWORD
).replaceFirst("~","").getStr()), false);
604 setLabelToControl(iCustom
, nControlId
);
607 if ((nFeatures
& FEATURE_GPGPASSWORD
) == FEATURE_GPGPASSWORD
)
609 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION
;
610 iCustom
->AddCheckButton (nControlId
, L
"GpgPassword", false);
611 setLabelToControl(iCustom
, nControlId
);
614 if ((nFeatures
& FEATURE_READONLY
) == FEATURE_READONLY
)
616 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
;
617 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_READONLY
).replaceFirst("~","").getStr()), false);
618 setLabelToControl(iCustom
, nControlId
);
621 if ((nFeatures
& FEATURE_FILTEROPTIONS
) == FEATURE_FILTEROPTIONS
)
623 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
;
624 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_FILTER_OPTIONS
).replaceFirst("~","").getStr()), false);
625 setLabelToControl(iCustom
, nControlId
);
628 if ((nFeatures
& FEATURE_LINK
) == FEATURE_LINK
)
630 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
;
631 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_INSERT_AS_LINK
).replaceFirst("~","").getStr()), false);
632 setLabelToControl(iCustom
, nControlId
);
635 if ((nFeatures
& FEATURE_SELECTION
) == FEATURE_SELECTION
)
637 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
;
638 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_SELECTION
).replaceFirst("~","").getStr()), false);
639 setLabelToControl(iCustom
, nControlId
);
642 /* can be ignored ... new COM dialog supports preview native now !
643 if ((nFeatures & FEATURE_PREVIEW) == FEATURE_PREVIEW)
644 iCustom->AddCheckButton (css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, L"Preview", false);
647 iCustom
->EndVisualGroup();
649 if ((nFeatures
& FEATURE_PLAY
) == FEATURE_PLAY
)
650 iCustom
->AddPushButton (css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PLAY
).replaceFirst("~","").getStr()));
655 void VistaFilePickerImpl::impl_sta_SetMultiSelectionMode(const RequestRef
& rRequest
)
657 const bool bMultiSelection
= rRequest
->getArgumentOrDefault(PROP_MULTISELECTION_MODE
, true);
660 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
661 TFileDialog iDialog
= impl_getBaseDialogInterface();
666 m_hLastResult
= iDialog
->GetOptions ( &nFlags
);
669 nFlags
|= FOS_ALLOWMULTISELECT
;
671 nFlags
&= ~FOS_ALLOWMULTISELECT
;
673 iDialog
->SetOptions ( nFlags
);
677 void VistaFilePickerImpl::impl_sta_SetTitle(const RequestRef
& rRequest
)
679 OUString sTitle
= rRequest
->getArgumentOrDefault(PROP_TITLE
, OUString());
682 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
683 TFileDialog iDialog
= impl_getBaseDialogInterface();
687 iDialog
->SetTitle(o3tl::toW(sTitle
.getStr()));
691 void VistaFilePickerImpl::impl_sta_SetFileName(const RequestRef
& rRequest
)
693 OUString sFileName
= rRequest
->getArgumentOrDefault(PROP_FILENAME
, OUString());
696 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
697 TFileDialog iDialog
= impl_getBaseDialogInterface();
701 iDialog
->SetFileName(o3tl::toW(sFileName
.getStr()));
705 void VistaFilePickerImpl::impl_sta_SetDirectory(const RequestRef
& rRequest
)
707 OUString sDirectory
= rRequest
->getArgumentOrDefault(PROP_DIRECTORY
, OUString());
708 bool bForce
= rRequest
->getArgumentOrDefault(PROP_FORCE
, false);
712 // Vista stores last used folders for file dialogs
713 // so we don't want the application to change the folder
715 // Store the requested folder in the mean time and decide later
717 m_sDirectory
= sDirectory
;
721 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
722 TFileDialog iDialog
= impl_getBaseDialogInterface();
726 ComPtr
< IShellItem
> pFolder
;
727 if ( !createFolderItem(sDirectory
, pFolder
) )
730 if ( m_bInExecute
|| bForce
)
731 iDialog
->SetFolder(pFolder
);
734 // Use set default folder as Microsoft recommends in the IFileDialog documentation.
735 iDialog
->SetDefaultFolder(pFolder
);
739 void VistaFilePickerImpl::impl_sta_GetDirectory(const RequestRef
& rRequest
)
741 TFileDialog iDialog
= impl_getBaseDialogInterface();
742 ComPtr
< IShellItem
> pFolder
;
743 HRESULT hResult
= iDialog
->GetFolder( &pFolder
);
744 if ( FAILED(hResult
) )
746 OUString sFolder
= lcl_getURLFromShellItem ( pFolder
);
747 if( sFolder
.getLength())
748 rRequest
->setArgument( PROP_DIRECTORY
, sFolder
);
752 void VistaFilePickerImpl::impl_sta_SetDefaultName(const RequestRef
& rRequest
)
754 OUString sFilename
= rRequest
->getArgumentOrDefault(PROP_FILENAME
, OUString());
755 TFileDialog iDialog
= impl_getBaseDialogInterface();
757 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
761 // if we have the autoextension check box set, remove (or change ???) the extension of the filename
762 // so that the autoextension mechanism can do its job
764 HRESULT hResult
= iCustom
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
765 if ( FAILED(hResult
) )
769 sal_Int32 nSepPos
= sFilename
.lastIndexOf( '.' );
771 sFilename
= sFilename
.copy(0, nSepPos
);
774 iDialog
->SetFileName (o3tl::toW(sFilename
.getStr()));
775 m_sFilename
= sFilename
;
779 void VistaFilePickerImpl::impl_sta_setFiltersOnDialog()
782 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
784 ::std::vector
< COMDLG_FILTERSPEC
> lFilters
= lcl_buildFilterList(m_lFilters
);
785 OUString sCurrentFilter
= m_lFilters
.getCurrentFilter();
786 sal_Int32 nCurrentFilter
= m_lFilters
.getFilterPos(sCurrentFilter
);
787 TFileDialog iDialog
= impl_getBaseDialogInterface();
788 TFileDialogCustomize iCustomize
= impl_getCustomizeInterface();
793 if (lFilters
.empty())
796 COMDLG_FILTERSPEC
*pFilt
= &lFilters
[0];
797 iDialog
->SetFileTypes(lFilters
.size(), pFilt
/*&lFilters[0]*/);
798 iDialog
->SetFileTypeIndex(nCurrentFilter
+ 1);
801 HRESULT hResult
= iCustomize
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
802 if ( FAILED(hResult
) )
807 PCWSTR lpFilterExt
= lFilters
[0].pszSpec
;
809 lpFilterExt
= wcsrchr( lpFilterExt
, '.' );
812 iDialog
->SetDefaultExtension( lpFilterExt
);
818 void VistaFilePickerImpl::impl_sta_getSelectedFiles(const RequestRef
& rRequest
)
821 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
823 TFileOpenDialog iOpen
= m_iDialogOpen
;
824 TFileSaveDialog iSave
= m_iDialogSave
;
825 bool bInExecute
= m_bInExecute
;
830 // ask dialog for results
831 // Note : we must differ between single/multi selection !
832 // Note further: we must react different if dialog is in execute or not .-(
833 ComPtr
< IShellItem
> iItem
;
834 ComPtr
< IShellItemArray
> iItems
;
835 HRESULT hResult
= E_FAIL
;
840 hResult
= iOpen
->GetSelectedItems(&iItems
);
843 hResult
= iOpen
->GetResults(&iItems
);
845 hResult
= iOpen
->GetResult(&iItem
);
851 hResult
= iSave
->GetCurrentSelection(&iItem
);
853 hResult
= iSave
->GetResult(&iItem
);
859 // convert and pack results
860 std::vector
< OUString
> lFiles
;
863 const OUString sURL
= lcl_getURLFromShellItem(iItem
);
864 if (sURL
.getLength() > 0)
865 lFiles
.push_back(sURL
);
871 hResult
= iItems
->GetCount(&nCount
);
872 if ( SUCCEEDED(hResult
) )
874 for (DWORD i
=0; i
<nCount
; ++i
)
876 hResult
= iItems
->GetItemAt(i
, &iItem
);
877 if ( SUCCEEDED(hResult
) )
879 const OUString sURL
= lcl_getURLFromShellItem(iItem
);
880 if (sURL
.getLength() > 0)
881 lFiles
.push_back(sURL
);
887 rRequest
->setArgument(PROP_SELECTED_FILES
, comphelper::containerToSequence(lFiles
));
891 void VistaFilePickerImpl::impl_sta_ShowDialogModal(const RequestRef
& rRequest
)
893 impl_sta_setFiltersOnDialog();
896 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
898 TFileDialog iDialog
= impl_getBaseDialogInterface();
899 TFileOpenDialog iOpen
= m_iDialogOpen
;
900 TFileSaveDialog iSave
= m_iDialogSave
;
902 // it's important to know if we are showing the dialog.
903 // Some dialog interface methods can't be called then or some
904 // tasks must be done differently .-) (e.g. see impl_sta_getSelectedFiles())
907 m_bWasExecuted
= true;
912 // we set the directory only if we have a save dialog and a filename
913 // for the other cases, the file dialog remembers its last location
914 // according to its client guid.
915 if( m_sDirectory
.getLength())
917 ComPtr
< IShellItem
> pFolder
;
918 if ( createFolderItem(m_sDirectory
, pFolder
) )
920 if (m_sFilename
.getLength())
922 OUString
aFileURL(m_sDirectory
);
923 sal_Int32 nIndex
= aFileURL
.lastIndexOf('/');
924 if (nIndex
!= aFileURL
.getLength()-1)
926 aFileURL
+= m_sFilename
;
928 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
931 HRESULT hResult
= iCustom
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
935 hResult
= iDialog
->GetFileTypeIndex(&nFileType
);
936 if ( SUCCEEDED(hResult
) && nFileType
> 0 )
938 // COM dialog base on 1 ... filter container on 0 .-)
939 ::size_t nRealIndex
= (nFileType
-1);
940 ::std::vector
< COMDLG_FILTERSPEC
> lFilters
= lcl_buildFilterList(m_lFilters
);
941 if ( nRealIndex
< lFilters
.size() )
943 PCWSTR lpFilterExt
= lFilters
[nRealIndex
].pszSpec
;
945 lpFilterExt
= wcsrchr( lpFilterExt
, '.' );
947 aFileURL
+= o3tl::toU(lpFilterExt
);
952 // Check existence of file. Set folder only for this special case
953 OUString aSystemPath
;
954 osl_getSystemPathFromFileURL( aFileURL
.pData
, &aSystemPath
.pData
);
956 WIN32_FIND_DATAW aFindFileData
;
957 HANDLE hFind
= FindFirstFileW( o3tl::toW(aSystemPath
.getStr()), &aFindFileData
);
958 if (hFind
!= INVALID_HANDLE_VALUE
)
959 iDialog
->SetFolder(pFolder
);
961 hResult
= iDialog
->AddPlace(pFolder
, FDAP_TOP
);
966 iDialog
->AddPlace(pFolder
, FDAP_TOP
);
971 HRESULT hResult
= E_FAIL
;
974 // show dialog and wait for user decision
976 hResult
= iOpen
->Show( m_hParentWindow
); // parent window needed
979 hResult
= iSave
->Show( m_hParentWindow
); // parent window needed
986 m_bInExecute
= false;
990 if ( FAILED(hResult
) )
993 impl_sta_getSelectedFiles(rRequest
);
994 rRequest
->setArgument(PROP_DIALOG_SHOW_RESULT
, true);
998 TFileDialog
VistaFilePickerImpl::impl_getBaseDialogInterface()
1000 TFileDialog iDialog
;
1003 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
1005 if (m_iDialogOpen
.is())
1006 m_iDialogOpen
.query(&iDialog
);
1007 if (m_iDialogSave
.is())
1008 m_iDialogSave
.query(&iDialog
);
1014 TFileDialogCustomize
VistaFilePickerImpl::impl_getCustomizeInterface()
1016 TFileDialogCustomize iCustom
;
1019 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
1021 if (m_iDialogOpen
.is())
1022 m_iDialogOpen
.query(&iCustom
);
1023 else if (m_iDialogSave
.is())
1024 m_iDialogSave
.query(&iCustom
);
1030 void lcl_removeControlItemsWorkaround(const TFileDialogCustomize
& iCustom
,
1031 ::sal_Int16 nControlId
)
1036 hResult
= iCustom
->SetSelectedControlItem(nControlId
, 1000);
1038 while ( SUCCEEDED(hResult
) )
1039 hResult
= iCustom
->RemoveControlItem(nControlId
, i
++);
1043 void VistaFilePickerImpl::impl_sta_SetControlValue(const RequestRef
& rRequest
)
1045 ::sal_Int16 nId
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1046 ::sal_Int16 nAction
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ACTION
, INVALID_CONTROL_ACTION
);
1047 css::uno::Any aValue
= rRequest
->getValue(PROP_CONTROL_VALUE
);
1049 // don't check for right values here ...
1050 // most parameters are optional !
1052 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1053 if ( ! iCustom
.is())
1058 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
:
1059 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
:
1060 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
:
1061 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
:
1062 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
:
1063 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1064 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
:
1066 bool bValue
= false;
1068 iCustom
->SetCheckButtonState(nId
, bValue
);
1072 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
:
1073 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
:
1074 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
:
1075 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
:
1080 case css::ui::dialogs::ControlActions::DELETE_ITEMS
:
1082 hResult
= iCustom
->RemoveAllControlItems(nId
);
1083 if ( FAILED(hResult
) )
1084 lcl_removeControlItemsWorkaround(iCustom
, nId
);
1088 case css::ui::dialogs::ControlActions::ADD_ITEMS
:
1090 aValue
>>= m_lItems
;
1091 for (::sal_Int32 i
=0; i
<m_lItems
.getLength(); ++i
)
1093 const OUString
& sItem
= m_lItems
[i
];
1094 hResult
= iCustom
->AddControlItem(nId
, i
, o3tl::toW(sItem
.getStr()));
1099 case css::ui::dialogs::ControlActions::SET_SELECT_ITEM
:
1101 ::sal_Int32 nItem
= 0;
1103 hResult
= iCustom
->SetSelectedControlItem(nId
, nItem
);
1110 case css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY
:
1118 void VistaFilePickerImpl::impl_sta_GetControlValue(const RequestRef
& rRequest
)
1120 ::sal_Int16 nId
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1122 // don't check for right values here ...
1123 // most parameters are optional !
1125 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1126 if ( ! iCustom
.is())
1129 css::uno::Any aValue
;
1130 if( m_bWasExecuted
)
1133 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
:
1134 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION
:
1135 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
:
1136 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
:
1137 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
:
1138 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1139 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
:
1141 BOOL bValue
= FALSE
;
1142 HRESULT hResult
= iCustom
->GetCheckButtonState(nId
, &bValue
);
1143 if ( SUCCEEDED(hResult
) )
1144 aValue
<<= bool(bValue
);
1147 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
:
1148 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
:
1149 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
:
1150 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
:
1153 HRESULT hResult
= iCustom
->GetSelectedControlItem(nId
, &bValue
);
1154 if ( SUCCEEDED(hResult
) )
1156 const OUString
& sItem
= m_lItems
[bValue
];
1157 aValue
<<= OUString(sItem
.getStr());
1163 if (aValue
.hasValue())
1164 rRequest
->setArgument(PROP_CONTROL_VALUE
, aValue
);
1168 void VistaFilePickerImpl::impl_sta_SetControlLabel(const RequestRef
& rRequest
)
1170 ::sal_Int16 nId
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1171 OUString sLabel
= rRequest
->getArgumentOrDefault(PROP_CONTROL_LABEL
, OUString() );
1173 // don't check for right values here ...
1174 // most parameters are optional !
1176 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1177 if ( ! iCustom
.is())
1179 iCustom
->SetControlLabel (nId
, o3tl::toW(sLabel
.getStr()));
1183 void VistaFilePickerImpl::impl_sta_GetControlLabel(const RequestRef
& /*rRequest*/)
1188 void VistaFilePickerImpl::impl_sta_EnableControl(const RequestRef
& rRequest
)
1190 ::sal_Int16 nId
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1191 bool bEnabled
= rRequest
->getArgumentOrDefault(PROP_CONTROL_ENABLE
, true);
1193 // don't check for right values here ...
1194 // most parameters are optional !
1196 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1197 if ( ! iCustom
.is())
1200 CDCONTROLSTATEF eState
= CDCS_VISIBLE
;
1202 eState
|= CDCS_ENABLED
;
1204 eState
|= CDCS_INACTIVE
;
1206 iCustom
->SetControlState(nId
, eState
);
1209 void VistaFilePickerImpl::impl_SetDefaultExtension( const OUString
& currentFilter
)
1211 TFileDialog iDialog
= impl_getBaseDialogInterface();
1212 if (currentFilter
.getLength())
1215 m_lFilters
.getFilter(currentFilter
, FilterExt
);
1217 sal_Int32 posOfPoint
= FilterExt
.indexOf(L
'.');
1218 const sal_Unicode
* pFirstExtStart
= FilterExt
.getStr() + posOfPoint
+ 1;
1220 sal_Int32 posOfSemiColon
= FilterExt
.indexOf(L
';') - 1;
1221 if (posOfSemiColon
< 0)
1222 posOfSemiColon
= FilterExt
.getLength() - 1;
1224 FilterExt
= OUString(pFirstExtStart
, posOfSemiColon
- posOfPoint
);
1225 iDialog
->SetDefaultExtension ( o3tl::toW(FilterExt
.getStr()) );
1229 void VistaFilePickerImpl::onAutoExtensionChanged (bool bChecked
)
1232 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
1234 const OUString sFilter
= m_lFilters
.getCurrentFilter ();
1236 if ( !m_lFilters
.getFilter (sFilter
, sExt
))
1239 TFileDialog iDialog
= impl_getBaseDialogInterface();
1244 PCWSTR pExt
= nullptr;
1247 pExt
= o3tl::toW(sExt
.getStr());
1248 pExt
= wcsrchr( pExt
, '.' );
1252 iDialog
->SetDefaultExtension( pExt
);
1255 bool VistaFilePickerImpl::onFileTypeChanged( UINT
/*nTypeIndex*/ )
1260 } // namespace vista
1261 } // namespace win32
1262 } // namespace fpicker
1264 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */