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 //-----------------------------------------------------------------------------------------
VistaFilePickerEventHandler(IVistaFilePickerInternalNotify * pInternalNotify)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 //-----------------------------------------------------------------------------------------
~VistaFilePickerEventHandler()73 VistaFilePickerEventHandler::~VistaFilePickerEventHandler()
74 {
75 }
76 
77 //-----------------------------------------------------------------------------------------
QueryInterface(REFIID rIID,void ** ppObject)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 //-----------------------------------------------------------------------------------------
AddRef()102 ULONG STDMETHODCALLTYPE VistaFilePickerEventHandler::AddRef()
103 {
104 	return osl_incrementInterlockedCount(&m_nRefCount);
105 }
106 
107 //-----------------------------------------------------------------------------------------
Release()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 //-----------------------------------------------------------------------------------------
OnFileOk(IFileDialog *)118 STDMETHODIMP VistaFilePickerEventHandler::OnFileOk(IFileDialog* /*pDialog*/)
119 {
120     return E_NOTIMPL;
121 }
122 
123 //-----------------------------------------------------------------------------------------
OnFolderChanging(IFileDialog *,IShellItem *)124 STDMETHODIMP VistaFilePickerEventHandler::OnFolderChanging(IFileDialog* /*pDialog*/,
125                                                            IShellItem*  /*pFolder*/)
126 {
127     return E_NOTIMPL;
128 }
129 
130 //-----------------------------------------------------------------------------------------
OnFolderChange(IFileDialog *)131 STDMETHODIMP VistaFilePickerEventHandler::OnFolderChange(IFileDialog* /*pDialog*/)
132 {
133     impl_sendEvent(E_DIRECTORY_CHANGED, 0);
134     return S_OK;
135 }
136 
137 //-----------------------------------------------------------------------------
lcl_getURLFromShellItem2(IShellItem * pItem)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 //-----------------------------------------------------------------------------------------
lcl_updateVersionListDirectly(IFileDialog * pDialog)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 //-----------------------------------------------------------------------------------------
OnSelectionChange(IFileDialog *)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 //-----------------------------------------------------------------------------------------
OnShareViolation(IFileDialog *,IShellItem *,FDE_SHAREVIOLATION_RESPONSE *)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 //-----------------------------------------------------------------------------------------
OnTypeChange(IFileDialog * pDialog)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 //-----------------------------------------------------------------------------------------
OnOverwrite(IFileDialog *,IShellItem *,FDE_OVERWRITE_RESPONSE *)283 STDMETHODIMP VistaFilePickerEventHandler::OnOverwrite(IFileDialog*            /*pDialog*/  ,
284                                                       IShellItem*             /*pItem*/    ,
285                                                       FDE_OVERWRITE_RESPONSE* /*pResponse*/)
286 {
287     return E_NOTIMPL;
288 }
289 
290 //-----------------------------------------------------------------------------------------
OnItemSelected(IFileDialogCustomize *,DWORD nIDCtl,DWORD)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 //-----------------------------------------------------------------------------------------
OnButtonClicked(IFileDialogCustomize *,DWORD nIDCtl)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 //-----------------------------------------------------------------------------------------
OnCheckButtonToggled(IFileDialogCustomize *,DWORD nIDCtl,BOOL bChecked)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 //-----------------------------------------------------------------------------------------
OnControlActivating(IFileDialogCustomize *,DWORD nIDCtl)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 //-----------------------------------------------------------------------------------------
addFilePickerListener(const css::uno::Reference<css::ui::dialogs::XFilePickerListener> & xListener)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 //-----------------------------------------------------------------------------------------
removeFilePickerListener(const css::uno::Reference<css::ui::dialogs::XFilePickerListener> & xListener)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 //-----------------------------------------------------------------------------------------
startListening(const TFileDialog & pBroadcaster)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 //-----------------------------------------------------------------------------------------
stopListening()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 
AsyncPickerEvents()377     AsyncPickerEvents()
378     {}
379 
~AsyncPickerEvents()380     virtual ~AsyncPickerEvents()
381     {}
382 
before()383     virtual void before()
384     {}
385 
doRequest(const RequestRef & rRequest)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 
after()424     virtual void after()
425     {}
426 };
427 
428 //-----------------------------------------------------------------------------------------
impl_sendEvent(EEventType eEventType,::sal_Int16 nControlID)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