LibreOffice Module vcl (master)  1
menuitemlist.cxx
Go to the documentation of this file.
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 "menuitemlist.hxx"
21 
22 #include <salframe.hxx>
23 #include <salinst.hxx>
24 #include <salmenu.hxx>
25 #include <svdata.hxx>
26 #include <vcl/i18nhelp.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/vcllayout.hxx>
29 #include <vcl/window.hxx>
30 
31 using namespace css;
32 using namespace vcl;
33 
35 {
36  if (aUserValueReleaseFunc)
37  aUserValueReleaseFunc(nUserValue);
38  pSalMenuItem.reset();
39  pSubMenu.disposeAndClear();
40 }
41 
43 {
44  if (aTextGlyphs.IsValid())
45  // Use pre-calculated result.
46  return &aTextGlyphs;
47 
48  OUString aNonMnemonicString = OutputDevice::GetNonMnemonicString(aText);
49  std::unique_ptr<SalLayout> pLayout
50  = pOutputDevice->ImplLayout(aNonMnemonicString, 0, aNonMnemonicString.getLength(),
51  Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly);
52  if (!pLayout)
53  return nullptr;
54 
55  // Remember the calculation result.
56  aTextGlyphs = pLayout->GetGlyphs();
57 
58  return &aTextGlyphs;
59 }
60 
62 {
63 }
64 
66  sal_uInt16 nId,
67  MenuItemType eType,
68  MenuItemBits nBits,
69  const OUString& rStr,
70  Menu* pMenu,
71  size_t nPos,
72  const OString &rIdent
73 )
74 {
75  MenuItemData* pData = new MenuItemData( rStr );
76  pData->nId = nId;
77  pData->sIdent = rIdent;
78  pData->eType = eType;
79  pData->nBits = nBits;
80  pData->pSubMenu = nullptr;
81  pData->nUserValue = nullptr;
82  pData->bChecked = false;
83  pData->bEnabled = true;
84  pData->bVisible = true;
85  pData->bIsTemporary = false;
86 
87  SalItemParams aSalMIData;
88  aSalMIData.nId = nId;
89  aSalMIData.eType = eType;
90  aSalMIData.nBits = nBits;
91  aSalMIData.pMenu = pMenu;
92  aSalMIData.aText = rStr;
93 
94  // Native-support: returns NULL if not supported
95  pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
96 
97  if( nPos < maItemList.size() ) {
98  maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
99  } else {
100  maItemList.emplace_back( pData );
101  }
102  return pData;
103 }
104 
105 void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
106 {
108  pData->nId = 0;
109  pData->sIdent = rIdent;
111  pData->nBits = MenuItemBits::NONE;
112  pData->pSubMenu = nullptr;
113  pData->nUserValue = nullptr;
114  pData->bChecked = false;
115  pData->bEnabled = true;
116  pData->bVisible = true;
117  pData->bIsTemporary = false;
118 
119  SalItemParams aSalMIData;
120  aSalMIData.nId = 0;
121  aSalMIData.eType = MenuItemType::SEPARATOR;
122  aSalMIData.nBits = MenuItemBits::NONE;
123  aSalMIData.pMenu = nullptr;
124  aSalMIData.aText.clear();
125  aSalMIData.aImage = Image();
126 
127  // Native-support: returns NULL if not supported
128  pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
129 
130  if( nPos < maItemList.size() ) {
131  maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
132  } else {
133  maItemList.emplace_back( pData );
134  }
135 }
136 
137 void MenuItemList::Remove( size_t nPos )
138 {
139  if( nPos < maItemList.size() )
140  {
141  maItemList.erase( maItemList.begin() + nPos );
142  }
143 }
144 
146 {
147  maItemList.clear();
148 }
149 
150 MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
151 {
152  for( size_t i = 0, n = maItemList.size(); i < n; ++i )
153  {
154  if ( maItemList[ i ]->nId == nSVId )
155  {
156  rPos = i;
157  return maItemList[ i ].get();
158  }
159  }
160  return nullptr;
161 }
162 
164  sal_Unicode cSelectChar,
165  KeyCode aKeyCode,
166  size_t& rPos,
167  size_t& nDuplicates,
168  size_t nCurrentPos
169 ) const
170 {
172 
173  size_t nListCount = maItemList.size();
174 
175  // try character code first
176  nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
177  if( nDuplicates )
178  {
179  MenuItemData* pFirstMatch = nullptr;
180  size_t nFirstPos(0);
181  for ( rPos = 0; rPos < nListCount; rPos++)
182  {
183  MenuItemData* pData = maItemList[ rPos ].get();
184  if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
185  {
186  if (nDuplicates == 1)
187  return pData;
188  if (rPos > nCurrentPos)
189  return pData; // select next entry with the same mnemonic
190  if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
191  {
192  pFirstMatch = pData;
193  nFirstPos = rPos;
194  }
195  }
196  }
197  if (pFirstMatch)
198  {
199  rPos = nFirstPos;
200  return pFirstMatch;
201  }
202  }
203 
204  // nothing found, try keycode instead
205  nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
206 
207  if( nDuplicates )
208  {
209  char ascii = 0;
210  if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
211  ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
212 
213  MenuItemData* pFirstMatch = nullptr;
214  size_t nFirstPos(0);
215  for ( rPos = 0; rPos < nListCount; rPos++)
216  {
217  MenuItemData* pData = maItemList[ rPos ].get();
218  if ( pData->bEnabled )
219  {
220  sal_Int32 n = pData->aText.indexOf('~');
221  if ( n != -1 )
222  {
223  KeyCode nKeyCode;
224  sal_Unicode nUnicode = pData->aText[n+1];
225  vcl::Window* pDefWindow = ImplGetDefaultWindow();
226  if( ( pDefWindow
227  && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( nUnicode,
228  Application::GetSettings().GetUILanguageTag().getLanguageType(), nKeyCode )
229  && aKeyCode.GetCode() == nKeyCode.GetCode()
230  )
231  || ( ascii
232  && rI18nHelper.MatchMnemonic( pData->aText, ascii )
233  )
234  )
235  {
236  if (nDuplicates == 1)
237  return pData;
238  if (rPos > nCurrentPos)
239  return pData; // select next entry with the same mnemonic
240  if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
241  {
242  pFirstMatch = pData;
243  nFirstPos = rPos;
244  }
245  }
246  }
247  }
248  }
249  if (pFirstMatch)
250  {
251  rPos = nFirstPos;
252  return pFirstMatch;
253  }
254  }
255 
256  return nullptr;
257 }
258 
259 size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
260 {
261  // returns number of entries with same mnemonic
263 
264  size_t nItems = 0;
265  for ( size_t nPos = maItemList.size(); nPos; )
266  {
267  MenuItemData* pData = maItemList[ --nPos ].get();
268  if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
269  nItems++;
270  }
271 
272  return nItems;
273 }
274 
275 size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
276 {
277  // returns number of entries with same mnemonic
278  // uses key codes instead of character codes
280  char ascii = 0;
281  if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
282  ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
283 
284  size_t nItems = 0;
285  for ( size_t nPos = maItemList.size(); nPos; )
286  {
287  MenuItemData* pData = maItemList[ --nPos ].get();
288  if ( pData->bEnabled )
289  {
290  sal_Int32 n = pData->aText.indexOf('~');
291  if (n != -1)
292  {
293  KeyCode nKeyCode;
294  // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
295  // so we have working shortcuts when ascii mnemonics are used
296  vcl::Window* pDefWindow = ImplGetDefaultWindow();
297  if( ( pDefWindow
298  && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
300  && aKeyCode.GetCode() == nKeyCode.GetCode()
301  )
302  || ( ascii
303  && rI18nHelper.MatchMnemonic( pData->aText, ascii )
304  )
305  )
306  nItems++;
307  }
308  }
309  }
310 
311  return nItems;
312 }
313 
314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
VclPtr< Menu > pSubMenu
OUString aText
Definition: salmenu.hxx:34
#define ascii(x)
MenuItemType
Definition: vclenum.hxx:30
const LanguageTag & GetUILanguageTag() const
std::unique_ptr< ContentProperties > pData
MenuItemData * SearchItem(sal_Unicode cSelectChar, vcl::KeyCode aKeyCode, size_t &rPos, size_t &nDuplicates, size_t nCurrentPos) const
LanguageType getLanguageType(bool bResolveSystem=true) const
void Remove(size_t nPos)
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:733
constexpr sal_uInt16 KEY_A
Definition: keycodes.hxx:56
sal_Int64 n
virtual std::unique_ptr< SalMenuItem > CreateMenuItem(const SalItemParams &pItemData)
Definition: salvtables.cxx:138
sal_Int16 nId
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
size_t GetItemCount(sal_Unicode cSelectChar) const
const vcl::I18nHelper & GetUILocaleI18nHelper() const
MenuItemBits nBits
Definition: salmenu.hxx:37
MenuItemBits
Definition: vclenum.hxx:32
sal_uInt16 nId
Definition: salmenu.hxx:36
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), tools::Long nLogicWidth=0, const tools::Long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1221
sal_uInt16 sal_Unicode
void InsertSeparator(const OString &rIdent, size_t nPos)
void * nUserValue
MenuItemType eType
Definition: salmenu.hxx:35
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:75
sal_uInt16 nId
int i
MenuItemType eType
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:168
std::unique_ptr< SalMenuItem > pSalMenuItem
bool MatchMnemonic(const OUString &rString, sal_Unicode cMnemonicChar) const
Definition: i18nhelp.cxx:141
SalLayoutGlyphs * GetTextGlyphs(const OutputDevice *pOutputDevice)
Computes aText's text layout (glyphs), cached in aTextGlyphs.
VclPtr< Menu > pMenu
Definition: salmenu.hxx:33
SalFrame * ImplGetFrame() const
Definition: window2.cxx:837
Definition: menu.hxx:123
OString sIdent
Image aImage
Definition: salmenu.hxx:32
Definition: image.hxx:39
MenuItemData * GetData(sal_uInt16 nSVId, size_t &rPos) const
constexpr sal_uInt16 KEY_Z
Definition: keycodes.hxx:81
OUString aText
virtual bool MapUnicodeToKeyCode(sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode &rKeyCode)=0
static OUString GetNonMnemonicString(const OUString &rStr, sal_Int32 &rMnemonicPos)
Definition: text.cxx:2198
vcl::Window * ImplGetDefaultWindow()
Returns either the application window, or the default GL context window.
Definition: svdata.cxx:209
MenuItemData * Insert(sal_uInt16 nId, MenuItemType eType, MenuItemBits nBits, const OUString &rStr, Menu *pMenu, size_t nPos, const OString &rIdent)
SalInstance * mpDefInst
Definition: svdata.hxx:385
sal_uInt16 nPos
MenuItemBits nBits