summaryrefslogtreecommitdiffstats
path: root/fpicker/source/win32
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fpicker/source/win32/FilterContainer.cxx275
-rw-r--r--fpicker/source/win32/FilterContainer.hxx107
-rw-r--r--fpicker/source/win32/IVistaFilePickerInternalNotify.hxx48
-rw-r--r--fpicker/source/win32/VistaFilePicker.cxx541
-rw-r--r--fpicker/source/win32/VistaFilePicker.hxx224
-rw-r--r--fpicker/source/win32/VistaFilePickerEventHandler.cxx313
-rw-r--r--fpicker/source/win32/VistaFilePickerEventHandler.hxx192
-rw-r--r--fpicker/source/win32/VistaFilePickerImpl.cxx1249
-rw-r--r--fpicker/source/win32/VistaFilePickerImpl.hxx310
-rw-r--r--fpicker/source/win32/WinImplHelper.cxx161
-rw-r--r--fpicker/source/win32/WinImplHelper.hxx49
-rw-r--r--fpicker/source/win32/fps.component29
-rw-r--r--fpicker/source/win32/platform_vista.h43
-rw-r--r--fpicker/source/win32/requests.hxx76
-rw-r--r--fpicker/source/win32/resourceprovider.cxx103
-rw-r--r--fpicker/source/win32/resourceprovider.hxx35
-rw-r--r--fpicker/source/win32/shared.hxx29
-rw-r--r--fpicker/source/win32/vistatypes.h43
-rw-r--r--fpicker/source/win32/workbench/Test_fps.cxx356
-rw-r--r--fpicker/source/win32/workbench/makefile.mk55
20 files changed, 4238 insertions, 0 deletions
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..a1e498cef
--- /dev/null
+++ b/fpicker/source/win32/FilterContainer.hxx
@@ -0,0 +1,107 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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 );
+
+/* 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..42f00c196
--- /dev/null
+++ b/fpicker/source/win32/IVistaFilePickerInternalNotify.hxx
@@ -0,0 +1,48 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <systools/win32/uwinapi.h>
+
+namespace fpicker::win32::vista{
+
+
+// types, const etc.
+
+
+/** todo document me
+ */
+class IVistaFilePickerInternalNotify
+{
+ public:
+
+ virtual void onAutoExtensionChanged (bool bChecked) = 0;
+
+ virtual bool onFileTypeChanged( UINT nTypeIndex ) = 0;
+
+ virtual void onDirectoryChanged() = 0;
+
+ protected:
+ ~IVistaFilePickerInternalNotify() {}
+};
+
+}
+
+/* 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..dbd503073
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePicker.cxx
@@ -0,0 +1,541 @@
+/* -*- 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 "VistaFilePicker.hxx"
+
+#include "WinImplHelper.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/file.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <shlobj.h>
+
+namespace fpicker{
+namespace win32{
+namespace vista{
+
+VistaFilePicker::VistaFilePicker(bool bFolderPicker)
+ : TVistaFilePickerBase (m_aMutex )
+ , m_bInitialized (false )
+ , m_bFolderPicker (bFolderPicker )
+{
+}
+
+VistaFilePicker::~VistaFilePicker()
+{
+}
+
+void SAL_CALL VistaFilePicker::addFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener)
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_ADD_PICKER_LISTENER);
+ rRequest.setArgument(PROP_PICKER_LISTENER, xListener);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::removeFilePickerListener(const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener )
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_REMOVE_PICKER_LISTENER);
+ rRequest.setArgument(PROP_PICKER_LISTENER, xListener);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void VistaFilePicker::disposing(const css::lang::EventObject& /*aEvent*/)
+{
+}
+
+void SAL_CALL VistaFilePicker::setMultiSelectionMode(sal_Bool bMode)
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_MULTISELECTION_MODE);
+ rRequest.setArgument(PROP_MULTISELECTION_MODE, bMode);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::setTitle(const OUString& sTitle)
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_TITLE);
+ rRequest.setArgument(PROP_TITLE, sTitle);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::appendFilter(const OUString& sTitle ,
+ const OUString& sFilter)
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_APPEND_FILTER);
+ rRequest.setArgument(PROP_FILTER_TITLE, sTitle );
+ rRequest.setArgument(PROP_FILTER_VALUE, sFilter);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::setCurrentFilter(const OUString& sTitle)
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_CURRENT_FILTER);
+ rRequest.setArgument(PROP_FILTER_TITLE, sTitle);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+OUString SAL_CALL VistaFilePicker::getCurrentFilter()
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_GET_CURRENT_FILTER);
+
+ m_rDialog.doRequest(rRequest);
+
+ 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 )
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_APPEND_FILTERGROUP);
+ rRequest.setArgument(PROP_FILTER_GROUP, rFilters);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::setDefaultName(const OUString& sName )
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_DEFAULT_NAME);
+ rRequest.setArgument(PROP_FILENAME, sName);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::setDisplayDirectory(const OUString& sDirectory)
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_DIRECTORY);
+ rRequest.setArgument(PROP_DIRECTORY, sDirectory);
+
+ m_rDialog.doRequest(rRequest);
+}
+
+OUString SAL_CALL VistaFilePicker::getDisplayDirectory()
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_GET_DIRECTORY);
+ m_rDialog.doRequest(rRequest);
+ 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()
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_GET_SELECTED_FILES);
+
+ m_rDialog.doRequest(rRequest);
+
+ const css::uno::Sequence< OUString > lFiles = rRequest.getArgumentOrDefault(PROP_SELECTED_FILES, css::uno::Sequence< OUString >());
+ m_lLastFiles = lFiles;
+ return lFiles;
+}
+
+void VistaFilePicker::ensureInit()
+{
+ if ( !m_bInitialized )
+ {
+ if (m_bFolderPicker)
+ {
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_CREATE_FOLDER_PICKER);
+ m_rDialog.doRequest(rRequest);
+ m_bInitialized = true;
+ }
+ else
+ {
+ initialize( { css::uno::Any(css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE) });
+ }
+ }
+}
+
+::sal_Int16 SAL_CALL VistaFilePicker::execute()
+{
+ ensureInit();
+
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SHOW_DIALOG_MODAL);
+
+ // show a modal window
+ m_rDialog.doRequest(rRequest);
+
+ 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 )
+{
+ Request rRequest;
+ 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_rDialog.doRequest(rRequest);
+}
+
+css::uno::Any SAL_CALL VistaFilePicker::getValue(::sal_Int16 nControlId ,
+ ::sal_Int16 nControlAction)
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_GET_CONTROL_VALUE);
+ rRequest.setArgument(PROP_CONTROL_ID , nControlId );
+ rRequest.setArgument(PROP_CONTROL_ACTION, nControlAction);
+
+ m_rDialog.doRequest(rRequest);
+ return rRequest.getValue(PROP_CONTROL_VALUE);
+}
+
+void SAL_CALL VistaFilePicker::enableControl(::sal_Int16 nControlId,
+ sal_Bool bEnable )
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_ENABLE_CONTROL);
+ rRequest.setArgument(PROP_CONTROL_ID , nControlId);
+ rRequest.setArgument(PROP_CONTROL_ENABLE, bEnable );
+
+ m_rDialog.doRequest(rRequest);
+}
+
+void SAL_CALL VistaFilePicker::setLabel( ::sal_Int16 nControlId,
+ const OUString& sLabel )
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_SET_CONTROL_LABEL);
+ rRequest.setArgument(PROP_CONTROL_ID , nControlId);
+ rRequest.setArgument(PROP_CONTROL_LABEL, sLabel );
+
+ m_rDialog.doRequest(rRequest);
+}
+
+OUString SAL_CALL VistaFilePicker::getLabel(::sal_Int16 nControlId)
+{
+ Request rRequest;
+ rRequest.setRequest (VistaFilePickerImpl::E_GET_CONTROL_LABEL);
+ rRequest.setArgument(PROP_CONTROL_ID, nControlId);
+
+ m_rDialog.doRequest(rRequest);
+ 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;
+ }
+ Request rRequest;
+ if (bFileOpenDialog)
+ {
+ if (!m_bFolderPicker)
+ rRequest.setRequest(VistaFilePickerImpl::E_CREATE_OPEN_DIALOG);
+ else
+ rRequest.setRequest(VistaFilePickerImpl::E_CREATE_FOLDER_PICKER);
+ }
+ 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);
+ m_rDialog.doRequest(rRequest);
+
+ 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 "com.sun.star.ui.dialogs.Win32FolderPicker";
+ else
+ return "com.sun.star.ui.dialogs.Win32FilePicker";
+}
+
+sal_Bool SAL_CALL VistaFilePicker::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL VistaFilePicker::getSupportedServiceNames()
+{
+ return {
+ "com.sun.star.ui.dialogs.FilePicker",
+ "com.sun.star.ui.dialogs.SystemFilePicker",
+ "com.sun.star.ui.dialogs.SystemFolderPicker" };
+}
+
+} // namespace vista
+} // namespace win32
+} // namespace fpicker
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+fpicker_win32_FilePicker_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::fpicker::win32::vista::VistaFilePicker(false));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+fpicker_win32_FolderPicker_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::fpicker::win32::vista::VistaFilePicker(true));
+}
+
+
+/* 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..db4235a1d
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePicker.hxx
@@ -0,0 +1,224 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "requests.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( 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:
+
+ css::uno::Sequence< OUString > m_lLastFiles;
+
+ VistaFilePickerImpl m_rDialog;
+
+ bool m_bInitialized;
+ const bool m_bFolderPicker;
+};
+
+} // namespace vista
+} // namespace win32
+} // namespace fpicker
+
+/* 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..97c0c9fbd
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePickerEventHandler.cxx
@@ -0,0 +1,313 @@
+/* -*- 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 "VistaFilePickerEventHandler.hxx"
+
+#include "requests.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.clear();
+ }
+}
+
+const OUStringLiteral PROP_CONTROL_ID = u"control_id";
+const OUStringLiteral PROP_PICKER_LISTENER = u"picker_listener";
+
+namespace {
+
+void doRequest(Request& rRequest)
+{
+ 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 !
+ }
+}
+
+}
+
+void VistaFilePickerEventHandler::impl_sendEvent( EEventType eEventType,
+ ::sal_Int16 nControlID)
+{
+ comphelper::OInterfaceContainerHelper2* pContainer = m_lListener.getContainer( cppu::UnoType<css::ui::dialogs::XFilePickerListener>::get());
+ if ( ! pContainer)
+ return;
+
+ comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
+ while (pIterator.hasMoreElements())
+ {
+ try
+ {
+ css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener (
+ static_cast< css::ui::dialogs::XFilePickerListener* >(pIterator.next()));
+
+ Request rRequest;
+ rRequest.setRequest (eEventType);
+ rRequest.setArgument(PROP_PICKER_LISTENER, xListener);
+ if ( nControlID )
+ rRequest.setArgument(PROP_CONTROL_ID, nControlID);
+
+ doRequest(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..b27ef7326
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePickerEventHandler.hxx
@@ -0,0 +1,192 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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 <comphelper/multicontainer2.hxx>
+#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 .-))
+ */
+ comphelper::OMultiTypeInterfaceContainerHelper2 m_lListener;
+};
+
+} // namespace vista
+} // namespace win32
+} // namespace fpicker
+
+/* 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..741fdadb6
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePickerImpl.cxx
@@ -0,0 +1,1249 @@
+/* -*- 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 "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 <fpicker/fpsofficeResMgr.hxx>
+#include <osl/file.hxx>
+#include <rtl/process.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/string_view.hxx>
+#include <vcl/svapp.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, sal::systools::COMReference<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.
+
+
+const ::sal_Int16 INVALID_CONTROL_ID = -1;
+const ::sal_Int16 INVALID_CONTROL_ACTION = -1;
+
+// Guids used for IFileDialog::SetClientGuid
+const GUID CLIENTID_FILEDIALOG_SIMPLE = {0xB8628FD3, 0xA3F5, 0x4845, 0x9B, 0x62, 0xD5, 0x1E, 0xDF, 0x97, 0xC4, 0x83};
+const GUID CLIENTID_FILEDIALOG_OPTIONS = {0x93ED486F, 0x0D04, 0x4807, 0x8C, 0x44, 0xAC, 0x26, 0xCB, 0x6C, 0x5D, 0x36};
+const GUID CLIENTID_FILESAVE_PASSWORD = {0xC12D4F4C, 0x4D41, 0x4D4F, 0x97, 0xEF, 0x87, 0xF9, 0x8D, 0xB6, 0x1E, 0xA6};
+const GUID CLIENTID_FILESAVE_SELECTION = {0x5B2482B3, 0x0358, 0x4E09, 0xAA, 0x64, 0x2B, 0x76, 0xB2, 0xA0, 0xDD, 0xFE};
+const GUID CLIENTID_FILESAVE_TEMPLATE = {0x9996D877, 0x20D5, 0x424B, 0x9C, 0x2E, 0xD3, 0xB6, 0x31, 0xEC, 0xF7, 0xCE};
+const GUID CLIENTID_FILEOPEN_LINK_TEMPLATE = {0x32237796, 0x1509, 0x49D1, 0xBB, 0x7E, 0x63, 0xAD, 0x36, 0xAE, 0x86, 0x8C};
+const GUID CLIENTID_FILEOPEN_LINK_ANCHOR = {0xBE3188CB, 0x399A, 0x45AE, 0x8F, 0x78, 0x75, 0x17, 0xAF, 0x26, 0x81, 0xEA};
+const GUID CLIENTID_FILEOPEN_PLAY = {0x32CFB147, 0xF5AE, 0x4F90, 0xA1, 0xF1, 0x81, 0x20, 0x72, 0xBB, 0x2F, 0xC5};
+const GUID CLIENTID_FILEOPEN_LINK = {0x39AC4BAE, 0x7D2D, 0x46BC, 0xBE, 0x2E, 0xF8, 0x8C, 0xB5, 0x65, 0x5E, 0x6A};
+
+
+class TDialogImplBase
+{
+public:
+ TDialogImplBase(IFileDialog* iDialog)
+ : m_iDialog(iDialog)
+ {
+ }
+
+ virtual ~TDialogImplBase() = default;
+
+ TFileDialog getComPtr() { return m_iDialog; }
+ virtual sal::systools::COMReference<IShellItemArray> getResult(bool bInExecute)
+ {
+ sal::systools::COMReference<IShellItem> iItem;
+ if (m_iDialog.is())
+ {
+ if (bInExecute)
+ m_iDialog->GetCurrentSelection(&iItem);
+ else
+ m_iDialog->GetResult(&iItem);
+ }
+ void* iItems = nullptr;
+ if (iItem.is())
+ SHCreateShellItemArrayFromShellItem(iItem.get(), IID_IShellItemArray, &iItems);
+ return static_cast<IShellItemArray*>(iItems);
+ }
+
+private:
+ TFileDialog m_iDialog;
+};
+
+namespace {
+
+template <class ComPtrDialog, REFCLSID CLSID> class TDialogImpl : public TDialogImplBase
+{
+public:
+ TDialogImpl()
+ : TDialogImplBase(ComPtrDialog(CLSID).get())
+ {
+ }
+};
+
+class TOpenDialogImpl : public TDialogImpl<TFileOpenDialog, CLSID_FileOpenDialog>
+{
+public:
+ sal::systools::COMReference<IShellItemArray> getResult(bool bInExecute) override
+ {
+ sal::systools::COMReference<IShellItemArray> iItems;
+ TFileOpenDialog iDialog(getComPtr(), sal::systools::COM_QUERY_THROW);
+ bool bGetResult = false;
+ if (!iDialog.is())
+ bGetResult = true;
+ else if (FAILED(bInExecute ? iDialog->GetSelectedItems(&iItems) : iDialog->GetResults(&iItems)))
+ bGetResult = true;
+
+ if (bGetResult)
+ iItems = TDialogImplBase::getResult(bInExecute);
+
+ return iItems;
+ }
+};
+
+}
+
+using TSaveDialogImpl = TDialogImpl<TFileSaveDialog, CLSID_FileSaveDialog>;
+using TFolderPickerDialogImpl = TDialogImpl<TFileOpenDialog, CLSID_FileOpenDialog>;
+
+
+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( OUString(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(OUString(o3tl::toU(pStr)), sURL);
+ goto cleanup;
+ }
+ }
+ }
+
+ // Default fallback
+ hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &pStr);
+ if (SUCCEEDED(hr))
+ ::osl::FileBase::getFileURLFromSystemPath(OUString(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) ? OUString(o3tl::trim(sName.subView(0, idx))) : 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_lFilters ()
+ , m_iEventHandler(new VistaFilePickerEventHandler(this))
+ , m_bInExecute (false)
+ , m_bWasExecuted (false)
+ , m_hParentWindow(nullptr)
+ , m_sDirectory ()
+ , m_sFilename ()
+{
+}
+
+
+VistaFilePickerImpl::~VistaFilePickerImpl()
+{
+}
+
+
+void VistaFilePickerImpl::doRequest(Request& 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::impl_sta_addFilePickerListener(Request& rRequest)
+{
+ 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;
+
+ if (m_iEventHandler.is())
+ {
+ auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
+ pHandlerImpl->addFilePickerListener(xListener);
+ }
+}
+
+
+void VistaFilePickerImpl::impl_sta_removeFilePickerListener(Request& rRequest)
+{
+ 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;
+
+ if (m_iEventHandler.is())
+ {
+ auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
+ pHandlerImpl->removeFilePickerListener(xListener);
+ }
+}
+
+
+void VistaFilePickerImpl::impl_sta_appendFilter(Request& rRequest)
+{
+ const OUString sTitle = rRequest.getArgumentOrDefault(PROP_FILTER_TITLE, OUString());
+ const OUString sFilter = rRequest.getArgumentOrDefault(PROP_FILTER_VALUE, OUString());
+
+ m_lFilters.addFilter(sTitle, sFilter);
+}
+
+
+void VistaFilePickerImpl::impl_sta_appendFilterGroup(Request& rRequest)
+{
+ const css::uno::Sequence< css::beans::StringPair > aFilterGroup =
+ rRequest.getArgumentOrDefault(PROP_FILTER_GROUP, css::uno::Sequence< css::beans::StringPair >());
+
+ 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(Request& rRequest)
+{
+ const OUString sTitle = rRequest.getArgumentOrDefault(PROP_FILTER_TITLE, OUString());
+
+ m_lFilters.setCurrentFilter(sTitle);
+}
+
+
+void VistaFilePickerImpl::impl_sta_getCurrentFilter(Request& rRequest)
+{
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ 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;
+
+ 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);
+ }
+}
+
+
+template <class TDialogImplClass> void VistaFilePickerImpl::impl_sta_CreateDialog()
+{
+ m_pDialog = std::make_shared<TDialogImplClass>();
+}
+
+
+void VistaFilePickerImpl::impl_sta_InitDialog(Request& rRequest, DWORD nOrFlags)
+{
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ 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);
+
+ if (m_iEventHandler.is())
+ {
+ auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
+ pHandlerImpl->startListening(iDialog);
+ }
+}
+
+
+void VistaFilePickerImpl::impl_sta_CreateOpenDialog(Request& rRequest)
+{
+ impl_sta_CreateDialog<TOpenDialogImpl>();
+ impl_sta_InitDialog(rRequest, FOS_FILEMUSTEXIST | FOS_OVERWRITEPROMPT);
+}
+
+
+void VistaFilePickerImpl::impl_sta_CreateSaveDialog(Request& rRequest)
+{
+ impl_sta_CreateDialog<TSaveDialogImpl>();
+ impl_sta_InitDialog(rRequest, FOS_FILEMUSTEXIST | FOS_OVERWRITEPROMPT);
+}
+
+
+void VistaFilePickerImpl::impl_sta_CreateFolderPicker(Request& rRequest)
+{
+ impl_sta_CreateDialog<TFolderPickerDialogImpl>();
+ impl_sta_InitDialog(rRequest, FOS_PICKFOLDERS);
+}
+
+
+const ::sal_Int32 GROUP_VERSION = 1;
+const ::sal_Int32 GROUP_TEMPLATE = 2;
+const ::sal_Int32 GROUP_IMAGETEMPLATE = 3;
+const ::sal_Int32 GROUP_CHECKBOXES = 4;
+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();
+ if (iDialog.is())
+ iDialog->SetClientGuid ( aGUID );
+
+ TFileDialogCustomize iCustom = impl_getCustomizeInterface();
+ if (!iCustom.is())
+ return;
+
+ 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(Request& rRequest)
+{
+ const bool bMultiSelection = rRequest.getArgumentOrDefault(PROP_MULTISELECTION_MODE, true);
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ DWORD nFlags = 0;
+ iDialog->GetOptions(&nFlags);
+
+ if (bMultiSelection)
+ nFlags |= FOS_ALLOWMULTISELECT;
+ else
+ nFlags &= ~FOS_ALLOWMULTISELECT;
+
+ iDialog->SetOptions ( nFlags );
+}
+
+
+void VistaFilePickerImpl::impl_sta_SetTitle(Request& rRequest)
+{
+ OUString sTitle = rRequest.getArgumentOrDefault(PROP_TITLE, OUString());
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ iDialog->SetTitle(o3tl::toW(sTitle.getStr()));
+}
+
+
+void VistaFilePickerImpl::impl_sta_SetFileName(Request& rRequest)
+{
+ OUString sFileName = rRequest.getArgumentOrDefault(PROP_FILENAME, OUString());
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ iDialog->SetFileName(o3tl::toW(sFileName.getStr()));
+}
+
+
+void VistaFilePickerImpl::impl_sta_SetDirectory(Request& 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;
+ }
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ sal::systools::COMReference<IShellItem> pFolder;
+ if ( !createFolderItem(sDirectory, pFolder) )
+ return;
+
+ iDialog->SetFolder(pFolder.get());
+}
+
+OUString VistaFilePickerImpl::GetDirectory()
+{
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return OUString();
+ sal::systools::COMReference<IShellItem> pFolder;
+ HRESULT hResult = iDialog->GetFolder( &pFolder );
+ if ( FAILED(hResult) )
+ return OUString();
+ return lcl_getURLFromShellItem(pFolder.get());
+}
+
+void VistaFilePickerImpl::impl_sta_GetDirectory(Request& rRequest)
+{
+ const OUString sFolder = m_sDirectory.isEmpty() ? GetDirectory() : m_sDirectory;
+ if (!sFolder.isEmpty())
+ rRequest.setArgument(PROP_DIRECTORY, sFolder);
+}
+
+void VistaFilePickerImpl::impl_sta_SetDefaultName(Request& rRequest)
+{
+ OUString sFilename = rRequest.getArgumentOrDefault(PROP_FILENAME, OUString());
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ 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()
+{
+ 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();
+ if (!iDialog.is())
+ return;
+ TFileDialogCustomize iCustomize = impl_getCustomizeInterface();
+ if (!iCustomize.is())
+ return;
+
+ 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(Request& rRequest)
+{
+ if (m_pDialog == nullptr)
+ return;
+
+ // ask dialog for results
+ // we must react different if dialog is in execute or not .-(
+ sal::systools::COMReference<IShellItemArray> iItems = m_pDialog->getResult(m_bInExecute);
+ if (!iItems.is())
+ return;
+
+ // convert and pack results
+ std::vector< OUString > lFiles;
+ if (DWORD nCount; SUCCEEDED(iItems->GetCount(&nCount)))
+ {
+ for (DWORD i = 0; i < nCount; ++i)
+ {
+ if (sal::systools::COMReference<IShellItem> iItem;
+ SUCCEEDED(iItems->GetItemAt(i, &iItem)))
+ {
+ if (const OUString sURL = lcl_getURLFromShellItem(iItem.get()); !sURL.isEmpty())
+ lFiles.push_back(sURL);
+ }
+ }
+ }
+
+ rRequest.setArgument(PROP_SELECTED_FILES, comphelper::containerToSequence(lFiles));
+}
+
+
+void VistaFilePickerImpl::impl_sta_ShowDialogModal(Request& rRequest)
+{
+ impl_sta_setFiltersOnDialog();
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ // 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;
+
+ // 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())
+ {
+ sal::systools::COMReference<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();
+ if (!iCustom.is())
+ return;
+
+ 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.subView(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.get());
+ else
+ hResult = iDialog->AddPlace(pFolder.get(), FDAP_TOP);
+
+ FindClose( hFind );
+ }
+ else
+ iDialog->AddPlace(pFolder.get(), FDAP_TOP);
+ }
+ }
+
+ HRESULT hResult = E_FAIL;
+ try
+ {
+ // tdf#146007: Make sure we don't hold solar mutex: COM may need to forward
+ // the execution to the main thread, and holding solar mutex could deadlock
+ SolarMutexGuard g; // First acquire, to avoid releaser failure
+ SolarMutexReleaser r;
+ // show dialog and wait for user decision
+ hResult = iDialog->Show(m_hParentWindow ? m_hParentWindow
+ : choose_parent_window()); // parent window needed
+ }
+ catch(...)
+ {}
+
+ m_bInExecute = false;
+
+ if (m_iEventHandler.is())
+ {
+ auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
+ pHandlerImpl->stopListening();
+ }
+
+ if ( FAILED(hResult) )
+ return;
+
+ impl_sta_getSelectedFiles(rRequest);
+ rRequest.setArgument(PROP_DIALOG_SHOW_RESULT, true);
+}
+
+
+TFileDialog VistaFilePickerImpl::impl_getBaseDialogInterface()
+{
+ TFileDialog iDialog;
+
+ if (m_pDialog != nullptr)
+ iDialog = m_pDialog->getComPtr();
+
+ return iDialog;
+}
+
+
+TFileDialogCustomize VistaFilePickerImpl::impl_getCustomizeInterface()
+{
+ if (m_pDialog != nullptr)
+ return { m_pDialog->getComPtr(), sal::systools::COM_QUERY_THROW };
+
+ return {};
+}
+
+
+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(Request& 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(Request& 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(Request& 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(Request& /*rRequest*/)
+{
+}
+
+
+void VistaFilePickerImpl::impl_sta_EnableControl(Request& 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 (!iDialog.is())
+ return;
+
+ 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)
+{
+ const OUString sFilter = m_lFilters.getCurrentFilter ();
+ OUString sExt ;
+ if (!m_lFilters.getFilterByName(sFilter, sExt))
+ return;
+
+ TFileDialog iDialog = impl_getBaseDialogInterface();
+ if (!iDialog.is())
+ return;
+
+ 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..8e757c9c6
--- /dev/null
+++ b/fpicker/source/win32/VistaFilePickerImpl.hxx
@@ -0,0 +1,310 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "platform_vista.h"
+
+#include <shobjidl.h>
+
+#include "requests.hxx"
+#include "vistatypes.h"
+#include "FilterContainer.hxx"
+#include "VistaFilePickerEventHandler.hxx"
+#include "IVistaFilePickerInternalNotify.hxx"
+#include "resourceprovider.hxx"
+
+#include <cppuhelper/interfacecontainer.h>
+#include <osl/thread.hxx>
+#include <osl/conditn.hxx>
+#include <rtl/ustring.hxx>
+
+namespace fpicker{
+namespace win32{
+namespace vista{
+
+
+// types, const etcpp
+
+
+const ::sal_Int32 FEATURE_AUTOEXTENSION = 1;
+const ::sal_Int32 FEATURE_PASSWORD = 2;
+const ::sal_Int32 FEATURE_FILTEROPTIONS = 4;
+const ::sal_Int32 FEATURE_SELECTION = 8;
+const ::sal_Int32 FEATURE_TEMPLATE = 16;
+const ::sal_Int32 FEATURE_LINK = 32;
+const ::sal_Int32 FEATURE_PREVIEW = 64;
+const ::sal_Int32 FEATURE_IMAGETEMPLATE = 128;
+const ::sal_Int32 FEATURE_PLAY = 256;
+const ::sal_Int32 FEATURE_READONLY = 512;
+const ::sal_Int32 FEATURE_VERSION = 1024;
+const ::sal_Int32 FEATURE_GPGPASSWORD = 2048;
+const ::sal_Int32 FEATURE_IMAGEANCHOR = 4096;
+
+inline constexpr OUStringLiteral PROP_PICKER_LISTENER(u"picker_listener" ); // [XFilePickerListenert]
+inline constexpr OUStringLiteral PROP_DIALOG_SHOW_RESULT(u"dialog_show_result" ); // [sal_Bool] true=OK, false=CANCEL
+inline constexpr OUStringLiteral PROP_SELECTED_FILES(u"selected_files" ); // [seq< OUString >] contains all user selected files (can be empty!)
+inline constexpr OUStringLiteral PROP_MULTISELECTION_MODE(u"multiselection_mode"); // [sal_Bool] true=ON, false=OFF
+inline constexpr OUStringLiteral PROP_TITLE(u"title" ); // [OUString]
+inline constexpr OUStringLiteral PROP_FILENAME(u"filename" ); // [OUString]
+inline constexpr OUStringLiteral PROP_DIRECTORY(u"directory" ); // [OUString]
+inline constexpr OUStringLiteral PROP_FEATURES(u"features" ); // [sal_Int32]
+inline constexpr OUStringLiteral PROP_TEMPLATE_DESCR(u"templatedescription"); // [sal_Int32]
+inline constexpr OUStringLiteral PROP_FILTER_TITLE(u"filter_title" ); // [OUString]
+inline constexpr OUStringLiteral PROP_FILTER_VALUE(u"filter_value" ); // [OUString]
+inline constexpr OUStringLiteral PROP_FILTER_GROUP(u"filter-group" ); // [seq< css:beans::StringPair >] contains a group of filters
+
+inline constexpr OUStringLiteral PROP_CONTROL_ID(u"control_id" ); // [sal_Int16]
+inline constexpr OUStringLiteral PROP_CONTROL_ACTION(u"control_action" ); // [sal_Int16]
+inline constexpr OUStringLiteral PROP_CONTROL_VALUE(u"control_value" ); // [Any]
+inline constexpr OUStringLiteral PROP_CONTROL_LABEL(u"control_label" ); // [OUString]
+inline constexpr OUStringLiteral PROP_CONTROL_ENABLE(u"control_enable" ); // [sal_Bool] true=ON, false=OFF
+inline constexpr OUStringLiteral PROP_PARENT_WINDOW(u"ParentWindow"); //[css::awt::XWindow] preferred parent window
+inline constexpr OUStringLiteral STRING_SEPARATOR(u"------------------------------------------" );
+
+class TDialogImplBase;
+
+/** 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 on the main thread which is an STA thread !
+ */
+
+class VistaFilePickerImpl : 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();
+
+
+ // RequestHandler
+
+ void doRequest(Request& rRequest);
+
+
+ // 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(Request& rRequest);
+
+
+ /// implementation of request E_REMOVE_FILEPICKER_LISTENER
+ void impl_sta_removeFilePickerListener(Request& rRequest);
+
+
+ /// implementation of request E_APPEND_FILTER
+ void impl_sta_appendFilter(Request& rRequest);
+
+
+ /// implementation of request E_APPEND_FILTERGROUP
+ void impl_sta_appendFilterGroup(Request& rRequest);
+
+
+ /// implementation of request E_SET_CURRENT_FILTER
+ void impl_sta_setCurrentFilter(Request& rRequest);
+
+
+ /// implementation of request E_GET_CURRENT_FILTER
+ void impl_sta_getCurrentFilter(Request& rRequest);
+
+
+ /// implementation of request E_CREATE_OPEN_DIALOG
+ void impl_sta_CreateOpenDialog(Request& rRequest);
+
+
+ /// implementation of request E_CREATE_SAVE_DIALOG
+ void impl_sta_CreateSaveDialog(Request& rRequest);
+
+
+ /// implementation of request E_CREATE_FOLDER_PICKER
+ void impl_sta_CreateFolderPicker(Request& rRequest);
+
+
+ /// implementation of request E_SET_MULTISELECTION_MODE
+ void impl_sta_SetMultiSelectionMode(Request& rRequest);
+
+
+ /// implementation of request E_SET_TITLE
+ void impl_sta_SetTitle(Request& rRequest);
+
+
+ /// implementation of request E_SET_FILENAME
+ void impl_sta_SetFileName(Request& rRequest);
+
+
+ /// implementation of request E_SET_DIRECTORY
+ void impl_sta_SetDirectory(Request& rRequest);
+
+
+ /// implementation of request E_GET_DIRECTORY
+ void impl_sta_GetDirectory(Request& rRequest);
+
+
+ /// implementation of request E_SET_DEFAULT_NAME
+ void impl_sta_SetDefaultName(Request& rRequest);
+
+
+ /// implementation of request E_GET_SELECTED_FILES
+ void impl_sta_getSelectedFiles(Request& rRequest);
+
+
+ /// implementation of request E_SHOW_DIALOG_MODAL
+ void impl_sta_ShowDialogModal(Request& rRequest);
+
+
+ /// implementation of request E_SET_CONTROL_VALUE
+ void impl_sta_SetControlValue(Request& rRequest);
+
+
+ /// implementation of request E_GET_CONTROL_VALUE
+ void impl_sta_GetControlValue(Request& rRequest);
+
+
+ /// implementation of request E_SET_CONTROL_LABEL
+ void impl_sta_SetControlLabel(Request& rRequest);
+
+
+ /// implementation of request E_GET_CONTROL_LABEL
+ static void impl_sta_GetControlLabel(Request& rRequest);
+
+
+ /// implementation of request E_ENABLE_CONTROL
+ void impl_sta_EnableControl(Request& 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:
+ template <class TDialogImplClass> void impl_sta_CreateDialog();
+ void impl_sta_InitDialog(Request& rRequest, DWORD nOrFlags);
+
+
+ /// object representing a file dialog
+ std::shared_ptr<TDialogImplBase> m_pDialog;
+
+
+ /// @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
+
+/* 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..5d6e20d92
--- /dev/null
+++ b/fpicker/source/win32/WinImplHelper.cxx
@@ -0,0 +1,161 @@
+/* -*- 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 sal_Unicode TILDE_SIGN = L'~';
+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_SIGN ) > -1) || (aWinLabel.indexOf( AMPERSAND_SIGN ) > -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_SIGN ) > -1) || (aSOLabel.indexOf( AMPERSAND_SIGN ) > -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..9f7e16e94
--- /dev/null
+++ b/fpicker/source/win32/WinImplHelper.hxx
@@ -0,0 +1,49 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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);
+
+/* 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..3cc9c8029
--- /dev/null
+++ b/fpicker/source/win32/fps.component
@@ -0,0 +1,29 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.ui.dialogs.Win32FilePicker"
+ constructor="fpicker_win32_FilePicker_get_implementation">
+ <service name="com.sun.star.ui.dialogs.SystemFilePicker"/>
+ </implementation>
+ <implementation name="com.sun.star.ui.dialogs.Win32FolderPicker"
+ constructor="fpicker_win32_FolderPicker_get_implementation">
+ <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..ab3f7c52c
--- /dev/null
+++ b/fpicker/source/win32/platform_vista.h
@@ -0,0 +1,43 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/fpicker/source/win32/requests.hxx b/fpicker/source/win32/requests.hxx
new file mode 100644
index 000000000..a12f61ad8
--- /dev/null
+++ b/fpicker/source/win32/requests.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include <comphelper/sequenceashashmap.hxx>
+
+namespace fpicker
+{
+namespace win32
+{
+namespace vista
+{
+/** @todo document me
+ */
+class Request
+{
+ // interface
+
+public:
+ explicit Request()
+ : m_nRequest(-1)
+ , m_lArguments()
+ {
+ }
+
+ 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); }
+
+ // member
+
+private:
+ ::sal_Int32 m_nRequest;
+ ::comphelper::SequenceAsHashMap m_lArguments;
+};
+
+} // namespace vista
+} // namespace win32
+} // namespace fpicker
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/fpicker/source/win32/resourceprovider.cxx b/fpicker/source/win32/resourceprovider.cxx
new file mode 100644
index 000000000..3515e9432
--- /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 <fpicker/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;
+ TranslateId 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 TranslateId CtrlIdToResId( sal_Int32 aControlId )
+{
+ TranslateId pResId;
+
+ 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
+ TranslateId 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..09ae8339b
--- /dev/null
+++ b/fpicker/source/win32/resourceprovider.hxx
@@ -0,0 +1,35 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <sal/types.h>
+
+#include <rtl/ustring.hxx>
+
+namespace CResourceProvider
+{
+OUString getResString(sal_Int16 aId);
+};
+
+/* 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..c47f6411e
--- /dev/null
+++ b/fpicker/source/win32/shared.hxx
@@ -0,0 +1,29 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+const OUStringLiteral BACKSLASH(u"\\");
+const OUStringLiteral FILTER_SEPARATOR(u"------------------------------------------");
+const OUStringLiteral ALL_FILES_WILDCARD(u"*.*");
+const bool ALLOW_DUPLICATES = true;
+
+/* 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..a6a08faa5
--- /dev/null
+++ b/fpicker/source/win32/vistatypes.h
@@ -0,0 +1,43 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <shobjidl.h>
+#include <systools/win32/comtools.hxx>
+
+namespace fpicker{
+namespace win32{
+namespace vista{
+
+
+// types, const etcpp.
+
+
+typedef sal::systools::COMReference<IFileDialog> TFileDialog;
+typedef sal::systools::COMReference<IFileOpenDialog> TFileOpenDialog;
+typedef sal::systools::COMReference<IFileSaveDialog> TFileSaveDialog;
+typedef sal::systools::COMReference<IFileDialogEvents> TFileDialogEvents;
+typedef sal::systools::COMReference<IFileDialogCustomize> TFileDialogCustomize;
+
+} // namespace vista
+} // namespace win32
+} // namespace fpicker
+
+/* 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..899f208f1
--- /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;
+
+static const OUStringLiteral BMP_EXTENSION( u"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(
+ "com.sun.star.ui.dialogs.SystemFilePicker", 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
+
+