Bug Summary

File:home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx
Warning:line 1394, column 10
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name menu.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx

/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx

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 <tools/diagnose_ex.h>
21#include <sal/log.hxx>
22
23#include <comphelper/lok.hxx>
24#include <vcl/svapp.hxx>
25#include <vcl/mnemonic.hxx>
26#include <vcl/image.hxx>
27#include <vcl/event.hxx>
28#include <vcl/help.hxx>
29#include <vcl/floatwin.hxx>
30#include <vcl/decoview.hxx>
31#include <vcl/menu.hxx>
32#include <vcl/taskpanelist.hxx>
33#include <vcl/toolkit/controllayout.hxx>
34#include <vcl/settings.hxx>
35#include <vcl/commandinfoprovider.hxx>
36
37#include <salinst.hxx>
38#include <svdata.hxx>
39#include <strings.hrc>
40#include <window.h>
41#include <salmenu.hxx>
42#include <salframe.hxx>
43
44#include "menubarwindow.hxx"
45#include "menufloatingwindow.hxx"
46#include "menuitemlist.hxx"
47
48#include <com/sun/star/uno/Reference.h>
49#include <com/sun/star/lang/XComponent.hpp>
50#include <com/sun/star/accessibility/XAccessible.hpp>
51#include <vcl/toolkit/unowrap.hxx>
52#include <rtl/ustrbuf.hxx>
53
54#include <configsettings.hxx>
55
56#include <map>
57#include <string_view>
58#include <vector>
59
60namespace vcl
61{
62
63struct MenuLayoutData : public ControlLayoutData
64{
65 std::vector< sal_uInt16 > m_aLineItemIds;
66 std::map< sal_uInt16, tools::Rectangle > m_aVisibleItemBoundRects;
67};
68
69}
70
71using namespace vcl;
72
73#define EXTRAITEMHEIGHT4 4
74#define SPACE_AROUND_TITLE4 4
75
76static bool ImplAccelDisabled()
77{
78 // display of accelerator strings may be suppressed via configuration
79 static int nAccelDisabled = -1;
80
81 if( nAccelDisabled == -1 )
82 {
83 OUString aStr =
84 vcl::SettingsConfigItem::get()->
85 getValue( "Menu", "SuppressAccelerators" );
86 nAccelDisabled = aStr.equalsIgnoreAsciiCase("true") ? 1 : 0;
87 }
88 return nAccelDisabled == 1;
89}
90
91static void ImplSetMenuItemData( MenuItemData* pData )
92{
93 // convert data
94 if ( !pData->aImage )
95 pData->eType = MenuItemType::STRING;
96 else if ( pData->aText.isEmpty() )
97 pData->eType = MenuItemType::IMAGE;
98 else
99 pData->eType = MenuItemType::STRINGIMAGE;
100}
101
102namespace {
103
104void ImplClosePopupToolBox( const VclPtr<vcl::Window>& pWin )
105{
106 if ( pWin->GetType() == WindowType::TOOLBOX && ImplGetDockingManager()->IsInPopupMode( pWin ) )
107 {
108 ImplDockingWindowWrapper* pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pWin );
109 if ( pWrapper && pWrapper->GetFloatingWindow() )
110 pWrapper->GetFloatingWindow()->EndPopupMode( FloatWinPopupEndFlags::CloseAll );
111 }
112}
113
114// TODO: Move to common code with the same function in toolbox
115// Draw the ">>" - more indicator at the coordinates
116void lclDrawMoreIndicator(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
117{
118 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
119 rRenderContext.SetLineColor();
120
121 if (rRenderContext.GetSettings().GetStyleSettings().GetFaceColor().IsDark())
122 rRenderContext.SetFillColor(COL_WHITE);
123 else
124 rRenderContext.SetFillColor(COL_BLACK);
125 float fScaleFactor = rRenderContext.GetDPIScaleFactor();
126
127 int linewidth = 1 * fScaleFactor;
128 int space = 4 * fScaleFactor;
129
130 long width = 8 * fScaleFactor;
131 long height = 5 * fScaleFactor;
132
133 //Keep odd b/c drawing code works better
134 if ( height % 2 == 0 )
135 height--;
136
137 long heightOrig = height;
138
139 long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1;
140 long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1;
141 while( height >= 1)
142 {
143 rRenderContext.DrawRect( tools::Rectangle( x, y, x + linewidth, y ) );
144 x += space;
145 rRenderContext.DrawRect( tools::Rectangle( x, y, x + linewidth, y ) );
146 x -= space;
147 y++;
148 if( height <= heightOrig / 2 + 1) x--;
149 else x++;
150 height--;
151 }
152 rRenderContext.Pop();
153}
154
155} // end anonymous namespace
156
157
158Menu::Menu()
159 : mpFirstDel(nullptr),
160 pItemList(new MenuItemList),
161 pStartedFrom(nullptr),
162 pWindow(nullptr),
163 nTitleHeight(0),
164 nEventId(nullptr),
165 mnHighlightedItemPos(ITEMPOS_INVALID),
166 nMenuFlags(MenuFlags::NONE),
167 nSelectedId(0),
168 nImgOrChkPos(0),
169 nTextPos(0),
170 bCanceled(false),
171 bInCallback(false),
172 bKilled(false)
173{
174}
175
176Menu::~Menu()
177{
178 disposeOnce();
179}
180
181void Menu::dispose()
182{
183 ImplCallEventListeners( VclEventId::ObjectDying, ITEMPOS_INVALID );
184
185 // at the window free the reference to the accessible component
186 // and make sure the MenuFloatingWindow knows about our destruction
187 if ( pWindow )
188 {
189 MenuFloatingWindow* pFloat = static_cast<MenuFloatingWindow*>(pWindow.get());
190 if( pFloat->pMenu.get() == this )
191 pFloat->pMenu.clear();
192 pWindow->SetAccessible( css::uno::Reference< css::accessibility::XAccessible >() );
193 }
194
195 // dispose accessible components
196 if ( mxAccessible.is() )
197 {
198 css::uno::Reference< css::lang::XComponent> xComponent( mxAccessible, css::uno::UNO_QUERY );
199 if ( xComponent.is() )
200 xComponent->dispose();
201 }
202
203 if ( nEventId )
204 Application::RemoveUserEvent( nEventId );
205
206 // Notify deletion of this menu
207 ImplMenuDelData* pDelData = mpFirstDel;
208 while ( pDelData )
209 {
210 pDelData->mpMenu = nullptr;
211 pDelData = pDelData->mpNext;
212 }
213
214 bKilled = true;
215
216 pItemList->Clear();
217 mpLayoutData.reset();
218
219 // Native-support: destroy SalMenu
220 mpSalMenu.reset();
221
222 pStartedFrom.clear();
223 pWindow.clear();
224 VclReferenceBase::dispose();
225}
226
227void Menu::CreateAutoMnemonics()
228{
229 MnemonicGenerator aMnemonicGenerator;
230 size_t n;
231 for ( n = 0; n < pItemList->size(); n++ )
232 {
233 MenuItemData* pData = pItemList->GetDataFromPos( n );
234 if ( ! (pData->nBits & MenuItemBits::NOSELECT ) )
235 aMnemonicGenerator.RegisterMnemonic( pData->aText );
236 }
237 for ( n = 0; n < pItemList->size(); n++ )
238 {
239 MenuItemData* pData = pItemList->GetDataFromPos( n );
240 if ( ! (pData->nBits & MenuItemBits::NOSELECT ) )
241 pData->aText = aMnemonicGenerator.CreateMnemonic( pData->aText );
242 }
243}
244
245void Menu::Activate()
246{
247 bInCallback = true;
248
249 ImplMenuDelData aDelData( this );
250
251 ImplCallEventListeners( VclEventId::MenuActivate, ITEMPOS_INVALID );
252
253 if( !aDelData.isDeleted() )
254 {
255 if ( !aActivateHdl.Call( this ) )
256 {
257 if( !aDelData.isDeleted() )
258 {
259 Menu* pStartMenu = ImplGetStartMenu();
260 if ( pStartMenu && ( pStartMenu != this ) )
261 {
262 pStartMenu->bInCallback = true;
263 // MT 11/01: Call EventListener here? I don't know...
264 pStartMenu->aActivateHdl.Call( this );
265 pStartMenu->bInCallback = false;
266 }
267 }
268 }
269 bInCallback = false;
270 }
271
272 if (!aDelData.isDeleted() && !(nMenuFlags & MenuFlags::NoAutoMnemonics))
273 CreateAutoMnemonics();
274}
275
276void Menu::Deactivate()
277{
278 for ( size_t n = pItemList->size(); n; )
279 {
280 MenuItemData* pData = pItemList->GetDataFromPos( --n );
281 if ( pData->bIsTemporary )
282 {
283 if ( ImplGetSalMenu() )
284 ImplGetSalMenu()->RemoveItem( n );
285
286 pItemList->Remove( n );
287 }
288 }
289
290 bInCallback = true;
291
292 ImplMenuDelData aDelData( this );
293
294 Menu* pStartMenu = ImplGetStartMenu();
295 ImplCallEventListeners( VclEventId::MenuDeactivate, ITEMPOS_INVALID );
296
297 if( !aDelData.isDeleted() )
298 {
299 if ( !aDeactivateHdl.Call( this ) )
300 {
301 if( !aDelData.isDeleted() )
302 {
303 if ( pStartMenu && ( pStartMenu != this ) )
304 {
305 pStartMenu->bInCallback = true;
306 pStartMenu->aDeactivateHdl.Call( this );
307 pStartMenu->bInCallback = false;
308 }
309 }
310 }
311 }
312
313 if( !aDelData.isDeleted() )
314 {
315 bInCallback = false;
316 }
317}
318
319void Menu::ImplSelect()
320{
321 MenuItemData* pData = GetItemList()->GetData( nSelectedId );
322 if ( pData && (pData->nBits & MenuItemBits::AUTOCHECK) )
323 {
324 bool bChecked = IsItemChecked( nSelectedId );
325 if ( pData->nBits & MenuItemBits::RADIOCHECK )
326 {
327 if ( !bChecked )
328 CheckItem( nSelectedId );
329 }
330 else
331 CheckItem( nSelectedId, !bChecked );
332 }
333
334 // call select
335 ImplSVData* pSVData = ImplGetSVData();
336 pSVData->maAppData.mpActivePopupMenu = nullptr; // if new execute in select()
337 nEventId = Application::PostUserEvent( LINK( this, Menu, ImplCallSelect )::tools::detail::makeLink( ::tools::detail::castTo<Menu *>
(this), &Menu::LinkStubImplCallSelect)
);
338}
339
340void Menu::Select()
341{
342 ImplMenuDelData aDelData( this );
343
344 ImplCallEventListeners( VclEventId::MenuSelect, GetItemPos( GetCurItemId() ) );
345 if (aDelData.isDeleted())
346 return;
347 if (aSelectHdl.Call(this))
348 return;
349 if (aDelData.isDeleted())
350 return;
351 Menu* pStartMenu = ImplGetStartMenu();
352 if (!pStartMenu || (pStartMenu == this))
353 return;
354 pStartMenu->nSelectedId = nSelectedId;
355 pStartMenu->sSelectedIdent = sSelectedIdent;
356 pStartMenu->aSelectHdl.Call( this );
357}
358
359#if defined(MACOSX)
360void Menu::ImplSelectWithStart( Menu* pSMenu )
361{
362 auto pOldStartedFrom = pStartedFrom;
363 pStartedFrom = pSMenu;
364 auto pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : VclPtr<Menu>();
365 Select();
366 if( pOldStartedFrom )
367 pOldStartedFrom->pStartedFrom = pOldStartedStarted;
368 pStartedFrom = pOldStartedFrom;
369}
370#endif
371
372void Menu::ImplCallEventListeners( VclEventId nEvent, sal_uInt16 nPos )
373{
374 ImplMenuDelData aDelData( this );
375
376 VclMenuEvent aEvent( this, nEvent, nPos );
377
378 // This is needed by atk accessibility bridge
379 if ( nEvent == VclEventId::MenuHighlight )
380 {
381 Application::ImplCallEventListeners( aEvent );
382 }
383
384 if ( !aDelData.isDeleted() )
385 {
386 // Copy the list, because this can be destroyed when calling a Link...
387 std::list<Link<VclMenuEvent&,void>> aCopy( maEventListeners );
388 for ( const auto& rLink : aCopy )
389 {
390 if( std::find(maEventListeners.begin(), maEventListeners.end(), rLink) != maEventListeners.end() )
391 rLink.Call( aEvent );
392 }
393 }
394}
395
396void Menu::AddEventListener( const Link<VclMenuEvent&,void>& rEventListener )
397{
398 maEventListeners.push_back( rEventListener );
399}
400
401void Menu::RemoveEventListener( const Link<VclMenuEvent&,void>& rEventListener )
402{
403 maEventListeners.remove( rEventListener );
404}
405
406MenuItemData* Menu::NbcInsertItem(sal_uInt16 nId, MenuItemBits nBits,
407 const OUString& rStr, Menu* pMenu,
408 size_t nPos, const OString &rIdent)
409{
410 // put Item in MenuItemList
411 MenuItemData* pData = pItemList->Insert(nId, MenuItemType::STRING,
412 nBits, rStr, pMenu, nPos, rIdent);
413
414 // update native menu
415 if (ImplGetSalMenu() && pData->pSalMenuItem)
416 ImplGetSalMenu()->InsertItem(pData->pSalMenuItem.get(), nPos);
417
418 return pData;
419}
420
421void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr, MenuItemBits nItemBits,
422 const OString &rIdent, sal_uInt16 nPos)
423{
424 SAL_WARN_IF( !nItemId, "vcl", "Menu::InsertItem(): ItemId == 0" )do { if (true && (!nItemId)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Menu::InsertItem(): ItemId == 0"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "424" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId == 0"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId == 0"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "424" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::InsertItem(): ItemId == 0") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "424" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId == 0"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId == 0"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "424" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
425 SAL_WARN_IF( GetItemPos( nItemId ) != MENU_ITEM_NOTFOUND, "vcl",do { if (true && (GetItemPos( nItemId ) != MENU_ITEM_NOTFOUND
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::InsertItem(): ItemId already exists") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId already exists"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::InsertItem(): ItemId already exists") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId already exists"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
426 "Menu::InsertItem(): ItemId already exists" )do { if (true && (GetItemPos( nItemId ) != MENU_ITEM_NOTFOUND
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::InsertItem(): ItemId already exists") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId already exists"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::InsertItem(): ItemId already exists") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::InsertItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::InsertItem(): ItemId already exists"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "426" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
427
428 // if Position > ItemCount, append
429 if ( nPos >= pItemList->size() )
430 nPos = MENU_APPEND;
431
432 // put Item in MenuItemList
433 NbcInsertItem(nItemId, nItemBits, rStr, this, nPos, rIdent);
434
435 vcl::Window* pWin = ImplGetWindow();
436 mpLayoutData.reset();
437 if ( pWin )
438 {
439 ImplCalcSize( pWin );
440 if ( pWin->IsVisible() )
441 pWin->Invalidate();
442 }
443 ImplCallEventListeners( VclEventId::MenuInsertItem, nPos );
444}
445
446void Menu::InsertItem(sal_uInt16 nItemId, const Image& rImage,
447 MenuItemBits nItemBits, const OString &rIdent, sal_uInt16 nPos)
448{
449 InsertItem(nItemId, OUString(), nItemBits, rIdent, nPos);
450 SetItemImage( nItemId, rImage );
451}
452
453void Menu::InsertItem(sal_uInt16 nItemId, const OUString& rStr,
454 const Image& rImage, MenuItemBits nItemBits,
455 const OString &rIdent, sal_uInt16 nPos)
456{
457 InsertItem(nItemId, rStr, nItemBits, rIdent, nPos);
458 SetItemImage( nItemId, rImage );
459}
460
461void Menu::InsertItem(const OUString& rCommand, const css::uno::Reference<css::frame::XFrame>& rFrame)
462{
463 sal_uInt16 nItemId = GetItemCount() + 1;
464
465 if (rFrame.is())
466 {
467 OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame));
468 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCommand, aModuleName);
469 OUString aLabel(CommandInfoProvider::GetPopupLabelForCommand(aProperties));
470 OUString aTooltip(CommandInfoProvider::GetTooltipForCommand(rCommand, aProperties, rFrame));
471 Image aImage(CommandInfoProvider::GetImageForCommand(rCommand, rFrame));
472
473 InsertItem(nItemId, aLabel, aImage);
474 SetHelpText(nItemId, aTooltip);
475 }
476 else
477 InsertItem(nItemId, OUString());
478
479 SetItemCommand(nItemId, rCommand);
480}
481
482
483void Menu::InsertSeparator(const OString &rIdent, sal_uInt16 nPos)
484{
485 // do nothing if it's a menu bar
486 if (IsMenuBar())
487 return;
488
489 // if position > ItemCount, append
490 if ( nPos >= pItemList->size() )
491 nPos = MENU_APPEND;
492
493 // put separator in item list
494 pItemList->InsertSeparator(rIdent, nPos);
495
496 // update native menu
497 size_t itemPos = ( nPos != MENU_APPEND ) ? nPos : pItemList->size() - 1;
498 MenuItemData *pData = pItemList->GetDataFromPos( itemPos );
499 if( ImplGetSalMenu() && pData && pData->pSalMenuItem )
500 ImplGetSalMenu()->InsertItem( pData->pSalMenuItem.get(), nPos );
501
502 mpLayoutData.reset();
503
504 ImplCallEventListeners( VclEventId::MenuInsertItem, nPos );
505}
506
507void Menu::RemoveItem( sal_uInt16 nPos )
508{
509 bool bRemove = false;
510
511 if ( nPos < GetItemCount() )
512 {
513 // update native menu
514 if( ImplGetSalMenu() )
515 ImplGetSalMenu()->RemoveItem( nPos );
516
517 pItemList->Remove( nPos );
518 bRemove = true;
519 }
520
521 vcl::Window* pWin = ImplGetWindow();
522 if ( pWin )
523 {
524 ImplCalcSize( pWin );
525 if ( pWin->IsVisible() )
526 pWin->Invalidate();
527 }
528 mpLayoutData.reset();
529
530 if ( bRemove )
531 ImplCallEventListeners( VclEventId::MenuRemoveItem, nPos );
532}
533
534static void ImplCopyItem( Menu* pThis, const Menu& rMenu, sal_uInt16 nPos, sal_uInt16 nNewPos )
535{
536 MenuItemType eType = rMenu.GetItemType( nPos );
537
538 if ( eType == MenuItemType::DONTKNOW )
539 return;
540
541 if ( eType == MenuItemType::SEPARATOR )
542 pThis->InsertSeparator( OString(), nNewPos );
543 else
544 {
545 sal_uInt16 nId = rMenu.GetItemId( nPos );
546
547 SAL_WARN_IF( pThis->GetItemPos( nId ) != MENU_ITEM_NOTFOUND, "vcl",do { if (true && (pThis->GetItemPos( nId ) != MENU_ITEM_NOTFOUND
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::CopyItem(): ItemId already exists") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::CopyItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::CopyItem(): ItemId already exists"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::CopyItem(): ItemId already exists") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::CopyItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::CopyItem(): ItemId already exists"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
548 "Menu::CopyItem(): ItemId already exists" )do { if (true && (pThis->GetItemPos( nId ) != MENU_ITEM_NOTFOUND
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::CopyItem(): ItemId already exists") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::CopyItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::CopyItem(): ItemId already exists"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::CopyItem(): ItemId already exists") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::CopyItem(): ItemId already exists"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::CopyItem(): ItemId already exists"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "548" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
549
550 MenuItemData* pData = rMenu.GetItemList()->GetData( nId );
551
552 if (!pData)
553 return;
554
555 if ( eType == MenuItemType::STRINGIMAGE )
556 pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
557 else if ( eType == MenuItemType::STRING )
558 pThis->InsertItem( nId, pData->aText, pData->nBits, pData->sIdent, nNewPos );
559 else
560 pThis->InsertItem( nId, pData->aImage, pData->nBits, pData->sIdent, nNewPos );
561
562 if ( rMenu.IsItemChecked( nId ) )
563 pThis->CheckItem( nId );
564 if ( !rMenu.IsItemEnabled( nId ) )
565 pThis->EnableItem( nId, false );
566 pThis->SetHelpId( nId, pData->aHelpId );
567 pThis->SetHelpText( nId, pData->aHelpText );
568 pThis->SetAccelKey( nId, pData->aAccelKey );
569 pThis->SetItemCommand( nId, pData->aCommandStr );
570 pThis->SetHelpCommand( nId, pData->aHelpCommandStr );
571
572 PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId );
573 if ( pSubMenu )
574 {
575 // create auto-copy
576 VclPtr<PopupMenu> pNewMenu = VclPtr<PopupMenu>::Create( *pSubMenu );
577 pThis->SetPopupMenu( nId, pNewMenu );
578 }
579 }
580}
581
582void Menu::Clear()
583{
584 for ( sal_uInt16 i = GetItemCount(); i; i-- )
585 RemoveItem( 0 );
586}
587
588sal_uInt16 Menu::GetItemCount() const
589{
590 return static_cast<sal_uInt16>(pItemList->size());
591}
592
593sal_uInt16 Menu::ImplGetVisibleItemCount() const
594{
595 sal_uInt16 nItems = 0;
596 for ( size_t n = pItemList->size(); n; )
597 {
598 if ( ImplIsVisible( --n ) )
599 nItems++;
600 }
601 return nItems;
602}
603
604sal_uInt16 Menu::ImplGetFirstVisible() const
605{
606 for ( size_t n = 0; n < pItemList->size(); n++ )
607 {
608 if ( ImplIsVisible( n ) )
609 return n;
610 }
611 return ITEMPOS_INVALID;
612}
613
614sal_uInt16 Menu::ImplGetPrevVisible( sal_uInt16 nPos ) const
615{
616 for ( size_t n = nPos; n; )
617 {
618 if (ImplIsVisible(--n))
619 return n;
620 }
621 return ITEMPOS_INVALID;
622}
623
624sal_uInt16 Menu::ImplGetNextVisible( sal_uInt16 nPos ) const
625{
626 for ( size_t n = nPos+1; n < pItemList->size(); n++ )
627 {
628 if ( ImplIsVisible( n ) )
629 return n;
630 }
631 return ITEMPOS_INVALID;
632}
633
634sal_uInt16 Menu::GetItemId(sal_uInt16 nPos) const
635{
636 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
637
638 if ( pData )
639 return pData->nId;
640 else
641 return 0;
642}
643
644sal_uInt16 Menu::GetItemId(const OString &rIdent) const
645{
646 for (size_t n = 0; n < pItemList->size(); ++n)
647 {
648 MenuItemData* pData = pItemList->GetDataFromPos(n);
649 if (pData && pData->sIdent == rIdent)
650 return pData->nId;
651 }
652 return MENU_ITEM_NOTFOUND;
653}
654
655sal_uInt16 Menu::GetItemPos( sal_uInt16 nItemId ) const
656{
657 size_t nPos;
658 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
659
660 if ( pData )
661 return static_cast<sal_uInt16>(nPos);
662 else
663 return MENU_ITEM_NOTFOUND;
664}
665
666MenuItemType Menu::GetItemType( sal_uInt16 nPos ) const
667{
668 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
669
670 if ( pData )
671 return pData->eType;
672 else
673 return MenuItemType::DONTKNOW;
674}
675
676OString Menu::GetItemIdent(sal_uInt16 nId) const
677{
678 const MenuItemData* pData = pItemList->GetData(nId);
679 return pData ? pData->sIdent : OString();
680}
681
682void Menu::SetItemBits( sal_uInt16 nItemId, MenuItemBits nBits )
683{
684 size_t nPos;
685 MenuItemData* pData = pItemList->GetData(nItemId, nPos);
686
687 if (pData && (pData->nBits != nBits))
688 {
689 pData->nBits = nBits;
690
691 // update native menu
692 if (ImplGetSalMenu())
693 ImplGetSalMenu()->SetItemBits(nPos, nBits);
694 }
695}
696
697MenuItemBits Menu::GetItemBits( sal_uInt16 nItemId ) const
698{
699 MenuItemBits nBits = MenuItemBits::NONE;
700 MenuItemData* pData = pItemList->GetData( nItemId );
701 if ( pData )
702 nBits = pData->nBits;
703 return nBits;
704}
705
706void Menu::SetUserValue(sal_uInt16 nItemId, void* nUserValue, MenuUserDataReleaseFunction aFunc)
707{
708 MenuItemData* pData = pItemList->GetData(nItemId);
709 if (pData)
710 {
711 if (pData->aUserValueReleaseFunc)
712 pData->aUserValueReleaseFunc(pData->nUserValue);
713 pData->aUserValueReleaseFunc = aFunc;
714 pData->nUserValue = nUserValue;
715 }
716}
717
718void* Menu::GetUserValue( sal_uInt16 nItemId ) const
719{
720 MenuItemData* pData = pItemList->GetData( nItemId );
721 return pData ? pData->nUserValue : nullptr;
722}
723
724void Menu::SetPopupMenu( sal_uInt16 nItemId, PopupMenu* pMenu )
725{
726 size_t nPos;
727 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
728
729 // Item does not exist -> return NULL
730 if ( !pData )
731 return;
732
733 // same menu, nothing to do
734 if ( static_cast<PopupMenu*>(pData->pSubMenu.get()) == pMenu )
735 return;
736
737 // remove old menu
738 auto oldSubMenu = pData->pSubMenu;
739
740 // data exchange
741 pData->pSubMenu = pMenu;
742
743 // #112023# Make sure pStartedFrom does not point to invalid (old) data
744 if ( pData->pSubMenu )
745 pData->pSubMenu->pStartedFrom = nullptr;
746
747 // set native submenu
748 if( ImplGetSalMenu() && pData->pSalMenuItem )
749 {
750 if( pMenu )
751 ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem.get(), pMenu->ImplGetSalMenu(), nPos );
752 else
753 ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem.get(), nullptr, nPos );
754 }
755
756 oldSubMenu.disposeAndClear();
757
758 ImplCallEventListeners( VclEventId::MenuSubmenuChanged, nPos );
759}
760
761PopupMenu* Menu::GetPopupMenu( sal_uInt16 nItemId ) const
762{
763 MenuItemData* pData = pItemList->GetData( nItemId );
764
765 if ( pData )
766 return static_cast<PopupMenu*>(pData->pSubMenu.get());
767 else
768 return nullptr;
769}
770
771void Menu::SetAccelKey( sal_uInt16 nItemId, const KeyCode& rKeyCode )
772{
773 size_t nPos;
774 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
775
776 if ( !pData )
777 return;
778
779 if ( pData->aAccelKey == rKeyCode )
780 return;
781
782 pData->aAccelKey = rKeyCode;
783
784 // update native menu
785 if( ImplGetSalMenu() && pData->pSalMenuItem )
786 ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem.get(), rKeyCode, rKeyCode.GetName() );
787}
788
789KeyCode Menu::GetAccelKey( sal_uInt16 nItemId ) const
790{
791 MenuItemData* pData = pItemList->GetData( nItemId );
792
793 if ( pData )
794 return pData->aAccelKey;
795 else
796 return KeyCode();
797}
798
799KeyEvent Menu::GetActivationKey( sal_uInt16 nItemId ) const
800{
801 KeyEvent aRet;
802 MenuItemData* pData = pItemList->GetData( nItemId );
803 if( pData )
804 {
805 sal_Int32 nPos = pData->aText.indexOf( '~' );
806 if( nPos != -1 && nPos < pData->aText.getLength()-1 )
807 {
808 sal_uInt16 nCode = 0;
809 sal_Unicode cAccel = pData->aText[nPos+1];
810 if( cAccel >= 'a' && cAccel <= 'z' )
811 nCode = KEY_A + (cAccel-'a');
812 else if( cAccel >= 'A' && cAccel <= 'Z' )
813 nCode = KEY_A + (cAccel-'A');
814 else if( cAccel >= '0' && cAccel <= '9' )
815 nCode = KEY_0 + (cAccel-'0');
816
817 aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) );
818 }
819
820 }
821 return aRet;
822}
823
824void Menu::CheckItem( sal_uInt16 nItemId, bool bCheck )
825{
826 size_t nPos;
827 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
828
829 if ( !pData || pData->bChecked == bCheck )
830 return;
831
832 // if radio-check, then uncheck previous
833 if ( bCheck && (pData->nBits & MenuItemBits::AUTOCHECK) &&
834 (pData->nBits & MenuItemBits::RADIOCHECK) )
835 {
836 MenuItemData* pGroupData;
837 sal_uInt16 nGroupPos;
838 sal_uInt16 nItemCount = GetItemCount();
839 bool bFound = false;
840
841 nGroupPos = nPos;
842 while ( nGroupPos )
843 {
844 pGroupData = pItemList->GetDataFromPos( nGroupPos-1 );
845 if ( pGroupData->nBits & MenuItemBits::RADIOCHECK )
846 {
847 if ( IsItemChecked( pGroupData->nId ) )
848 {
849 CheckItem( pGroupData->nId, false );
850 bFound = true;
851 break;
852 }
853 }
854 else
855 break;
856 nGroupPos--;
857 }
858
859 if ( !bFound )
860 {
861 nGroupPos = nPos+1;
862 while ( nGroupPos < nItemCount )
863 {
864 pGroupData = pItemList->GetDataFromPos( nGroupPos );
865 if ( pGroupData->nBits & MenuItemBits::RADIOCHECK )
866 {
867 if ( IsItemChecked( pGroupData->nId ) )
868 {
869 CheckItem( pGroupData->nId, false );
870 break;
871 }
872 }
873 else
874 break;
875 nGroupPos++;
876 }
877 }
878 }
879
880 pData->bChecked = bCheck;
881
882 // update native menu
883 if( ImplGetSalMenu() )
884 ImplGetSalMenu()->CheckItem( nPos, bCheck );
885
886 ImplCallEventListeners( bCheck ? VclEventId::MenuItemChecked : VclEventId::MenuItemUnchecked, nPos );
887}
888
889void Menu::CheckItem( const OString &rIdent , bool bCheck )
890{
891 CheckItem( GetItemId( rIdent ), bCheck );
892}
893
894bool Menu::IsItemChecked( sal_uInt16 nItemId ) const
895{
896 size_t nPos;
897 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
898
899 if ( !pData )
900 return false;
901
902 return pData->bChecked;
903}
904
905void Menu::EnableItem( sal_uInt16 nItemId, bool bEnable )
906{
907 size_t nPos;
908 MenuItemData* pItemData = pItemList->GetData( nItemId, nPos );
909
910 if ( !(pItemData && ( pItemData->bEnabled != bEnable )) )
911 return;
912
913 pItemData->bEnabled = bEnable;
914
915 vcl::Window* pWin = ImplGetWindow();
916 if ( pWin && pWin->IsVisible() )
917 {
918 SAL_WARN_IF(!IsMenuBar(), "vcl", "Menu::EnableItem - Popup visible!" )do { if (true && (!IsMenuBar())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Menu::EnableItem - Popup visible!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "918" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::EnableItem - Popup visible!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::EnableItem - Popup visible!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "918" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::EnableItem - Popup visible!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "918" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::EnableItem - Popup visible!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::EnableItem - Popup visible!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "918" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
919 long nX = 0;
920 size_t nCount = pItemList->size();
921 for ( size_t n = 0; n < nCount; n++ )
922 {
923 MenuItemData* pData = pItemList->GetDataFromPos( n );
924 if ( n == nPos )
925 {
926 pWin->Invalidate( tools::Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) );
927 break;
928 }
929 nX += pData->aSz.Width();
930 }
931 }
932 // update native menu
933 if( ImplGetSalMenu() )
934 ImplGetSalMenu()->EnableItem( nPos, bEnable );
935
936 ImplCallEventListeners( bEnable ? VclEventId::MenuEnable : VclEventId::MenuDisable, nPos );
937}
938
939bool Menu::IsItemEnabled( sal_uInt16 nItemId ) const
940{
941 size_t nPos;
942 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
943
944 if ( !pData )
945 return false;
946
947 return pData->bEnabled;
948}
949
950void Menu::ShowItem( sal_uInt16 nItemId, bool bVisible )
951{
952 size_t nPos;
953 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
954
955 SAL_WARN_IF(IsMenuBar() && !bVisible , "vcl", "Menu::ShowItem - ignored for menu bar entries!")do { if (true && (IsMenuBar() && !bVisible)) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ShowItem - ignored for menu bar entries!")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "955" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::ShowItem - ignored for menu bar entries!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ShowItem - ignored for menu bar entries!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "955" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ShowItem - ignored for menu bar entries!")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "955" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::ShowItem - ignored for menu bar entries!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ShowItem - ignored for menu bar entries!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "955" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
956 if (IsMenuBar() || !pData || (pData->bVisible == bVisible))
957 return;
958
959 vcl::Window* pWin = ImplGetWindow();
960 if ( pWin && pWin->IsVisible() )
961 {
962 SAL_WARN( "vcl", "Menu::ShowItem - ignored for visible popups!" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ShowItem - ignored for visible popups!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "962" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::ShowItem - ignored for visible popups!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ShowItem - ignored for visible popups!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "962" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ShowItem - ignored for visible popups!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "962" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Menu::ShowItem - ignored for visible popups!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ShowItem - ignored for visible popups!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "962" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
963 return;
964 }
965 pData->bVisible = bVisible;
966
967 // update native menu
968 if( ImplGetSalMenu() )
969 ImplGetSalMenu()->ShowItem( nPos, bVisible );
970}
971
972void Menu::SetItemText( sal_uInt16 nItemId, const OUString& rStr )
973{
974 size_t nPos;
975 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
976
977 if ( !pData )
978 return;
979
980 if ( rStr == pData->aText )
981 return;
982
983 pData->aText = rStr;
984 // Clear layout for aText.
985 pData->aTextGlyphs.Invalidate();
986 ImplSetMenuItemData( pData );
987 // update native menu
988 if( ImplGetSalMenu() && pData->pSalMenuItem )
989 ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem.get(), rStr );
990
991 vcl::Window* pWin = ImplGetWindow();
992 mpLayoutData.reset();
993 if (pWin && IsMenuBar())
994 {
995 ImplCalcSize( pWin );
996 if ( pWin->IsVisible() )
997 pWin->Invalidate();
998 }
999
1000 ImplCallEventListeners( VclEventId::MenuItemTextChanged, nPos );
1001}
1002
1003OUString Menu::GetItemText( sal_uInt16 nItemId ) const
1004{
1005 size_t nPos;
1006 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1007
1008 if ( pData )
1009 return pData->aText;
1010
1011 return OUString();
1012}
1013
1014void Menu::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1015{
1016 size_t nPos;
1017 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1018
1019 if ( !pData )
1020 return;
1021
1022 pData->aImage = rImage;
1023 ImplSetMenuItemData( pData );
1024
1025 // update native menu
1026 if( ImplGetSalMenu() && pData->pSalMenuItem )
1027 ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem.get(), rImage );
1028}
1029
1030Image Menu::GetItemImage( sal_uInt16 nItemId ) const
1031{
1032 MenuItemData* pData = pItemList->GetData( nItemId );
1033
1034 if ( pData )
1035 return pData->aImage;
1036 else
1037 return Image();
1038}
1039
1040void Menu::SetItemCommand( sal_uInt16 nItemId, const OUString& rCommand )
1041{
1042 size_t nPos;
1043 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
1044
1045 if ( pData )
1046 pData->aCommandStr = rCommand;
1047}
1048
1049OUString Menu::GetItemCommand( sal_uInt16 nItemId ) const
1050{
1051 MenuItemData* pData = pItemList->GetData( nItemId );
1052
1053 if (pData)
1054 return pData->aCommandStr;
1055
1056 return OUString();
1057}
1058
1059void Menu::SetHelpCommand( sal_uInt16 nItemId, const OUString& rStr )
1060{
1061 MenuItemData* pData = pItemList->GetData( nItemId );
1062
1063 if ( pData )
1064 pData->aHelpCommandStr = rStr;
1065}
1066
1067OUString Menu::GetHelpCommand( sal_uInt16 nItemId ) const
1068{
1069 MenuItemData* pData = pItemList->GetData( nItemId );
1070
1071 if ( pData )
1072 return pData->aHelpCommandStr;
1073
1074 return OUString();
1075}
1076
1077void Menu::SetHelpText( sal_uInt16 nItemId, const OUString& rStr )
1078{
1079 MenuItemData* pData = pItemList->GetData( nItemId );
1080
1081 if ( pData )
1082 pData->aHelpText = rStr;
1083}
1084
1085OUString Menu::ImplGetHelpText( sal_uInt16 nItemId ) const
1086{
1087 MenuItemData* pData = pItemList->GetData( nItemId );
1088
1089 if ( pData && pData->aHelpText.isEmpty() &&
1090 (( !pData->aHelpId.isEmpty() ) || ( !pData->aCommandStr.isEmpty() )))
1091 {
1092 Help* pHelp = Application::GetHelp();
1093 if ( pHelp )
1094 {
1095 if (!pData->aCommandStr.isEmpty())
1096 pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, static_cast<weld::Widget*>(nullptr) );
1097 if (pData->aHelpText.isEmpty() && !pData->aHelpId.isEmpty())
1098 pData->aHelpText = pHelp->GetHelpText( OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)) ), static_cast<weld::Widget*>(nullptr) );
1099 }
1100 }
1101
1102 return OUString();
1103}
1104
1105OUString Menu::GetHelpText( sal_uInt16 nItemId ) const
1106{
1107 return ImplGetHelpText( nItemId );
1108}
1109
1110void Menu::SetTipHelpText( sal_uInt16 nItemId, const OUString& rStr )
1111{
1112 MenuItemData* pData = pItemList->GetData( nItemId );
1113
1114 if ( pData )
1115 pData->aTipHelpText = rStr;
1116}
1117
1118OUString Menu::GetTipHelpText( sal_uInt16 nItemId ) const
1119{
1120 MenuItemData* pData = pItemList->GetData( nItemId );
1121
1122 if ( pData )
1123 return pData->aTipHelpText;
1124
1125 return OUString();
1126}
1127
1128void Menu::SetHelpId( sal_uInt16 nItemId, const OString& rHelpId )
1129{
1130 MenuItemData* pData = pItemList->GetData( nItemId );
1131
1132 if ( pData )
1133 pData->aHelpId = rHelpId;
1134}
1135
1136OString Menu::GetHelpId( sal_uInt16 nItemId ) const
1137{
1138 OString aRet;
1139
1140 MenuItemData* pData = pItemList->GetData( nItemId );
1141
1142 if ( pData )
1143 {
1144 if ( !pData->aHelpId.isEmpty() )
1145 aRet = pData->aHelpId;
1146 else
1147 aRet = OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)) );
1148 }
1149
1150 return aRet;
1151}
1152
1153Menu& Menu::operator=( const Menu& rMenu )
1154{
1155 if(this == &rMenu)
1156 return *this;
1157
1158 // clean up
1159 Clear();
1160
1161 // copy items
1162 sal_uInt16 nCount = rMenu.GetItemCount();
1163 for ( sal_uInt16 i = 0; i < nCount; i++ )
1164 ImplCopyItem( this, rMenu, i, MENU_APPEND );
1165
1166 aActivateHdl = rMenu.aActivateHdl;
1167 aDeactivateHdl = rMenu.aDeactivateHdl;
1168 aSelectHdl = rMenu.aSelectHdl;
1169 aTitleText = rMenu.aTitleText;
1170 nTitleHeight = rMenu.nTitleHeight;
1171
1172 return *this;
1173}
1174
1175// Returns true if the item is completely hidden on the GUI and shouldn't
1176// be possible to interact with
1177bool Menu::ImplCurrentlyHiddenOnGUI(sal_uInt16 nPos) const
1178{
1179 MenuItemData* pData = pItemList->GetDataFromPos(nPos);
1180 if (pData)
1181 {
1182 MenuItemData* pPreviousData = pItemList->GetDataFromPos( nPos - 1 );
1183 if (pPreviousData && pPreviousData->bHiddenOnGUI)
1184 {
1185 return true;
1186 }
1187 }
1188 return false;
1189}
1190
1191bool Menu::ImplIsVisible( sal_uInt16 nPos ) const
1192{
1193 bool bVisible = true;
1194
1195 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1196 // check general visibility first
1197 if( pData && !pData->bVisible )
1198 bVisible = false;
1199
1200 if ( bVisible && pData && pData->eType == MenuItemType::SEPARATOR )
1201 {
1202 if( nPos == 0 ) // no separator should be shown at the very beginning
1203 bVisible = false;
1204 else
1205 {
1206 // always avoid adjacent separators
1207 size_t nCount = pItemList->size();
1208 size_t n;
1209 MenuItemData* pNextData = nullptr;
1210 // search next visible item
1211 for( n = nPos + 1; n < nCount; n++ )
1212 {
1213 pNextData = pItemList->GetDataFromPos( n );
1214 if( pNextData && pNextData->bVisible )
1215 {
1216 if( pNextData->eType == MenuItemType::SEPARATOR || ImplIsVisible(n) )
1217 break;
1218 }
1219 }
1220 if( n == nCount ) // no next visible item
1221 bVisible = false;
1222 // check for separator
1223 if( pNextData && pNextData->bVisible && pNextData->eType == MenuItemType::SEPARATOR )
1224 bVisible = false;
1225
1226 if( bVisible )
1227 {
1228 for( n = nPos; n > 0; n-- )
1229 {
1230 pNextData = pItemList->GetDataFromPos( n-1 );
1231 if( pNextData && pNextData->bVisible )
1232 {
1233 if( pNextData->eType != MenuItemType::SEPARATOR && ImplIsVisible(n-1) )
1234 break;
1235 }
1236 }
1237 if( n == 0 ) // no previous visible item
1238 bVisible = false;
1239 }
1240 }
1241 }
1242
1243 // not allowed for menubar, as I do not know
1244 // whether a menu-entry will disappear or will appear
1245 if (bVisible && !IsMenuBar() && (nMenuFlags & MenuFlags::HideDisabledEntries) &&
1246 !(nMenuFlags & MenuFlags::AlwaysShowDisabledEntries))
1247 {
1248 if( !pData ) // e.g. nPos == ITEMPOS_INVALID
1249 bVisible = false;
1250 else if ( pData->eType != MenuItemType::SEPARATOR ) // separators handled above
1251 {
1252 // tdf#86850 Always display clipboard functions
1253 if ( pData->aCommandStr == ".uno:Cut" || pData->aCommandStr == ".uno:Copy" || pData->aCommandStr == ".uno:Paste" )
1254 bVisible = true;
1255 else
1256 // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( true ) );
1257 bVisible = pData->bEnabled; // do not check submenus as they might be filled at Activate().
1258 }
1259 }
1260
1261 return bVisible;
1262}
1263
1264bool Menu::IsItemPosVisible( sal_uInt16 nItemPos ) const
1265{
1266 return IsMenuVisible() && ImplIsVisible( nItemPos );
1267}
1268
1269bool Menu::IsMenuVisible() const
1270{
1271 return pWindow && pWindow->IsReallyVisible();
1272}
1273
1274bool Menu::ImplIsSelectable( sal_uInt16 nPos ) const
1275{
1276 bool bSelectable = true;
1277
1278 MenuItemData* pData = pItemList->GetDataFromPos( nPos );
1279 // check general visibility first
1280 if ( pData && ( pData->nBits & MenuItemBits::NOSELECT ) )
1281 bSelectable = false;
1282
1283 return bSelectable;
1284}
1285
1286css::uno::Reference<css::accessibility::XAccessible> Menu::GetAccessible()
1287{
1288 // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets
1289 // overwritten and may contain a disposed object when the initial menubar gets set again. So use the
1290 // mxAccessible member only for sub menus.
1291 if ( pStartedFrom )
1292 {
1293 for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i )
1294 {
1295 sal_uInt16 nItemId = pStartedFrom->GetItemId( i );
1296 if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this )
1297 {
1298 css::uno::Reference<css::accessibility::XAccessible> xParent = pStartedFrom->GetAccessible();
1299 if ( xParent.is() )
1300 {
1301 css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext( xParent->getAccessibleContext() );
1302 if (xParentContext.is())
1303 return xParentContext->getAccessibleChild( i );
1304 }
1305 }
1306 }
1307 }
1308 else if ( !mxAccessible.is() )
1309 {
1310 UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
1311 if ( pWrapper )
1312 mxAccessible = pWrapper->CreateAccessible(this, IsMenuBar());
1313 }
1314
1315 return mxAccessible;
1316}
1317
1318void Menu::SetAccessible(const css::uno::Reference<css::accessibility::XAccessible>& rxAccessible )
1319{
1320 mxAccessible = rxAccessible;
1321}
1322
1323Size Menu::ImplGetNativeCheckAndRadioSize(vcl::RenderContext const & rRenderContext, long& rCheckHeight, long& rRadioHeight ) const
1324{
1325 long nCheckWidth = 0, nRadioWidth = 0;
1326 rCheckHeight = rRadioHeight = 0;
1327
1328 if (!IsMenuBar())
1329 {
1330 ImplControlValue aVal;
1331 tools::Rectangle aNativeBounds;
1332 tools::Rectangle aNativeContent;
1333
1334 tools::Rectangle aCtrlRegion(tools::Rectangle(Point(), Size(100, 15)));
1335 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::MenuItemCheckMark))
1336 {
1337 if (rRenderContext.GetNativeControlRegion(ControlType::MenuPopup, ControlPart::MenuItemCheckMark,
1338 aCtrlRegion, ControlState::ENABLED, aVal,
1339 aNativeBounds, aNativeContent))
1340 {
1341 rCheckHeight = aNativeBounds.GetHeight();
1342 nCheckWidth = aNativeContent.GetWidth();
1343 }
1344 }
1345 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::MenuItemRadioMark))
1346 {
1347 if (rRenderContext.GetNativeControlRegion(ControlType::MenuPopup, ControlPart::MenuItemRadioMark,
1348 aCtrlRegion, ControlState::ENABLED, aVal,
1349 aNativeBounds, aNativeContent))
1350 {
1351 rRadioHeight = aNativeBounds.GetHeight();
1352 nRadioWidth = aNativeContent.GetWidth();
1353 }
1354 }
1355 }
1356 return Size(std::max(nCheckWidth, nRadioWidth), std::max(rCheckHeight, rRadioHeight));
1357}
1358
1359bool Menu::ImplGetNativeSubmenuArrowSize(vcl::RenderContext const & rRenderContext, Size& rArrowSize, long& rArrowSpacing)
1360{
1361 ImplControlValue aVal;
1362 tools::Rectangle aCtrlRegion(tools::Rectangle(Point(), Size(100, 15)));
1363 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::SubmenuArrow))
1364 {
1365 tools::Rectangle aNativeContent;
1366 tools::Rectangle aNativeBounds;
1367 if (rRenderContext.GetNativeControlRegion(ControlType::MenuPopup, ControlPart::SubmenuArrow,
1368 aCtrlRegion, ControlState::ENABLED,
1369 aVal, aNativeBounds, aNativeContent))
1370 {
1371 Size aSize(aNativeContent.GetWidth(), aNativeContent.GetHeight());
1372 rArrowSize = aSize;
1373 rArrowSpacing = aNativeBounds.GetWidth() - aNativeContent.GetWidth();
1374 return true;
1375 }
1376 }
1377 return false;
1378}
1379
1380void Menu::ImplAddDel( ImplMenuDelData& rDel )
1381{
1382 SAL_WARN_IF( rDel.mpMenu, "vcl", "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" )do { if (true && (rDel.mpMenu)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1382" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1382" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1383 if( !rDel.mpMenu )
1384 {
1385 rDel.mpMenu = this;
1386 rDel.mpNext = mpFirstDel;
1387 mpFirstDel = &rDel;
1388 }
1389}
1390
1391void Menu::ImplRemoveDel( ImplMenuDelData& rDel )
1392{
1393 rDel.mpMenu = nullptr;
3
Calling 'VclPtr::operator='
13
Returning; memory was released
1394 if ( mpFirstDel == &rDel )
14
Use of memory after it is freed
1395 {
1396 mpFirstDel = rDel.mpNext;
1397 }
1398 else
1399 {
1400 ImplMenuDelData* pData = mpFirstDel;
1401 while ( pData && (pData->mpNext != &rDel) )
1402 pData = pData->mpNext;
1403
1404 SAL_WARN_IF( !pData, "vcl", "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" )do { if (true && (!pData)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1404" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1404" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1404" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Menu::ImplRemoveDel(): ImplMenuDelData not registered !"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "1404" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1405 if( pData )
1406 pData->mpNext = rDel.mpNext;
1407 }
1408}
1409
1410Size Menu::ImplCalcSize( vcl::Window* pWin )
1411{
1412 // | Check/Radio/Image| Text| Accel/Popup|
1413
1414 // for symbols: nFontHeight x nFontHeight
1415 long nFontHeight = pWin->GetTextHeight();
1416 long nExtra = nFontHeight/4;
1417
1418 long nMinMenuItemHeight = nFontHeight;
1419 long nCheckHeight = 0, nRadioHeight = 0;
1420 Size aMaxSize = ImplGetNativeCheckAndRadioSize(*pWin, nCheckHeight, nRadioHeight); // FIXME
1421 if( aMaxSize.Height() > nMinMenuItemHeight )
1422 nMinMenuItemHeight = aMaxSize.Height();
1423
1424 Size aMaxImgSz;
1425
1426 const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings();
1427 if ( rSettings.GetUseImagesInMenus() )
1428 {
1429 if ( 16 > nMinMenuItemHeight )
1430 nMinMenuItemHeight = 16;
1431 for ( size_t i = pItemList->size(); i; )
1432 {
1433 MenuItemData* pData = pItemList->GetDataFromPos( --i );
1434 if ( ImplIsVisible( i )
1435 && ( ( pData->eType == MenuItemType::IMAGE )
1436 || ( pData->eType == MenuItemType::STRINGIMAGE )
1437 )
1438 )
1439 {
1440 Size aImgSz = pData->aImage.GetSizePixel();
1441 if ( aImgSz.Height() > aMaxImgSz.Height() )
1442 aMaxImgSz.setHeight( aImgSz.Height() );
1443 if ( aImgSz.Height() > nMinMenuItemHeight )
1444 nMinMenuItemHeight = aImgSz.Height();
1445 break;
1446 }
1447 }
1448 }
1449
1450 Size aSz;
1451 long nCheckWidth = 0;
1452 long nMaxWidth = 0;
1453
1454 for ( size_t n = pItemList->size(); n; )
1455 {
1456 MenuItemData* pData = pItemList->GetDataFromPos( --n );
1457
1458 pData->aSz.setHeight( 0 );
1459 pData->aSz.setWidth( 0 );
1460
1461 if ( ImplIsVisible( n ) )
1462 {
1463 long nWidth = 0;
1464
1465 // Separator
1466 if (!IsMenuBar()&& (pData->eType == MenuItemType::SEPARATOR))
1467 {
1468 pData->aSz.setHeight( 4 );
1469 }
1470
1471 // Image:
1472 if (!IsMenuBar() && ((pData->eType == MenuItemType::IMAGE) || (pData->eType == MenuItemType::STRINGIMAGE)))
1473 {
1474 Size aImgSz = pData->aImage.GetSizePixel();
1475
1476 aImgSz.AdjustHeight(4 ); // add a border for native marks
1477 aImgSz.AdjustWidth(4 ); // add a border for native marks
1478 if ( aImgSz.Width() > aMaxImgSz.Width() )
1479 aMaxImgSz.setWidth( aImgSz.Width() );
1480 if ( aImgSz.Height() > aMaxImgSz.Height() )
1481 aMaxImgSz.setHeight( aImgSz.Height() );
1482 if ( aImgSz.Height() > pData->aSz.Height() )
1483 pData->aSz.setHeight( aImgSz.Height() );
1484 }
1485
1486 // Check Buttons:
1487 if (!IsMenuBar() && pData->HasCheck())
1488 {
1489 nCheckWidth = aMaxSize.Width();
1490 // checks / images take the same place
1491 if( ( pData->eType != MenuItemType::IMAGE ) && ( pData->eType != MenuItemType::STRINGIMAGE ) )
1492 nWidth += nCheckWidth + nExtra * 2;
1493 }
1494
1495 // Text:
1496 if ( (pData->eType == MenuItemType::STRING) || (pData->eType == MenuItemType::STRINGIMAGE) )
1497 {
1498 const SalLayoutGlyphs* pGlyphs = pData->GetTextGlyphs(pWin);
1499 long nTextWidth = pWin->GetCtrlTextWidth(pData->aText, pGlyphs);
1500 long nTextHeight = pWin->GetTextHeight();
1501
1502 if (IsMenuBar())
1503 {
1504 if ( nTextHeight > pData->aSz.Height() )
1505 pData->aSz.setHeight( nTextHeight );
1506
1507 pData->aSz.setWidth( nTextWidth + 4*nExtra );
1508 aSz.AdjustWidth(pData->aSz.Width() );
1509 }
1510 else
1511 pData->aSz.setHeight( std::max( std::max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight ) );
1512
1513 nWidth += nTextWidth;
1514 }
1515
1516 // Accel
1517 if (!IsMenuBar()&& pData->aAccelKey.GetCode() && !ImplAccelDisabled())
1518 {
1519 OUString aName = pData->aAccelKey.GetName();
1520 long nAccWidth = pWin->GetTextWidth( aName );
1521 nAccWidth += nExtra;
1522 nWidth += nAccWidth;
1523 }
1524
1525 // SubMenu?
1526 if (!IsMenuBar() && pData->pSubMenu)
1527 {
1528 if ( nFontHeight > nWidth )
1529 nWidth += nFontHeight;
1530
1531 pData->aSz.setHeight( std::max( std::max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight ) );
1532 }
1533
1534 pData->aSz.AdjustHeight(EXTRAITEMHEIGHT4 ); // little bit more distance
1535
1536 if (!IsMenuBar())
1537 aSz.AdjustHeight(pData->aSz.Height() );
1538
1539 if ( nWidth > nMaxWidth )
1540 nMaxWidth = nWidth;
1541
1542 }
1543 }
1544
1545 // Additional space for title
1546 nTitleHeight = 0;
1547 if (!IsMenuBar() && aTitleText.getLength() > 0) {
1548 // Set expected font
1549 pWin->Push(PushFlags::FONT);
1550 vcl::Font aFont = pWin->GetFont();
1551 aFont.SetWeight(WEIGHT_BOLD);
1552 pWin->SetFont(aFont);
1553
1554 // Compute text bounding box
1555 tools::Rectangle aTextBoundRect;
1556 pWin->GetTextBoundRect(aTextBoundRect, aTitleText);
1557
1558 // Vertically, one height of char + extra space for decoration
1559 nTitleHeight = aTextBoundRect.GetSize().Height() + 4 * SPACE_AROUND_TITLE4 ;
1560 aSz.AdjustHeight(nTitleHeight );
1561
1562 long nWidth = aTextBoundRect.GetSize().Width() + 4 * SPACE_AROUND_TITLE4;
1563 pWin->Pop();
1564 if ( nWidth > nMaxWidth )
1565 nMaxWidth = nWidth;
1566 }
1567
1568 if (!IsMenuBar())
1569 {
1570 // popup menus should not be wider than half the screen
1571 // except on rather small screens
1572 // TODO: move GetScreenNumber from SystemWindow to Window ?
1573 // currently we rely on internal privileges
1574 unsigned int nDisplayScreen = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nDisplayScreenNumber;
1575 tools::Rectangle aDispRect( Application::GetScreenPosSizePixel( nDisplayScreen ) );
1576 long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800;
1577 if( nMaxWidth > nScreenWidth/2 )
1578 nMaxWidth = nScreenWidth/2;
1579
1580 sal_uInt16 gfxExtra = static_cast<sal_uInt16>(std::max( nExtra, 7L )); // #107710# increase space between checkmarks/images/text
1581 nImgOrChkPos = static_cast<sal_uInt16>(nExtra);
1582 long nImgOrChkWidth = 0;
1583 if( aMaxSize.Height() > 0 ) // NWF case
1584 nImgOrChkWidth = aMaxSize.Height() + nExtra;
1585 else // non NWF case
1586 nImgOrChkWidth = nFontHeight/2 + gfxExtra;
1587 nImgOrChkWidth = std::max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra );
1588 nTextPos = static_cast<sal_uInt16>(nImgOrChkPos + nImgOrChkWidth);
1589 nTextPos = nTextPos + gfxExtra;
1590
1591 aSz.setWidth( nTextPos + nMaxWidth + nExtra );
1592 aSz.AdjustWidth(4*nExtra ); // a _little_ more ...
1593
1594 aSz.AdjustWidth(2*ImplGetSVData()->maNWFData.mnMenuFormatBorderX );
1595 aSz.AdjustHeight(2*ImplGetSVData()->maNWFData.mnMenuFormatBorderY );
1596 }
1597 else
1598 {
1599 nTextPos = static_cast<sal_uInt16>(2*nExtra);
1600 aSz.setHeight( nFontHeight+6 );
1601
1602 // get menubar height from native methods if supported
1603 if( pWindow->IsNativeControlSupported( ControlType::Menubar, ControlPart::Entire ) )
1604 {
1605 ImplControlValue aVal;
1606 tools::Rectangle aNativeBounds;
1607 tools::Rectangle aNativeContent;
1608 Point tmp( 0, 0 );
1609 tools::Rectangle aCtrlRegion( tmp, Size( 100, 15 ) );
1610 if( pWindow->GetNativeControlRegion( ControlType::Menubar,
1611 ControlPart::Entire,
1612 aCtrlRegion,
1613 ControlState::ENABLED,
1614 aVal,
1615 aNativeBounds,
1616 aNativeContent )
1617 )
1618 {
1619 int nNativeHeight = aNativeBounds.GetHeight();
1620 if( nNativeHeight > aSz.Height() )
1621 aSz.setHeight( nNativeHeight );
1622 }
1623 }
1624
1625 // account for the size of the close button, which actually is a toolbox
1626 // due to NWF this is variable
1627 long nCloseButtonHeight = static_cast<MenuBarWindow*>(pWindow.get())->MinCloseButtonSize().Height();
1628 if (aSz.Height() < nCloseButtonHeight)
1629 aSz.setHeight( nCloseButtonHeight );
1630 }
1631
1632 return aSz;
1633}
1634
1635static void ImplPaintCheckBackground(vcl::RenderContext & rRenderContext, vcl::Window const & rWindow, const tools::Rectangle& i_rRect, bool i_bHighlight)
1636{
1637 bool bNativeOk = false;
1638 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ControlPart::Button))
1639 {
1640 ImplControlValue aControlValue;
1641 aControlValue.setTristateVal(ButtonValue::On);
1642
1643 bNativeOk = rRenderContext.DrawNativeControl(ControlType::Toolbar, ControlPart::Button,
1644 i_rRect,
1645 ControlState::PRESSED | ControlState::ENABLED,
1646 aControlValue,
1647 OUString());
1648 }
1649
1650 if (!bNativeOk)
1651 {
1652 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1653 Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() );
1654 RenderTools::DrawSelectionBackground(rRenderContext, rWindow, i_rRect, 0, i_bHighlight, true, false, nullptr, 2, &aColor);
1655 }
1656}
1657
1658static OUString getShortenedString( const OUString& i_rLong, vcl::RenderContext const & rRenderContext, long i_nMaxWidth )
1659{
1660 sal_Int32 nPos = -1;
1661 OUString aNonMnem(OutputDevice::GetNonMnemonicString(i_rLong, nPos));
1662 aNonMnem = rRenderContext.GetEllipsisString( aNonMnem, i_nMaxWidth, DrawTextFlags::CenterEllipsis);
1663 // re-insert mnemonic
1664 if (nPos != -1)
1665 {
1666 if (nPos < aNonMnem.getLength() && i_rLong[nPos+1] == aNonMnem[nPos])
1667 {
1668 OUStringBuffer aBuf( i_rLong.getLength() );
1669 aBuf.append( std::u16string_view(aNonMnem).substr(0, nPos) );
1670 aBuf.append( '~' );
1671 aBuf.append( std::u16string_view(aNonMnem).substr(nPos) );
1672 aNonMnem = aBuf.makeStringAndClear();
1673 }
1674 }
1675 return aNonMnem;
1676}
1677
1678void Menu::ImplPaintMenuTitle(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) const
1679{
1680 // Save previous graphical settings, set new one
1681 rRenderContext.Push(PushFlags::FONT | PushFlags::FILLCOLOR);
1682 Wallpaper aOldBackground = rRenderContext.GetBackground();
1683
1684 Color aBackgroundColor = rRenderContext.GetSettings().GetStyleSettings().GetMenuBarColor();
1685 rRenderContext.SetBackground(Wallpaper(aBackgroundColor));
1686 rRenderContext.SetFillColor(aBackgroundColor);
1687 vcl::Font aFont = rRenderContext.GetFont();
1688 aFont.SetWeight(WEIGHT_BOLD);
1689 rRenderContext.SetFont(aFont);
1690
1691 // Draw background rectangle
1692 tools::Rectangle aBgRect(rRect);
1693 int nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
1694 aBgRect.setX(aBgRect.getX() + SPACE_AROUND_TITLE4);
1695 aBgRect.setWidth(aBgRect.getWidth() - 2 * SPACE_AROUND_TITLE4 - 2 * nOuterSpaceX);
1696 aBgRect.setY(aBgRect.getY() + SPACE_AROUND_TITLE4);
1697 aBgRect.setHeight(nTitleHeight - 2 * SPACE_AROUND_TITLE4);
1698 rRenderContext.DrawRect(aBgRect);
1699
1700 // Draw the text centered
1701 Point aTextTopLeft(aBgRect.TopLeft());
1702 tools::Rectangle aTextBoundRect;
1703 rRenderContext.GetTextBoundRect( aTextBoundRect, aTitleText );
1704 aTextTopLeft.AdjustX((aBgRect.getWidth() - aTextBoundRect.GetSize().Width()) / 2 );
1705 aTextTopLeft.AdjustY((aBgRect.GetHeight() - aTextBoundRect.GetSize().Height()) / 2
1706 - aTextBoundRect.TopLeft().Y() );
1707 rRenderContext.DrawText(aTextTopLeft, aTitleText, 0, aTitleText.getLength());
1708
1709 // Restore
1710 rRenderContext.Pop();
1711 rRenderContext.SetBackground(aOldBackground);
1712}
1713
1714void Menu::ImplPaint(vcl::RenderContext& rRenderContext, Size const & rSize,
1715 sal_uInt16 nBorder, long nStartY, MenuItemData const * pThisItemOnly,
1716 bool bHighlighted, bool bLayout, bool bRollover) const
1717{
1718 // for symbols: nFontHeight x nFontHeight
1719 long nFontHeight = rRenderContext.GetTextHeight();
1720 long nExtra = nFontHeight / 4;
1721
1722 long nCheckHeight = 0, nRadioHeight = 0;
1723 ImplGetNativeCheckAndRadioSize(rRenderContext, nCheckHeight, nRadioHeight);
1724
1725 DecorationView aDecoView(&rRenderContext);
1726 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1727
1728 Point aTopLeft, aTmpPos;
1729
1730 int nOuterSpaceX = 0;
1731 if (!IsMenuBar())
1732 {
1733 nOuterSpaceX = ImplGetSVData()->maNWFData.mnMenuFormatBorderX;
1734 aTopLeft.AdjustX(nOuterSpaceX );
1735 aTopLeft.AdjustY(ImplGetSVData()->maNWFData.mnMenuFormatBorderY );
1736 }
1737
1738 // for the computations, use size of the underlying window, not of RenderContext
1739 Size aOutSz(rSize);
1740
1741 size_t nCount = pItemList->size();
1742 if (bLayout)
1743 mpLayoutData->m_aVisibleItemBoundRects.clear();
1744
1745 // Paint title
1746 if (!pThisItemOnly && !IsMenuBar() && nTitleHeight > 0)
1747 ImplPaintMenuTitle(rRenderContext, tools::Rectangle(aTopLeft, aOutSz));
1748
1749 bool bHiddenItems = false; // are any items on the GUI hidden
1750
1751 for (size_t n = 0; n < nCount; n++)
1752 {
1753 MenuItemData* pData = pItemList->GetDataFromPos( n );
1754 if (ImplIsVisible(n) && (!pThisItemOnly || (pData == pThisItemOnly)))
1755 {
1756 if (pThisItemOnly)
1757 {
1758 if (IsMenuBar())
1759 {
1760 if (!ImplGetSVData()->maNWFData.mbRolloverMenubar)
1761 {
1762 if (bRollover)
1763 rRenderContext.SetTextColor(rSettings.GetMenuBarRolloverTextColor());
1764 else if (bHighlighted)
1765 rRenderContext.SetTextColor(rSettings.GetMenuBarHighlightTextColor());
1766 }
1767 else
1768 {
1769 if (bHighlighted)
1770 rRenderContext.SetTextColor(rSettings.GetMenuBarHighlightTextColor());
1771 else if (bRollover)
1772 rRenderContext.SetTextColor(rSettings.GetMenuBarRolloverTextColor());
1773 }
1774 if (!bRollover && !bHighlighted)
1775 rRenderContext.SetTextColor(rSettings.GetMenuBarTextColor());
1776 }
1777 else if (bHighlighted)
1778 rRenderContext.SetTextColor(rSettings.GetMenuHighlightTextColor());
1779 }
1780
1781 Point aPos(aTopLeft);
1782 aPos.AdjustY(nBorder );
1783 aPos.AdjustY(nStartY );
1784
1785 if (aPos.Y() >= 0)
1786 {
1787 long nTextOffsetY = (pData->aSz.Height() - nFontHeight) / 2;
1788 if (IsMenuBar())
1789 nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2;
1790 DrawTextFlags nTextStyle = DrawTextFlags::NONE;
1791 DrawSymbolFlags nSymbolStyle = DrawSymbolFlags::NONE;
1792 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
1793
1794 // submenus without items are not disabled when no items are
1795 // contained. The application itself should check for this!
1796 // Otherwise it could happen entries are disabled due to
1797 // asynchronous loading
1798 if (!pData->bEnabled || !pWindow->IsEnabled())
1799 {
1800 nTextStyle |= DrawTextFlags::Disable;
1801 nSymbolStyle |= DrawSymbolFlags::Disable;
1802 nImageStyle |= DrawImageFlags::Disable;
1803 }
1804
1805 // Separator
1806 if (!bLayout && !IsMenuBar() && (pData->eType == MenuItemType::SEPARATOR))
1807 {
1808 bool bNativeOk = false;
1809 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Separator))
1810 {
1811 ControlState nState = ControlState::NONE;
1812 if (pData->bEnabled && pWindow->IsEnabled())
1813 nState |= ControlState::ENABLED;
1814 if (bHighlighted)
1815 nState |= ControlState::SELECTED;
1816 Size aSz(pData->aSz);
1817 aSz.setWidth( aOutSz.Width() - 2*nOuterSpaceX );
1818 tools::Rectangle aItemRect(aPos, aSz);
1819 MenupopupValue aVal(nTextPos - GUTTERBORDER8, aItemRect);
1820 bNativeOk = rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::Separator,
1821 aItemRect, nState, aVal, OUString());
1822 }
1823 if (!bNativeOk)
1824 {
1825 aTmpPos.setY( aPos.Y() + ((pData->aSz.Height() - 2) / 2) );
1826 aTmpPos.setX( aPos.X() + 2 + nOuterSpaceX );
1827 rRenderContext.SetLineColor(rSettings.GetShadowColor());
1828 rRenderContext.DrawLine(aTmpPos, Point(aOutSz.Width() - 3 - 2 * nOuterSpaceX, aTmpPos.Y()));
1829 aTmpPos.AdjustY( 1 );
1830 rRenderContext.SetLineColor(rSettings.GetLightColor());
1831 rRenderContext.DrawLine(aTmpPos, Point(aOutSz.Width() - 3 - 2 * nOuterSpaceX, aTmpPos.Y()));
1832 rRenderContext.SetLineColor();
1833 }
1834 }
1835
1836 tools::Rectangle aOuterCheckRect(Point(aPos.X()+nImgOrChkPos, aPos.Y()),
1837 Size(pData->aSz.Height(), pData->aSz.Height()));
1838 aOuterCheckRect.AdjustLeft(1 );
1839 aOuterCheckRect.AdjustRight( -1 );
1840 aOuterCheckRect.AdjustTop(1 );
1841 aOuterCheckRect.AdjustBottom( -1 );
1842
1843 // CheckMark
1844 if (!bLayout && !IsMenuBar() && pData->HasCheck())
1845 {
1846 // draw selection transparent marker if checked
1847 // onto that either a checkmark or the item image
1848 // will be painted
1849 // however do not do this if native checks will be painted since
1850 // the selection color too often does not fit the theme's check and/or radio
1851
1852 if( (pData->eType != MenuItemType::IMAGE) && (pData->eType != MenuItemType::STRINGIMAGE))
1853 {
1854 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup,
1855 (pData->nBits & MenuItemBits::RADIOCHECK)
1856 ? ControlPart::MenuItemCheckMark
1857 : ControlPart::MenuItemRadioMark))
1858 {
1859 ControlPart nPart = ((pData->nBits & MenuItemBits::RADIOCHECK)
1860 ? ControlPart::MenuItemRadioMark
1861 : ControlPart::MenuItemCheckMark);
1862
1863 ControlState nState = ControlState::NONE;
1864
1865 if (pData->bChecked)
1866 nState |= ControlState::PRESSED;
1867
1868 if (pData->bEnabled && pWindow->IsEnabled())
1869 nState |= ControlState::ENABLED;
1870
1871 if (bHighlighted)
1872 nState |= ControlState::SELECTED;
1873
1874 long nCtrlHeight = (pData->nBits & MenuItemBits::RADIOCHECK) ? nCheckHeight : nRadioHeight;
1875 aTmpPos.setX( aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight) / 2 );
1876 aTmpPos.setY( aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight) / 2 );
1877
1878 tools::Rectangle aCheckRect(aTmpPos, Size(nCtrlHeight, nCtrlHeight));
1879 Size aSz(pData->aSz);
1880 aSz.setWidth( aOutSz.Width() - 2 * nOuterSpaceX );
1881 tools::Rectangle aItemRect(aPos, aSz);
1882 MenupopupValue aVal(nTextPos - GUTTERBORDER8, aItemRect);
1883 rRenderContext.DrawNativeControl(ControlType::MenuPopup, nPart, aCheckRect,
1884 nState, aVal, OUString());
1885 }
1886 else if (pData->bChecked) // by default do nothing for unchecked items
1887 {
1888 ImplPaintCheckBackground(rRenderContext, *pWindow, aOuterCheckRect, pThisItemOnly && bHighlighted);
1889
1890 SymbolType eSymbol;
1891 Size aSymbolSize;
1892 if (pData->nBits & MenuItemBits::RADIOCHECK)
1893 {
1894 eSymbol = SymbolType::RADIOCHECKMARK;
1895 aSymbolSize = Size(nFontHeight / 2, nFontHeight / 2);
1896 }
1897 else
1898 {
1899 eSymbol = SymbolType::CHECKMARK;
1900 aSymbolSize = Size((nFontHeight * 25) / 40, nFontHeight / 2);
1901 }
1902 aTmpPos.setX( aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width()) / 2 );
1903 aTmpPos.setY( aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height()) / 2 );
1904 tools::Rectangle aRect(aTmpPos, aSymbolSize);
1905 aDecoView.DrawSymbol(aRect, eSymbol, rRenderContext.GetTextColor(), nSymbolStyle);
1906 }
1907 }
1908 }
1909
1910 // Image:
1911 if (!bLayout && !IsMenuBar() && ((pData->eType == MenuItemType::IMAGE) || (pData->eType == MenuItemType::STRINGIMAGE)))
1912 {
1913 // Don't render an image for a check thing
1914 if (pData->bChecked)
1915 ImplPaintCheckBackground(rRenderContext, *pWindow, aOuterCheckRect, pThisItemOnly && bHighlighted);
1916
1917 Image aImage = pData->aImage;
1918
1919 aTmpPos = aOuterCheckRect.TopLeft();
1920 aTmpPos.AdjustX((aOuterCheckRect.GetWidth() - aImage.GetSizePixel().Width()) / 2 );
1921 aTmpPos.AdjustY((aOuterCheckRect.GetHeight() - aImage.GetSizePixel().Height()) / 2 );
1922 rRenderContext.DrawImage(aTmpPos, aImage, nImageStyle);
1923 }
1924
1925 // Text:
1926 if ((pData->eType == MenuItemType::STRING ) || (pData->eType == MenuItemType::STRINGIMAGE))
1927 {
1928 aTmpPos.setX( aPos.X() + nTextPos );
1929 aTmpPos.setY( aPos.Y() );
1930 aTmpPos.AdjustY(nTextOffsetY );
1931 DrawTextFlags nStyle = nTextStyle | DrawTextFlags::Mnemonic;
1932
1933 const Menu *pMenu = this;
1934 while (!pMenu->IsMenuBar() && pMenu->pStartedFrom)
1935 pMenu = pMenu->pStartedFrom;
1936 if (pMenu->IsMenuBar() && static_cast<MenuBarWindow*>(pMenu->pWindow.get())->GetMBWHideAccel())
1937 nStyle |= DrawTextFlags::HideMnemonic;
1938
1939 if (pData->bIsTemporary)
1940 nStyle |= DrawTextFlags::Disable;
1941 MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : nullptr;
1942 OUString* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : nullptr;
1943 if (bLayout)
1944 {
1945 mpLayoutData->m_aLineIndices.push_back(mpLayoutData->m_aDisplayText.getLength());
1946 mpLayoutData->m_aLineItemIds.push_back(pData->nId);
1947 }
1948 // #i47946# with NWF painted menus the background is transparent
1949 // since DrawCtrlText can depend on the background (e.g. for
1950 // DrawTextFlags::Disable), temporarily set a background which
1951 // hopefully matches the NWF background since it is read
1952 // from the system style settings
1953 bool bSetTmpBackground = !rRenderContext.IsBackground()
1954 && rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Entire);
1955 if (bSetTmpBackground)
1956 {
1957 Color aBg = IsMenuBar() ? rRenderContext.GetSettings().GetStyleSettings().GetMenuBarColor()
1958 : rRenderContext.GetSettings().GetStyleSettings().GetMenuColor();
1959 rRenderContext.SetBackground(Wallpaper(aBg));
1960 }
1961 // how much space is there for the text?
1962 long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpaceX;
1963 if (!IsMenuBar() && pData->aAccelKey.GetCode() && !ImplAccelDisabled())
1964 {
1965 OUString aAccText = pData->aAccelKey.GetName();
1966 nMaxItemTextWidth -= rRenderContext.GetTextWidth(aAccText) + 3 * nExtra;
1967 }
1968 if (!IsMenuBar() && pData->pSubMenu)
1969 {
1970 nMaxItemTextWidth -= nFontHeight - nExtra;
1971 }
1972
1973 OUString aItemText(pData->aText);
1974 pData->bHiddenOnGUI = false;
1975
1976 if (IsMenuBar()) // In case of menubar if we are out of bounds we shouldn't paint the item
1977 {
1978 if (nMaxItemTextWidth < rRenderContext.GetTextWidth(aItemText))
1979 {
1980 aItemText = "";
1981 pData->bHiddenOnGUI = true;
1982 bHiddenItems = true;
1983 }
1984 }
1985 else
1986 {
1987 aItemText = getShortenedString(aItemText, rRenderContext, nMaxItemTextWidth);
1988 pData->bHiddenOnGUI = false;
1989 }
1990
1991 const SalLayoutGlyphs* pGlyphs = pData->GetTextGlyphs(&rRenderContext);
1992 if (aItemText != pData->aText)
1993 // Can't use pre-computed glyphs, item text was
1994 // changed.
1995 pGlyphs = nullptr;
1996 rRenderContext.DrawCtrlText(aTmpPos, aItemText, 0, aItemText.getLength(),
1997 nStyle, pVector, pDisplayText, pGlyphs);
1998 if (bSetTmpBackground)
1999 rRenderContext.SetBackground();
2000 }
2001
2002 // Accel
2003 if (!bLayout && !IsMenuBar() && pData->aAccelKey.GetCode() && !ImplAccelDisabled())
2004 {
2005 OUString aAccText = pData->aAccelKey.GetName();
2006 aTmpPos.setX( aOutSz.Width() - rRenderContext.GetTextWidth(aAccText) );
2007 aTmpPos.AdjustX( -(4 * nExtra) );
2008
2009 aTmpPos.AdjustX( -nOuterSpaceX );
2010 aTmpPos.setY( aPos.Y() );
2011 aTmpPos.AdjustY(nTextOffsetY );
2012 rRenderContext.DrawCtrlText(aTmpPos, aAccText, 0, aAccText.getLength(), nTextStyle);
2013 }
2014
2015 // SubMenu?
2016 if (!bLayout && !IsMenuBar() && pData->pSubMenu)
2017 {
2018 bool bNativeOk = false;
2019 if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::SubmenuArrow))
2020 {
2021 ControlState nState = ControlState::NONE;
2022 Size aTmpSz(0, 0);
2023 long aSpacing = 0;
2024
2025 if (!ImplGetNativeSubmenuArrowSize(rRenderContext, aTmpSz, aSpacing))
2026 {
2027 aTmpSz = Size(nFontHeight, nFontHeight);
2028 aSpacing = nOuterSpaceX;
2029 }
2030
2031 if (pData->bEnabled && pWindow->IsEnabled())
2032 nState |= ControlState::ENABLED;
2033 if (bHighlighted)
2034 nState |= ControlState::SELECTED;
2035
2036 aTmpPos.setX( aOutSz.Width() - aTmpSz.Width() - aSpacing - nOuterSpaceX );
2037 aTmpPos.setY( aPos.Y() + ( pData->aSz.Height() - aTmpSz.Height() ) / 2 );
2038 aTmpPos.AdjustY(nExtra / 2 );
2039
2040 tools::Rectangle aItemRect(aTmpPos, aTmpSz);
2041 MenupopupValue aVal(nTextPos - GUTTERBORDER8, aItemRect);
2042 bNativeOk = rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::SubmenuArrow,
2043 aItemRect, nState, aVal, OUString());
2044 }
2045 if (!bNativeOk)
2046 {
2047 aTmpPos.setX( aOutSz.Width() - nFontHeight + nExtra - nOuterSpaceX );
2048 aTmpPos.setY( aPos.Y() );
2049 aTmpPos.AdjustY(nExtra/2 );
2050 aTmpPos.AdjustY((pData->aSz.Height() / 2) - (nFontHeight / 4) );
2051 if (pData->nBits & MenuItemBits::POPUPSELECT)
2052 {
2053 rRenderContext.SetTextColor(rSettings.GetMenuTextColor());
2054 Point aTmpPos2(aPos);
2055 aTmpPos2.setX( aOutSz.Width() - nFontHeight - nFontHeight/4 );
2056 aDecoView.DrawFrame(tools::Rectangle(aTmpPos2, Size(nFontHeight + nFontHeight / 4,
2057 pData->aSz.Height())),
2058 DrawFrameStyle::Group);
2059 }
2060 aDecoView.DrawSymbol(tools::Rectangle(aTmpPos, Size(nFontHeight / 2, nFontHeight / 2)),
2061 SymbolType::SPIN_RIGHT, rRenderContext.GetTextColor(), nSymbolStyle);
2062 }
2063 }
2064
2065 if (pThisItemOnly && bHighlighted)
2066 {
2067 // This restores the normal menu or menu bar text
2068 // color for when it is no longer highlighted.
2069 if (IsMenuBar())
2070 rRenderContext.SetTextColor(rSettings.GetMenuBarTextColor());
2071 else
2072 rRenderContext.SetTextColor(rSettings.GetMenuTextColor());
2073 }
2074 }
2075 if( bLayout )
2076 {
2077 if (!IsMenuBar())
2078 mpLayoutData->m_aVisibleItemBoundRects[ n ] = tools::Rectangle(aTopLeft, Size(aOutSz.Width(), pData->aSz.Height()));
2079 else
2080 mpLayoutData->m_aVisibleItemBoundRects[ n ] = tools::Rectangle(aTopLeft, pData->aSz);
2081 }
2082 }
2083
2084 if (!IsMenuBar())
2085 aTopLeft.AdjustY(pData->aSz.Height() );
2086 else
2087 aTopLeft.AdjustX(pData->aSz.Width() );
2088 }
2089
2090 // draw "more" (">>") indicator if some items have been hidden as they go out of visible area
2091 if (bHiddenItems)
2092 {
2093 sal_Int32 nSize = nFontHeight;
2094 tools::Rectangle aRectangle(Point(aOutSz.Width() - nSize, (aOutSz.Height() / 2) - (nSize / 2)), Size(nSize, nSize));
2095 lclDrawMoreIndicator(rRenderContext, aRectangle);
2096 }
2097}
2098
2099Menu* Menu::ImplGetStartMenu()
2100{
2101 Menu* pStart = this;
2102 while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) )
2103 pStart = pStart->pStartedFrom;
2104 return pStart;
2105}
2106
2107void Menu::ImplCallHighlight(sal_uInt16 nItem)
2108{
2109 ImplMenuDelData aDelData( this );
2110
2111 nSelectedId = 0;
2112 sSelectedIdent.clear();
2113 MenuItemData* pData = pItemList->GetDataFromPos(nItem);
2114 if (pData)
2115 {
2116 nSelectedId = pData->nId;
2117 sSelectedIdent = pData->sIdent;
2118 }
2119 ImplCallEventListeners( VclEventId::MenuHighlight, GetItemPos( GetCurItemId() ) );
2120
2121 if( !aDelData.isDeleted() )
2122 {
2123 nSelectedId = 0;
2124 sSelectedIdent.clear();
2125 }
2126}
2127
2128IMPL_LINK_NOARG(Menu, ImplCallSelect, void*, void)void Menu::LinkStubImplCallSelect(void * instance, void* data
) { return static_cast<Menu *>(instance)->ImplCallSelect
(data); } void Menu::ImplCallSelect(__attribute__ ((unused)) void
*)
2129{
2130 nEventId = nullptr;
2131 Select();
2132}
2133
2134Menu* Menu::ImplFindSelectMenu()
2135{
2136 Menu* pSelMenu = nEventId ? this : nullptr;
2137
2138 for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
2139 {
2140 MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2141
2142 if ( pData->pSubMenu )
2143 pSelMenu = pData->pSubMenu->ImplFindSelectMenu();
2144 }
2145
2146 return pSelMenu;
2147}
2148
2149Menu* Menu::ImplFindMenu( sal_uInt16 nItemId )
2150{
2151 Menu* pSelMenu = nullptr;
2152
2153 for ( size_t n = GetItemList()->size(); n && !pSelMenu; )
2154 {
2155 MenuItemData* pData = GetItemList()->GetDataFromPos( --n );
2156
2157 if( pData->nId == nItemId )
2158 pSelMenu = this;
2159 else if ( pData->pSubMenu )
2160 pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId );
2161 }
2162
2163 return pSelMenu;
2164}
2165
2166void Menu::RemoveDisabledEntries( bool bCheckPopups, bool bRemoveEmptyPopups )
2167{
2168 for ( sal_uInt16 n = 0; n < GetItemCount(); n++ )
2169 {
2170 bool bRemove = false;
2171 MenuItemData* pItem = pItemList->GetDataFromPos( n );
2172 if ( pItem->eType == MenuItemType::SEPARATOR )
2173 {
2174 if ( !n || ( GetItemType( n-1 ) == MenuItemType::SEPARATOR ) )
2175 bRemove = true;
2176 }
2177 else
2178 bRemove = !pItem->bEnabled;
2179
2180 if ( bCheckPopups && pItem->pSubMenu )
2181 {
2182 pItem->pSubMenu->RemoveDisabledEntries();
2183 if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() )
2184 bRemove = true;
2185 }
2186
2187 if ( bRemove )
2188 RemoveItem( n-- );
2189 }
2190
2191 if ( GetItemCount() )
2192 {
2193 sal_uInt16 nLast = GetItemCount() - 1;
2194 MenuItemData* pItem = pItemList->GetDataFromPos( nLast );
2195 if ( pItem->eType == MenuItemType::SEPARATOR )
2196 RemoveItem( nLast );
2197 }
2198 mpLayoutData.reset();
2199}
2200
2201void Menu::UpdateNativeMenu()
2202{
2203 if ( ImplGetSalMenu() )
2204 ImplGetSalMenu()->Update();
2205}
2206
2207void Menu::MenuBarKeyInput(const KeyEvent&)
2208{
2209}
2210
2211void Menu::ImplKillLayoutData() const
2212{
2213 mpLayoutData.reset();
2214}
2215
2216void Menu::ImplFillLayoutData() const
2217{
2218 if (!(pWindow && pWindow->IsReallyVisible()))
2219 return;
2220
2221 mpLayoutData.reset(new MenuLayoutData);
2222 if (IsMenuBar())
2223 {
2224 ImplPaint(*pWindow, pWindow->GetOutputSizePixel(), 0, 0, nullptr, false, true); // FIXME
2225 }
2226 else
2227 {
2228 MenuFloatingWindow* pFloat = static_cast<MenuFloatingWindow*>(pWindow.get());
2229 ImplPaint(*pWindow, pWindow->GetOutputSizePixel(), pFloat->nScrollerHeight, pFloat->ImplGetStartY(),
2230 nullptr, false, true); //FIXME
2231 }
2232}
2233
2234tools::Rectangle Menu::GetCharacterBounds( sal_uInt16 nItemID, long nIndex ) const
2235{
2236 long nItemIndex = -1;
2237 if( ! mpLayoutData )
2238 ImplFillLayoutData();
2239 if( mpLayoutData )
2240 {
2241 for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ )
2242 {
2243 if( mpLayoutData->m_aLineItemIds[i] == nItemID )
2244 {
2245 nItemIndex = mpLayoutData->m_aLineIndices[i];
2246 break;
2247 }
2248 }
2249 }
2250 return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : tools::Rectangle();
2251}
2252
2253long Menu::GetIndexForPoint( const Point& rPoint, sal_uInt16& rItemID ) const
2254{
2255 long nIndex = -1;
2256 rItemID = 0;
2257 if( ! mpLayoutData )
2258 ImplFillLayoutData();
2259 if( mpLayoutData )
2260 {
2261 nIndex = mpLayoutData->GetIndexForPoint( rPoint );
2262 for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ )
2263 {
2264 if( mpLayoutData->m_aLineIndices[i] <= nIndex &&
2265 (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) )
2266 {
2267 // make index relative to item
2268 nIndex -= mpLayoutData->m_aLineIndices[i];
2269 rItemID = mpLayoutData->m_aLineItemIds[i];
2270 break;
2271 }
2272 }
2273 }
2274 return nIndex;
2275}
2276
2277tools::Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const
2278{
2279 tools::Rectangle aRet;
2280
2281 if (!mpLayoutData )
2282 ImplFillLayoutData();
2283 if (mpLayoutData)
2284 {
2285 std::map< sal_uInt16, tools::Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos );
2286 if( it != mpLayoutData->m_aVisibleItemBoundRects.end() )
2287 aRet = it->second;
2288 }
2289 return aRet;
2290}
2291
2292void Menu::SetAccessibleName( sal_uInt16 nItemId, const OUString& rStr )
2293{
2294 size_t nPos;
2295 MenuItemData* pData = pItemList->GetData( nItemId, nPos );
2296
2297 if (pData && !rStr.equals(pData->aAccessibleName))
2298 {
2299 pData->aAccessibleName = rStr;
2300 ImplCallEventListeners(VclEventId::MenuAccessibleNameChanged, nPos);
2301 }
2302}
2303
2304OUString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
2305{
2306 MenuItemData* pData = pItemList->GetData( nItemId );
2307
2308 if ( pData )
2309 return pData->aAccessibleName;
2310
2311 return OUString();
2312}
2313
2314void Menu::SetAccessibleDescription( sal_uInt16 nItemId, const OUString& rStr )
2315{
2316 MenuItemData* pData = pItemList->GetData( nItemId );
2317
2318 if ( pData )
2319 pData->aAccessibleDescription = rStr;
2320}
2321
2322OUString Menu::GetAccessibleDescription( sal_uInt16 nItemId ) const
2323{
2324 MenuItemData* pData = pItemList->GetData( nItemId );
2325
2326 if (pData && !pData->aAccessibleDescription.isEmpty())
2327 return pData->aAccessibleDescription;
2328
2329 return GetHelpText(nItemId);
2330}
2331
2332void Menu::GetSystemMenuData( SystemMenuData* pData ) const
2333{
2334 Menu* pMenu = const_cast<Menu*>(this);
2335 if( pData && pMenu->ImplGetSalMenu() )
2336 {
2337 pMenu->ImplGetSalMenu()->GetSystemMenuData( pData );
2338 }
2339}
2340
2341bool Menu::IsHighlighted( sal_uInt16 nItemPos ) const
2342{
2343 bool bRet = false;
2344
2345 if( pWindow )
2346 {
2347 if (IsMenuBar())
2348 bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow.get())->GetHighlightedItem() );
2349 else
2350 bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow.get())->GetHighlightedItem() );
2351 }
2352
2353 return bRet;
2354}
2355
2356void Menu::HighlightItem( sal_uInt16 nItemPos )
2357{
2358 if ( !pWindow )
2359 return;
2360
2361 if (IsMenuBar())
2362 {
2363 MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow.get() );
2364 pMenuWin->SetAutoPopup( false );
2365 pMenuWin->ChangeHighlightItem( nItemPos, false );
2366 }
2367 else
2368 {
2369 static_cast< MenuFloatingWindow* >( pWindow.get() )->ChangeHighlightItem( nItemPos, false );
2370 }
2371}
2372
2373MenuBarWindow* MenuBar::getMenuBarWindow()
2374{
2375 // so far just a dynamic_cast, hopefully to be turned into something saner
2376 // at some stage
2377 MenuBarWindow *pWin = dynamic_cast<MenuBarWindow*>(pWindow.get());
2378 //either there is no window (fdo#87663) or it is a MenuBarWindow
2379 assert(!pWindow || pWin)(static_cast <bool> (!pWindow || pWin) ? void (0) : __assert_fail
("!pWindow || pWin", "/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
, 2379, __extension__ __PRETTY_FUNCTION__))
;
2380 return pWin;
2381}
2382
2383MenuBar::MenuBar()
2384 : Menu(),
2385 mbCloseBtnVisible(false),
2386 mbFloatBtnVisible(false),
2387 mbHideBtnVisible(false),
2388 mbDisplayable(true)
2389{
2390 mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(true, this);
2391}
2392
2393MenuBar::MenuBar( const MenuBar& rMenu )
2394 : Menu(),
2395 mbCloseBtnVisible(false),
2396 mbFloatBtnVisible(false),
2397 mbHideBtnVisible(false),
2398 mbDisplayable(true)
2399{
2400 mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(true, this);
2401 *this = rMenu;
2402}
2403
2404MenuBar::~MenuBar()
2405{
2406 disposeOnce();
2407}
2408
2409void MenuBar::dispose()
2410{
2411 ImplDestroy( this, true );
2412 Menu::dispose();
2413}
2414
2415void MenuBar::ClosePopup(Menu *pMenu)
2416{
2417 MenuBarWindow* pMenuWin = getMenuBarWindow();
2418 if (!pMenuWin)
2419 return;
2420 pMenuWin->PopupClosed(pMenu);
2421}
2422
2423void MenuBar::MenuBarKeyInput(const KeyEvent& rEvent)
2424{
2425 pWindow->KeyInput(rEvent);
2426}
2427
2428void MenuBar::ShowCloseButton(bool bShow)
2429{
2430 ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible );
2431}
2432
2433void MenuBar::ShowButtons( bool bClose, bool bFloat, bool bHide )
2434{
2435 if ((bClose != mbCloseBtnVisible) ||
2436 (bFloat != mbFloatBtnVisible) ||
2437 (bHide != mbHideBtnVisible))
2438 {
2439 mbCloseBtnVisible = bClose;
2440 mbFloatBtnVisible = bFloat;
2441 mbHideBtnVisible = bHide;
2442 MenuBarWindow* pMenuWin = getMenuBarWindow();
2443 if (pMenuWin)
2444 pMenuWin->ShowButtons(bClose, bFloat, bHide);
2445 }
2446}
2447
2448void MenuBar::LayoutChanged()
2449{
2450 MenuBarWindow* pMenuWin = getMenuBarWindow();
2451 if (pMenuWin)
2452 pMenuWin->LayoutChanged();
2453}
2454
2455void MenuBar::SetDisplayable( bool bDisplayable )
2456{
2457 if( bDisplayable != mbDisplayable )
2458 {
2459 if ( ImplGetSalMenu() )
2460 ImplGetSalMenu()->ShowMenuBar( bDisplayable );
2461
2462 mbDisplayable = bDisplayable;
2463 LayoutChanged();
2464 }
2465}
2466
2467VclPtr<vcl::Window> MenuBar::ImplCreate(vcl::Window* pParent, vcl::Window* pWindow, MenuBar* pMenu)
2468{
2469 VclPtr<MenuBarWindow> pMenuBarWindow = dynamic_cast<MenuBarWindow*>(pWindow);
2470 if (!pMenuBarWindow)
2471 {
2472 pWindow = pMenuBarWindow = VclPtr<MenuBarWindow>::Create( pParent );
2473 }
2474
2475 pMenu->pStartedFrom = nullptr;
2476 pMenu->pWindow = pWindow;
2477 pMenuBarWindow->SetMenu(pMenu);
2478 long nHeight = pWindow ? pMenu->ImplCalcSize(pWindow).Height() : 0;
2479
2480 // depending on the native implementation or the displayable flag
2481 // the menubar windows is suppressed (ie, height=0)
2482 if (!pMenu->IsDisplayable() || (pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar()))
2483 {
2484 nHeight = 0;
2485 }
2486
2487 pMenuBarWindow->SetHeight(nHeight);
2488 return pWindow;
2489}
2490
2491void MenuBar::ImplDestroy( MenuBar* pMenu, bool bDelete )
2492{
2493 vcl::Window *pWindow = pMenu->ImplGetWindow();
2494 if (pWindow && bDelete)
2495 {
2496 MenuBarWindow* pMenuWin = pMenu->getMenuBarWindow();
2497 if (pMenuWin)
2498 pMenuWin->KillActivePopup();
2499 pWindow->disposeOnce();
2500 }
2501 pMenu->pWindow = nullptr;
2502}
2503
2504bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent )
2505{
2506 // No keyboard processing when our menubar is invisible
2507 if (!IsDisplayable())
2508 return false;
2509
2510 // No keyboard processing when system handles the menu.
2511 SalMenu *pNativeMenu = ImplGetSalMenu();
2512 if (pNativeMenu && pNativeMenu->VisibleMenuBar())
2513 {
2514 // Except when the event is the F6 cycle pane event and we can put our
2515 // focus into it (i.e. the gtk3 menubar case but not the mac/unity case
2516 // where it's not part of the application window)
2517 if (!TaskPaneList::IsCycleKey(rKEvent.GetKeyCode()))
2518 return false;
2519 if (!pNativeMenu->CanGetFocus())
2520 return false;
2521 }
2522
2523 bool bDone = false;
2524 // check for enabled, if this method is called from another window...
2525 vcl::Window* pWin = ImplGetWindow();
2526 if (pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && !pWin->IsInModalMode())
2527 {
2528 MenuBarWindow* pMenuWin = getMenuBarWindow();
2529 bDone = pMenuWin && pMenuWin->HandleKeyEvent(rKEvent, false/*bFromMenu*/);
2530 }
2531 return bDone;
2532}
2533
2534bool MenuBar::ImplHandleCmdEvent( const CommandEvent& rCEvent )
2535{
2536 // No keyboard processing when system handles the menu or our menubar is invisible
2537 if( !IsDisplayable() ||
2538 ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
2539 return false;
2540
2541 // check for enabled, if this method is called from another window...
2542 MenuBarWindow* pWin = static_cast<MenuBarWindow*>(ImplGetWindow());
2543 if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() )
2544 {
2545 if (rCEvent.GetCommand() == CommandEventId::ModKeyChange && ImplGetSVData()->maNWFData.mbAutoAccel)
2546 {
2547 const CommandModKeyData* pCData = rCEvent.GetModKeyData ();
2548 if (pWin->m_nHighlightedItem == ITEMPOS_INVALID)
2549 {
2550 if (pCData && pCData->IsMod2() && pCData->IsDown())
2551 pWin->SetMBWHideAccel(false);
2552 else
2553 pWin->SetMBWHideAccel(true);
2554 pWin->Invalidate(InvalidateFlags::Update);
2555 }
2556 return true;
2557 }
2558 }
2559 return false;
2560}
2561
2562void MenuBar::SelectItem(sal_uInt16 nId)
2563{
2564 if (!pWindow)
2565 return;
2566
2567 pWindow->GrabFocus();
2568 nId = GetItemPos( nId );
2569
2570 MenuBarWindow* pMenuWin = getMenuBarWindow();
2571 if (pMenuWin)
2572 {
2573 // #99705# popup the selected menu
2574 pMenuWin->SetAutoPopup( true );
2575 if (ITEMPOS_INVALID != pMenuWin->GetHighlightedItem())
2576 {
2577 pMenuWin->KillActivePopup();
2578 pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, false );
2579 }
2580 if (nId != ITEMPOS_INVALID)
2581 pMenuWin->ChangeHighlightItem( nId, false );
2582 }
2583}
2584
2585// handler for native menu selection and command events
2586bool Menu::HandleMenuActivateEvent( Menu *pMenu ) const
2587{
2588 if( pMenu )
2589 {
2590 ImplMenuDelData aDelData( this );
2591
2592 pMenu->pStartedFrom = const_cast<Menu*>(this);
2593 pMenu->bInCallback = true;
2594 pMenu->Activate();
2595
2596 if( !aDelData.isDeleted() )
2597 pMenu->bInCallback = false;
2598 }
2599 return true;
2600}
2601
2602bool Menu::HandleMenuDeActivateEvent( Menu *pMenu ) const
2603{
2604 if( pMenu )
2605 {
2606 ImplMenuDelData aDelData( this );
2607
2608 pMenu->pStartedFrom = const_cast<Menu*>(this);
2609 pMenu->bInCallback = true;
2610 pMenu->Deactivate();
2611 if( !aDelData.isDeleted() )
2612 pMenu->bInCallback = false;
2613 }
2614 return true;
2615}
2616
2617bool MenuBar::HandleMenuHighlightEvent( Menu *pMenu, sal_uInt16 nHighlightEventId ) const
2618{
2619 if( !pMenu )
2620 pMenu = const_cast<MenuBar*>(this)->ImplFindMenu(nHighlightEventId);
2621 if( pMenu )
2622 {
2623 ImplMenuDelData aDelData( pMenu );
2624
2625 if( mnHighlightedItemPos != ITEMPOS_INVALID )
2626 pMenu->ImplCallEventListeners( VclEventId::MenuDehighlight, mnHighlightedItemPos );
2627
2628 if( !aDelData.isDeleted() )
2629 {
2630 pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId );
2631 pMenu->nSelectedId = nHighlightEventId;
2632 pMenu->sSelectedIdent = pMenu->GetItemIdent( nHighlightEventId );
2633 pMenu->pStartedFrom = const_cast<MenuBar*>(this);
2634 pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos );
2635 }
2636 return true;
2637 }
2638 else
2639 return false;
2640}
2641
2642bool Menu::HandleMenuCommandEvent( Menu *pMenu, sal_uInt16 nCommandEventId ) const
2643{
2644 if( !pMenu )
2645 pMenu = const_cast<Menu*>(this)->ImplFindMenu(nCommandEventId);
2646 if( pMenu )
2647 {
2648 pMenu->nSelectedId = nCommandEventId;
2649 pMenu->sSelectedIdent = pMenu->GetItemIdent(nCommandEventId);
2650 pMenu->pStartedFrom = const_cast<Menu*>(this);
2651 pMenu->ImplSelect();
2652 return true;
2653 }
2654 else
2655 return false;
2656}
2657
2658sal_uInt16 MenuBar::AddMenuBarButton( const Image& i_rImage, const Link<MenuBar::MenuBarButtonCallbackArg&,bool>& i_rLink, const OUString& i_rToolTip )
2659{
2660 MenuBarWindow* pMenuWin = getMenuBarWindow();
2661 return pMenuWin ? pMenuWin->AddMenuBarButton(i_rImage, i_rLink, i_rToolTip) : 0;
2662}
2663
2664void MenuBar::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link<MenuBar::MenuBarButtonCallbackArg&,bool>& rLink )
2665{
2666 MenuBarWindow* pMenuWin = getMenuBarWindow();
2667 if (!pMenuWin)
2668 return;
2669 pMenuWin->SetMenuBarButtonHighlightHdl(nId, rLink);
2670}
2671
2672void MenuBar::RemoveMenuBarButton( sal_uInt16 nId )
2673{
2674 MenuBarWindow* pMenuWin = getMenuBarWindow();
2675 if (!pMenuWin)
2676 return;
2677 pMenuWin->RemoveMenuBarButton(nId);
2678}
2679
2680tools::Rectangle MenuBar::GetMenuBarButtonRectPixel( sal_uInt16 nId )
2681{
2682 MenuBarWindow* pMenuWin = getMenuBarWindow();
2683 return pMenuWin ? pMenuWin->GetMenuBarButtonRectPixel(nId) : tools::Rectangle();
2684}
2685
2686bool MenuBar::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
2687{
2688 MenuBarWindow* pMenuWin = getMenuBarWindow();
2689 return pMenuWin && pMenuWin->HandleMenuButtonEvent(i_nButtonId);
2690}
2691
2692int MenuBar::GetMenuBarHeight() const
2693{
2694 MenuBar* pMenuBar = const_cast<MenuBar*>(this);
2695 const SalMenu *pNativeMenu = pMenuBar->ImplGetSalMenu();
2696 int nMenubarHeight;
2697 if (pNativeMenu)
2698 nMenubarHeight = pNativeMenu->GetMenuBarHeight();
2699 else
2700 {
2701 vcl::Window* pMenubarWin = GetWindow();
2702 nMenubarHeight = pMenubarWin ? pMenubarWin->GetOutputHeightPixel() : 0;
2703 }
2704 return nMenubarHeight;
2705}
2706
2707// bool PopupMenu::bAnyPopupInExecute = false;
2708
2709MenuFloatingWindow * PopupMenu::ImplGetFloatingWindow() const {
2710 return static_cast<MenuFloatingWindow *>(Menu::ImplGetWindow());
2711}
2712
2713PopupMenu::PopupMenu()
2714 : mpLOKNotifier(nullptr)
2715{
2716 mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this);
2717}
2718
2719PopupMenu::PopupMenu( const PopupMenu& rMenu )
2720 : Menu(),
2721 mpLOKNotifier(nullptr)
2722{
2723 mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu(false, this);
2724 *this = rMenu;
2725}
2726
2727PopupMenu::~PopupMenu()
2728{
2729 disposeOnce();
2730}
2731
2732void PopupMenu::ClosePopup(Menu* pMenu)
2733{
2734 MenuFloatingWindow* p = dynamic_cast<MenuFloatingWindow*>(ImplGetWindow());
2735 PopupMenu *pPopup = dynamic_cast<PopupMenu*>(pMenu);
2736 if (p && pPopup)
2737 p->KillActivePopup(pPopup);
2738}
2739
2740bool PopupMenu::IsInExecute()
2741{
2742 return GetActivePopupMenu() != nullptr;
2743}
2744
2745PopupMenu* PopupMenu::GetActivePopupMenu()
2746{
2747 ImplSVData* pSVData = ImplGetSVData();
2748 return pSVData->maAppData.mpActivePopupMenu;
2749}
2750
2751void PopupMenu::EndExecute()
2752{
2753 if ( ImplGetWindow() )
2754 ImplGetFloatingWindow()->EndExecute( 0 );
2755}
2756
2757void PopupMenu::SelectItem(sal_uInt16 nId)
2758{
2759 if ( !ImplGetWindow() )
2760 return;
2761
2762 if( nId != ITEMPOS_INVALID )
2763 {
2764 size_t nPos = 0;
2765 MenuItemData* pData = GetItemList()->GetData( nId, nPos );
2766 if (pData && pData->pSubMenu)
2767 ImplGetFloatingWindow()->ChangeHighlightItem( nPos, true );
2768 else
2769 ImplGetFloatingWindow()->EndExecute( nId );
2770 }
2771 else
2772 {
2773 MenuFloatingWindow* pFloat = ImplGetFloatingWindow();
2774 pFloat->GrabFocus();
2775
2776 for( size_t nPos = 0; nPos < GetItemList()->size(); nPos++ )
2777 {
2778 MenuItemData* pData = GetItemList()->GetDataFromPos( nPos );
2779 if( pData->pSubMenu )
2780 {
2781 pFloat->KillActivePopup();
2782 }
2783 }
2784 pFloat->ChangeHighlightItem( ITEMPOS_INVALID, false );
2785 }
2786}
2787
2788void PopupMenu::SetSelectedEntry( sal_uInt16 nId )
2789{
2790 nSelectedId = nId;
2791 sSelectedIdent = GetItemIdent(nId);
2792}
2793
2794sal_uInt16 PopupMenu::Execute( vcl::Window* pExecWindow, const Point& rPopupPos )
2795{
2796 return Execute( pExecWindow, tools::Rectangle( rPopupPos, rPopupPos ), PopupMenuFlags::ExecuteDown );
2797}
2798
2799sal_uInt16 PopupMenu::Execute( vcl::Window* pExecWindow, const tools::Rectangle& rRect, PopupMenuFlags nFlags )
2800{
2801 ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 )if( !(pExecWindow) ) { do { if (true && (!(pExecWindow
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2801" ": "), "%s", "PopupMenu::Execute: need a non-NULL window!"
); } } while (false); return 0; }
;
2802
2803 FloatWinPopupFlags nPopupModeFlags = FloatWinPopupFlags::NONE;
2804 if ( nFlags & PopupMenuFlags::ExecuteDown )
2805 nPopupModeFlags = FloatWinPopupFlags::Down;
2806 else if ( nFlags & PopupMenuFlags::ExecuteUp )
2807 nPopupModeFlags = FloatWinPopupFlags::Up;
2808 else if ( nFlags & PopupMenuFlags::ExecuteLeft )
2809 nPopupModeFlags = FloatWinPopupFlags::Left;
2810 else if ( nFlags & PopupMenuFlags::ExecuteRight )
2811 nPopupModeFlags = FloatWinPopupFlags::Right;
2812 else
2813 nPopupModeFlags = FloatWinPopupFlags::Down;
2814
2815 if (nFlags & PopupMenuFlags::NoMouseUpClose ) // allow popup menus to stay open on mouse button up
2816 nPopupModeFlags |= FloatWinPopupFlags::NoMouseUpClose; // useful if the menu was opened on mousebutton down (eg toolbox configuration)
2817
2818 if (nFlags & PopupMenuFlags::NoHorzPlacement)
2819 nPopupModeFlags |= FloatWinPopupFlags::NoHorzPlacement;
2820
2821 return ImplExecute( pExecWindow, rRect, nPopupModeFlags, nullptr, false );
2822}
2823
2824void PopupMenu::ImplFlushPendingSelect()
2825{
2826 // is there still Select?
2827 Menu* pSelect = ImplFindSelectMenu();
2828 if (pSelect)
2829 {
2830 // Select should be called prior to leaving execute in a popup menu!
2831 Application::RemoveUserEvent( pSelect->nEventId );
2832 pSelect->nEventId = nullptr;
2833 pSelect->Select();
2834 }
2835}
2836
2837sal_uInt16 PopupMenu::ImplExecute( const VclPtr<vcl::Window>& pW, const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags, Menu* pSFrom, bool bPreSelectFirst )
2838{
2839 if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) )
2840 return 0;
2841
2842 // set the flag to hide or show accelerators in the menu depending on whether the menu was launched by mouse or keyboard shortcut
2843 if( pSFrom && pSFrom->IsMenuBar())
2844 {
2845 auto pMenuBarWindow = static_cast<MenuBarWindow*>(pSFrom->pWindow.get());
2846 pMenuBarWindow->SetMBWHideAccel( !(pMenuBarWindow->GetMBWMenuKey()) );
2847 }
2848
2849 mpLayoutData.reset();
2850
2851 ImplSVData* pSVData = ImplGetSVData();
2852
2853 pStartedFrom = pSFrom;
2854 nSelectedId = 0;
2855 sSelectedIdent.clear();
2856 bCanceled = false;
2857
2858 VclPtr<vcl::Window> xFocusId;
2859 bool bRealExecute = false;
2860 if ( !pStartedFrom )
2861 {
2862 pSVData->mpWinData->mbNoDeactivate = true;
2863 xFocusId = Window::SaveFocus();
2864 bRealExecute = true;
2865 }
2866 else
2867 {
2868 // assure that only one menu is open at a time
2869 if (pStartedFrom->IsMenuBar() && pSVData->mpWinData->mpFirstFloat)
2870 pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel
2871 | FloatWinPopupEndFlags::CloseAll);
2872 }
2873
2874 SAL_WARN_IF( ImplGetWindow(), "vcl", "Win?!" )do { if (true && (ImplGetWindow())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Win?!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2874" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Win?!"), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "Win?!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2874" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Win?!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2874" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Win?!"), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "Win?!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2874" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2875 tools::Rectangle aRect( rRect );
2876 aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) );
2877
2878 if (bRealExecute)
2879 nPopupModeFlags |= FloatWinPopupFlags::NewLevel;
2880 nPopupModeFlags |= FloatWinPopupFlags::NoKeyClose | FloatWinPopupFlags::AllMouseButtonClose;
2881
2882 bInCallback = true; // set it here, if Activate overridden
2883 Activate();
2884 bInCallback = false;
2885
2886 if ( pW->IsDisposed() )
2887 return 0; // Error
2888
2889 if ( bCanceled || bKilled )
2890 return 0;
2891
2892 if ( !GetItemCount() )
2893 return 0;
2894
2895 // The flag MenuFlags::HideDisabledEntries is inherited.
2896 if ( pSFrom )
2897 {
2898 if ( pSFrom->nMenuFlags & MenuFlags::HideDisabledEntries )
2899 nMenuFlags |= MenuFlags::HideDisabledEntries;
2900 else
2901 nMenuFlags &= ~MenuFlags::HideDisabledEntries;
2902 }
2903 else
2904 // #102790# context menus shall never show disabled entries
2905 nMenuFlags |= MenuFlags::HideDisabledEntries;
2906
2907 sal_uInt16 nVisibleEntries = ImplGetVisibleItemCount();
2908 if ( !nVisibleEntries )
2909 {
2910 OUString aTmpEntryText(VclResId(SV_RESID_STRING_NOSELECTIONPOSSIBLEreinterpret_cast<char const *>("SV_RESID_STRING_NOSELECTIONPOSSIBLE"
"\004" u8"<No selection possible>")
));
2911
2912 MenuItemData* pData = NbcInsertItem(0xFFFF, MenuItemBits::NONE, aTmpEntryText, nullptr, 0xFFFF, OString());
2913 size_t nPos = 0;
2914 pData = pItemList->GetData( pData->nId, nPos );
2915 assert(pData)(static_cast <bool> (pData) ? void (0) : __assert_fail (
"pData", "/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
, 2915, __extension__ __PRETTY_FUNCTION__))
;
2916 if (pData)
2917 {
2918 pData->bIsTemporary = true;
2919 }
2920 ImplCallEventListeners(VclEventId::MenuSubmenuChanged, nPos);
2921 }
2922
2923 VclPtrInstance<MenuFloatingWindow> pWin( this, pW, WB_BORDER | WB_SYSTEMWINDOW );
2924 if (comphelper::LibreOfficeKit::isActive() && mpLOKNotifier)
2925 pWin->SetLOKNotifier(mpLOKNotifier);
2926
2927 if( pSVData->maNWFData.mbFlatMenu )
2928 pWin->SetBorderStyle( WindowBorderStyle::NOBORDER );
2929 else
2930 pWin->SetBorderStyle( pWin->GetBorderStyle() | WindowBorderStyle::MENU );
2931 pWindow = pWin;
2932
2933 Size aSz = ImplCalcSize( pWin );
2934
2935 tools::Rectangle aDesktopRect(pWin->GetDesktopRectPixel());
2936 if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
2937 {
2938 vcl::Window* pDeskW = pWindow->GetWindow( GetWindowType::RealParent );
2939 if( ! pDeskW )
2940 pDeskW = pWindow;
2941 Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) );
2942 aDesktopRect = Application::GetScreenPosSizePixel(
2943 Application::GetBestScreen( tools::Rectangle( aDesktopTL, aRect.GetSize() ) ));
2944 }
2945
2946 long nMaxHeight = aDesktopRect.GetHeight();
2947
2948 //rhbz#1021915. If a menu won't fit in the desired location the default
2949 //mode is to place it somewhere it will fit. e.g. above, left, right. For
2950 //some cases, e.g. menubars, it's desirable to limit the options to
2951 //above/below and force the menu to scroll if it won't fit
2952 if (nPopupModeFlags & FloatWinPopupFlags::NoHorzPlacement)
2953 {
2954 vcl::Window* pRef = pWin;
2955 if ( pRef->GetParent() )
2956 pRef = pRef->GetParent();
2957
2958 tools::Rectangle devRect( pRef->OutputToAbsoluteScreenPixel( aRect.TopLeft() ),
2959 pRef->OutputToAbsoluteScreenPixel( aRect.BottomRight() ) );
2960
2961 long nHeightAbove = devRect.Top() - aDesktopRect.Top();
2962 long nHeightBelow = aDesktopRect.Bottom() - devRect.Bottom();
2963 nMaxHeight = std::min(nMaxHeight, std::max(nHeightAbove, nHeightBelow));
2964 }
2965
2966 // In certain cases this might be misdetected with a height of 0, leading to menus not being displayed.
2967 // So assume that the available screen size matches at least the system requirements
2968 SAL_WARN_IF(nMaxHeight < 768, "vcl",do { if (true && (nMaxHeight < 768)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Available height misdetected as "
<< nMaxHeight << "px. Setting to 768px instead."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Available height misdetected as " << nMaxHeight
<< "px. Setting to 768px instead.") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2969 "Available height misdetected as " << nMaxHeightdo { if (true && (nMaxHeight < 768)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Available height misdetected as "
<< nMaxHeight << "px. Setting to 768px instead."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Available height misdetected as " << nMaxHeight
<< "px. Setting to 768px instead.") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2970 << "px. Setting to 768px instead.")do { if (true && (nMaxHeight < 768)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Available height misdetected as "
<< nMaxHeight << "px. Setting to 768px instead."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Available height misdetected as " << nMaxHeight
<< "px. Setting to 768px instead.") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Available height misdetected as " <<
nMaxHeight << "px. Setting to 768px instead."), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Available height misdetected as " << nMaxHeight <<
"px. Setting to 768px instead."; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
":" "2970" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2971 nMaxHeight = std::max(nMaxHeight, 768l);
2972
2973 if (pStartedFrom && pStartedFrom->IsMenuBar())
2974 nMaxHeight -= pW->GetSizePixel().Height();
2975 sal_Int32 nLeft, nTop, nRight, nBottom;
2976 pWindow->GetBorder( nLeft, nTop, nRight, nBottom );
2977 nMaxHeight -= nTop+nBottom;
2978 if ( aSz.Height() > nMaxHeight )
2979 {
2980 pWin->EnableScrollMenu( true );
2981 sal_uInt16 nStart = ImplGetFirstVisible();
2982 sal_uInt16 nEntries = ImplCalcVisEntries( nMaxHeight, nStart );
2983 aSz.setHeight( ImplCalcHeight( nEntries ) );
2984 }
2985
2986 // tdf#126054 hold this until after function completes
2987 VclPtr<PopupMenu> xThis(this);
2988
2989 pWin->SetFocusId( xFocusId );
2990 pWin->SetOutputSizePixel( aSz );
2991 if ( GetItemCount() )
2992 {
2993 SalMenu* pMenu = ImplGetSalMenu();
2994 if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FloatWinPopupFlags::GrabFocus ) )
2995 {
2996 pWin->StopExecute();
2997 pWin->doShutdown();
2998 pWindow->SetParentToDefaultWindow();
2999 pWindow.disposeAndClear();
3000 ImplClosePopupToolBox(pW);
3001 ImplFlushPendingSelect();
3002 return nSelectedId;
3003 }
3004 else
3005 {
3006 pWin->StartPopupMode( aRect, nPopupModeFlags | FloatWinPopupFlags::GrabFocus );
3007 }
3008 if( pSFrom )
3009 {
3010 sal_uInt16 aPos;
3011 if (pSFrom->IsMenuBar())
3012 aPos = static_cast<MenuBarWindow *>(pSFrom->pWindow.get())->GetHighlightedItem();
3013 else
3014 aPos = static_cast<MenuFloatingWindow *>(pSFrom->pWindow.get())->GetHighlightedItem();
3015
3016 pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE
3017 pSFrom->ImplCallEventListeners( VclEventId::MenuSubmenuActivate, aPos );
3018 }
3019 }
3020 if ( bPreSelectFirst )
3021 {
3022 size_t nCount = pItemList->size();
3023 for ( size_t n = 0; n < nCount; n++ )
3024 {
3025 MenuItemData* pData = pItemList->GetDataFromPos( n );
3026 if ( ( pData->bEnabled
3027 || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus()
3028 )
3029 && ( pData->eType != MenuItemType::SEPARATOR )
3030 && ImplIsVisible( n )
3031 && ImplIsSelectable( n )
3032 )
3033 {
3034 pWin->ChangeHighlightItem( n, false );
3035 break;
3036 }
3037 }
3038 }
3039 if ( bRealExecute )
3040 {
3041 pWin->Execute();
3042 if (pWin->IsDisposed())
3043 return 0;
3044
3045 xFocusId = pWin->GetFocusId();
3046 assert(xFocusId == nullptr && "Focus should already be restored by MenuFloatingWindow::End")(static_cast <bool> (xFocusId == nullptr && "Focus should already be restored by MenuFloatingWindow::End"
) ? void (0) : __assert_fail ("xFocusId == nullptr && \"Focus should already be restored by MenuFloatingWindow::End\""
, "/home/maarten/src/libreoffice/core/vcl/source/window/menu.cxx"
, 3046, __extension__ __PRETTY_FUNCTION__))
;
3047 pWin->ImplEndPopupMode(FloatWinPopupEndFlags::NONE, xFocusId);
3048
3049 if ( nSelectedId ) // then clean up .. ( otherwise done by TH )
3050 {
3051 PopupMenu* pSub = pWin->GetActivePopup();
3052 while ( pSub )
3053 {
3054 pSub->ImplGetFloatingWindow()->EndPopupMode();
3055 pSub = pSub->ImplGetFloatingWindow()->GetActivePopup();
3056 }
3057 }
3058 pWin->doShutdown();
3059 pWindow->SetParentToDefaultWindow();
3060 pWindow.disposeAndClear();
3061 ImplClosePopupToolBox(pW);
3062 ImplFlushPendingSelect();
3063 }
3064
3065 return bRealExecute ? nSelectedId : 0;
3066}
3067
3068sal_uInt16 PopupMenu::ImplCalcVisEntries( long nMaxHeight, sal_uInt16 nStartEntry, sal_uInt16* pLastVisible ) const
3069{
3070 nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight();
3071
3072 long nHeight = 0;
3073 size_t nEntries = pItemList->size();
3074 sal_uInt16 nVisEntries = 0;
3075
3076 if ( pLastVisible )
3077 *pLastVisible = 0;
3078
3079 for ( size_t n = nStartEntry; n < nEntries; n++ )
3080 {
3081 if ( ImplIsVisible( n ) )
3082 {
3083 MenuItemData* pData = pItemList->GetDataFromPos( n );
3084 nHeight += pData->aSz.Height();
3085 if ( nHeight > nMaxHeight )
3086 break;
3087
3088 if ( pLastVisible )
3089 *pLastVisible = n;
3090 nVisEntries++;
3091 }
3092 }
3093 return nVisEntries;
3094}
3095
3096long PopupMenu::ImplCalcHeight( sal_uInt16 nEntries ) const
3097{
3098 long nHeight = 0;
3099
3100 sal_uInt16 nFound = 0;
3101 for ( size_t n = 0; ( nFound < nEntries ) && ( n < pItemList->size() ); n++ )
3102 {
3103 if ( ImplIsVisible( static_cast<sal_uInt16>(n) ) )
3104 {
3105 MenuItemData* pData = pItemList->GetDataFromPos( n );
3106 nHeight += pData->aSz.Height();
3107 nFound++;
3108 }
3109 }
3110
3111 nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight();
3112
3113 return nHeight;
3114}
3115
3116ImplMenuDelData::ImplMenuDelData( const Menu* pMenu )
3117: mpNext( nullptr )
3118, mpMenu( nullptr )
3119{
3120 if( pMenu )
3121 const_cast< Menu* >( pMenu )->ImplAddDel( *this );
3122}
3123
3124ImplMenuDelData::~ImplMenuDelData()
3125{
3126 if( mpMenu )
1
Taking true branch
3127 const_cast< Menu* >( mpMenu.get() )->ImplRemoveDel( *this );
2
Calling 'Menu::ImplRemoveDel'
3128}
3129
3130/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
4
Calling 'Reference::set'
12
Returning; memory was released
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody
4.1
'pBody' is null
4.1
'pBody' is null
4.1
'pBody' is null
4.1
'pBody' is null
)
5
Taking false branch
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld
5.1
'pOld' is non-null
5.1
'pOld' is non-null
5.1
'pOld' is non-null
5.1
'pOld' is non-null
)
6
Taking true branch
127 pOld->release();
7
Calling 'VclReferenceBase::release'
11
Returning; memory was released
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
8
Assuming the condition is true
9
Taking true branch
40 delete this;
10
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif