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