/************************************************************** * * 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 #include #include #include #include #include #include #ifdef __MINGW32__ #include #endif #include "..\misc\WinImplHelper.hxx" #include 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(pStr)); } else { ::osl::FileBase::getFileURLFromSystemPath( reinterpret_cast(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(aFilter.first.getStr()) ; aSpec.pszSpec = reinterpret_cast(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; igetArgumentOrDefault(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(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(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(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(sDirectory.getStr()), NULL, IID_IShellItem, reinterpret_cast(&pFolder) ); #else HRESULT hResult = SHCreateItemFromParsingName ( sDirectory, 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(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 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; iGetItemAt(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(m_sDirectory.getStr()), NULL, IID_IShellItem, reinterpret_cast(&pFolder) ); #else HRESULT hResult = SHCreateItemFromParsingName ( m_sDirectory, 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) ) { ::sal_Int32 nRealIndex = (nFileType-1); // COM dialog base on 1 ... filter container on 0 .-) ::std::vector< COMDLG_FILTERSPEC > lFilters = lcl_buildFilterList(m_lFilters); LPCWSTR lpFilterExt = lFilters[nRealIndex].pszSpec; lpFilterExt = wcsrchr( lpFilterExt, '.' ); if ( lpFilterExt ) aFileURL += reinterpret_cast(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(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; iAddControlItem(nId, i, reinterpret_cast(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(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(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(&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(sExt.getStr()); pExt = wcsrchr( pExt, '.' ); if ( pExt ) pExt++; } iDialog->SetDefaultExtension( pExt ); } bool VistaFilePickerImpl::onFileTypeChanged( UINT /*nTypeIndex*/ ) { return true; } } // namespace vista } // namespace win32 } // namespace fpicker