LCOV - code coverage report
Current view: top level - libreoffice/framework/source/uielement - recentfilesmenucontroller.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1 209 0.5 %
Date: 2012-12-27 Functions: 1 28 3.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <uielement/recentfilesmenucontroller.hxx>
      21             : 
      22             : #include <threadhelp/resetableguard.hxx>
      23             : #include "services.h"
      24             : 
      25             : #include <classes/resource.hrc>
      26             : #include <classes/fwkresid.hxx>
      27             : 
      28             : #include <com/sun/star/awt/XDevice.hpp>
      29             : #include <com/sun/star/beans/PropertyValue.hpp>
      30             : #include <com/sun/star/awt/MenuItemStyle.hpp>
      31             : #include <com/sun/star/util/XStringWidth.hpp>
      32             : 
      33             : #include <vcl/menu.hxx>
      34             : #include <vcl/svapp.hxx>
      35             : #include <vcl/i18nhelp.hxx>
      36             : #include <tools/urlobj.hxx>
      37             : #include <rtl/ustrbuf.hxx>
      38             : #include <unotools/historyoptions.hxx>
      39             : #include <cppuhelper/implbase1.hxx>
      40             : #include <osl/file.hxx>
      41             : #ifdef WNT
      42             : #define GradientStyle_RECT BLA_GradientStyle_RECT
      43             : #include <windows.h>
      44             : #undef GradientStyle_RECT
      45             : #endif
      46             : #include <osl/mutex.hxx>
      47             : 
      48             : //_________________________________________________________________________________________________________________
      49             : //  Defines
      50             : //_________________________________________________________________________________________________________________
      51             : 
      52             : using namespace com::sun::star::uno;
      53             : using namespace com::sun::star::lang;
      54             : using namespace com::sun::star::frame;
      55             : using namespace com::sun::star::beans;
      56             : using namespace com::sun::star::util;
      57             : using namespace com::sun::star::container;
      58             : 
      59             : static const char SFX_REFERER_USER[] = "private:user";
      60             : 
      61             : namespace framework
      62             : {
      63             : 
      64             : class RecentFilesStringLength : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XStringWidth >
      65             : {
      66             :     public:
      67           0 :         RecentFilesStringLength() {}
      68           0 :         virtual ~RecentFilesStringLength() {}
      69             : 
      70             :         // XStringWidth
      71           0 :         sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
      72             :             throw (::com::sun::star::uno::RuntimeException)
      73             :         {
      74           0 :             return aString.getLength();
      75             :         }
      76             : };
      77             : 
      78          63 : DEFINE_XSERVICEINFO_MULTISERVICE        (   RecentFilesMenuController                   ,
      79             :                                             OWeakObject                                 ,
      80             :                                             SERVICENAME_POPUPMENUCONTROLLER             ,
      81             :                                             IMPLEMENTATIONNAME_RECENTFILESMENUCONTROLLER
      82             :                                         )
      83             : 
      84           0 : DEFINE_INIT_SERVICE                     (   RecentFilesMenuController, {} )
      85             : 
      86           0 : RecentFilesMenuController::RecentFilesMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
      87             :     svt::PopupMenuControllerBase( xServiceManager ),
      88           0 :     m_bDisabled( sal_False )
      89             : {
      90           0 : }
      91             : 
      92           0 : RecentFilesMenuController::~RecentFilesMenuController()
      93             : {
      94           0 : }
      95             : 
      96             : // private function
      97           0 : void RecentFilesMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu )
      98             : {
      99           0 :     VCLXPopupMenu*                                     pPopupMenu        = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
     100           0 :     PopupMenu*                                         pVCLPopupMenu     = 0;
     101             : 
     102           0 :     SolarMutexGuard aSolarMutexGuard;
     103             : 
     104           0 :     resetPopupMenu( rPopupMenu );
     105           0 :     if ( pPopupMenu )
     106           0 :         pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
     107             : 
     108           0 :     if ( pVCLPopupMenu )
     109             :     {
     110           0 :         Sequence< Sequence< PropertyValue > > aHistoryList = SvtHistoryOptions().GetList( ePICKLIST );
     111           0 :         Reference< XStringWidth > xStringLength( new RecentFilesStringLength );
     112             : 
     113           0 :         int nPickListMenuItems = ( aHistoryList.getLength() > 99 ) ? 99 : aHistoryList.getLength();
     114             : 
     115             :         // New vnd.sun.star.popup: command URL to support direct dispatches
     116           0 :         const rtl::OUString aCmdPrefix( "vnd.sun.star.popup:RecentFileList?entry=" );
     117             : 
     118           0 :         m_aRecentFilesItems.clear();
     119           0 :         if (( nPickListMenuItems > 0 ) && !m_bDisabled )
     120             :         {
     121           0 :             for ( int i = 0; i < nPickListMenuItems; i++ )
     122             :             {
     123           0 :                 Sequence< PropertyValue >& rPickListEntry = aHistoryList[i];
     124           0 :                 RecentFile aRecentFile;
     125             : 
     126           0 :                 for ( int j = 0; j < rPickListEntry.getLength(); j++ )
     127             :                 {
     128           0 :                     Any a = rPickListEntry[j].Value;
     129             : 
     130           0 :                     if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_URL )
     131           0 :                         a >>= aRecentFile.aURL;
     132           0 :                     else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_TITLE )
     133           0 :                         a >>= aRecentFile.aTitle;
     134           0 :                     else if ( rPickListEntry[j].Name == HISTORY_PROPERTYNAME_PASSWORD )
     135           0 :                         a >>= aRecentFile.aPassword;
     136           0 :                 }
     137             : 
     138           0 :                 m_aRecentFilesItems.push_back( aRecentFile );
     139           0 :             }
     140             :         }
     141             : 
     142           0 :         if ( !m_aRecentFilesItems.empty() )
     143             :         {
     144           0 :             URL aTargetURL;
     145             : 
     146           0 :             const sal_uInt32 nCount = m_aRecentFilesItems.size();
     147           0 :             for ( sal_uInt32 i = 0; i < nCount; i++ )
     148             :             {
     149           0 :                 char menuShortCut[5] = "~n: ";
     150             : 
     151           0 :                 ::rtl::OUString aMenuShortCut;
     152           0 :                 if ( i <= 9 )
     153             :                 {
     154           0 :                     if ( i == 9 )
     155           0 :                         aMenuShortCut = rtl::OUString( "1~0: " );
     156             :                     else
     157             :                     {
     158           0 :                         menuShortCut[1] = (char)( '1' + i );
     159           0 :                         aMenuShortCut = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(menuShortCut) );
     160             :                     }
     161             :                 }
     162             :                 else
     163             :                 {
     164           0 :                     aMenuShortCut = rtl::OUString::valueOf((sal_Int32)( i + 1 ));
     165           0 :                     aMenuShortCut += rtl::OUString( ": " );
     166             :                 }
     167             : 
     168             :                 // Abbreviate URL
     169           0 :                 rtl::OUString   aURLString( aCmdPrefix + rtl::OUString::valueOf( sal_Int32( i )));
     170           0 :                 rtl::OUString   aTipHelpText;
     171           0 :                 rtl::OUString   aMenuTitle;
     172           0 :                 INetURLObject   aURL( m_aRecentFilesItems[i].aURL );
     173             : 
     174           0 :                 if ( aURL.GetProtocol() == INET_PROT_FILE )
     175             :                 {
     176             :                     // Do handle file URL differently => convert it to a system
     177             :                     // path and abbreviate it with a special function:
     178           0 :                     String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
     179             : 
     180           0 :                     ::rtl::OUString aSystemPath( aFileSystemPath );
     181           0 :                     ::rtl::OUString aCompactedSystemPath;
     182             : 
     183           0 :                     aTipHelpText = aSystemPath;
     184           0 :                     oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
     185           0 :                     if ( !nError )
     186           0 :                         aMenuTitle = String( aCompactedSystemPath );
     187             :                     else
     188           0 :                         aMenuTitle = aSystemPath;
     189             :                 }
     190             :                 else
     191             :                 {
     192             :                     // Use INetURLObject to abbreviate all other URLs
     193           0 :                     String  aShortURL;
     194           0 :                     aShortURL = aURL.getAbbreviated( xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
     195           0 :                     aMenuTitle += aShortURL;
     196           0 :                     aTipHelpText = aURLString;
     197             :                 }
     198             : 
     199           0 :                 ::rtl::OUString aTitle( aMenuShortCut + aMenuTitle );
     200             : 
     201           0 :                 pVCLPopupMenu->InsertItem( sal_uInt16( i+1 ), aTitle );
     202           0 :                 pVCLPopupMenu->SetTipHelpText( sal_uInt16( i+1 ), aTipHelpText );
     203           0 :                 pVCLPopupMenu->SetItemCommand( sal_uInt16( i+1 ), aURLString );
     204           0 :             }
     205             :         }
     206             :         else
     207             :         {
     208             :             // No recent documents => insert "no document" string
     209           0 :             String aNoDocumentStr = String( FwkResId( STR_NODOCUMENT ));
     210           0 :             pVCLPopupMenu->InsertItem( 1, aNoDocumentStr );
     211           0 :             pVCLPopupMenu->EnableItem( 1, sal_False );
     212           0 :         }
     213           0 :     }
     214           0 : }
     215             : 
     216           0 : void RecentFilesMenuController::executeEntry( sal_Int32 nIndex )
     217             : {
     218           0 :     Reference< css::awt::XPopupMenu > xPopupMenu;
     219           0 :     Reference< XDispatch >            xDispatch;
     220           0 :     Reference< XDispatchProvider >    xDispatchProvider;
     221           0 :     Reference< XMultiServiceFactory > xServiceManager;
     222             : 
     223           0 :     osl::ClearableMutexGuard aLock( m_aMutex );
     224           0 :     xPopupMenu          = m_xPopupMenu;
     225           0 :     xDispatchProvider   = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
     226           0 :     xServiceManager     = m_xServiceManager;
     227           0 :     aLock.clear();
     228             : 
     229           0 :     css::util::URL            aTargetURL;
     230           0 :     Sequence< PropertyValue > aArgsList;
     231             : 
     232           0 :     if (( nIndex >= 0 ) &&
     233           0 :         ( nIndex < sal::static_int_cast<sal_Int32>( m_aRecentFilesItems.size() )))
     234             :     {
     235           0 :         const RecentFile& rRecentFile = m_aRecentFilesItems[ nIndex ];
     236             : 
     237           0 :         aTargetURL.Complete = rRecentFile.aURL;
     238           0 :         m_xURLTransformer->parseStrict( aTargetURL );
     239             : 
     240           0 :         sal_Int32 nSize = 2;
     241           0 :         aArgsList.realloc(nSize);
     242           0 :         aArgsList[0].Name = ::rtl::OUString( "Referer" );
     243           0 :         aArgsList[0].Value = makeAny( ::rtl::OUString(SFX_REFERER_USER ));
     244             : 
     245             :         // documents in the picklist will never be opened as templates
     246           0 :         aArgsList[1].Name = ::rtl::OUString( "AsTemplate" );
     247           0 :         aArgsList[1].Value = makeAny( (sal_Bool) sal_False );
     248             : 
     249           0 :         if (!m_aModuleName.isEmpty())
     250             :         {
     251             :             // Type detection needs to know which app we are opening it from.
     252           0 :             aArgsList.realloc(++nSize);
     253           0 :             aArgsList[nSize-1].Name = "DocumentService";
     254           0 :             aArgsList[nSize-1].Value <<= m_aModuleName;
     255             :         }
     256             : 
     257           0 :         xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString("_default"), 0 );
     258             :     }
     259             : 
     260           0 :     if ( xDispatch.is() )
     261             :     {
     262             :         // Call dispatch asychronously as we can be destroyed while dispatch is
     263             :         // executed. VCL is not able to survive this as it wants to call listeners
     264             :         // after select!!!
     265           0 :         LoadRecentFile* pLoadRecentFile = new LoadRecentFile;
     266           0 :         pLoadRecentFile->xDispatch  = xDispatch;
     267           0 :         pLoadRecentFile->aTargetURL = aTargetURL;
     268           0 :         pLoadRecentFile->aArgSeq    = aArgsList;
     269           0 :         Application::PostUserEvent( STATIC_LINK(0, RecentFilesMenuController, ExecuteHdl_Impl), pLoadRecentFile );
     270           0 :     }
     271           0 : }
     272             : 
     273             : // XEventListener
     274           0 : void SAL_CALL RecentFilesMenuController::disposing( const EventObject& ) throw ( RuntimeException )
     275             : {
     276           0 :     Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
     277             : 
     278           0 :     osl::MutexGuard aLock( m_aMutex );
     279           0 :     m_xFrame.clear();
     280           0 :     m_xDispatch.clear();
     281           0 :     m_xServiceManager.clear();
     282             : 
     283           0 :     if ( m_xPopupMenu.is() )
     284           0 :         m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
     285           0 :     m_xPopupMenu.clear();
     286           0 : }
     287             : 
     288             : // XStatusListener
     289           0 : void SAL_CALL RecentFilesMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
     290             : {
     291           0 :     osl::MutexGuard aLock( m_aMutex );
     292           0 :     m_bDisabled = !Event.IsEnabled;
     293           0 : }
     294             : 
     295           0 : void SAL_CALL RecentFilesMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException)
     296             : {
     297           0 :     Reference< css::awt::XPopupMenu > xPopupMenu;
     298           0 :     Reference< XDispatch >            xDispatch;
     299           0 :     Reference< XDispatchProvider >    xDispatchProvider;
     300           0 :     Reference< XMultiServiceFactory > xServiceManager;
     301             : 
     302           0 :     osl::ClearableMutexGuard aLock( m_aMutex );
     303           0 :     xPopupMenu          = m_xPopupMenu;
     304           0 :     xDispatchProvider   = Reference< XDispatchProvider >( m_xFrame, UNO_QUERY );
     305           0 :     xServiceManager     = m_xServiceManager;
     306           0 :     aLock.clear();
     307             : 
     308           0 :     css::util::URL aTargetURL;
     309           0 :     Sequence< PropertyValue > aArgsList;
     310             : 
     311           0 :     if ( xPopupMenu.is() && xDispatchProvider.is() )
     312             :     {
     313           0 :         VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu );
     314           0 :         if ( pPopupMenu )
     315           0 :             executeEntry( rEvent.MenuId-1 );
     316           0 :     }
     317           0 : }
     318             : 
     319           0 : void SAL_CALL RecentFilesMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException)
     320             : {
     321           0 :     osl::MutexGuard aLock( m_aMutex );
     322           0 :     impl_setPopupMenu();
     323           0 : }
     324             : 
     325             : // XPopupMenuController
     326           0 : void RecentFilesMenuController::impl_setPopupMenu()
     327             : {
     328           0 :     if ( m_xPopupMenu.is() )
     329           0 :         fillPopupMenu( m_xPopupMenu );
     330           0 : }
     331             : 
     332           0 : void SAL_CALL RecentFilesMenuController::updatePopupMenu() throw (RuntimeException)
     333             : {
     334           0 :     osl::ClearableMutexGuard aLock( m_aMutex );
     335             : 
     336           0 :     throwIfDisposed();
     337             : 
     338           0 :     Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY );
     339           0 :     Reference< XDispatch > xDispatch( m_xDispatch );
     340           0 :     com::sun::star::util::URL aTargetURL;
     341           0 :     aTargetURL.Complete = m_aCommandURL;
     342           0 :     m_xURLTransformer->parseStrict( aTargetURL );
     343           0 :     aLock.clear();
     344             : 
     345             :     // Add/remove status listener to get a status update once
     346           0 :     if ( xDispatch.is() )
     347             :     {
     348           0 :         xDispatch->addStatusListener( xStatusListener, aTargetURL );
     349           0 :         xDispatch->removeStatusListener( xStatusListener, aTargetURL );
     350           0 :     }
     351           0 : }
     352             : 
     353             : // XDispatchProvider
     354           0 : Reference< XDispatch > SAL_CALL RecentFilesMenuController::queryDispatch(
     355             :     const URL& aURL,
     356             :     const ::rtl::OUString& /*sTarget*/,
     357             :     sal_Int32 /*nFlags*/ )
     358             : throw( RuntimeException )
     359             : {
     360           0 :     osl::MutexGuard aLock( m_aMutex );
     361             : 
     362           0 :     throwIfDisposed();
     363             : 
     364           0 :     if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 )
     365           0 :         return Reference< XDispatch >( static_cast< OWeakObject* >( this ), UNO_QUERY );
     366             :     else
     367           0 :         return Reference< XDispatch >();
     368             : }
     369             : 
     370             : // XDispatch
     371           0 : void SAL_CALL RecentFilesMenuController::dispatch(
     372             :     const URL& aURL,
     373             :     const Sequence< PropertyValue >& /*seqProperties*/ )
     374             : throw( RuntimeException )
     375             : {
     376           0 :     osl::MutexGuard aLock( m_aMutex );
     377             : 
     378           0 :     throwIfDisposed();
     379             : 
     380           0 :     if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 )
     381             :     {
     382             :         // Parse URL to retrieve entry argument and its value
     383           0 :         sal_Int32 nQueryPart = aURL.Complete.indexOf( '?', m_aBaseURL.getLength() );
     384           0 :         if ( nQueryPart > 0 )
     385             :         {
     386           0 :             const rtl::OUString aEntryArgStr( "entry=" );
     387           0 :             sal_Int32 nEntryArg = aURL.Complete.indexOf( aEntryArgStr, nQueryPart );
     388           0 :             sal_Int32 nEntryPos = nEntryArg + aEntryArgStr.getLength();
     389           0 :             if (( nEntryArg > 0 ) && ( nEntryPos < aURL.Complete.getLength() ))
     390             :             {
     391           0 :                 sal_Int32 nAddArgs = aURL.Complete.indexOf( '&', nEntryPos );
     392           0 :                 rtl::OUString aEntryArg;
     393             : 
     394           0 :                 if ( nAddArgs < 0 )
     395           0 :                     aEntryArg = aURL.Complete.copy( nEntryPos );
     396             :                 else
     397           0 :                     aEntryArg = aURL.Complete.copy( nEntryPos, nAddArgs-nEntryPos );
     398             : 
     399           0 :                 sal_Int32 nEntry = aEntryArg.toInt32();
     400           0 :                 executeEntry( nEntry );
     401           0 :             }
     402             :         }
     403           0 :     }
     404           0 : }
     405             : 
     406           0 : void SAL_CALL RecentFilesMenuController::addStatusListener(
     407             :     const Reference< XStatusListener >& xControl,
     408             :     const URL& aURL )
     409             : throw( RuntimeException )
     410             : {
     411           0 :     osl::MutexGuard aLock( m_aMutex );
     412             : 
     413           0 :     throwIfDisposed();
     414             : 
     415           0 :     svt::PopupMenuControllerBase::addStatusListener( xControl, aURL );
     416           0 : }
     417             : 
     418           0 : void SAL_CALL RecentFilesMenuController::removeStatusListener(
     419             :     const Reference< XStatusListener >& xControl,
     420             :     const URL& aURL )
     421             : throw( RuntimeException )
     422             : {
     423           0 :     svt::PopupMenuControllerBase::removeStatusListener( xControl, aURL );
     424           0 : }
     425             : 
     426           0 : IMPL_STATIC_LINK_NOINSTANCE( RecentFilesMenuController, ExecuteHdl_Impl, LoadRecentFile*, pLoadRecentFile )
     427             : {
     428             :     try
     429             :     {
     430             :         // Asynchronous execution as this can lead to our own destruction!
     431             :         // Framework can recycle our current frame and the layout manager disposes all user interface
     432             :         // elements if a component gets detached from its frame!
     433           0 :         pLoadRecentFile->xDispatch->dispatch( pLoadRecentFile->aTargetURL, pLoadRecentFile->aArgSeq );
     434             :     }
     435           0 :     catch ( const Exception& )
     436             :     {
     437             :     }
     438             : 
     439           0 :     delete pLoadRecentFile;
     440           0 :     return 0;
     441             : }
     442             : 
     443             : }
     444             : 
     445             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10