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