18692cc141
Part XX Module framework
449 lines
16 KiB
C++
449 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#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.isEmpty() || ( 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.isEmpty() )
|
|
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() );
|
|
|
|
ReferencePathInfo aResult;
|
|
if ( !nCount )
|
|
{
|
|
aResult.eResult = RP_MENUITEM_NOT_FOUND;
|
|
return aResult;
|
|
}
|
|
|
|
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 ));
|
|
|
|
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
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|