blob: f9b7ce78cfccdd630a51b7f31c28ac3c114ef749 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
//-----------------------------------------------------------------------------
// includes
//-----------------------------------------------------------------------------
#include "VistaFilePickerImpl.hxx"
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <com/sun/star/ui/dialogs/ControlActions.hpp>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/beans/StringPair.hpp>
#include <comphelper/sequenceasvector.hxx>
#include <osl/file.hxx>
#include <osl/mutex.hxx>
#ifdef __MINGW32__
#include <limits.h>
#endif
#include "..\misc\WinImplHelper.hxx"
#include <Shlguid.h>
inline bool is_current_process_window(HWND hwnd)
{
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
return (pid == GetCurrentProcessId());
}
HWND choose_parent_window()
{
HWND hwnd_parent = GetForegroundWindow();
if (!is_current_process_window(hwnd_parent))
hwnd_parent = GetDesktopWindow();
return hwnd_parent;
}
//-----------------------------------------------------------------------------
// namespace
//-----------------------------------------------------------------------------
namespace fpicker{
namespace win32{
namespace vista{
namespace css = ::com::sun::star;
//-----------------------------------------------------------------------------
// types, const etcpp.
//-----------------------------------------------------------------------------
static const ::sal_Int16 INVALID_CONTROL_ID = -1;
static const ::sal_Int16 INVALID_CONTROL_ACTION = -1;
typedef ::comphelper::SequenceAsVector< ::rtl::OUString > TStringList;
// Guids used for IFileDialog::SetClientGuid
static const GUID CLIENTID_FILEDIALOG_SIMPLE = {0xB8628FD3, 0xA3F5, 0x4845, 0x9B, 0x62, 0xD5, 0x1E, 0xDF, 0x97, 0xC4, 0x83};
static const GUID CLIENTID_FILEDIALOG_OPTIONS = {0x93ED486F, 0x0D04, 0x4807, 0x8C, 0x44, 0xAC, 0x26, 0xCB, 0x6C, 0x5D, 0x36};
static const GUID CLIENTID_FILESAVE = {0x3B2E2261, 0x402D, 0x4049, 0xB0, 0xC0, 0x91, 0x13, 0xF8, 0x6E, 0x84, 0x7C};
static const GUID CLIENTID_FILESAVE_PASSWORD = {0xC12D4F4C, 0x4D41, 0x4D4F, 0x97, 0xEF, 0x87, 0xF9, 0x8D, 0xB6, 0x1E, 0xA6};
static const GUID CLIENTID_FILESAVE_SELECTION = {0x5B2482B3, 0x0358, 0x4E09, 0xAA, 0x64, 0x2B, 0x76, 0xB2, 0xA0, 0xDD, 0xFE};
static const GUID CLIENTID_FILESAVE_TEMPLATE = {0x9996D877, 0x20D5, 0x424B, 0x9C, 0x2E, 0xD3, 0xB6, 0x31, 0xEC, 0xF7, 0xCE};
static const GUID CLIENTID_FILEOPEN_LINK_TEMPLATE = {0x32237796, 0x1509, 0x49D1, 0xBB, 0x7E, 0x63, 0xAD, 0x36, 0xAE, 0x86, 0x8C};
static const GUID CLIENTID_FILEOPEN_PLAY = {0x32CFB147, 0xF5AE, 0x4F90, 0xA1, 0xF1, 0x81, 0x20, 0x72, 0xBB, 0x2F, 0xC5};
static const GUID CLIENTID_FILEOPEN_LINK = {0x39AC4BAE, 0x7D2D, 0x46BC, 0xBE, 0x2E, 0xF8, 0x8C, 0xB5, 0x65, 0x5E, 0x6A};
//-----------------------------------------------------------------------------
::rtl::OUString lcl_getURLFromShellItem (IShellItem* pItem)
{
LPOLESTR pStr = NULL;
::rtl::OUString sURL;
SIGDN eConversion = SIGDN_FILESYSPATH;
HRESULT hr = pItem->GetDisplayName ( eConversion, &pStr );
if ( FAILED(hr) )
{
eConversion = SIGDN_URL;
hr = pItem->GetDisplayName ( eConversion, &pStr );
if ( FAILED(hr) )
return ::rtl::OUString();
sURL = ::rtl::OUString(reinterpret_cast<sal_Unicode*>(pStr));
}
else
{
::osl::FileBase::getFileURLFromSystemPath( reinterpret_cast<sal_Unicode*>(pStr), sURL );
}
CoTaskMemFree (pStr);
return sURL;
}
//-----------------------------------------------------------------------------------------
::std::vector< COMDLG_FILTERSPEC > lcl_buildFilterList(CFilterContainer& rContainer)
{
const sal_Int32 c = rContainer.numFilter();
sal_Int32 i = 0;
::std::vector< COMDLG_FILTERSPEC > lList ;
CFilterContainer::FILTER_ENTRY_T aFilter;
rContainer.beginEnumFilter( );
while( rContainer.getNextFilter(aFilter) )
{
COMDLG_FILTERSPEC aSpec;
aSpec.pszName = reinterpret_cast<LPCTSTR>(aFilter.first.getStr()) ;
aSpec.pszSpec = reinterpret_cast<LPCTSTR>(aFilter.second.getStr());
lList.push_back(aSpec);
}
return lList;
}
//-----------------------------------------------------------------------------------------
VistaFilePickerImpl::VistaFilePickerImpl()
: m_iDialogOpen ()
, m_iDialogSave ()
, m_hLastResult ()
, m_lFilters ()
, m_lLastFiles ()
, m_iEventHandler(new VistaFilePickerEventHandler(this))
, m_bInExecute (sal_False)
, m_bWasExecuted (sal_False)
, m_sDirectory ()
, m_sFilename ()
{
m_hParentWindow = choose_parent_window();
}
//-------------------------------------------------------------------------------
VistaFilePickerImpl::~VistaFilePickerImpl()
{
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::before()
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
// TRICKY .-)
// osl::Thread class initializes COm already in MTA mode because it's needed
// by VCL and UNO so. There is no way to change that from outside ...
// but we need a STA environment ...
// So we make it by try-and-error ...
// If first CoInitialize will fail .. we unitialize COM initialize it new .-)
m_hLastResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if ( FAILED(m_hLastResult) )
{
CoUninitialize();
m_hLastResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::doRequest(const RequestRef& rRequest)
{
try
{
switch(rRequest->getRequest())
{
case E_ADD_PICKER_LISTENER :
impl_sta_addFilePickerListener(rRequest);
break;
case E_REMOVE_PICKER_LISTENER :
impl_sta_removeFilePickerListener(rRequest);
break;
case E_APPEND_FILTER :
impl_sta_appendFilter(rRequest);
break;
case E_APPEND_FILTERGROUP :
impl_sta_appendFilterGroup(rRequest);
break;
case E_SET_CURRENT_FILTER :
impl_sta_setCurrentFilter(rRequest);
break;
case E_GET_CURRENT_FILTER :
impl_sta_getCurrentFilter(rRequest);
break;
case E_CREATE_OPEN_DIALOG :
impl_sta_CreateOpenDialog(rRequest);
break;
case E_CREATE_SAVE_DIALOG :
impl_sta_CreateSaveDialog(rRequest);
break;
case E_SET_MULTISELECTION_MODE :
impl_sta_SetMultiSelectionMode(rRequest);
break;
case E_SET_TITLE :
impl_sta_SetTitle(rRequest);
break;
case E_SET_FILENAME:
impl_sta_SetFileName(rRequest);
break;
case E_SET_DIRECTORY :
impl_sta_SetDirectory(rRequest);
break;
case E_GET_DIRECTORY :
impl_sta_GetDirectory(rRequest);
break;
case E_SET_DEFAULT_NAME :
impl_sta_SetDefaultName(rRequest);
break;
case E_GET_SELECTED_FILES :
impl_sta_getSelectedFiles(rRequest);
break;
case E_SHOW_DIALOG_MODAL :
impl_sta_ShowDialogModal(rRequest);
break;
case E_SET_CONTROL_VALUE :
impl_sta_SetControlValue(rRequest);
break;
case E_GET_CONTROL_VALUE :
impl_sta_GetControlValue(rRequest);
break;
case E_SET_CONTROL_LABEL :
impl_sta_SetControlLabel(rRequest);
break;
case E_GET_CONTROL_LABEL :
impl_sta_GetControlLabel(rRequest);
break;
case E_ENABLE_CONTROL :
impl_sta_EnableControl(rRequest);
break;
// no default: let the compiler detect changes on enum ERequest !
}
}
catch(...)
{}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::after()
{
CoUninitialize();
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_addFilePickerListener(const RequestRef& rRequest)
{
// SYNCHRONIZED outside !
const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest->getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >());
if ( ! xListener.is())
return;
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialogEvents iHandler = m_iEventHandler;
aLock.clear();
// <- SYNCHRONIZED
VistaFilePickerEventHandler* pHandlerImpl = (VistaFilePickerEventHandler*)iHandler.get();
if (pHandlerImpl)
pHandlerImpl->addFilePickerListener(xListener);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_removeFilePickerListener(const RequestRef& rRequest)
{
// SYNCHRONIZED outside !
const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest->getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >());
if ( ! xListener.is())
return;
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialogEvents iHandler = m_iEventHandler;
aLock.clear();
// <- SYNCHRONIZED
VistaFilePickerEventHandler* pHandlerImpl = (VistaFilePickerEventHandler*)iHandler.get();
if (pHandlerImpl)
pHandlerImpl->removeFilePickerListener(xListener);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_appendFilter(const RequestRef& rRequest)
{
const ::rtl::OUString sTitle = rRequest->getArgumentOrDefault(PROP_FILTER_TITLE, ::rtl::OUString());
const ::rtl::OUString sFilter = rRequest->getArgumentOrDefault(PROP_FILTER_VALUE, ::rtl::OUString());
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
m_lFilters.addFilter(sTitle, sFilter);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_appendFilterGroup(const RequestRef& rRequest)
{
const css::uno::Sequence< css::beans::StringPair > aFilterGroup =
rRequest->getArgumentOrDefault(PROP_FILTER_GROUP, css::uno::Sequence< css::beans::StringPair >());
// SYNCHRONIZED->
::rtl::OUString aEmpty;
::osl::ResettableMutexGuard aLock(m_aMutex);
if ( m_lFilters.numFilter() > 0 && aFilterGroup.getLength() > 0 )
m_lFilters.addFilter( STRING_SEPARATOR, aEmpty, sal_True );
::sal_Int32 c = aFilterGroup.getLength();
::sal_Int32 i = 0;
for (i=0; i<c; ++i)
{
const css::beans::StringPair& rFilter = aFilterGroup[i];
m_lFilters.addFilter(rFilter.First, rFilter.Second);
}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_setCurrentFilter(const RequestRef& rRequest)
{
const ::rtl::OUString sTitle = rRequest->getArgumentOrDefault(PROP_FILTER_TITLE, ::rtl::OUString());
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
m_lFilters.setCurrentFilter(sTitle);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_getCurrentFilter(const RequestRef& rRequest)
{
TFileDialog iDialog = impl_getBaseDialogInterface();
UINT nIndex = UINT_MAX;
HRESULT hResult = iDialog->GetFileTypeIndex(&nIndex);
if (
( FAILED(hResult) ) ||
( nIndex == UINT_MAX ) // COM dialog sometimes return S_OK for empty filter lists .-(
)
return;
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
::rtl::OUString sTitle;
::sal_Int32 nRealIndex = (nIndex-1); // COM dialog base on 1 ... filter container on 0 .-)
if (
(nRealIndex >= 0 ) &&
(m_lFilters.getFilter(nRealIndex, sTitle))
)
rRequest->setArgument(PROP_FILTER_TITLE, sTitle);
else if ( nRealIndex == -1 ) // Dialog not visible yet
{
sTitle = m_lFilters.getCurrentFilter();
rRequest->setArgument(PROP_FILTER_TITLE, sTitle);
}
aLock.clear();
// <- SYNCHRONIZED
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_CreateOpenDialog(const RequestRef& rRequest)
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
m_hLastResult = m_iDialogOpen.create();
if (FAILED(m_hLastResult))
return;
TFileDialog iDialog;
#ifdef __MINGW32__
m_iDialogOpen->QueryInterface(IID_IFileDialog, (void **)(&iDialog));
#else
m_iDialogOpen.query(&iDialog);
#endif
TFileDialogEvents iHandler = m_iEventHandler;
aLock.clear();
// <- SYNCHRONIZED
DWORD nFlags = 0;
iDialog->GetOptions ( &nFlags );
nFlags &= ~FOS_FORCESHOWHIDDEN;
nFlags |= FOS_PATHMUSTEXIST;
nFlags |= FOS_FILEMUSTEXIST;
nFlags |= FOS_OVERWRITEPROMPT;
nFlags |= FOS_DONTADDTORECENT;
iDialog->SetOptions ( nFlags );
::sal_Int32 nFeatures = rRequest->getArgumentOrDefault(PROP_FEATURES, (::sal_Int32)0);
::sal_Int32 nTemplate = rRequest->getArgumentOrDefault(PROP_TEMPLATE_DESCR, (::sal_Int32)0);
impl_sta_enableFeatures(nFeatures, nTemplate);
VistaFilePickerEventHandler* pHandlerImpl = (VistaFilePickerEventHandler*)iHandler.get();
if (pHandlerImpl)
pHandlerImpl->startListening(iDialog);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_CreateSaveDialog(const RequestRef& rRequest)
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
m_hLastResult = m_iDialogSave.create();
if (FAILED(m_hLastResult))
return;
TFileDialogEvents iHandler = m_iEventHandler;
TFileDialog iDialog;
#ifdef __MINGW32__
m_iDialogSave->QueryInterface(IID_IFileDialog, (void **)(&iDialog));
#else
m_iDialogSave.query(&iDialog);
#endif
aLock.clear();
// <- SYNCHRONIZED
DWORD nFlags = 0;
iDialog->GetOptions ( &nFlags );
nFlags &= ~FOS_FORCESHOWHIDDEN;
nFlags |= FOS_PATHMUSTEXIST;
nFlags |= FOS_FILEMUSTEXIST;
nFlags |= FOS_OVERWRITEPROMPT;
nFlags |= FOS_DONTADDTORECENT;
iDialog->SetOptions ( nFlags );
::sal_Int32 nFeatures = rRequest->getArgumentOrDefault(PROP_FEATURES, (::sal_Int32)0);
::sal_Int32 nTemplate = rRequest->getArgumentOrDefault(PROP_TEMPLATE_DESCR, (::sal_Int32)0);
impl_sta_enableFeatures(nFeatures, nTemplate);
VistaFilePickerEventHandler* pHandlerImpl = (VistaFilePickerEventHandler*)iHandler.get();
if (pHandlerImpl)
pHandlerImpl->startListening(iDialog);
}
//-------------------------------------------------------------------------------
static const ::sal_Int32 GROUP_VERSION = 1;
static const ::sal_Int32 GROUP_TEMPLATE = 2;
static const ::sal_Int32 GROUP_IMAGETEMPLATE = 3;
static const ::sal_Int32 GROUP_CHECKBOXES = 4;
//-------------------------------------------------------------------------------
static void setLabelToControl(CResourceProvider& rResourceProvider, TFileDialogCustomize iCustom, sal_uInt16 nControlId)
{
::rtl::OUString aLabel = rResourceProvider.getResString(nControlId);
aLabel = SOfficeToWindowsLabel(aLabel);
iCustom->SetControlLabel(nControlId, reinterpret_cast<LPCWSTR>(aLabel.getStr()) );
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures, ::sal_Int32 nTemplate)
{
GUID aGUID = {};
switch (nTemplate)
{
case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE :
case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE :
aGUID = CLIENTID_FILEDIALOG_SIMPLE;
break;
case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION :
case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS :
aGUID = CLIENTID_FILEDIALOG_OPTIONS;
break;
case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION :
aGUID = CLIENTID_FILESAVE;
break;
case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD :
aGUID = CLIENTID_FILESAVE_PASSWORD;
break;
case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION :
aGUID = CLIENTID_FILESAVE_SELECTION;
break;
case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE :
aGUID = CLIENTID_FILESAVE_TEMPLATE;
break;
case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE :
aGUID = CLIENTID_FILEOPEN_LINK_TEMPLATE;
break;
case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY :
aGUID = CLIENTID_FILEOPEN_PLAY;
break;
case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW :
aGUID = CLIENTID_FILEOPEN_LINK;
break;
}
TFileDialog iDialog = impl_getBaseDialogInterface();
iDialog->SetClientGuid ( aGUID );
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ((nFeatures & FEATURE_VERSION) == FEATURE_VERSION)
{
iCustom->StartVisualGroup (GROUP_VERSION, L"Version");
iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION);
iCustom->EndVisualGroup ();
iCustom->MakeProminent (GROUP_VERSION);
}
if ((nFeatures & FEATURE_TEMPLATE) == FEATURE_TEMPLATE)
{
iCustom->StartVisualGroup (GROUP_TEMPLATE, L"Template");
iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE);
iCustom->EndVisualGroup ();
iCustom->MakeProminent (GROUP_TEMPLATE);
}
if ((nFeatures & FEATURE_IMAGETEMPLATE) == FEATURE_IMAGETEMPLATE)
{
iCustom->StartVisualGroup (GROUP_IMAGETEMPLATE, L"Style");
iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE);
iCustom->EndVisualGroup ();
iCustom->MakeProminent (GROUP_IMAGETEMPLATE);
}
iCustom->StartVisualGroup (GROUP_CHECKBOXES, L"");
sal_uInt16 nControlId(0);
if ((nFeatures & FEATURE_AUTOEXTENSION) == FEATURE_AUTOEXTENSION)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION;
iCustom->AddCheckButton (nControlId, L"Auto Extension", true);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
if ((nFeatures & FEATURE_PASSWORD) == FEATURE_PASSWORD)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD;
iCustom->AddCheckButton (nControlId, L"Password", false);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
if ((nFeatures & FEATURE_READONLY) == FEATURE_READONLY)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY;
iCustom->AddCheckButton (nControlId, L"Readonly", false);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
if ((nFeatures & FEATURE_FILTEROPTIONS) == FEATURE_FILTEROPTIONS)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS;
iCustom->AddCheckButton (nControlId, L"Filter Options", false);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
if ((nFeatures & FEATURE_LINK) == FEATURE_LINK)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK;
iCustom->AddCheckButton (nControlId, L"Link", false);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
if ((nFeatures & FEATURE_SELECTION) == FEATURE_SELECTION)
{
nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION;
iCustom->AddCheckButton (nControlId, L"Selection", false);
setLabelToControl(m_ResProvider, iCustom, nControlId);
}
/* can be ignored ... new COM dialog supports preview native now !
if ((nFeatures & FEATURE_PREVIEW) == FEATURE_PREVIEW)
iCustom->AddCheckButton (css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, L"Preview", false);
*/
iCustom->EndVisualGroup();
if ((nFeatures & FEATURE_PLAY) == FEATURE_PLAY)
iCustom->AddPushButton (css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY, L"Play");
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetMultiSelectionMode(const RequestRef& rRequest)
{
const ::sal_Bool bMultiSelection = rRequest->getArgumentOrDefault(PROP_MULTISELECTION_MODE, (::sal_Bool)sal_True);
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialog iDialog = impl_getBaseDialogInterface();
aLock.clear();
// <- SYNCHRONIZED
DWORD nFlags = 0;
m_hLastResult = iDialog->GetOptions ( &nFlags );
if (bMultiSelection)
nFlags |= FOS_ALLOWMULTISELECT;
else
nFlags &= ~FOS_ALLOWMULTISELECT;
iDialog->SetOptions ( nFlags );
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetTitle(const RequestRef& rRequest)
{
::rtl::OUString sTitle = rRequest->getArgumentOrDefault(PROP_TITLE, ::rtl::OUString());
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialog iDialog = impl_getBaseDialogInterface();
aLock.clear();
// <- SYNCHRONIZED
iDialog->SetTitle(reinterpret_cast<LPCTSTR>(sTitle.getStr()));
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetFileName(const RequestRef& rRequest)
{
::rtl::OUString sFileName = rRequest->getArgumentOrDefault(PROP_FILENAME, ::rtl::OUString());
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialog iDialog = impl_getBaseDialogInterface();
aLock.clear();
// <- SYNCHRONIZED
iDialog->SetFileName(reinterpret_cast<LPCTSTR>(sFileName.getStr()));
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetDirectory(const RequestRef& rRequest)
{
::rtl::OUString sDirectory = rRequest->getArgumentOrDefault(PROP_DIRECTORY, ::rtl::OUString());
bool bForce = rRequest->getArgumentOrDefault(PROP_FORCE, false);
if( !m_bInExecute)
{
// Vista stores last used folders for file dialogs
// so we don't want the application to change the folder
// in most cases.
// Store the requested folder in the mean time and decide later
// what to do
m_sDirectory = sDirectory;
}
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialog iDialog = impl_getBaseDialogInterface();
aLock.clear();
// <- SYNCHRONIZED
ComPtr< IShellItem > pFolder;
#ifdef __MINGW32__
HRESULT hResult = SHCreateItemFromParsingName ( reinterpret_cast<LPCTSTR>(sDirectory.getStr()), NULL, IID_IShellItem, reinterpret_cast<void**>(&pFolder) );
#else
HRESULT hResult = SHCreateItemFromParsingName( sDirectory.getStr(), NULL, IID_PPV_ARGS(&pFolder) );
#endif
if ( FAILED(hResult) )
return;
if ( m_bInExecute || bForce )
iDialog->SetFolder(pFolder);
else
{
// Use set default folder as Microsoft recommends in the IFileDialog documentation.
iDialog->SetDefaultFolder(pFolder);
}
}
void VistaFilePickerImpl::impl_sta_GetDirectory(const RequestRef& rRequest)
{
TFileDialog iDialog = impl_getBaseDialogInterface();
ComPtr< IShellItem > pFolder;
HRESULT hResult = iDialog->GetFolder( &pFolder );
if ( FAILED(hResult) )
return;
::rtl::OUString sFolder = lcl_getURLFromShellItem ( pFolder );
if( sFolder.getLength())
rRequest->setArgument( PROP_DIRECTORY, sFolder );
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetDefaultName(const RequestRef& rRequest)
{
::rtl::OUString sFilename = rRequest->getArgumentOrDefault(PROP_FILENAME, ::rtl::OUString());
TFileDialog iDialog = impl_getBaseDialogInterface();
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ( ! iCustom.is())
return;
// if we have the autoextension check box set, remove (or change ???) the extension of the filename
// so that the autoextension mechanism can do its job
BOOL bValue = FALSE;
HRESULT hResult = iCustom->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
if ( bValue )
{
sal_Int32 nSepPos = sFilename.lastIndexOf( '.' );
if ( -1 != nSepPos )
sFilename = sFilename.copy(0, nSepPos);
}
iDialog->SetFileName ( reinterpret_cast<LPCTSTR>(sFilename.getStr()));
m_sFilename = sFilename;
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_setFiltersOnDialog()
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
::std::vector< COMDLG_FILTERSPEC > lFilters = lcl_buildFilterList(m_lFilters);
::rtl::OUString sCurrentFilter = m_lFilters.getCurrentFilter();
sal_Int32 nCurrentFilter = m_lFilters.getFilterPos(sCurrentFilter);
TFileDialog iDialog = impl_getBaseDialogInterface();
TFileDialogCustomize iCustomize = impl_getCustomizeInterface();
aLock.clear();
// <- SYNCHRONIZED
if (lFilters.empty())
return;
COMDLG_FILTERSPEC *pFilt = &lFilters[0];
iDialog->SetFileTypes(lFilters.size(), pFilt/*&lFilters[0]*/);
iDialog->SetFileTypeIndex(nCurrentFilter + 1);
BOOL bValue = FALSE;
HRESULT hResult = iCustomize->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
if ( bValue )
{
LPCWSTR lpFilterExt = lFilters[0].pszSpec;
lpFilterExt = wcsrchr( lpFilterExt, '.' );
if ( lpFilterExt )
lpFilterExt++;
iDialog->SetDefaultExtension( lpFilterExt );
}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_getSelectedFiles(const RequestRef& rRequest)
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileOpenDialog iOpen = m_iDialogOpen;
TFileSaveDialog iSave = m_iDialogSave;
::sal_Bool bInExecute = m_bInExecute;
aLock.clear();
// <- SYNCHRONIZED
// ask dialog for results
// Note : we must differ between single/multi selection !
// Note further: we must react different if dialog is in execute or not .-(
ComPtr< IShellItem > iItem;
ComPtr< IShellItemArray > iItems;
HRESULT hResult = E_FAIL;
if (iOpen.is())
{
if (bInExecute)
hResult = iOpen->GetSelectedItems(&iItems);
else
{
hResult = iOpen->GetResults(&iItems);
if (FAILED(hResult))
hResult = iOpen->GetResult(&iItem);
}
}
else
if (iSave.is())
{
if (bInExecute)
hResult = iSave->GetCurrentSelection(&iItem);
else
hResult = iSave->GetResult(&iItem);
}
if (FAILED(hResult))
return;
// convert and pack results
TStringList lFiles;
if (iItem.is())
{
const ::rtl::OUString sURL = lcl_getURLFromShellItem(iItem);
if (sURL.getLength() > 0)
lFiles.push_back(sURL);
}
if (iItems.is())
{
DWORD nCount;
hResult = iItems->GetCount(&nCount);
if ( SUCCEEDED(hResult) )
{
for (DWORD i=0; i<nCount; ++i)
{
hResult = iItems->GetItemAt(i, &iItem);
if ( SUCCEEDED(hResult) )
{
const ::rtl::OUString sURL = lcl_getURLFromShellItem(iItem);
if (sURL.getLength() > 0)
lFiles.push_back(sURL);
}
}
}
}
rRequest->setArgument(PROP_SELECTED_FILES, lFiles.getAsConstList());
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_ShowDialogModal(const RequestRef& rRequest)
{
impl_sta_setFiltersOnDialog();
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
TFileDialog iDialog = impl_getBaseDialogInterface();
TFileOpenDialog iOpen = m_iDialogOpen;
TFileSaveDialog iSave = m_iDialogSave;
// it's important to know if we are showing the dialog.
// Some dialog interface methods cant be called then or some
// tasks must be done differently .-) (e.g. see impl_sta_getSelectedFiles())
m_bInExecute = sal_True;
m_bWasExecuted = sal_True;
aLock.clear();
// <- SYNCHRONIZED
// we set the directory only if we have a save dialog and a filename
// for the other cases, the file dialog remembers its last location
// according to its client guid.
if( m_sDirectory.getLength())
{
ComPtr< IShellItem > pFolder;
#ifdef __MINGW32__
HRESULT hResult = SHCreateItemFromParsingName ( reinterpret_cast<LPCTSTR>(m_sDirectory.getStr()), NULL, IID_IShellItem, reinterpret_cast<void**>(&pFolder) );
#else
HRESULT hResult = SHCreateItemFromParsingName( m_sDirectory.getStr(), NULL, IID_PPV_ARGS(&pFolder) );
#endif
if ( SUCCEEDED(hResult) )
{
if (m_sFilename.getLength())
{
::rtl::OUString aFileURL(m_sDirectory);
sal_Int32 nIndex = aFileURL.lastIndexOf('/');
if (nIndex != aFileURL.getLength()-1)
aFileURL += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/"));
aFileURL += m_sFilename;
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
BOOL bValue = FALSE;
HRESULT hResult = iCustom->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
if ( bValue )
{
::rtl::OUString aExt;
UINT nFileType;
hResult = iDialog->GetFileTypeIndex(&nFileType);
if ( SUCCEEDED(hResult) && nFileType > 0 )
{
::sal_Int32 nRealIndex = (nFileType-1); // COM dialog base on 1 ... filter container on 0 .-)
::std::vector< COMDLG_FILTERSPEC > lFilters = lcl_buildFilterList(m_lFilters);
if ( nRealIndex < lFilters.size() )
{
LPCWSTR lpFilterExt = lFilters[nRealIndex].pszSpec;
lpFilterExt = wcsrchr( lpFilterExt, '.' );
if ( lpFilterExt )
aFileURL += reinterpret_cast<const sal_Unicode*>(lpFilterExt);
}
}
}
// Check existence of file. Set folder only for this special case
::rtl::OUString aSystemPath;
osl_getSystemPathFromFileURL( aFileURL.pData, &aSystemPath.pData );
WIN32_FIND_DATA aFindFileData;
HANDLE hFind = FindFirstFile( reinterpret_cast<LPCWSTR>(aSystemPath.getStr()), &aFindFileData );
if (hFind != INVALID_HANDLE_VALUE)
iDialog->SetFolder(pFolder);
else
hResult = iDialog->AddPlace(pFolder, FDAP_TOP);
FindClose( hFind );
}
else
hResult = iDialog->AddPlace(pFolder, FDAP_TOP);
}
}
HRESULT hResult = E_FAIL;
try
{
// show dialog and wait for user decision
if (iOpen.is())
hResult = iOpen->Show( m_hParentWindow ); // parent window needed
else
if (iSave.is())
hResult = iSave->Show( m_hParentWindow ); // parent window needed
}
catch(...)
{}
// SYNCHRONIZED->
aLock.reset();
m_bInExecute = sal_False;
aLock.clear();
// <- SYNCHRONIZED
if ( FAILED(hResult) )
return;
impl_sta_getSelectedFiles(rRequest);
rRequest->setArgument(PROP_DIALOG_SHOW_RESULT, sal_True);
}
//-------------------------------------------------------------------------------
TFileDialog VistaFilePickerImpl::impl_getBaseDialogInterface()
{
TFileDialog iDialog;
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
if (m_iDialogOpen.is())
#ifdef __MINGW32__
m_iDialogOpen->QueryInterface(IID_IFileDialog, (void**)(&iDialog));
#else
m_iDialogOpen.query(&iDialog);
#endif
if (m_iDialogSave.is())
#ifdef __MINGW32__
m_iDialogSave->QueryInterface(IID_IFileDialog, (void**)(&iDialog));
#else
m_iDialogSave.query(&iDialog);
#endif
return iDialog;
}
//-------------------------------------------------------------------------------
TFileDialogCustomize VistaFilePickerImpl::impl_getCustomizeInterface()
{
TFileDialogCustomize iCustom;
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
if (m_iDialogOpen.is())
#ifdef __MINGW32__
m_iDialogOpen->QueryInterface(IID_IFileDialogCustomize, (void**)(&iCustom));
#else
m_iDialogOpen.query(&iCustom);
#endif
else
if (m_iDialogSave.is())
#ifdef __MINGW32__
m_iDialogSave->QueryInterface(IID_IFileDialogCustomize, (void**)(&iCustom));
#else
m_iDialogSave.query(&iCustom);
#endif
return iCustom;
}
//-------------------------------------------------------------------------------
void lcl_removeControlItemsWorkaround(const TFileDialogCustomize& iCustom ,
::sal_Int16 nControlId)
{
::sal_Int32 i = 0;
HRESULT hResult;
hResult = iCustom->SetSelectedControlItem(nControlId, 1000);
hResult = S_OK;
while ( SUCCEEDED(hResult) )
hResult = iCustom->RemoveControlItem(nControlId, i++);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetControlValue(const RequestRef& rRequest)
{
::sal_Int16 nId = rRequest->getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
::sal_Int16 nAction = rRequest->getArgumentOrDefault(PROP_CONTROL_ACTION, INVALID_CONTROL_ACTION);
css::uno::Any aValue = rRequest->getArgumentOrDefault(PROP_CONTROL_VALUE , css::uno::Any() );
// dont check for right values here ...
// most parameters are optional !
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ( ! iCustom.is())
return;
switch (nId)
{
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK :
//case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
{
::sal_Bool bValue = sal_False;
aValue >>= bValue;
iCustom->SetCheckButtonState(nId, bValue);
}
break;
case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION :
case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE :
case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE :
{
HRESULT hResult;
switch (nAction)
{
case css::ui::dialogs::ControlActions::DELETE_ITEMS :
{
hResult = iCustom->RemoveAllControlItems(nId);
if ( FAILED(hResult) )
lcl_removeControlItemsWorkaround(iCustom, nId);
}
break;
case css::ui::dialogs::ControlActions::ADD_ITEMS :
{
css::uno::Sequence< ::rtl::OUString > lItems;
aValue >>= lItems;
for (::sal_Int32 i=0; i<lItems.getLength(); ++i)
{
const ::rtl::OUString& sItem = lItems[i];
hResult = iCustom->AddControlItem(nId, i, reinterpret_cast<LPCTSTR>(sItem.getStr()));
}
}
break;
case css::ui::dialogs::ControlActions::SET_SELECT_ITEM :
{
::sal_Int32 nItem = 0;
aValue >>= nItem;
hResult = iCustom->SetSelectedControlItem(nId, nItem);
}
break;
}
}
break;
case css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY :
{
}
break;
}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_GetControlValue(const RequestRef& rRequest)
{
::sal_Int16 nId = rRequest->getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
::sal_Int16 nAction = rRequest->getArgumentOrDefault(PROP_CONTROL_ACTION, INVALID_CONTROL_ACTION);
// dont check for right values here ...
// most parameters are optional !
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ( ! iCustom.is())
return;
css::uno::Any aValue;
if( m_bWasExecuted )
switch (nId)
{
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK :
//case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
{
BOOL bValue = FALSE;
HRESULT hResult = iCustom->GetCheckButtonState(nId, &bValue);
if ( SUCCEEDED(hResult) )
aValue = css::uno::makeAny((sal_Bool)bValue);
}
break;
}
if (aValue.hasValue())
rRequest->setArgument(PROP_CONTROL_VALUE, aValue);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_SetControlLabel(const RequestRef& rRequest)
{
::sal_Int16 nId = rRequest->getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
::rtl::OUString sLabel = rRequest->getArgumentOrDefault(PROP_CONTROL_LABEL, ::rtl::OUString() );
// dont check for right values here ...
// most parameters are optional !
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ( ! iCustom.is())
return;
iCustom->SetControlLabel ( nId, reinterpret_cast<LPCTSTR>(sLabel.getStr()));
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_GetControlLabel(const RequestRef& /*rRequest*/)
{
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_sta_EnableControl(const RequestRef& rRequest)
{
::sal_Int16 nId = rRequest->getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
::sal_Bool bEnabled = rRequest->getArgumentOrDefault(PROP_CONTROL_ENABLE, (::sal_Bool)sal_True);
// dont check for right values here ...
// most parameters are optional !
TFileDialogCustomize iCustom = impl_getCustomizeInterface();
if ( ! iCustom.is())
return;
CDCONTROLSTATEF eState = CDCS_VISIBLE;
if (bEnabled)
eState |= CDCS_ENABLED;
else
eState |= CDCS_INACTIVE;
iCustom->SetControlState(nId, eState);
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::impl_SetDefaultExtension( const rtl::OUString& currentFilter )
{
TFileDialog iDialog = impl_getBaseDialogInterface();
if (currentFilter.getLength())
{
rtl::OUString FilterExt;
m_lFilters.getFilter(currentFilter, FilterExt);
sal_Int32 posOfPoint = FilterExt.indexOf(L'.');
const sal_Unicode* pFirstExtStart = FilterExt.getStr() + posOfPoint + 1;
sal_Int32 posOfSemiColon = FilterExt.indexOf(L';') - 1;
if (posOfSemiColon < 0)
posOfSemiColon = FilterExt.getLength() - 1;
FilterExt = rtl::OUString(pFirstExtStart, posOfSemiColon - posOfPoint);
iDialog->SetDefaultExtension ( reinterpret_cast<LPCTSTR>(FilterExt.getStr()) );
}
}
static void impl_refreshFileDialog( TFileDialog iDialog )
{
if ( SUCCEEDED(iDialog->SetFileName(L"")) &&
SUCCEEDED(iDialog->SetFileName(L"*.*")) )
{
IOleWindow* iOleWindow;
#ifdef __MINGW32__
if (SUCCEEDED(iDialog->QueryInterface(IID_IOleWindow, reinterpret_cast<void**>(&iOleWindow))))
#else
if (SUCCEEDED(iDialog->QueryInterface(IID_PPV_ARGS(&iOleWindow))))
#endif
{
HWND hwnd;
if (SUCCEEDED(iOleWindow->GetWindow(&hwnd)))
{
PostMessage(hwnd, WM_COMMAND, IDOK, 0);
}
iOleWindow->Release();
}
}
}
//-------------------------------------------------------------------------------
void VistaFilePickerImpl::onAutoExtensionChanged (bool bChecked)
{
// SYNCHRONIZED->
::osl::ResettableMutexGuard aLock(m_aMutex);
const ::rtl::OUString sFilter = m_lFilters.getCurrentFilter ();
::rtl::OUString sExt ;
if ( !m_lFilters.getFilter (sFilter, sExt))
return;
TFileDialog iDialog = impl_getBaseDialogInterface();
aLock.clear();
// <- SYNCHRONIZED
LPCWSTR pExt = 0;
if ( bChecked )
{
pExt = reinterpret_cast<LPCTSTR>(sExt.getStr());
pExt = wcsrchr( pExt, '.' );
if ( pExt )
pExt++;
}
iDialog->SetDefaultExtension( pExt );
}
bool VistaFilePickerImpl::onFileTypeChanged( UINT /*nTypeIndex*/ )
{
return true;
}
} // namespace vista
} // namespace win32
} // namespace fpicker