diff options
Diffstat (limited to 'fpicker/source/win32')
24 files changed, 5142 insertions, 0 deletions
diff --git a/fpicker/source/win32/FPServiceInfo.hxx b/fpicker/source/win32/FPServiceInfo.hxx new file mode 100644 index 000000000..edc350c1a --- /dev/null +++ b/fpicker/source/win32/FPServiceInfo.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_FPSERVICEINFO_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_FPSERVICEINFO_HXX + +// the service names +#define FILE_PICKER_SERVICE_NAME "com.sun.star.ui.dialogs.SystemFilePicker" + +// the implementation names +#define FILE_PICKER_IMPL_NAME "com.sun.star.ui.dialogs.Win32FilePicker" + +// the service names +#define FOLDER_PICKER_SERVICE_NAME "com.sun.star.ui.dialogs.SystemFolderPicker" + +// the implementation names +#define FOLDER_PICKER_IMPL_NAME "com.sun.star.ui.dialogs.Win32FolderPicker" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/FPentry.cxx b/fpicker/source/win32/FPentry.cxx new file mode 100644 index 000000000..a4e48f886 --- /dev/null +++ b/fpicker/source/win32/FPentry.cxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <cppuhelper/factory.hxx> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include "FPServiceInfo.hxx" + +#include "VistaFilePicker.hxx" +#include "WinImplHelper.hxx" +#include <stdio.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::cppu; +using ::com::sun::star::ui::dialogs::XFilePicker2; +using ::com::sun::star::ui::dialogs::XFolderPicker2; + +static Reference< XInterface > createInstance( + const Reference< XMultiServiceFactory >& rServiceManager ) +{ + return Reference<ui::dialogs::XFilePicker2>( + new ::fpicker::win32::vista::VistaFilePicker(rServiceManager, false)); +} + +static Reference< XInterface > +createInstance_fop( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + return Reference<ui::dialogs::XFolderPicker2>( + new ::fpicker::win32::vista::VistaFilePicker(rServiceManager, true)); +} + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void* fps_win32_component_getFactory( + const char* pImplName, void* pSrvManager, void* ) +{ + void* pRet = nullptr; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, FILE_PICKER_IMPL_NAME ) ) ) + { + Sequence<OUString> aSNS { FILE_PICKER_SERVICE_NAME }; + + Reference< XSingleServiceFactory > xFactory ( createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createInstance, + aSNS ) ); + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, FOLDER_PICKER_IMPL_NAME ) ) ) + { + Sequence<OUString> aSNS { FOLDER_PICKER_SERVICE_NAME }; + + Reference< XSingleServiceFactory > xFactory ( createSingleFactory( + static_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createInstance_fop, + aSNS ) ); + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/FilterContainer.cxx b/fpicker/source/win32/FilterContainer.cxx new file mode 100644 index 000000000..67ccd6353 --- /dev/null +++ b/fpicker/source/win32/FilterContainer.cxx @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sal/config.h> + +#include <algorithm> +#include <memory> +#include <stdexcept> +#include <osl/diagnose.h> +#include "FilterContainer.hxx" + +#include <utility> + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +CFilterContainer::CFilterContainer( sal_Int32 initSize ) : + m_vFilters( initSize ), + m_bIterInitialized( false ) +{ +} + +// add a name/filter pair + +bool CFilterContainer::addFilter( + const OUString& aName, const OUString& aFilter, bool bAllowDuplicates ) +{ + // check if the filter is already in the container + sal_Int32 pos = -1; + + if ( !bAllowDuplicates ) + { + pos = getFilterTagPos( aName ); + if ( pos < 0 ) // if not there, append + { + m_vFilters.push_back( std::make_pair( aName, aFilter ) ); + m_bIterInitialized = false; + } + } + else + { + m_vFilters.push_back( std::make_pair( aName, aFilter ) ); + m_bIterInitialized = false; + } + + return pos < 0; +} + +// delete a filter +// Precondition: the container is not empty +// there is a filter identified by the given name + +bool CFilterContainer::delFilter( const OUString& aName ) +{ + OSL_ASSERT( !m_vFilters.empty() ); + + sal_Int32 pos = getFilterTagPos( aName ); + if ( pos > -1 ) + { + m_vFilters.erase( m_vFilters.begin() + pos ); + m_bIterInitialized = false; + } + + return pos > -1; +} + +// return the number of filters currently in the container + +sal_Int32 CFilterContainer::numFilter( ) +{ + return m_vFilters.size( ); +} + +// clear all entries + +void CFilterContainer::empty() +{ + m_vFilters.clear( ); +} + +// get a filter by name +// Precondition: the container is not empty +// there is a filter identified by the name + +bool CFilterContainer::getFilterByName(const OUString& aName, OUString& theFilter) const +{ + OSL_PRECOND( !m_vFilters.empty() , "Empty filter container" ); + return getFilterByIndex(getFilterTagPos(aName), theFilter); +} + +bool CFilterContainer::getFilterByIndex(sal_Int32 aIndex, OUString& theFilter) const +{ + bool bRet = true; + + try + { + theFilter = m_vFilters.at(aIndex).second; + } + catch (std::out_of_range&) + { + OSL_FAIL("Filter index out of range"); + bRet = false; + } + + return bRet; +} + +bool CFilterContainer::getFilterNameByIndex(sal_Int32 aIndex, OUString& theName) const +{ + bool bRet = true; + + try + { + theName = m_vFilters.at(aIndex).first; + } + catch( std::out_of_range& ) + { + OSL_FAIL( "Filter index out of range" ); + bRet = false; + } + + return bRet; +} + +sal_Int32 CFilterContainer::getFilterPos( const OUString& aName ) const +{ + return getFilterTagPos( aName ); +} + +// returns the index of the filter identified by name + +sal_Int32 CFilterContainer::getFilterTagPos( const OUString& aName ) const +{ + if ( !m_vFilters.empty() ) + { + FILTER_VECTOR_T::const_iterator iter = std::find_if(m_vFilters.begin(), m_vFilters.end(), + [&aName](const FILTER_ENTRY_T& rFilter) { return rFilter.first.equalsIgnoreAsciiCase(aName); }); + if (iter != m_vFilters.end()) + return std::distance(m_vFilters.begin(), iter); + } + + return -1; +} + +// starts enumerating the filter in the container + +void CFilterContainer::beginEnumFilter( ) +{ + m_iter = m_vFilters.begin( ); + m_bIterInitialized = true; +} + +// returns true if another filter has been retrieved + +bool CFilterContainer::getNextFilter( FILTER_ENTRY_T& nextFilterEntry ) +{ + OSL_ASSERT( m_bIterInitialized ); + + bool bRet = ( m_iter != m_vFilters.end( ) ); + + if ( bRet ) + nextFilterEntry = *m_iter++; + else + m_bIterInitialized = false; + + return bRet; +} + +void CFilterContainer::setCurrentFilter( const OUString& aName ) +{ + m_sCurrentFilter = aName; +} + +OUString CFilterContainer::getCurrentFilter() const +{ + return m_sCurrentFilter; +} + +// calculates the length of a '\0' separated filter, that means +// length of the name + '\0' + length of the filter string + +// a trailing '\0' + +static sal_uInt32 getLengthFilter( CFilterContainer::FILTER_ENTRY_T aFilterEntry ) +{ + return ( + aFilterEntry.first.getLength( ) + 1 + + aFilterEntry.second.getLength( ) + 1 ); +} + +// calculates the length of all filters currently in the container + +static sal_uInt32 getTotalFilterLength( CFilterContainer& aFilterContainer ) +{ + CFilterContainer::FILTER_ENTRY_T nextFilter; + + aFilterContainer.beginEnumFilter( ); + + sal_uInt32 totalLength = 0; + while( aFilterContainer.getNextFilter( nextFilter ) ) + totalLength += getLengthFilter( nextFilter ); + + return ( totalLength > 0 ) ? totalLength + 1 : totalLength; +} + +static +void wcsmemcpy( sal_Unicode* pDest, const sal_Unicode* pSrc, sal_uInt32 nLength ) +{ + memcpy( pDest, pSrc, nLength * sizeof( sal_Unicode ) ); +} + +// a helper trivial helper function to create a filter buffer in the +// format the Win32 API requires, +// e.g. "Text\0*.txt\0Doc\0*.doc;*xls\0\0" + +OUString makeWinFilterBuffer( CFilterContainer& aFilterContainer ) +{ + // calculate the required buffer size + sal_uInt32 reqBuffSize = getTotalFilterLength( aFilterContainer ); + + // return if there are no filters + if ( !reqBuffSize ) + return OUString( ); + + auto pBuff = std::make_unique<sal_Unicode[]>(reqBuffSize); + + // initialize the buffer with 0 + ZeroMemory( pBuff.get(), sizeof( sal_Unicode ) * reqBuffSize ); + + OUString winFilterBuff; + CFilterContainer::FILTER_ENTRY_T nextFilter; + sal_uInt32 memPos = 0; + + aFilterContainer.beginEnumFilter( ); + + while( aFilterContainer.getNextFilter( nextFilter ) ) + { + wcsmemcpy( + pBuff.get() + memPos, + nextFilter.first.getStr( ), + nextFilter.first.getLength( ) ); + + memPos += nextFilter.first.getLength( ) + 1; + + wcsmemcpy( + pBuff.get() + memPos, + nextFilter.second.getStr( ), + nextFilter.second.getLength( ) ); + + memPos += nextFilter.second.getLength( ) + 1 ; + } + + winFilterBuff = OUString( pBuff.get(), reqBuffSize ); + + return winFilterBuff; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/FilterContainer.hxx b/fpicker/source/win32/FilterContainer.hxx new file mode 100644 index 000000000..f54b10a7f --- /dev/null +++ b/fpicker/source/win32/FilterContainer.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_FILTERCONTAINER_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_FILTERCONTAINER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +#include <vector> + + +// helper class, only usable by OFilterContainer + + +class CFilterContainer +{ +public: + // defines a filter entry which is made of a name and a filter value + // e.g. 'Text *.txt' + typedef std::pair< OUString, OUString > FILTER_ENTRY_T; + +public: + explicit CFilterContainer( sal_Int32 initSize = 0 ); + + // add a new filter + // returns true if the filter was successfully added + // returns false if duplicates are not allowed and + // the filter is already in the container + bool addFilter( + const OUString& aName, + const OUString& aFilter, + bool bAllowDuplicates = false ); + + // delete the specified filter returns true on + // success and false if the filter was not found + bool delFilter( const OUString& aName ); + + // the number of filter already added + sal_Int32 numFilter( ); + + // clear all entries + void empty( ); + + // retrieve a filter from the container. These methods + // return true on success and false if the specified + // filter was not found + bool getFilterByName(const OUString& aName, OUString& theFilter) const; + bool getFilterByIndex(sal_Int32 aIndex, OUString& theFilter) const; + bool getFilterNameByIndex(sal_Int32 aIndex, OUString& theName) const; + + // returns the position of the specified filter or -1 + // if the filter was not found + sal_Int32 getFilterPos( const OUString& aName ) const; + + // starts enumerating the filter in the container + void beginEnumFilter( ); + + // returns true if another filter has been retrieved + bool getNextFilter( FILTER_ENTRY_T& nextFilterEntry ); + + // cache current filter + void setCurrentFilter( const OUString& aName ); + + // returns cached current filter + OUString getCurrentFilter() const; + +protected: + typedef std::vector< FILTER_ENTRY_T > FILTER_VECTOR_T; + +private: + // prevent copy and assignment + CFilterContainer( const CFilterContainer& ); + CFilterContainer& SAL_CALL operator=( const CFilterContainer& ); + + sal_Int32 getFilterTagPos( const OUString& aName ) const; + +private: + FILTER_VECTOR_T m_vFilters; + FILTER_VECTOR_T::const_iterator m_iter; + bool m_bIterInitialized; + OUString m_sCurrentFilter; +}; + + +// a helper function to create a filter buffer in the format +// the Win32 API requires, e.g. "Text\0*.txt\0Doc\0*.doc;*xls\0\0" + + +OUString makeWinFilterBuffer( CFilterContainer& aFilterContainer ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/IVistaFilePickerInternalNotify.hxx b/fpicker/source/win32/IVistaFilePickerInternalNotify.hxx new file mode 100644 index 000000000..f39d5aff4 --- /dev/null +++ b/fpicker/source/win32/IVistaFilePickerInternalNotify.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_IVISTAFILEPICKERINTERNALNOTIFY_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_IVISTAFILEPICKERINTERNALNOTIFY_HXX + +#include "vistatypes.h" + +#include <cppuhelper/basemutex.hxx> +#include <osl/interlck.h> + +#include <shobjidl.h> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types, const etcpp. + + +/** todo document me + */ +class IVistaFilePickerInternalNotify +{ + public: + + virtual void onAutoExtensionChanged (bool bChecked) = 0; + + virtual bool onFileTypeChanged( UINT nTypeIndex ) = 0; + + virtual void onDirectoryChanged() = 0; + + protected: + ~IVistaFilePickerInternalNotify() {} +}; + +}}} + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_IVISTAFILEPICKERINTERNALNOTIFY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePicker.cxx b/fpicker/source/win32/VistaFilePicker.cxx new file mode 100644 index 000000000..67c49f4d1 --- /dev/null +++ b/fpicker/source/win32/VistaFilePicker.cxx @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sal/config.h> + +#include <memory> + +#include "VistaFilePicker.hxx" + +#include "WinImplHelper.hxx" +#include "FPServiceInfo.hxx" +#include "shared.hxx" + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerNotifier.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerListener.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> + +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/mutex.hxx> +#include <osl/file.hxx> +#include <officecfg/Office/Common.hxx> + +#include <shlobj.h> + +namespace fpicker{ +namespace win32{ +namespace vista{ + +namespace +{ + css::uno::Sequence< OUString > VistaFilePicker_getSupportedServiceNames() + { + return { + "com.sun.star.ui.dialogs.FilePicker", + "com.sun.star.ui.dialogs.SystemFilePicker", + "com.sun.star.ui.dialogs.SystemFolderPicker" }; + } +} + +VistaFilePicker::VistaFilePicker(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR, bool bFolderPicker) + : TVistaFilePickerBase (m_aMutex ) + , m_xSMGR (xSMGR ) + , m_rDialog (std::make_shared<VistaFilePickerImpl>()) + , m_aAsyncExecute (m_rDialog ) + , m_nFilePickerThreadId (0 ) + , m_bInitialized (false ) + , m_bFolderPicker (bFolderPicker ) +{ +} + +VistaFilePicker::~VistaFilePicker() +{ +} + +void SAL_CALL VistaFilePicker::addFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_ADD_PICKER_LISTENER); + rRequest->setArgument(PROP_PICKER_LISTENER, xListener); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::removeFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_REMOVE_PICKER_LISTENER); + rRequest->setArgument(PROP_PICKER_LISTENER, xListener); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void VistaFilePicker::disposing(const css::lang::EventObject& /*aEvent*/) +{ +} + +void SAL_CALL VistaFilePicker::setMultiSelectionMode(sal_Bool bMode) +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_MULTISELECTION_MODE); + rRequest->setArgument(PROP_MULTISELECTION_MODE, bMode); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::setTitle(const OUString& sTitle) +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_TITLE); + rRequest->setArgument(PROP_TITLE, sTitle); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::appendFilter(const OUString& sTitle , + const OUString& sFilter) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_APPEND_FILTER); + rRequest->setArgument(PROP_FILTER_TITLE, sTitle ); + rRequest->setArgument(PROP_FILTER_VALUE, sFilter); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::setCurrentFilter(const OUString& sTitle) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_CURRENT_FILTER); + rRequest->setArgument(PROP_FILTER_TITLE, sTitle); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +OUString SAL_CALL VistaFilePicker::getCurrentFilter() +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_GET_CURRENT_FILTER); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED); + + const OUString sTitle = rRequest->getArgumentOrDefault(PROP_FILTER_TITLE, OUString()); + return sTitle; +} + +void SAL_CALL VistaFilePicker::appendFilterGroup(const OUString& /*sGroupTitle*/, + const css::uno::Sequence< css::beans::StringPair >& rFilters ) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_APPEND_FILTERGROUP); + rRequest->setArgument(PROP_FILTER_GROUP, rFilters); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::setDefaultName(const OUString& sName ) +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_DEFAULT_NAME); + rRequest->setArgument(PROP_FILENAME, sName); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::setDisplayDirectory(const OUString& sDirectory) +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_DIRECTORY); + rRequest->setArgument(PROP_DIRECTORY, sDirectory); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +OUString SAL_CALL VistaFilePicker::getDisplayDirectory() +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_GET_DIRECTORY); + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED); + const OUString sDirectory = rRequest->getArgumentOrDefault(PROP_DIRECTORY, OUString()); + + return sDirectory; +} + +// @deprecated can't be supported any longer ... see IDL description for further details +css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getFiles() +{ + css::uno::Sequence< OUString > lFiles = getSelectedFiles(); + // multiselection doesn't really work + // so just retrieve the first url + if (lFiles.getLength() > 1) + lFiles.realloc(1); + m_lLastFiles = lFiles; + return lFiles; +} + +css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getSelectedFiles() +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_GET_SELECTED_FILES); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED); + + const css::uno::Sequence< OUString > lFiles = rRequest->getArgumentOrDefault(PROP_SELECTED_FILES, css::uno::Sequence< OUString >()); + m_lLastFiles = lFiles; + return lFiles; +} + +void VistaFilePicker::ensureInit() +{ + bool bInitialized(false); + { + osl::MutexGuard aGuard(m_aMutex); + bInitialized = m_bInitialized; + } + + if ( !bInitialized ) + { + if (m_bFolderPicker) + { + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_CREATE_FOLDER_PICKER); + if ( ! m_aAsyncExecute.isRunning()) + m_aAsyncExecute.create(); + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); + { + osl::MutexGuard aGuard(m_aMutex); + m_bInitialized = true; + } + } + else + { + css::uno::Sequence < css::uno::Any > aInitArguments(1); + aInitArguments[0] <<= css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE; + initialize(aInitArguments); + } + } +} + +::sal_Int16 SAL_CALL VistaFilePicker::execute() +{ + ensureInit(); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SHOW_DIALOG_MODAL); + + // if we want to show a modal window, the calling thread needs to process messages + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::PROCESS_MESSAGES); + + const bool bOK = rRequest->getArgumentOrDefault(PROP_DIALOG_SHOW_RESULT, false ); + m_lLastFiles = rRequest->getArgumentOrDefault(PROP_SELECTED_FILES , css::uno::Sequence< OUString >()); + + ::sal_Int16 nResult = css::ui::dialogs::ExecutableDialogResults::CANCEL; + if (bOK) + nResult = css::ui::dialogs::ExecutableDialogResults::OK; + return nResult; +} + +// XFilePicker + +void SAL_CALL VistaFilePicker::setValue( ::sal_Int16 nControlId , + ::sal_Int16 nControlAction, + const css::uno::Any& aValue ) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_CONTROL_VALUE); + rRequest->setArgument(PROP_CONTROL_ID , nControlId ); + rRequest->setArgument(PROP_CONTROL_ACTION, nControlAction); + rRequest->setArgument(PROP_CONTROL_VALUE , aValue ); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +css::uno::Any SAL_CALL VistaFilePicker::getValue(::sal_Int16 nControlId , + ::sal_Int16 nControlAction) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_GET_CONTROL_VALUE); + rRequest->setArgument(PROP_CONTROL_ID , nControlId ); + rRequest->setArgument(PROP_CONTROL_ACTION, nControlAction); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED); + return rRequest->getValue(PROP_CONTROL_VALUE); +} + +void SAL_CALL VistaFilePicker::enableControl(::sal_Int16 nControlId, + sal_Bool bEnable ) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_ENABLE_CONTROL); + rRequest->setArgument(PROP_CONTROL_ID , nControlId); + rRequest->setArgument(PROP_CONTROL_ENABLE, bEnable ); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +void SAL_CALL VistaFilePicker::setLabel( ::sal_Int16 nControlId, + const OUString& sLabel ) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_SET_CONTROL_LABEL); + rRequest->setArgument(PROP_CONTROL_ID , nControlId); + rRequest->setArgument(PROP_CONTROL_LABEL, sLabel ); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); +} + +OUString SAL_CALL VistaFilePicker::getLabel(::sal_Int16 nControlId) +{ + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (VistaFilePickerImpl::E_GET_CONTROL_LABEL); + rRequest->setArgument(PROP_CONTROL_ID, nControlId); + + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED); + const OUString sLabel = rRequest->getArgumentOrDefault(PROP_CONTROL_LABEL, OUString()); + return sLabel; +} + +css::uno::Sequence< ::sal_Int16 > SAL_CALL VistaFilePicker::getSupportedImageFormats() +{ + return css::uno::Sequence< sal_Int16 >(); +} + +sal_Int32 SAL_CALL VistaFilePicker::getTargetColorDepth() +{ + return 0; +} + +sal_Int32 SAL_CALL VistaFilePicker::getAvailableWidth() +{ + return 0; +} + +sal_Int32 SAL_CALL VistaFilePicker::getAvailableHeight() +{ + return 0; +} + +void SAL_CALL VistaFilePicker::setImage( sal_Int16 /*nImageFormat*/, + const css::uno::Any& /*aImage */) +{ +} + +sal_Bool SAL_CALL VistaFilePicker::setShowState(sal_Bool /*bShowState*/) +{ + return false; +} + +sal_Bool SAL_CALL VistaFilePicker::getShowState() +{ + return false; +} + +void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::Any >& lArguments) +{ + if (lArguments.getLength() < 1) + throw css::lang::IllegalArgumentException( + "XInitialization::initialize() called without arguments.", + static_cast< css::ui::dialogs::XFilePicker2* >( this ), + 1); + + sal_Int32 nTemplate = -1; + lArguments[0] >>= nTemplate; + + bool bFileOpenDialog = true; + ::sal_Int32 nFeatures = 0; + + switch(nTemplate) + { + case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE : + { + bFileOpenDialog = true; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE : + { + bFileOpenDialog = false; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD : + { + bFileOpenDialog = false; + nFeatures |= FEATURE_AUTOEXTENSION; + nFeatures |= FEATURE_PASSWORD; + nFeatures |= FEATURE_GPGPASSWORD; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS : + { + bFileOpenDialog = false; + nFeatures |= FEATURE_AUTOEXTENSION; + nFeatures |= FEATURE_PASSWORD; + nFeatures |= FEATURE_FILTEROPTIONS; + nFeatures |= FEATURE_GPGPASSWORD; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION : + { + bFileOpenDialog = false; + nFeatures |= FEATURE_AUTOEXTENSION; + nFeatures |= FEATURE_SELECTION; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE : + { + bFileOpenDialog = false; + nFeatures |= FEATURE_AUTOEXTENSION; + nFeatures |= FEATURE_TEMPLATE; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_LINK; + nFeatures |= FEATURE_PREVIEW; + nFeatures |= FEATURE_IMAGETEMPLATE; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_LINK; + nFeatures |= FEATURE_PREVIEW; + nFeatures |= FEATURE_IMAGEANCHOR; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_PLAY; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_LINK; + nFeatures |= FEATURE_PLAY; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_READONLY; + nFeatures |= FEATURE_VERSION; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_LINK; + nFeatures |= FEATURE_PREVIEW; + } + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION : + { + bFileOpenDialog = false; + nFeatures |= FEATURE_AUTOEXTENSION; + } + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW : + { + bFileOpenDialog = true; + nFeatures |= FEATURE_PREVIEW; + } + break; + } + css::uno::Reference<css::awt::XWindow> xParentWindow; + if(lArguments.getLength() > 1) + { + lArguments[1] >>= xParentWindow; + } + RequestRef rRequest = std::make_shared<Request>(); + if (bFileOpenDialog) + rRequest->setRequest (VistaFilePickerImpl::E_CREATE_OPEN_DIALOG); + else + rRequest->setRequest (VistaFilePickerImpl::E_CREATE_SAVE_DIALOG); + rRequest->setArgument(PROP_FEATURES, nFeatures); + rRequest->setArgument(PROP_TEMPLATE_DESCR, nTemplate); + if(xParentWindow.is()) + rRequest->setArgument(PROP_PARENT_WINDOW, xParentWindow); + if ( ! m_aAsyncExecute.isRunning()) + m_aAsyncExecute.create(); + m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::NON_BLOCKED); + + { + osl::MutexGuard aGuard(m_aMutex); + m_bInitialized = true; + } +} + +void SAL_CALL VistaFilePicker::cancel() +{ +} + +OUString SAL_CALL VistaFilePicker::getDirectory() +{ + ensureInit(); + css::uno::Sequence< OUString > aFileSeq = getSelectedFiles(); + assert(aFileSeq.getLength() <= 1); + return aFileSeq.getLength() ? aFileSeq[0] : OUString(); +} + +void SAL_CALL VistaFilePicker::setDescription( const OUString& aDescription ) +{ + setTitle(aDescription); +} + +// XServiceInfo + +OUString SAL_CALL VistaFilePicker::getImplementationName() +{ + if (m_bFolderPicker) + return FOLDER_PICKER_IMPL_NAME; + else + return FILE_PICKER_IMPL_NAME; +} + +sal_Bool SAL_CALL VistaFilePicker::supportsService(const OUString& sServiceName) +{ + return cppu::supportsService(this, sServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getSupportedServiceNames() +{ + return VistaFilePicker_getSupportedServiceNames(); +} + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePicker.hxx b/fpicker/source/win32/VistaFilePicker.hxx new file mode 100644 index 000000000..71ccfd992 --- /dev/null +++ b/fpicker/source/win32/VistaFilePicker.hxx @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKER_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKER_HXX + +#include "asyncrequests.hxx" +#include "VistaFilePickerImpl.hxx" +#include "VistaFilePickerEventHandler.hxx" + +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/XFilePreview.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <rtl/ustring.hxx> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types + + +typedef ::cppu::WeakComponentImplHelper< + css::ui::dialogs::XFilePicker3, + css::ui::dialogs::XFilePickerControlAccess, + css::ui::dialogs::XFilePreview, + css::ui::dialogs::XFolderPicker2, + css::lang::XInitialization, + css::lang::XServiceInfo > TVistaFilePickerBase; + + +/** Implements the XFilePicker & friends interface(s) + for Windows Vista and upcoming versions. + + Note: This will be a UNO wrapper for the real file picker + implementation only. The real implementation is done in class + VistaFilePickerImpl. + */ +class VistaFilePicker : public ::cppu::BaseMutex + , public TVistaFilePickerBase +{ +public: + + + // ctor/dtor + + + explicit VistaFilePicker( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR, bool bFolderPicker ); + virtual ~VistaFilePicker() override; + + + // XFilePickerNotifier + + + virtual void SAL_CALL addFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) override; + + virtual void SAL_CALL removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) override; + + + // XExecutableDialog functions + + + virtual void SAL_CALL setTitle( const OUString& sTitle ) override; + + virtual sal_Int16 SAL_CALL execute( ) override; + + + // XFilePicker functions + + + virtual void SAL_CALL setMultiSelectionMode( sal_Bool bMode ) override; + + virtual void SAL_CALL setDefaultName( const OUString& sName ) override; + + virtual void SAL_CALL setDisplayDirectory( const OUString& sDirectory ) override; + + virtual OUString SAL_CALL getDisplayDirectory( ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getFiles( ) override; + + // XFilePicker2 functions + virtual css::uno::Sequence< OUString > SAL_CALL getSelectedFiles( ) override; + + + // XFilterManager functions + + + virtual void SAL_CALL appendFilter( const OUString& sTitle , + const OUString& sFilter ) override; + + virtual void SAL_CALL setCurrentFilter( const OUString& sTitle ) override; + + virtual OUString SAL_CALL getCurrentFilter( ) override; + + + // XFilterGroupManager functions + + + virtual void SAL_CALL appendFilterGroup( const OUString& sGroupTitle, + const css::uno::Sequence< css::beans::StringPair >& lFilters ) override; + + + // XFilePickerControlAccess functions + + + virtual void SAL_CALL setValue( sal_Int16 nControlId , + sal_Int16 nControlAction, + const css::uno::Any& aValue ) override; + + virtual css::uno::Any SAL_CALL getValue( sal_Int16 nControlId , + sal_Int16 nControlAction ) override; + + virtual void SAL_CALL enableControl( sal_Int16 nControlId, + sal_Bool bEnable ) override; + + virtual void SAL_CALL setLabel( sal_Int16 nControlId, + const OUString& sLabel ) override; + + virtual OUString SAL_CALL getLabel( sal_Int16 nControlId ) override; + + + // XFilePreview + + + virtual css::uno::Sequence< sal_Int16 > SAL_CALL getSupportedImageFormats( ) override; + + virtual sal_Int32 SAL_CALL getTargetColorDepth( ) override; + + virtual sal_Int32 SAL_CALL getAvailableWidth( ) override; + + virtual sal_Int32 SAL_CALL getAvailableHeight( ) override; + + virtual void SAL_CALL setImage( sal_Int16 nImageFormat, + const css::uno::Any& aImage ) override; + + virtual sal_Bool SAL_CALL setShowState( sal_Bool bShowState ) override; + + virtual sal_Bool SAL_CALL getShowState( ) override; + + + // XInitialization + + + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& lArguments ) override; + + + // XCancellable + + + virtual void SAL_CALL cancel( ) override; + + + // XEventListener + + /// @throws css::uno::RuntimeException + virtual void disposing( const css::lang::EventObject& aEvent ); + + + // XServiceInfo + + + virtual OUString SAL_CALL getImplementationName( ) override; + + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + + // XFolderPicker functions + + + virtual OUString SAL_CALL getDirectory( ) override; + + virtual void SAL_CALL setDescription( const OUString& aDescription ) override; + + + private: + + // prevent copy and assignment + VistaFilePicker( const VistaFilePicker& ); + VistaFilePicker& operator=( const VistaFilePicker& ); + + using WeakComponentImplHelperBase::disposing; + + void ensureInit(); + + private: + + + /// service manager to create own used uno services + css::uno::Reference< css::lang::XMultiServiceFactory > m_xSMGR; + + + css::uno::Sequence< OUString > m_lLastFiles; + + + /** execute the COM dialog within a STA thread + * Must be used on the heap ... because it's implemented as OSL thread .-) + */ + RequestHandlerRef m_rDialog; + AsyncRequests m_aAsyncExecute; + + + oslThreadIdentifier m_nFilePickerThreadId; + + bool m_bInitialized; + const bool m_bFolderPicker; +}; + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePickerEventHandler.cxx b/fpicker/source/win32/VistaFilePickerEventHandler.cxx new file mode 100644 index 000000000..a116a6909 --- /dev/null +++ b/fpicker/source/win32/VistaFilePickerEventHandler.cxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sal/config.h> + +#include <memory> + +#include "VistaFilePickerEventHandler.hxx" + +#include "asyncrequests.hxx" + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/document/XDocumentRevisionListPersistence.hpp> +#include <com/sun/star/util/RevisionTag.hpp> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> + +#include <osl/file.hxx> + + +// namespace directives + + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +VistaFilePickerEventHandler::VistaFilePickerEventHandler(IVistaFilePickerInternalNotify* pInternalNotify) + : m_nRefCount (0 ) + , m_nListenerHandle (0 ) + , m_pDialog ( ) + , m_pInternalNotify (pInternalNotify) + , m_lListener (m_aMutex) +{ +} + + +VistaFilePickerEventHandler::~VistaFilePickerEventHandler() +{ +} + + +HRESULT STDMETHODCALLTYPE VistaFilePickerEventHandler::QueryInterface(REFIID rIID , + void** ppObject) +{ + *ppObject=nullptr; + + if ( rIID == IID_IUnknown ) + *ppObject = static_cast<IUnknown*>(static_cast<IFileDialogEvents*>(this)); + + if ( rIID == IID_IFileDialogEvents ) + *ppObject = static_cast<IFileDialogEvents*>(this); + + if ( rIID == IID_IFileDialogControlEvents ) + *ppObject = static_cast<IFileDialogControlEvents*>(this); + + if ( *ppObject != nullptr ) + { + static_cast<IUnknown*>(*ppObject)->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::AddRef() +{ + return osl_atomic_increment(&m_nRefCount); +} + + +ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::Release() +{ + ULONG nReturn = --m_nRefCount; + if ( m_nRefCount == 0 ) + delete this; + + return nReturn; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnFileOk(IFileDialog* /*pDialog*/) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnFolderChanging(IFileDialog* /*pDialog*/, + IShellItem* /*pFolder*/) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnFolderChange(IFileDialog* /*pDialog*/) +{ + impl_sendEvent(E_DIRECTORY_CHANGED, 0); + m_pInternalNotify->onDirectoryChanged(); + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnSelectionChange(IFileDialog* /*pDialog*/) +{ + impl_sendEvent(E_FILE_SELECTION_CHANGED, 0); + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnShareViolation(IFileDialog* /*pDialog*/ , + + IShellItem* /*pItem*/ , + + FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/) +{ + impl_sendEvent(E_CONTROL_STATE_CHANGED, css::ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER); + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnTypeChange(IFileDialog* pDialog) +{ + UINT nFileTypeIndex; + HRESULT hResult = pDialog->GetFileTypeIndex( &nFileTypeIndex ); + + if ( hResult == S_OK ) + { + if ( m_pInternalNotify->onFileTypeChanged( nFileTypeIndex )) + impl_sendEvent(E_CONTROL_STATE_CHANGED, css::ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER); + } + + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnOverwrite(IFileDialog* /*pDialog*/ , + IShellItem* /*pItem*/ , + FDE_OVERWRITE_RESPONSE* /*pResponse*/) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnItemSelected(IFileDialogCustomize* /*pCustomize*/, + + DWORD nIDCtl , + + DWORD /*nIDItem*/ ) +{ + + impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl )); + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnButtonClicked(IFileDialogCustomize* /*pCustomize*/, + DWORD nIDCtl ) +{ + + impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnCheckButtonToggled(IFileDialogCustomize* /*pCustomize*/, + DWORD nIDCtl , + BOOL bChecked ) +{ + if (nIDCtl == css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION) + m_pInternalNotify->onAutoExtensionChanged(bChecked); + + impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); + + return S_OK; +} + + +STDMETHODIMP VistaFilePickerEventHandler::OnControlActivating(IFileDialogCustomize* /*pCustomize*/, + DWORD nIDCtl ) +{ + impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); + return S_OK; +} + + +void VistaFilePickerEventHandler::addFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) +{ + m_lListener.addInterface(cppu::UnoType<css::ui::dialogs::XFilePickerListener>::get(), xListener); +} + + +void VistaFilePickerEventHandler::removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) +{ + m_lListener.removeInterface(cppu::UnoType<css::ui::dialogs::XFilePickerListener>::get(), xListener); +} + + +void VistaFilePickerEventHandler::startListening( const TFileDialog& pBroadcaster ) +{ + if (m_pDialog.is()) + return; + + m_pDialog = pBroadcaster; + m_pDialog->Advise(this, &m_nListenerHandle); +} + + +void VistaFilePickerEventHandler::stopListening() +{ + if (m_pDialog.is()) + { + m_pDialog->Unadvise(m_nListenerHandle); + m_pDialog.release(); + } +} + +static const char PROP_CONTROL_ID[] = "control_id"; +static const char PROP_PICKER_LISTENER[] = "picker_listener"; + +namespace { + +class AsyncPickerEvents : public RequestHandler +{ +public: + + AsyncPickerEvents() + {} + + virtual void before() override + {} + + virtual void doRequest(const RequestRef& rRequest) override + { + const ::sal_Int32 nEventID = rRequest->getRequest(); + const ::sal_Int16 nControlID = rRequest->getArgumentOrDefault(PROP_CONTROL_ID, ::sal_Int16(0)); + 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; + + css::ui::dialogs::FilePickerEvent aEvent; + aEvent.ElementId = nControlID; + + switch (nEventID) + { + case VistaFilePickerEventHandler::E_FILE_SELECTION_CHANGED : + xListener->fileSelectionChanged(aEvent); + break; + + case VistaFilePickerEventHandler::E_DIRECTORY_CHANGED : + xListener->directoryChanged(aEvent); + break; + + case VistaFilePickerEventHandler::E_HELP_REQUESTED : + xListener->helpRequested(aEvent); + break; + + case VistaFilePickerEventHandler::E_CONTROL_STATE_CHANGED : + xListener->controlStateChanged(aEvent); + break; + + case VistaFilePickerEventHandler::E_DIALOG_SIZE_CHANGED : + xListener->dialogSizeChanged(); + break; + + // no default here. Let compiler detect changes on enum set ! + } + } + + virtual void after() override + {} +}; + +} + +void VistaFilePickerEventHandler::impl_sendEvent( EEventType eEventType, + ::sal_Int16 nControlID) +{ + // See special handling in ~AsyncRequests for this static + static AsyncRequests aNotify(std::make_shared<AsyncPickerEvents>()); + + ::cppu::OInterfaceContainerHelper* pContainer = m_lListener.getContainer( cppu::UnoType<css::ui::dialogs::XFilePickerListener>::get()); + if ( ! pContainer) + return; + + ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); + while (pIterator.hasMoreElements()) + { + try + { + css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener (pIterator.next(), css::uno::UNO_QUERY); + + RequestRef rRequest = std::make_shared<Request>(); + rRequest->setRequest (eEventType); + rRequest->setArgument(PROP_PICKER_LISTENER, xListener); + if ( nControlID ) + rRequest->setArgument(PROP_CONTROL_ID, nControlID); + + aNotify.triggerRequestDirectly(rRequest); + //aNotify.triggerRequestNonBlocked(rRequest); + } + catch(const css::uno::RuntimeException&) + { + pIterator.remove(); + } + } +} + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePickerEventHandler.hxx b/fpicker/source/win32/VistaFilePickerEventHandler.hxx new file mode 100644 index 000000000..3ea47dbd8 --- /dev/null +++ b/fpicker/source/win32/VistaFilePickerEventHandler.hxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKEREVENTHANDLER_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKEREVENTHANDLER_HXX + +#include <shobjidl.h> + +#include "vistatypes.h" +#include "IVistaFilePickerInternalNotify.hxx" + +#include <com/sun/star/ui/dialogs/XFilePickerListener.hpp> +#include <com/sun/star/uno/Reference.hxx> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <osl/interlck.h> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types, const etcpp. + + +/** todo document me + */ +class VistaFilePickerEventHandler : public ::cppu::BaseMutex + , public IFileDialogEvents + , public IFileDialogControlEvents +{ + public: + + + // ctor/dtor + + + explicit VistaFilePickerEventHandler(IVistaFilePickerInternalNotify* pInternalNotify); + virtual ~VistaFilePickerEventHandler(); + + + // IUnknown + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID rIID , + void** ppObject) override; + virtual ULONG STDMETHODCALLTYPE AddRef() override; + virtual ULONG STDMETHODCALLTYPE Release() override; + + + // IFileDialogEvents + + + STDMETHODIMP OnFileOk(IFileDialog* pDialog) override; + + STDMETHODIMP OnFolderChanging(IFileDialog* pDialog, + IShellItem* pFolder) override; + + STDMETHODIMP OnFolderChange(IFileDialog* pDialog) override; + + STDMETHODIMP OnSelectionChange(IFileDialog* pDialog) override; + + STDMETHODIMP OnShareViolation(IFileDialog* pDialog , + IShellItem* pItem , + FDE_SHAREVIOLATION_RESPONSE* pResponse) override; + + STDMETHODIMP OnTypeChange(IFileDialog* pDialog) override; + + STDMETHODIMP OnOverwrite(IFileDialog* pDialog , + IShellItem* pItem , + FDE_OVERWRITE_RESPONSE* pResponse) override; + + + // IFileDialogControlEvents + + + STDMETHODIMP OnItemSelected(IFileDialogCustomize* pCustomize, + DWORD nIDCtl , + DWORD nIDItem ) override; + + STDMETHODIMP OnButtonClicked(IFileDialogCustomize* pCustomize, + DWORD nIDCtl ) override; + + STDMETHODIMP OnCheckButtonToggled(IFileDialogCustomize* pCustomize, + DWORD nIDCtl , + BOOL bChecked ) override; + + STDMETHODIMP OnControlActivating(IFileDialogCustomize* pCustomize, + DWORD nIDCtl ) override; + + + // XFilePickerNotifier + + /// @throws css::uno::RuntimeException + virtual void addFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ); + + /// @throws css::uno::RuntimeException + virtual void removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ); + + + // native interface + + + /** start listening for file picker events on the given file open dialog COM object. + * + * The broadcaster will be cached internally so deregistration will be easy. + * Further all needed information is capsulated within this class (e.g. the listener handler). + * Nobody outside must know such information. + * + * Nothing will happen if an inconsistent state will be detected + * (means: double registration will be ignored). + * + * @param pBroadcaster + * reference to the dialog, where we should start listening. + */ + void startListening( const TFileDialog& pBroadcaster ); + + + /** stop listening for file picker events on the internally cached dialog COM object. + * + * The COM dialog provided on the startListening() call was cached internally. + * And now it's used to deregister this listener. Doing so the also internally cached + * listener handle is used. If listener was not already registered - nothing will happen. + */ + void stopListening(); + + public: + + enum EEventType + { + E_FILE_SELECTION_CHANGED, + E_DIRECTORY_CHANGED, + E_HELP_REQUESTED, + E_CONTROL_STATE_CHANGED, + E_DIALOG_SIZE_CHANGED + }; + + private: + + + /// @todo document me + void impl_sendEvent( EEventType eEventType, + ::sal_Int16 nControlID); + + private: + + + /// ref count for AddRef/Release() + oslInterlockedCount m_nRefCount; + + + /// unique handle for this listener provided by the broadcaster on registration time + DWORD m_nListenerHandle; + + + /// cached file dialog instance (there we listen for events) + TFileDialog m_pDialog; + + + IVistaFilePickerInternalNotify* m_pInternalNotify; + + + /** used to inform file picker listener asynchronously. + * Those listener must be called asynchronously .. because + * every request will block the caller thread. Mostly that will be + * the main thread of the office. Further the global SolarMutex will + * be locked during this time. If we call our listener back now synchronously .. + * we will block on SolarMutex.acquire() forever .-)) + */ + ::cppu::OMultiTypeInterfaceContainerHelper m_lListener; +}; + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKEREVENTHANDLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePickerImpl.cxx b/fpicker/source/win32/VistaFilePickerImpl.cxx new file mode 100644 index 000000000..c84fe5f3a --- /dev/null +++ b/fpicker/source/win32/VistaFilePickerImpl.cxx @@ -0,0 +1,1333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#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 <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <comphelper/sequence.hxx> +#include <fpicker/strings.hrc> +#include <fpsofficeResMgr.hxx> +#include <osl/file.hxx> +#include <osl/mutex.hxx> +#include <rtl/process.h> +#include <o3tl/char16_t2wchar_t.hxx> +#include "WinImplHelper.hxx" + +#include <shlguid.h> +#include <shlobj.h> + +static bool is_current_process_window(HWND hwnd) +{ + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + return (pid == GetCurrentProcessId()); +} + +static HWND choose_parent_window() +{ + HWND hwnd_parent = GetForegroundWindow(); + if (!is_current_process_window(hwnd_parent)) + hwnd_parent = GetDesktopWindow(); + return hwnd_parent; +} + +namespace { + +bool createFolderItem(OUString const & url, ComPtr<IShellItem> & folder) { + OUString path; + if (osl::FileBase::getSystemPathFromFileURL(url, path) + != osl::FileBase::E_None) + { + return false; + } + HRESULT res = SHCreateItemFromParsingName( + o3tl::toW(path.getStr()), nullptr, + IID_PPV_ARGS(&folder)); + return SUCCEEDED(res); +} + +} + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types, const etcpp. + + +static const ::sal_Int16 INVALID_CONTROL_ID = -1; +static const ::sal_Int16 INVALID_CONTROL_ACTION = -1; + +// 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_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_LINK_ANCHOR = {0xBE3188CB, 0x399A, 0x45AE, 0x8F, 0x78, 0x75, 0x17, 0xAF, 0x26, 0x81, 0xEA}; +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}; + + +static OUString lcl_getURLFromShellItem (IShellItem* pItem) +{ + LPWSTR pStr = nullptr; + OUString sURL; + HRESULT hr; + + hr = pItem->GetDisplayName ( SIGDN_FILESYSPATH, &pStr ); + if (SUCCEEDED(hr)) + { + ::osl::FileBase::getFileURLFromSystemPath( o3tl::toU(pStr), sURL ); + goto cleanup; + } + + hr = pItem->GetDisplayName ( SIGDN_URL, &pStr ); + if (SUCCEEDED(hr)) + { + sURL = o3tl::toU(pStr); + goto cleanup; + } + + hr = pItem->GetDisplayName ( SIGDN_PARENTRELATIVEPARSING, &pStr ); + if (SUCCEEDED(hr)) + { + GUID known_folder_id; + std::wstring aStr = pStr; + CoTaskMemFree (pStr); + + if (0 == aStr.compare(0, 3, L"::{")) + aStr = aStr.substr(2); + hr = IIDFromString(aStr.c_str(), &known_folder_id); + if (SUCCEEDED(hr)) + { + hr = SHGetKnownFolderPath(known_folder_id, 0, nullptr, &pStr); + if (SUCCEEDED(hr)) + { + ::osl::FileBase::getFileURLFromSystemPath(o3tl::toU(pStr), sURL); + goto cleanup; + } + } + } + + // Default fallback + hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &pStr); + if (SUCCEEDED(hr)) + ::osl::FileBase::getFileURLFromSystemPath(o3tl::toU(pStr), sURL); + else // shouldn't happen... + goto bailout; + +cleanup: + CoTaskMemFree (pStr); +bailout: + return sURL; +} + +// Vista file picker shows the filter mask next to filter name in the list; so we need to remove the +// mask from the filter name to avoid duplicating masks +static OUString lcl_AdjustFilterName(const OUString& sName) +{ + const sal_Int32 idx = sName.indexOf("(."); + return (idx > 0) ? sName.copy(0, idx).trim() : sName; +} + +// rvStrings holds the OUStrings, pointers to which data are stored in returned COMDLG_FILTERSPEC +static ::std::vector<COMDLG_FILTERSPEC> lcl_buildFilterList(CFilterContainer& rContainer, + std::vector<OUString>& rvStrings) +{ + ::std::vector< COMDLG_FILTERSPEC > lList ; + CFilterContainer::FILTER_ENTRY_T aFilter; + + rContainer.beginEnumFilter( ); + while( rContainer.getNextFilter(aFilter) ) + { + COMDLG_FILTERSPEC aSpec; + + rvStrings.push_back(lcl_AdjustFilterName(aFilter.first)); // to avoid dangling pointer + aSpec.pszName = o3tl::toW(rvStrings.back().getStr()); + aSpec.pszSpec = o3tl::toW(aFilter.second.getStr()); + + lList.push_back(aSpec); + } + + return lList; +} + + +VistaFilePickerImpl::VistaFilePickerImpl() + : m_iDialogOpen () + , m_iDialogSave () + , m_iFolderPicker() + , m_hLastResult () + , m_lFilters () + , m_iEventHandler(new VistaFilePickerEventHandler(this)) + , m_bInExecute (false) + , m_bWasExecuted (false) + , m_hParentWindow(choose_parent_window()) + , m_sDirectory () + , m_sFilename () +{ +} + + +VistaFilePickerImpl::~VistaFilePickerImpl() +{ +} + + +void VistaFilePickerImpl::before() +{ + // SYNCHRONIZED-> + osl::MutexGuard 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 CoInitializeEx will fail... we uninitialize COM initialize it new .-) + + m_hLastResult = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if ( FAILED(m_hLastResult) ) + { + CoUninitialize(); + m_hLastResult = CoInitializeEx(nullptr, 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_CREATE_FOLDER_PICKER: + impl_sta_CreateFolderPicker(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::ClearableMutexGuard aLock(m_aMutex); + TFileDialogEvents iHandler = m_iEventHandler; + aLock.clear(); + // <- SYNCHRONIZED + + VistaFilePickerEventHandler* pHandlerImpl = static_cast<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::ClearableMutexGuard aLock(m_aMutex); + TFileDialogEvents iHandler = m_iEventHandler; + aLock.clear(); + // <- SYNCHRONIZED + + VistaFilePickerEventHandler* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(iHandler.get()); + if (pHandlerImpl) + pHandlerImpl->removeFilePickerListener(xListener); +} + + +void VistaFilePickerImpl::impl_sta_appendFilter(const RequestRef& rRequest) +{ + const OUString sTitle = rRequest->getArgumentOrDefault(PROP_FILTER_TITLE, OUString()); + const OUString sFilter = rRequest->getArgumentOrDefault(PROP_FILTER_VALUE, OUString()); + + // SYNCHRONIZED-> + osl::MutexGuard 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-> + osl::MutexGuard aLock(m_aMutex); + + if ( m_lFilters.numFilter() > 0 && aFilterGroup.getLength() > 0 ) + m_lFilters.addFilter( STRING_SEPARATOR, "", 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 OUString sTitle = rRequest->getArgumentOrDefault(PROP_FILTER_TITLE, OUString()); + + // SYNCHRONIZED-> + osl::MutexGuard 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::MutexGuard aLock(m_aMutex); + + OUString sTitle; + ::sal_Int32 nRealIndex = nIndex-1; // COM dialog base on 1 ... filter container on 0 .-) + if ( + (nRealIndex >= 0 ) && + (m_lFilters.getFilterNameByIndex(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); + } + // <- SYNCHRONIZED +} + + +void VistaFilePickerImpl::impl_sta_CreateDialog(const RequestRef& rRequest, PickerDialog eType, DWORD nOrFlags) +{ + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + + TFileDialog iDialog; + + switch (eType) + { + case PickerDialog::FileOpen: + m_hLastResult = m_iDialogOpen.create(); + if (FAILED(m_hLastResult)) + return; + m_iDialogOpen.query(&iDialog); + break; + + case PickerDialog::FileSave: + m_hLastResult = m_iDialogSave.create(); + if (FAILED(m_hLastResult)) + return; + m_iDialogSave.query(&iDialog); + break; + + case PickerDialog::Folder: + m_hLastResult = m_iFolderPicker.create(); + if (FAILED(m_hLastResult)) + return; + m_iFolderPicker.query(&iDialog); + break; + } + + TFileDialogEvents iHandler = m_iEventHandler; + + aLock.clear(); + // <- SYNCHRONIZED + + DWORD nFlags = 0; + iDialog->GetOptions ( &nFlags ); + + nFlags &= ~FOS_FORCESHOWHIDDEN; + nFlags |= FOS_PATHMUSTEXIST; + nFlags |= FOS_DONTADDTORECENT; + nFlags |= nOrFlags; + + iDialog->SetOptions ( nFlags ); + + css::uno::Reference<css::awt::XWindow> xWindow = rRequest->getArgumentOrDefault(PROP_PARENT_WINDOW, css::uno::Reference<css::awt::XWindow>()); + if(xWindow.is()) + { + css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysDepWin(xWindow,css::uno::UNO_QUERY); + if(xSysDepWin.is()) { + css::uno::Sequence<sal_Int8> aProcessIdent(16); + rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray())); + css::uno::Any aAny = xSysDepWin->getWindowHandle(aProcessIdent,css::lang::SystemDependent::SYSTEM_WIN32); + sal_Int64 tmp = 0; + aAny >>= tmp; + if(tmp != 0) + m_hParentWindow = reinterpret_cast<HWND>(tmp); + } + } + + ::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 = static_cast<VistaFilePickerEventHandler*>(iHandler.get()); + if (pHandlerImpl) + pHandlerImpl->startListening(iDialog); +} + + +void VistaFilePickerImpl::impl_sta_CreateOpenDialog(const RequestRef& rRequest) +{ + DWORD nFlags = 0; + nFlags |= FOS_FILEMUSTEXIST; + nFlags |= FOS_OVERWRITEPROMPT; + + impl_sta_CreateDialog(rRequest, PickerDialog::FileOpen, nFlags); +} + + +void VistaFilePickerImpl::impl_sta_CreateSaveDialog(const RequestRef& rRequest) +{ + DWORD nFlags = 0; + nFlags |= FOS_FILEMUSTEXIST; + nFlags |= FOS_OVERWRITEPROMPT; + + impl_sta_CreateDialog(rRequest, PickerDialog::FileSave, nFlags); +} + + +void VistaFilePickerImpl::impl_sta_CreateFolderPicker(const RequestRef& rRequest) +{ + DWORD nFlags = 0; + nFlags |= FOS_PICKFOLDERS; + + impl_sta_CreateDialog(rRequest, PickerDialog::Folder, nFlags); +} + + +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 const ::sal_Int32 GROUP_IMAGEANCHOR = 5; + + +static void setLabelToControl(TFileDialogCustomize iCustom, sal_uInt16 nControlId) +{ + OUString aLabel = CResourceProvider::getResString(nControlId); + aLabel = SOfficeToWindowsLabel(aLabel); + iCustom->SetControlLabel(nControlId, o3tl::toW(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::FILEOPEN_PREVIEW : + 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_PASSWORD : + aGUID = CLIENTID_FILESAVE_PASSWORD; + break; + + case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION : + 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_LINK_PREVIEW_IMAGE_ANCHOR : + aGUID = CLIENTID_FILEOPEN_LINK_ANCHOR; + break; + + case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY : + case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_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, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_VERSION).replaceFirst("~","").getStr())); + iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION); + iCustom->EndVisualGroup (); + iCustom->MakeProminent (GROUP_VERSION); + } + + if ((nFeatures & FEATURE_TEMPLATE) == FEATURE_TEMPLATE) + { + iCustom->StartVisualGroup (GROUP_TEMPLATE, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_TEMPLATES).replaceFirst("~","").getStr())); + iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE); + iCustom->EndVisualGroup (); + iCustom->MakeProminent (GROUP_TEMPLATE); + } + + if ((nFeatures & FEATURE_IMAGETEMPLATE) == FEATURE_IMAGETEMPLATE) + { + iCustom->StartVisualGroup (GROUP_IMAGETEMPLATE, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_TEMPLATE).replaceFirst("~","").getStr())); + iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE); + iCustom->EndVisualGroup (); + iCustom->MakeProminent (GROUP_IMAGETEMPLATE); + } + + if ((nFeatures & FEATURE_IMAGEANCHOR) == FEATURE_IMAGEANCHOR) + { + iCustom->StartVisualGroup (GROUP_IMAGEANCHOR, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_ANCHOR).replaceFirst("~","").getStr())); + iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR); + iCustom->EndVisualGroup (); + iCustom->MakeProminent (GROUP_IMAGEANCHOR); + } + + 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, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_AUTO_EXTENSION).replaceFirst("~","").getStr()), true); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_PASSWORD) == FEATURE_PASSWORD) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD; + iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PASSWORD).replaceFirst("~","").getStr()), false); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_GPGPASSWORD) == FEATURE_GPGPASSWORD) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION; + iCustom->AddCheckButton (nControlId, L"GpgPassword", false); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_READONLY) == FEATURE_READONLY) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY; + iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_READONLY).replaceFirst("~","").getStr()), false); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_FILTEROPTIONS) == FEATURE_FILTEROPTIONS) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS; + iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_FILTER_OPTIONS).replaceFirst("~","").getStr()), false); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_LINK) == FEATURE_LINK) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK; + iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_INSERT_AS_LINK).replaceFirst("~","").getStr()), false); + setLabelToControl(iCustom, nControlId); + } + + if ((nFeatures & FEATURE_SELECTION) == FEATURE_SELECTION) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION; + iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_SELECTION).replaceFirst("~","").getStr()), false); + setLabelToControl(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, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PLAY).replaceFirst("~","").getStr())); + +} + + +void VistaFilePickerImpl::impl_sta_SetMultiSelectionMode(const RequestRef& rRequest) +{ + const bool bMultiSelection = rRequest->getArgumentOrDefault(PROP_MULTISELECTION_MODE, true); + + // SYNCHRONIZED-> + osl::ClearableMutexGuard 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) +{ + OUString sTitle = rRequest->getArgumentOrDefault(PROP_TITLE, OUString()); + + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + TFileDialog iDialog = impl_getBaseDialogInterface(); + aLock.clear(); + // <- SYNCHRONIZED + + iDialog->SetTitle(o3tl::toW(sTitle.getStr())); +} + + +void VistaFilePickerImpl::impl_sta_SetFileName(const RequestRef& rRequest) +{ + OUString sFileName = rRequest->getArgumentOrDefault(PROP_FILENAME, OUString()); + + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + TFileDialog iDialog = impl_getBaseDialogInterface(); + aLock.clear(); + // <- SYNCHRONIZED + + iDialog->SetFileName(o3tl::toW(sFileName.getStr())); +} + + +void VistaFilePickerImpl::impl_sta_SetDirectory(const RequestRef& rRequest) +{ + OUString sDirectory = rRequest->getArgumentOrDefault(PROP_DIRECTORY, OUString()); + + 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 meantime and decide later + // what to do + m_sDirectory = sDirectory; + } + + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + TFileDialog iDialog = impl_getBaseDialogInterface(); + aLock.clear(); + // <- SYNCHRONIZED + + ComPtr< IShellItem > pFolder; + if ( !createFolderItem(sDirectory, pFolder) ) + return; + + iDialog->SetFolder(pFolder); +} + +OUString VistaFilePickerImpl::GetDirectory() +{ + TFileDialog iDialog = impl_getBaseDialogInterface(); + ComPtr< IShellItem > pFolder; + HRESULT hResult = iDialog->GetFolder( &pFolder ); + if ( FAILED(hResult) ) + return OUString(); + return lcl_getURLFromShellItem(pFolder); +} + +void VistaFilePickerImpl::impl_sta_GetDirectory(const RequestRef& rRequest) +{ + const OUString sFolder = m_sDirectory.isEmpty() ? GetDirectory() : m_sDirectory; + if (!sFolder.isEmpty()) + rRequest->setArgument(PROP_DIRECTORY, sFolder); +} + +void VistaFilePickerImpl::impl_sta_SetDefaultName(const RequestRef& rRequest) +{ + OUString sFilename = rRequest->getArgumentOrDefault(PROP_FILENAME, 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 ( FAILED(hResult) ) + return; + if ( bValue ) + { + sal_Int32 nSepPos = sFilename.lastIndexOf( '.' ); + if ( -1 != nSepPos ) + sFilename = sFilename.copy(0, nSepPos); + } + + iDialog->SetFileName (o3tl::toW(sFilename.getStr())); + m_sFilename = sFilename; +} + + +void VistaFilePickerImpl::impl_sta_setFiltersOnDialog() +{ + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + + std::vector<OUString> vStrings; // to hold the adjusted filter names, pointers to which will be + // stored in lFilters + ::std::vector< COMDLG_FILTERSPEC > lFilters = lcl_buildFilterList(m_lFilters, vStrings); + 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.data(); + 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 ( FAILED(hResult) ) + return; + + if ( bValue ) + { + PCWSTR lpFilterExt = lFilters[0].pszSpec; + + lpFilterExt = wcsrchr( lpFilterExt, '.' ); + if ( lpFilterExt ) + lpFilterExt++; + iDialog->SetDefaultExtension( lpFilterExt ); + } + +} + + +void VistaFilePickerImpl::impl_sta_getSelectedFiles(const RequestRef& rRequest) +{ + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + + TFileOpenDialog iOpen = m_iDialogOpen; + TFileSaveDialog iSave = m_iDialogSave; + TFolderPickerDialog iPick = m_iFolderPicker; + 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); + } + else if (iPick.is()) + { + if (bInExecute) + hResult = iPick->GetCurrentSelection(&iItem); + else + { + hResult = iPick->GetResult(&iItem); + } + } + + if (FAILED(hResult)) + return; + + // convert and pack results + std::vector< OUString > lFiles; + if (iItem.is()) + { + const 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 OUString sURL = lcl_getURLFromShellItem(iItem); + if (sURL.getLength() > 0) + lFiles.push_back(sURL); + } + } + } + } + + rRequest->setArgument(PROP_SELECTED_FILES, comphelper::containerToSequence(lFiles)); +} + + +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; + TFolderPickerDialog iPick = m_iFolderPicker; + + // it's important to know if we are showing the dialog. + // Some dialog interface methods can't be called then or some + // tasks must be done differently .-) (e.g. see impl_sta_getSelectedFiles()) + m_bInExecute = true; + + m_bWasExecuted = 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; + if ( createFolderItem(m_sDirectory, pFolder) ) + { + if (m_sFilename.getLength()) + { + OUString aFileURL(m_sDirectory); + sal_Int32 nIndex = aFileURL.lastIndexOf('/'); + if (nIndex != aFileURL.getLength()-1) + aFileURL += "/"; + aFileURL += m_sFilename; + + TFileDialogCustomize iCustom = impl_getCustomizeInterface(); + + BOOL bValue = FALSE; + HRESULT hResult = iCustom->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue); + if ( bValue ) + { + UINT nFileType; + hResult = iDialog->GetFileTypeIndex(&nFileType); + if ( SUCCEEDED(hResult) && nFileType > 0 ) + { + // COM dialog base on 1 ... filter container on 0 .-) + ::size_t nRealIndex = nFileType-1; + OUString sFilter; + if (m_lFilters.getFilterByIndex(nRealIndex, sFilter)) + { + const sal_Int32 idx = sFilter.indexOf('.'); + if (idx >= 0) + aFileURL += sFilter.copy(idx); + } + } + } + + // Check existence of file. Set folder only for this special case + OUString aSystemPath; + osl_getSystemPathFromFileURL( aFileURL.pData, &aSystemPath.pData ); + + WIN32_FIND_DATAW aFindFileData; + HANDLE hFind = FindFirstFileW( o3tl::toW(aSystemPath.getStr()), &aFindFileData ); + if (hFind != INVALID_HANDLE_VALUE) + iDialog->SetFolder(pFolder); + else + hResult = iDialog->AddPlace(pFolder, FDAP_TOP); + + FindClose( hFind ); + } + else + 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 + else + if (iPick.is()) + hResult = iPick->Show( m_hParentWindow ); // parent window needed + } + catch(...) + {} + + // SYNCHRONIZED-> + aLock.reset(); + m_bInExecute = false; + aLock.clear(); + // <- SYNCHRONIZED + + if ( FAILED(hResult) ) + return; + + impl_sta_getSelectedFiles(rRequest); + rRequest->setArgument(PROP_DIALOG_SHOW_RESULT, true); +} + + +TFileDialog VistaFilePickerImpl::impl_getBaseDialogInterface() +{ + TFileDialog iDialog; + + // SYNCHRONIZED-> + osl::MutexGuard aLock(m_aMutex); + + if (m_iDialogOpen.is()) + m_iDialogOpen.query(&iDialog); + if (m_iDialogSave.is()) + m_iDialogSave.query(&iDialog); + if (m_iFolderPicker.is()) + m_iFolderPicker.query(&iDialog); + + return iDialog; +} + + +TFileDialogCustomize VistaFilePickerImpl::impl_getCustomizeInterface() +{ + TFileDialogCustomize iCustom; + + // SYNCHRONIZED-> + osl::MutexGuard aLock(m_aMutex); + + if (m_iDialogOpen.is()) + m_iDialogOpen.query(&iCustom); + else if (m_iDialogSave.is()) + m_iDialogSave.query(&iCustom); + else if (m_iFolderPicker.is()) + m_iFolderPicker.query(&iCustom); + + return iCustom; +} + + +static void lcl_removeControlItemsWorkaround(const TFileDialogCustomize& iCustom , + ::sal_Int16 nControlId) +{ + (void)iCustom->SetSelectedControlItem(nControlId, 1000); // Don't care if this fails (useless?) + DWORD i = 0; + HRESULT 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->getValue(PROP_CONTROL_VALUE); + + // don't 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 : + { + bool bValue = 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 : + case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR : + { + 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 : + { + aValue >>= m_lItems; + for (::sal_Int32 i=0; i<m_lItems.getLength(); ++i) + { + const OUString& sItem = m_lItems[i]; + hResult = iCustom->AddControlItem(nId, i, o3tl::toW(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 ); + + // don't 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_GPGENCRYPTION : + 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 <<= bool(bValue); + } + break; + case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION: + case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE: + case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE: + case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR: + { + DWORD bValue = 0; + HRESULT hResult = iCustom->GetSelectedControlItem(nId, &bValue); + if ( SUCCEEDED(hResult) ) + { + const OUString& sItem = m_lItems[bValue]; + aValue <<= OUString(sItem.getStr()); + } + } + 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 ); + OUString sLabel = rRequest->getArgumentOrDefault(PROP_CONTROL_LABEL, OUString() ); + + // don't check for right values here ... + // most parameters are optional ! + + TFileDialogCustomize iCustom = impl_getCustomizeInterface(); + if ( ! iCustom.is()) + return; + iCustom->SetControlLabel (nId, o3tl::toW(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 ); + bool bEnabled = rRequest->getArgumentOrDefault(PROP_CONTROL_ENABLE, true); + + // don't 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 OUString& currentFilter ) +{ + TFileDialog iDialog = impl_getBaseDialogInterface(); + if (currentFilter.getLength()) + { + OUString FilterExt; + m_lFilters.getFilterByName(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 = OUString(pFirstExtStart, posOfSemiColon - posOfPoint); + iDialog->SetDefaultExtension ( o3tl::toW(FilterExt.getStr()) ); + } +} + +void VistaFilePickerImpl::onAutoExtensionChanged (bool bChecked) +{ + // SYNCHRONIZED-> + osl::ClearableMutexGuard aLock(m_aMutex); + + const OUString sFilter = m_lFilters.getCurrentFilter (); + OUString sExt ; + if (!m_lFilters.getFilterByName(sFilter, sExt)) + return; + + TFileDialog iDialog = impl_getBaseDialogInterface(); + + aLock.clear(); + // <- SYNCHRONIZED + + PCWSTR pExt = nullptr; + if ( bChecked ) + { + pExt = o3tl::toW(sExt.getStr()); + pExt = wcsrchr( pExt, '.' ); + if ( pExt ) + pExt++; + } + iDialog->SetDefaultExtension( pExt ); +} + +bool VistaFilePickerImpl::onFileTypeChanged( UINT /*nTypeIndex*/ ) +{ + return true; +} + +void VistaFilePickerImpl::onDirectoryChanged() +{ + m_sDirectory = GetDirectory(); +} + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/VistaFilePickerImpl.hxx b/fpicker/source/win32/VistaFilePickerImpl.hxx new file mode 100644 index 000000000..e5d2d88e4 --- /dev/null +++ b/fpicker/source/win32/VistaFilePickerImpl.hxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKERIMPL_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKERIMPL_HXX + +#include "platform_vista.h" + +#include <shobjidl.h> + +#include "asyncrequests.hxx" +#include "comptr.hxx" +#include "vistatypes.h" +#include "FilterContainer.hxx" +#include "VistaFilePickerEventHandler.hxx" +#include "IVistaFilePickerInternalNotify.hxx" +#include "resourceprovider.hxx" + +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/basemutex.hxx> +#include <osl/thread.hxx> +#include <osl/conditn.hxx> +#include <rtl/ustring.hxx> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types, const etcpp + + +static const ::sal_Int32 FEATURE_AUTOEXTENSION = 1; +static const ::sal_Int32 FEATURE_PASSWORD = 2; +static const ::sal_Int32 FEATURE_FILTEROPTIONS = 4; +static const ::sal_Int32 FEATURE_SELECTION = 8; +static const ::sal_Int32 FEATURE_TEMPLATE = 16; +static const ::sal_Int32 FEATURE_LINK = 32; +static const ::sal_Int32 FEATURE_PREVIEW = 64; +static const ::sal_Int32 FEATURE_IMAGETEMPLATE = 128; +static const ::sal_Int32 FEATURE_PLAY = 256; +static const ::sal_Int32 FEATURE_READONLY = 512; +static const ::sal_Int32 FEATURE_VERSION = 1024; +static const ::sal_Int32 FEATURE_GPGPASSWORD = 2048; +static const ::sal_Int32 FEATURE_IMAGEANCHOR = 4096; + +static const OUString PROP_PICKER_LISTENER("picker_listener" ); // [XFilePickerListenert] +static const OUString PROP_DIALOG_SHOW_RESULT("dialog_show_result" ); // [sal_Bool] true=OK, false=CANCEL +static const OUString PROP_SELECTED_FILES("selected_files" ); // [seq< OUString >] contains all user selected files (can be empty!) +static const OUString PROP_MULTISELECTION_MODE("multiselection_mode"); // [sal_Bool] true=ON, false=OFF +static const OUString PROP_TITLE("title" ); // [OUString] +static const OUString PROP_FILENAME("filename" ); // [OUString] +static const OUString PROP_DIRECTORY("directory" ); // [OUString] +static const OUString PROP_FEATURES("features" ); // [sal_Int32] +static const OUString PROP_TEMPLATE_DESCR("templatedescription"); // [sal_Int32] +static const OUString PROP_FILTER_TITLE("filter_title" ); // [OUString] +static const OUString PROP_FILTER_VALUE("filter_value" ); // [OUString] +static const OUString PROP_FILTER_GROUP("filter-group" ); // [seq< css:beans::StringPair >] contains a group of filters + +static const OUString PROP_CONTROL_ID("control_id" ); // [sal_Int16] +static const OUString PROP_CONTROL_ACTION("control_action" ); // [sal_Int16] +static const OUString PROP_CONTROL_VALUE("control_value" ); // [Any] +static const OUString PROP_CONTROL_LABEL("control_label" ); // [OUString] +static const OUString PROP_CONTROL_ENABLE("control_enable" ); // [sal_Bool] true=ON, false=OFF +static const OUString PROP_PARENT_WINDOW("ParentWindow"); //[css::awt::XWindow] preferred parent window +static const OUString STRING_SEPARATOR("------------------------------------------" ); + + +/** native implementation of the file picker on Vista and upcoming windows versions. + * This dialog uses COM internally. Further it marshall every request so it will + * be executed within its own STA thread ! + */ + +class VistaFilePickerImpl : private ::cppu::BaseMutex + , public RequestHandler + , public IVistaFilePickerInternalNotify +{ + public: + + // Workaround made to get input in Template Listbox + css::uno::Sequence< OUString > m_lItems; + /** used for marshalling requests. + * Will be used to map requests to the right implementations. + */ + enum ERequest + { + E_NO_REQUEST, + E_ADD_PICKER_LISTENER, + E_REMOVE_PICKER_LISTENER, + E_APPEND_FILTER, + E_SET_CURRENT_FILTER, + E_GET_CURRENT_FILTER, + E_CREATE_OPEN_DIALOG, + E_CREATE_SAVE_DIALOG, + E_CREATE_FOLDER_PICKER, + E_SET_MULTISELECTION_MODE, + E_SET_TITLE, + E_SET_FILENAME, + E_GET_DIRECTORY, + E_SET_DIRECTORY, + E_SET_DEFAULT_NAME, + E_GET_SELECTED_FILES, + E_SHOW_DIALOG_MODAL, + E_SET_CONTROL_VALUE, + E_GET_CONTROL_VALUE, + E_SET_CONTROL_LABEL, + E_GET_CONTROL_LABEL, + E_ENABLE_CONTROL, + E_APPEND_FILTERGROUP + }; + + public: + + + // ctor/dtor - nothing special + + VistaFilePickerImpl(); + virtual ~VistaFilePickerImpl() override; + + + // RequestHandler + + + virtual void before() override; + virtual void doRequest(const RequestRef& rRequest) override; + virtual void after() override; + + + // IVistaFilePickerInternalNotify + + virtual void onAutoExtensionChanged (bool bChecked) override; + virtual bool onFileTypeChanged( UINT nTypeIndex ) override; + virtual void onDirectoryChanged() override; + + private: + OUString GetDirectory(); + + /// implementation of request E_ADD_FILEPICKER_LISTENER + void impl_sta_addFilePickerListener(const RequestRef& rRequest); + + + /// implementation of request E_REMOVE_FILEPICKER_LISTENER + void impl_sta_removeFilePickerListener(const RequestRef& rRequest); + + + /// implementation of request E_APPEND_FILTER + void impl_sta_appendFilter(const RequestRef& rRequest); + + + /// implementation of request E_APPEND_FILTERGROUP + void impl_sta_appendFilterGroup(const RequestRef& rRequest); + + + /// implementation of request E_SET_CURRENT_FILTER + void impl_sta_setCurrentFilter(const RequestRef& rRequest); + + + /// implementation of request E_GET_CURRENT_FILTER + void impl_sta_getCurrentFilter(const RequestRef& rRequest); + + + /// implementation of request E_CREATE_OPEN_DIALOG + void impl_sta_CreateOpenDialog(const RequestRef& rRequest); + + + /// implementation of request E_CREATE_SAVE_DIALOG + void impl_sta_CreateSaveDialog(const RequestRef& rRequest); + + + /// implementation of request E_CREATE_FOLDER_PICKER + void impl_sta_CreateFolderPicker(const RequestRef& rRequest); + + + /// implementation of request E_SET_MULTISELECTION_MODE + void impl_sta_SetMultiSelectionMode(const RequestRef& rRequest); + + + /// implementation of request E_SET_TITLE + void impl_sta_SetTitle(const RequestRef& rRequest); + + + /// implementation of request E_SET_FILENAME + void impl_sta_SetFileName(const RequestRef& rRequest); + + + /// implementation of request E_SET_DIRECTORY + void impl_sta_SetDirectory(const RequestRef& rRequest); + + + /// implementation of request E_GET_DIRECTORY + void impl_sta_GetDirectory(const RequestRef& rRequest); + + + /// implementation of request E_SET_DEFAULT_NAME + void impl_sta_SetDefaultName(const RequestRef& rRequest); + + + /// implementation of request E_GET_SELECTED_FILES + void impl_sta_getSelectedFiles(const RequestRef& rRequest); + + + /// implementation of request E_SHOW_DIALOG_MODAL + void impl_sta_ShowDialogModal(const RequestRef& rRequest); + + + /// implementation of request E_SET_CONTROL_VALUE + void impl_sta_SetControlValue(const RequestRef& rRequest); + + + /// implementation of request E_GET_CONTROL_VALUE + void impl_sta_GetControlValue(const RequestRef& rRequest); + + + /// implementation of request E_SET_CONTROL_LABEL + void impl_sta_SetControlLabel(const RequestRef& rRequest); + + + /// implementation of request E_GET_CONTROL_LABEL + static void impl_sta_GetControlLabel(const RequestRef& rRequest); + + + /// implementation of request E_ENABLE_CONTROL + void impl_sta_EnableControl(const RequestRef& rRequest); + + /** create all needed (optional!) UI controls addressed by the field nFeatures. + * The given number nFeatures is used as a flag field. Use const values FEATURE_XXX + * to address it. + * + * Internal new controls will be added to the dialog. Every control can be accessed + * by its own control id. Those control ID must be one of the const set + * css::ui::dialogs::ExtendedFilePickerElementIds. + * + * @see setControlValue() + * @see getControlValue() + * @see setControlLabel() + * @see getControlLabel() + * @see enableControl() + * + * @param nFeatures + * flag field(!) knows all features which must be enabled. + */ + void impl_sta_enableFeatures(::sal_Int32 nFeatures, ::sal_Int32 nTemplate); + + + /** returns an interface, which can be used to customize the internally used + * COM dialog. + * + * Because we use two member (open/save dialog) internally, this method + * ask the current active one for its customization interface. + * + * @return the customization interface for the current used dialog. + * Must not be null. + */ + TFileDialogCustomize impl_getCustomizeInterface(); + TFileDialog impl_getBaseDialogInterface(); + + + /// fill filter list of internal used dialog. + void impl_sta_setFiltersOnDialog(); + + void impl_SetDefaultExtension( const OUString& currentFilter ); + + private: + enum class PickerDialog + { + FileOpen, + FileSave, + Folder, + }; + + void impl_sta_CreateDialog(const RequestRef& rRequest, PickerDialog eType, DWORD nOrFlags); + + + /// COM object representing a file open dialog + TFileOpenDialog m_iDialogOpen; + + + /// COM object representing a file save dialog + TFileSaveDialog m_iDialogSave; + + + /// COM object representing a folder picker dialog + TFolderPickerDialog m_iFolderPicker; + + + /// knows the return state of the last COM call + HRESULT m_hLastResult; + + + /// @todo document me + CFilterContainer m_lFilters; + + + /** help us to handle dialog events and provide them to interested office + * listener. + */ + TFileDialogEvents m_iEventHandler; + + + /// @todo document me + bool m_bInExecute; + + bool m_bWasExecuted; + + // handle to parent window + HWND m_hParentWindow; + + + OUString m_sDirectory; + + + OUString m_sFilename; +}; + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTAFILEPICKERIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/WinImplHelper.cxx b/fpicker/source/win32/WinImplHelper.cxx new file mode 100644 index 000000000..ab1dcbe00 --- /dev/null +++ b/fpicker/source/win32/WinImplHelper.cxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "WinImplHelper.hxx" + +#include <vector> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; + +const OUString TILDE( "~" ); +const sal_Unicode TILDE_SIGN = L'~'; +const OUString AMPERSAND( "&" ); +const sal_Unicode AMPERSAND_SIGN = L'&'; + +// OS NAME Platform Major Minor + +// Windows NT 3.51 VER_PLATFORM_WIN32_NT 3 51 +// Windows NT 4.0 VER_PLATFORM_WIN32_NT 4 0 +// Windows 2000 VER_PLATFORM_WIN32_NT 5 0 +// Windows XP VER_PLATFORM_WIN32_NT 5 1 +// Windows Vista VER_PLATFORM_WIN32_NT 6 0 +// Windows 7 VER_PLATFORM_WIN32_NT 6 1 +// Windows 95 VER_PLATFORM_WIN32_WINDOWS 4 0 +// Windows 98 VER_PLATFORM_WIN32_WINDOWS 4 10 +// Windows ME VER_PLATFORM_WIN32_WINDOWS 4 90 + + +static void Replace( const OUString& aLabel, sal_Unicode OldChar, sal_Unicode NewChar, OUStringBuffer& aBuffer ) +{ + OSL_ASSERT( aLabel.getLength( ) ); + OSL_ASSERT( aBuffer.getCapacity( ) >= (aLabel.getLength( )) ); + + sal_Int32 i = 0; + const sal_Unicode* pCurrent = aLabel.getStr( ); + const sal_Unicode* pNext = aLabel.getStr( ) + 1; + const sal_Unicode* pEnd = aLabel.getStr( ) + aLabel.getLength( ); + + while( pCurrent < pEnd ) + { + OSL_ASSERT( pNext <= pEnd ); + OSL_ASSERT( (i >= 0) && (i < aBuffer.getCapacity( )) ); + + if ( OldChar == *pCurrent ) + { + if ( OldChar == *pNext ) + { + // two OldChars in line will + // be replaced by one + // e.g. ~~ -> ~ + aBuffer.insert( i, *pCurrent ); + + // skip the next one + pCurrent++; + pNext++; + } + else + { + // one OldChar will be replace + // by NexChar + aBuffer.insert( i, NewChar ); + } + } + else if ( *pCurrent == NewChar ) + { + // a NewChar will be replaced by + // two NewChars + // e.g. & -> && + aBuffer.insert( i++, *pCurrent ); + aBuffer.insert( i, *pCurrent ); + } + else + { + aBuffer.insert( i, *pCurrent ); + } + + pCurrent++; + pNext++; + i++; + } +} + +// converts a soffice label to a windows label +// the following rules for character replacements +// will be done: +// '~' -> '&' +// '~~' -> '~' +// '&' -> '&&' + +OUString SOfficeToWindowsLabel( const OUString& aSOLabel ) +{ + OUString aWinLabel = aSOLabel; + + if ( (aWinLabel.indexOf( TILDE ) > -1) || (aWinLabel.indexOf( AMPERSAND ) > -1) ) + { + sal_Int32 nStrLen = aWinLabel.getLength( ); + + // in the worst case the new string is + // doubled in length, maybe some waste + // of memory but how long is a label + // normally(?) + OUStringBuffer aBuffer( nStrLen * 2 ); + + Replace( aWinLabel, TILDE_SIGN, AMPERSAND_SIGN, aBuffer ); + + aWinLabel = aBuffer.makeStringAndClear( ); + } + + return aWinLabel; +} + +// converts a windows label to a soffice label +// the following rules for character replacements +// will be done: +// '&' -> '~' +// '&&' -> '&' +// '~' -> '~~' + +OUString WindowsToSOfficeLabel( const OUString& aWinLabel ) +{ + OUString aSOLabel = aWinLabel; + + if ( (aSOLabel.indexOf( TILDE ) > -1) || (aSOLabel.indexOf( AMPERSAND ) > -1) ) + { + sal_Int32 nStrLen = aSOLabel.getLength( ); + + // in the worst case the new string is + // doubled in length, maybe some waste + // of memory but how long is a label + // normally(?) + OUStringBuffer aBuffer( nStrLen * 2 ); + + Replace( aSOLabel, AMPERSAND_SIGN, TILDE_SIGN, aBuffer ); + + aSOLabel = aBuffer.makeStringAndClear( ); + } + + return aSOLabel; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/WinImplHelper.hxx b/fpicker/source/win32/WinImplHelper.hxx new file mode 100644 index 000000000..acac133d3 --- /dev/null +++ b/fpicker/source/win32/WinImplHelper.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_MISC_WINIMPLHELPER_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_MISC_WINIMPLHELPER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +// converts a soffice label to a windows label +// the following rules for character replacements +// will be done: +// '~' -> '&' +// '~~' -> '~' +// '&' -> '&&' +OUString SOfficeToWindowsLabel( const OUString& aSOLabel ); + +// converts a windows label to a soffice label +// the following rules for character replacements +// will be done: +// '&' -> '~' +// '&&' -> '&' +// '~' -> '~~' +OUString WindowsToSOfficeLabel( const OUString& aWinLabel ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/asyncrequests.cxx b/fpicker/source/win32/asyncrequests.cxx new file mode 100644 index 000000000..86b71cf51 --- /dev/null +++ b/fpicker/source/win32/asyncrequests.cxx @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "asyncrequests.hxx" +#include <vcl/svapp.hxx> +#include <vcl/winscheduler.hxx> +#include <osl/mutex.hxx> + +namespace fpicker{ +namespace win32{ +namespace vista{ + +static void lcl_sleep( ::osl::Condition& aCondition, + ::sal_Int32 nMilliSeconds ) +{ + if (nMilliSeconds < 1) + aCondition.wait(); + else + { + TimeValue aTime; + aTime.Seconds = (nMilliSeconds / 1000); + aTime.Nanosec = (nMilliSeconds % 1000) * 1000000; + aCondition.wait(&aTime); + } +} + +void Request::wait( ::sal_Int32 nMilliSeconds ) +{ + SolarMutexReleaser aReleaser; + + lcl_sleep( m_aJoiner, nMilliSeconds ); +} + +void Request::waitProcessMessages() +{ + SolarMutexGuard aGuard; + while ( !m_aJoiner.check() ) + Application::Yield(); +} + +void Request::notify() +{ + m_aJoiner.set(); + // Make sure that main loop receives at least this message to return from GetMessage and recheck + // the condition, even in case when there's no visible application windows present, and thus no + // other messages might arrive to the main loop. + WinScheduler::PostDummyMessage(); +} + +AsyncRequests::AsyncRequests(const RequestHandlerRef& rHandler) + : ::cppu::BaseMutex( ) + , ::osl::Thread ( ) + , m_bFinish (false) + , m_rHandler (rHandler ) + , m_lRequests ( ) +{ +} + +AsyncRequests::~AsyncRequests() +{ + // SYNCHRONIZED -> + { + osl::MutexGuard aLock(m_aMutex); + m_bFinish = true; + } + // <- SYNCHRONIZED + + // The static AsyncRequests aNotify in VistaFilePickerEventHandler::impl_sendEvent + // is destructed at DLL atexit. But it won't run, so needs no join and release of + // the already destructed SolarMutex, which would crash LO on exit. + if (isRunning()) + { + // tdf#123502: make sure we actually hold the mutex before releasing it + // UNO directly destroys the VistaFilePicker object, so we need GUI protection in there. + // But since we redirect GUI stuff to the async thread we also have to release it, so we + // can join it, if the thread currently blocks on the SolarMutex. + SolarMutexGuard aGuard; + SolarMutexReleaser aReleaser; + join(); + } +} + +void AsyncRequests::triggerJobExecution() +{ + if ( ! isRunning()) + create(); + else + maWait.set(); +} + +void AsyncRequests::triggerRequestProcessMessages (const RequestRef& rRequest) +{ + // SYNCHRONIZED -> + { + osl::MutexGuard aLock(m_aMutex); + m_lRequests.push(rRequest); + } + // <- SYNCHRONIZED + + rRequest->waitProcessMessages(); +} + +void AsyncRequests::triggerRequestBlocked(const RequestRef& rRequest) +{ + // SYNCHRONIZED -> + { + osl::MutexGuard aLock(m_aMutex); + m_lRequests.push(rRequest); + } + // <- SYNCHRONIZED + + triggerJobExecution(); + + rRequest->wait(); +} + +void AsyncRequests::triggerRequestNonBlocked(const RequestRef& rRequest) +{ + // SYNCHRONIZED -> + { + osl::MutexGuard aLock(m_aMutex); + m_lRequests.push(rRequest); + } + // <- SYNCHRONIZED + + triggerJobExecution(); +} + +void AsyncRequests::triggerRequestDirectly(const RequestRef& rRequest) +{ + // SYNCHRONIZED -> + osl::ClearableMutexGuard aLock(m_aMutex); + RequestHandlerRef rHandler = m_rHandler; + aLock.clear(); + // <- SYNCHRONIZED + + if (rHandler != nullptr) + rHandler->doRequest(rRequest); +} + +void AsyncRequests::triggerRequestThreadAware(const RequestRef& rRequest, + ::sal_Int16 nWait ) +{ + oslThreadIdentifier nOurThreadId = getIdentifier(); + oslThreadIdentifier nCallerThreadId = ::osl::Thread::getCurrentIdentifier(); + SolarMutexGuard aGuard; + if (nOurThreadId == nCallerThreadId) + triggerRequestDirectly(rRequest); + else if (nWait == BLOCKED) + triggerRequestBlocked(rRequest); + else if (nWait == PROCESS_MESSAGES) + triggerRequestProcessMessages(rRequest); + else + triggerRequestNonBlocked(rRequest); +} + +void SAL_CALL AsyncRequests::run() +{ + osl_setThreadName("fpicker::win32::vista::AsyncRequests"); + + static const ::sal_Int32 TIME_TO_WAIT_FOR_NEW_REQUESTS = 250; + + // SYNCHRONIZED -> + ::osl::ResettableMutexGuard aLock(m_aMutex); + RequestHandlerRef rHandler = m_rHandler; + bool bFinished = m_bFinish; + aLock.clear(); + // <- SYNCHRONIZED + + if (rHandler != nullptr) + rHandler->before(); + + while ( ! bFinished) + { + // SYNCHRONIZED -> + aLock.reset(); + + RequestRef rRequest; + if ( ! m_lRequests.empty()) + { + rRequest = m_lRequests.front(); + m_lRequests.pop(); + } + bFinished = m_bFinish; + + aLock.clear(); + // <- SYNCHRONIZED + + if (rRequest == nullptr) + { + lcl_sleep(maWait, TIME_TO_WAIT_FOR_NEW_REQUESTS); + maWait.reset(); + continue; + } + + if (rHandler != nullptr) + { + rHandler->doRequest(rRequest); + rRequest->notify(); + } + } + + if (rHandler != nullptr) + rHandler->after(); +} + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/asyncrequests.hxx b/fpicker/source/win32/asyncrequests.hxx new file mode 100644 index 000000000..5fbd7dde8 --- /dev/null +++ b/fpicker/source/win32/asyncrequests.hxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_ASYNCREQUESTS_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_ASYNCREQUESTS_HXX + +#include <cppuhelper/basemutex.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <osl/conditn.hxx> +#include <osl/thread.hxx> +#include <osl/time.h> +#include <queue> +#include <memory> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +/** @todo document me + */ +class Request +{ + + public: + + static const ::sal_Int32 WAIT_INFINITE = 0; + + + // interface + + + public: + + + explicit Request() + : m_aJoiner ( ) + , m_nRequest (-1) + , m_lArguments( ) + { + m_aJoiner.reset(); + } + + + virtual ~Request() {}; + + + void setRequest(::sal_Int32 nRequest) + { + m_nRequest = nRequest; + } + + + ::sal_Int32 getRequest() + { + return m_nRequest; + } + + + void clearArguments() + { + m_lArguments.clear(); + } + + + template< class TArgumentType > + void setArgument(const OUString& sName , + const TArgumentType& aValue) + { + m_lArguments[sName] = css::uno::toAny(aValue); + } + + + template< class TArgumentType > + TArgumentType getArgumentOrDefault(const OUString& sName , + const TArgumentType& aDefault) + { + return m_lArguments.getUnpackedValueOrDefault(sName, aDefault); + } + + css::uno::Any getValue(OUString const & key) const + { + return m_lArguments.getValue(key); + } + + void wait(::sal_Int32 nMilliSeconds = WAIT_INFINITE); + + void waitProcessMessages(); + + + void notify(); + + + // member + + + private: + + ::osl::Condition m_aJoiner; + ::sal_Int32 m_nRequest; + ::comphelper::SequenceAsHashMap m_lArguments; +}; + +typedef std::shared_ptr< Request > RequestRef; +typedef std::queue< RequestRef > RequestQueue; + + +class RequestHandler +{ + public: + virtual ~RequestHandler() {} + virtual void before() = 0; + virtual void doRequest(const RequestRef& rRequest) = 0; + virtual void after() = 0; +}; + +typedef std::shared_ptr< RequestHandler > RequestHandlerRef; + + +/** @todo document me + */ +class AsyncRequests final: private ::cppu::BaseMutex + , public ::osl::Thread +{ + public: + static const ::sal_Int16 PROCESS_MESSAGES = 2; + static const ::sal_Int16 BLOCKED = 1; + static const ::sal_Int16 NON_BLOCKED = 0; + + + /** creates the new asynchronous request executor. + */ + explicit AsyncRequests(const RequestHandlerRef& rHandler); + + void setHandler(const RequestHandlerRef& rHandler) + { + m_rHandler = rHandler; + } + + /// ensure the execution thread gets going. + void triggerJobExecution(); + + + /** does nothing special / excepting to make sure our class won't be inline .-) + */ + virtual ~AsyncRequests() override; + + + /** @todo document me + */ + void triggerRequestProcessMessages (const RequestRef& rRequest); + + + /** @todo document me + */ + void triggerRequestBlocked(const RequestRef& rRequest); + + + /** @todo document me + */ + void triggerRequestNonBlocked(const RequestRef& rRequest); + + + /** @todo document me + */ + void triggerRequestDirectly(const RequestRef& rRequest); + + + /** @todo document me + */ + void triggerRequestThreadAware(const RequestRef& rRequest, + ::sal_Int16 nWait ); + + private: + + + /** our STA .-) + * Will run between start() & finish(). Internally it runs a loop ... + * waiting for requests. Every request will be executed synchronously + * in blocked mode. + */ + virtual void SAL_CALL run() override; + + private: + + bool m_bFinish; + RequestHandlerRef m_rHandler; + RequestQueue m_lRequests; + osl::Condition maWait; +}; + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_ASYNCREQUESTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/comptr.hxx b/fpicker/source/win32/comptr.hxx new file mode 100644 index 000000000..2469d8b5e --- /dev/null +++ b/fpicker/source/win32/comptr.hxx @@ -0,0 +1,212 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_COMPTR_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_COMPTR_HXX + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <shobjidl.h> + +template< class T_INTERFACE , + REFIID P_IID = IID_NULL , + REFCLSID P_CLSID = CLSID_NULL > +class ComPtr +{ + public: + + + /** initialize com ptr with null. + */ + ComPtr() + { + m_pInterface = nullptr; + } + + + /** initialize com ptr with given interface. + */ + explicit ComPtr(T_INTERFACE* pInterface) + { + m_pInterface = pInterface; + if (m_pInterface) + m_pInterface->AddRef(); + } + + + /** copy ctor. + */ + ComPtr(const ComPtr< T_INTERFACE, P_IID, P_CLSID >& aCopy) + { + m_pInterface = aCopy.m_pInterface; + if (m_pInterface) + m_pInterface->AddRef(); + } + + + /** initialize object by querying external object for the right interface. + */ + explicit ComPtr(IUnknown* pIUnknown) + { + if (pIUnknown) + pIUnknown->QueryInterface(P_IID, (void**)&m_pInterface); + } + + + /** deinitialize com object right. + */ + ~ComPtr() + { + release(); + } + + public: + + + HRESULT create() + { + return CoCreateInstance(P_CLSID, nullptr, CLSCTX_ALL, P_IID, reinterpret_cast<void**>(&m_pInterface)); + } + + + operator T_INTERFACE*() const + { + return m_pInterface; + } + + + T_INTERFACE& operator*() const + { + return *m_pInterface; + } + + + T_INTERFACE** operator&() + { + return &m_pInterface; + } + + + T_INTERFACE* operator->() const + { + return m_pInterface; + } + + + T_INTERFACE* operator=(T_INTERFACE* pInterface) + { + if ( equals(pInterface) ) + return m_pInterface; + + m_pInterface->Release(); + m_pInterface = pInterface; + if (m_pInterface) + m_pInterface->AddRef(); + + return m_pInterface; + } + + + T_INTERFACE* operator=(IUnknown* pIUnknown) + { + if (pIUnknown) + pIUnknown->QueryInterface(P_IID, (void**)&m_pInterface); + return m_pInterface; + } + + + T_INTERFACE* operator=(const ComPtr< T_INTERFACE, P_IID, P_CLSID >& aCopy) + { + m_pInterface = aCopy.m_pInterface; + if (m_pInterface) + m_pInterface->AddRef(); + + return m_pInterface; + } + + + T_INTERFACE* get() const + { + return m_pInterface; + } + + + void attach(T_INTERFACE* pInterface) + { + if (pInterface) + { + m_pInterface->Release(); + m_pInterface = pInterface; + } + } + + + T_INTERFACE* detach() + { + T_INTERFACE* pInterface = m_pInterface; + m_pInterface = NULL; + return pInterface; + } + + + void release() + { + if (m_pInterface) + { + m_pInterface->Release(); + m_pInterface = nullptr; + } + } + + template< class T_QUERYINTERFACE > + HRESULT query(T_QUERYINTERFACE** pQuery) + { + return m_pInterface->QueryInterface(__uuidof(T_QUERYINTERFACE), reinterpret_cast<void**>(pQuery)); + } + + bool equals(IUnknown* pCheck) + { + if ( + ( ! m_pInterface ) && + ( ! pCheck ) + ) + return sal_True; + + IUnknown* pCurrent = NULL; + m_pInterface->QueryInterface(IID_IUnknown, (void**)&pCurrent); + + sal_Bool bEquals = (pCheck == pCurrent); + pCurrent->Release(); + + return bEquals; + } + + + bool is() + { + return (m_pInterface != nullptr); + } + + private: + T_INTERFACE* m_pInterface; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/fps.component b/fpicker/source/win32/fps.component new file mode 100644 index 000000000..80dac1a9b --- /dev/null +++ b/fpicker/source/win32/fps.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . +--> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="fps_win32" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.ui.dialogs.Win32FilePicker"> + <service name="com.sun.star.ui.dialogs.SystemFilePicker"/> + </implementation> + <implementation name="com.sun.star.ui.dialogs.Win32FolderPicker"> + <service name="com.sun.star.ui.dialogs.SystemFolderPicker"/> + </implementation> +</component> diff --git a/fpicker/source/win32/platform_vista.h b/fpicker/source/win32/platform_vista.h new file mode 100644 index 000000000..a6e6d2121 --- /dev/null +++ b/fpicker/source/win32/platform_vista.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_PLATFORM_VISTA_H +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_PLATFORM_VISTA_H + +#undef _WTL_NO_CSTRING + +#define _WTL_NO_CSTRING + +#if defined _MSC_VER +#include <comip.h> +#undef RGB +#endif + +#ifdef _MSC_VER +#if defined _M_IX86 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/resourceprovider.cxx b/fpicker/source/win32/resourceprovider.cxx new file mode 100644 index 000000000..883edf36d --- /dev/null +++ b/fpicker/source/win32/resourceprovider.cxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sal/config.h> + +#include <memory> + +#include <rtl/ustrbuf.hxx> +#include "resourceprovider.hxx" +#include <osl/mutex.hxx> +#include <fpicker/strings.hrc> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <unotools/resmgr.hxx> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <fpsofficeResMgr.hxx> + +using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; +using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; + +#define FOLDERPICKER_TITLE 500 +#define FOLDER_PICKER_DEF_DESCRIPTION 501 + +// we have to translate control ids to resource ids + +namespace { + +struct Entry +{ + sal_Int32 ctrlId; + const char* resId; +}; + +} + +Entry const CtrlIdToResIdTable[] = { + { CHECKBOX_AUTOEXTENSION, STR_SVT_FILEPICKER_AUTO_EXTENSION }, + { CHECKBOX_PASSWORD, STR_SVT_FILEPICKER_PASSWORD }, + { CHECKBOX_FILTEROPTIONS, STR_SVT_FILEPICKER_FILTER_OPTIONS }, + { CHECKBOX_READONLY, STR_SVT_FILEPICKER_READONLY }, + { CHECKBOX_LINK, STR_SVT_FILEPICKER_INSERT_AS_LINK }, + { CHECKBOX_PREVIEW, STR_SVT_FILEPICKER_SHOW_PREVIEW }, + { PUSHBUTTON_PLAY, STR_SVT_FILEPICKER_PLAY }, + { LISTBOX_VERSION_LABEL, STR_SVT_FILEPICKER_VERSION }, + { LISTBOX_TEMPLATE_LABEL, STR_SVT_FILEPICKER_TEMPLATES }, + { LISTBOX_IMAGE_TEMPLATE_LABEL, STR_SVT_FILEPICKER_IMAGE_TEMPLATE }, + { LISTBOX_IMAGE_ANCHOR_LABEL, STR_SVT_FILEPICKER_IMAGE_ANCHOR }, + { CHECKBOX_SELECTION, STR_SVT_FILEPICKER_SELECTION }, + { FOLDERPICKER_TITLE, STR_SVT_FOLDERPICKER_DEFAULT_TITLE }, + { FOLDER_PICKER_DEF_DESCRIPTION, STR_SVT_FOLDERPICKER_DEFAULT_DESCRIPTION }, + { CHECKBOX_GPGENCRYPTION, STR_SVT_FILEPICKER_GPGENCRYPT } +}; + +const sal_Int32 SIZE_TABLE = SAL_N_ELEMENTS( CtrlIdToResIdTable ); + +static const char* CtrlIdToResId( sal_Int32 aControlId ) +{ + const char* pResId = nullptr; + + for ( sal_Int32 i = 0; i < SIZE_TABLE; i++ ) + { + if ( CtrlIdToResIdTable[i].ctrlId == aControlId ) + { + pResId = CtrlIdToResIdTable[i].resId; + break; + } + } + + return pResId; +} + +namespace CResourceProvider +{ + OUString getResString( sal_Int16 aId ) + { + OUString aResOUString; + // translate the control id to a resource id + const char *pResId = CtrlIdToResId(aId); + if (pResId) + aResOUString = FpsResId(pResId); + return aResOUString; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/resourceprovider.hxx b/fpicker/source/win32/resourceprovider.hxx new file mode 100644 index 000000000..a611d1aaf --- /dev/null +++ b/fpicker/source/win32/resourceprovider.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_MISC_RESOURCEPROVIDER_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_MISC_RESOURCEPROVIDER_HXX + +#include <sal/config.h> + +#include <memory> + +#include <sal/types.h> + +#include <rtl/ustring.hxx> + +namespace CResourceProvider +{ + OUString getResString(sal_Int16 aId); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/shared.hxx b/fpicker/source/win32/shared.hxx new file mode 100644 index 000000000..be8813f32 --- /dev/null +++ b/fpicker/source/win32/shared.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_SHARED_HXX +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_SHARED_HXX + +#include <rtl/ustring.hxx> + +const OUString BACKSLASH( "\\" ); +const OUString FILTER_SEPARATOR( "------------------------------------------" ); +const OUString ALL_FILES_WILDCARD( "*.*" ); +const bool ALLOW_DUPLICATES = true; + +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/vistatypes.h b/fpicker/source/win32/vistatypes.h new file mode 100644 index 000000000..4271b0cea --- /dev/null +++ b/fpicker/source/win32/vistatypes.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTATYPES_H +#define INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTATYPES_H + +#include "comptr.hxx" +#include <shobjidl.h> + +namespace fpicker{ +namespace win32{ +namespace vista{ + + +// types, const etcpp. + + +typedef ComPtr< IFileDialog , IID_IFileDialog > TFileDialog; +typedef ComPtr< IFileOpenDialog , IID_IFileOpenDialog , CLSID_FileOpenDialog > TFileOpenDialog; +typedef ComPtr< IFileSaveDialog , IID_IFileSaveDialog , CLSID_FileSaveDialog > TFileSaveDialog; +typedef ComPtr< IFileDialogEvents , IID_IFileDialogEvents > TFileDialogEvents; +typedef ComPtr< IFileDialogCustomize, IID_IFileDialogCustomize > TFileDialogCustomize; +typedef TFileOpenDialog TFolderPickerDialog; + +} // namespace vista +} // namespace win32 +} // namespace fpicker + +#endif // INCLUDED_FPICKER_SOURCE_WIN32_FILEPICKER_VISTATYPES_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/workbench/Test_fps.cxx b/fpicker/source/win32/workbench/Test_fps.cxx new file mode 100644 index 000000000..b801fcef3 --- /dev/null +++ b/fpicker/source/win32/workbench/Test_fps.cxx @@ -0,0 +1,356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <osl/file.hxx> + +#include <cppuhelper/servicefactory.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <osl/diagnose.h> +#include <com/sun/star/ui/dialogs/XFilePicker.hpp> +#include <com/sun/star/ui/dialogs/XFilterManager.hpp> + +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/ui/dialogs/XFilePickerListener.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerNotifier.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ListboxControlActions.hpp> +#include <com/sun/star/ui/dialogs/XFilePreview.hpp> + +#include <osl/thread.h> + +#include <stdio.h> +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include "..\FPServiceInfo.hxx" + + +// namespaces + + +using namespace ::cppu ; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::lang ; +using namespace ::com::sun::star::ui::dialogs ; +using namespace ::com::sun::star::ui::dialogs::TemplateDescription; + +using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; +using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; +using namespace ::com::sun::star::ui::dialogs::ListboxControlActions; + +using namespace std ; + +// forward + +void TestFilterManager( Reference< XFilePicker > xFilePicker ); + + +#define RDB_SYSPATH "D:\\Projects\\gsl\\sysui\\wntmsci7\\bin\\applicat.rdb" + + +// global variables + + +Reference< XMultiServiceFactory > g_xFactory; + +const OUString BMP_EXTENSION( "bmp" ); + + +// a test client + + +class FilePickerListener : public WeakImplHelper< XFilePickerListener > +{ +public: + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) + throw(css::uno::RuntimeException); + + // XFilePickerListener + virtual void SAL_CALL fileSelectionChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException); + + virtual void SAL_CALL directoryChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException); + + virtual OUString SAL_CALL helpRequested( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException); + + virtual void SAL_CALL controlStateChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException); + + virtual void SAL_CALL dialogSizeChanged( ) + throw (css::uno::RuntimeException); +}; + +void SAL_CALL FilePickerListener::disposing( const css::lang::EventObject& Source ) + throw(css::uno::RuntimeException) +{ +} + +void SAL_CALL FilePickerListener::fileSelectionChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException) +{ + try + { + Reference< XFilePicker > rXFilePicker( aEvent.Source, UNO_QUERY ); + Reference< XFilePreview > rXFilePreview( rXFilePicker, UNO_QUERY ); + + if ( !rXFilePreview.is( ) ) + return; + + Sequence< OUString > aFileList = rXFilePicker->getFiles( ); + if ( 1 == aFileList.getLength( ) ) + { + OUString FilePath = aFileList[0]; + + // detect file extension + sal_Int32 nIndex = FilePath.lastIndexOf( BMP_EXTENSION ); + if ( (FilePath.getLength( ) - 3) == nIndex ) + { + OUString FileSysPath; + ::osl::FileBase::getSystemPathFromFileURL( + FilePath, FileSysPath ); + + HANDLE hFile = CreateFileW( + FileSysPath.getStr( ), + GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ; + + if (hFile == INVALID_HANDLE_VALUE) + return; + + DWORD dwHighSize; + DWORD dwFileSize = GetFileSize (hFile, &dwHighSize) ; + + if (dwHighSize) + { + CloseHandle (hFile) ; + return; + } + + Sequence< sal_Int8 > aDIB( dwFileSize ); + + DWORD dwBytesRead; + sal_Bool bSuccess = ReadFile (hFile, aDIB.getArray( ), dwFileSize, &dwBytesRead, NULL) ; + CloseHandle (hFile); + + BITMAPFILEHEADER* pbmfh = (BITMAPFILEHEADER*)aDIB.getConstArray( ); + if (!bSuccess || (dwBytesRead != dwFileSize) + || (pbmfh->bfType != * (WORD *) "BM") + || (pbmfh->bfSize != dwFileSize)) + { + return; + } + + Any aAny; + + aAny <<= aDIB; + rXFilePreview->setImage( 1, aAny ); + } + } + } + catch( IllegalArgumentException& ) + { + } +} + +void SAL_CALL FilePickerListener::directoryChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException) +{ + Reference< XFilePickerControlAccess > rFilePickerCtrlAccess( aEvent.Source, UNO_QUERY ); +} + +OUString SAL_CALL FilePickerListener::helpRequested( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException) +{ + return OUString( ); +} + +void SAL_CALL FilePickerListener::controlStateChanged( const css::ui::dialogs::FilePickerEvent& aEvent ) + throw(css::uno::RuntimeException) +{ + try + { + Reference< XFilePickerControlAccess > rFPCtrlAccess( aEvent.Source, UNO_QUERY ); + + Any aValue; + + OUString lbString( L"Ein Eintrag 1" ); + aValue <<= lbString; + rFPCtrlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aValue ); + + lbString = L"Ein Eintrag 2"; + aValue <<= lbString; + rFPCtrlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aValue ); + + lbString = L"Ein Eintrag 3"; + aValue <<= lbString; + rFPCtrlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aValue ); + + sal_Int16 nSel = 1; + aValue <<= nSel; + rFPCtrlAccess->setValue( LISTBOX_VERSION, SET_SELECT_ITEM, aValue ); + + sal_Int32 nDel = 0; + aValue <<= nDel; + rFPCtrlAccess->setValue( LISTBOX_VERSION, DELETE_ITEM, aValue ); + } + catch( ... ) + { + } +} + +void SAL_CALL FilePickerListener::dialogSizeChanged( ) + throw(css::uno::RuntimeException) +{ +} + + +// main + + +int SAL_CALL main(int nArgc, char* Argv[], char* Env[] ) +{ + printf("Starting test of FPS-Service\n"); + + + // get the global service-manager + + + // Get global factory for uno services. + Reference< XMultiServiceFactory > g_xFactory( createRegistryServiceFactory( RDB_SYSPATH ) ); + + // Print a message if an error occurred. + if ( g_xFactory.is() == sal_False ) + { + OSL_FAIL("Can't create RegistryServiceFactory"); + return(-1); + } + + + // try to get an Interface to a XFilePicker Service + + + Sequence< Any > arguments(1); + arguments[0] = makeAny( FILEOPEN_READONLY_VERSION ); + + Reference< XFilePicker > xFilePicker( + g_xFactory->createInstanceWithArguments( + FILE_PICKER_SERVICE_NAME, arguments ), UNO_QUERY ); + + // install a FilePicker notifier + Reference< XFilePickerListener > xFPListener( + static_cast< XFilePickerListener* >( new FilePickerListener()), UNO_QUERY ); + + Reference< XFilePickerNotifier > xFPNotifier( xFilePicker, UNO_QUERY ); + if ( xFPNotifier.is( ) ) + xFPNotifier->addFilePickerListener( xFPListener ); + + xFilePicker->setTitle( OUString("FileOpen Simple...")); + xFilePicker->setMultiSelectionMode( sal_True ); + xFilePicker->setDefaultName( OUString("d:\\test2.sxw")); + + OUString aDirURL; + OUString aSysPath = OStringToOUString( "d:\\ueaeoe", osl_getThreadTextEncoding( ) ); + ::osl::FileBase::getFileURLFromSystemPath( aSysPath, aDirURL ); + xFilePicker->setDisplayDirectory( aDirURL ); + + Reference< XFilterManager > xFilterMgr( xFilePicker, UNO_QUERY ); + if ( xFilterMgr.is( ) ) + { + xFilterMgr->appendFilter( L"Alle", L"*.*" ); + xFilterMgr->appendFilter( L"BMP", L"*.bmp" ); + xFilterMgr->appendFilter( L"SDW", L"*.sdw;*.sdc;*.sdi" ); + xFilterMgr->appendFilter( L"SXW", L"*.sxw;*.sxi" ); + } + + Reference< XFilePickerControlAccess > xFPControlAccess( xFilePicker, UNO_QUERY ); + + Any aAny; + sal_Bool bChkState = sal_False; + + aAny.setValue( &bChkState, cppu::UnoType<sal_Bool>::get()); + xFPControlAccess->setValue( CHECKBOX_AUTOEXTENSION, 0, aAny ); + + OUString aVersion( L"Version 1" ); + aAny <<= aVersion; + xFPControlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aAny ); + xFPControlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aAny ); + xFPControlAccess->setValue( LISTBOX_VERSION, ADD_ITEM, aAny ); + + xFilePicker->execute( ); + + sal_Bool bCheckState; + aAny = xFPControlAccess->getValue( CHECKBOX_AUTOEXTENSION, 0 ); + if ( aAny.hasValue( ) ) + bCheckState = *reinterpret_cast< const sal_Bool* >( aAny.getValue( ) ); + + aAny = xFPControlAccess->getValue( CHECKBOX_READONLY, 0 ); + if ( aAny.hasValue( ) ) + bCheckState = *reinterpret_cast< const sal_Bool* >( aAny.getValue( ) ); + + aAny = xFPControlAccess->getValue( LISTBOX_VERSION, GET_SELECTED_ITEM ); + sal_Int32 nSel; + if ( aAny.hasValue( ) ) + aAny >>= nSel; + + aDirURL = xFilePicker->getDisplayDirectory( ); + Sequence< OUString > aFileList = xFilePicker->getFiles( ); + for ( int i = 0; i < aFileList.getLength( ); i++ ) + { + OUString nextPath = aFileList[i]; + } + + if ( xFPNotifier.is( ) ) + xFPNotifier->removeFilePickerListener( xFPListener ); + + + // shutdown + + + // Cast factory to XComponent + Reference< XComponent > xComponent( g_xFactory, UNO_QUERY ); + + // Print a message if an error occurred. + if ( xComponent.is() == sal_False ) + { + OSL_FAIL("Error shutting down"); + } + + // Dispose and clear factory + xComponent->dispose(); + g_xFactory.clear(); + + printf("Test successful\n"); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/fpicker/source/win32/workbench/makefile.mk b/fpicker/source/win32/workbench/makefile.mk new file mode 100644 index 000000000..5398300c1 --- /dev/null +++ b/fpicker/source/win32/workbench/makefile.mk @@ -0,0 +1,55 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# 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 . +# + +PRJ=..$/..$/..$/.. + +PRJNAME=sysui +TARGET=testfps +LIBTARGET=NO +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(COM)" == "MSC" +CFLAGS+=-GR -GX +.ENDIF + +# --- Files -------------------------------------------------------- + + +OBJFILES=$(OBJ)$/test_fps.obj + +APP1TARGET=$(TARGET) +APP1OBJS=$(OBJFILES) + +APP1STDLIBS+=\ + $(CPPULIB)\ + $(CPPUHELPERLIB)\ + $(SALLIB)\ + $(USER32LIB)\ + $(OLE32LIB) + +APP1DEF=$(MISC)$/$(APP1TARGET).def + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + |