LCOV - code coverage report
Current view: top level - libreoffice/framework/source/fwe/classes - addonmenu.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 13 187 7.0 %
Date: 2012-12-27 Functions: 2 18 11.1 %
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 "framework/addonmenu.hxx"
      21             : #include "framework/addonsoptions.hxx"
      22             : #include <general.h>
      23             : #include <macros/debug/assertion.hxx>
      24             : #include <framework/imageproducer.hxx>
      25             : #include <framework/menuconfiguration.hxx>
      26             : 
      27             : #include <com/sun/star/uno/Reference.hxx>
      28             : #include <com/sun/star/util/URL.hpp>
      29             : #include <com/sun/star/util/XURLTransformer.hpp>
      30             : #include <com/sun/star/lang/XServiceInfo.hpp>
      31             : 
      32             : #include <tools/config.hxx>
      33             : #include <vcl/svapp.hxx>
      34             : #include <svtools/menuoptions.hxx>
      35             : #include <svl/solar.hrc>
      36             : 
      37             : using namespace ::com::sun::star::uno;
      38             : using namespace ::com::sun::star::lang;
      39             : using namespace ::com::sun::star::frame;
      40             : using namespace ::com::sun::star::beans;
      41             : 
      42             : // Please look at sfx2/inc/sfxsids.hrc the values are defined there. Due to build dependencies
      43             : // we cannot include the header file.
      44             : const sal_uInt16 SID_HELPMENU            = (SID_SFX_START + 410);
      45             : 
      46             : namespace framework
      47             : {
      48             : 
      49           0 : AddonMenu::AddonMenu( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame ) :
      50           0 :     m_xFrame( rFrame )
      51             : {
      52           0 : }
      53             : 
      54           0 : AddonMenu::~AddonMenu()
      55             : {
      56           0 :     for ( sal_uInt16 i = 0; i < GetItemCount(); i++ )
      57             :     {
      58           0 :         if ( GetItemType( i ) != MENUITEM_SEPARATOR )
      59             :         {
      60             :             // delete user attributes created with new!
      61           0 :             sal_uInt16 nId = GetItemId( i );
      62           0 :             MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
      63           0 :             delete pUserAttributes;
      64           0 :             delete GetPopupMenu( nId );
      65             :         }
      66             :     }
      67           0 : }
      68             : 
      69             : // ------------------------------------------------------------------------
      70             : 
      71             : // ------------------------------------------------------------------------
      72             : // Check if command URL string has the unique prefix to identify addon popup menus
      73           0 : sal_Bool AddonPopupMenu::IsCommandURLPrefix( const ::rtl::OUString& aCmdURL )
      74             : {
      75           0 :     const char aPrefixCharBuf[] = ADDONSPOPUPMENU_URL_PREFIX_STR;
      76             : 
      77           0 :     return aCmdURL.matchAsciiL( aPrefixCharBuf, sizeof( aPrefixCharBuf )-1, 0 );
      78             : }
      79             : 
      80           0 : AddonPopupMenu::AddonPopupMenu( const com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& rFrame ) :
      81           0 :     AddonMenu( rFrame )
      82             : {
      83           0 : }
      84             : 
      85           0 : AddonPopupMenu::~AddonPopupMenu()
      86             : {
      87           0 : }
      88             : 
      89             : // ------------------------------------------------------------------------
      90             : 
      91           0 : static Reference< XModel > GetModelFromFrame( const Reference< XFrame >& rFrame )
      92             : {
      93             :     // Query for the model to get check the context information
      94           0 :     Reference< XModel > xModel;
      95           0 :     if ( rFrame.is() )
      96             :     {
      97           0 :         Reference< XController > xController( rFrame->getController(), UNO_QUERY );
      98           0 :         if ( xController.is() )
      99           0 :             xModel = xController->getModel();
     100             :     }
     101             : 
     102           0 :     return xModel;
     103             : }
     104             : 
     105             : // ------------------------------------------------------------------------
     106             : 
     107           0 : sal_Bool AddonMenuManager::HasAddonMenuElements()
     108             : {
     109           0 :     return AddonsOptions().HasAddonsMenu();
     110             : }
     111             : 
     112             : // Factory method to create different Add-On menu types
     113           0 : PopupMenu* AddonMenuManager::CreatePopupMenuType( MenuType eMenuType, const Reference< XFrame >& rFrame )
     114             : {
     115           0 :     if ( eMenuType == ADDON_MENU )
     116           0 :         return new AddonMenu( rFrame );
     117           0 :     else if ( eMenuType == ADDON_POPUPMENU )
     118           0 :         return new AddonPopupMenu( rFrame );
     119             :     else
     120           0 :         return NULL;
     121             : }
     122             : 
     123             : // Create the Add-Ons menu
     124           0 : AddonMenu* AddonMenuManager::CreateAddonMenu( const Reference< XFrame >& rFrame )
     125             : {
     126           0 :     AddonsOptions aOptions;
     127           0 :     AddonMenu*  pAddonMenu      = NULL;
     128           0 :     sal_uInt16      nUniqueMenuId   = ADDONMENU_ITEMID_START;
     129             : 
     130           0 :     const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aOptions.GetAddonsMenu();
     131           0 :     if ( rAddonMenuEntries.getLength() > 0 )
     132             :     {
     133           0 :         pAddonMenu = (AddonMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_MENU, rFrame );
     134           0 :         Reference< XModel > xModel = GetModelFromFrame( rFrame );
     135           0 :         AddonMenuManager::BuildMenu( pAddonMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, rAddonMenuEntries, rFrame, xModel );
     136             : 
     137             :         // Don't return an empty Add-On menu
     138           0 :         if ( pAddonMenu->GetItemCount() == 0 )
     139             :         {
     140           0 :             delete pAddonMenu;
     141           0 :             pAddonMenu = NULL;
     142           0 :         }
     143             :     }
     144             : 
     145           0 :     return pAddonMenu;
     146             : }
     147             : 
     148             : // Returns the next insert position from nPos.
     149           0 : sal_uInt16 AddonMenuManager::GetNextPos( sal_uInt16 nPos )
     150             : {
     151           0 :     return ( nPos == MENU_APPEND ) ? MENU_APPEND : ( nPos+1 );
     152             : }
     153             : 
     154             : 
     155         236 : static sal_uInt16 FindMenuId( Menu* pMenu, const String aCommand )
     156             : {
     157         236 :     sal_uInt16 nPos = 0;
     158         236 :     String aCmd;
     159         236 :     for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
     160             :     {
     161           0 :         sal_uInt16 nId = pMenu->GetItemId( nPos );
     162           0 :         aCmd = pMenu->GetItemCommand( nId );
     163           0 :         if ( aCmd == aCommand )
     164           0 :             return nId;
     165             :     }
     166             : 
     167         236 :     return USHRT_MAX;
     168             : }
     169             : 
     170             : 
     171             : // Merge the Add-Ons help menu items into the given menu bar at a defined pos
     172         236 : void AddonMenuManager::MergeAddonHelpMenu( const Reference< XFrame >& rFrame, MenuBar* pMergeMenuBar )
     173             : {
     174         236 :     if ( pMergeMenuBar )
     175             :     {
     176         236 :         PopupMenu* pHelpMenu = pMergeMenuBar->GetPopupMenu( SID_HELPMENU );
     177         236 :         if ( !pHelpMenu )
     178             :         {
     179         236 :             sal_uInt16 nId = FindMenuId(pMergeMenuBar, rtl::OUString(".uno:HelpMenu"));
     180         236 :             if ( nId != USHRT_MAX )
     181           0 :                 pHelpMenu = pMergeMenuBar->GetPopupMenu( nId );
     182             :         }
     183             : 
     184         236 :         if ( pHelpMenu )
     185             :         {
     186             :             // Add-Ons help menu items should be inserted after the "registration" menu item
     187           0 :             sal_uInt16 nItemCount       = pHelpMenu->GetItemCount();
     188           0 :             sal_uInt16 nInsSepAfterPos  = MENU_APPEND;
     189           0 :             sal_uInt16 nUniqueMenuId    = ADDONMENU_ITEMID_START;
     190           0 :             AddonsOptions aOptions;
     191             : 
     192             :             // try to detect the about menu item with the command URL
     193           0 :             sal_uInt16 nId = FindMenuId(pHelpMenu, rtl::OUString(".uno:About"));
     194           0 :             sal_uInt16 nInsPos = pHelpMenu->GetItemPos( nId );
     195             : 
     196           0 :             Sequence< Sequence< PropertyValue > > aAddonSubMenu;
     197           0 :             const Sequence< Sequence< PropertyValue > >& rAddonHelpMenuEntries = aOptions.GetAddonsHelpMenu();
     198             : 
     199           0 :             if ( nInsPos < nItemCount && pHelpMenu->GetItemType( nInsPos ) != MENUITEM_SEPARATOR )
     200           0 :                 nInsSepAfterPos = nInsPos;
     201             : 
     202           0 :             Reference< XModel > xModel = GetModelFromFrame( rFrame );
     203           0 :             AddonMenuManager::BuildMenu( pHelpMenu, ADDON_MENU, nInsPos, nUniqueMenuId, rAddonHelpMenuEntries, rFrame, xModel );
     204             : 
     205           0 :             if ( pHelpMenu->GetItemCount() > nItemCount )
     206             :             {
     207           0 :                 if ( nInsSepAfterPos < MENU_APPEND )
     208             :                 {
     209           0 :                     nInsSepAfterPos += ( pHelpMenu->GetItemCount() - nItemCount );
     210           0 :                     if ( pHelpMenu->GetItemType( nInsSepAfterPos ) != MENUITEM_SEPARATOR )
     211           0 :                         pHelpMenu->InsertSeparator( nInsSepAfterPos );
     212             :                 }
     213           0 :                 pHelpMenu->InsertSeparator( nItemCount );
     214           0 :             }
     215             :         }
     216             :     }
     217         236 : }
     218             : 
     219             : // Merge the addon popup menus into the given menu bar at the provided pos.
     220           0 : void AddonMenuManager::MergeAddonPopupMenus( const Reference< XFrame >& rFrame,
     221             :                                              const Reference< XModel >& rModel,
     222             :                                              sal_uInt16               nMergeAtPos,
     223             :                                              MenuBar*             pMergeMenuBar )
     224             : {
     225           0 :     if ( pMergeMenuBar )
     226             :     {
     227           0 :         AddonsOptions   aAddonsOptions;
     228           0 :         sal_uInt16          nInsertPos = nMergeAtPos;
     229             : 
     230           0 :         ::rtl::OUString                              aTitle;
     231           0 :         ::rtl::OUString                              aURL;
     232           0 :         ::rtl::OUString                              aTarget;
     233           0 :         ::rtl::OUString                              aImageId;
     234           0 :         ::rtl::OUString                              aContext;
     235           0 :         Sequence< Sequence< PropertyValue > > aAddonSubMenu;
     236           0 :         sal_uInt16                                nUniqueMenuId = ADDONMENU_ITEMID_START;
     237             : 
     238           0 :         const Sequence< Sequence< PropertyValue > >&    rAddonMenuEntries = aAddonsOptions.GetAddonsMenuBarPart();
     239           0 :         for ( sal_Int32 i = 0; i < rAddonMenuEntries.getLength(); i++ )
     240             :         {
     241           0 :             AddonMenuManager::GetMenuEntry( rAddonMenuEntries[i],
     242             :                                             aTitle,
     243             :                                             aURL,
     244             :                                             aTarget,
     245             :                                             aImageId,
     246             :                                             aContext,
     247           0 :                                             aAddonSubMenu );
     248           0 :             if ( !aTitle.isEmpty() &&
     249           0 :                  !aURL.isEmpty()   &&
     250           0 :                  aAddonSubMenu.getLength() > 0 &&
     251           0 :                  AddonMenuManager::IsCorrectContext( rModel, aContext ))
     252             :             {
     253           0 :                 sal_uInt16          nId             = nUniqueMenuId++;
     254           0 :                 AddonPopupMenu* pAddonPopupMenu = (AddonPopupMenu *)AddonMenuManager::CreatePopupMenuType( ADDON_POPUPMENU, rFrame );
     255             : 
     256           0 :                 AddonMenuManager::BuildMenu( pAddonPopupMenu, ADDON_MENU, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
     257             : 
     258           0 :                 if ( pAddonPopupMenu->GetItemCount() > 0 )
     259             :                 {
     260           0 :                     pAddonPopupMenu->SetCommandURL( aURL );
     261           0 :                     pMergeMenuBar->InsertItem( nId, aTitle, 0, nInsertPos++ );
     262           0 :                     pMergeMenuBar->SetPopupMenu( nId, pAddonPopupMenu );
     263             : 
     264             :                     // Store the command URL into the VCL menu bar for later identification
     265           0 :                     pMergeMenuBar->SetItemCommand( nId, aURL );
     266             :                 }
     267             :                 else
     268           0 :                     delete pAddonPopupMenu;
     269             :             }
     270           0 :         }
     271             :     }
     272           0 : }
     273             : 
     274             : // Insert the menu and sub menu entries into pCurrentMenu with the aAddonMenuDefinition provided
     275           0 : void AddonMenuManager::BuildMenu( PopupMenu*                            pCurrentMenu,
     276             :                                   MenuType                              nSubMenuType,
     277             :                                   sal_uInt16                                nInsPos,
     278             :                                   sal_uInt16&                               nUniqueMenuId,
     279             :                                   Sequence< Sequence< PropertyValue > > aAddonMenuDefinition,
     280             :                                   const Reference< XFrame >&            rFrame,
     281             :                                   const Reference< XModel >&            rModel )
     282             : {
     283           0 :     Sequence< Sequence< PropertyValue > >   aAddonSubMenu;
     284           0 :     sal_Bool                                    bInsertSeparator    = sal_False;
     285           0 :     sal_uInt32                                  i                   = 0;
     286           0 :     sal_uInt32                                  nElements           = 0;
     287           0 :     sal_uInt32                                  nCount              = aAddonMenuDefinition.getLength();
     288           0 :     AddonsOptions                           aAddonsOptions;
     289             : 
     290           0 :     ::rtl::OUString aTitle;
     291           0 :     ::rtl::OUString aURL;
     292           0 :     ::rtl::OUString aTarget;
     293           0 :     ::rtl::OUString aImageId;
     294           0 :     ::rtl::OUString aContext;
     295             : 
     296           0 :     for ( i = 0; i < nCount; ++i )
     297             :     {
     298           0 :         GetMenuEntry( aAddonMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aContext, aAddonSubMenu );
     299             : 
     300           0 :         if ( !IsCorrectContext( rModel, aContext ) || ( aTitle.isEmpty() && aURL.isEmpty() ))
     301           0 :             continue;
     302             : 
     303           0 :         if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
     304           0 :             bInsertSeparator = sal_True;
     305             :         else
     306             :         {
     307           0 :             PopupMenu* pSubMenu = NULL;
     308           0 :             if ( aAddonSubMenu.getLength() > 0 )
     309             :             {
     310           0 :                 pSubMenu = AddonMenuManager::CreatePopupMenuType( nSubMenuType, rFrame );
     311           0 :                 AddonMenuManager::BuildMenu( pSubMenu, nSubMenuType, MENU_APPEND, nUniqueMenuId, aAddonSubMenu, rFrame, rModel );
     312             : 
     313             :                 // Don't create a menu item for an empty sub menu
     314           0 :                 if ( pSubMenu->GetItemCount() == 0 )
     315             :                 {
     316           0 :                     delete pSubMenu;
     317           0 :                     pSubMenu =  NULL;
     318           0 :                     continue;
     319             :                 }
     320             :             }
     321             : 
     322           0 :             if ( bInsertSeparator && nElements > 0 )
     323             :             {
     324             :                 // Insert a separator only when we insert a new element afterwards and we
     325             :                 // have already one before us
     326           0 :                 nElements = 0;
     327           0 :                 bInsertSeparator = sal_False;
     328           0 :                 pCurrentMenu->InsertSeparator( nInsPos );
     329           0 :                 nInsPos = AddonMenuManager::GetNextPos( nInsPos );
     330             :             }
     331             : 
     332           0 :             sal_uInt16 nId = nUniqueMenuId++;
     333           0 :             pCurrentMenu->InsertItem( nId, aTitle, 0, nInsPos );
     334           0 :             nInsPos = AddonMenuManager::GetNextPos( nInsPos );
     335             : 
     336           0 :             ++nElements;
     337             : 
     338             :             // Store values from configuration to the New and Wizard menu entries to enable
     339             :             // sfx2 based code to support high contrast mode correctly!
     340           0 :             pCurrentMenu->SetUserValue( nId, sal_uIntPtr( new MenuConfiguration::Attributes( aTarget, aImageId )) );
     341           0 :             pCurrentMenu->SetItemCommand( nId, aURL );
     342             : 
     343           0 :             if ( pSubMenu )
     344           0 :                 pCurrentMenu->SetPopupMenu( nId, pSubMenu );
     345             :         }
     346           0 :     }
     347           0 : }
     348             : 
     349             : // Retrieve the menu entry property values from a sequence
     350           0 : void AddonMenuManager::GetMenuEntry( const Sequence< PropertyValue >& rAddonMenuEntry,
     351             :                                      ::rtl::OUString& rTitle,
     352             :                                      ::rtl::OUString& rURL,
     353             :                                      ::rtl::OUString& rTarget,
     354             :                                      ::rtl::OUString& rImageId,
     355             :                                      ::rtl::OUString& rContext,
     356             :                                      Sequence< Sequence< PropertyValue > >& rAddonSubMenu )
     357             : {
     358             :     // Reset submenu parameter
     359           0 :     rAddonSubMenu   = Sequence< Sequence< PropertyValue > >();
     360             : 
     361           0 :     for ( int i = 0; i < rAddonMenuEntry.getLength(); i++ )
     362             :     {
     363           0 :         ::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
     364           0 :         if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_URL )
     365           0 :             rAddonMenuEntry[i].Value >>= rURL;
     366           0 :         else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TITLE )
     367           0 :             rAddonMenuEntry[i].Value >>= rTitle;
     368           0 :         else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_TARGET )
     369           0 :             rAddonMenuEntry[i].Value >>= rTarget;
     370           0 :         else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER )
     371           0 :             rAddonMenuEntry[i].Value >>= rImageId;
     372           0 :         else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_SUBMENU )
     373           0 :             rAddonMenuEntry[i].Value >>= rAddonSubMenu;
     374           0 :         else if ( aMenuEntryPropName == ADDONSMENUITEM_PROPERTYNAME_CONTEXT )
     375           0 :             rAddonMenuEntry[i].Value >>= rContext;
     376           0 :     }
     377           0 : }
     378             : 
     379             : // Check if the context string matches the provided xModel context
     380           0 : sal_Bool AddonMenuManager::IsCorrectContext( const Reference< XModel >& rModel, const ::rtl::OUString& aContext )
     381             : {
     382           0 :     if ( rModel.is() )
     383             :     {
     384           0 :         Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( rModel, UNO_QUERY );
     385           0 :         if ( xServiceInfo.is() )
     386             :         {
     387           0 :             sal_Int32 nIndex = 0;
     388           0 :             do
     389             :             {
     390           0 :                 ::rtl::OUString aToken = aContext.getToken( 0, ',', nIndex );
     391             : 
     392           0 :                 if ( xServiceInfo->supportsService( aToken ))
     393           0 :                     return sal_True;
     394             :             }
     395             :             while ( nIndex >= 0 );
     396           0 :         }
     397             :     }
     398             : 
     399           0 :     return ( aContext.isEmpty() );
     400             : }
     401             : 
     402             : }
     403             : 
     404             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10