merge the formfield patch from ooo-build
[ooovba.git] / framework / source / uielement / recentfilesmenucontroller.cxx
blob914acc33df8eda41d11c3ab60a4a2efe657c7ac5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: recentfilesmenucontroller.cxx,v $
10 * $Revision: 1.9.40.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 #include <uielement/recentfilesmenucontroller.hxx>
35 //_________________________________________________________________________________________________________________
36 // my own includes
37 //_________________________________________________________________________________________________________________
38 #include <threadhelp/resetableguard.hxx>
39 #include "services.h"
41 #ifndef __FRAMEWORK_CLASSES_RESOURCE_HRC_
42 #include <classes/resource.hrc>
43 #endif
44 #include <classes/fwkresid.hxx>
46 //_________________________________________________________________________________________________________________
47 // interface includes
48 //_________________________________________________________________________________________________________________
49 #include <com/sun/star/awt/XDevice.hpp>
50 #include <com/sun/star/beans/PropertyValue.hpp>
51 #include <com/sun/star/awt/MenuItemStyle.hpp>
52 #include <com/sun/star/util/XStringWidth.hpp>
53 #include <com/sun/star/lang/DisposedException.hpp>
54 //_________________________________________________________________________________________________________________
55 // includes of other projects
56 //_________________________________________________________________________________________________________________
58 #ifndef _VCL_MENU_HXX_
59 #include <vcl/menu.hxx>
60 #endif
61 #include <vcl/svapp.hxx>
62 #include <vcl/i18nhelp.hxx>
63 #include <tools/urlobj.hxx>
64 #include <rtl/ustrbuf.hxx>
65 #include <svtools/historyoptions.hxx>
66 #include <cppuhelper/implbase1.hxx>
67 #include <osl/file.hxx>
68 #ifdef WNT
69 #include <tools/prewin.h>
70 #include <tools/postwin.h>
71 #include <odma_lib.hxx>
72 #endif
73 //#include <tools/solar.hrc>
74 #include <dispatch/uieventloghelper.hxx>
76 //_________________________________________________________________________________________________________________
77 // Defines
78 //_________________________________________________________________________________________________________________
81 using namespace com::sun::star::uno;
82 using namespace com::sun::star::lang;
83 using namespace com::sun::star::frame;
84 using namespace com::sun::star::beans;
85 using namespace com::sun::star::util;
86 using namespace com::sun::star::container;
88 static const char SFX_REFERER_USER[] = "private:user";
90 namespace framework
93 class RecentFilesStringLength : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XStringWidth >
95 public:
96 RecentFilesStringLength() {}
97 virtual ~RecentFilesStringLength() {}
99 // XStringWidth
100 sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
101 throw (::com::sun::star::uno::RuntimeException)
103 return aString.getLength();
107 DEFINE_XSERVICEINFO_MULTISERVICE ( RecentFilesMenuController ,
108 OWeakObject ,
109 SERVICENAME_POPUPMENUCONTROLLER ,
110 IMPLEMENTATIONNAME_RECENTFILESMENUCONTROLLER
113 DEFINE_INIT_SERVICE ( RecentFilesMenuController, {} )
115 RecentFilesMenuController::RecentFilesMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
116 PopupMenuControllerBase( xServiceManager ),
117 m_bDisabled( sal_False )
121 RecentFilesMenuController::~RecentFilesMenuController()
125 // private function
126 void RecentFilesMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu )
128 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
129 PopupMenu* pVCLPopupMenu = 0;
131 vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
133 resetPopupMenu( rPopupMenu );
134 if ( pPopupMenu )
135 pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
137 if ( pVCLPopupMenu )
139 Sequence< Sequence< PropertyValue > > aHistoryList = SvtHistoryOptions().GetList( ePICKLIST );
140 Reference< XStringWidth > xStringLength( new RecentFilesStringLength );
142 int nPickListMenuItems = ( aHistoryList.getLength() > 99 ) ? 99 : aHistoryList.getLength();
144 // New vnd.sun.star.popup: command URL to support direct dispatches
145 const rtl::OUString aCmdPrefix( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:RecentFileList?entry=" ));
147 m_aRecentFilesItems.clear();
148 if (( nPickListMenuItems > 0 ) && !m_bDisabled )
150 for ( int i = 0; i < nPickListMenuItems; i++ )
152 Sequence< PropertyValue >& rPickListEntry = aHistoryList[i];
153 RecentFile aRecentFile;
155 for ( int j = 0; j < rPickListEntry.getLength(); j++ )
157 Any a = rPickListEntry[j].Value;
159 if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_URL )
160 a >>= aRecentFile.aURL;
161 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_FILTER )
162 a >>= aRecentFile.aFilter;
163 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_TITLE )
164 a >>= aRecentFile.aTitle;
165 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_PASSWORD )
166 a >>= aRecentFile.aPassword;
169 m_aRecentFilesItems.push_back( aRecentFile );
173 if ( !m_aRecentFilesItems.empty() )
175 URL aTargetURL;
177 const sal_uInt32 nCount = m_aRecentFilesItems.size();
178 for ( sal_uInt32 i = 0; i < nCount; i++ )
180 char menuShortCut[5] = "~n: ";
182 ::rtl::OUString aMenuShortCut;
183 if ( i <= 9 )
185 if ( i == 9 )
186 aMenuShortCut = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "1~0: " ));
187 else
189 menuShortCut[1] = (char)( '1' + i );
190 aMenuShortCut = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( menuShortCut ));
193 else
195 aMenuShortCut = rtl::OUString::valueOf((sal_Int32)( i + 1 ));
196 aMenuShortCut += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ": " ));
199 // Abbreviate URL
200 rtl::OUString aURLString( aCmdPrefix + rtl::OUString::valueOf( sal_Int32( i )));
201 rtl::OUString aTipHelpText;
202 rtl::OUString aMenuTitle;
203 INetURLObject aURL( m_aRecentFilesItems[i].aURL );
205 if ( aURL.GetProtocol() == INET_PROT_FILE )
207 // Do handle file URL differently => convert it to a system
208 // path and abbreviate it with a special function:
209 String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
211 ::rtl::OUString aSystemPath( aFileSystemPath );
212 ::rtl::OUString aCompactedSystemPath;
214 aTipHelpText = aSystemPath;
215 oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
216 if ( !nError )
217 aMenuTitle = String( aCompactedSystemPath );
218 else
219 aMenuTitle = aSystemPath;
221 #ifdef WNT
222 else if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_ODMA && ::odma::DMSsAvailable ())
224 String aShortTitle = m_aRecentFilesItems.at( i ).aTitle;
226 // This is against all rules for using
227 // proper abstraction layers and whatnot.
228 // But figuring out how to do it "right"
229 // would have taken the whole week.
230 // So just call the odma_lib functions...
231 // (odma_lib is a thin layer on
232 // top of the ODMA32 DLL)
234 static ODMHANDLE handle = NULL;
235 static sal_Bool beenhere = sal_False;
236 ODMSTATUS status;
238 if ( ! beenhere )
240 status = NODMRegisterApp( &handle, ODM_API_VERSION, "sodma", NULL, NULL );
241 beenhere = sal_True;
244 if ( handle != NULL )
246 rtl::OUString s = aURL.GetMainURL( INetURLObject::DECODE_WITH_CHARSET, RTL_TEXTENCODING_MS_1252 );
247 s = s.copy( strlen ( "vnd.sun.star.odma:/" ) );
248 char title[47];
249 status = NODMGetDocInfo( handle, rtl::OUStringToOString( s, RTL_TEXTENCODING_MS_1252 ).pData->buffer, ODM_NAME, title, sizeof ( title ) );
250 aShortTitle = String::CreateFromAscii( title );
252 aMenuTitle += aShortTitle;
253 aTipHelpText = aURLString;
255 #endif
256 else
258 // Use INetURLObject to abbreviate all other URLs
259 String aShortURL;
260 aShortURL = aURL.getAbbreviated( xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
261 aMenuTitle += aShortURL;
262 aTipHelpText = aURLString;
265 ::rtl::OUString aTitle( aMenuShortCut + aMenuTitle );
267 pVCLPopupMenu->InsertItem( USHORT( i+1 ), aTitle );
268 pVCLPopupMenu->SetTipHelpText( USHORT( i+1 ), aTipHelpText );
269 pVCLPopupMenu->SetItemCommand( USHORT( i+1 ), aURLString );
272 else
274 // No recent documents => insert "no document" string
275 String aNoDocumentStr = String( FwkResId( STR_NODOCUMENT ));
276 pVCLPopupMenu->InsertItem( 1, aNoDocumentStr );
277 pVCLPopupMenu->EnableItem( 1, FALSE );
282 void RecentFilesMenuController::executeEntry( sal_Int32 nIndex )
284 static int NUM_OF_PICKLIST_ARGS = 3;
286 Reference< css::awt::XPopupMenu > xPopupMenu;
287 Reference< XDispatch > xDispatch;
288 Reference< XDispatchProvider > xDispatchProvider;
289 Reference< XMultiServiceFactory > xServiceManager;
291 ResetableGuard aLock( m_aLock );
292 xPopupMenu = m_xPopupMenu;
293 xDispatchProvider = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
294 xServiceManager = m_xServiceManager;
295 aLock.unlock();
297 css::util::URL aTargetURL;
298 Sequence< PropertyValue > aArgsList;
300 if (( nIndex >= 0 ) &&
301 ( nIndex < sal::static_int_cast<sal_Int32>( m_aRecentFilesItems.size() )))
303 const RecentFile& rRecentFile = m_aRecentFilesItems[ nIndex ];
305 aTargetURL.Complete = rRecentFile.aURL;
306 m_xURLTransformer->parseStrict( aTargetURL );
308 aArgsList.realloc( NUM_OF_PICKLIST_ARGS );
309 aArgsList[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer" ));
310 aArgsList[0].Value = makeAny( ::rtl::OUString::createFromAscii( SFX_REFERER_USER ));
312 // documents in the picklist will never be opened as templates
313 aArgsList[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AsTemplate" ));
314 aArgsList[1].Value = makeAny( (sal_Bool) sal_False );
316 ::rtl::OUString aFilter( rRecentFile.aFilter );
317 sal_Int32 nPos = aFilter.indexOf( '|' );
318 if ( nPos >= 0 )
320 ::rtl::OUString aFilterOptions;
322 if ( nPos < ( aFilter.getLength() - 1 ) )
323 aFilterOptions = aFilter.copy( nPos+1 );
325 aArgsList[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterOptions" ));
326 aArgsList[2].Value <<= aFilterOptions;
328 aFilter = aFilter.copy( 0, nPos-1 );
329 aArgsList.realloc( ++NUM_OF_PICKLIST_ARGS );
332 aArgsList[NUM_OF_PICKLIST_ARGS-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ));
333 aArgsList[NUM_OF_PICKLIST_ARGS-1].Value <<= aFilter;
335 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString::createFromAscii("_default"), 0 );
338 if ( xDispatch.is() )
340 // Call dispatch asychronously as we can be destroyed while dispatch is
341 // executed. VCL is not able to survive this as it wants to call listeners
342 // after select!!!
343 LoadRecentFile* pLoadRecentFile = new LoadRecentFile;
344 pLoadRecentFile->xDispatch = xDispatch;
345 pLoadRecentFile->aTargetURL = aTargetURL;
346 pLoadRecentFile->aArgSeq = aArgsList;
347 if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
348 UiEventLogHelper(::rtl::OUString::createFromAscii("RecentFilesMenuController")).log(m_xServiceManager, m_xFrame, aTargetURL, aArgsList);
349 Application::PostUserEvent( STATIC_LINK(0, RecentFilesMenuController, ExecuteHdl_Impl), pLoadRecentFile );
353 // XEventListener
354 void SAL_CALL RecentFilesMenuController::disposing( const EventObject& ) throw ( RuntimeException )
356 Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
358 ResetableGuard aLock( m_aLock );
359 m_xFrame.clear();
360 m_xDispatch.clear();
361 m_xServiceManager.clear();
363 if ( m_xPopupMenu.is() )
364 m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
365 m_xPopupMenu.clear();
368 // XStatusListener
369 void SAL_CALL RecentFilesMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
371 ResetableGuard aLock( m_aLock );
372 m_bDisabled = !Event.IsEnabled;
375 void SAL_CALL RecentFilesMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException)
377 Reference< css::awt::XPopupMenu > xPopupMenu;
378 Reference< XDispatch > xDispatch;
379 Reference< XDispatchProvider > xDispatchProvider;
380 Reference< XMultiServiceFactory > xServiceManager;
382 ResetableGuard aLock( m_aLock );
383 xPopupMenu = m_xPopupMenu;
384 xDispatchProvider = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
385 xServiceManager = m_xServiceManager;
386 aLock.unlock();
388 css::util::URL aTargetURL;
389 Sequence< PropertyValue > aArgsList;
391 if ( xPopupMenu.is() && xDispatchProvider.is() )
393 VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu );
394 if ( pPopupMenu )
395 executeEntry( rEvent.MenuId-1 );
399 void SAL_CALL RecentFilesMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException)
401 ResetableGuard aLock( m_aLock );
402 impl_setPopupMenu();
405 // XPopupMenuController
406 void RecentFilesMenuController::impl_setPopupMenu()
408 if ( m_xPopupMenu.is() )
409 fillPopupMenu( m_xPopupMenu );
412 void SAL_CALL RecentFilesMenuController::updatePopupMenu() throw (RuntimeException)
414 ResetableGuard aLock( m_aLock );
416 if ( m_bDisposed )
417 throw DisposedException();
419 Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
420 Reference< XDispatch > xDispatch( m_xDispatch );
421 com::sun::star::util::URL aTargetURL;
422 aTargetURL.Complete = m_aCommandURL;
423 m_xURLTransformer->parseStrict( aTargetURL );
424 aLock.unlock();
426 // Add/remove status listener to get a status update once
427 if ( xDispatch.is() )
429 xDispatch->addStatusListener( xStatusListener, aTargetURL );
430 xDispatch->removeStatusListener( xStatusListener, aTargetURL );
434 // XDispatchProvider
435 Reference< XDispatch > SAL_CALL RecentFilesMenuController::queryDispatch(
436 const URL& aURL,
437 const ::rtl::OUString& /*sTarget*/,
438 sal_Int32 /*nFlags*/ )
439 throw( RuntimeException )
441 ResetableGuard aLock( m_aLock );
443 if ( m_bDisposed )
444 throw DisposedException();
446 if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 )
447 return Reference< XDispatch >( static_cast< OWeakObject* >( this ), UNO_QUERY );
448 else
449 return Reference< XDispatch >();
452 // XDispatch
453 void SAL_CALL RecentFilesMenuController::dispatch(
454 const URL& aURL,
455 const Sequence< PropertyValue >& /*seqProperties*/ )
456 throw( RuntimeException )
458 ResetableGuard aLock( m_aLock );
460 if ( m_bDisposed )
461 throw DisposedException();
463 if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 )
465 // Parse URL to retrieve entry argument and its value
466 sal_Int32 nQueryPart = aURL.Complete.indexOf( '?', m_aBaseURL.getLength() );
467 if ( nQueryPart > 0 )
469 const rtl::OUString aEntryArgStr( RTL_CONSTASCII_USTRINGPARAM( "entry=" ));
470 sal_Int32 nEntryArg = aURL.Complete.indexOf( aEntryArgStr, nQueryPart );
471 sal_Int32 nEntryPos = nEntryArg + aEntryArgStr.getLength();
472 if (( nEntryArg > 0 ) && ( nEntryPos < aURL.Complete.getLength() ))
474 sal_Int32 nAddArgs = aURL.Complete.indexOf( '&', nEntryPos );
475 rtl::OUString aEntryArg;
477 if ( nAddArgs < 0 )
478 aEntryArg = aURL.Complete.copy( nEntryPos );
479 else
480 aEntryArg = aURL.Complete.copy( nEntryPos, nAddArgs-nEntryPos );
482 sal_Int32 nEntry = aEntryArg.toInt32();
483 executeEntry( nEntry );
489 void SAL_CALL RecentFilesMenuController::addStatusListener(
490 const Reference< XStatusListener >& xControl,
491 const URL& aURL )
492 throw( RuntimeException )
494 ResetableGuard aLock( m_aLock );
496 if ( m_bDisposed )
497 throw DisposedException();
499 PopupMenuControllerBase::addStatusListener( xControl, aURL );
502 void SAL_CALL RecentFilesMenuController::removeStatusListener(
503 const Reference< XStatusListener >& xControl,
504 const URL& aURL )
505 throw( RuntimeException )
507 PopupMenuControllerBase::removeStatusListener( xControl, aURL );
510 IMPL_STATIC_LINK_NOINSTANCE( RecentFilesMenuController, ExecuteHdl_Impl, LoadRecentFile*, pLoadRecentFile )
514 // Asynchronous execution as this can lead to our own destruction!
515 // Framework can recycle our current frame and the layout manager disposes all user interface
516 // elements if a component gets detached from its frame!
517 pLoadRecentFile->xDispatch->dispatch( pLoadRecentFile->aTargetURL, pLoadRecentFile->aArgSeq );
519 catch ( Exception& )
523 delete pLoadRecentFile;
524 return 0;