fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / uielement / recentfilesmenucontroller.cxx
blob1ea02d21dc63bac9401440435f576e8e3b1acf47
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <classes/resource.hrc>
21 #include <classes/fwkresid.hxx>
23 #include <cppuhelper/implbase1.hxx>
24 #include <cppuhelper/supportsservice.hxx>
25 #include <osl/file.hxx>
26 #include <osl/mutex.hxx>
27 #include <rtl/ref.hxx>
28 #include <svtools/popupmenucontrollerbase.hxx>
29 #include <tools/urlobj.hxx>
30 #include <unotools/historyoptions.hxx>
31 #include <vcl/menu.hxx>
32 #include <vcl/svapp.hxx>
34 using namespace css;
35 using namespace com::sun::star::uno;
36 using namespace com::sun::star::lang;
37 using namespace com::sun::star::frame;
38 using namespace com::sun::star::beans;
39 using namespace com::sun::star::util;
40 using namespace framework;
42 #define MAX_MENU_ITEMS 99
44 namespace {
46 static const char CMD_CLEAR_LIST[] = ".uno:ClearRecentFileList";
47 static const char CMD_PREFIX[] = "vnd.sun.star.popup:RecentFileList?entry=";
48 static const char MENU_SHORTCUT[] = "~N. ";
50 struct LoadRecentFile
52 util::URL aTargetURL;
53 uno::Sequence< beans::PropertyValue > aArgSeq;
54 uno::Reference< frame::XDispatch > xDispatch;
57 class RecentFilesMenuController : public svt::PopupMenuControllerBase
59 using svt::PopupMenuControllerBase::disposing;
61 public:
62 RecentFilesMenuController( const uno::Reference< uno::XComponentContext >& xContext );
63 virtual ~RecentFilesMenuController();
65 // XServiceInfo
66 virtual OUString SAL_CALL getImplementationName()
67 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
69 return OUString("com.sun.star.comp.framework.RecentFilesMenuController");
72 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
73 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
75 return cppu::supportsService(this, ServiceName);
78 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
79 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
81 css::uno::Sequence< OUString > aSeq(1);
82 aSeq[0] = "com.sun.star.frame.PopupMenuController";
83 return aSeq;
86 // XStatusListener
87 virtual void SAL_CALL statusChanged( const frame::FeatureStateEvent& Event ) throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
89 // XMenuListener
90 virtual void SAL_CALL itemSelected( const awt::MenuEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
91 virtual void SAL_CALL itemActivated( const awt::MenuEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
93 // XDispatchProvider
94 virtual uno::Reference< frame::XDispatch > SAL_CALL queryDispatch( const util::URL& aURL, const OUString& sTarget, sal_Int32 nFlags ) throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
96 // XDispatch
97 virtual void SAL_CALL dispatch( const util::URL& aURL, const uno::Sequence< beans::PropertyValue >& seqProperties ) throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
99 // XEventListener
100 virtual void SAL_CALL disposing( const com::sun::star::lang::EventObject& Source ) throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
102 DECL_STATIC_LINK( RecentFilesMenuController, ExecuteHdl_Impl, LoadRecentFile* );
104 private:
105 virtual void impl_setPopupMenu() SAL_OVERRIDE;
106 struct RecentFile
108 OUString aURL;
109 OUString aTitle;
112 void fillPopupMenu( com::sun::star::uno::Reference< com::sun::star::awt::XPopupMenu >& rPopupMenu );
113 void executeEntry( sal_Int32 nIndex );
115 std::vector< RecentFile > m_aRecentFilesItems;
116 bool m_bDisabled : 1;
119 RecentFilesMenuController::RecentFilesMenuController( const uno::Reference< uno::XComponentContext >& xContext ) :
120 svt::PopupMenuControllerBase( xContext ),
121 m_bDisabled( false )
125 RecentFilesMenuController::~RecentFilesMenuController()
129 // private function
130 void RecentFilesMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu )
132 VCLXPopupMenu* pPopupMenu = static_cast<VCLXPopupMenu *>(VCLXMenu::GetImplementation( rPopupMenu ));
133 PopupMenu* pVCLPopupMenu = 0;
135 SolarMutexGuard aSolarMutexGuard;
137 resetPopupMenu( rPopupMenu );
138 if ( pPopupMenu )
139 pVCLPopupMenu = static_cast<PopupMenu *>(pPopupMenu->GetMenu());
141 if ( pVCLPopupMenu )
143 Sequence< Sequence< PropertyValue > > aHistoryList = SvtHistoryOptions().GetList( ePICKLIST );
145 int nPickListMenuItems = ( aHistoryList.getLength() > MAX_MENU_ITEMS ) ? MAX_MENU_ITEMS : aHistoryList.getLength();
146 m_aRecentFilesItems.clear();
147 if (( nPickListMenuItems > 0 ) && !m_bDisabled )
149 for ( int i = 0; i < nPickListMenuItems; i++ )
151 Sequence< PropertyValue >& rPickListEntry = aHistoryList[i];
152 RecentFile aRecentFile;
154 for ( int j = 0; j < rPickListEntry.getLength(); j++ )
156 Any a = rPickListEntry[j].Value;
158 if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_URL )
159 a >>= aRecentFile.aURL;
160 else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_TITLE )
161 a >>= aRecentFile.aTitle;
164 m_aRecentFilesItems.push_back( aRecentFile );
168 if ( !m_aRecentFilesItems.empty() )
170 const sal_uInt32 nCount = m_aRecentFilesItems.size();
171 for ( sal_uInt32 i = 0; i < nCount; i++ )
174 OUStringBuffer aMenuShortCut;
175 if ( i <= 9 )
177 if ( i == 9 )
178 aMenuShortCut.append( "1~0. " );
179 else
181 aMenuShortCut.append( MENU_SHORTCUT );
182 aMenuShortCut[ 1 ] = sal_Unicode( i + '1' );
185 else
187 aMenuShortCut.append( sal_Int32( i + 1 ) );
188 aMenuShortCut.append( ". " );
191 OUStringBuffer aStrBuffer;
192 aStrBuffer.append( CMD_PREFIX );
193 aStrBuffer.append( sal_Int32( i ) );
194 OUString aURLString( aStrBuffer.makeStringAndClear() );
196 // Abbreviate URL
197 OUString aMenuTitle;
198 INetURLObject aURL( m_aRecentFilesItems[i].aURL );
199 OUString aTipHelpText( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
201 if ( aURL.GetProtocol() == INetProtocol::File )
203 // Do handle file URL differently: don't show the protocol, just the file name
204 aMenuTitle = aURL.GetLastName(INetURLObject::DECODE_WITH_CHARSET, RTL_TEXTENCODING_UTF8);
206 else
208 // In all other URLs show the protocol name before the file name
209 aMenuTitle = INetURLObject::GetSchemeName(aURL.GetProtocol()) + ": " + aURL.getName();
212 aMenuShortCut.append( aMenuTitle );
214 pVCLPopupMenu->InsertItem( sal_uInt16( i+1 ), aMenuShortCut.makeStringAndClear() );
215 pVCLPopupMenu->SetTipHelpText( sal_uInt16( i+1 ), aTipHelpText );
216 pVCLPopupMenu->SetItemCommand( sal_uInt16( i+1 ), aURLString );
219 pVCLPopupMenu->InsertSeparator();
220 // Clear List menu entry
221 pVCLPopupMenu->InsertItem( sal_uInt16( nCount + 1 ),
222 FWK_RESSTR(STR_CLEAR_RECENT_FILES) );
223 pVCLPopupMenu->SetItemCommand( sal_uInt16( nCount + 1 ),
224 OUString( CMD_CLEAR_LIST ) );
225 pVCLPopupMenu->SetHelpText( sal_uInt16( nCount + 1 ),
226 FWK_RESSTR(STR_CLEAR_RECENT_FILES_HELP) );
228 else
230 // No recent documents => insert "no document" string
231 pVCLPopupMenu->InsertItem( 1, FWK_RESSTR(STR_NODOCUMENT) );
232 // Do not disable it, otherwise the Toolbar controller and MenuButton
233 // will display SV_RESID_STRING_NOSELECTIONPOSSIBLE instead of STR_NODOCUMENT
234 pVCLPopupMenu->SetItemBits( 1, pVCLPopupMenu->GetItemBits( 1 ) | MenuItemBits::NOSELECT );
239 void RecentFilesMenuController::executeEntry( sal_Int32 nIndex )
241 Reference< XDispatch > xDispatch;
242 Reference< XDispatchProvider > xDispatchProvider;
243 css::util::URL aTargetURL;
244 Sequence< PropertyValue > aArgsList;
246 osl::ClearableMutexGuard aLock( m_aMutex );
247 xDispatchProvider = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
248 aLock.clear();
250 if (( nIndex >= 0 ) &&
251 ( nIndex < sal::static_int_cast<sal_Int32>( m_aRecentFilesItems.size() )))
253 const RecentFile& rRecentFile = m_aRecentFilesItems[ nIndex ];
255 aTargetURL.Complete = rRecentFile.aURL;
256 m_xURLTransformer->parseStrict( aTargetURL );
258 sal_Int32 nSize = 2;
259 aArgsList.realloc( nSize );
260 aArgsList[0].Name = "Referer";
261 aArgsList[0].Value = makeAny( OUString( "private:user" ) );
263 // documents in the picklist will never be opened as templates
264 aArgsList[1].Name = "AsTemplate";
265 aArgsList[1].Value = makeAny( sal_False );
267 if (!m_aModuleName.isEmpty())
269 // Type detection needs to know which app we are opening it from.
270 aArgsList.realloc(++nSize);
271 aArgsList[nSize-1].Name = "DocumentService";
272 aArgsList[nSize-1].Value <<= m_aModuleName;
275 xDispatch = xDispatchProvider->queryDispatch( aTargetURL, "_default", 0 );
278 if ( xDispatch.is() )
280 // Call dispatch asychronously as we can be destroyed while dispatch is
281 // executed. VCL is not able to survive this as it wants to call listeners
282 // after select!!!
283 LoadRecentFile* pLoadRecentFile = new LoadRecentFile;
284 pLoadRecentFile->xDispatch = xDispatch;
285 pLoadRecentFile->aTargetURL = aTargetURL;
286 pLoadRecentFile->aArgSeq = aArgsList;
288 Application::PostUserEvent( LINK(0, RecentFilesMenuController, ExecuteHdl_Impl), pLoadRecentFile );
292 // XEventListener
293 void SAL_CALL RecentFilesMenuController::disposing( const EventObject& ) throw ( RuntimeException, std::exception )
295 Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
297 osl::MutexGuard aLock( m_aMutex );
298 m_xFrame.clear();
299 m_xDispatch.clear();
301 if ( m_xPopupMenu.is() )
302 m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
303 m_xPopupMenu.clear();
306 // XStatusListener
307 void SAL_CALL RecentFilesMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException, std::exception )
309 osl::MutexGuard aLock( m_aMutex );
310 m_bDisabled = !Event.IsEnabled;
313 void SAL_CALL RecentFilesMenuController::itemSelected( const css::awt::MenuEvent& rEvent ) throw (RuntimeException, std::exception)
315 Reference< css::awt::XPopupMenu > xPopupMenu;
317 osl::ClearableMutexGuard aLock( m_aMutex );
318 xPopupMenu = m_xPopupMenu;
319 aLock.clear();
321 if ( xPopupMenu.is() )
323 const OUString aCommand( xPopupMenu->getCommand( rEvent.MenuId ) );
324 OSL_TRACE( "RecentFilesMenuController::itemSelected() - Command : %s",
325 OUStringToOString( aCommand, RTL_TEXTENCODING_UTF8 ).getStr() );
327 if ( aCommand == CMD_CLEAR_LIST )
329 SvtHistoryOptions().Clear( ePICKLIST );
330 dispatchCommand(
331 "vnd.org.libreoffice.recentdocs:ClearRecentFileList",
332 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >() );
334 else
335 executeEntry( rEvent.MenuId-1 );
339 void SAL_CALL RecentFilesMenuController::itemActivated( const css::awt::MenuEvent& ) throw (RuntimeException, std::exception)
341 osl::MutexGuard aLock( m_aMutex );
342 impl_setPopupMenu();
345 // XPopupMenuController
346 void RecentFilesMenuController::impl_setPopupMenu()
348 if ( m_xPopupMenu.is() )
349 fillPopupMenu( m_xPopupMenu );
352 // XDispatchProvider
353 Reference< XDispatch > SAL_CALL RecentFilesMenuController::queryDispatch(
354 const URL& aURL,
355 const OUString& /*sTarget*/,
356 sal_Int32 /*nFlags*/ )
357 throw( RuntimeException, std::exception )
359 osl::MutexGuard aLock( m_aMutex );
361 throwIfDisposed();
363 if ( aURL.Complete.startsWith( m_aBaseURL ) )
364 return Reference< XDispatch >( static_cast< OWeakObject* >( this ), UNO_QUERY );
365 else
366 return Reference< XDispatch >();
369 // XDispatch
370 void SAL_CALL RecentFilesMenuController::dispatch(
371 const URL& aURL,
372 const Sequence< PropertyValue >& /*seqProperties*/ )
373 throw( RuntimeException, std::exception )
375 osl::MutexGuard aLock( m_aMutex );
377 throwIfDisposed();
379 if ( aURL.Complete.startsWith( m_aBaseURL ) )
381 // Parse URL to retrieve entry argument and its value
382 sal_Int32 nQueryPart = aURL.Complete.indexOf( '?', m_aBaseURL.getLength() );
383 if ( nQueryPart > 0 )
385 const OUString aEntryArgStr( "entry=" );
386 sal_Int32 nEntryArg = aURL.Complete.indexOf( aEntryArgStr, nQueryPart );
387 sal_Int32 nEntryPos = nEntryArg + aEntryArgStr.getLength();
388 if (( nEntryArg > 0 ) && ( nEntryPos < aURL.Complete.getLength() ))
390 sal_Int32 nAddArgs = aURL.Complete.indexOf( '&', nEntryPos );
391 OUString aEntryArg;
393 if ( nAddArgs < 0 )
394 aEntryArg = aURL.Complete.copy( nEntryPos );
395 else
396 aEntryArg = aURL.Complete.copy( nEntryPos, nAddArgs-nEntryPos );
398 sal_Int32 nEntry = aEntryArg.toInt32();
399 executeEntry( nEntry );
405 IMPL_STATIC_LINK( RecentFilesMenuController, ExecuteHdl_Impl, LoadRecentFile*, pLoadRecentFile )
409 // Asynchronous execution as this can lead to our own destruction!
410 // Framework can recycle our current frame and the layout manager disposes all user interface
411 // elements if a component gets detached from its frame!
412 pLoadRecentFile->xDispatch->dispatch( pLoadRecentFile->aTargetURL, pLoadRecentFile->aArgSeq );
414 catch ( const Exception& )
418 delete pLoadRecentFile;
419 return 0;
424 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
425 com_sun_star_comp_framework_RecentFilesMenuController_get_implementation(
426 css::uno::XComponentContext *context,
427 css::uno::Sequence<css::uno::Any> const &)
429 return cppu::acquire(new RecentFilesMenuController(context));
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */