/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_fpicker.hxx" //------------------------------------------------------------------------ // includes //------------------------------------------------------------------------ #include "VistaFilePickerEventHandler.hxx" #include "asyncrequests.hxx" #include #include #include #include #include #include #include #include //#include //#include #include //------------------------------------------------------------------------ // namespace directives //------------------------------------------------------------------------ namespace css = ::com::sun::star; namespace fpicker{ namespace win32{ namespace vista{ //------------------------------------------------------------------------ // defines //------------------------------------------------------------------------ //----------------------------------------------------------------------------------------- VistaFilePickerEventHandler::VistaFilePickerEventHandler(IVistaFilePickerInternalNotify* pInternalNotify) : m_nRefCount (0 ) , m_nListenerHandle (0 ) , m_pDialog ( ) , m_lListener (m_aMutex) , m_pInternalNotify (pInternalNotify) { } //----------------------------------------------------------------------------------------- VistaFilePickerEventHandler::~VistaFilePickerEventHandler() { } //----------------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE VistaFilePickerEventHandler::QueryInterface(REFIID rIID , void** ppObject) { *ppObject=NULL; if ( rIID == IID_IUnknown ) *ppObject = (IUnknown*)(IFileDialogEvents*)this; if ( rIID == IID_IFileDialogEvents ) *ppObject = (IFileDialogEvents*)this; if ( rIID == IID_IFileDialogControlEvents ) *ppObject = (IFileDialogControlEvents*)this; if ( *ppObject != NULL ) { ((IUnknown*)*ppObject)->AddRef(); return S_OK; } return E_NOINTERFACE; } //----------------------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::AddRef() { return osl_incrementInterlockedCount(&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); return S_OK; } //----------------------------------------------------------------------------- ::rtl::OUString lcl_getURLFromShellItem2 (IShellItem* pItem) { LPOLESTR pStr = NULL; ::rtl::OUString sURL; SIGDN eConversion = SIGDN_FILESYSPATH; HRESULT hr = pItem->GetDisplayName ( eConversion, &pStr ); if ( FAILED(hr) ) { eConversion = SIGDN_URL; hr = pItem->GetDisplayName ( eConversion, &pStr ); if ( FAILED(hr) ) return ::rtl::OUString(); sURL = ::rtl::OUString(reinterpret_cast(pStr)); } else { ::osl::FileBase::getFileURLFromSystemPath( reinterpret_cast(pStr), sURL ); } CoTaskMemFree (pStr); return sURL; } //----------------------------------------------------------------------------------------- void lcl_updateVersionListDirectly(IFileDialog* pDialog) { static const ::rtl::OUString SERVICENAME_REVISIONPERSISTENCE = ::rtl::OUString::createFromAscii("com.sun.star.document.DocumentRevisionListPersistence"); static const ::sal_Int16 CONTROL_VERSIONLIST = css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION; TFileDialog iDialog (pDialog); TFileOpenDialog iOpen ; TFileDialogCustomize iCustomize; #ifdef __MINGW32__ iDialog->QueryInterface(IID_IFileOpenDialog, (void**)(&iOpen)); iDialog->QueryInterface(IID_IFileDialogCustomize, (void**)(&iCustomize)); #else iDialog.query(&iOpen ); iDialog.query(&iCustomize); #endif // make sure version list match to the current selection always ... // at least an empty version list will be better then the wrong one .-) iCustomize->RemoveAllControlItems(CONTROL_VERSIONLIST); HRESULT hResult = E_FAIL; ComPtr< IShellItemArray > iItems; ComPtr< IShellItem > iItem; if (iOpen.is()) { hResult = iOpen->GetSelectedItems(&iItems); if (FAILED(hResult)) return; DWORD nCount; hResult = iItems->GetCount(&nCount); if ( FAILED(hResult) ) return; // we can show one version list only within control if (nCount != 1) return; hResult = iItems->GetItemAt(0, &iItem); } else if (iDialog.is()) hResult = iDialog->GetCurrentSelection(&iItem); if ( FAILED(hResult) ) return; const ::rtl::OUString sURL = lcl_getURLFromShellItem2(iItem); if (sURL.getLength() < 1) return; /* INetURLObject aURL(sURL); if (aURL.GetProtocol() != INET_PROT_FILE) return; ::rtl::OUString sMain = aURL.GetMainURL(INetURLObject::NO_DECODE); if ( ! ::utl::UCBContentHelper::IsDocument(sURL)) return; */ try { css::uno::Reference< css::embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(sURL, css::embed::ElementModes::READ); if ( ! xStorage.is() ) return; css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); css::uno::Reference< css::document::XDocumentRevisionListPersistence > xReader (xSMGR->createInstance(SERVICENAME_REVISIONPERSISTENCE), css::uno::UNO_QUERY_THROW); css::uno::Sequence< css::util::RevisionTag > lVersions = xReader->load(xStorage); for (::sal_Int32 i=0; iAddControlItem(CONTROL_VERSIONLIST, i, reinterpret_cast(aTag.Identifier.getStr())); } iCustomize->SetSelectedControlItem(CONTROL_VERSIONLIST, 0); } catch(const css::uno::Exception&) {} } //----------------------------------------------------------------------------------------- STDMETHODIMP VistaFilePickerEventHandler::OnSelectionChange(IFileDialog* /*pDialog*/) { impl_sendEvent(E_FILE_SELECTION_CHANGED, 0); //lcl_updateVersionListDirectly(pDialog); 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( nIDCtl )); return S_OK; } //----------------------------------------------------------------------------------------- STDMETHODIMP VistaFilePickerEventHandler::OnButtonClicked(IFileDialogCustomize* /*pCustomize*/, DWORD nIDCtl ) { impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast( 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( nIDCtl)); return S_OK; } //----------------------------------------------------------------------------------------- STDMETHODIMP VistaFilePickerEventHandler::OnControlActivating(IFileDialogCustomize* /*pCustomize*/, DWORD nIDCtl ) { impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast( nIDCtl)); return S_OK; } //----------------------------------------------------------------------------------------- void SAL_CALL VistaFilePickerEventHandler::addFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) throw( css::uno::RuntimeException ) { m_lListener.addInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener); } //----------------------------------------------------------------------------------------- void SAL_CALL VistaFilePickerEventHandler::removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) throw( css::uno::RuntimeException ) { m_lListener.removeInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener); } //----------------------------------------------------------------------------------------- void VistaFilePickerEventHandler::startListening( const TFileDialog& pBroadcaster ) { static const sal_Bool STARTUP_SUSPENDED = sal_True; static const sal_Bool STARTUP_WORKING = sal_False; if (m_pDialog.is()) return; m_pDialog = pBroadcaster; m_pDialog->Advise(this, &m_nListenerHandle); } //----------------------------------------------------------------------------------------- void VistaFilePickerEventHandler::stopListening() { if (m_pDialog.is()) { m_pDialog->Unadvise(m_nListenerHandle); m_pDialog.release(); } } static const ::rtl::OUString PROP_CONTROL_ID = ::rtl::OUString::createFromAscii("control_id"); static const ::rtl::OUString PROP_PICKER_LISTENER = ::rtl::OUString::createFromAscii("picker_listener"); //----------------------------------------------------------------------------------------- class AsyncPickerEvents : public RequestHandler { public: AsyncPickerEvents() {} virtual ~AsyncPickerEvents() {} virtual void before() {} virtual void doRequest(const RequestRef& 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 ! } } virtual void after() {} }; //----------------------------------------------------------------------------------------- void VistaFilePickerEventHandler::impl_sendEvent( EEventType eEventType, ::sal_Int16 nControlID) { static AsyncRequests aNotify(RequestHandlerRef(new AsyncPickerEvents())); ::cppu::OInterfaceContainerHelper* pContainer = m_lListener.getContainer( ::getCppuType( ( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*) NULL ) ); if ( ! pContainer) return; ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); while (pIterator.hasMoreElements()) { try { css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener (pIterator.next(), css::uno::UNO_QUERY); RequestRef rRequest(new Request()); rRequest->setRequest (eEventType); rRequest->setArgument(PROP_PICKER_LISTENER, xListener); if ( nControlID ) rRequest->setArgument(PROP_CONTROL_ID, nControlID); aNotify.triggerRequestDirectly(rRequest); //aNotify.triggerRequestNonBlocked(rRequest); } catch(const css::uno::RuntimeException&) { pIterator.remove(); } } } } // namespace vista } // namespace win32 } // namespace fpicker