blob: ad6a13a04304e509d7b74f495c1b1a9b245f3b5c [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"
#include <uielement/menubarmerger.hxx>
#include <framework/addonsoptions.hxx>
using namespace ::com::sun::star;
static const char SEPARATOR_STRING[] = "private:separator";
static const sal_uInt32 SEPARATOR_STRING_LEN = 17;
static const char MERGECOMMAND_ADDAFTER[] = "AddAfter";
static const sal_uInt32 MERGECOMMAND_ADDAFTER_LEN = 8;
static const char MERGECOMMAND_ADDBEFORE[] = "AddBefore";
static const sal_uInt32 MERGECOMMAND_ADDBEFORE_LEN = 9;
static const char MERGECOMMAND_REPLACE[] = "Replace";
static const sal_uInt32 MERGECOMMAND_REPLACE_LEN = 7;
static const char MERGECOMMAND_REMOVE[] = "Remove";
static const sal_uInt32 MERGECOMMAND_REMOVE_LEN = 6;
static const char MERGEFALLBACK_ADDPATH[] = "AddPath";
static const char MERGEFALLBACK_ADDPATH_LEN = 7;
static const char MERGEFALLBACK_IGNORE[] = "Ignore";
static const char MERGEFALLBACK_IGNORE_LEN = 6;
namespace framework
{
/**
Check whether a module identifier is part of a context
defined by a colon separated list of module identifier.
@param
rContext
Describes a context string list where all contexts
are delimited by a colon. For more information about
the module identifier used as context strings see the
IDL description of com::sun::star::frame::XModuleManager
@param
rModuleIdentifier
A string describing a module identifier. See IDL
description of com::sun::star::frame::XModuleManager.
*/
bool MenuBarMerger::IsCorrectContext( const ::rtl::OUString& rContext, const ::rtl::OUString& rModuleIdentifier )
{
return (( rContext.getLength() == 0 ) || ( rContext.indexOf( rModuleIdentifier ) >= 0 ));
}
void MenuBarMerger::RetrieveReferencePath(
const ::rtl::OUString& rReferencePathString,
::std::vector< ::rtl::OUString >& rReferencePath )
{
const sal_Char aDelimiter = '\\';
rReferencePath.clear();
sal_Int32 nIndex( 0 );
do
{
::rtl::OUString aToken = rReferencePathString.getToken( 0, aDelimiter, nIndex );
if ( aToken.getLength() > 0 )
rReferencePath.push_back( aToken );
}
while ( nIndex >= 0 );
}
ReferencePathInfo MenuBarMerger::FindReferencePath(
const ::std::vector< ::rtl::OUString >& rReferencePath,
Menu* pMenu )
{
sal_uInt32 i( 0 );
const sal_uInt32 nCount( rReferencePath.size() );
Menu* pCurrMenu( pMenu );
RPResultInfo eResult( RP_OK );
sal_Int32 nLevel( - 1 );
sal_uInt16 nPos( MENU_ITEM_NOTFOUND );
do
{
++nLevel;
::rtl::OUString aCmd( rReferencePath[i] );
if ( i == nCount-1 )
{
// Check last reference path element. Must be a leave (menu item).
sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
if ( nTmpPos != MENU_ITEM_NOTFOUND )
nPos = nTmpPos;
eResult = ( nTmpPos != MENU_ITEM_NOTFOUND ) ? RP_OK : RP_MENUITEM_NOT_FOUND;
}
else
{
// Check reference path element. Must be a node (popup menu)!
sal_uInt16 nTmpPos = FindMenuItem( aCmd, pCurrMenu );
if ( nTmpPos != MENU_ITEM_NOTFOUND )
{
sal_uInt16 nItemId = pCurrMenu->GetItemId( nTmpPos );
Menu* pTmpMenu = pCurrMenu->GetPopupMenu( nItemId );
if ( pTmpMenu != 0 )
pCurrMenu = pTmpMenu;
else
{
nPos = nTmpPos;
eResult = RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND;
}
}
else
eResult = RP_POPUPMENU_NOT_FOUND;
}
i++;
}
while (( pCurrMenu != 0 ) && ( i < nCount ) && ( eResult == RP_OK ));
ReferencePathInfo aResult;
aResult.pPopupMenu = pCurrMenu;
aResult.nPos = nPos;
aResult.nLevel = nLevel;
aResult.eResult = eResult;
return aResult;
}
sal_uInt16 MenuBarMerger::FindMenuItem( const ::rtl::OUString& rCmd, Menu* pCurrMenu )
{
for ( sal_uInt16 i = 0; i < pCurrMenu->GetItemCount(); i++ )
{
const sal_uInt16 nItemId = pCurrMenu->GetItemId( i );
if ( nItemId > 0 )
{
if ( rCmd == ::rtl::OUString( pCurrMenu->GetItemCommand( nItemId )))
return i;
}
}
return MENU_ITEM_NOTFOUND;
}
bool MenuBarMerger::CreateSubMenu(
Menu* pSubMenu,
sal_uInt16& nItemId,
const ::rtl::OUString& rModuleIdentifier,
const AddonMenuContainer& rAddonSubMenu )
{
const sal_uInt32 nSize = rAddonSubMenu.size();
for ( sal_uInt32 i = 0; i < nSize; i++ )
{
const AddonMenuItem& rMenuItem = rAddonSubMenu[i];
if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
{
if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
{
pSubMenu->InsertSeparator( MENU_APPEND );
}
else
{
pSubMenu->InsertItem( nItemId, rMenuItem.aTitle, 0, MENU_APPEND );
pSubMenu->SetItemCommand( nItemId, rMenuItem.aURL );
if ( !rMenuItem.aSubMenu.empty() )
{
PopupMenu* pPopupMenu = new PopupMenu();
pSubMenu->SetPopupMenu( nItemId, pPopupMenu );
++nItemId;
CreateSubMenu( pPopupMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
}
else
++nItemId;
}
}
}
return true;
}
bool MenuBarMerger::MergeMenuItems(
Menu* pMenu,
sal_uInt16 nPos,
sal_uInt16 nModIndex,
sal_uInt16& nItemId,
const ::rtl::OUString& rModuleIdentifier,
const AddonMenuContainer& rAddonMenuItems )
{
sal_uInt16 nIndex( 0 );
const sal_uInt32 nSize = rAddonMenuItems.size();
for ( sal_uInt32 i = 0; i < nSize; i++ )
{
const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
{
if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
{
pMenu->InsertSeparator( nPos+nModIndex+nIndex );
}
else
{
pMenu->InsertItem( nItemId, rMenuItem.aTitle, 0, nPos+nModIndex+nIndex );
pMenu->SetItemCommand( nItemId, rMenuItem.aURL );
if ( !rMenuItem.aSubMenu.empty() )
{
PopupMenu* pSubMenu = new PopupMenu();
pMenu->SetPopupMenu( nItemId, pSubMenu );
++nItemId;
CreateSubMenu( pSubMenu, nItemId, rModuleIdentifier, rMenuItem.aSubMenu );
}
else
++nItemId;
}
++nIndex;
}
}
return true;
}
bool MenuBarMerger::ReplaceMenuItem(
Menu* pMenu,
sal_uInt16 nPos,
sal_uInt16& rItemId,
const ::rtl::OUString& rModuleIdentifier,
const AddonMenuContainer& rAddonMenuItems )
{
// There is no replace available. Therfore we first have to
// remove the old menu entry,
pMenu->RemoveItem( nPos );
return MergeMenuItems( pMenu, nPos, 0, rItemId, rModuleIdentifier, rAddonMenuItems );
}
bool MenuBarMerger::RemoveMenuItems(
Menu* pMenu,
sal_uInt16 nPos,
const ::rtl::OUString& rMergeCommandParameter )
{
const sal_uInt16 nParam( sal_uInt16( rMergeCommandParameter.toInt32() ));
sal_uInt16 nCount( 1 );
nCount = std::max( nParam, nCount );
sal_uInt16 i = 0;
while (( nPos < pMenu->GetItemCount() ) && ( i < nCount ))
{
pMenu->RemoveItem( nPos );
++i;
}
return true;
}
bool MenuBarMerger::ProcessMergeOperation(
Menu* pMenu,
sal_uInt16 nPos,
sal_uInt16& nItemId,
const ::rtl::OUString& rMergeCommand,
const ::rtl::OUString& rMergeCommandParameter,
const ::rtl::OUString& rModuleIdentifier,
const AddonMenuContainer& rAddonMenuItems )
{
sal_uInt16 nModIndex( 0 );
if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_ADDBEFORE, MERGECOMMAND_ADDBEFORE_LEN ))
{
nModIndex = 0;
return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
}
else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_ADDAFTER, MERGECOMMAND_ADDAFTER_LEN ))
{
nModIndex = 1;
return MergeMenuItems( pMenu, nPos, nModIndex, nItemId, rModuleIdentifier, rAddonMenuItems );
}
else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REPLACE, MERGECOMMAND_REPLACE_LEN ))
{
return ReplaceMenuItem( pMenu, nPos, nItemId, rModuleIdentifier, rAddonMenuItems );
}
else if ( rMergeCommand.equalsAsciiL( MERGECOMMAND_REMOVE, MERGECOMMAND_REMOVE_LEN ))
{
return RemoveMenuItems( pMenu, nPos, rMergeCommandParameter );
}
return false;
}
bool MenuBarMerger::ProcessFallbackOperation(
const ReferencePathInfo& aRefPathInfo,
sal_uInt16& rItemId,
const ::rtl::OUString& rMergeCommand,
const ::rtl::OUString& rMergeFallback,
const ::std::vector< ::rtl::OUString >& rReferencePath,
const ::rtl::OUString& rModuleIdentifier,
const AddonMenuContainer& rAddonMenuItems )
{
if (( rMergeFallback.equalsAsciiL( MERGEFALLBACK_IGNORE, MERGEFALLBACK_IGNORE_LEN )) ||
( rMergeCommand.equalsAsciiL( MERGECOMMAND_REPLACE, MERGECOMMAND_REPLACE_LEN )) ||
( rMergeCommand.equalsAsciiL( MERGECOMMAND_REMOVE, MERGECOMMAND_REMOVE_LEN )) )
{
return true;
}
else if ( rMergeFallback.equalsAsciiL( MERGEFALLBACK_ADDPATH, MERGEFALLBACK_ADDPATH_LEN ))
{
Menu* pCurrMenu( aRefPathInfo.pPopupMenu );
sal_Int32 nLevel( aRefPathInfo.nLevel );
const sal_Int32 nSize( rReferencePath.size() );
bool bFirstLevel( true );
while ( nLevel < nSize )
{
if ( nLevel == nSize-1 )
{
const sal_uInt32 nCount = rAddonMenuItems.size();
for ( sal_uInt32 i = 0; i < nCount; ++i )
{
const AddonMenuItem& rMenuItem = rAddonMenuItems[i];
if ( IsCorrectContext( rMenuItem.aContext, rModuleIdentifier ))
{
if ( rMenuItem.aURL.equalsAsciiL( SEPARATOR_STRING, SEPARATOR_STRING_LEN ))
pCurrMenu->InsertSeparator( MENU_APPEND );
else
{
pCurrMenu->InsertItem( rItemId, rMenuItem.aTitle, 0, MENU_APPEND );
pCurrMenu->SetItemCommand( rItemId, rMenuItem.aURL );
++rItemId;
}
}
}
}
else
{
const ::rtl::OUString aCmd( rReferencePath[nLevel] );
sal_uInt16 nInsPos( MENU_APPEND );
PopupMenu* pPopupMenu( new PopupMenu );
if ( bFirstLevel && ( aRefPathInfo.eResult == RP_MENUITEM_INSTEAD_OF_POPUPMENU_FOUND ))
{
// special case: menu item without popup
nInsPos = aRefPathInfo.nPos;
sal_uInt16 nSetItemId = pCurrMenu->GetItemId( nInsPos );
pCurrMenu->SetItemCommand( nSetItemId, aCmd );
pCurrMenu->SetPopupMenu( nSetItemId, pPopupMenu );
}
else
{
// normal case: insert a new item with popup
pCurrMenu->InsertItem( rItemId, ::rtl::OUString(), 0, MENU_APPEND );
pCurrMenu->SetItemCommand( rItemId, aCmd );
pCurrMenu->SetPopupMenu( rItemId, pPopupMenu );
}
pCurrMenu = pPopupMenu;
++rItemId;
bFirstLevel = false;
}
++nLevel;
}
return true;
}
return false;
}
void MenuBarMerger::GetMenuEntry(
const uno::Sequence< beans::PropertyValue >& rAddonMenuEntry,
AddonMenuItem& rAddonMenuItem )
{
// Reset submenu member
rAddonMenuItem.aSubMenu.clear();
for ( sal_Int32 i = 0; i < rAddonMenuEntry.getLength(); i++ )
{
::rtl::OUString aMenuEntryPropName = rAddonMenuEntry[i].Name;
if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_URL, ADDONSMENUITEM_URL_LEN ))
rAddonMenuEntry[i].Value >>= rAddonMenuItem.aURL;
else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_TITLE, ADDONSMENUITEM_TITLE_LEN ))
rAddonMenuEntry[i].Value >>= rAddonMenuItem.aTitle;
else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_TARGET, ADDONSMENUITEM_TARGET_LEN ))
rAddonMenuEntry[i].Value >>= rAddonMenuItem.aTarget;
else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_SUBMENU, ADDONSMENUITEM_SUBMENU_LEN ))
{
uno::Sequence< uno::Sequence< beans::PropertyValue > > aSubMenu;
rAddonMenuEntry[i].Value >>= aSubMenu;
GetSubMenu( aSubMenu, rAddonMenuItem.aSubMenu );
}
else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_CONTEXT, ADDONSMENUITEM_CONTEXT_LEN ))
rAddonMenuEntry[i].Value >>= rAddonMenuItem.aContext;
else if ( aMenuEntryPropName.equalsAsciiL( ADDONSMENUITEM_STRING_IMAGEIDENTIFIER, ADDONSMENUITEM_IMAGEIDENTIFIER_LEN ))
rAddonMenuEntry[i].Value >>= rAddonMenuItem.aImageId;
}
}
void MenuBarMerger::GetSubMenu(
const uno::Sequence< uno::Sequence< beans::PropertyValue > >& rSubMenuEntries,
AddonMenuContainer& rSubMenu )
{
rSubMenu.clear();
const sal_Int32 nCount = rSubMenuEntries.getLength();
rSubMenu.reserve(rSubMenu.size() + nCount);
for ( sal_Int32 i = 0; i < nCount; i++ )
{
const uno::Sequence< beans::PropertyValue >& rMenuEntry = rSubMenuEntries[ i ];
AddonMenuItem aMenuItem;
GetMenuEntry( rMenuEntry, aMenuItem );
rSubMenu.push_back( aMenuItem );
}
}
} // namespace framework