316 lines
9.9 KiB
C++
316 lines
9.9 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* 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 .
|
|
*/
|
|
|
|
#include "menuitemlist.hxx"
|
|
|
|
#include <salframe.hxx>
|
|
#include <salinst.hxx>
|
|
#include <salmenu.hxx>
|
|
#include <svdata.hxx>
|
|
|
|
#include <vcl/i18nhelp.hxx>
|
|
#include <vcl/mnemonic.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/vcllayout.hxx>
|
|
#include <vcl/window.hxx>
|
|
|
|
using namespace css;
|
|
using namespace vcl;
|
|
|
|
MenuItemData::~MenuItemData()
|
|
{
|
|
if (aUserValueReleaseFunc)
|
|
aUserValueReleaseFunc(nUserValue);
|
|
pSalMenuItem.reset();
|
|
pSubMenu.disposeAndClear();
|
|
}
|
|
|
|
SalLayoutGlyphs* MenuItemData::GetTextGlyphs(const OutputDevice* pOutputDevice)
|
|
{
|
|
if (aTextGlyphs.IsValid())
|
|
// Use pre-calculated result.
|
|
return &aTextGlyphs;
|
|
|
|
OUString aNonMnemonicString = removeMnemonicFromString(aText);
|
|
std::unique_ptr<SalLayout> pLayout
|
|
= pOutputDevice->ImplLayout(aNonMnemonicString, 0, aNonMnemonicString.getLength(),
|
|
Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly);
|
|
if (!pLayout)
|
|
return nullptr;
|
|
|
|
// Remember the calculation result.
|
|
aTextGlyphs = pLayout->GetGlyphs();
|
|
|
|
return &aTextGlyphs;
|
|
}
|
|
|
|
MenuItemList::~MenuItemList()
|
|
{
|
|
}
|
|
|
|
MenuItemData* MenuItemList::Insert(
|
|
sal_uInt16 nId,
|
|
MenuItemType eType,
|
|
MenuItemBits nBits,
|
|
const OUString& rStr,
|
|
Menu* pMenu,
|
|
size_t nPos,
|
|
const OUString &rIdent
|
|
)
|
|
{
|
|
MenuItemData* pData = new MenuItemData( rStr );
|
|
pData->nId = nId;
|
|
pData->sIdent = rIdent;
|
|
pData->eType = eType;
|
|
pData->nBits = nBits;
|
|
pData->pSubMenu = nullptr;
|
|
pData->nUserValue = nullptr;
|
|
pData->bChecked = false;
|
|
pData->bEnabled = true;
|
|
pData->bVisible = true;
|
|
pData->bIsTemporary = false;
|
|
|
|
SalItemParams aSalMIData;
|
|
aSalMIData.nId = nId;
|
|
aSalMIData.eType = eType;
|
|
aSalMIData.nBits = nBits;
|
|
aSalMIData.pMenu = pMenu;
|
|
aSalMIData.aText = rStr;
|
|
|
|
// Native-support: returns NULL if not supported
|
|
pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
|
|
|
|
if( nPos < maItemList.size() ) {
|
|
maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
|
|
} else {
|
|
maItemList.emplace_back( pData );
|
|
}
|
|
return pData;
|
|
}
|
|
|
|
void MenuItemList::InsertSeparator(const OUString &rIdent, size_t nPos)
|
|
{
|
|
MenuItemData* pData = new MenuItemData;
|
|
pData->nId = 0;
|
|
pData->sIdent = rIdent;
|
|
pData->eType = MenuItemType::SEPARATOR;
|
|
pData->nBits = MenuItemBits::NONE;
|
|
pData->pSubMenu = nullptr;
|
|
pData->nUserValue = nullptr;
|
|
pData->bChecked = false;
|
|
pData->bEnabled = true;
|
|
pData->bVisible = true;
|
|
pData->bIsTemporary = false;
|
|
|
|
SalItemParams aSalMIData;
|
|
aSalMIData.nId = 0;
|
|
aSalMIData.eType = MenuItemType::SEPARATOR;
|
|
aSalMIData.nBits = MenuItemBits::NONE;
|
|
aSalMIData.pMenu = nullptr;
|
|
aSalMIData.aText.clear();
|
|
aSalMIData.aImage = Image();
|
|
|
|
// Native-support: returns NULL if not supported
|
|
pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
|
|
|
|
if( nPos < maItemList.size() ) {
|
|
maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
|
|
} else {
|
|
maItemList.emplace_back( pData );
|
|
}
|
|
}
|
|
|
|
void MenuItemList::Remove( size_t nPos )
|
|
{
|
|
if( nPos < maItemList.size() )
|
|
{
|
|
maItemList.erase( maItemList.begin() + nPos );
|
|
}
|
|
}
|
|
|
|
void MenuItemList::Clear()
|
|
{
|
|
maItemList.clear();
|
|
}
|
|
|
|
MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
|
|
{
|
|
for( size_t i = 0, n = maItemList.size(); i < n; ++i )
|
|
{
|
|
if ( maItemList[ i ]->nId == nSVId )
|
|
{
|
|
rPos = i;
|
|
return maItemList[ i ].get();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
MenuItemData* MenuItemList::SearchItem(
|
|
sal_Unicode cSelectChar,
|
|
KeyCode aKeyCode,
|
|
size_t& rPos,
|
|
size_t& nDuplicates,
|
|
size_t nCurrentPos
|
|
) const
|
|
{
|
|
const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
|
|
|
|
size_t nListCount = maItemList.size();
|
|
|
|
// try character code first
|
|
nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
|
|
if( nDuplicates )
|
|
{
|
|
MenuItemData* pFirstMatch = nullptr;
|
|
size_t nFirstPos(0);
|
|
for ( rPos = 0; rPos < nListCount; rPos++)
|
|
{
|
|
MenuItemData* pData = maItemList[ rPos ].get();
|
|
if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
|
|
{
|
|
if (nDuplicates == 1)
|
|
return pData;
|
|
if (rPos > nCurrentPos)
|
|
return pData; // select next entry with the same mnemonic
|
|
if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
|
|
{
|
|
pFirstMatch = pData;
|
|
nFirstPos = rPos;
|
|
}
|
|
}
|
|
}
|
|
if (pFirstMatch)
|
|
{
|
|
rPos = nFirstPos;
|
|
return pFirstMatch;
|
|
}
|
|
}
|
|
|
|
// nothing found, try keycode instead
|
|
nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
|
|
|
|
if( nDuplicates )
|
|
{
|
|
char ascii = 0;
|
|
if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
|
|
ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
|
|
|
|
MenuItemData* pFirstMatch = nullptr;
|
|
size_t nFirstPos(0);
|
|
for ( rPos = 0; rPos < nListCount; rPos++)
|
|
{
|
|
MenuItemData* pData = maItemList[ rPos ].get();
|
|
if ( pData->bEnabled )
|
|
{
|
|
sal_Int32 n = pData->aText.indexOf('~');
|
|
if ( n != -1 )
|
|
{
|
|
KeyCode nKeyCode;
|
|
sal_Unicode nUnicode = pData->aText[n+1];
|
|
vcl::Window* pDefWindow = ImplGetDefaultWindow();
|
|
if( ( pDefWindow
|
|
&& pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( nUnicode,
|
|
Application::GetSettings().GetUILanguageTag().getLanguageType(), nKeyCode )
|
|
&& aKeyCode.GetCode() == nKeyCode.GetCode()
|
|
)
|
|
|| ( ascii
|
|
&& rI18nHelper.MatchMnemonic( pData->aText, ascii )
|
|
)
|
|
)
|
|
{
|
|
if (nDuplicates == 1)
|
|
return pData;
|
|
if (rPos > nCurrentPos)
|
|
return pData; // select next entry with the same mnemonic
|
|
if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
|
|
{
|
|
pFirstMatch = pData;
|
|
nFirstPos = rPos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pFirstMatch)
|
|
{
|
|
rPos = nFirstPos;
|
|
return pFirstMatch;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
|
|
{
|
|
// returns number of entries with same mnemonic
|
|
const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
|
|
|
|
size_t nItems = 0;
|
|
for ( size_t nPos = maItemList.size(); nPos; )
|
|
{
|
|
MenuItemData* pData = maItemList[ --nPos ].get();
|
|
if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
|
|
nItems++;
|
|
}
|
|
|
|
return nItems;
|
|
}
|
|
|
|
size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
|
|
{
|
|
// returns number of entries with same mnemonic
|
|
// uses key codes instead of character codes
|
|
const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
|
|
char ascii = 0;
|
|
if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
|
|
ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
|
|
|
|
size_t nItems = 0;
|
|
for ( size_t nPos = maItemList.size(); nPos; )
|
|
{
|
|
MenuItemData* pData = maItemList[ --nPos ].get();
|
|
if ( pData->bEnabled )
|
|
{
|
|
sal_Int32 n = pData->aText.indexOf('~');
|
|
if (n != -1)
|
|
{
|
|
KeyCode nKeyCode;
|
|
// if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
|
|
// so we have working shortcuts when ascii mnemonics are used
|
|
vcl::Window* pDefWindow = ImplGetDefaultWindow();
|
|
if( ( pDefWindow
|
|
&& pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
|
|
Application::GetSettings().GetUILanguageTag().getLanguageType(), nKeyCode )
|
|
&& aKeyCode.GetCode() == nKeyCode.GetCode()
|
|
)
|
|
|| ( ascii
|
|
&& rI18nHelper.MatchMnemonic( pData->aText, ascii )
|
|
)
|
|
)
|
|
nItems++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nItems;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|