1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_fpicker.hxx" 26 27 //------------------------------------------------------------------------ 28 // includes 29 //------------------------------------------------------------------------ 30 31 #include "VistaFilePickerEventHandler.hxx" 32 #include "asyncrequests.hxx" 33 34 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 35 #include <com/sun/star/embed/XStorage.hpp> 36 #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp> 37 #include <com/sun/star/util/RevisionTag.hpp> 38 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> 39 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> 40 41 #include <comphelper/processfactory.hxx> 42 #include <comphelper/storagehelper.hxx> 43 //#include <tools/urlobj.hxx> 44 //#include <unotools/ucbhelper.hxx> 45 46 #include <osl/file.hxx> 47 48 //------------------------------------------------------------------------ 49 // namespace directives 50 //------------------------------------------------------------------------ 51 52 namespace css = ::com::sun::star; 53 54 namespace fpicker{ 55 namespace win32{ 56 namespace vista{ 57 58 //------------------------------------------------------------------------ 59 // defines 60 //------------------------------------------------------------------------ 61 62 //----------------------------------------------------------------------------------------- 63 VistaFilePickerEventHandler::VistaFilePickerEventHandler(IVistaFilePickerInternalNotify* pInternalNotify) 64 : m_nRefCount (0 ) 65 , m_nListenerHandle (0 ) 66 , m_pDialog ( ) 67 , m_lListener (m_aMutex) 68 , m_pInternalNotify (pInternalNotify) 69 { 70 } 71 72 //----------------------------------------------------------------------------------------- 73 VistaFilePickerEventHandler::~VistaFilePickerEventHandler() 74 { 75 } 76 77 //----------------------------------------------------------------------------------------- 78 HRESULT STDMETHODCALLTYPE VistaFilePickerEventHandler::QueryInterface(REFIID rIID , 79 void** ppObject) 80 { 81 *ppObject=NULL; 82 83 if ( rIID == IID_IUnknown ) 84 *ppObject = (IUnknown*)(IFileDialogEvents*)this; 85 86 if ( rIID == IID_IFileDialogEvents ) 87 *ppObject = (IFileDialogEvents*)this; 88 89 if ( rIID == IID_IFileDialogControlEvents ) 90 *ppObject = (IFileDialogControlEvents*)this; 91 92 if ( *ppObject != NULL ) 93 { 94 ((IUnknown*)*ppObject)->AddRef(); 95 return S_OK; 96 } 97 98 return E_NOINTERFACE; 99 } 100 101 //----------------------------------------------------------------------------------------- 102 ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::AddRef() 103 { 104 return osl_incrementInterlockedCount(&m_nRefCount); 105 } 106 107 //----------------------------------------------------------------------------------------- 108 ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::Release() 109 { 110 ULONG nReturn = --m_nRefCount; 111 if ( m_nRefCount == 0 ) 112 delete this; 113 114 return nReturn; 115 } 116 117 //----------------------------------------------------------------------------------------- 118 STDMETHODIMP VistaFilePickerEventHandler::OnFileOk(IFileDialog* /*pDialog*/) 119 { 120 return E_NOTIMPL; 121 } 122 123 //----------------------------------------------------------------------------------------- 124 STDMETHODIMP VistaFilePickerEventHandler::OnFolderChanging(IFileDialog* /*pDialog*/, 125 IShellItem* /*pFolder*/) 126 { 127 return E_NOTIMPL; 128 } 129 130 //----------------------------------------------------------------------------------------- 131 STDMETHODIMP VistaFilePickerEventHandler::OnFolderChange(IFileDialog* /*pDialog*/) 132 { 133 impl_sendEvent(E_DIRECTORY_CHANGED, 0); 134 return S_OK; 135 } 136 137 //----------------------------------------------------------------------------- 138 ::rtl::OUString lcl_getURLFromShellItem2 (IShellItem* pItem) 139 { 140 LPOLESTR pStr = NULL; 141 ::rtl::OUString sURL; 142 143 SIGDN eConversion = SIGDN_FILESYSPATH; 144 HRESULT hr = pItem->GetDisplayName ( eConversion, &pStr ); 145 146 if ( FAILED(hr) ) 147 { 148 eConversion = SIGDN_URL; 149 hr = pItem->GetDisplayName ( eConversion, &pStr ); 150 151 if ( FAILED(hr) ) 152 return ::rtl::OUString(); 153 154 sURL = ::rtl::OUString(reinterpret_cast<sal_Unicode*>(pStr)); 155 } 156 else 157 { 158 ::osl::FileBase::getFileURLFromSystemPath( reinterpret_cast<sal_Unicode*>(pStr), sURL ); 159 } 160 161 CoTaskMemFree (pStr); 162 return sURL; 163 } 164 165 //----------------------------------------------------------------------------------------- 166 void lcl_updateVersionListDirectly(IFileDialog* pDialog) 167 { 168 static const ::rtl::OUString SERVICENAME_REVISIONPERSISTENCE = ::rtl::OUString::createFromAscii("com.sun.star.document.DocumentRevisionListPersistence"); 169 static const ::sal_Int16 CONTROL_VERSIONLIST = css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION; 170 171 TFileDialog iDialog (pDialog); 172 TFileOpenDialog iOpen ; 173 TFileDialogCustomize iCustomize; 174 175 #ifdef __MINGW32__ 176 iDialog->QueryInterface(IID_IFileOpenDialog, (void**)(&iOpen)); 177 iDialog->QueryInterface(IID_IFileDialogCustomize, (void**)(&iCustomize)); 178 #else 179 iDialog.query(&iOpen ); 180 iDialog.query(&iCustomize); 181 #endif 182 183 // make sure version list match to the current selection always ... 184 // at least an empty version list will be better then the wrong one .-) 185 iCustomize->RemoveAllControlItems(CONTROL_VERSIONLIST); 186 187 HRESULT hResult = E_FAIL; 188 ComPtr< IShellItemArray > iItems; 189 ComPtr< IShellItem > iItem; 190 191 if (iOpen.is()) 192 { 193 hResult = iOpen->GetSelectedItems(&iItems); 194 if (FAILED(hResult)) 195 return; 196 197 DWORD nCount; 198 hResult = iItems->GetCount(&nCount); 199 if ( FAILED(hResult) ) 200 return; 201 202 // we can show one version list only within control 203 if (nCount != 1) 204 return; 205 206 hResult = iItems->GetItemAt(0, &iItem); 207 } 208 else 209 if (iDialog.is()) 210 hResult = iDialog->GetCurrentSelection(&iItem); 211 212 if ( FAILED(hResult) ) 213 return; 214 215 const ::rtl::OUString sURL = lcl_getURLFromShellItem2(iItem); 216 if (sURL.getLength() < 1) 217 return; 218 /* 219 INetURLObject aURL(sURL); 220 if (aURL.GetProtocol() != INET_PROT_FILE) 221 return; 222 223 ::rtl::OUString sMain = aURL.GetMainURL(INetURLObject::NO_DECODE); 224 if ( ! ::utl::UCBContentHelper::IsDocument(sURL)) 225 return; 226 */ 227 try 228 { 229 css::uno::Reference< css::embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(sURL, css::embed::ElementModes::READ); 230 if ( ! xStorage.is() ) 231 return; 232 233 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); 234 css::uno::Reference< css::document::XDocumentRevisionListPersistence > xReader (xSMGR->createInstance(SERVICENAME_REVISIONPERSISTENCE), css::uno::UNO_QUERY_THROW); 235 css::uno::Sequence< css::util::RevisionTag > lVersions = xReader->load(xStorage); 236 237 for (::sal_Int32 i=0; i<lVersions.getLength(); ++i) 238 { 239 const css::util::RevisionTag& aTag = lVersions[i]; 240 iCustomize->AddControlItem(CONTROL_VERSIONLIST, i, reinterpret_cast<LPCTSTR>(aTag.Identifier.getStr())); 241 } 242 iCustomize->SetSelectedControlItem(CONTROL_VERSIONLIST, 0); 243 } 244 catch(const css::uno::Exception&) 245 {} 246 } 247 248 //----------------------------------------------------------------------------------------- 249 STDMETHODIMP VistaFilePickerEventHandler::OnSelectionChange(IFileDialog* /*pDialog*/) 250 { 251 impl_sendEvent(E_FILE_SELECTION_CHANGED, 0); 252 //lcl_updateVersionListDirectly(pDialog); 253 return S_OK; 254 } 255 256 //----------------------------------------------------------------------------------------- 257 STDMETHODIMP VistaFilePickerEventHandler::OnShareViolation(IFileDialog* /*pDialog*/ , 258 259 IShellItem* /*pItem*/ , 260 261 FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/) 262 { 263 impl_sendEvent(E_CONTROL_STATE_CHANGED, css::ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER); 264 return S_OK; 265 } 266 267 //----------------------------------------------------------------------------------------- 268 STDMETHODIMP VistaFilePickerEventHandler::OnTypeChange(IFileDialog* pDialog) 269 { 270 UINT nFileTypeIndex; 271 HRESULT hResult = pDialog->GetFileTypeIndex( &nFileTypeIndex ); 272 273 if ( hResult == S_OK ) 274 { 275 if ( m_pInternalNotify->onFileTypeChanged( nFileTypeIndex )) 276 impl_sendEvent(E_CONTROL_STATE_CHANGED, css::ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER); 277 } 278 279 return S_OK; 280 } 281 282 //----------------------------------------------------------------------------------------- 283 STDMETHODIMP VistaFilePickerEventHandler::OnOverwrite(IFileDialog* /*pDialog*/ , 284 IShellItem* /*pItem*/ , 285 FDE_OVERWRITE_RESPONSE* /*pResponse*/) 286 { 287 return E_NOTIMPL; 288 } 289 290 //----------------------------------------------------------------------------------------- 291 STDMETHODIMP VistaFilePickerEventHandler::OnItemSelected(IFileDialogCustomize* /*pCustomize*/, 292 293 DWORD nIDCtl , 294 295 DWORD /*nIDItem*/ ) 296 { 297 298 impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl )); 299 return S_OK; 300 } 301 302 //----------------------------------------------------------------------------------------- 303 STDMETHODIMP VistaFilePickerEventHandler::OnButtonClicked(IFileDialogCustomize* /*pCustomize*/, 304 DWORD nIDCtl ) 305 { 306 307 impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); 308 return S_OK; 309 } 310 311 //----------------------------------------------------------------------------------------- 312 STDMETHODIMP VistaFilePickerEventHandler::OnCheckButtonToggled(IFileDialogCustomize* /*pCustomize*/, 313 DWORD nIDCtl , 314 BOOL bChecked ) 315 { 316 if (nIDCtl == css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION) 317 m_pInternalNotify->onAutoExtensionChanged(bChecked); 318 319 impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); 320 321 return S_OK; 322 } 323 324 //----------------------------------------------------------------------------------------- 325 STDMETHODIMP VistaFilePickerEventHandler::OnControlActivating(IFileDialogCustomize* /*pCustomize*/, 326 DWORD nIDCtl ) 327 { 328 impl_sendEvent(E_CONTROL_STATE_CHANGED, static_cast<sal_Int16>( nIDCtl)); 329 return S_OK; 330 } 331 332 //----------------------------------------------------------------------------------------- 333 void SAL_CALL VistaFilePickerEventHandler::addFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) 334 throw( css::uno::RuntimeException ) 335 { 336 m_lListener.addInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener); 337 } 338 339 //----------------------------------------------------------------------------------------- 340 void SAL_CALL VistaFilePickerEventHandler::removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener ) 341 throw( css::uno::RuntimeException ) 342 { 343 m_lListener.removeInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener); 344 } 345 346 //----------------------------------------------------------------------------------------- 347 void VistaFilePickerEventHandler::startListening( const TFileDialog& pBroadcaster ) 348 { 349 static const sal_Bool STARTUP_SUSPENDED = sal_True; 350 static const sal_Bool STARTUP_WORKING = sal_False; 351 352 if (m_pDialog.is()) 353 return; 354 355 m_pDialog = pBroadcaster; 356 m_pDialog->Advise(this, &m_nListenerHandle); 357 } 358 359 //----------------------------------------------------------------------------------------- 360 void VistaFilePickerEventHandler::stopListening() 361 { 362 if (m_pDialog.is()) 363 { 364 m_pDialog->Unadvise(m_nListenerHandle); 365 m_pDialog.release(); 366 } 367 } 368 369 static const ::rtl::OUString PROP_CONTROL_ID = ::rtl::OUString::createFromAscii("control_id"); 370 static const ::rtl::OUString PROP_PICKER_LISTENER = ::rtl::OUString::createFromAscii("picker_listener"); 371 372 //----------------------------------------------------------------------------------------- 373 class AsyncPickerEvents : public RequestHandler 374 { 375 public: 376 377 AsyncPickerEvents() 378 {} 379 380 virtual ~AsyncPickerEvents() 381 {} 382 383 virtual void before() 384 {} 385 386 virtual void doRequest(const RequestRef& rRequest) 387 { 388 const ::sal_Int32 nEventID = rRequest->getRequest(); 389 const ::sal_Int16 nControlID = rRequest->getArgumentOrDefault(PROP_CONTROL_ID, (::sal_Int16)0); 390 const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest->getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >()); 391 392 if ( ! xListener.is()) 393 return; 394 395 css::ui::dialogs::FilePickerEvent aEvent; 396 aEvent.ElementId = nControlID; 397 398 switch (nEventID) 399 { 400 case VistaFilePickerEventHandler::E_FILE_SELECTION_CHANGED : 401 xListener->fileSelectionChanged(aEvent); 402 break; 403 404 case VistaFilePickerEventHandler::E_DIRECTORY_CHANGED : 405 xListener->directoryChanged(aEvent); 406 break; 407 408 case VistaFilePickerEventHandler::E_HELP_REQUESTED : 409 xListener->helpRequested(aEvent); 410 break; 411 412 case VistaFilePickerEventHandler::E_CONTROL_STATE_CHANGED : 413 xListener->controlStateChanged(aEvent); 414 break; 415 416 case VistaFilePickerEventHandler::E_DIALOG_SIZE_CHANGED : 417 xListener->dialogSizeChanged(); 418 break; 419 420 // no default here. Let compiler detect changes on enum set ! 421 } 422 } 423 424 virtual void after() 425 {} 426 }; 427 428 //----------------------------------------------------------------------------------------- 429 void VistaFilePickerEventHandler::impl_sendEvent( EEventType eEventType, 430 ::sal_Int16 nControlID) 431 { 432 static AsyncRequests aNotify(RequestHandlerRef(new AsyncPickerEvents())); 433 434 ::cppu::OInterfaceContainerHelper* pContainer = m_lListener.getContainer( ::getCppuType( ( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*) NULL ) ); 435 if ( ! pContainer) 436 return; 437 438 ::cppu::OInterfaceIteratorHelper pIterator(*pContainer); 439 while (pIterator.hasMoreElements()) 440 { 441 try 442 { 443 css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener (pIterator.next(), css::uno::UNO_QUERY); 444 445 RequestRef rRequest(new Request()); 446 rRequest->setRequest (eEventType); 447 rRequest->setArgument(PROP_PICKER_LISTENER, xListener); 448 if ( nControlID ) 449 rRequest->setArgument(PROP_CONTROL_ID, nControlID); 450 451 aNotify.triggerRequestDirectly(rRequest); 452 //aNotify.triggerRequestNonBlocked(rRequest); 453 } 454 catch(const css::uno::RuntimeException&) 455 { 456 pIterator.remove(); 457 } 458 } 459 } 460 461 } // namespace vista 462 } // namespace win32 463 } // namespace fpicker 464