xref: /trunk/main/fpicker/source/win32/filepicker/VistaFilePickerEventHandler.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956) !
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 {
335     m_lListener.addInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener);
336 }
337 
338 //-----------------------------------------------------------------------------------------
removeFilePickerListener(const css::uno::Reference<css::ui::dialogs::XFilePickerListener> & xListener)339 void SAL_CALL VistaFilePickerEventHandler::removeFilePickerListener( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >& xListener )
340 {
341     m_lListener.removeInterface(::getCppuType( (const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*)NULL ), xListener);
342 }
343 
344 //-----------------------------------------------------------------------------------------
startListening(const TFileDialog & pBroadcaster)345 void VistaFilePickerEventHandler::startListening( const TFileDialog& pBroadcaster )
346 {
347     static const sal_Bool STARTUP_SUSPENDED = sal_True;
348     static const sal_Bool STARTUP_WORKING   = sal_False;
349 
350     if (m_pDialog.is())
351         return;
352 
353     m_pDialog = pBroadcaster;
354     m_pDialog->Advise(this, &m_nListenerHandle);
355 }
356 
357 //-----------------------------------------------------------------------------------------
stopListening()358 void VistaFilePickerEventHandler::stopListening()
359 {
360     if (m_pDialog.is())
361     {
362         m_pDialog->Unadvise(m_nListenerHandle);
363         m_pDialog.release();
364     }
365 }
366 
367 static const ::rtl::OUString PROP_CONTROL_ID      = ::rtl::OUString::createFromAscii("control_id");
368 static const ::rtl::OUString PROP_PICKER_LISTENER = ::rtl::OUString::createFromAscii("picker_listener");
369 
370 //-----------------------------------------------------------------------------------------
371 class AsyncPickerEvents : public RequestHandler
372 {
373 public:
374 
AsyncPickerEvents()375     AsyncPickerEvents()
376     {}
377 
~AsyncPickerEvents()378     virtual ~AsyncPickerEvents()
379     {}
380 
before()381     virtual void before()
382     {}
383 
doRequest(const RequestRef & rRequest)384     virtual void doRequest(const RequestRef& rRequest)
385     {
386         const ::sal_Int32 nEventID   = rRequest->getRequest();
387         const ::sal_Int16 nControlID = rRequest->getArgumentOrDefault(PROP_CONTROL_ID, (::sal_Int16)0);
388         const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest->getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >());
389 
390         if ( ! xListener.is())
391             return;
392 
393         css::ui::dialogs::FilePickerEvent aEvent;
394         aEvent.ElementId = nControlID;
395 
396         switch (nEventID)
397         {
398             case VistaFilePickerEventHandler::E_FILE_SELECTION_CHANGED :
399                     xListener->fileSelectionChanged(aEvent);
400                     break;
401 
402             case VistaFilePickerEventHandler::E_DIRECTORY_CHANGED :
403                     xListener->directoryChanged(aEvent);
404                     break;
405 
406             case VistaFilePickerEventHandler::E_HELP_REQUESTED :
407                     xListener->helpRequested(aEvent);
408                     break;
409 
410             case VistaFilePickerEventHandler::E_CONTROL_STATE_CHANGED :
411                     xListener->controlStateChanged(aEvent);
412                     break;
413 
414             case VistaFilePickerEventHandler::E_DIALOG_SIZE_CHANGED :
415                     xListener->dialogSizeChanged();
416                     break;
417 
418             // no default here. Let compiler detect changes on enum set !
419         }
420     }
421 
after()422     virtual void after()
423     {}
424 };
425 
426 //-----------------------------------------------------------------------------------------
impl_sendEvent(EEventType eEventType,::sal_Int16 nControlID)427 void VistaFilePickerEventHandler::impl_sendEvent(  EEventType eEventType,
428                                                  ::sal_Int16  nControlID)
429 {
430     static AsyncRequests aNotify(RequestHandlerRef(new AsyncPickerEvents()));
431 
432     ::cppu::OInterfaceContainerHelper* pContainer = m_lListener.getContainer( ::getCppuType( ( const css::uno::Reference< css::ui::dialogs::XFilePickerListener >*) NULL ) );
433     if ( ! pContainer)
434         return;
435 
436     ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
437     while (pIterator.hasMoreElements())
438     {
439         try
440         {
441             css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener (pIterator.next(), css::uno::UNO_QUERY);
442 
443             RequestRef rRequest(new Request());
444             rRequest->setRequest (eEventType);
445             rRequest->setArgument(PROP_PICKER_LISTENER, xListener);
446             if ( nControlID )
447                 rRequest->setArgument(PROP_CONTROL_ID, nControlID);
448 
449             aNotify.triggerRequestDirectly(rRequest);
450             //aNotify.triggerRequestNonBlocked(rRequest);
451         }
452         catch(const css::uno::RuntimeException&)
453         {
454             pIterator.remove();
455         }
456     }
457 }
458 
459 } // namespace vista
460 } // namespace win32
461 } // namespace fpicker
462