summaryrefslogtreecommitdiffstats
path: root/vcl/source/window/menuitemlist.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/window/menuitemlist.cxx')
-rw-r--r--vcl/source/window/menuitemlist.cxx314
1 files changed, 314 insertions, 0 deletions
diff --git a/vcl/source/window/menuitemlist.cxx b/vcl/source/window/menuitemlist.cxx
new file mode 100644
index 000000000..173a6204e
--- /dev/null
+++ b/vcl/source/window/menuitemlist.cxx
@@ -0,0 +1,314 @@
+/* -*- 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/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 = OutputDevice::GetNonMnemonicString(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 OString &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 OString &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: */