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  const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
56  if (!pGlyphs)
57  return nullptr;
58 
59  // Remember the calculation result.
60  aTextGlyphs = *pGlyphs;
61 
62  return &aTextGlyphs;
63 }
64 
66 {
67 }
68 
70  sal_uInt16 nId,
71  MenuItemType eType,
72  MenuItemBits nBits,
73  const OUString& rStr,
74  Menu* pMenu,
75  size_t nPos,
76  const OString &rIdent
77 )
78 {
79  MenuItemData* pData = new MenuItemData( rStr );
80  pData->nId = nId;
81  pData->sIdent = rIdent;
82  pData->eType = eType;
83  pData->nBits = nBits;
84  pData->pSubMenu = nullptr;
85  pData->nUserValue = nullptr;
86  pData->bChecked = false;
87  pData->bEnabled = true;
88  pData->bVisible = true;
89  pData->bIsTemporary = false;
90 
91  SalItemParams aSalMIData;
92  aSalMIData.nId = nId;
93  aSalMIData.eType = eType;
94  aSalMIData.nBits = nBits;
95  aSalMIData.pMenu = pMenu;
96  aSalMIData.aText = rStr;
97 
98  // Native-support: returns NULL if not supported
99  pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
100 
101  if( nPos < maItemList.size() ) {
102  maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
103  } else {
104  maItemList.emplace_back( pData );
105  }
106  return pData;
107 }
108 
109 void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
110 {
112  pData->nId = 0;
113  pData->sIdent = rIdent;
115  pData->nBits = MenuItemBits::NONE;
116  pData->pSubMenu = nullptr;
117  pData->nUserValue = nullptr;
118  pData->bChecked = false;
119  pData->bEnabled = true;
120  pData->bVisible = true;
121  pData->bIsTemporary = false;
122 
123  SalItemParams aSalMIData;
124  aSalMIData.nId = 0;
125  aSalMIData.eType = MenuItemType::SEPARATOR;
126  aSalMIData.nBits = MenuItemBits::NONE;
127  aSalMIData.pMenu = nullptr;
128  aSalMIData.aText.clear();
129  aSalMIData.aImage = Image();
130 
131  // Native-support: returns NULL if not supported
132  pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
133 
134  if( nPos < maItemList.size() ) {
135  maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
136  } else {
137  maItemList.emplace_back( pData );
138  }
139 }
140 
141 void MenuItemList::Remove( size_t nPos )
142 {
143  if( nPos < maItemList.size() )
144  {
145  maItemList.erase( maItemList.begin() + nPos );
146  }
147 }
148 
150 {
151  maItemList.clear();
152 }
153 
154 MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
155 {
156  for( size_t i = 0, n = maItemList.size(); i < n; ++i )
157  {
158  if ( maItemList[ i ]->nId == nSVId )
159  {
160  rPos = i;
161  return maItemList[ i ].get();
162  }
163  }
164  return nullptr;
165 }
166 
168  sal_Unicode cSelectChar,
169  KeyCode aKeyCode,
170  size_t& rPos,
171  size_t& nDuplicates,
172  size_t nCurrentPos
173 ) const
174 {
176 
177  size_t nListCount = maItemList.size();
178 
179  // try character code first
180  nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
181  if( nDuplicates )
182  {
183  MenuItemData* pFirstMatch = nullptr;
184  size_t nFirstPos(0);
185  for ( rPos = 0; rPos < nListCount; rPos++)
186  {
187  MenuItemData* pData = maItemList[ rPos ].get();
188  if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
189  {
190  if (nDuplicates == 1)
191  return pData;
192  if (rPos > nCurrentPos)
193  return pData; // select next entry with the same mnemonic
194  if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
195  {
196  pFirstMatch = pData;
197  nFirstPos = rPos;
198  }
199  }
200  }
201  if (pFirstMatch)
202  {
203  rPos = nFirstPos;
204  return pFirstMatch;
205  }
206  }
207 
208  // nothing found, try keycode instead
209  nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
210 
211  if( nDuplicates )
212  {
213  char ascii = 0;
214  if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
215  ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
216 
217  MenuItemData* pFirstMatch = nullptr;
218  size_t nFirstPos(0);
219  for ( rPos = 0; rPos < nListCount; rPos++)
220  {
221  MenuItemData* pData = maItemList[ rPos ].get();
222  if ( pData->bEnabled )
223  {
224  sal_Int32 n = pData->aText.indexOf('~');
225  if ( n != -1 )
226  {
227  KeyCode nKeyCode;
228  sal_Unicode nUnicode = pData->aText[n+1];
229  vcl::Window* pDefWindow = ImplGetDefaultWindow();
230  if( ( pDefWindow
231  && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( nUnicode,
232  Application::GetSettings().GetUILanguageTag().getLanguageType(), nKeyCode )
233  && aKeyCode.GetCode() == nKeyCode.GetCode()
234  )
235  || ( ascii
236  && rI18nHelper.MatchMnemonic( pData->aText, ascii )
237  )
238  )
239  {
240  if (nDuplicates == 1)
241  return pData;
242  if (rPos > nCurrentPos)
243  return pData; // select next entry with the same mnemonic
244  if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
245  {
246  pFirstMatch = pData;
247  nFirstPos = rPos;
248  }
249  }
250  }
251  }
252  }
253  if (pFirstMatch)
254  {
255  rPos = nFirstPos;
256  return pFirstMatch;
257  }
258  }
259 
260  return nullptr;
261 }
262 
263 size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
264 {
265  // returns number of entries with same mnemonic
267 
268  size_t nItems = 0;
269  for ( size_t nPos = maItemList.size(); nPos; )
270  {
271  MenuItemData* pData = maItemList[ --nPos ].get();
272  if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
273  nItems++;
274  }
275 
276  return nItems;
277 }
278 
279 size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
280 {
281  // returns number of entries with same mnemonic
282  // uses key codes instead of character codes
284  char ascii = 0;
285  if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
286  ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
287 
288  size_t nItems = 0;
289  for ( size_t nPos = maItemList.size(); nPos; )
290  {
291  MenuItemData* pData = maItemList[ --nPos ].get();
292  if ( pData->bEnabled )
293  {
294  sal_Int32 n = pData->aText.indexOf('~');
295  if (n != -1)
296  {
297  KeyCode nKeyCode;
298  // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
299  // so we have working shortcuts when ascii mnemonics are used
300  vcl::Window* pDefWindow = ImplGetDefaultWindow();
301  if( ( pDefWindow
302  && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
304  && aKeyCode.GetCode() == nKeyCode.GetCode()
305  )
306  || ( ascii
307  && rI18nHelper.MatchMnemonic( pData->aText, ascii )
308  )
309  )
310  nItems++;
311  }
312  }
313  }
314 
315  return nItems;
316 }
317 
318 /* 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:715
constexpr sal_uInt16 KEY_A
Definition: keycodes.hxx:56
sal_Int64 n
virtual std::unique_ptr< SalMenuItem > CreateMenuItem(const SalItemParams &pItemData)
Definition: salvtables.cxx:126
sal_Int16 nId
sal_uInt16 GetCode() const
Definition: keycod.hxx:53
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
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:304
std::unique_ptr< SalMenuItem > pSalMenuItem
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), long nLogicWidth=0, const long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1241
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:848
Definition: menu.hxx:118
OString sIdent
Image aImage
Definition: salmenu.hxx:32
Definition: image.hxx:40
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:2218
vcl::Window * ImplGetDefaultWindow()
Returns either the application window, or the default GL context window.
Definition: svdata.cxx:210
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:382
sal_uInt16 nPos
MenuItemBits nBits